From: Chet Ramey Date: Wed, 7 Dec 2011 14:37:48 +0000 (-0500) Subject: bash-4.0 remove leftover and stray files X-Git-Tag: bash-4.3-alpha~241 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=023010f8b8a2e755da97484e3e6fdc2f41e4fbf3;p=thirdparty%2Fbash.git bash-4.0 remove leftover and stray files --- diff --git a/AUTHORS~ b/AUTHORS~ deleted file mode 100644 index a44e906e4..000000000 --- a/AUTHORS~ +++ /dev/null @@ -1,458 +0,0 @@ -# -# Master author manifest for bash -# -# The files in lib/intl were taken from the GNU gettext distribution. -# -# 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 - -tests/posix-ifs.sh Glenn Fowler diff --git a/CHANGES~ b/CHANGES~ deleted file mode 100644 index 3a02fe7a4..000000000 --- a/CHANGES~ +++ /dev/null @@ -1,6218 +0,0 @@ -This document details the changes between this version, bash-4.0-release, -and the previous version, bash-4.0-rc1. - -This document details the changes between this version, bash-4.0-rc1, -and the previous version, bash-4.0-beta2. - -1. Changes to Bash - -a. Changed the message printed when setlocale(3) fails to only include the - strerror error text if the call changes errno. - -b. Changed trap command execution to reset the line number before running a - trap (except DEBUG and RETURN traps). - -c. Fixed behavior of case-modifiying word expansions to not work on - individual words within a variable's value. - -d. Fixed a bug that caused mapfile to not be interruptible when run in an - interactive shell. - -e. Fixed a bug that caused mapfile to not run callbacks for the first line - read. - -f. Fixed a bug that caused mapfile to not honor EOF typed in an interactive - shell. - -g. Fixed the coprocess reaping code to not run straight from a signal handler. - -h. Fixed a bug that caused printf -b to ignore the first % conversion specifier - in the format string on 64-bit systems. - -i. Fixed a bug that caused incorrect word splitting when `:', `=', or `~' - appeared in $IFS. - -j. Fixed a bug that caused data corruption in the programmable completion code - when a shell function called from a completion aborted execution. - -k. Fixed a bug that caused the CPU usage reported by the `time' builtin to be - capped at 100%. - -2. Changes to Readline - -a. Fixed a bug that caused !(...) extended glob patterns to inhibit later - history expansion. - -b. Reworked the signal handling to avoid calling disallowed functions from a - signal handler. - -3. New Features in Bash - -a. `readarray' is now a synonym for `mapfile'. ------------------------------------------------------------------------------- -1. Changes to Bash - -a. Fixed a bug that caused parsing errors when a $()-style command - substitution was follwed immediately by a quoted newline. - -b. Fixed a bug that caused extended shell globbing patterns beginning with - `*(' to not work when used with pattern substitution word expansions. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-4.0-beta2, -and the previous version, bash-4.0-beta. - -1. Changes to Bash - -a. Fixed a bug that caused failed word expansions to set $? but not - PIPESTATUS. - -b. Changed filename completion to quote the tilde in a filename with a - leading tilde that exists in the current directory. - -c. Fixed a bug that caused a file descriptor leak when performing - redirections attached to a compound command. - -d. Fixed a bug that caused expansions of $@ and $* to not exit the shell if - the -u option was enabled and there were no posititional parameters. - -e. Fixed a bug that resulted in bash not terminating immediately if a - terminating signal was received while performing output. - -f. Fixed a bug that caused the shell to crash after creating 256 process - substitutions during word completion. - -2. Changes to Readline - -a. Fixed a bug that caused redisplay errors when using prompts with invisible - characters and numeric arguments to a command in a multibyte locale. - -b. Fixed a bug that caused redisplay errors when using prompts with invisible - characters spanning more than two physical screen lines. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-4.0-beta, -and the previous version, bash-4.0-alpha. - -1. Changes to Bash - -a. Fixed a typo that caused a variable to be used before initialization - while parsing Posix-style command substitutions. - -b. Fixed a bug that caused stray ^? when the expansion of a parameter used - as part of a pattern removal expansion is empty, but part of a non- - empty string. - -c. Fixed a bug that could cause strings not converted to numbers by strtol - to be treated as if the conversion had been successful. - -d. The `return' builtin now accepts no options and requires a `--' before - a negative return value, as Posix requires. - -e. Fixed a bug that caused local variables to be created with the empty - string for a value rather than no value. - -f. Changed behavior so the shell now acts as if it received an interrupt - when a pipeline is killed by SIGINT while executing a list. - -g. Fixed a bug that caused `declare var' and `typeset var' to initialize - `var' to the empty string. - -h. Changed `bind' builtin to print a warning but proceed if invoked when - line editing is not active. - -i. Fixed a bug that caused the shell to exit when the `errexit' option is - set and a command in a pipeline returns a non-zero exit status. - -j. Fixed a bug that caused the shell to not run the exit trap in a command - run with `bash -c' under some circumstances. - -k. Fixed a bug that caused parser errors to occasionally not set $? when - running commands with `eval'. - -l. Fixed a bug that caused stray control characters when evaluating compound - array assignments containing $'\x7f' escapes. - -m. Fixed a bug that caused redirections involving file descriptor 10 as the - target to behave incorrectly. - -n. Fixed a bug that could cause memory to be freed multiple times when - assigning to COMP_WORDBREAKS. - -o. Fixed a bug that could cause NULL pointer dereferences when COMP_WORDBREAKS - was unset. - -2. Changes to Readline - -3. New Features in Bash - -a. A value of 0 for the -t option to `read' now returns success if there is - input available to be read from the specified file descriptor. - -b. CDPATH and GLOBIGNORE are ignored when the shell is running in privileged - mode. - -c. New bindable readline functions shell-forward-word and shell-backward-word, - which move forward and backward words delimited by shell metacharacters - and honor shell quoting. - -d. New bindable readline functions shell-backward-kill-word and shell-kill-word - which kill words backward and forward, but use the same word boundaries - as shell-forward-word and shell-backward-word. - -4. New Features in Readline - -a. If the kernel supports it, readline displays special characters - corresponding to a keyboard-generated signal when the signal is received. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-4.0-alpha, -and the previous version, bash-3.2-release. - -1. Changes to Bash - -a. Fixed several bugs in old-style `` command substitution parsing, including - comment parsing and quoted string handling. - -b. Fixed problems parsing arguments to the [[ command's =~ regular expression - matching operator: metacharacter and whitespace parsing. - -c. Fixed a bug that caused the shell to inappropriately reuse high-numbered - file descriptors it used internally. - -d. Fixed a bug in pattern replacement word expansions that caused a `/' as - the first character of an expanded pattern to be mistaken for a global - replacement specifier. - -e. Fixed several problems with the asprintf and snprintf replacement functions - that caused hangs and crashes. - -f. Fixed a bug in the calculation of the current and previous job that caused - it to refer to incorrect jobs. - -g. Fixed a bug in the check for the validity of a hashed command pathname that - caused unnecessary hash table deletions and additions. - -h. Fixed a bug that caused child processes to inherit the wrong value for $!. - -i. Fixed a bug that caused `.' to fail to read and execute commands from non- - regular files such as devices or named pipes. - -j. Fixed a bug in printf formatting for the %x and %X expansions that occurred - on some systems. - -k. Fixed a bug that caused the shell to crash when creating temporary files if - $TMPDIR named a non-writable directory. - -l. Fixed a bug that caused the shell to ignore $TMPDIR when creating temporary - files under some circumstances. - -m. Fixed a bug that caused named pipes created by process substitution to not - be cleaned up. - -n. Fixed a bug that caused HISTTIMEFORMAT to not be honored when it appeared - in the initial shell environment. - -o. Fixed several bugs in the expansion of $* and $@ (quoted and unquoted) - when IFS is null or contains non-whitespace characters; the same changes - apply to arrays subscripted with * or @. - -p. Fixed several problems with pattern substitution expansions on the - positional parameters and arrays subscripted with * or @ that occurred - when $IFS was set to the empty string. - -q. Made a change to the default locale initialization code that should - result in better behavior from the locale-aware library functions. - -r. Fixed a bug that caused compacting the jobs list to drop jobs. - -s. Fixed a bug that caused jumps back to the top-level processing loop from - a builtin command to leave the shell in an inconsistent state. - -t. Fixed a bug that caused characters that would be escaped internally to be - doubled when escaped with a backslash. - -u. Fixed the initialization of mailboxes to not cause maildirs to be read - (and stat(2) called for every message file) at shell startup. - -v. Fixed a bug that caused the shell to not display $PS2 when the read builtin - reads a line continued with a backslash. - -w. Fixed a bug that caused errors in word splitting when $IFS contained - characters used for internal quoting. - -x. Fixed bugs that caused problems with output from shell builtins not being - completely displayed on some systems. - -y. Fixed a bug that caused output to be lost when a redirection is acting on - the shell's output file descriptor. - -z. Fixed bugs caused by shell builtins not checking for all write errors. - -aa. Fixed a problem that caused the shell to dump core if expansions on the - pattern passed to the pattern removal word expansions resulted in expansion - errors. - -bb. Fixed a bug that caused bash to loop infinitely after creating and - waiting for 4096 jobs. - -cc. Fixed a bug that caused bash to lose the status of a background job under - certain circumstances. - -dd. Fixed a bug that caused bash to not look in the temporary environment - when performing variable lookup under certain circumstances. - -ee. Fixed a bug that caused bash to close file descriptors greater than 10 - when they were used in redirections. - -ff. Fixed a problem that caused the shell to attempt to read from the standard - input when called as `bash -i script'. - -gg. Fixed a memory leak and variable initialization problems when the -v option - was supplied to `printf' that could cause incorrect results. - -hh. Fixed a bug that caused the `read' builtin to count bytes when the -n option - was supplied, rather than (possibly multibyte) characters. - -ii. Fixed a bug when displaying a function due to not converting the function - to an external form. - -jj. Changed job control initialization to ensure that the shell has a tty - as its controlling terminal before enabling job control. - -kk. Fixed a bug with the `test' builtin that caused it to misinterpret - arguments beginning with `-' but containing more than one character. - -ll. Fixed bug that could cause the shell to dump core in certain cases where - a command sets the SIGINT disposition to the default. - -mm. Fixed a bug in the pattern replacement (affecting both word expansion - and the `fc' builtin) that occurred when the pattern and replacement - strings were empty. - -nn. Fixed a bug that caused an arithmetic evaluation error to disable all - further evaluation. - -oo. Fixed a bug in pathname expansion that caused it to interpret backslashes - in the pathname as quoting characters. - -pp. Fixed a bug in the replacement getcwd() implementation that could cause - memory to be overwritten. - -qq. When in Posix mode, the `ulimit' builtin now uses a block size of 512 for - the `-c' and `-f' options. - -rr. Brace expansion now allows process substitutions to pass through unchanged. - -ss. Fixed a problem in the command name completion code to avoid quoting - escaped special characters twice when the command name begins with a tilde. - -tt. Fixed a problem in the printf builtin that resulted in single-byte - output for the "'" escape, even when using multibyte characters. - -uu. Fixed a bug that caused the failure exit status to be lost when redirections - attached to a compound command failed. - -vv. Fixed a bug that caused the internal random number generator to not be - re-seeded correctly when creating a subshell. - -ww. Fixed a bug that could cause the bash replacement getcwd to overwrite - memory. - -xx. Fixed a bug that caused the shell to not receive SIGINT if it was sent - while the shell was waiting for a command substitution to terminate, and - make sure the exit status is correct when it does. - -yy. Fixed a bug that resulted in the second and subsequent children spawned - by a shell begun to run a command substitution being placed into the - wrong process group. - -zz. Fixed a bug that caused the results of successful tilde expansion to be - subject to pathname expansion and word splitting. - -aaa. Fixed a bug that could cause the shell to hang if it encountered an - error that caused it to jump back to the top processing loop during a - command substitution or `eval' command. - -bbb. Fixed a bug that caused the `read' builtin to use the tty's attributes - instead of those of the file descriptor passed with the -u option when - processing the -n and -d options. - -ccc. Fixed a bug that caused incorrect expansion of ${array[@]:foo} if the - first character of $IFS was not whitespace. - -ddd. Fixed a bug that occurred when scanning for the ending delimiter of a - ${parameter/pat/sub} expansion. - -eee. Fixed a bug that caused the shell to inappropriately expand command - substitutions in words when expanding directory names for completion. - -fff. Fixed a bug that caused the `fc' builtin to look too far back in the - history list under certain circumstances. - -ggg. Fixed a bug that caused a shell running in Posix mode to search $PWD for - a file specified as an argument to source/. when the file was not found - in $PATH. - -hhh. Fixed a bug that caused the shell to modify the case of a command word - found via command completion when the shell was performing case- - insensitive completion. - -iii. Fixed a bug that caused the shell to search $PATH for an argument to - source/. even when it contained a `/'. - -jjj. Fixed a bug that caused brace expansion to misorder expansions when the - locale did not have a collating order like aAbBcC...zZ. - -kkk. Fixed a bug that did not allow `set +o history' to have any effect when - run in a startup file or from a sourced file. - -lll. Fixed a bug with the precedence of the ?: conditional arithmetic operator. - -mmm. Fixed a bug that caused side effects of temporary variable assignments - to persist in the shell environment. - -nnn. Fixed a bug that caused the terminal to be left in non-canonical mode - when using editing commands that invoke the an editor on the current - command line. - -ooo. Fixed a bug that caused globbing characters and characters in $IFS to not - be quoted appropriately when displaying assignment statements. - -ppp. Fixed a bug that caused the `-e' option to be inherited when sourcing a - file or evaluating a command with `eval' even if the return value of the - command was supposed to be ignored. - -qqq. Fixed a bug that caused the shell to attempt to created variables with - invalid names if such names appeared in the initial environment. - -rrr. Fixed a bug with quote removal in strings where the final character is a - backslash. - -sss. Fixed a bug that caused the effects of special variables to persist even - when the variables were unset as part of the shell reinitializing itself - to execute a shell script. - -ttt. Fixed a bug that caused the history to not be saved after `history -c' or - `history -d' was executed until a sufficient number of commands had been - saved to the history. - -uuu. Bash now parses command substitutions according to Posix rules: parsing - the command contained in $() to find the closing delimiter. - -vvv. Fixed a bug that caused traps on SIGCHLD set in a SIGCHLD handler to - not persist. - -www. Fixed a bug that didn't allow SIGCHLD to interrupt the `wait' builtin - as Posix specifies. - -xxx. Invalid numeric arguments to shell builtins no longer cause the shell to - short-circuit any executing compound command. - -yyy. Fixed a bug that caused the exit status to be lost when `break' was - used to short-circuit a loop's execution. - -zzz. Fixed a bug that caused stray ^? characters to be left in expansions of - "${array[*]}". - -aaaa. Bash now prints better error messages for here documents terminated by - EOF and for identifying the incorrect token in an invalid arithmetic - expression. - -bbbb. Fixed a bug in the variable length word expansion that caused it to - incorrectly calculate the number of multibyte characters. - -cccc. Fixed a race condition that could result in the top-level shell setting - the terminal's process group to an incorrect value if the process - group was changed by a child of a child of the shell. - -dddd. Fixed a bug that caused here documents belonging to commands within a - compound command to be displayed in a syntactially-incorrect form, which - prevented them from being re-read as input. - -eeee. The shell displays more warnings about failures to set the locale. - -ffff. Fixed a bug that caused the body of a here-document to not be saved to - the history list. - -gggg. Fixed a bug that caused configure to incorrectly conclude that FreeBSD - had /dev/fd available, resulting in problems with process substitution. - -2. Changes to Readline - -a. Fixed a number of redisplay errors in environments supporting multibyte - characters. - -b. Fixed bugs in vi command mode that caused motion commands to inappropriately - set the mark. - -c. When using the arrow keys in vi insertion mode, readline allows movement - beyond the current end of the line (unlike command mode). - -d. Fixed bugs that caused readline to loop when the terminal has been taken - away and reads return -1/EIO. - -e. Fixed bugs in redisplay occurring when displaying prompts containing - invisible characters. - -f. Fixed a bug that caused the completion append character to not be reset to - the default after an application-specified completion function changed it. - -g. Fixed a problem that caused incorrect positioning of the cursor while in - emacs editing mode when moving forward at the end of a line while using - a locale supporting multibyte characters. - -h. Fixed an off-by-one error that caused readline to drop every 511th - character of buffered input. - -i. Fixed a bug that resulted in SIGTERM not being caught or cleaned up. - -j. Fixed redisplay bugs caused by multiline prompts with invisible characters - or no characters following the final newline. - -k. Fixed redisplay bug caused by prompts consisting solely of invisible - characters. - -l. Fixed a bug in the code that buffers characters received very quickly in - succession which caused characters to be dropped. - -m. Fixed a bug that caused readline to reference uninitialized data structures - if it received a SIGWINCH before completing initialzation. - -n. Fixed a bug that caused the vi-mode `last command' to be set incorrectly - and therefore unrepeatable. - -o. Fixed a bug that caused readline to disable echoing when it was being used - with an output file descriptor that was not a terminal. - -p. Readline now blocks SIGINT while manipulating internal data structures - during redisplay. - -q. Fixed a bug in redisplay that caused readline to segfault when pasting a - very long line (over 130,000 characters). - -r. Fixed bugs in redisplay when using prompts with no visible printing - characters. - -3. New Features in Bash - -a. When using substring expansion on the positional parameters, a starting - index of 0 now causes $0 to be prefixed to the list. - -b. The `help' builtin now prints its columns with entries sorted vertically - rather than horizontally. - -c. There is a new variable, $BASHPID, which always returns the process id of - the current shell. - -d. There is a new `autocd' option that, when enabled, causes bash to attempt - to `cd' to a directory name that is supplied as the first word of a - simple command. - -e. There is a new `checkjobs' option that causes the shell to check for and - report any running or stopped jobs at exit. - -f. The programmable completion code exports a new COMP_TYPE variable, set to - a character describing the type of completion being attempted. - -g. The programmable completion code exports a new COMP_KEY variable, set to - the character that caused the completion to be invoked (e.g., TAB). - -h. If creation of a child process fails due to insufficient resources, bash - will try again several times before reporting failure. - -i. The programmable completion code now uses the same set of characters as - readline when breaking the command line into a list of words. - -j. The block multiplier for the ulimit -c and -f options is now 512 when in - Posix mode, as Posix specifies. - -k. Changed the behavior of the read builtin to save any partial input received - in the specified variable when the read builtin times out. This also - results in variables specified as arguments to read to be set to the empty - string when there is no input available. When the read builtin times out, - it returns an exit status greater than 128. - -l. The shell now has the notion of a `compatibility level', controlled by - new variables settable by `shopt'. Setting this variable currently - restores the bash-3.1 behavior when processing quoted strings on the rhs - of the `=~' operator to the `[[' command. - -m. The `ulimit' builtin now has new -b (socket buffer size) and -T (number - of threads) options. - -n. The -p option to `declare' now displays all variable values and attributes - (or function values and attributes if used with -f). - -o. There is a new `compopt' builtin that allows completion functions to modify - completion options for existing completions or the completion currently - being executed. - -p. The `read' builtin has a new -i option which inserts text into the reply - buffer when using readline. - -q. A new `-E' option to the complete builtin allows control of the default - behavior for completion on an empty line. - -r. There is now limited support for completing command name words containing - globbing characters. - -s. Changed format of internal help documentation for all builtins to roughly - follow man page format. - -t. The `help' builtin now has a new -d option, to display a short description, - and a -m option, to print help information in a man page-like format. - -u. There is a new `mapfile' builtin to populate an array with lines from a - given file. - -v. If a command is not found, the shell attempts to execute a shell function - named `command_not_found_handle', supplying the command words as the - function arguments. - -w. There is a new shell option: `globstar'. When enabled, the globbing code - treats `**' specially -- it matches all directories (and files within - them, when appropriate) recursively. - -x. There is a new shell option: `dirspell'. When enabled, the filename - completion code performs spelling correction on directory names during - completion. - -y. The `-t' option to the `read' builtin now supports fractional timeout - values. - -z. Brace expansion now allows zero-padding of expanded numeric values and - will add the proper number of zeroes to make sure all values contain the - same number of digits. - -aa. There is a new bash-specific bindable readline function: `dabbrev-expand'. - It uses menu completion on a set of words taken from the history list. - -bb. The command assigned to a key sequence with `bind -x' now sets two new - variables in the environment of the executed command: READLINE_LINE_BUFFER - and READLINE_POINT. The command can change the current readline line - and cursor position by modifying READLINE_LINE_BUFFER and READLINE_POINT, - respectively. - -cc. There is a new >>& redirection operator, which appends the standard output - and standard error to the named file. - -dd. The parser now understands `|&' as a synonym for `2>&1 |', which redirects - the standard error for a command through a pipe. - -ee. The new `;&' case statement action list terminator causes execution to - continue with the action associated with the next pattern in the - statement rather than terminating the command. - -ff. The new `;;&' case statement action list terminator causes the shell to - test the next set of patterns after completing execution of the current - action, rather than terminating the command. - -gg. The shell understands a new variable: PROMPT_DIRTRIM. When set to an - integer value greater than zero, prompt expansion of \w and \W will - retain only that number of trailing pathname components and replace - the intervening characters with `...'. - -hh. There are new case-modifying word expansions: uppercase (^[^]) and - lowercase (,[,]). They can work on either the first character or - array element, or globally. They accept an optional shell pattern - that determines which characters to modify. There is an optionally- - configured feature to include capitalization operators. - -ii. The shell provides associative array variables, with the appropriate - support to create, delete, assign values to, and expand them. - -jj. The `declare' builtin now has new -l (convert value to lowercase upon - assignment) and -u (convert value to uppercase upon assignment) options. - There is an optionally-configurable -c option to capitalize a value at - assignment. - -kk. There is a new `coproc' reserved word that specifies a coprocess: an - asynchronous command run with two pipes connected to the creating shell. - Coprocs can be named. The input and output file descriptors and the - PID of the coprocess are available to the calling shell in variables - with coproc-specific names. - -4. New Features in Readline - -a. A new variable, rl_sort_completion_matches; allows applications to inhibit - match list sorting (but beware: some things don't work right if - applications do this). - -b. A new variable, rl_completion_invoking_key; allows applications to discover - the key that invoked rl_complete or rl_menu_complete. - -c. The functions rl_block_sigint and rl_release_sigint are now public and - available to calling applications who want to protect critical sections - (like redisplay). - -d. The functions rl_save_state and rl_restore_state are now public and - available to calling applications; documented rest of readline's state - flag values. - -e. A new user-settable variable, `history-size', allows setting the maximum - number of entries in the history list. - -f. There is a new implementation of menu completion, with several improvements - over the old; the most notable improvement is a better `completions - browsing' mode. - -g. The menu completion code now uses the rl_menu_completion_entry_function - variable, allowing applications to provide their own menu completion - generators. - -h. There is support for replacing a prefix of a pathname with a `...' when - displaying possible completions. This is controllable by setting the - `completion-prefix-display-length' variable. Matches with a common prefix - longer than this value have the common prefix replaced with `...'. - -i. There is a new `revert-all-at-newline' variable. If enabled, readline will - undo all outstanding changes to all history lines when `accept-line' is - executed. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-3.2-release, -and the previous version, bash-3.2-beta. - -1. Changes to Bash - -a. Fixed a bug that caused the temporary environment passed to a command to - affect the shell's environment under certain circumstances. - -b. Fixed a bug in the printf builtin that caused the %q format specifier to - ignore empty string arguments. - -c. Improved multibyte character environment detection at configuration time. - -d. Fixed a bug in the read builtin that left spurious escape characters in the - input after processing backslashes when assigning to an array variable. - -2. Changes to Readline - -a. Fixed a redisplay bug that occurred in multibyte-capable locales when the - prompt was one character longer than the screen width. ------------------------------------------------------------------------------- -This document details the changes between this version, bash-3.2-beta, -and the previous version, bash-3.2-alpha. - -1. Changes to Bash - -a. Changed the lexical analyzer to treat locale-specific blank characters as - white space. - -b. Fixed a bug in command printing to avoid confusion between redirections and - process substitution. - -c. Fixed problems with cross-compiling originating from inherited environment - variables. - -d. Added write error reporting to printf builtin. - -e. Fixed a bug in the variable expansion code that could cause a core dump in - a multi-byte locale. - -f. Fixed a bug that caused substring expansion of a null string to return - incorrect results. - -g. BASH_COMMAND now retains its previous value while executing commands as the - result of a trap, as the documentation states. - -2. Changes to Readline - -a. Fixed a bug with prompt redisplay in a multi-byte locale to avoid redrawing - the prompt and input line multiple times. - -b. Fixed history expansion to not be confused by here-string redirection. - -c. Readline no longer treats read errors by converting them to newlines, as - it does with EOF. This caused partial lines to be returned from readline(). - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-3.2-alpha, -and the previous version, bash-3.1-release. - -1. Changes to Bash - -a. Fixed a source bug that caused the minimal configuration to not compile. - -b. Fixed memory leaks in error handling for the `read' builtin. - -c. Changed the [[ and (( compound commands to set PIPESTATUS with their exit - status. - -d. Fixed some parsing problems with compound array assignments. - -e. Added additional configuration changes for: NetBSD (incomplete multibyte - character support) - -f. Fixed two bugs with local array variable creation when shadowing a variable - of the same name from a previous context. - -g. Fixed the `read' builtin to restore the correct set of completion functions - if a timeout occurs. - -h. Added code to defer the initialization of HISTSIZE (and its stifling of the - history list) until the history file is loaded, allowing a startup file to - override the default value. - -i. Tightened up the arithmetic expression parsing to produce better error - messages when presented with invalid operators. - -j. Fixed the cross-compilation support to build the signal list at shell - invocation rather than compile time if cross-compiling. - -k. Fixed multibyte support for non-gcc compilers (or compilers that do not - allow automatic array variable sizing based on a non-constant value). - -l. Several fixes to the code that manages the list of terminated jobs and - their exit statuses, and the list of active and recently-terminated jobs - to avoid pid aliasing/wraparound and allocation errors. - -m. Fixed a problem that allowed scripts to die due to SIGINT while waiting - for children, even when started in the background or otherwise ignoring - SIGINT. - -n. Fixed a bug that caused shells invoked as -/bin/bash from not being - recognized as login shells. - -o. Fixed a problem that caused shells in the background to give the terminal - to a process group other than the foreground shell process group. - -p. Fixed a problem with extracting the `varname' in ${#varname}. - -q. Fixed the code that handles SIGQUIT to not exit immediately -- thereby - calling functions that may not be called in a signal handler context -- - but set a flag and exit afterward (like SIGINT). - -r. Changed the brace expansion code to skip over braces that don't begin a - valid matched brace expansion construct. - -s. Fixed `typeset' and `declare' to not require that their shell function - operands to be valid shell identifiers. - -t. Changed `test' to use access(2) with a temporary uid/euid swap when testing - file attributes and running setuid, and access(2) in most other cases. - -u. Changed completion code to not attempt command name completion on a line - consisting solely of whitespace when no_empty_command_completion is set. - -v. The `hash' builtin now prints nothing in posix mode when the hash table is - empty, and prints a message to that effect to stdout instead of stderr - when not in posix mode. - -w. Fixed a bug in the extended pattern matching code that caused it to fail to - match periods with certain patterns. - -x. Fixed a bug that caused the shell to dump core when performing filename - generation in directories with thousands of files. - -y. Returned to the original Bourne shell rules for parsing ``: no recursive - parsing of embedded quoted strings or ${...} constructs. - -z. The inheritence of the DEBUG, RETURN, and ERR traps is now dependent only - on the settings of the `functrace' and `errtrace' shell options, rather - than whether or not the shell is in debugging mode. - -aa. Fixed a problem with $HOME being converted to ~ in the expansion of - members of the DIRSTACK array. - -bb. Fixed a problem with quoted arguments to arithmetic expansions in certain - constructs. - -cc. The command word completion code now no longer returns matching directories - while searching $PATH. - -dd. Fixed a bug with zero-padding and precision handling in snprintf() - replacement. - -ee. Fixed a bug that caused the command substitution code not to take embedded - shell comments into account. - -ff. Fixed a bug that caused $((...);(...)) to be misinterpreted as an - arithmetic substitution. - -gg. Fixed a bug in the prompt expansion code that inappropriately added a - \001 before a \002 under certain circumstances. - -hh. Fixed a bug that caused `unset LANG' to not properly reset the locale - (previous versions would set the locale back to what it was when bash - was started rather than the system's "native" locale). - -ii. Fixed a bug that could cause file descriptors > 10 to not be closed even - when closed explicitly by a script. - -jj. Fixed a bug that caused single quotes to be stripped from ANSI-C quoting - inside double-quoted command substitutions. - -kk. Fixed a bug that could cause core dumps when `return' was executed as the - last element of a pipeline inside a shell function. - -ll. Fixed a bug that caused DEBUG trap strings to overwrite commands stored in - the jobs list. - -2. Changes to Readline - -a. Fixed a problem that caused segmentation faults when using readline in - callback mode and typing consecutive DEL characters on an empty line. - -b. Fixed several redisplay problems with multibyte characters, all having to - do with the different code paths and variable meanings between single-byte - and multibyte character redisplay. - -c. Fixed a problem with key sequence translation when presented with the - sequence \M-\C-x. - -d. Fixed a problem that prevented the `a' command in vi mode from being - undone and redone properly. - -e. Fixed a problem that prevented empty inserts in vi mode from being undone - properly. - -f. Fixed a problem that caused readline to initialize with an incorrect idea - of whether or not the terminal can autowrap. - -g. Fixed output of key bindings (like bash `bind -p') to honor the setting of - convert-meta and use \e where appropriate. - -h. Changed the default filename completion function to call the filename - dequoting function if the directory completion hook isn't set. This means - that any directory completion hooks need to dequote the directory name, - since application-specific hooks need to know how the word was quoted, - even if no other changes are made. - -i. Fixed a bug with creating the prompt for a non-interactive search string - when there are non-printing characters in the primary prompt. - -j. Fixed a bug that caused prompts with invisible characters to be redrawn - multiple times in a multibyte locale. - -k. Fixed a bug that could cause the key sequence scanning code to return the - wrong function. - -l. Fixed a problem with the callback interface that caused it to fail when - using multi-character keyboard macros. - -m. Fixed a bug that could cause a core dump when an edited history entry was - re-executed under certain conditions. - -n. Fixed a bug that caused readline to reference freed memory when attmpting - to display a portion of the prompt. - -3. New Features in Bash - -a. Changed the parameter pattern replacement functions to not anchor the - pattern at the beginning of the string if doing global replacement - that - combination doesn't make any sense. - -b. When running in `word expansion only' mode (--wordexp option), inhibit - process substitution. - -c. Loadable builtins now work on MacOS X 10.[34]. - -d. Shells running in posix mode no longer set $HOME, as POSIX requires. - -e. The code that checks for binary files being executed as shell scripts now - checks only for NUL rather than any non-printing character. - -f. Quoting the string argument to the [[ command's =~ operator now forces - string matching, as with the other pattern-matching operators. - -4. New Features in Readline - -a. Calling applications can now set the keyboard timeout to 0, allowing - poll-like behavior. - -b. The value of SYS_INPUTRC (configurable at compilation time) is now used as - the default last-ditch startup file. - -c. The history file reading functions now allow windows-like \r\n line - terminators. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-3.1-release, -and the previous version, bash-3.1-rc2. - -1. Changes to Readline - -a. Several changes to the multibyte redisplay code to fix problems with - prompts containing invisible characters. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-3.1-rc2, -and the previous version, bash-3.1-rc1. - -1. Changes to Bash - -a. Fixed a bug that caused a DEBUG trap to overwrite a command string that's - eventually attached to a background job. - -b. Changed some code so that filenames with leading tildes with spaces in the - name aren't tilde-expanded by the bash completion code. - -c. Fixed a bug that caused the pushd builtin to fail to change to - directories with leading `-'. - -d. Fixed a small memory leak in the programmable completion code. - -2. Changes to Readline - -a. Fixed a redisplay bug caused by moving the cursor vertically to a line - with invisible characters in the prompt in a multibyte locale. - -b. Fixed a bug that could cause the terminal special chars to be bound in the - wrong keymap in vi mode. - -3. New Features in Bash - -a. If compiled for strict POSIX conformance, LINES and COLUMNS may now - override the true terminal size. - -4. New Features in Readline - -a. A new external application-controllable variable that allows the LINES - and COLUMNS environment variables to set the window size regardless of - what the kernel returns. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-3.1-rc1, -and the previous version, bash-3.1-beta1. - -1. Changes to Bash - -a. Fixed a bug that could cause core dumps due to accessing the current - pipeline while in the middle of modifying it. - -b. Fixed a bug that caused pathnames with backslashes still quoting characters - to be passed to opendir(). - -c. Command word completion now obeys the setting of completion-ignore-case. - -d. Fixed a problem with redirection that caused file descriptors greater than - 2 to be inappropriately marked as close-on-exec. - -e. In Posix mode, after `wait' is called to wait for a particular process - explicitly, that process is removed from the list of processes known to - the shell, and subsequent attempts to wait for it return errors. - -f. Fixed a bug that caused extended pattern matching to incorrectly scan - backslash-escaped pattern characters. - -g. Fixed a synchronization problem that could cause core dumps when handling - a SIGWINCH. - -h. Fixed a bug that caused an unmatched backquote to be accepted without an - error when processing here documents. - -i. Fixed a small memory leak in the `cd' builtin. - -j. Fix for MacOS X so it gets the values for the HOSTTYPE, MACHTYPE, and - OSTYPE variables at build time, to support universal binaries. - -k. Fixed a bug that could cause an exit trap to return the exit status of - the trap command rather than the status as it was before the trap was - run as the shell's exit status. - -2. New Features in Bash - -3. Changes to Readline - -a. Fixed a bug that caused reversing the incremental search direction to - not work correctly. - -b. Fixed the vi-mode `U' command to only undo up to the first time insert mode - was entered, as Posix specifies. - -c. Fixed a bug in the vi-mode `r' command that left the cursor in the wrong - place. - -4. New Features in Readline - -a. New application-callable auxiliary function, rl_variable_value, returns - a string corresponding to a readline variable's value. - -b. When parsing inputrc files and variable binding commands, the parser - strips trailing whitespace from values assigned to boolean variables - before checking them. - - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-3.1-beta1, -and the previous version, bash-3.1-alpha1. - -1. Changes to Bash - -a. Added some system-specific signal names. - -b. Fixed a typo in the ulimit builtin to make `x' the right option to - maniuplate the limit on file locks. - -c. Fixed a problem with using += to append to index 0 of an array variable - when not using subscript syntax. - -d. A few changes to configure.in to remove calls to obsolete or outdated - macros. - -e. Make sure changes to variables bash handles specially (e.g., LC_ALL) are - made when the variable is set in the temporary environment to a command. - -f. Make sure changes to variables bash handles specially (e.g., LC_ALL) are - made when the variable is modified using `printf -v'. - -g. The export environment is now remade on cygwin when HOME is changed, so - DLLs bash is linked against pick up the new value. This fixes problems - with tilde expansion when linking against and already-installed readline. - -h. Small fix to the logic for performing tilde expansion in posix mode, so - expansion on the right-hand side of an assignment statement takes place. - -i. Fixed a bug that prevented redirections associated with a shell function - from being executed when in a subshell. - -j. Fixed `source' and `.' builtins to not require an executable file when - searching $PATH for a file to source. - -k. Fixed a bug that caused incorrect word splitting in a function when IFS - was declared local, then unset. - -l. Fixed a problem with the `kill' builtin that prevented sending signals - to a process group under certain circumstances when providing a pid < 0. - -m. When in POSIX mode, `pwd' now checks that the value it prints is the same - directory as `.', even when displaying $PWD. - -n. Fixed a problem with the `read' builtin when reading a script from standard - input and reading data from the same file. - -o. Fixed a problem with the `type' and `command' builtins that caused absolute - pathnames to be displayed incorrectly. - -p. Some changes to the `bg' builtin for POSIX conformance. - -q. The `fc' builtin now removes the `fc' command that caused it to invoke an - editor on specified history entries from the history entirely, rather than - simply ignoring it. - -r. When in POSIX mode, the `v' command in vi editing mode simply invokes vi - on the current command, rather than checking $FCEDIT and $EDITOR. - -s. Fixed a small memory leak in the pathname canonicalization code. - -t. Fixed a bug that caused the expanded value of a $'...' string to be - incorrectly re-quoted if it occurred within a double-quoted ${...} - parameter expansion. - -u. Restored default emacs-mode key binding of M-TAB to dynamic-complete-history. - -v. Fixed a bug that caused core dumps when interrupting loops running builtins - on some systems. - -w. Make sure that some of the functions bash provides replacements for are - not cpp defines. - -x. The code that scans embedded commands for the parser (`...` and $(...)) is - now more aware of embedded comments and their effect on quoted strings. - -y. Changed the `-n' option to the `history' builtin to not reset the number of - history lines read in the current session after reading the new lines from - the history file if the history is being appended when it is written to - the file, since the appending takes care of the problem that the adjustment - was intended to solve. - -z. Improved the error message displayed when a shell script fails to execute - because the environment and size of command line arguments are too large. - -aa. A small fix to make sure that $HISTCMD is evaluated whenever the shell is - saving commands to the history list, not just when HISTSIZE is defined. - -2. Changes to Readline - -a. The `change-case' command now correctly changes the case of multibyte - characters. - -b. Changes to the shared library construction scripts to deal with Windows - DLL naming conventions for Cygwin. - -c. Fixed the redisplay code to avoid core dumps resulting from a poorly-timed - SIGWINCH. - -d. Fixed the non-incremental search code in vi mode to dispose of any current - undo list when copying a line from the history into the current editing - buffer. - -e. The variable assignment code now ignores whitespace at the end of lines - when assigning to boolean variables. - -f. The `C-w' binding in incremental search now understands multibyte - characters. - -3. New Features in Bash - -a. A new configuration option, `--enable-strict-posix-default', which will - build bash to be POSIX conforming by default. - -4. New Features in Readline - -a. If the rl_completion_query_items is set to a value < 0, readline never - asks the user whether or not to view the possible completions. - ------------------------------------------------------------------------------- -This document details the changes between this version, bash-3.1-alpha1, -and the previous version, bash-3.0-release. - -1. Changes to Bash - -a. Fixed a bug that caused bash to crash if referencing an unset local array. - -b. Fixed a problem that caused tilde expansion to not be performed before - attempting globbing word completion. - -c. Fixed an incompatibility so that a first argument to trap that's a valid - signal number will be trated as a signal rather than a command to execute. - -d. Fixed ${#word} expansion to correctly compute the length of a string - containing multibyte characters. - -e. Fixed a bug that caused bash to not pass the correct flags for signal - disposition to child processes. - -f. Fixed a bug that caused `fc -l' to list one too many history entries. - -g. Some fixes to `fc' for POSIX conformance. - -h. Some fixes to job status display for POSIX conformance. - -i. Fixed a bug that caused `command -v' to display output if a command was not - found -- it should be silent. - -j. In POSIX mode, `type' and `command -[vV]' do not report non-executable - files, even if the shell will attempt to execute them. - -k. Fixed a bug that caused the `==' operator to the [[ command to not attempt - extended pattern matching. - -l. Fixed the brace expansion code to handle characters whose value exceeds 128. - -m. Fixed `printf' to handle strings with a leading `\0' whose length is - non-zero. - -n. Fixed a couple of problems with brace expansion where `${' was handled - incorrectly. - -o. Fixed off-by-one error when calculating the upper bound of `offset' when - processing the ${array[@]:offset:length} expansion. - -p. System-specific configuration changes for: FreeBSD 5.x, Interix, MacOS X - 10.4, Linux 2.4+ kernels, Linux 3.x kernels, Dragonfly BSD, QNX 6.x, - Cygwin - -q. Fixed a bug that caused the shell to ignore the status of the rightmost - command in a pipeline when the `pipefail' option was enabled. - -r. Fixed a completion bug that caused core dumps when expanding a directory - name. - -s. Fixed a bug that prevented `hash -d' from removing commands from the hash - table. - -t. Fixed word splitting to avoid really bad quadratic performance when - expanding long lists. - -u. Fixed a bug that caused negative offsets in substring expansion to use the - wrong values. - -v. Fixed a bug in printf that caused it to not return failure on write errors. - -w. Fixed a bug that caused commands in subshells to not be properly timed. - -x. The shell parser no longer attempts to parse a compound assignment specially - unless in a position where an assignment statement is acceptable or parsing - arguments to a builtin that accepts assignment statements. - -y. Fixed a problem that caused a `case' statement to be added to the history - incorrectly as a single command if the `case word' was on one line and the - `in' on another. - -z. Fixed a problem that caused internal shell quoting characters to be - incorrectly quoted with backslashes under some circumstances. - -aa. The shell now performs correct word splitting when IFS contains multibyte - characters. - -bb. The mail checking code now resets the cached file information if the size - drops to 0, even if the times don't change. - -cc. A completed command name that is found in $PATH as well as the name of a - directory in the current directory no longer has a slash appended in certain - circumstances: a single instance found in $PATH when `.' is not in $PATH, - and multiple instances found in $PATH, even when `.' is in $PATH. - -dd. Incorporated tilde expansion into the word expansion code rather than as a - separately-called function, fixing some cases where it was performed - inappropriately (e.g., after the second `=' in an assignment statement or - in a double-quoted parameter expansion). - -ee. Fixed several bugs encountered when parsing compound assignment statements, - so that compound assignments appearing as arguments to builtins are no - longer double-expanded. - -ff. Fixed a bug in the command execution code that caused asynchronous commands - containing command substitutions to not put the terminal in the wrong - process group. - -gg. Bash now handles the case where the WCONTINUED flag causes waitpid() to - return -1/EINVAL at runtime as well as configuration time. - -hh. Fixed parser to generate an error when the pipeline `argument' to `!' or - `time' is NULL. - -ii. The shell now takes a little more care when manipulating file descriptors - greater than 9 with the `exec' builtin. - -jj. Fixed a bug that caused variable assignments preceding the `command' builtin - preceding a special builtin to be preserved after the command completed in - POSIX mode. - -kk. Fixed a bug that allowed variables beginning with a digit to be created. - -ll. Fixed a bug that caused a \ to be removed when parsing a $'...' - construct. - -mm. A shell whose name begins with `-' will now be a restricted shell if the - remainder of the name indicates it should be restricted. - -nn. Fixed a bug that could cause a core dump if FUNCNAME were changed or unset - during a function's execution. - -oo. Fixed a bug that caused executing a `return' in a function to not execute - a RETURN trap. The RETURN trap is inherited by shell functions only if - function tracing is globally enabled or has been enabled for that function. - -pp. Fixed cases where var[@] was not handled exactly like var, when var is a - scalar variable. - -qq. Fixed a bug that caused the first character after a SIGINT to be discarded - under certain circumstances. - -rr. Fixed exit status code so that a suspended job returns 128+signal as its - exit status (preventing commands after it in `&&' lists from being - executed). - -ss. Fixed a bug that caused the shell parser state to be changed by executing - a shell function as a result of word completion. - -tt. Fixed a long-standing bug that caused '\177' characters in variable - values to be discarded when expanded in double-quoted strings. - -uu. Fixed a bug that caused $RANDOM to be re-seeded multiple times in a - subshell environment. - -vv. Extensive changes to the job management code to avoid the pid-reuse and - pid-aliasing problems caused by retaining the exit status of too many jobs, - but still retain as many background job statuses as POSIX requires. - -ww. Fixed a parser bug in processing \ that caused things like - - ((echo 5) \ - (echo 6)) - - to not work correctly. - -xx. `pwd -P' now sets $PWD to a directory name containing no symbolic links - when in posix mode, as POSIX requires. - -yy. In posix mode, bash no longer sets $PWD to a name containing no symbolic - links if a directory is chosen from $CDPATH. - -zz. The word splitting code now treats an IFS character that is not space, - tab, or newline and any adjacent IFS white space as a single delimiter, as - SUSv3/XPG6 require. - -aaa. The `read' builtin now checks whether or not the number of fields read is - exactly the same as the number of variables instead of just assigning the - rest of the line (minus any trailing IFS white space) to the last - variable. This is what POSIX/SUS/XPG all require. - -bbb. Fixed a bug that caused `read' to always check whether or not fd 0 was a - pipe, even when reading from another file descriptor. - -ccc. Fixed a bug that caused short-circuiting of execution even if the return - value was being inverted. - -ddd. Fixed a bug that caused a core dump while decoding \W escapes in PS1 if - PWD was unset. - -eee. Fixed a bug in `read' that counted internal quoting characters for the - purposes of `read -n'. - -fff. Fixed a bug so that a function definition in a pipeline causes a child - process to be forked at the right time. - -ggg. Bash will not attempt to link against a readline library that doesn't - have rl_gnu_readline_p == 1. - -hhh. Fixed a bug that caused `read' to consume one too many characters when - reading a fixed number of characters and the Nth character is a backslash. - -iii. Fixed a bug that caused `unset' on variables in the temporary environment - to leave them set when `unset' completed. - -jjj. Fixed a bug that caused bash to close fd 2 if an `exec' failed and the - shell didn't exit. - -kkk. The completion code is more careful to not turn `/' or `///' into `//', - for those systems on which `//' has special meaning. - -lll. Fixed a bug that caused command substitution in asynchronous commands to - close the wrong file descriptors. - -mmm. The shell no longer prints status messages about terminated background - processes unless job control is active. - -nnn. Fixed a bug that prevented multiple consecutive invocations of `history -s' - from adding all the commands to the history list. - -ooo. Added a couple of changes to make arithmetic expansion more consistent in - all its contexts (still not perfect). - -ppp. Fixed a bug that caused the parser to occasionally not find the right - terminating "`" in an old-style command substitution. - -qqq. Fixed a bug that caused core dumps when the shell was reading its non- - interactive input from fd 0 and fd 0 was duplicated and restored using a - combination of `exec' (to save) and redirection (to restore). - -rrr. Fixed a problem that caused loops in sourced scripts to not be cleaned - up properly when a `return' is executed. - -sss. Change internal command substitution completion function to append a slash - to directory names in the command. - -2. Changes to Readline - -a. Fixed a bug that caused multiliine prompts to be wrapped and displayed - incorrectly. - -b. Fixed a bug that caused ^P/^N in emacs mode to fail to display the current - line correctly. - -c. Fixed a problem in computing the number of invisible characters on the first - line of a prompt whose length exceeds the screen width. - -d. Fixed vi-mode searching so that failure preserves the current line rather - than the last line in the history list. - -e. Fixed the vi-mode `~' command (change-case) to have the correct behavior at - end-of-line when manipulating multibyte characters. - -f. Fixed the vi-mode `r' command (change-char) to have the correct behavior at - end-of-line when manipulating multibyte characters. - -g. Fixed multiple bugs in the redisplay of multibyte characters: displaying - prompts longer than the screen width containing multibyte characters, - -h. Fix the calculation of the number of physical characters in the prompt - string when it contains multibyte characters. - -i. A non-zero value for the `rl_complete_suppress_append' variable now causes - no `/' to be appended to a directory name. - -j. Fixed forward-word and backward-word to work when words contained - multibyte characters. - -k. Fixed a bug in finding the delimiter of a `?' substring when performing - history expansion in a locale that supports multibyte characters. - -l. Fixed a memory leak caused by not freeing the timestamp in a history entry. - -m. Fixed a bug that caused "\M-x" style key bindings to not obey the setting - of the `convert-meta' variable. - -n. Fixed saving and restoring primary prompt when prompting for incremental - and non-incremental searches; search prompts now display multibyte - characters correctly. - -o. Fixed a bug that caused keys originally bound to self-insert but shadowed - by a multi-character key sequence to not be inserted. - -p. Fixed code so rl_prep_term_function and rl_deprep_term_function aren't - dereferenced if NULL (matching the documentation). - -q. Extensive changes to readline to add enough state so that commands - requiring additional characters (searches, multi-key sequences, numeric - arguments, commands requiring an additional specifier character like - vi-mode change-char, etc.) work without synchronously waiting for - additional input. - -r. Lots of changes so readline builds and runs on MinGW. - -s. Readline no longer tries to modify the terminal settings when running in - callback mode. - -t. The Readline display code no longer sets the location of the last invisible - character in the prompt if the \[\] sequence is empty. - -3. New Features in Bash - -a. Bash now understands LC_TIME as a special variable so that time display - tracks the current locale. - -b. BASH_ARGC, BASH_ARGV, BASH_SOURCE, and BASH_LINENO are no longer created - as `invisible' variables and may not be unset. - -c. In POSIX mode, if `xpg_echo' option is enabled, the `echo' builtin doesn't - try to interpret any options at all, as POSIX requires. - -d. The `bg' builtin now accepts multiple arguments, as POSIX seems to specify. - -e. Fixed vi-mode word completion and glob expansion to perform tilde - expansion. - -f. The `**' mathematic exponentiation operator is now right-associative. - -g. The `ulimit' builtin has new options: -i (max number of pending signals), - -q (max size of POSIX message queues), and -x (max number of file locks). - -h. A bare `%' once again expands to the current job when used as a job - specifier. - -i. The `+=' assignment operator (append to the value of a string or array) is - now supported for assignment statements and arguments to builtin commands - that accept assignment statements. - -j. BASH_COMMAND now preserves its value when a DEBUG trap is executed. - -k. The `gnu_errfmt' option is enabled automatically if the shell is running - in an emacs terminal window. - -l. New configuration option: --single-help-strings. Causes long help text - to be written as a single string; intended to ease translation. - -m. The COMP_WORDBREAKS variable now causes the list of word break characters - to be emptied when the variable is unset. - -n. An unquoted expansion of $* when $IFS is empty now causes the positional - parameters to be concatenated if the expansion doesn't undergo word - splitting. - -o. Bash now inherits $_ from the environment if it appears there at startup. - -p. New shell option: nocasematch. If non-zero, shell pattern matching ignores - case when used by `case' and `[[' commands. - -q. The `printf' builtin takes a new option: -v var. That causes the output - to be placed into var instead of on stdout. - -r. By default, the shell no longer reports processes dying from SIGPIPE. - -s. Bash now sets the extern variable `environ' to the export environment it - creates, so C library functions that call getenv() (and can't use the - shell-provided replacement) get current values of environment variables. - -4. New Features in Readline - -a. The key sequence sent by the keypad `delete' key is now automatically - bound to delete-char. - -b. A negative argument to menu-complete now cycles backward through the - completion list. - -c. A new bindable readline variable: bind-tty-special-chars. If non-zero, - readline will bind the terminal special characters to their readline - equivalents when it's called (on by default). - -d. New bindable command: vi-rubout. Saves deleted text for possible - reinsertion, as with any vi-mode `text modification' command; `X' is bound - to this in vi command mode. - ------------------------------------------------------------------------------- -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 that caused `bash -r' to turn on restrictions before - reading the startup files. - -e. 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 code 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 8e7b9a1a5..000000000 --- a/COMPAT~ +++ /dev/null @@ -1,309 +0,0 @@ -This document details the incompatibilities between this version of bash, -bash-4.0, and the previous widely-available versions, bash-1.14 (which is -still the `standard' version for a few Linux distributions) and bash-2.x. -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. If they appear in the initial - environment, the export attribute will be set, but if bash provides a - default value, they will remain local to the current shell. - -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; - any compound command is accepted. - -19. As of bash-3.0, the pattern substitution operators no longer perform - quote removal on the pattern before attempting the match. This is the - way the pattern removal functions behave, and is more consistent. - -20. After bash-3.0 was released, I reimplemented tilde expansion, incorporating - it into the mainline word expansion code. This fixes the bug that caused - the results of tilde expansion to be re-expanded. There is one - incompatibility: a ${paramOPword} expansion within double quotes will not - perform tilde expansion on WORD. This is consistent with the other - expansions, and what POSIX specifies. - -21. A number of variables have the integer attribute by default, so the += - assignment operator returns expected results: RANDOM, LINENO, MAILCHECK, - HISTCMD, OPTIND. - -22. Bash-3.x is much stricter about $LINENO correctly reflecting the line - number in a script; assignments to LINENO have little effect. - -23. By default, readline binds the terminal special characters to their - readline equivalents. As of bash-3.1/readline-5.1, this is optional and - controlled by the bind-tty-special-chars readline variable. - -24. The \W prompt string expansion abbreviates $HOME as `~'. The previous - behavior is available with ${PWD##/*/}. - -25. The arithmetic exponentiation operator is right-associative as of bash-3.1. - -26. The rules concerning valid alias names are stricter, as per POSIX.2. - -27. The Readline key binding functions now obey the convert-meta setting active - when the binding takes place, as the dispatch code does when characters - are read and processed. - -28. The historical behavior of `trap' reverting signal disposition to the - original handling in the absence of a valid first argument is implemented - only if the first argument is a valid signal number. - -29. In versions of bash after 3.1, the ${parameter//pattern/replacement} - expansion does not interpret `%' or `#' specially. Those anchors don't - have any real meaning when replacing every match. - -30. Beginning with bash-3.1, the combination of posix mode and enabling the - `xpg_echo' option causes echo to ignore all options, not looking for `-n' - -31. Beginning with bash-3.2, bash follows the Bourne-shell-style (and POSIX- - style) rules for parsing the contents of old-style backquoted command - substitutions. Previous versions of bash attempted to recursively parse - embedded quoted strings and shell constructs; bash-3.2 uses strict POSIX - rules to find the closing backquote and simply passes the contents of the - command substitution to a subshell for parsing and execution. - -32. Beginning with bash-3.2, bash uses access(2) when executing primaries for - the test builtin and the [[ compound command, rather than looking at the - file permission bits obtained with stat(2). This obeys restrictions of - the file system (e.g., read-only or noexec mounts) not available via stat. - -33. Bash-3.2 adopts the convention used by other string and pattern matching - operators for the `[[' compound command, and matches any quoted portion - of the right-hand-side argument to the =~ operator as a string rather - than a regular expression. - -34. Bash-4.0 allows the behavior in the previous item to be modified using - the notion of a shell `compatibility level'. - -35. Bash-3.2 (patched) and Bash-4.0 fix a bug that leaves the shell in an - inconsistent internal state following an assignment error. One of the - changes means that compound commands or { ... } grouping commands are - aborted. This is what Posix specifies. - -36. Bash-4.0 now allows process substitution constructs to pass unchanged - through brace expansion, so any expansion of the contents will have to be - separately specified, and each process subsitution will have to be - separately entered. - -37. Bash-4.0 now allows SIGCHLD to interrupt the wait builtin, as Posix - specifies, so the SIGCHLD trap is no longer always invoked once per - exiting child if you are using `wait' to wait for all children. - -38. Since bash-4.0 now follows Posix rules for finding the closing delimiter - of a $() command substitution, it will not behave as previous versions - did, but will catch more syntax and parsing errors before spawning a - subshell to evaluate the command substitution. - -39. The programmable completion code uses the same set of delimiting characters - as readline when breaking the command line into words, rather than the - set of shell metacharacters, so programmable completion and readline - should be more consistent. - -40. When the read builtin times out, it attempts to assign any input read to - specified variables, which also causes variables to be set to the empty - string if there is not enough input. Previous versions discarded the - characters read. diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ deleted file mode 100644 index d28e90ae1..000000000 --- a/CWRU/CWRU.chlog~ +++ /dev/null @@ -1,7508 +0,0 @@ - 7/27/2004 - --------- - -[bash-3.0 released] - - 7/28 - ---- -array.c - - in array_insert(), make sure the value to be added is non-NULL before - calling savestring() on it - -builtins/reserved.def - - fix description of `CDPATH' - -lib/readline/display.c - - when expanding a prompt that spans multiple lines with embedded - newlines, set prompt_physical_chars from the portion after the - final newline, not the preceding portion. Bug reported by - "Ralf S. Engelschall" - -make_cmd.c - - explicitly declare `lineno' in function prologue for make_case_command - -builtins/evalfile.c - - include `trap.h' for declaration for run_return_trap - -bashline.c - - fix a `return' without a value in enable_hostname_completion - -general.c - - include test.h for extern declaration for test_eaccess - -externs.h - - add declaration for zcatfd - -tests/{history,histexp}.tests - - unset HISTFILESIZE to avoid problems if a value of 0 is inherited - from the environment - - 7/30 - ---- -bashline.c - - small changes to glob_expand_word to perform tilde expansion before - attempting globbing - -builtins/Makefile.in - - fix the install-help target to not cd into the `helpfiles' - subdirectory, so a value of $INSTALL_DATA containing a relative - pathname (e.g., .././support/install.sh) remains valid - - 7/31 - ---- -subst.c - - new function, mbstrlen(s), returns length of a multibyte character - string - -include/shmbutil.h - - new macro, MB_STRLEN(s), calls mbstrlen or STRLEN as appropriate - -builtins/trap.def - - small change so that a first argument that's a valid signal number - (digits only -- no symbolic names) will be treated as a signal and - reverted back to the original handling disposition. Fixes debian - complaints - -subst.c - - call MB_STRLEN instead of STRLEN where appropriate in - parameter_brace_expand_length to handle multibyte characters properly - - call MB_STRLEN instead of strlen in verify_substring_values so that - negative substrings of strings with multibyte chars work properly - - 8/1 - --- -jobs.c - - describe_pid needs to write to stderr, not stdout (POSIX) - - start_job, since it's only used by builtins (fg/bg), needs to write - its output to stdout, not stderr (POSIX) - -sig.c - - add an `orig_flags' member to struct terminating_signal so the - original signal handling flags (SA_RESTART, etc.) can be preserved - on POSIX systems - - make sure to preserve the signal flags state in - initialize_terminating_signals and reset them for child processes - in reset_terminating_signals - -builtins/fc.def - - fixed an off-by-one error that caused `fc -l' to list one too many - history entries - - in posix mode, `fc' should not list any indication as to whether or - not history lines have been modified (POSIX) - - when in posix mode, the default editor for `fc' should be `ed' (POSIX) - -doc/bashref.texi - - updated the description of `trap' behavior when given a first - argument that is a valid signal number - - noted that `fc -l' won't indicate whether a history entry has been - modified if the shell is in posix mode - -builtins/command.def - - fixed bug: `command -v' is supposed to be silent if a command is not - found - -builtins/hash.def - - `hash' should print its `hash table empty' message to stderr - -lib/readline/misc.c - - back out 7/7 change to _rl_maybe_save_line; it breaks emacs-mode ^P - -general.c - - changed base_pathname so that it will return reasonable results for - non-absolute pathnames -- this is what is intended by all of its - callers - -arrayfunc.c - - fix array_variable_part to return NULL if it finds an invisible - variable in the hash table. Fixes seg fault caused by referring to - unset local variable using array notation - -{locale,variables}.c - - support LC_TIME as a special locale variable so HISTTIMEFORMAT tracks - the current locale - - 8/2 - --- -variables.c - - fixed small memory leak in makunbound() when a local array variable - is unset. Fix from William Park - -lib/readline/display.c - - fixed a problem when computing the number of invisible characters on - the first line of a prompt whose length exceeds the screen width - (should only happen when invisible characters occur after the - line wrap). Bug reported by agriffis@gentoo.org - -builtins/command.def - - `command -V' passes a new flag, CDESC_ABSPATH, which means to convert - to an absolute path - -builtins/type.def - - in posix mode, `type' and `command -v/-V' should not report - non-executable files, even if the execution code will attempt to - run them. Other posix shells do this - -doc/bashref.texi - - add note to POSIX Mode section describing behavior of type and command - when finding a non-executable file - -execute_cmd.c - - force extended_glob to 1 before calling binary_test in - execute_cond_node so that the right extended pattern matching gets - performed - - 8/3 - --- -braces.c - - make sure lhs[0] and rhs[0] are cast to `unsigned char' so chars - with values > 128 are handled correctly - -builtins/printf.def - - change bexpand() and printstr() to handle strings with a leading - '\0' whose length is non-zero, since that's valid input for the - `%b' format specifier - -subst.c - - fix a couple of instances of find_variable that didn't check the - result for an invisible variable - -variables.c - - BASH_ARGC, BASH_ARGV, BASH_SOURCE, BASH_LINENO no longer created as - invisible vars - -pcomplete.c - - make sure COMP_WORDS is not invisible when bind_comp_words returns - - ditto for COMPREPLY in gen_shell_function_matches - - 8/4 - --- -braces.c - - fix problem where ${ was ignored but did not increment the open - brace count. Bug reported by Tim Waugh - -variables.c - - if make_local_variable finds a variable in the correct context in - the right variable scope, make sure it's not invisible before - returning it - - 8/5 - --- -builtins/trap.def - - fixed usage message to show `action' as not optional, though it - actually is when not in posix mode (for a single argument) - - 8/7 - --- -configure.in - - kfreebsd-gnu has had its sbrk() problems fixed, and no longer needs - to be configured --without-gnu-malloc - -lib/readline/vi_mode.c - - in rl_vi_search, free any saved history line before starting the - search, so failure leaves you at that line, not the last line in - the history (assuming the current line is not the last history line). - Fix from llattanzi@apple.com to replace fix of 7/7 - - 8/9 - --- -support/Makefile.in - - renamed `mostly-clean' target to `mostlyclean' - - 8/11 - ---- -lib/readline/vi_mode.c - - make same change for EOL in multibyte character case of - rl_vi_change_char - - 8/12 - ---- -subst.c - - in verify_substring_values, fix off-by-one error checking bounds of - `offset', esp. in array values (e.g., getting the highest element - of an array) - - 8/16 - ---- -aclocal.m4 - - change BASH_CHECK_DEV_FD to make sure that file descriptors > 2 are - accessible via /dev/fd, unlike FreeBSD 5.x - -lib/sh/strftime.c - - make sure `zone' is initialized with gettimeofday before it is used - - work around HPUX lack of `altzone' and differing definitions of - `timezone' - -lib/malloc/malloc.c - - internal_memalign and memalign now take a `size_t' as their first - argument, which seems to be the prevailing standard - -lib/malloc/{malloc.c,shmalloc.h} - - change sh_memalign to take a `size_t' as its first argument - -builtins/echo.def - - if posixly_correct and xpg_echo are both set, don't try to interpret - any arguments at all, as POSIX/XOPEN requires (fix inspired by Paul - Eggert) - -doc/bashref.texi - - amend description of bash posix mode to include new echo behavior - -builtins/fg_bg.def - - allow bg to take multiple job arguments, as posix seems to specify, - placing them all in the background, returning the status of the last - one as the status of `bg' - -lib/readline/vi_mode - - fix _rl_vi_change_mbchar_case (multibyte-char version of `~' - command) to have the right behavior at EOL -- handle case where vi - mode backs up at the end of the line - - 8/18 - ---- -array.c - - check for an empty array in array_rshift before shifting elements - and adjusting max_index - - check for null array in array_subrange - -jobs.c - - fix raw_job_exit_status to not ignore exit status of the last - process in the pipeline when `set -o pipefail' is enabled - - 8/19 - ---- -lib/readline/mbutil.c - - make sure _rl_find_next_mbchar_internal has a valid multibyte - character before it checks whether or not it's a zero-width - wide character and adjusts point accordingly - - 8/24 - ---- -bashline.c - - new function, bash_directory_expansion, duplicates the expansions - performed on the directory name by rl_filename_completion_function - - call bash_directory_expansion in command_word_completion_function - if we decide we're doing tilde expansion (and any other - canonicalization) on the directory name being completed - - 8/25 - ---- -configure.in - - use new-style AC_CHECK_HEADER to check for sys/ptem.h (which requires - sys/stream.h). The correct checks are in the code, but autoconf - complains if sys/stream.h is not included, rather than simply - checking for the header's presence - - 8/26 - ---- -builtins/hash.def - - fix a bug that prevented `hash -d' from working right (as soon as - hash removed a command from the table, the bug caused it to be added - right back) - - 8/27 - ---- -doc/{bash.1,bashref.texi} - - explicitly note that conditional primaries that operate on files - operate on the targets of symbolic links rather than the links - themselves - - 8/30 - ---- -lib/readline/display.c - - fix multibyte calculation of `physchars' in prompt expansion, to - handle double-width multibyte characters correctly - - changes to rl_redisplay to handle prompts longer than the screenwidth - that might contain double-width multibyte characters. Fixes from - Tomohiro Kubota - - 9/6 - --- -subst.c - - change word_list_split to avoid really bad behavior caused by calling - list_append for each split word -- as the list gets long, you have - to traverse it every time. Keep a pointer to the end of the list and - and just tack onto it - - 9/8 - --- -lib/readline/complete.c - - change fnprint to calculate the displayed width of a filename in - the same way as fnwidth - -subst.c - - in verify_substring_values, when expanding ${array[@]:offset}, make - sure negative offsets count from one greater than the array's - maximum index so things like ${x[@}: -1} work to give the last element - (requires fixing array tests) - -builtins/common.c - - new error function, sh_wrerror(), for builtins to call when a write - error occurs - -builtins/common.h - - extern declaration for sh_wrerror() - -builtins/cd.def - - change builtin_error call to use sh_wrerror() - -builtins/echo.def - - report write errors with sh_wrerror() instead of just returning - failure - -builtins/printf.def - - change printstr to return failure (-1) or success (0) indication - rather than void - - report write errors when printstr() fails, return failure - - if any of the PF/printf calls fail, report write error and return - failure - -execute_cmd.c - - change execute_in_subshell so the subshell command inherits the - command timing flags from the enclosing COMMAND * - - 9/11 - ---- -[prayers for the victims of 9/11/2001] - -lib/sh/strnlen.c - - new file, implementation of GNU libc extension function strnlen - -lib/sh/Makefile.in, {config.h,configure,Makefile}.in, MANIFEST - - changes for strnlen - -configure.in - - version changed to 3.1-devel - -doc/bash.1, lib/readline/doc/rluser.texi - - added description of `-o plusdirs' to complete/compgen (thanks, - Arnold) - -parse.y - - new parser_state flag, PST_ASSIGNOK, if set indicates we're parsing - arguments to a builtin that accepts assignment statement arguments - - turn on PST_ASSIGNOK in read_token_word when appropriate - - turn off PST_ASSIGNOK in read_token when appropriate - - don't attempt to parse a compound assignment specially unless we're - in a position where an assignment statement is acceptable, or - PST_ASSIGNOK is set - - 9/13 - ---- -variables.c - - make BASH_ARGC, BASH_ARGV, BASH_LINENO, and BASH_SOURCE - non-unsettable, since the shell uses those values internally - -expr.c - - make exponentiation right-associative, as is apparently correct - - 9/16 - ---- -arrayfunc.c - - make sure convert_var_to_array marks the environment as needing - recreation if the converted variable was exported - - 9/17 - ---- -braces.c - - mark ${ as introducing an additional level of braces only if it's - not in a quoted string -- quoted strings are handled before brace - matching is done - -parse.y - - fixed an obscure problem in history_delimiting_chars where the `in' - in a case statement could have a semicolon added after it, if the - `case word' was on a previous line - -support/config.guess - - support for newest versions of tandem non-stop kernel - -lib/readline/display.c - - in compute_lcd_of_matches, explicitly cast `text' to `char *' before - passing it to rl_filename_dequoting_function - -lib/readline/terminal.c - - bind the key sequence sent by the keypad `delete' key to delete-char - (same as ^D in emacs mode) - -builtins/ulimit.def - - in print_all_limits, don't print anything if get_limit returns - -1/EINVAL, indicating that the kernel doesn't support that particular - limit - - add -i (max number of pending signals), -q (max size of posix msg - queues), -x (max number of file locks) for systems (Linux) that - support them - -doc/{bash.1,bashref.texi} - - fix description of correspondence between FUNCNAME, BASH_LINENO, - and BASH_SOURCE indices in description of BASH_LINENO - - 9/18 - ---- -lib/sh/shquote.c - - don't quote CTLESC and CTLNUL with CTLESC in sh_backslash_quote, as - long as the resultant string never gets sent to the word expansion - functions without going through the shell parser - -externs.h - - add extern declarations for strnlen and strpbkrk from lib/sh - -subst.[ch] - - changes to handle case where IFS consists of multibyte characters. - Changed: string_extract_verbatim, split_at_delims, - string_list_dollar_star, string_list_dollar_at, list_string, - get_word_from_string, setifs - - 9/19 - ---- -mailcheck.c - - change file_mod_date_changed to reset the cached mail file data if - the file size drops to zero - -lib/readline/complete.c - - change append_to_match so that a non-zero value for - rl_completion_suppress_append will cause no `/' to be appended to a - directory name - -bashline.c - - experimental change to suppress appending a slash for a completed - filename that is found in PATH as well as a directory in the current - directory under certain circumstances: a single instance found in - $PATH when `.' is not in $PATH, and multiple instances found in the - $PATH, even when `.' is in the $PATH - - 9/24 - ---- -command.h - - new word flag: W_ASSIGNRHS, means word is rhs of assignment statement - - new word flag: W_NOTILDE, means word is not to be tilde expanded - - new word flag (internal): W_ITILDE, means the next character is a - tilde that should be expanded - -general.c - - new set of tilde suffixes for use when parsing the RHS of an - assignment statement and =~ should not be subject to tilde expansion - - if ASSIGN_P argument to bash_tilde_expand is 2, use tilde prefixes - for parsing RHS of assignment statement - -general.[ch] - - new function bash_tilde_find_word, drop-in replacement for - tilde_find_word - -subst.c - - call bash_tilde_expand with secord argument of 2 when expanding rhs - of an assignment statement, so tildes after second and subsequent - `=' in an assignment are not expanded - - new function, expand_string_assignment, to expand the rhs of an - assignment statement - - add `~' to EXP_CHAR, the characters that will cause the word - expansion functions to be called - - move tilde expansion into expand_word_internal instead of many - different calls to bash_tilde_expand scattered across different - functions. NOTE: This means that double quotes surrounding a - {paramOPword} expansion will cause tilde expansion to NOT be - performed on `word'. I think this is right, what POSIX specifies, - and consistent with the behavior of other characters in the rhs - -execute_cmd.c - - take out calls to bash_tilde_expand before calling word expansion - functions - - 9/26 - ---- -execute_cmd.c - - make sure to call UNBLOCK_CHILD before returning on a pipe creation - failure in execute_pipeline - - 9/27 - ---- -variables.c - - change get_bash_command to deal with the_printed_command_except_trap - being NULL - -execute_cmd.c - - fix execute_simple_command to deal with the_printed_command being - NULL when assigning to the_printed_command_except_trap -- fixes - seg fault in savestring() - -parse.y - - change the parser so that the closing `)' in a compound variable - assignment delimits a token -- ksh93 does it this way - -doc/{bash.1,bashref.texi} - - change description of tilde expansion to note that expansion is - attempted only after the first =~ in an assignment statement - -builtins/declare.def - - when assigning to an array variable with declare -a x=(...), make - sure the last character in the rhs of the variable assignment is - `)', not just that it appears somewhere - - 9/28 - ---- -command.h - - add a `W_NOEXPAND' flag to inhibit all expansion except quote removal - - add a `W_COMPASSIGN' flag to denote a word is a compound assignment - statement - -parse.y - - set W_COMPASSIGN on words that appear to be compound assignments - -subst.c - - pass W_NOXPAND and W_COMPASSIGN through end of expand_word_internal - -subst.[ch] - - new function, expand_assignment_string_to_string, calls - expand_string_assignment and then string_list on the result - -variables.c - - assign_in_env now calls expand_assignment_string_to_string - - 9/30 - ---- -builtins/common.c - - change get_job_spec so the null job `%' once again means the current - job - - 10/1 - ---- -subst.c - - do_assignment_internal now takes a WORD_DESC * as its first - argument, and uses its `word' member as the assignment string - - change expand_word_list_internal to call do_word_assignment instead - of do_assignment, passing it `word' instead of, e.g., `word->word' - - change extract_array_assignment_list to just return the passed - string minus a trailing `)' if the last character is a right - paren - - change do_assignment_internal to call extract_array_assignment_list - -subst.[ch] - - change do_assignment and do_assignment_no_expand to take a `char *' - instead of `const char *' first argument; change extern prototypes - - new function, do_word_assignment, takes a WORD_DESC * and calls - do_assignment_internal on it; add extern declaration with prototype - -general.h - - new typedef, sh_wassign_func_t, like sh_assign_func_t but takes a - WORD_DESC * as its first argument - -variables.[ch] - - assign_in_env now takes a WORD_DESC * as its first argument - - 10/2 - ---- -command.h - - new word flag, W_ASSNBLTIN, denotes that the word is a builtin - command (in a command position) that takes assignment statements - as arguments, like `declare' - - new word flags, W_ASSIGNARG, denotes that word is an assignment - statement given as argument to assignment builtin - -execute_cmd.c - - set W_ASSNBLTIN flag in fix_assignment_words if necessary (if there - are any arguments that are assignment statements) - - set W_ASSIGNARG flag in fix_assignment_words if necessary - -subst.c - - new function, do_compound_assignment, encapsulates the necessary - code to perform a compound array assignment (including creation of - local variables); called from do_assignment_internal - - to fix the double-expansion problem with compound array assignments - that are arguments to builtins like `declare', changed - shell_expand_word_list to treat those arguments like assignment - statements (with proper creation of local variables inside shell - functions) and pass the attribute-setting portion of the statement - onto the builtin. This is what ksh93 appears to do, from inspection - of the `ksh93 -x' output - -execute_cmd.c - - fix execute_simple_command: in case of pipeline or async command, - when forking early, set `subshell_environment' so that it can contain - both SUBSHELL_PIPE and SUBSHELL_ASYNC -- the two should not be - mutually exclusive. Fixes bug reported by pierre.humblet@ieee.org - - remove references to last_pid, old_command_subst_pid; use NO_PID as - a sentinel value to decide whether or not a child process has been - created and needs to be waited for. Submitted by - pierre.humblet@ieee.org to fix recycling-pid problem on cygwin - -doc/{bash.1,bashref.texi} - - fixed documentation of `@(pattern)' extended globbing operator -- - it succeeds if the string matches one of the patterns, not exactly - one. This is what ksh93 does, too - -lib/readline/complete.c - - fixed rl_menu_complete so that a negative argument cycles backwards - through the list - - 10/3 - ---- -subst.c - - use W_COMPASSIGN flag in do_assignment_internal instead of deciding - lexically which assignments are compound array assignments - - 10/6 - ---- -support/shobj-conf - - additions for System V.5 from Boyd Gerber - -subst.c - - in command_substitute, if subshell_environment includes - SUBSHELL_ASYNC, call make_child with the `async_p' argument set to - non-zero. This keeps command substitutions for async commands or - pipelines from trying to give the terminal back to the shell's - pgrp. make sure to save and restore last_asynchronous_pid. Fix - suggested by - - 10/7 - ---- -config.h.in - - add a placeholder definition for WCONTINUED_BROKEN - - 10/9 - ---- -aclocal.m4 - - add BASH_CHECK_WCONTINUED, checks for glibc bug where WCONTINUED is - defined but rejected as invalid by waitpid(2) - -configure.in - - add call to BASH_CHECK_WCONTINUED, defines WCONTINUED_BROKEN - -redir.c - - experimental change to add_undo_redirect to save manipulations to - file descriptors >= SHELL_FD_BASE (10) on the list of redirections - to be undone even if `exec' causes the list to be discarded - -doc/{bash.1,bashref.texi} - - note that redirections using file descriptors > 9 should be used - carefully, because they might conflict with file descriptors the - shell uses internally - - 10/11 - ----- -parse.y - - fix pipeline_command production to handle case where `pipeline' - as `argument' of `!' or `time' is null (e.g., a syntax error not - handled by the grammar) - - 10/13 - ----- -lib/readline/readline.c - - new internal variable, _rl_bind_stty_chars; if non-zero, bind the - terminal special characters to readline equivalents at startup - - change readline_default_bindings() and reset_default_bindings() to - understand _rl_bind_stty_chars - -lib/readline/rlprivate.h - - new extern declaration for _rl_bind_stty_chars - -lib/readline/rltty.c - - change rl_prep_terminal to add support for _rl_bind_stty_chars - - 10/15 - ----- -lib/readline/bind.c - - new bindable variable, `bind-tty-special-chars', bound to value of - _rl_bind_stty_chars - -doc/bash.1,lib/readline/doc/{readline.3,rluser.texi} - - documented new readline variable `bind-tty-special-chars' - -builtins/pushd.def - - make the first check for option `--' skip the rest of option - checking - - 10/16 - ----- -lib/readline/shell.c - - change sh_set_lines_and_columns to prefer setenv, which has - predictable memory allocation behavior, to putenv, which does not - - 10/19 - ----- -variables.c - - change push_exported_var so that a tempenv variable has to have the - export attribute set (which they all do -- something to look at) and - the `propagate' attribute set to be propagated down to the next - scope - -execute_cmd.c - - change execute_builtin so that if CMD_COMMAND_BUILTIN is set in the - passed flags argument, call pop_scope with a value that says the - builtin is not special, since `command' means that preceding variable - assignments don't persist in the environment. Fixes problem with - variable assignments preceding command preceding special builtin - keeping those variable assignments around (when in posix mode) - - 10/20 - ----- -lib/sh/shquote.c - - new function, sh_mkdoublequoted, brackets a given string with - double quotes and returns a new string. Flags argument, if non- - zero, means to quote embedded double quotes with backslashes - -externs.h - - new extern declaration for sh_mkdoublequoted - -parse.y - - use sh_mkdoublequoted after calling localeexpand() - -lib/sh/strtrans.c - - change ansicstr to understand that (flags & 4) != 0 means to remove - backslash from unrecognized escape sequences - -general.c - - fix logic problem in assignment() that caused non-variable-starter - characters to be allowed, resulting in things like `1=xxx' creating - a variable `1' in the hash table - - 10/21 - ----- -bashline.c - - don't call programmable_completions with an assignment statement - argument - - 10/22 - ----- -lib/readline/rltty.c - - in prepare_terminal_settings, turn echoing on (readline_echoing_p) - if get_tty_settings fails because the input is not a terminal - - 10/24 - ----- -lib/readline/util.c - - include rlmbutil.h for multibyte definitions - - new function, _rl_walphabetic, wide char version of rl_alphabetic - -lib/readline/mbutil.c - - new function, _rl_char_value(buf, ind), returns value of (possibly - multibyte) character at buf[ind] - -lib/readline/rlmbutil.h - - extern defines for _rl_walphabetic and _rl_char_value for when - multibyte chars are not being used - - new wrapper definitions for _rl_find_next_mbchar (MB_NEXTCHAR) and - _rl_find_prev_mbchar (MB_PREVCHAR) that try to avoid unneeded - function calls - -lib/readline/text.c - - fix rl_foward_word to work with multibyte characters (or in a - multibyte locale) using above utility functions - - fix rl_backward_word to work with multibyte characters (or in a - multibyte locale) using above utility functions - - 10/26 - ----- -parse.y - - fix parse_matched_pair so that it doesn't swallow \ when - parsing a $'...' construct (call shell_getc with different arg) - - 10/28 - ----- -lib/glob/glob.c - - after some (compiled-in) threshold, glob_vector will stop using - alloca to allocate `struct globval's and will switch to using - malloc, with appropriate cleanup before returning - -subst.c - - don't expand tildes after `=' in expand_word_internal, even if the - W_TILDEEXP flag is set, unless it's the first tilde in a word - marked W_ASSIGNMENT - - 10/31 - ----- -lib/readline/text.c - - make sure rl_point doesn't go below 0 in rl_delete_horizontal_space - (from SUSE, but not sent in) - -shell.c - - make sure shell_is_restricted skips over a single leading `-' in - the shell name (from SUSE, but not sent in) - -lib/readline/display.c - - disable `fast redisplay' at the end of the line if in a locale that - supports multibyte characters (from SUSE, but not sent in) - -lib/readline/histexpand.c - - fix a problem with finding the delimiter of a `?' substring when - compiled for multibyte characters (from SUSE, but not sent in) - - 11/1 - ---- -lib/readline/display.c - - correct some assignments to _rl_last_c_pos: when in a multibyte - locale, it's used as an absolute cursor position; when not using - multibyte characters, it's a buffer offset. I should have caught - this when the multibyte character support was donated - - 11/5 - ---- -general.c - - change `assignment()' to accept `+=' assignment operator - -arrayfunc.[ch] - - bind_array_variable and assign_array_element both take a new `flags' - argument - - assign_array_var_from_string, assign_array_from_string, and - assign_array_var_from_word_list now all take a new `flags' argument - - change assign_array_var_from_word_list to understand how to append - to an array variable - - change assign_array_var_from_string to understand how to append - to an array variable. It does not unset the previous value if - appending, allowing both old values to be changed and new ones to - be added - -subst.h - - new flag #defines to use for evaluating assignment statements - -{subst,variables}.c, builtins/{declare,read}.def - - change callers of assign_array_element and bind_array_variable - - change do_compound_assignment to understand assignment flags - - change do_assignment_internal to set assignment flags and pass them - to underlying functions - -pcomplete.c,builtins/{declare,read}.def - - fix callers of assign_array_var_from_string, assign_array_var_from_word_list - -variables.[ch] - - make_variable_value now takes a new `flags' argument - - make_variable_value now understands how to append to a particular - variable, using the old value - - bind_variable_value now takes a new `flags' argument - - change make_variable_value to understand ASS_APPEND flag - - bind_variable now takes a new `flags' argument - - bind_variable_internal now takes a new `flags' argument - -arrayfunc.c - - change callers of make_variable_value to add flags arg - -builtins/declare.def - - change callers of bind_variable_value to add flags arg - -{execute_cmd,mailcheck,pcomplete,shell,subst,variables}.c,parse.y -builtins/{cd,command,declare,getopts,read,set,setattr}.def - - change callers of bind_variable to add flags arg - -variables.c - - change callers of bind_variable_internal - - change bind_variable_internal to pass assignment flags on to - make_variable_value - - change assign_in_env to treat `var+=value' like `var=value' - -arrayfunc.c - - break code that actually constructs the new value and assigns it - to a particular array index out into a new functions: - bind_array_var_internal. This fakes out make_variable_value by - passing a dummy SHELL_VAR * so it can do proper appending and other - += processing - - changes to assign_array_var_from_string to accept and process as if - they were `standalone' assignment statements array assignment words - of the form [ind]+=val - - 11/7 - ---- -builtins/declare.def - - added support for `declare [flags] var+=value'. `Flags' are applied - before the assignment is performed, which has implications for things - like `-i' -- if -i is supplied, arithmetic evaluation and increment - will be performed - -builtins/setattr.def - - add support for `+=' assignment for rest of `assignment builtins': - export, readonly - - 11/12 - ----- -lib/readline/display.c - - make sure prompt_physical_chars and prompt_invis_chars_first_line - are reset to 0 if the prompt string passed to rl_expand_prompt is - NULL or empty - - 11/14 - ----- -{configure,config.h}.in - - check for `raise', define HAVE_RAISE if available - -lib/intl/dcigettext.c - - make sure `raise' is defined if HAVE_RAISE is not before - eval-plurah.h is included - -lib/malloc/trace.c - - put extern declaration for imalloc_fopen inside the MALLOC_TRACE - #ifdef - - 11/16 - ----- -lib/intl/Makefile.in - - make sure SHELL is defined to cpp - -lib/intl/dcigettext.c - - make sure we use getcwd() even if HAVE_GETCWD is not defined after - including config.h; if SHELL is defined, #define HAVE_GETCWD - - 11/18 - ----- -trap.[ch] - - new function, int signal_in_progress(int sig), returns TRUE if the - trap handler for signal SIG is currently executing - - 11/19 - ----- -redir.c - - slightly change do_redirection_internal to set the close-on-exec - flag for file descriptors > 2 used to save file descriptors < 2 - using explicit redirections (e.g., `exec 3>&1'). This keeps file - descriptors pointing to pipes from being left open but doesn't - change the shell's file descriptor semantics - - 11/20 - ----- -doc/{bash.1,bashref.texi} - - correct some minor typos, forwarded from doko@debian.org - - 11/22 - ----- -doc/bash.1,lib/readline/doc/{readline.3,rluser.texi} - - documented detail that yank-last-arg and yank-nth-arg use the history - arg expansion code (and, as a result, are subject to restrictions - of the history-comment character) - - 11/23 - ----- -execute_cmd.c - - changes so that BASH_COMMAND preserves its value into a DEBUG trap: - for commands, arithmetic for command expressions, select commands, - case commands, (( commands, [[ commands, simple commands - - 11/24 - ----- -doc/{bash.1,bashref.texi} - - changed description of `set' builtin slightly so that it is clear - that only variables are displayed in posix mode and that read-only - variables can't be reset by simply sourcing the output of `set' - -lib/sh/strftime.c - - don't try to redefine `inline' if it's already defined - - 11/26 - ----- -execute_cmd.c - - fix execute_function to check funcname_a after function execution, - since FUNCNAME can be changed or unset within a function - - 11/27 - ----- -builtins/evalfile.c - - make same changes as 11/26, this time to _evalfile - -execute_cmd.c - - change execute_function to run the return trap after a function - completes execution even if the shell is compiled without DEBUGGER - defined - -trap.c - - change reset_or_restore_signal_handlers so that the RETURN trap is - not inherited by command substitution when DEBUGGER is not defined - - 11/30 - ----- -lib/readline/misc.c - - fix memory leaks in _rl_free_history_entry and rl_maybe_replace_line - caused by not freeing `timestamp' member of history entry - - make sure timestamp is initialized to NULL in rl_maybe_save_line - - 12/1 - ---- -execute_cmd.c - - fix execute_function so a function calling `return' will run the - RETURN trap, if one's defined - -doc/{bash.1,bashref.texi} - - fix description of RETURN trap in various places to indicate that it's - only inherited by shell functions if function tracing is on globally - or has been enabled for that function - - fix documentation to indicate that the DEBUG and RETURN traps are - inherited under the same conditions - -execute_cmd.c - - a function does not inherit the RETURN trap if a DEBUG trap is - currently running - - 12/2 - ---- -lib/glob/xmbsrtowcs.c - - change xmbsrtowcs to handle the one case where malloc can fail - (though it should not matter) -- don't try to free a null pointer - - 12/9 - ---- -subst.c - - fix get_var_and_type to handle var[@], where `var' is a scalar - variable, identically to var -- all calling expansions can now - handle var[@] like var. Bug reported by agriffis@gentoo.org - - 12/10 - ----- -lib/readline/bind.c - - make new-style "\M-x" keybindings obey `convert-meta' settings - (bug reported by twaugh@redhat.com) - - 12/14 - ----- -builtins/set.def - - added description of `-' option to help text - -builtins/shopt.def - - fix bug that caused `gnu_errfmt' to not be compiled in unless - READLINE is defined - - 12/16 - ----- -subst.c - - fixed a typo in string_extract_verbatim in first call to MBLEN - (used `slen - 1' instead of `slen - i') - - 12/17 - ----- -subst.c - - avoid some calls to strlen if the value is only being used for - ADVANCE_CHAR and MB_CUR_MAX == 1 (since ADVANCE_CHAR doesn't need - it unless multibyte characters are possible) - - change string_extract_verbatim so it takes the length of the string - as a parameter, so we don't have to recompute the length of the same - string over and over again when doing word splitting (that kills if - it's a long string) - - 12/18 - ----- -subst.c - - in string_list_dollar_star, make sure to null-terminate the - separator if the character is longer than one byte - - 12/22 - ----- -doc/{bash.1,bashref.texi} - - changed text in quoting section explaining that double quotes do - not prevent history expansion from taking place, and that backslashes - escaping ! are not removed - - 12/28 - ----- -shell.c - - set gnu_error_format to 1 if running under emacs. This should allow - the emacs `next-error' stuff to work, at least for interactive shells - -parse.y - - change yy_stream_get to set interrupt_immediately before calling - getc_with_restart when the shell is interactive. This avoids the - synchronization problem caused by the call to QUIT in read_a_line, - which results in the first character after a SIGINT/^C to be - dropped - - 12/30 - ----- -builtins/mkbuiltins.c - - changes to write long documentation to arrays as a single string by - default, rather than an array of strings -- enabled by default - - new option, -S, to restore old behavior of writing multiple strings - for long documentation - - changes to avoid filenames written when the separate-filenames option - (-H) has been supplied being run through gettext - -configure.in - - new cofiguration option, --enable-single-help-strings (on by default), - causes help text to be stored as a single string (or smaller set than - one string per line) - -builtins/Makefile.in - - pass `-S' to mkbuiltins if single-help-strings is turned off - -doc/bashref.texi - - documented new `single-help-strings' configure option - - 1/3/2005 - -------- -jobs.c - - make wait_for return a non-zero status if the job or processed - waited for is suspended. Returns 128 + stop signal. This fixes - the problem with `echo one && sleep 5 && echo two' displaying - `two' after the sleep is suspended - - 1/5 - --- -print_cmd.c - - change indirection_level_string so the code duplicates the first - character of $PS4 to indicate the indirection level, rather than - the first byte - - 1/8 - --- -variables.c - - new special variable hook function for COMP_WORDBREAKS; sets - rl_completer_word_break_characters back to NULL when the variable - is unset - - change bind_variable_value to understand dynamic variables with - assign_function set, and handle them correctly. If the variable is - being appended to, use make_variable_value to create the new - value - - change bind_variable_internal to understand dynamic variables with - assign_function set, and handle them the same way - - RANDOM and LINENO now get the integer attribute, so appending works - as expected - - ditto for HISTCMD, MAILCHECK, OPTIND - -lib/readline/display.c - - change _rl_make_prompt_for_search to set prompt_physical_chars - appropriately - - rl_save_prompt and rl_restore_prompt save and restore - prompt_prefix_length - - change redraw_prompt to use rl_save_prompt and rl_restore_prompt - - change rl_restore_prompt to set the `save' variables back to - NULL/0 so code can check whether or not the prompt has been saved - - change rl_message and rl_clear_message to save and restore the - prompt if the caller has not already done it (using a simple - semaphore-like variable) - - change rl_message to call expand_prompt, so that local_prompt and - local_prompt prefix are set before calling the redisplay functions, - in case the prompt is longer than a screenwidth (fixes bug - reported to debian by epl@unimelb.edu.au) - -lib/readline/doc/rltech.texi - - make sure to note that rl_save_prompt should be called before - rl_message, and rl_restore_prompt before rl_clear_message - -pcomplete.c - - make sure to save and restore the parser state around the call to - execute_shell_function in gen_shell_function_matches. Fixes bug - reported by a050106.1.keeLae3x@captaincrumb.com (cute) - -lib/readline/readline.c - - fix _rl_dispatch_subseq in the case where we're recursing back up - the chain (r == -2) and we encounter a key shadowed by a keymap, - but originally bound to self-insert. Calling rl_dispatch with - ANYOTHERKEY as the first argument will call rl_insert, but with - ANYOTHERKEY (256) as the char to insert. Use the shadow keymap - and set things up to dispatch to rl_insert with the shadowed key - as the argument. Fixes the bug reported by Thomas Glanzmann - (sithglan@stud.uni-erlangen.de) - - 1/13 - ---- -command.h - - new word flag: W_HASQUOTEDNULL - -make_cmd.c - - new function to allocate a WORD_DESC * without doing anything with a - containing string: alloc_word_desc - -make_cmd.h - - extern declaration for alloc_word_desc - -dispose_cmd.c - - new function to just free a WORD_DESC * without freeing the contained - string: dispose_word_desc - -dispose_cmd.h - - extern declaration for dispose_word_desc - -subst.c - - change some places to use alloc_word_desc - - make same changes to word_list_quote_removal as were made to - word_list_split - - set W_HASQUOTEDNULL when a word is created with w->word[0] == - CTLNUL and w->word[1] == '\0' - -subst.c - - parameter_brace_expand_word now returns a WORD_DESC * -- changed - callers to understand - - parameter_brace_expand_indir now returns a WORD_DESC * -- changed - callers to understand - - parameter_brace_expand_rhs now returns a WORD_DESC * -- changed - callers to understand - - remove W_HASQUOTEDNULL from a word's flags when remove_quoted_nulls - is called on the word's enclosed string - - 1/15 - ---- -subst.c - - param_expand now returns a WORD_DESC * -- changed callers to - understand - - parameter_brace_expand now returns a WORD_DESC * -- changed - callers to understand - - in expand_word_internal, only call remove_quoted_nulls after a word - is returned with W_HASQUOTEDNULL - - changes to pass W_HASQUOTEDNULL flag out of expand_word_internal; - changed callers to call remove_quoted_nulls only if return value has - W_HASQUOTEDNULL set. This is a mostly-complete fix for the - long-standing CTLNUL confusion between a quoted null expansion and - the expansion of a variable with a literal '\177' in its value - - change string_list_dollar_at to compute the separator character the - same way as string_list_dollar_star: using the already-computed - values generated in setifs() - - when expanding unquoted $*, if $IFS is empty, check whether or not - we're eventually going to split the results (e.g., on the rhs of an - assignment statement) and concatenate the positional parameters as - if the expansion were within double quotes if we're not going to - split - -tests/iquote.tests - - test cases based on old bug reports about the quoted-null vs. 0177 - problem the recent code fixes - - 1/16 - ---- -dispose_cmd.c - - set w->word to 0 before putting a WORD_DESC * back in the cache in - dispose_word_desc; changed callers to delete those assignments - -variables.c - - change assign_random and get_random_value so that the random number - generator only gets re-seeded once in a subshell environment, and - assigning a value to RANDOM counts as seeding the generator. This - makes the sequences a little more predictable - - 1/20 - ---- -lib/readline/history.c - - fix replace_history_entry, remove_history to return NULL if - passed index is < 0 - - 1/22 - ---- -lib/sh/netconn.c - - fix isnetconn() to understand that getpeername can return ENOTCONN - to indicate that an fd is not a socket - -configure.in - - set BUILD_DIR to contain backslashes to escape any spaces in the - directory name -- this is what make will accept in targets and - prerequisites, so it's better than trying to use double quotes - - set SIZE to the appropriate value if some cross-compiling tool - chain is being used; `size' by default (can be overridden by - SIZE environment variable) - -Makefile.in - - use $(SIZE) instead of size; set SIZE from configure - - 1/31 - ---- -arrayfunc.c - - in array_value_internal, return NULL right away if the variable's - value is NULL, instead of passing a null string to add_string_to_list - - 2/1 - --- -jobs.h - - new struct to hold stats and counters for child processes and jobs - - change some uses of global and static variables to use members of - new struct (struct jobstats) - - 2/2 - --- - -jobs.[ch] - - change PRUNNING to PALIVE - - new define INVALID_JOB - - new macro get_job_by_jid(ind), currently expands to jobs[ind] - - new define J_JOBSTATE, operates on a JOB * like JOBSTATE operates on - a job index - - new function, reset_job_indices, called from delete_job if - js.j_lastj or js.j_firstj are removed - - change various functions to keep counters and stats in struct jobstats - -pcomplete.c, builtins/common.c, builtins/{exit,fg_bg,jobs,kill,wait}.def - - change global variables (e.g., job_slots) to struct members - (e.g., js.j_jobslots) - - use INVALID_JOB define where appropriate - - use get_job_by_jid and J_JOBSTATE where appropriate - -trap.c - - change reset_or_restore_signal_handler to not free the exit trap - string if the function pointer is reset_signal, which is used when - the trap strings shouldn't be freed, like in command substitution - - 2/4 - --- -jobs.c - - new function, realloc_jobs_list, copies jobs array to newly-allocated - memory shrinking (or growing) size to have next multiple of JOB_SLOTS - greater than js.j_njobs - - change compact_jobs_list to just call reap_dead_jobs and then - realloc_jobs_list, simplifying it considerably - - discard_pipeline now returns `int': the number of processes freed - - slightly changed the logic deciding whether or not to call - compact_jobs_list: now non-interactive shells will compact the - list if it reaches MAX_JOBS_IN_ARRAY in size - -parse.y - - move test for backslash-newline after pop_string in shell_getc so - that things like - - ((echo 5) \ - (echo 6)) - - work right - - 2/8 - --- -jobs.h - - new structs for holding status of exited background processes, as - POSIX specifies - - new job flag: J_ASYNC - -jobs.c - - new functions to manipulate struct holding status of exited - background processes - - new members in struct jobstats to hold pointer to last created job - and last created asynchronous job - - initialize js.c_childmax in initialize_job_control - - if the `async' arg to stop_pipeline is non-null, set the J_ASYNC - flag in the job struct - - set js.j_last_made_job and js.j_last_asynchronous_job in - stop_pipeline - - new function: find_last_proc, returns the PROCESS * to the last proc - in a job's pipeline - - changed find_last_pid to call find_last_proc - - change delete_job to call bgp_add on the last proc of the job being - deleted - - change delete_all_jobs and wait_for_background_pids to call bgp_clear - - 2/9 - --- -jobs.c - - change wait_for_single_pid to look for pid in bgpids.list (using - bgp_search()) if find_pipeline returns NULL - - 2/10 - ---- -support/shobj-conf - - change the solaris-gcc stanza so that it auto-selects the appropriate - options for ld depending on which `ld' gcc says it's going to run - - 2/11 - ---- -jobs.h - - add support for PS_RECYCLED as a process state, add PRECYCLED macro - to test it. Change PALIVE and PRUNNING macros to not count processes - in PS_RECYCLED state - -execute_cmd.c - - restore use of last_pid as sentinel value; use NO_PID as sentinel - only if RECYCLES_PIDS is defined - -jobs.c - - change find_job to return a pointer to the PROCESS the desired pid - belongs to, analogous to find_pipeline returning pointer to JOB - - change find_job callers to add extra argument - - change running_only arguments to find_pipeline and find_job to - alive_only, since we don't want recycled pids returned here and it - better describes the result - - new function find_process, calls find_pipeline and searches the - returned pipeline for the PROCESS * describing the desired pid - - in make_child, if fork() returns the same pid as the value of - last_asynchronous_pid when RECYCLES_PIDS is defined, avoid pid - aliasing by resetting last_asynchronous_pid to 1 - - use PRUNNING instead of child->running, since we, for the most - part, don't want to consider recycled pids (e.g., in make_child()) - - call find_process instead of find_pipeline in waitchld() - - use PEXITED(p) instead of testing p->running == PS_DONE - - in make_child, call bgp_delete to remove a just-created pid from the - last of saved pid statuses - - in add_process, check whether or not pid being added is already in - the_pipeline or the jobs list (using find_process) and mark it as - recycled if so - - This set of fixes mostly came from Pierre Humblet - to fix pid aliasing and reuse problems on - cygwin - -variables.c - - set $_ from the environment if we get it there, set to $0 by - default if not in env - -doc/{bashref.texi,bash.1} - - a couple of clarifying changes to the description of $_ based on - comments from Glenn Morris - - 2/15 - ---- -shell.c - - use strstr instead of strmatch when checking whether $EMACS contains - `term' -- simpler and faster - - 2/18 - ---- -builtins/cd.def - - implement posix requirement that `pwd -P' set $PWD to a directory - name containing no symlinks - - add new function, setpwd(), just sets (and changes exported value) - of PWD - -doc/bashref.texi - - add note to posix mode section about pwd -P setting $PWD - -doc{bash.1,bashref.texi} - - added note that BASH_ARGC and BASH_ARGV are only set in extended - debug mode - - expand description of extdebug option to include everything changed - by extended debug mode - - 2/19 - ---- -pathexp.h - - new flag macro, FNMATCH_IGNCASE, evaluates to FNM_CASEFOLD if the - match_ignore_case variable is non-zero - -execute_cmd.c - - new variable, match_ignore_case - - change call to strmatch() in execute_case_command so it includes - FNMATCH_IGNCASE - -test.c - - change call to strmatch() in patcomp() so that pattern matching - calls for [[ ... ]] obey the match_ignore_case variable - -lib/sh/shmatch.c - - if match_ignore_case is set, enable REG_ICASE in the regexp match - flags - -builtins/shopt.def - - new settable option, `nocasematch', controls the match_ignore_case - variable. Currently alters pattern matching for case and [[ ... ]] - commands (==, !=, and =~ operators) - -doc/{bashref.texi,bash.1} - - updated descriptions of [[ and case to include reference to - nocasematch option - - 2/22 - ---- -builtins/mkbuiltins.c - - add `times' to the list of posix special builtins - - 2/23 - ---- -builtins/cd.def - - posix mode no longer turns on effect of -P option on $PWD if a - directory is chosen from CDPATH - -doc/bashref.texi - - clarified that in posix mode, reserved words are not alias expanded - only in a reserved word context - - removed item about cd, $CDPATH, and -P from posix mode section - - 2/24 - ---- -builtins/reserved.def - - minor cleanups to the description of `if' - - 3/2 - --- -subst.c - - change list_string and get_word_from_string to explicitly treat an - IFS character that is not space, tab, or newline *and any adjacent - IFS white space* as a single delimiter, as SUSv3/XPG6 says - -builtins/read.def - - check whether or not the number of fields is exactly the same as - the number of variables instead of just assigning the rest of the - line (minus any trailing IFS white space) to the last variable. - This parses a field and checks whether or not it consumes all of - the input (including any trailing field delimiters), falling back - to the previous behavior if it does not. This is what POSIX.2 - specifies, I believe (and the consensus of the austin-group list). - This requires a few tests in read.tests to be changed: backslashes - escaping IFS whitespace characters at the end of input cause the - whitespace characters to be preserved in the value assigned to the - variable, and the trailing non-whitespace field delimiter issue - - 3/7 - --- -configure.in - - add -D_POSIX_SOURCE to the LOCAL_CFLAGS for Interix - - 3/8 - --- -bashline.c - - make bash_directory_expansion a void function, since it doesn't have - any return value - - 3/9 - --- -builtins/read.def - - when testing for a pipe, use `fd' instead of hard-coding 0, since we - can read from other file descriptors now - -lib/sh/zread.c - - in zsyncfd, only set lind and lused to 0 if the lseek succeeds. - If the lseek fails, we might steal input from other programs, but - a failed lseek won't cause us to erroneously discard input - - 3/11 - ---- -builtins/evalstring.c - - don't allow parse_and_execute to short-circuit and call exec() if - the command's return value is being inverted - - 3/15 - ---- -builtins/printf.def - - new macro PC to call putchar and increment number of chars printed - - fixes bug in computation of value for %n format char - - `tw' is now a global var so printstr can modify it using PC() - - convert PF macro to use asprintf into a local buffer - Preparation for printf -v var - - add code to add the text printed to a `variable buffer' if -v option - supplied. The buffer grows as needed - - printf now takes a `-v var' option to put the output into the variable - VAR rather than sending it to stdout. It does not: - print partial output on error (e.g., format string error) - handle NULs in the variable value, as usual - - 3/16 - ---- -parse.y - - fix bug in prompt string decoding that caused a core dump when PS1 - contained \W and PWD was unset (null pointer deref) - -builtins/printf.def - - changed -v var behavior so it stores partial output into the named - variable upon an error - - 3/24 - ---- -lib/readline/bind.c - - bool_to_int now takes a `const char *' argument - -support/{printenv,recho,zecho}.c - - include config.h - - include "bashansi.h" for appropriate extern function declarations - -configure.in - - on MacOS X 10.4, compensate for loader not allowing static library - to override existing system dynamic library when compiling -dynamic - (affects readline and history libraries); so use absolute pathname - instead of -lreadline as library name - -lib/glob/{glob,sm_loop,smatch}.c - - make sure to cast arguments to (char *) or (unsigned char *) as - appropriate to avoid gcc4 warnings - -lib/glob/smatch.c - - collsym (single-byte version) now takes a (CHAR *) first argument to - match callers; cast argument to strncmp appropriately - -lib/sh/snprintf.c - - fix ldfallback and dfallback to handle width and precision specs in - the format passed to sprintf() - - fix STAR_ARGS macro to deal with negative field widths and precisions - - 3/25 - ---- -builtins/printf.def - - since a negative precision in a "x.x[fFgGeE]" format specifier should - be allowed but treated as if the precision were missing, let it - through - -lib/sh/snprintf.c - - fix * code to deal with a negative precision by treating it as if - the `.' and any digit string in the precision had not been specified - - fix format parsing code to deal with a negative inline precision, - e.g., "%4.-4f" by treating it as if the `'. and any digit string in - the precision had not been specified - - a `+' in a format specifier should only act as a flag if it comes - before a `.' (otherwise it is ignored) - -lib/readline/vi_mode.c - - new function, rl_vi_rubout, to rl_rubout as rl_vi_delete is to - rl_delete; saves deleted text for possible reinsertion as with any - vi-mode `text modification' command (fixes problem with `X' reported - by beat.wieland@gmx.ch) - -lib/readline/vi_keymap.c - - bind `X' in vi command mode to rl_vi_rubout - -lib/readline/funmap.c - - add a bindable `vi-rubout' command, runs rl_vi_rubout - -lib/readline/text.c - - rewrote internals of _rl_rubout_char to make structure cleaner - -lib/readline/{complete,text}.c - - changed code to remove #ifdef HANDLE_MULTIBYTE where possible - - 3/28 - ---- -lib/readline/examples/rl.c - - include instead of posixstat.h if READLINE_LIBRARY not - defined - -subst.c - - fix mbstrlen to treat invalid multibyte sequences as sequences of - single-byte characters - - 4/8 - --- -configure.in - - default SIZE to `:' if cross-compiling and an appropriate size for - the target is not found - - 4/11 - ---- -subst.c - - change match_upattern and match_wpattern to check whether or not the - supplied pattern matches anywhere in the supplied string, prefixing - and appending the pattern with `*' if necessary. If it doesn't we - can short-circuit immediately rather than waste time doing up to - N-1 unsuccessful calls to strmatch/wcsmatch (which kills for long - strings, even if the pattern is short) - - 4/12 - ---- -configure.in - - make sure the special case for MacOS X 10.4 only kicks in if the - `--with-installed-readline' option isn't supplied - -lib/readline/{callback,readline,signals}.c - - make sure rl_prep_term_function and rl_deprep_term_function aren't - dereferenced if NULL (as the documentation says) - -builtins/mkbuiltins.c - - don't bother with the special HAVE_BCOPY code; just use straight - assignments - -builtins/ulimit.def - - use _POSIX_PIPE_BUF in pipesize() if it's defined and PIPE_BUF is - not - - 4/13 - ---- -execute_cmd.c - - add cm_function_def to the list of control structures for which - child processes are forked when pipes come in or out - - 4/14 - ---- -builtins/read.def - - make sure the ^As added for internal quoting are not counted as - characters read when -n is supplied - - 4/20 - ---- -redir.c - - fix redir_open so that the repeat open on failure that AFS support - adds restores the correct value of errno for any error message - - 4/26 - ---- - -Makefile.in - - make sure mksignames and mksyntax are invoked with the $(EXEEXT) - extension - - 4/28 - ---- -lib/readline/readline.h - - new state variable: RL_STATE_CALLBACK, means readline is using the - callback interface - -lib/readline/callback.c - - set RL_STATE_CALLBACK in rl_callback_handler_install, unset in - rl_callback_handler_remove - - 4/29 - ---- -config-top.h - - DONT_REPORT_SIGPIPE is now on by default, since it apparently - interferes with scripts - -configure.in - - arrange things so PGRP_PIPE is defined on Linux-2.4+ and version 3 - kernels (ones that apparently schedule children to run before their - parent) - - 4/30 - ---- -builtins/caller.def - - add call to no_options, so it can handle `--' option - -doc/{bash.1,bashref.texi} - - note explicitly that test, :, true, and false don't understand -- - as meaning the end of options - - 5/7 - --- -support/shobj-conf - - darwin 8 needs the same LDFLAGS setting as darwin 7 - -parse.y - - in save_parser_state, make sure we cast the return value from - xmalloc() to the right type - - remove casts to (char *) in calls to yyerror() - -lib/readline/signals.c - - make SIGQUIT and SIGALRM code conditional on their definition - - use raise() to send a signal if we don't have kill() - -lib/readline/display.c - - some MS-DOS and MINGW changes from the cygwin and mingw folks - -config.h.in - - add HAVE_PWD_H for - - add HAVE_FCNTL, HAVE_KILL for respective system calls - - add HAVE_GETPW{ENT,NAM,UID} for passwd functions - -configure.in - - add check for - - add checks for fcntl, kill system calls - - add checks for getpw{ent,nam,uid} C library functions - - pass a flag indicating we're cross compiling through to - CFLAGS_FOR_BUILD in Makefile.in - -lib/readline/complete.c - - guard inclusion of with HAVE_PWD_H - - don't provide a missing declaration for getpwent if we don't have it - - guard calls to {get,end}pwent with HAVE_GETPWENT - -lib/readline/shell.c - - guard inclusion of with HAVE_PWD_H - - guard inclusion of with HAVE_FCNTL_H - - don't provide a missing declaration for getpwuid if we don't have it - - guard calls to getpwuid with HAVE_GETPWUID - - don't bother with body of sh_unset_nodelay_mode if we don't have - fcntl - -lib/tilde/tilde.c - - guard inclusion of with HAVE_PWD_H - - guard calls to getpw{nam,uid} with HAVE_GETPW{NAM,UID} - - guard calls to {get,end}pwent with HAVE_GETPWENT - -Makefile.in,builtins/Makefile.in - - @CROSS_COMPILE@ is substituted into CFLAGS_FOR_BUILD (equal to - -DCROSS_COMPILING if bash is being cross-compiled) - - 5/9 - --- -aclocal.m4 - - print version as `0.0' in RL_LIB_READLINE_VERSION if the - `rl_gnu_readline_p' variable isn't 1 (accept no imitations) - - 5/11 - ---- -lib/readline/rlprivate.h - - definition of a readline `search context', to be use for incremental - search initially and other types of search later. Original from - Bob Rossi as part of work on incremental searching problems when - using callback interface - -lib/readline/isearch.c - - functions to allocate and free search contexts - - function to take a search context and a character just read and - `dispatch' on it: change search parameters, add to search string, - search further, etc. - - isearch is now completely context-driven: a search context is - allocated and passed to the rest of the functions - - 5/12 - ---- -lib/readline/isearch.c - - an additional `isearch cleanup' function that can be called from - the callback interface functions when the search is to be terminated - - an additional `isearch callback' function that can be called from - rl_callback_read_char when input is available - - short-circuit from rl_search_history after initialization if - the callback interface is being used - -lib/readline/callback.c - - in rl_callback_read_char(), if RL_STATE_ISEARCH is set, call - _rl_isearch_callback to read the character and dispatch on it. - If RL_STATE_ISEARCH is unset when that call returns, and there is - input pending, call rl_callback_read_char() again so we don't - have to wait for new input to pick it up - -support/shobj-conf,configure.in - - add support for dragonfly bsd, the same as freebsd - - 5/13-5/15 - --------- -lib/readline/callback.c - - support for readline functions to `register' a function that will - be called when more input is available, with a generic data - structure to encapsulate the arguments and parameters. Primarily - intended for functions that read a single additional character, - like quoted-insert - - support for callback code reading numeric arguments in a loop, - using readline state and an auxiliary variable - - support for callback code performing non-incremental searches using - the same search context struct as the isearch code - -lib/readline/{callback,display}.c - - if a callback function sets `_rl_redisplay_wanted', the redisplay - function will be called as soon as it returns - -lib/readline/input.c - - changes to _rl_read_mbchar to handle reading the null multibyte - character and translating it into '\0' - -lib/readline/misc.c - - break rl_digit_loop() into component functions that can be called - individually from the callback code more easily - - share some of the functions with rl_digit_loop1() in vi_mode.c - -lib/readline/readline.h - - change the version #defines to reflect readline 5.1 - -lib/readline/search.c - - break code into smaller functions that can be composed to work with - the callback code more easily - -lib/readline/text.c - - in rl_quoted_insert(), don't mess around with the tty signals if - running in `callback mode' - -lib/readline/vi_mode.c - - changed set-mark, goto-mark, change-char, and char-search to work - when called by callback functions - - 5/17 - ---- - -lib/readline/rlprivate.h - - new struct declaration for a `reading key sequence' context - -lib/readline/readline.c - - new variable, _rl_dispatching_keymap, keeps track of which keymap - we are currently searching - - functions to allocate and deallocate contexts for reading multi-char - key sequences - - 5/18 - ---- -lib/readline/rlprivate.h - - new struct defining a context for multiple-key key sequences (the - base case is escape-prefixed commands) - -lib/readline/readline.c - - change structure of _rl_dispatch_subseq to allow for callback code - to use it - rudimentary support for supporting the existing - recursion using a stack of contexts, each with a reference to the - previous - - fix so that ^G works when in callback mode - -lib/readline/callback.c - - call the appropriate multiple-key sequence callback if the state is - set - - 5/19 - ---- -lib/readline/readline.c - - broke code from _readline_internal_char after call to rl_dispatch - out into separate function: _rl_internal_char_cleanup, callable by - other parts of the code - - change _rl_internal_char_cleanup to unset _rl_want_redisplay after - it calls (*rl_redisplay_func) - -lib/readline/callback.c - - call _rl_internal_char_cleanup from rl_callback_read_char when - appropriate - - 5/24 - ---- -lib/readline/callback.c - - use _rl_dispatch_callback and a chain of _rl_keyseq_contexts to - simulate the recursion used to decode multicharacter key sequences - (even things like ESC- as meta-prefix) - - call setjmp in rl_callback_read_char to give things like rl_abort - a place to jump, since the saved location in readline() will not - be valid - - keep calling _rl_dispatch_callback from rl_callback_read_char while - we are still decoding a multi-key key sequence - - keep calling readline_internal_char from rl_callback_read_char while - we are reading characters from a macro - -lib/readline/macro.c - - use a slightly different strategy upon encountering the end of a macro - when using the callback interface: when the last character of a - macro is read, and we are reading a command, pop the macro off the - stack immediately so the loop in rl_callback_read_char terminates - when it should - -lib/readline/readline.c - - if longjmp() is called and we end up at the saved location while - using the callback interface, just return -- don't go back into a - blocking read - - new function to dispose a chain of rl_keyseq_cxts - - only read new input in _rl_dispatch_callback if the KSEQ_DISPATCHED - flag is not set in the current keyseq context -- if it is, we are - traversing the chain back up and should use what we already saved - - use -3 as a magic value from _rl_dispatch_subseq to indicate that - we're allocating a new context and moving downward in the chain - (a special return value for the benefit of _rl_dispatch_callback) - -lib/readline/rlprivate.h - - new extern declaration for _rl_keyseq_chain_dispose - - 6/1 - --- -builtins/read.def - - fixed a bug that occurred when reading a set number of chars and - the nth char is a backslash (read one too many). Bug reported by - Chris Morgan - -execute_cmd.c - - fix execute_builtin so the `unset' builtin also operates on the - temporary environment in POSIX mode (as well as source and eval), - so that unsetting variables in the temporary environment doesn't - leave them set when unset completes. Report by Eric Blake - - -array.c - - fix from William Park for array_rshift when shifting right on an - empty array -- corrects calculation of array->max_index - -builtins/exec.def - - if an exec fails and the execfail option is set, don't call - restart_job_control unless the shell is interactive or job_control - is set - -jobs.c - - add a run-time check for WCONTINUED being defined in header files - but rejected with EINVAL by waitpid(). Fix from Maciej Rozycki - - - 6/20 - ---- -bashhist.c - - make sure calls to sv_histchars are protected by #ifdef BANG_HISTORY - - ditto for calls to history_expand_line_internal - - 6/23 - ---- -doc/bashref.texi - - remove extra blank lines in @menu constructs - -variables.c - - assign export_env to environ (extern char **) every time it changes - (mostly in add_to_export_env define), so maybe getenv will work on - systems that don't allow it to be replaced - - 6/29 - ---- -bashline.c - - in bash_directory_completion_hook, be careful about not turning `/' - into `//' and `//' into `///' for benefit of those systems that treat - `//' as some sort of `network root'. Fix from Eric Blake - - -lib/readline/complete.c - - in to_print, do the right thing after stripping the trailing slash - from full_pathname: // doesn't turn into /, and /// doesn't become - //. Fix from Eric Blake - - 6/30 - ---- -lib/malloc/trace.c - - include if it's available for a definition of size_t - -jobs.c - - in wait_for, if a child process is marked as running but waitpid() - returns -1/ECHILD (e.g., when the bash process is being traced by - strace), make sure to increment c_reaped when marking the child as - dead - - in without_job_control, make sure to close the pgrp pipe after - calling start_pipeline - - 7/1 - --- -Makefile.in - - only remove pathnames.h when the other files created by running - configure are removed (e.g., Makefile). Fix from William Park - -lib/sh/shquote.c - - since backslash-newline disappears when within double quotes, don't - add a backslash in front of a newline in sh_double_quote. Problem - reported by William Park - -jobs.c - - in notify_of_job_status, don't print status messages about - terminated background processes unless job control is active - -bashhist.c - - new variable, hist_last_line_pushed, set to 0 in really_add_history - (used by `history -s' code) - -bashhist.h - - new extern declaration for history -s - -builtins/history.def - - don't remove last history entry in push_history if it was added by - a call to push_history -- use hist_last_line_pushed as a sentinel - and set it after adding history entry. This allows multiple - calls to history -s to work right: adding all lines to the history - rather than deleting all but the last. Bug reported by Matthias - Schniedermeyer - - pay attention to hist_last_line_pushed in expand_and_print_history() - so we don't delete an entry pushed by history -s - - 7/4 - --- -print_cmd.c - - fix print_arith_for_command to not print so many blanks between - expressions in ((...)) - -command.h - - new word flag: W_DQUOTE. Means word should be treated as if double - quoted - -make_cmd.c - - add W_DQUOTE to word flags in make_arith_for_expr - -parse.y - - add W_DQUOTE to word flags for (( ... )) arithmetic commands - -subst.c - - don't perform tilde expansion on a word with W_DQUOTE flag set - - don't perform process substitution on a word with W_DQUOTE flag set - -arrayfunc.c - - expand an array index within [...] the same way as an arithmetic - expansion between (( ... )) - -lib/readline/input.c - - use getch() instead of read() on mingw - -lib/readline/readline.c - - add a few key bindings for the arrow keys on mingw - -lib/readline/rldefs.h - - if on mingw, define NO_TTY_DRIVER - -lib/readline/rltty.c - - compile in the stub functions for _rl_{disable,restore}_tty_signals - if on mingw - - compile in stub function for rl_restart_output on mingw - - make sure enough functions and macros are defined to compile if - NO_TTY_DRIVER is defined (lightly tested - builds on MacOS X, at - least) - - 7/7 - --- -command.h - - add a `flags' member to the PATTERN_LIST structure - -make_cmd.c - - intialize the `flags' member of a PATTERN_LIST when it's created - -builtins/psize.c - - protect extern declaration of errno with usual #ifdef errno - -configure.in, variables.c - - changes for QNX 6.x - - 7/9 - --- -parse.y - - fix parse_matched_pair to handle single and double quoted strings - inside old-style command substitution (``) since they can each - quote the ` and embedded $-expansions. Report by Eric Blake - - -{configure,Makefile}.in - - TILDE_LIB is now substituted into Makefile by configure - -configure.in - - if configuring --with-installed-readline on cygwin, set TILDE_LIB - to the empty string to avoid multiply-defined symbols. Cygwin - doesn't allow undefined symbols in dynamic libraries. Report by - Eric Blake - - 7/11 - ---- -input.c - - in duplicate_buffered_stream, don't call free_buffered_stream if the - two buffered streams share the same b_buffer object (e.g., if they - had already been duplicated with a previous call). Fixes Debian bug - reported by eero17@bigfoot.com - - 7/12 - ---- -shell.c - - make set_shell_name more resistant to a NULL argument - - in bind_args, use < instead of != when counting the arguments and - making the arg list - - in main(), make sure arg_index is not initialized to a value greater - than argc - - 7/14 - ---- -lib/readline/display.c - - in expand_prompt, don't set the location of the last invisible - char if the sequence is zero length (\[\]) - - 7/15 - ---- -doc/{bash.1,bashref.texi} - - document that the shell uses $TMPDIR when creating temporary files - - 7/20 - ---- -[bash-3.1-alpha1 frozen] - - 7/29 - ---- -builtins/evalstring.c - - make sure that parse_and_execute saves and restores the value of - loop_level, so loops in sourced scripts and eval'd strings don't - mess up the shell's parser state - -bashline.c - - change command_subst_completion_function to suppress appending - any character to a unique completion, instead of a space, unless - the last word in the quoted command substitution completes to a - directory name. In that case we append the expected slash - - 8/1 - --- -builtins/printf.def - - make sure variables are initialized if their values are tested later - -[bash-3.1-alpha1 updated and re-frozen] - - 8/2 - --- -variables.c - - make sure to call stifle_history with an `int' instead of an intmax_t. - Sometimes it makes a difference - - 8/3 - --- -[bash-3.1-alpha1 released] - -support/mksignames.c - - add `SIGSTKFLT' (RHE3) - - add `SIGXRES' (Solaris 9) - - 8/4 - --- -builtins/ulimit.def - - fix typo to make `x' the right option for locks - - add new options to short help synopsis - -variables.c - - use get_variable_value instead of direct reference to value_cell - in make_variable_value when appending to the current value, so - references to array variables without subscripts will be equivalent - to element 0 - -lib/readline/text.c - - rewrote rl_change_case to correctly change the case of multibyte - characters where appropriate - - 8/5 - --- -configure.in - - remove call to obsolete macro AC_ACVERSION - - remove special calls to AC_CYGWIN and AC_MINGW32; AC_CANONICAL_HOST - takes care of those cases - -general.h - - include `chartypes.h' for definition of ISALPHA - - fix definitions of ABSPATH and RELPATH for cygwin - - fix definition of ISDIRSEP for cygwin to allow backslash as a - directory name separator - - 8/9 - --- -builtins/setattr.def - - when setting a variable from the temporary environment in - set_var_attribute (e.g., `LC_ALL=C export LC_ALL'), make sure to - call stupidly_hack_special_variables after binding the variable in - the current context - -builtins/printf.def - - make sure to call stupidly_hack_special_variables if using `printf -v' - to put formatted output in a shell variable - - 8/11 - ---- -support/shobj-conf - - new variable: SHLIB_LIBPREF, prefix for shared library name (defaults - to `lib' - - new variable: SHLIB_DLLVERSION, used on Cygwin to set the library - version number - - new variable: SHLIB_DOT, separator character between library name and - suffix and version information (defaults to `.') - - new stanza for cygwin to generate windows-compatible dll - - 8/14 - ---- -variables.c - - new special variable function for Cygwin, so the export environment - is remade when HOME is changed. The environment is the only way to - get information from the shell to cygwin dlls, for instanace, when - bash is compiled to use an already-installed libreadline - -variables.h - - new extern declaration for sv_home - - 8/15 - ---- -lib/readline/display.c - - call init_line_structures from rl_redisplay if vis_lbreaks == 0 - to avoid consequences of a poorly-timed SIGWINCH - - 8/16 - ---- -subst.c - - fix logic for performing tilde expansion when in posix mode (don't - rely on W_TILDEEXP flag always being set, because it won't be when - expanding the RHS of assignment statement). Use W_TILDEEXP only - when deciding to expand a word marked as W_ASSIGNMENT that doesn't - precede a command name - - 8/17 - ---- -execute_cmd.c - - in execute_function, when subshell == 1, don't short-cut by using - the command contained in the group command -- if you do, any - redirections attached to the group command (function) don't get - executed - -general.h - - new #define, FS_READABLE, indicates file is readable by current - user - -findcmd.c - - rewrote file_status to use S_xxx POSIX file mode bits and to add - support for FS_READABLE (affects ./source and searching $PATH for - scripts whose names are supplied as arguments on the command line) - - change find_path_file to look for readable files -- source requires - it - - change find_in_path_element to do the right thing when FS_READABLE - is supplied as a flag - -doc/bashref.texi - - remove note about posix non-compliance in `.': we now require and - look for readable files when searching $PATH - - 8/20 - ---- -subst.c - - fix setifs to handle case where passed variable is non-zero but - v->value == 0 (as in an unset local variable); treat IFS as unset - in this case - -jobs.c - - in kill_pid, if asked to killpg a process or pgrp whose pgrp is - recorded as the same as the shell's, just call killpg and let the - chips fall where they may -- there may be other processes in that - pgrp that are not children of the shell, so killing each process - in the pipeline will not do a complete job, and killpg'ing each - such process will send too many signals in the majority of cases - -builtins/cd.def - - in posix mode, pwd needs to check that the value it prints and `.' - are the same file - -builtins/read.def - - if reading input from stdin in a non-interactive shell and calling - `read', call sync_buffered_stream to seek backward in the input - stream if necessary (XXX - should we do this for all shell builtins?) - - 8/23 - ---- -builtins/cd.def - - in posix mode, if canonicalization of the absolute pathname fails - because the path length exceeds PATH_MAX, but the length of the passed - (non-absolute) pathname does not, attempt the chdir, just as when - not in posix mode - -builtins/type.def - - don't have describe_command call sh_makepath if the full path found - is already an absolute pathname (sh_makepath will stick $PWD onto the - front of it) - - 8/24 - ---- - -jobs.c - - in posix mode, don't have start_job print out and indication of - whether the job started by `bg' is the current or previous job - - change start_job to return success if a job to be resumed in the - background is already running. This means that bg won't fail when - asked to bg a background job, as SUSv3/XPG6 requires - - new function, init_job_stats, to zero out the global jobstats struct - -{jobs,nojobs}.c - - change kill_pid to handle pids < -1 by killing process groups - -jobs.h - - extern declaration for init_job_stats - -lib/readline/history.c - - check whether or not the history list is null in remove_history - -builtins/history.def - - delete_last_history is no longer static so fc builtin can use it - -builtins/fc.def - - use free_history_entry in fc_replhist instead of freeing struct - members individually - - call delete_last_history from fc_replhist instead of using inline - code - - if editing (-l not specified), make sure the fc command that caused - the editing is removed from the history list, as POSIX specifies - -builtins/kill.def - - just call kill_pid with any pid argument and let it handle pids < -1 - This is the only way to let kill_pid know whether a negative pid or - a job spec was supplied as an argument to kill - -builtins/fg_bg.def - - force fg_bg to return EXECUTION_SUCCESS explicitly if called by bg - and start_job returns successfully - - bg now returns success only if all the specified jobs were resumed - successfully - -execute_cmd.c - - call init_job_stats from initialize_subshell to zero out the global - job stats structure - - 8/25 - ---- -bashline.c - - change vi_edit_and_execute_command to just call vi when in posix - mode, instead of checking $FCEDIT and $EDITOR - -lib/readline/search.c - - if in vi_mode, call rl_free_undo_list in make_history_line_current - to dispose of undo list accumulated while reading the search string - (if this isn't done, since vi mode leaves the current history - position at the entry which matched the search, the call to - rl_revert_line in rl_internal_teardown will mangle the matched - history entry using a bogus rl_undo_list) - - call rl_free_undo_list after reading a non-incremental search string - into rl_line_buffer -- that undo list should be discarded - -lib/readline/rlprivate.h - - add UNDO_LIST * member to search context struct - -lib/readline/isearch.c - - initialize UNDO_LIST *save_undo_list member of search context struct - - 8/27 - ---- -lib/readline/bind.c - - change rl_parse_and_bind to strip whitespace from the end of a - variable value assignment before calling rl_variable_bind - -doc/bash.1,lib/readline/doc/{rluser.texi,readline.3} - - clarified the language concerning parsing values for boolean - variables in assignment statements - - 8/28 - ---- -lib/sh/pathphys.c - - fix small memory leak in sh_realpath reported by Eric Blake - - 8/31 - ---- -doc/bashref.texi - - add additional notes to posix mode section - - 9/3 - --- -parse.y - - if $'...' occurs within a ${...} parameter expansion within - double quotes, don't single-quote the expanded result -- the double - quotes will cause it to be expanded incorrectly - - 9/4 - --- -builtins/fc.def - - if STRICT_POSIX is defined, the posix mode default for the editor to - use is $FCEDIT, then ed - -shell.c - - if STRICT_POSIX is defined, initialize `posixly_correct' to 1 - -config.h.in - - add #undef STRICT_POSIX - - 9/5 - --- -configure.in - - add new option argument, --enable-strict-posix-default, configures - bash to be posix-conformant (including defaulting echo to posix - conformance) by default - -builtins/echo.def - - if STRICT_POSIX is defined, default echo to xpg-style - -doc/bashref.texi - - describe the --enable-strict-posix-default option to configure - - 9/10 - ---- -builtins/mkbuiltins.c - - change to not generate N_(""), because the translated empty string is - special to GNU gettext - - 9/13 - ---- -lib/readline/complete.c - - a negative value for rl_completion_query_items means to not ask - -lib/readline/doc/{{rltech,rluser}.texi,readline.3} - - documented new semantics for rl_completion_query_items/ - completion-query-items - - 9/14 - ---- -bashline.c - - bind M-TAB in emacs mode to dynamic-complete-history even if the - current binding is `tab-insert' (which is what it is by default), - not just if it's unbound - - 9/15 - ---- -eval.c - - call QUIT before calling dispose_command on current_command after - the `exec_done' label. If we dispose current_command first, the - longjmp might restore the value of current_command after we've - disposed it, and the subsequent call to dispose_command from the - DISCARD case will free memory twice - - 9/16 - ---- -lib/sh/strto[iu]max.c - - make sure the function being declared is not a cpp define before - defining it -- should fix problems on HP-UX - - 9/19 - ---- -Makefile.in - - make sure the binaries for the tests are at the front of $PATH - - 9/22 - ---- -parse.y - - new flag for parse_matched_pair: P_COMMAND, indicating that the - text being parsed is a command (`...`, $(...)) - - change calls to parse_matched_pair to include P_COMMAND where - appropriate - - if P_COMMAND flag is set and the text is unquoted, check for comments - and don't try to parse embedded quoted strings if in a comment (still - not exactly right yet) - - 9/24 - ---- -builtins/history.def - - if running history -n, don't count these new lines as history lines - for the current session if the `histappend' shell option is set. - If we're just appending to the history file, the issue that caused - history_lines_this_session to be recalculated doesn't apply -- the - history file won't be missing any entries - -lib/readline/isearch.c - - fix C-w handler for isearch string reader to handle multibyte chars - -lib/readline/rlmbutil.h - - new defines for _rl_to_wupper and _rl_to_wlower - -lib/readline/text.c - - use _rl_to_wupper and _rl_to_wlower as appropriate - - 9/26 - ---- -execute_cmd.c - - in shell_execve, if the exec fails due to E2BIG or ENOMEM, just print - the appropriate error message instead of checking out any interpreter - specified with #! - - 9/30 - ---- -bashhist.c - - make $HISTCMD available anytime remember_on_history is non-zero, - which indicates that we're saving commands to the history, and - let it evaluate to 1 if we're not - - 10/4 - ---- -lib/sh/snprintf.c - - in floating(), make sure d != 0 before calling chkinfnan -- gcc on the - version of Solaris 9 I have translates 0 to -inf on the call - -[bash-3.1-beta1 frozen] - - 10/6 - ---- -jobs.c - - set the_pipeline to NULL right away in cleanup_the_pipeline, and - dispose a copy of the pointer so we don't mess with the_pipeline - while we're in the process of destroying it - - block and unblock SIGCHLD around manipulating the_pipeline in - cleanup_the_pipeline - - 10/7 - ---- -[bash-3.1-beta1 released] - -lib/readline/isearch.c - - when switching directions, make sure we turn off the SF_REVERSE - flag in the search context's flags word if we're going from reverse - to forward i-search - -lib/readline/bind.c - - new function, rl_variable_value, returns a string representing a - bindable readline variable's value - - new auxiliary function, _rl_get_string_variable_value, encapsulates - everything needed to get a bindable string variable's value - - rewrote rl_variable_dumper to use _rl_get_string_variable_value - -lib/readline/readline.h - - new extern declaration for rl_variable_value - -lib/readline/doc/rltech.texi - - documented rl_variable_value - -bashline.c - - in command_word_completion_function, if readline sets - rl_completion_found_quote, but doesn't set rl_completion_quote_character, - we have an embedded quoted string or backslash-escaped character in - the passed text. We need to dequote that before calling - filename_completion_function. So far, this is in place only for - absolute program names (those containing a `/') - - in command_word_completion_function, use rl_variable_value to decide - whether or not we should ignore case, and use strncasecmp instead of - strncmp where appropriate - - 10/11 - ----- -builtins/fc.def - - fixed a typo when using POSIX_FC_EDIT_COMMAND - -redir.h - - new flag values for redirections: RX_INTERNAL and RX_USER (currently - unused) - -redir.c - - add_undo_redirect and add_undo_close_redirect now set RX_INTERNAL - flag when making new redirects - - in do_redirection_internal, only set file descriptors > 2 to CLEXEC - if they're marked as RX_INTERNAL - - 10/12 - ----- -jobs.c - - in wait_for_single_pid, if in posix mode, remove the waited-for pid - from the list of background pids, forgetting it entirely. POSIX - conformance tests test for this. - -lib/readline/{readline.h,vi_mode.c} - - new state flag, RL_STATE_VICMDONCE, set after entering vi command - mode the first time; reset on each call to readline() - - 10/13 - ----- -lib/readline/undo.c - - in rl_revert_line, make sure that revert-line in vi mode leaves - rl_point set to 0 no matter the state of the line buffer - -lib/readline/vi_mode.c - - when entering vi_command mode for the first time, free any existing - undo list so the previous insertions won't be undone by the `U' - command. This is how POSIX.2 says `U' should work (and the test - suite tests for it) - -lib/readline/bind.c - - change rl_parse_and_bind so only `set' commands involving boolean - readline variables have trailing whitespace stripped from the value - string - - 10/16 - ----- -lib/glob/sm_loop.c - - fix patscan() to correctly scan backslash-escaped characters - - 10/18 - ----- -lib/sh/{winsize.c,Makefile.in},{jobs,nojobs}.c,Makefile.in,externs.h - - moved get_new_window_size from jobs.c/nojobs.c to new file, - lib/sh/winsize.c, made function global - -{jobs,nojobs,sig}.c,{jobs,sig}.h - - moved SIGWINCH handling code to sig.c rather than duplicate it in - jobs.c and nojobs.c - - call set_sigwinch_handler from sig.c code rather than job control - signal initialization - -sig.[ch] - - new variable, sigwinch_received, acts like interrupt_state for - SIGWINCH, set by sigwinch_sighandler. sigwinch_sighandler no longer - calls get_new_window_size - -parse.y - - add call to get_new_window_size if sigwinch_received at top of - shell_getc - - 10/19 - ----- -lib/malloc/malloc.c - - to avoid orphaning memory on free if the right bucket is busy, use a - new function xplit(mem, bucket) to split the block into two or more - smaller ones and add those to the right bucket (appropriately marking - it as busy) - - audit bsplit(), bcoalesce(), and xsplit() for proper use of busy[], - since they're dealing with two separate buckets - - 10/22 - ----- -subst.c - - new flag for string_extract: EX_REQMATCH, means to return an error - if a matching/closing character is not found before EOS - - new static flag variables: extract_string_error and extract_string_fatal - - change expand_word_internal to check for new error returns from - string_extract and return errors if appropriate - - 10/23 - ----- -builtins/cd.def - - make sure we free TDIR in change_to_directory after calling - set_working_directory (which allocates new memory) and other places - we short-circuit and return - - 10/24 - ----- -subst.c - - modified fix from 10/22 to allow bare ` to pass through (for - some backwards compatibility and more correctness) - - 10/27 - ----- -conftypes.h - - make MacOS X use the RHAPSODY code that gets HOSTTYPE, et al. - at build rather than configure time, to support universal binaries - (fix from llattanzi@apple.com) - - 10/30 - ----- -builtins/evalstring.c - - make sure we don't turn on CMD_NO_FORK in parse_and_execute if - we're running a trap command on signal receipt or exit - -execute_cmd.c - - in shell_execve, improve the error message a little bit if the - interpreter name in a #! exec header ends with a ^M (as in a DOS- - format file) - - 11/1 - ---- -lib/readline/vi_mode.c - - fix vi-mode `r' command to leave the cursor in the right place - -[bash-3.1-rc1 frozen] - - 11/5 - ---- -execute_cmd.c - - make sure a DEBUG trap doesn't overwrite a command string passed to - make_child in execute_simple_command - -bashline.c - - rearrange some code in bash_quote_filename so filenames with leading - tildes containing spaces aren't tilde-expanded before being - returned to the caller - - 11/6 - ---- -lib/readline/display.c - - when deciding where to move the cursor in rl_redisplay and needing - to move the cursor back after moving it vertically and compensate - for invisible characters in the prompt string, make sure that - _rl_last_c_pos is treated as an absolute cursor position in a - multibyte locale and the wrap offset (number of invisible characters) - is added explicitly when deciding how many characters to backspace - - 11/10 - ----- -lib/readline/terminal.c - - _rl_set_screen_size now interprets a lines or columns argument < 0 - as an indication not to change the current value - - 11/11 - ----- - -lib/readline/terminal.c - - new function, rl_reset_screen_size, calls _rl_get_screen_size to - reset readline's idea of the terminal size - - don't call _rl_get_screen_size in _rl_init_terminal_io if both - _rl_screenheight and _rl_screenwidth are > 0 - - don't initialize _rl_screenheight and _rl_screenwidth to 0 in - _rl_init_terminal_io; let caller take care of it - - set _rl_screenheight and _rl_screenwidth to 0 before calling - _rl_init_terminal_io - -lib/readline/readline.h - - new extern declaration for rl_reset_screen_size - -lib/readline/doc/rltech.texi - - documented rl_reset_screen_size - -variables.c - - if readline is being used, compile in a special var function for - assignments to LINES and COLUMNS that calls rl_set_screen_size or - rl_reset_screen_size as appropriate. Only do this in posix mode - and only when STRICT_POSIX is defined at compile time - - new semaphore variable, winsize_assignment, set while doing an - assignment to LINES or COLUMNS - - new variable, winsize_assigned, says LINES or COLUMNS was assigned - to or found in the environment - - if in the middle of an assignment to LINES or COLUMNS, make - sh_set_lines_and_columns a no-op - -lib/sh/winsize.c - - get_new_window_size now takes two int * arguments, to return the - screen dimensions - -externs.h - - change extern declaration for get_new_window_size - -{jobs,nojobs}.c, parse.y - - change callers of get_new_window_size - - 11/12 - ----- -lib/readline/terminal.c - - new variable, rl_prefer_env_winsize, gives LINES and COLUMNS - precedence over values from the kernel when computing window size - -lib/readline/readline.h - - extern declaration for rl_prefer_env_winsize - -lib/readline/doc/rltech.texi - - document rl_prefer_env_winsize - - 11/13 - ----- -lib/readline/rltty.c - - change rl_prep_terminal to make sure we set and reset the tty - special characters in the vi insertion keymap if in vi mode. This - matters if we get accept-line for the previous line while in vi - command mode - - 11/14 - ----- -builtins/pushd.def - - make sure any call to cd_builtin includes a leading `--' from the - argument list (or constructs one) - - 11/16 - ----- -pcomplete.c - - fix small memory leak in gen_wordlist_matches - -[bash-3.1-rc2 frozen] - - 11/21 - ----- -[bash-3.1-rc2 released] - - 11/23 - ----- -lib/readline/display.c - - changes to rl_redisplay to compensate for update_line updating - _rl_last_c_pos without taking invisible characters in the line into - account. Important in multibyte locales where _rl_last_c_pos is an - absolute cursor position - - changes to _rl_move_cursor_relative to account for _rl_last_c_pos - being an absolute cursor position in a multibyte character locale - - rewrote _rl_move_cursor_relative to make it a little simpler - - 11/29 - ----- -lib/readline/display.c - - changes to rl_redisplay and update_line for update_line to communicate - upward that it took the number of invisible characters on the current - line into account when modifying _rl_last_c_pos - - in update_line, adjust _rl_last_c_pos by wrap_offset before calling - _rl_move_cursor_relative, so we pass correct information about the - true cursor position - - 12/1 - ---- -configure.in - - changed release status to `release' - -[bash-3.1 frozen] - - 12/8 - ---- -[bash-3.1 released] - - 12/9 - ---- -doc/{bash.1,version.texi},lib/readline/doc/version.texi - - remove `beta1' from man page footer and texinfo documents - -variables.c - - make sure winsize_assignment is protected by #ifdef READLINE, so - minimal shell will compile - -builtins/read.def - - make sure error cases free memory and run any unwind-protects to - avoid memory leaks - - 12/10 - ----- -execute_cmd.c - - change execute_command_internal to set $PIPESTATUS for ((...)) and - [[ ... ]] commands - -doc/{bash.1,bashref.texi,version.texi} - - add documentation for ulimit -[iqx] and bump revision date - - 12/12 - ----- -parse.y - - make sure parse_compound_assignment saves and restores the - PST_ASSIGNOK parser state flag around its calls to read_token. - Fixes bug reported by Mike Frysinger - - 12/13 - ----- -parse.y - - change parse_compound_assignment to save and restore the value of - last_read_token. Not sure why it was set unconditionally in the - first place after parsing the complete compound assignment - - 12/14 - ----- -lib/readline/text.c - - don't use return value of rl_kill_text (which always succeeds and - returns the number of characters killed) in rl_delete as an indication - of success or failure - - ditto for return value of rl_delete_text - -lib/readline/readline.c - - don't return the value of the called readline function as the return - value from _rl_dispatch_subseq; -1 means something different to the - callers (return 0 all the time to indicate that a readline function - was found and dispatched). Fix from Andreas Schwab for - bug in callback interface first reported by Mike Frysinger - -execute_cmd.c - - fixed a typo in execute_case_command - - 12/15 - ----- -aclocal.m4 - - add check for wctype() to BASH_CHECK_MULTIBYTE, define HAVE_WCTYPE - -config.h.in - - add HAVE_WCTYPE #define - -config-bot.h - - add HAVE_WCTYPE to the set of checks for HANDLE_MULTIBYTE. This - should catch the deficient NetBSD multibyte support - - 12/16 - ----- -parse.y - - use CTLESC instead of literal '\001' when decode_prompt_string - prefixes RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE - - 12/20 - ----- -lib/readline/display.c - - don't treat RL_PROMPT_START_IGNORE specially inside a sequence of - ignored characters - - keep track of the start of the current sequence of ignored - characters; make sure that an empty sequence of such characters - really is an empty sequence, not one that happens to end with '\001' - (RL_PROMPT_START_IGNORE) - - 12/21 - ----- -subst.c - - change expand_word_internal to process rest of `tilde-word' as a - regular part of the word if tilde expansion leaves the tilde-word - unchanged. This means that ~$USER expands to ~chet, which seems - more intuitive, and is effectively what bash-3.0 did - - 12/23 - ----- -subst.c - - when making a local array variable in do_compound_assignment, make - sure that we don't use a variable of the same name from a previous - context - -doc/bash.1 - - documented expansions for word and patterns in case statement - -builtins/ulimit.def,doc/{bashref.texi,bash.1} - - added new -e and -r (nice and rtprio) options to ulimit; documented - them - - 12/26 - ----- -variables.c - - use `hmax' instead of `num' in sv_histsize to avoid integer overflow - problems with intmax_t - -builtins/read.def - - add unwind-protect to restore rl_attempted_completion_function in - case of a timeout - -{bashline,variables}.c - - move initialization of HISTSIZE from initialization path to - load_history, so it can be overridden by a value assigned in a - startup file - -lib/readline/misc.c - - add a missing `return r' so that rl_digit_loop returns a meaningful - value - -lib/readline/{bind,callback,display,isearch,rltty,search,text,vi_mode}.c - - minor cleanups to satisfy compiler warnings, mostly removing unused - variables - - 12/27 - ----- -support/Makefile.in - - add LIBS_FOR_BUILD support; defaults to ${LIBS} - -Makefile.in - - add LIBS_FOR_BUILD with no default value; use when linking programs - using CC_FOR_BUILD (e.g., bashversion) - - 12/28 - ----- -lib/readline/bind.c - - fix rl_translate_keyseq bad translation of \M-\C-x sequences - -execute_cmd.c - - in execute_arith_command, if the expression expands to more than one - word, make sure we join the words into a single string and pass the - entire thing to evalexp() - -expr.c - - new functions: _is_arithop(c), returns true if C is a valid single- - character arithmetic operator; _is_multiop(c), returns true if C is - a token corresponding to a valid multi-character arithmetic operator - - if we encounter a character that isn't a valid arithmetic - operator, throw an error. Try to be intelligent about what type of - error message to print - -subst.c - - new function, expand_arith_string, calls expand_string_if_necessary; - used where an arithmetic expression needs to be expanded - -subst.h - - new extern declaration for expand_arith_string - -arrayfunc.c - - in array_expand_index, call expand_arith_string to expand the - subscript in a fashion consistent with other arithmetic expressions - -subst.c - - fix parameter_brace_patsub so that we don't try to anchor the pattern - at the beginning or end of the string if we're doing global - replacement -- that combination doesn't doesn't make sense, and - the changed behavior is compatible with ksh93 - -doc/{bash.1,bashref.texi} - - changed description of pattern substitution to match the new - semantics - -tests/new-exp.tests - - change tests to remove all ${pat//#rep} and ${pat//%rep} - expansions, since they don't mean the same thing anymore - - 12/29 - ----- -support/signames.c - - new file, initialize_signames() function from old mksignames.c. This - file builds the signal_names array - -support/mksignames.c - - strip out initialize_signames(), move to signames.c. This file only - writes signames.h - - set up to only write a stub signames.h if CROSS_COMPILING is defined, - with extern declaration for initialize_signames - - if not cross compiling, #define initialize_signames to nothing - -Makefile.in - - mksignames is now linked from mksignames.o and buildsignames.o - - add rules to build signames.o, assuming we're building it as part - of the shell (cross-compiling) - -trap.c - - call initialize_signames from initialize_traps - -configure.in - - set SIGNAMES_O to nothing (normal) or signames.o (cross-compiling), - substitute into Makefile - - don't set SIGNAMES_H if cross-compiling any more - - 12/30 - ----- -command.h - - new word flag: W_NOPROCSUB, inhibits process substitution on a word - -subst.c - - change expand_word_internal to suppress process substitution if the - word has the W_NOPROCSUB flag - -shell.c - - --wordexp turns on W_NOPROCSUB in addition to W_NOCOMSUB - -subst.c - - change string_list_dollar_at and string_list_dollar_star so that - MB_CUR_MAX is used to size an array only when using gcc, since gcc - can handle non-constant array sizes using a mechanism like alloca. - Other compilers, e.g. Sun's compiler, do not implement that - extension - - 12/31 - ----- -builtins/mkbuiltins.c - - when cross-compiling, don't include , since it's for the - target rather than the host system. Instead, choose a reasonable - set of default #defines based on a minimal POSIX system - -jobs.c - - change find_process to handle a NULL return value from find_pipeline - - return immediately from delete_job if jobs[index] is already NULL or - if it has a null pipeline associated with it - - in delete_job, if find_last_proc returns NULL, don't try to call - bgp_delete - - 1/7/2006 - -------- -doc/bash.1 - - patch from Tim Waugh to replace some literal single quotes with - \(aq, the groff special character for it - -jobs.c - - in realloc_jobs_list, make sure to zero out slots after j_lastj - in the new list - - 1/9 - --- -support/mksignames.c - - make sure to include to get right value of NSIG from - (usually) - - 1/10 - ---- -parse.y - - when calling parse_matched_pair on a $(...) command substitution, - don't pass the P_DQUOTE flag so that single quotes don't get - stripped from $'...' inside the command substitution. Bug report - and fix from Mike Stroyan - -jobs.c - - start maintaining true count of living children in js.c_living - - call reset_current in realloc_jobs_list, since old values for current - and previous job are most likely incorrect - - don't allocate a new list in realloc_jobs_list if the old size and - new size are the same; just compact the existing list - - make sure realloc_jobs_list updates value of js.j_njobs - - add some more itrace messages about non-null jobs after j_lastj in - jobs array - - 1/11 - ---- -bashjmp.h - - new value for second argument to longjmp: SIGEXIT. Reserved for - future use - - 1/12 - ---- -jobs.c - - add logic to make_child to figure out when pids wrap around - - turn second argument to delete_job into flags word, added flag to - prevent adding proc to bgpids list - - 1/13 - ---- -lib/readline/vi_mode.c - - move code that moves forward a character out of rl_vi_append_mode - into a separate function, _rl_vi_append_forward - - change _rl_vi_append_mode to save `a' as the last command, so it - can be redone properly - - new function _rl_vi_backup, moves point back a character taking - multibyte locales into account - - change rl_vi_redo to handle redoing an `a' command specially -- - it should be redone like `i' but after moving forward a character - - change rl_vi_redo to use _rl_vi_backup to move point backward - after redoing `i' or `a' - -jobs.c - - new function, delete_old_job (pid), checks whether or not PID is in - a job in the jobs list. If so, and the job is dead, it just removes - the job from the list. If so, and the job is not dead, it zeros - the pid in the appropriate PROCESS so pid aliasing doesn't occur - - make_child calls delete_old_job to potentially remove an already-used - instance of the pid just forked from the jobs list if pids have - wrapped around. Finally fixes the bug reported by Tim Waugh - - -trap.c - - new define, GETORIGSIG(sig), gets the original handling for SIG and - sets SIG_HARD_IGNORE if that handler is SIG_IGN - - call GETORIGSIG from initialize_traps, get_original_signal, and - set_signal - -jobs.c - - in wait_for, if the original SIGINT handler is SIG_IGN, don't set - the handler to wait_sigint_handler. This keeps scripts started in - the background (and ignoring SIGINT) from dying due to SIGINT while - they're waiting for a child to exit. Bug reported by Ingemar - Nilsson - -lib/readline/vi_mode.c - - don't save text to buffer unless undo pointer points to a record of - type UNDO_INSERT; zero it out instead. This fixes bug reported by - Craig Turner with redoing `ctd[ESC]' (empty - insert after change to) - -shell.c - - change set_shell_name so invocations like "-/bin/bash" are marked as - login shells - -doc/bash.1 - - add note about destroying functions with `unset -f' to the section - on shell functions - -lib/readline/terminal.c - - if readline hasn't been initialized (_rl_term_autowrap == -1, the - value it's now initialized with), call _rl_init_terminal_io from - _rl_set_screen_size before deciding whether or not to decrement - _rl_screenwidth. Fixes bug from Mike Frysinger - - 1/14 - ---- -lib/readline/input.c - - allow rl_set_keyboard_input_timeout to set the timeout to 0, for - applications that want to use select() like a poll without any - waiting - -lib/readline/doc/rltech.texi - - documented valid values for timeout in rl_set_keyboard_input_timeout - -jobs.c - - in stop_pipeline, don't have the parent shell call give_terminal_to - if subshell_environment contains SUBSHELL_ASYNC (no background - process should ever give the terminal to anything other than - shell_pgrp) - - in make_child, don't give the terminal away if subshell_environment - contains SUBSHELL_ASYNC - - 1/15 - ---- -subst.c - - in parameter_brace_expand, if extracting ${#varname}, only allow - `}' to end the expansion, since none of the other expansions are - valid. Fixes Debian bug reported by Jan Nordhorlz - - 1/17 - ---- -parse.y - - in parse_matched_pair, protect all character tests with the MBTEST - macro - - in parse_dparen, take out extra make_word after call to alloc_word_desc - (mem leak) - - 1/18 - ---- -parse.y - - in parse_matched_pair, add P_ALLOWESC to flags passed to recursive - parse_matched_pair call when encountering a single or double quote - inside a ``-style command substitution - -execute_cmd.c - - add call to QUIT at beginning of execute_command_internal; better - responsiveness to SIGINT - - 1/21 - ---- -lib/readline/bind.c - - change rl_invoking_keyseqs_in_map to honor the setting of - convert-meta when listing key bindings, since if convert-meta is off, - using '\M-' as the prefix for bindings in, for instance, - emacs-escape-keymap, is wrong. This affects `bind -p' output - - change rl_untranslate_keyseq to add '\e' instead of '\C-[' for - ESC - -execute_cmd.c - - add call to QUIT at end of execute_command - - 1/23 - ---- -lib/readline/display.c - - changed two places in update_line where a check of whether the cursor - is before the last invisible character in the prompt string to - differentiate between the multibyte character case (where - _rl_last_c_pos is a physical cursor position) and the single-byte - case (where it is a buffer index). This prevents many unnecessary - \r-redraw the line sequences. Reported by Dan Jacobson. - - 1/24 - ---- -quit.h - - wrap QUIT macro in do...while(0) like other compound statement - macros - - CHECK_TERMSIG define (placeholder for now); future use will be to - handle any received signals that should cause the shell to - terminate (e.g., SIGHUP) - -{input,jobs,nojobs}.c - - add calls to CHECK_TERMSIG where appropriate (reading input and - waiting for children) - - include quit.h if necessary - - 1/25 - ---- -parse.y - - undo change that makes `)' in a compound assignment delimit a token. - It messes up arithmetic expressions in assignments to `let', among - other things - -sig.h,{jobs,nojobs,sig,trap}.c,builtins/trap.def - - rename termination_unwind_protect to termsig_sighandler - -sig.c - - split termsig_sighandler into two functions: termsig_sighandler, which - runs as a signal handler and sets a flag noting that a terminating - signal was received, and termsig_handler, which runs when it is `safe' - to handle the signal and exit - - new terminate_immediately variable, similar to interrupt_immediately - - termsig_sighandler calls termsig_handler immediately if - terminate_immediately is non-zero - -quit.h - - change CHECK_TERMSIG macro to check terminating_signal and call - termsig_handler if it's non-zero - - add same check of terminating_signal and call to termsig_handler to - QUIT macro - -{jobs,nojobs}.c - - change call to termsig_sighandler to call termsig_handler directly, - as was intended - -parse.y,builtins/read.def - - set terminate_immediately to non-zero value when reading interactive - input, as is done with interrupt_immediately - - 1/26 - ---- -doc/{bash.1,bashref.texi} - - reworded the POSIX standard references to remove mention of POSIX.2 - or 1003.2 -- it's all the 1003.1 standard now. Recommended by - Arnold Robbins - - 1/27 - ---- -lib/readline/complete.c - - move call to filename dequoting function into - rl_filename_completion_function; call only if directory completion - hook isn't set. This means that directory-completion-hook now needs - to dequote the directory name. We don't want to dequote the directory - name before calling the directory-completion-hook. Bug reported by - Andrew Parker - -bashline.c - - add necessary directory name dequoting to bash_directory_expansion - and bash_directory_completion_hook - -lib/readline/doc/rltech.texi - - add note to description of rl_directory_completion_hook that it - needs to dequote the directory name even if no other expansions are - performed - - 1/28 - ---- -braces.c - - make sure that we skip over braces that don't start a valid matched - brace expansion construct in brace_expand -- there might be a valid - brace expansion after the unmatched `{' later in the string - - brace_gobbler now checks that when looking for a `}' to end a brace - expansion word, there is an unquoted `,' or `..' that's not inside - another pair of braces. Fixes the a{b{c,d}e}f problem reported by - Tim Waugh - -builtins/declare.def - - when not in posix mode, and operating on shell functions, typeset - and declare do not require their variable operands to be valid - shell identifiers. The other `attribute' builtins work this way. - Fixes inconsistency reported by Mike Frysinger - -{configure,config.h}.in - - add test for setregid, define HAVE_SETREGID and HAVE_DECL_SETREGID - as appropriate - - add test for eaccess, define HAVE_EACCESS if found - -lib/sh/eaccess.c - - new file, with sh_stat and sh_eaccess functions, moved from test.c - - renamed old sh_eaccess as sh_stataccess, since it uses the stat(2) - information to determine file accessibility - - new function, sh_euidaccess, to call when uid != euid or gid != egid; - temporarily swaps uid/euid and gid/egid around call to access - - rewrote sh_eaccess to call eaccess, access, sh_euidaccess or - sh_stataccess as appropriate. access(2) will take into account - things like ACLs, read-only file systems, file flags, and so on. - -lib/sh/Makefile.in,Makefile.in - - add necessary entries for eaccess.[co] - -test.c - - change calls to test_stat to call sh_stat - -{test,general}.c - - change calls to test_eaccess to call sh_eaccess - -externs.h - - new extern declaration for sh_eaccess - -test.[ch] - - remove test_stat and test_eaccess - - 1/29 - ---- -braces.c - - make change from 1/28 dependant on CSH_BRACE_COMPAT not being - defined (since old bash behavior is what csh does, defining - CSH_BRACE_COMPAT will produce old bash behavior) - - 1/30 - ---- -bashline.c - - last argument of bash_default_completion is now a flags word: - DEFCOMP_CMDPOS (in command position) is only current value - - attempt_shell_completion now computes flags before calling - bash_default_completion - - if no_empty_command_completion is set, bash does not attempt command - word completion even if not at the beginning of the line, as long - as the word to be completed is empty and start == end (catches - beginning of line and all whitespace preceding point) - - 2/4 - --- -lib/readline/display.c - - change _rl_make_prompt_for_search to use rl_prompt and append the - search character to it, so the call to expand_prompt in rl_message - will process the non-printing characters correctly. Bug reported - by Mike Stroyan - - 2/5 - --- -lib/readline/display.c - - fix off-by-one error when comparing against PROMPT_ENDING_INDEX, - which caused a prompt with invisible characters to be redrawn one - extra time in a multibyte locale. Change from <= to < fixes - multibyte locale, but I added 1 to single-byte definition of - PROMPT_ENDING_INDEX (worth checking) to compensate. Bug reported - by Egmont Koblinger - - 2/8 - --- -lib/readline/terminal.c - - call _emx_get_screensize with wr, wc like ioctl code for consistency - - new function, _win_get_screensize, gets screen dimensions using - standard Windows API for mingw32 (code from Denis Pilat) - - call _win_get_screensize from _rl_get_screen_size on mingw32 - -lib/readline/rlconf.h - - define SYS_INPUTRC (/etc/inputrc) as system-wide default inputrc - filename - -support/shobj-conf - - changes to make loadable builtins work on MacOS X 10.[34] - -builtins/pushd.def - - changes to make it work as a loadable builtin compiled with gcc4 - - 2/9 - --- -lib/readline/bind.c - - add SYS_INPUTRC as last-ditch default (if DEFAULT_INPUTRC does not - exist or can't be read) in rl_read_init_file - -lib/readline/doc/rluser.texi - - add description of /etc/inputrc as ultimate default startup file - - 2/10 - ---- -lib/readline/bind.c - - fix problem with rl_function_of_keyseq that returns a non-keymap - bound to a portion of the passed key sequence without processing - the entire thing. We can bind maps with existing non-map - functions using the ANYOTHERKEY binding code. - -variables.c - - shells running in posix mode do not set $HOME, as POSIX apparently - requires - - 2/15 - ---- -braces.c - - mkseq() now takes the increment as an argument; changed callers - - 2/16 - ---- -builtins/hash.def - - print `hash table empty' message to stdout instead of stderr - - 2/17 - ---- -lib/readline/readline.c - - when resetting rl_prompt in rl_set_prompt, make sure rl_display_prompt - is set when the function returns - - 2/18 - ---- -lib/readline/display.c - - further fixes to _rl_make_prompt_for_search from Eric Blake to deal - with multiple calls to expand_prompt - - 2/21 - ---- -builtins/hash.def - - don't print `hash table empty' message in posix mode - - 2/27 - ---- -lib/glob/sm_loop.c - - change extmatch() to turn off FNM_PERIOD in flags passed to recursive - calls to gmatch() when calling it with a substring after the start - of the string it receives. Changed `+', `*', `?, `@', and `!' cases - to do the right thing. Fixes bug reported by Benoit Vila - - -braces.c - - add QUIT; statements to mkseq to make large sequence generation - interruptible - - 2/28 - ---- -lib/glob/glob.c - - initialize nalloca in glob_vector - - 3/1 - --- -lib/glob/glob.c - - in glob_vector, when freeing up the linked list after some error, - make sure to set `tmplink' to 0 if `firstlink' is set to 0, else we - get multiple-free errors - - 3/5 - --- -trap.c - - inheritance of the DEBUG, RETURN, and ERR traps is now dependent - only on the `functrace' and `errtrace' shell options, as the - documentation says, rather than on whether or not the shell is in - debugging mode. Reported by Philip Susi - -parse.y - - in parse_matched_pair, don't recursively parse ${...} or other - ${...} constructs inside `` - - in parse_matched_pair, remove special code that recursively parses - quoted strings inside `` constructs. For Bourne shell compatibility - - 3/6 - --- -builtins/pushd.def - - let get_directory_stack take take an `int flags' argument and convert - $HOME to ~ if flags&1 is non-zero - -builtins/common.h - - change extern declaration for get_directory_stack - -variables.c - - call get_directory_stack with an arg of 0 to inhibit converting - $HOME to ~ in the result. Fixes cd ${DIRSTACK[1]} problem - reported by Len Lattanzi (cd fails because - the tildes won't be expanded after variable expansion) - -jobs.c - - changed hangup_all_jobs slightly so stopped jobs marked J_NOHUP - won't get a SIGCONT - -general.c - - changed check_binary_file() to check for a NUL byte instead of a - non-printable character. Might at some point want to check - entire (possibly multibyte) characters instead of just bytes. Hint - from ksh via David Korn - - 3/7 - --- -builtins/reserved.def - - changed runs of spaces to tabs in variables help text to make - indentation better when displayed - -builtins/mkbuiltins.c - - changes to avoid the annoying extra space that keeps gettext from - being passed an empty string - - 3/9 - --- -lib/glob/glob.c - - make sure globbing is interrupted if the shell receives a terminating - signal - - 3/14 - ---- -lib/readline/search.c - - call rl_message with format argument of "%" in _rl_nsearch_init - to avoid `%' characters in the prompt string from being interpreted - as format specifiers to vsnprintf/vsprintf - - 3/19 - ---- -parse.y, eval.c, input.h - - change execute_prompt_command to execute_variable_command; takes the - variable name as a new second argument - - 3/25 - ---- -bashline.c - - command_word_completion_function keeps track of when it's searching - $PATH and doesn't return directory names as matches in that case. - Problem reported by Pascal Terjan - - command_word_completion_function returns what it's passed as a - possible match if it's the name of a directory in the current - directory (only non-absolute pathnames are so tested). - - 3/27 - ---- -subst.c - - expand_arith_string takes a new argument: quoted. Either 0 (outside - subst.c) or Q_DOUBLE_QUOTES (substitution functions); changed callers - -subst.h - - changed extern declaration for expand_arith_string - -arrayfunc.c - - changed call to expand_arith_string in array_expand_index - - 3/31 - ---- -lib/readline/histfile.c - - change read_history_range to allow windows-like \r\n line endings - -execute_cmd.c - - add new variable, line_number_for_err_trap, currently set but not - used - - 4/2 - --- -lib/sh/strtrans.c - - add code to echo -e and echo with xpg_echo enabled to require - a leading 0 to specify octal constants - - 4/3 - --- -subst.c - - slight change to wcsdup() replacement: use memcpy instead of wcscpy - -parse.y - - before turning on W_COMPASSIGN, make sure the final character in the - token is a `(' (avoids problems with things like a=(4*3)/2) - - 4/4 - --- -lib/sh/snprintf.c - - in number() and lnumber(), turn off PF_ZEROPAD if explicit precision - supplied in format - - change number() and lnumber() to correctly implement zero-padding - specified by a non-zero `.precision' part of the format - -subst.c - - new flag for extract_delimited_string: EX_COMMAND. For $(...), so - we can do things like skip over delimiters in comments. Added to - appropriate callers - - changes to extract_delimited_string to skip over shell comments when - extracting a command for $(...) (EX_COMMAND is contained in the - flags argument) - - 4/5 - --- -subst.c - - first argument to skip_single_quoted is now a const char * - - new function, chk_arithsub, checks for valid arithmetic expressions - by balancing parentheses. Fix based on a patch from Len Lattanzi - - 4/6 - --- -{configure,config.h}.in - - add separate test for isnan in libc, instead of piggybacking on - isinf-in-libc test - -lib/sh/snprintf.c - - separate the isnan replacement function so it's guarded by its own - HAVE_ISNAN_IN_LIBC define - -lib/sh/wcsdup.c - - new file, contains replacement wcsdup library function from subst.c - with change back to using wcscpy - -Makefile.in,lib/sh/Makefile.in - - make sure wcsdup.c is compiled and linked in - -subst.c - - wcsdup now found in libsh; removed static definition - - 4/10 - ---- -lib/readline/callback.c - - loop over body of rl_callback_read_char as long as there is additional - input rather than just calling readline_internal_char, which does - not handle multi-character key sequences or escape-prefixed chars - -lib/readline/macro.c - - make sure we turn off RL_STATE_MACROINPUT when the macro stack is - empty if we are reading additional input with RL_STATE_MOREINPUT - -support/shobj-conf - - Mac OS X no longer likes the `-bundle' option to gcc when creating a - dynamic shared library - - 4/11 - ---- -lib/tilde/tilde.c - - don't try to dereference user_entry if HAVE_GETPWENT isn't defined - -lib/readline/input.c - - make sure chars_avail is not used without being assigned a value in - rl_gather_tyi - - use _kbhit() to check for available input on Windows consoles, in - rl_gather_tyi and _rl_input_available - - 4/21 - ---- -lib/readline/display.c - - calculate (in expand_prompt) and keep track of length of local_prompt - in local_prompt_len; use where appropriate - - when using o_pos to check whether or not we need to adjust - _rl_last_c_pos after calling update_line, assume that it's correct - (a buffer index in non-multibyte locales and a cursor position in - multibyte locales) and adjust with wrap_offset as appropriate - - in update_line, set cpos_adjusted to 1 after calling - _rl_move_cursor_relative to move to the end of the displayed prompt - string - - in _rl_move_cursor_relative, check that the multibyte display - position is after the last invisible character in the prompt string - before offsetting it by the number of invisible characters in the - prompt (woff) - - 4/26 - ---- -lib/readline/doc/{rluser.texi,readline.3} - - make sure to note that key bindings don't allow any whitespace - between the key name or sequence to be bound and the colon - - 4/28 - ---- -lib/readline/display.c - - in update_line, make sure we compare _rl_last_c_pos as strictly less - than PROMPT_ENDING_INDEX, since it's 0-based, to avoid multiple - prompt redraws - - 5/4 - --- -parse.y - - in decode_prompt_string, only prefix the expansion of \[ or \] - with CTLESC if the corresponding readline escape character is - CTLESC (coincidentally the same as \[) or CTLNUL. Bug report sent - by Mike Frysinger prompted the discovery - -aclocal.m4 - - slight change to test for /dev/fd to compensate for a linux - failing; suggested by Mike Frysinger - - 5/9 - --- -arrayfunc.c - - broke assign_array_var_from_string into two functions: - expand_compound_array_assignment and assign_compound_array_list; - assign_array_var_from_string just calls those functions now - -arrayfunc.h - - new extern declarations for expand_compound_array_assignment and - assign_compound_array_list - -subst.c - - in do_compound_assignment, call expand_compound_array_assignment - before creating the local variable so a previous inherited - value can be used when expanding the rhs of the compound assignment - statement - - 5/11 - ---- -doc/{bash.1,bashref.texi} - - clarifed `trap' description to make it clear that trapped signals - that are not set to SIG_IGN are reset when a subshell is created - - 5/18 - ---- -locale.c - - change reset_locale_vars to call setlocale (LC_ALL, "") if LANG - is unset or NULL - - if LANG is unset or NULL, reset the export environment before - calling setlocale in reset_locale_vars, and trust that it will - change the environment setlocale() inspects - - 5/21 - ---- -lib/readline/history.c - - new function, HIST_ENTRY *alloc_history_entry (char *string, char *ts); - creates a new history entry with text STRING and timestamp TS (both - of which may be NULL) - - new function, HIST_ENTRY *copy_history_entry (HIST_ENTRY *hist), - which copies the line and timestamp entries to new memory but just - copies the data member, since that's an opaque pointer - - new function, void replace_history_data (int which, histdata_t *old, histdata_t *new) - which replaces the `data' member of specified history entries with - NEW, as long as it is OLD. WHICH says which history entries to - modify - - add calls to replace_history_data in rl_free_undo_list and - rl_do_undo - -lib/readline/undo.c - - new function, alloc_undo_entry (enum undo_code what, int start, int end, char *text) - takes care of allocating and populating a struct for an individual - undo list entry - - new function: _rl_copy_undo_entry(UNDO_LIST *entry) - - new function: _rl_copy_undo_list(UNDO_LIST *head) - -lib/readline/rlprivate.h - - new extern declarations for _rl_copy_undo_{entry,list} - -execute_cmd.c - - change execute_cond_node so that quoting the rhs of the =~ - operator forces string matching, like the == and != operators - - 5/23 - ---- -redir.c - - add_undo_redirect now takes as an additional argument the type of - redirection we're trying to undo - - don't add a "preservation" redirection for fds > SHELL_FD_BASE if - the redirection is closing the fd - - 5/24 - ---- -subst.c - - make sure that parameter_brace_substring leaves this_command_name - set to either NULL or its previous value after setting it so that - arithmetic evaluation errors while expanding substring values - contain meaningful information - - 6/9 - --- -execute_cmd.c - - make sure that SUBSHELL_ASYNC and SUBSHELL_PIPE are set as flag bits - in subshell_environment, rather than setting only a single value - - change execute_subshell_builtin_or_function to give the `return' - builtin a place to longjmp to when executed in a subshell or pipeline - (mostly as the last command in a pipeline). Bug reported by - Oleg Verych - - in execute_simple_command, make sure to call execute_disk_command - with the_printed_command_except_trap to keep DEBUG trap command - strings from overwriting the command strings associated with jobs - and printed in job control messages. Bug reported by Daniel Kahn - Gillmor - -[bash-3.2-alpha frozen] - - 6/22 - ---- -syntax.h - - add new CBLANK (for [:blank:] class) flag value for syntax table and - shellblank(c) character test macro - -mksyntax.c - - add support for setting CBLANK flag in the syntax table depending on - whether or not isblank(x) returns true for character x - -locale.c - - change locale_setblanks to set or unset CBLANK flag for each - character when locale changes - -parse.y - - change call to whitespace(c) in lexical analyzer (read_token()) to - call shellblank(c) instead, so locale-specific blank characters are - treated as white space. Fixes bug reported by Serge van deb Boom - - -print_cmd.c - - when printing redirections, add a space between <, >, and <> and the - following word, to avoid conflicts with process substitution. Bug - reported by Ittay Dror - - 6/26 - ---- -configure.in - - set CROSS_COMPILE to the empty string by default, so we don't inherit - a random value from the environment. Bug reported by - Lee Revell - - 6/29 - ---- -lib/glob/xmbsrtowcs.c - - make sure destp is non-null before assigning a 0 to *destp in - xdupmbstowcs. Fix from Louiwa Salem - -execute_cmd.c - - fix execute_in_subshell to make sure asynchronous isn't set to 0 - before subshell_environment is set appropriately and - setup_async_signals is run. Based on report by Louiwa Salem - - -lib/readline/bind.c - - in rl_generic_bind(), make sure that the keys array is freed before - an error return. Fix from Louiwa Salem - - 7/1 - --- -builtins/read.def - - make sure all editing code is protected with #ifdef READLINE, esp. - unwind-protect that restores the default completion function - -lib/readline/display.c - - make sure to set local_prompt_len in rl_message() [in bash-3.2-alpha] - - 7/5 - --- -builtins/printf.def - - add more of echo's write error handling to printf. Suggested by - martin.wilck@fujitsu-siemens.com - - 7/7 - --- -lib/readline/display.c - - save and restore local_prompt_len in rl_{save,restore}_prompt - [in bash-3.2-alpha] - - 7/8 - --- -[bash-3.2-alpha released] - - 7/9 - --- -lib/readline/display.c - - make sure that _rl_move_cursor_relative sets cpos_adjusted when it - offsets `dpos' by wrap_offset in a multi-byte locale. Bug reported - by Andreas Schwab and Egmont Koblinger - -subst.c - - make sure that the call to mbstowcs in string_extract_verbatim is - passed a string with enough space for the closing NUL. Reported - by Andreas Schwab - - 7/18 - ---- -lib/readline/{display,terminal}.c - - remove #ifdefs for HACK_TERMCAP_MOTION so we can use - _rl_term_forward_char in the redisplay code unconditionally - -lib/readline/rlprivate.h - - new extern declaration for _rl_term_forward_char - -lib/readline/display.c - - in _rl_move_cursor_relative, use `dpos' instead of `new' when - deciding whether or not a CR is faster than moving the cursor from - its current position - - in _rl_move_cursor_relative, we can use _rl_term_forward_char to - move the cursor forward in a multibyte locale, if it's available. - Since that function doesn't have a handle on where the cursor is in - the display buffer, it has to output a cr and print all the data. - Fixes rest of problem reported by Egmont Koblinger - - change variable denoting the position of the cursor in the line buffer - from c_pos (variable local to rl_redisplay) to cpos_buffer_position - (variable local to file) for future use by other functions - - 7/25 - ---- -lib/malloc/{stats,table}.h - - include for prototypes for memset, strlen - -lib/termcap/{termcap,tparam}.c - - include and provide macro replacement for bcopy if - necessary - - 7/27 - ---- -lib/readline/histexpand.c - - add support for `<<<' here-string redirection operator to - history_tokenize_word. Bug reported by agriffis@gentoo.org - -externs.h - - don't add prototype for strerror() if HAVE_STRERROR defined - - 7/29 - ---- -subst.c - - in list_string, use `string' instead of `s' -- s is not initialized - - 8/9 - --- -subst.c - - fix parameter_brace_expand to set W_HASQUOTEDNULL in the WORD_DESC it - returns if the result of parameter_brace_substring is a quoted null - ("\177"). Fixes bug reported by Igor Peshansky - - 8/16 - ---- -lib/readline/readline.h - - new #define, READERR, intended to be used to denote read/input errors - -lib/readline/input.c - - in rl_getc, if read() returns an error other than EINTR (after the - EWOULDBLOCK/EAGAIN cases are handled), return READERR rather than - converting return value to EOF if readline is reading a top-level - command (RL_STATE_READCMD) - -lib/readline/readline.c - - if rl_read_key returns READERR to readline_internal_char[loop], - abort as if it had read EOF on an empty line, without any conversion - to newline, which would cause a partial line to be executed. This - fixes the bug reported by Mathieu Bonnet - -aclocal.m4 - - when testing for validity of /dev/fd/3, use /dev/null instead of - standard input, since the standard input fails with linux and `su'. - Bug reported by Greg Shafer - - 8/17 - ---- -Makefile.in - - switch the TAGS and tags targets so TAGS is the output of `etags' and - tags is the output of `ctags'. Suggested by Masatake YAMATO - - 8/25 - ---- -execute_cmd.c - - change code to match documentation: set BASH_COMMAND (which takes its - value from the_printed_command_except_trap) only when not running a - trap. Rocky says the debugger is ok with this, and this is what his - original diffs did - - 8/29 - ---- -variables.c - - change set_if_not to create shell_variables if it is NULL, since - -o invocation options can cause variables to be set before the - environment is scanned - -[bash-3.2-beta frozen] - - 9/5 - --- -[bash-3.2-beta released] - - 9/8 - --- -variables.c - - change dispose_used_env_vars to call maybe_make_export_env - immediately if we're disposing a temporary environment, since - `environ' points to the export environment and getenv() will use - that on systems that don't allow getenv() to be replaced. This - could cause the temporary environment to affect the shell. Bug - reported by Vasco Pedro - -builtins/echo.def,doc/{bash.1,bashref.texi} - - clarify that `echo -e' and echo when the `xpg_echo' shell option is - enabled require the \0 to precede any octal constant to be expanded. - Reported by Vasco Pedro - - 9/12 - ---- -builtins/printf.def - - make sure `%q' format specifier outputs '' for empty string arguments - Bug reported by Egmont Koblinger - -make_cmd.c - - change make_here_document to echo lines in here-doc if set -v has - been executed. Reported by Eduardo Ochs - -aclocal.m4 - - change BASH_CHECK_MULTIBYTE: - o replace check for wctomb with check for wcrtomb - o add checks for wcscoll, iswctype, iswupper, iswlower, - towupper, towlower - o add call to AC_FUNC_MBRTOWC to check for mbrtowc and mbstate_t - define HAVE_MBSTATE_T manually - o add checks for wchar_t, wctype_t, wint_t - -config.h.in - - add defines for wcscoll, iswctype, iswupper, iswlower, towupper, - towlower functions - - replace define for wctomb with one for wcrtomb - - add defines for wchar_t, wint_t, wctype_t types - -config-bot.h, lib/readline/rlmbutil.h - - add check for HAVE_LOCALE_H before defining HANDLE_MULTIBYTE - - add checks for: ISWCTYPE, ISWLOWER, ISWUPPER, TOWLOWER, TOWUPPER - - add checks for: WCTYPE_T, WCHAR_T, WCTYPE_T - - 9/13 - ---- -lib/readline/display.c - - when displaying prompts longer than the screenwidth in rl_redisplay, - and looking for the index of the last character whose buffer index - is <= the screen width to set up the inv_lbreaks array, make sure to - catch the case where the index == the screen width (an off-by-one - error occurs otherwise with prompts one character longer than the - screen width). Bug reported by Alexey Toptygin - -configure.in - - change DEBUGGER_START_FILE to start with ${ac_default_prefix}/share, - like bashdb installs itself. Reported by Nick Brown - - - 9/14 - ---- -lib/readline/display.c - - make multibyte code that computes the buffer indices of line breaks - for a multi-line prompt dependent on MB_CUR_MAX, so we don't take - the function call hit unless we're in a locale that can have - multibyte characters - - 9/19 - ---- -subst.c - - make dequote_list extern so other parts of the shell can use it - -subst.h - - extern declaration for dequote_list - -builtins/read.def - - call dequote_list before assigning words read to array variable if - we saw an escape character. Old code left spurious CTLESCs in the - string after processing backslashes. Bug reported by Daniel Dawson - - - 9/21 - ---- -[bash-3.2 frozen] - - 10/9 - ---- -support/shobj-coonf - - change -fpic to -fPIC for FreeBSD systems (needed for SPARC at least) - - 10/11 - ----- -[bash-3.2 released] - - 10/12 - ----- -parse.y - - change parse_matched_pair to make sure `` command substitution does - not check for shell comments while parsing. Bug reported against - bash-3.2 by Greg Schaefer - - 10/14 - ----- -parse.y - - add new parser_state flag: PST_REGEXP; means we are parsing a - regular expression following the =~ conditional operator - - cond_node sets PST_REGEXP after reading the `=~' operator - - change read_token to call read_token_word immediately if the - PST_REGEXP bit is set in parser_state - - change read_token_word to skip over `(' and `|' if PST_REGEXP is - set, since those characters are legitimate regexp chars (but still - parse matched pairs of parens) - - 10/16 - ----- -builtins/ulimit.def - - add -e and -r to $SHORT_DOC usage string - -po/ru.po - - fix encoding; Russian text in the file is actually encoded in KOI8-R - - 10/23 - ----- -shell.c - - make sure that the call to move_to_high_fd in open_shell_script - passes 1 for the `check_new' parameter so open high file descriptors - don't get closed and reused. Bug reported by Mike Stroyan - - -doc/bashref.texi - - fixes for typos and misspellings sent in by Brian Gough - - 10/24 - ----- -support/shobj-conf - - make netbsd shared library creation like openbsd's until I hear - differently (called using `gcc -shared') - - 10/26 - ----- -subst.c - - fix bug in parameter_brace_patsub so if the first character of the - expanded pattern is a `/', it is not taken as a global replacement - specifier. Bug reported on forums.nekochan.net - - 10/27 - ----- -builtins/printf.def - - if we need an extern declaration for asprintf, make sure we include - stdarg.h or varargs.h, whichever is appropriate - - if we do not have asprintf, add an extern declaration using - stdarg format. This fixes the bugs with %G on IRIX reported by - Matthew Woehlke and Stuart Shelton - - - -lib/sh/snprintf.c - - add note to not call log_10 with 0 argument -- we don't want to do - what real log10 does (-infinity/raise divide-by-zero exception) - - make sure numtoa (used by dtoa) takes the precision into account - when computing the fractional part with an argument of `0.0' - - make sure `g' and `G' formats don't print radix char if there are - no characters to be printed after it (change to floating()) - - change callers of log_10 (exponent, 'g' and 'G' cases in - vsnprintf_internal) to not call it with 0 for argument. This fixes - the hang reported on IRIX by Matthew Woehlke - and Stuart Shelton - - 10/28 - ----- -builtins/{caller,pushd}.def - - changed longdoc strings in loadable builtin section to be single - strings, as put in the build directory builtins.c file, to aid - translators - - 11/1 - ---- -execute_cmd.c - - reset subshell_environment to 0 after make_child() call in - execute_null_command. Fix provided by Roy Marples - - - 11/7 - ---- -lib/tilde/tilde.c -lib/readline/{util,undo,callback,input,isearch,kill}.c - - make sure that memory allocated with xmalloc is freed with xfree - - 11/9 - ---- -lib/readline/display.c - - make sure that _rl_redisplay_after_sigwinch clears the last displayed - line instead of the current line (instead of assuming that the - cursor is on the last line). Fixes bug reported by Egmont - Koblinger - - 11/10 - ----- -lib/readline/display.c - - make sure that _rl_col_width is never called with MB_CUR_MAX == 1, - since it doesn't count invisible characters and they are not - compensated for. Added a warning in _rl_col_width if called when - MB_CUR_MAX == 1. Bug reported and solution suggested by Eric - Blake - - 11/11 - ----- -lib/readline/display.c - - make sure _rl_wrapped_line is initialized to inv_lbsize int chars. - inv_lbsize and vis_lbsize are the same at that point, but it makes - the intent clearer. Fix from jan.kratochvil@redhat.com. - - in rl_redisplay, make sure we call memset on _rl_wrapped_line with - its full initialized size: inv_lbsize*sizeof(int). Fix from - jan.kratochvil@redhat.com. - - wrap the invisible and visible line variables and _rl_wrapped_line - into line_state structures, which can be swapped more efficiently. - Have to watch the wrapped_line field, since there's now one for - each struct. Changes from jan.kratochvil@redhat.com. - -lib/readline/complete.c - - in stat_char, check for `//server' on cygwin and return `/', since - it will always behave as a directory. Fix from Eric Blake - -lib/readline/histfile.c - - Cygwin's mmap() works in recent versions, so don't #undef HAVE_MMAP. - Recommendation from Eric Blake - -lib/readline/rlwinsize.h - - make sure tcflow() is defined on SCO Unix. Fix from William Bader - -aclocal.m4 - - add check for localeconv to AM_INTL_SUBDIR macro - -config.h.in - - add HAVE_LOCALECONV - -lib/sh/snprintf.c - - add check for HAVE_LOCALECONV for GETLOCALEDATA macro - -general.[ch] - - first argument to legal_number is now `const char *' - - 11/14 - ----- -lib/readline/{readline,rlprivate}.h - - move rl_display_prompt declaration from rlprivate.h to readline.h - -lib/readline/util.h - - new function: rl_free(void *mem), for use by users of readline dlls - on Windows - -lib/readline/readline.h - - new extern declaration for rl_free - -lib/readline/doc/rltech.texi - - document rl_free and rl_display_prompt for use by application writers - - 11/15 - ----- -aclocal.m4 - - change tests for /dev/fd and /dev/stdin to use constructs of the form - (exec test ... ) instead of test ... to avoid bash's /dev/fd and - /dev/stdin emulation - - 11/16 - ----- -jobs.c - - in delete_job, reset_current was being called before the job slot - was cleared -- moved after job_slots[job] was set to NULL. Fixes - bug reported by Dan Jacobson - - 11/19 - ----- -findcmd.c - - when the checkhash option is set, fix the check for the hashed - pathname being an existing executable file. Old code required a - hash table deletion and re-addition. Bug reported by Linda - Walsh - - 11/21 - ----- -subst.c - - in pos_params, handle case of `start' == 0 by making the list of - positional parameters begin with $0 - - in parameter_brace_substring, increment `len' if start == 0, sicne - we will be adding $0 to the beginning of the list when we process it - -doc/{bash.1,bashref.texi} - - document new behavior of `0' offset when using substring expansion - with the positional parameters - -support/shobj-conf - - changes to shared object creation for loadable builtins on Mac OS X - 10.4 to use libtool instead of ld by specifying -dynamiclib - argument and changing options to be appropriate for libtool. This - winds up creating a dynamic shared library instead of an executable - - 11/24 - ----- -{jobs,nojobs}.c - - don't set last_asynchronous_pid to the child's pid in the child - for asynchronous jobs (for compatibility -- all other posix shells - seem to do it this way). This means that (echo $! )& echo $! should - display two different pids. Fix from discussion on the - austin-group-l list - -builtins/mkbuiltins.c - - change builtins.c file generation so short doc strings are marked for - gettext and available for subsequent translation. Suggestion by - Benno Schulenberg - -builtins/{bind,cd,hash,inlib,printf,pushd,test,times,ulimit}.def -lib/malloc/malloc.c -{shell,subst}.c - - fix a few strings that were not marked as translatable. Fix from - Benno Schulenberg - -lib/readline/misc.c - - new function, _rl_revert_all_lines(void). Goes through history, - reverting all entries to their initial state by undoing any undo - lists. - -lib/readline/rlprivate.h - - extern declaration for _rl_revert_all_lines - -rldefs.h - - add #undef HAVE_STRCOLL if STRCOLL_BROKEN is defined, prep to move - from config.h.in. Problem reported by Valerly Ushakov - - - 11/25 - ----- -lib/readline/readline.c - - call _rl_revert_all_lines from readline_internal_teardown if the - variable _rl_revert_all_at_newline is non-zero - - declare _rl_revert_all_lines initially 0 - - 11/27 - ----- -doc/{bash.1,bashref.texi} - - make sure to be explicit that `typeset +r' cannot remove the readonly - attribute from a variable - - 11/28 - ----- -lib/sh/zmapfd.c - - new file, implements zmapfd(), which takes a file and returns its - contents in a string - -externs.h - - extern declaration for zmapfd - - 11/29 - ----- -builtins/evalfile.c - - in _evalfile, use zmapfd to read the contents of the file into a - string, rather than using the size reported by stat and reading that - many characters, if the file is not a regular file (for things like - named pipes, stat reports the size as 0) - - 12/3 - ---- -lib/sh/snprintf.c - - make sure number() sets the FL_UNSIGNED flag for %x and %X, so - fmtulong treats them as unsigned numbers. Fixes bug reported by - James Botte - - 12/13 - ----- -lib/readline/util.c - - new function, _rl_ttymsg, for internal warning messages -- does - redisplay after printing message - - new function, _rl_errmsg, for internal warning/error messages -- - does not do redisplay after printing message - -lib/readline/rlprivate.h - - new extern declaration for _rl_ttymsg, _rl_errmsg - -lib/readline/{bind,callback,complete,display,rltty}.c - - use _rl_ttymsg/_rl_errmsg instead of direct writes to stderr - -lib/sh/tmpfile.c - - in get_tmpdir(), make sure that $TMPDIR names a writable directory; - otherwise skip it. This catches names longer than PATH_MAX, but in - case it doesn't test that the length does not exceed PATH_MAX. Fixes - heap overrun bug reported by Eric Blake - - 12/16 - ----- -builtin/{set,declare,shopt,trap,wait,bind,complete,enable,fc,history,read,setattr}.def -doc/{bash.1,bashref.texi} - - improvements and clarifications to the help text associated with - several builtins, in some cases bringing them into line with the - man page text. From Benno Schulenberg - -doc/{bash.1,bashref.texi} - - add `E' and `T' to the synopsis of the set builtin. - From Benno Schulenberg - -builtins/{break,exit,fg_bg,hash,jobs,type,ulimit}.def -builtins/{common,evalfile}.c -{error,expr,jobs,mksyntax,nojobs,shell,subst,version,siglist}.c - - add gettextizing marks to untranslated strings - From Benno Schulenberg - - 12/19 - ----- -builtins/common.c - - change display_signal_list (used by `trap -l' and `kill -l') to use - five columns instead of 4 to display signal names - -builtins/help.def - - use the true terminal width instead of assuming 80 when displaying - help topics, leaving two characters of whitespace between horizontal - descriptions instead of 1 - - change to print in columns with entries sorted down rather than across - (that is, like `ls' rather than `ls -x'). Change inspired by Benno - Schulenberg - -jobs.h - - give values to the JOB_STATE enumerations so they can be used as - bitmasks, too - - 12/22 - ----- -doc/{bash.1,bashref.texi} - - change description of `set' to make it clearer that you can use - `+' to turn off options - - clarify in the description of word splitting that sequences of - IFS whitespace at the beginning or end of the string are ignored - - 12/26 - ----- -doc/bashref.texi - - move `shopt' builtin to its own section; change internal references - from `Bash Builtins' to the new shopt builtin - - new section for builtins that modify shell behavior in `Shell - Builtin Commands'; move set and shopt to new section. Changes - inspired by Benno Schulenberg - -{redir,subst}.c - - add MT_USETMPDIR flag to calls to sh_mktmpfd and sh_mktmpname. Bug - reported by Eric Blake - -{configure,Makefile}.in - - changes so that the pathname for DEBUGGER_START_FILE is substituted - into pathnames.h at make time (allowing more flexibility in setting - `prefix' or `datadir') instead of at configure time. Suggested by - Nick Brown - -shell.c - - declaration for have_devfd; initialized from HAVE_DEV_FD - - declaration for check_jobs_at_exit; initialized to 0 - - declaration for autocd; initialized to 0 - -variables.c - - new dynamic variable, BASHPID, always set from return value from - getpid() (changes even when $$ doesn't change). Idea from Bruce - Korb - -builtins/exit.def - - if check_jobs_at_exit is non-zero, list jobs if there are any stopped - or running background jobs; don't exit shell if any running jobs - -execute_cmd.c - - in execute_simple_command, if the first word of a simple command is - a directory name (after looking for builtins, so `.' isn't caught) - that isn't found in $PATH, and `autocd' is non-zero, prefix a "cd" - to the command words - -builtins/shopt.def - - new `checkjobs' option, changes value of check_jobs_at_exit - - new `autocd' option, changes value of autocd - -pcomplete.c - - add COMP_TYPE, set to rl_completion_type, to list of variables set - by bind_compfunc_variables and unset by unbind_compfunc_variables - -doc/{bash.1,bashref.texi} - - document BASHPID - - document new shopt `checkjobs' option - - document new shopt `autocd' option - - document COMP_TYPE completion variable - - 12/29 - ----- -aclocal.m4 - - in BASH_SYS_SIGLIST, check HAVE_DECL_SYS_SIGLIST instead of the - obsolete and no-longer-supported SYS_SIGLIST_DECLARED - - 12/30 - ----- -lib/readline/vi_mode.c - - add ` (backquote) to the list of vi motion characters - - in rl_vi_delete_to, rl_vi_change_to, and rl_vi_yank_to, don't delete - character under the cursor if the motion command moves the cursor - backward, so add F and T to the commands that don't cause the - mark to be adjusted - - add ` to the characters that don't cause the mark to be adjusted - when used as a motion command, since it's defined to behave that way - - when a motion character that may adjust the mark moves point - backward, don't adjust the mark so the character under the cursor - isn't deleted - -lib/readline/complete.c - - add variable rl_sort_completion_matches; allows application to - inhibit match list sorting - - add variable rl_completion_invoking_key; allows applications to - discover the key that invoked rl_complete or rl_menu_complete - -lib/readline/readline.h - - extern declarations for rl_completion_invoking_key and - rl_sort_completion_matches - -lib/readline/doc/rltech.texi - - documented rl_completion_invoking_key and rl_sort_completion_matches - -pcomplete.c - - export variable COMP_KEY to completion functions; initialized from - rl_completion_invoking_key; unset along with rest of completion - variables - -doc/{bash.1,bashref.texi},lib/readline/doc/rluser.texi - - document COMP_KEY - -[many files] - - changes to make variables and function parameters `const' for better - text sharing. Changes originally from Andreas Mohr - - - 1/4/2007 - -------- -lib/intl/Makefile.in - - use cmp before copying libgnuintl.h to libintl.h -- maybe save a few - rebuilds - -lib/builtins/Makefile - - fixes to build LIBINTL_H if necessary, dependency on this for - mkbuiltins.o prevented `make -j 6' from working correctly - - 1/8 - --- -subst.c - - new function, fifos_pending(), returns the count of FIFOs in - fifo_list (process substitution) - -subst.h - - extern declaration for fifos_pending() - -execute_cmd.c - - in execute_simple_command, if CMD_NO_FORK is set before we call - execute_disk_command, make sure there are no FIFOs in the expanded - words (from process substitution) and turn off CMD_NO_FORK if there - are, so they can get unlinked when the command finishes - - 1/10 - ---- -subst.c - - read_comsub now takes a flags parameter and returns appropriate W_* - flags in it - - command_substitute now returns a WORD_DESC *, with the string it used - to return as the `word' and `flags' filled in appropriately - -subst.h - - changed extern declaration for command_substitute - -{pcomplete,subst}.c - - changed callers of command_substitute appropriately - -subst.c - - string_extract_verbatim now takes an additional int flags argument; - changed callers - - 1/11 - ---- -support/texi2html - - fix problem that caused index links to not be generated if the first - index node had a name different than the node name - -doc/bashref.texi - - encapsulated all indexes into a single `Indexes' appendix; works - around bug fixed in texi2html - - 1/12 - ---- -subst.c - - add call to sv_histtimefmt in initialize_variables so HISTTIMEFORMAT - from the environment is honored. Fix from Ark Submedes (heh) - - -lib/readline/histfile.c - - make sure that the first character following the history comment - character at the beginning of a line is a digit before interpreting - it as a timestamp for the previous line - -doc/{bash.1,bashref.texi},lib/readline/doc/hsuser.texi - - added detail to make it clear exactly how history timestamps are - saved to and read from the history file - -subst.c - - change quote_escapes to add CTLESC before spaces if IFS is null, - just in case we have to split on literal spaces later on (e.g., in - case of unquoted $@). Corresponding changes to dequote_escapes. - Fixes a couple of problems reported by Brett Stahlman - - - 1/14 - ---- -subst.c - - make same change to read_comsub to add CTLESC before ' ' if $IFS is - null, since we will split on literal spaces later - - 1/15 - ---- -array.c - - new function, array_quote_escapes (ARRAY *a), calls quote_escapes - on each element of the array in the same way array_quote calls - quote_string - - call array_quote_escapes if match is not quoted in array_patsub - - array_slice is now used, so remove the #ifdef INCLUDE_UNUSED define - - change structure of array_subrange to call array_slice to create a - new array with the desired subset of elements, then call array_quote - or array_quote_escapes as necessary, like array_patsub. Convert to - a string by calling array_to_string on the sliced-out array - -array.h - - new extern declaration for array_quote_escapes - -subst.c - - since array_patsub now calls quote_escapes as necessary, callers - don't need to call it after array_patsub returns. Fixes first bug - reported by Brett Stahlman - - since array_subrange now calls quote_escapes as necessary, callers - don't need to call it after array_patsub returns. Same fix as - for array_patsub - - 1/31 - ---- -configure.in - - add -DSOLARIS to LOCAL_CFLAGS for solaris x - -config-bot.h - - don't #undef HAVE_GETCWD if GETCWD_BROKEN and SOLARIS are both - defined. Solaris's loopback mount implementation breaks some of the - file system assumptions the replacement getcwd uses. - -builtins/common.c - - if GETCWD_BROKEN is defined, call getcwd with PATH_MAX for the size - argument, so it will allocate a buffer for the current working dir - with that size, instead of one that's `big enough' - -config.h.in - - add #undef PRI_MACROS_BROKEN for AIX 4.3.3 - -pathexp.h - - new flag value for quote_string_for_globbing: QGLOB_REGEXP (quoting - an ERE for matching as a string) - -pathexp.c - - change quote_string_for_globbing to understand QGLOB_REGEXP - -execute_cmd.c - - change execute_cond_node to pass 2 (regexp match), 1 (shell pattern - match), or 0 (no matching) to cond_expand_word - -subst.c - - change cond_expand_word to translate SPECIAL==2 into passing - QGLOB_REGEXP to quote_string_for_globbing - -locale.c - - by default, if all else fails, set shell's idea of locale to "" - instead of its idea of `default_locale' -- the library functions - behave better with that value - - 2/2 - --- -builtins/printf.def - - if PRI_MACROS_BROKEN is defined, #undef PRIdMAX (AIX 4.3.3 broken) - - 2/3 - --- -Makefile.in,{builtins,doc}/Makefile.in,lib/*/Makefile.in - - add assignment for datarootdir as per GNU coding standards - -Makefile.in,builtins/Makefile.in,lib/intl/Makefile.in,po/Makefile.in.in - - use @localedir@ instead of $(datadir)/locale in assignment - - 2/13 - ---- -jobs.c - - fix compact_jobs_list to not return js.j_lastj, since that is in use - and should not be overwritten. Fix from Len Lattanzi - - - 2/16 - ---- -lib/readline/text.c - - change rl_forward_char to allow moving to the end of the line when - using the arrow keys in vi insertion mode, rather than having the - behavior identical between vi command and insertion modes. Change - suggested by Hugh Sasse - - 2/19 - ---- -CWRU/audit-patch - - patch from Steve Grubb of RedHat to make bash - audit root's behavior by logging commands using his audit - framework. Enabled if the shell's name is `aubash'. - - 3/8 - --- -jobs.c - - use WSTATUS (p->status) instead of bare p->status. Fix from - Jim Brown - - 3/9 - --- -lib/readline/{complete,input,isearch,misc,readline,text,vi_mode}.c - - make sure cases where rl_read_key returns -1 (usually due to EIO - because the controlling tty has gone away) are handled correctly. - Prompted by report from Thomas Loeber - - 3/10 - ---- -sig.c - - new function, top_level_cleanup, callable from contexts where some - cleanup needs to be performed before a non-fatal call to - jump_to_top_level - -sig.h - - new extern declaration for top_level_cleanup - -builtins/common.c - - add calls to top_level_cleanup before calls to jump_to_top_level - in a builtin command context (no_args(), get_numeric_arg()). Fixes - bug reported by Ian Watson - -lib/readline/display.c - - in _rl_move_cursor_relative, use `new' when comparing against - the last invisible character in the prompt, since they both denote - buffer indices when in a multibyte locale, whereas `dpos' is a - display position - - 3/13 - ---- -lib/readline/complete.c - - set rl_completion_append_character to the default (' ') in - set_completion_defaults(). Fixes bug reported by David Emerson - - - 3/23 - ---- -builtins/evalfile.c - - make sure read() returns a value >= 0 before using it as an index - into string[] - - use a variable of type `ssize_t' for return value from read() - - only try to read the entire contents of a regular file in one shot - if the file size is less than SSIZE_MAX. These fix problems - reported by hooanon05@yahoo.co.jp. - -include/typemax.h - - define SSIZE_MAX as 32767 if it's not defined - -lib/readline/display.c - - in rl_redisplay() and update_line(), if redrawing the prompt because - it contains invisible characters, make sure we redraw the character - indicating a modified history line and take it into account when - computing _rl_last_c_pos - - in update_line, if deleting characters and redrawing the new text, - make sure we adjust _rl_last_c_pos by wrap_offset in a multibyte - locale if the text we're drawing starts before or at the last - invisible character in the prompt string. Fixes bug reported on - bug-readline by J Pelkey - -parse.y - - when adding at CTLESC character to the current token, do not - escape it with CTLESC if pass_next_character indicates that the - CTLESC was escaped by a backslash. Fixes bug reported by - Paul Bagshaw . - - 3/25 - ---- -lib/readline/text.c - - in rl_forward_char, short-circuit the loop if in emacs mode and - rl_point == rl_end. Fixes problem with multibyte locales - reported by Len Lattanzi - - 3/29 - ---- -command.h - - new flag for subshell_environment: SUBSHELL_PROCSUB, for process - substitution - -subst.c - - add SUBSHELL_PROCSUB to subshell_environment in process_substitute - - 3/30 - ---- -doc/Makefile.in - - fix installation of bash.info to understand that it is in the build - directory, not the source directory - -mailcheck.c - - new function, init_mail_dates, calls remember_mail_dates only if - there are no mailboxes in `mailfiles' - - new function, init_mail_file, initializes a FILEINFO, using the - last time mail was checked as the mtime and atime (or the time the - shell was started if last_time_mail_checked is uninitialized) - - call init_mail_file instead of update_mail_file in add_mail_file, - called from remember_mail_dates (which is supposed to initialize - the list of mail files) - - new convenience functions, alloc_mail_file and dispose_mail_file to - allocate and free FILEINFO structs - -mailcheck.h - - extern declaration for init_mail_dates - -shell.c - - call init_mail_dates instead of remember_mail_dates - - 4/4 - --- -builtins/read.def - - changes to print $PS2 when a line is continued with a backslash in - an interactive shell. This is as POSIX requires - - 4/5 - --- -subst.c - - make sure quote_escapes is only ever called when the word to be - escaped is not marked as double-quoted -- cleaner, and allows us - to make certain assumptions - - 4/6 - --- -subst.c - - change all EX_* defines to begin with SX_ - - new flag, SX_NOCTLESC, obeyed by string_extract_verbatim, tells it - to not obey CTLESC quoting - - change quote_escapes to not quote CTLESC with CTLESC if one of the - chars in $IFS is CTLESC, since the return value from quote_string - will be passed to word splitting and filename generation - - change read_comsub to do the same thing for unquoted command - substitutions - - change list_string to pass SX_NOCTLESC if CTLESC is one of the - chars in $IFS, so it will split on CTLESC instead of using it as a - quote character - - 4/7 - --- -subst.c - - slight change to string_extract_verbatim to allow CTLESC to quote - CTLNUL even if SX_NOCTLESC is set in the flags passed, to protect - the CTLNULs from future calls to remove_quoted_nulls. Only - matters when $IFS contains CTLESC - - changes to cope with $IFS containing CTLNUL in the same way as the - CTLESC changes - -builtins/read.def - - changes to cope with $IFS containing CTLNUL in the same way as the - CTLESC changes - - 4/16 - ---- -lib/sh/strftime.c - - a couple of fixes to the `%z' code - -eval.c - - add an fflush after printing the auto-logout message - - 4/24 - ---- -subst.c - - add call to top_level_cleanup in exp_jump_to_top_level to get things - like unwind-protects and the loop levels cleaned up - -{arrayfunc,expr,variables}.c - - add calls to top_level_cleanup before jump_to_top_level() - - 4/27 - ---- -builtins/complete.def - - make sure the `command' argument to the -C option is printed with - single quotes, since multi-word commands will require them. Bug - reported by martin@snowplow.org - -execute_cmd.c - - change execute_builtin_or_function and execute_subshell_builtin_or_function - to call fflush(stdout) after the builtin or function returns, to - make sure that all output is flushed before the call returns. It - matters on cygwin. Fix suggested by Eric Blake - -redir.c - - in do_redirection_internal, if the file descriptor being acted upon - is the same one used by the stdout stream, call fflush(stdout) to - make sure all output is flushed before changing the underlying fd - out from underneath stdio. Fix suggested by Eric Blake - - - 4/30 - ---- - -builtins/common.c - - new function, sh_chkwrite(int), fflushes stdout and checks for error; - printing an error message and returning a new exit status if there's - an error on stdout. Takes exit status as argument; returns new exit - status (EXECUTION_FAILURE if write error) - -builtins/common.h - - new extern declaration for sh_chkwrite - -builtins/{alias,cd,complete,echo,fc,history,pushd,shopt,times,trap,type,ulimit,umask}.def - - change to use sh_chkwrite to report write errors - -builtins/fc.def - - if an error occurs while writing commands from the history to a file - to be executed, report a write error and return failure without - attempting to execute any commands - - 5/1 - --- -builtins/{bind,declare,set,setattr}.def - - change to use sh_chkwrite to report write errors - - 5/2 - --- -lib/readline/input.c - - fix off-by-one errors in _rl_get_char (pop_index) and rl_stuff_char - (push_index) that caused the 511th character in the buffer to be - discarded. Fixes bug reported by Tom Bjorkholm - - 5/8 - --- -subst.c - - fix parameter_brace_remove_pattern to pass getpattern() newly-allocated - memory. If word expansions (particularly brace expansions) are - required, the expansion code will free the string passed to - expand_word_internal, and we don't want to free unallocated memory - (patstr++) or have duplicate frees (patstr). Fixes bug reported on - Red Hat bugzilla - - 5/9 - --- -lib/readline/signals.c - - fix bug in rl_set_signals that caught SIGINT twice and didn't catch - SIGTERM. Bug reported by Ed Kwan - - 5/18 - ---- -jobs.c - - change compact_jobs_list to return 1 if js.j_lastj == 0 and there is - a job in jobs[0]; compact_jobs_list should never return an index - already occupied - - change reset_job_indices to avoid infinite looping when js.j_firstj - == 0 or js.j_firstj == js.j_jobslots upon function entry. Fixes - bug reported by osicka@post.cz - - 5/20 - ---- - -execute_cmd.c - - new variable, executing_builtin, keeps track of number of "levels" - of builtins being executed; incremented by execute_builtin; saved - and restored by execute_simple_command - -subst.c - - new variable, assigning_in_environment, set and unset around calls - to assign_in_env by the expansion code - -variables.c - - use executing_builtin and assigning_in_environment to decide whether - or not to look into temporary_env when calling find_variable_internal. - Fixes problem reported by Kevin Quinn - - 5/22 - ---- -redir.c - - change add_undo_redirect to differentiate between file descriptors - greater than SHELL_FD_BASE (currently 10) used internally to save - others and then being the targets of user redirection and fds that - are just the target of user redirections. The former need to have - an `exec undo' redirect added to undo it in case exec throws away - redirections; the latter does not. We use the close-on-exec flag - for this: if it's set, we assume that the file descriptor is being - used internally to save another. Fixes problem reported by Ian - Jackson - -shell.c - - new function, init_interactive_script(), does interactive initialization - for a script run with `bash -i script' -- does everything the same - as init_interactive except set `interactive == 1', which causes the - shell to read from the standard input, after calling - init_noninteractive - - call init_interactive_script if a script is run as `bash -i script'. - Fixes problem reported by Joseph Michaud - - 5/24 - ---- -builtins/printf.def - - change vbadd to only call FASTCOPY if the passed buffer length is - > 1 - - if the `-v' option is supplied and `vbuf' is already non-null from a - previous `printf -v var' call, set vbuf[0]=0 explicitly instead of - relying on vbadd to do it -- vbadd may not be called. - - fix PRETURN macro to set vbuf[0] == 0 if vbuf is not freed. These - should fix problem reported by Elmar Stellnberger - -lib/readline/display.c - - fix update_line to deal with the case where col_lendiff > 0 (meaning - the new string takes up more screen real estate than the old) but - lendiff < 0 (meaning that it takes fewer bytes to do so). This can - happen when a multibyte prompt string is replaced with a longer one - containing only single-byte characters (e.g., when doing a reverse - i-search). Fixes gentoo bug reported by Peter Volkov - - -builtins/read.def - - make sure we only print $PS2 if the standard input is a terminal - - new function, read_mbchar, to read a multibyte character so we - can make sure we read entire multibyte chars when `read -n' is - used, rather than bytes. Only called when -n is supplied. - Fixes problem reported by Stanislav Brabec - - 5/25 - ---- -externs.h - - new #defines for third argument to named_function_string: - FUNC_MULTILINE (don't suppress newlines) and FUNC_EXTERNAL (convert - to external display form) - -subst.h - - new extern declaration for remove_quoted_escapes - -subst.c - - remove_quoted_escapes is now global - -print_cmd.c - - in named_function_string, if FUNC_EXTERNAL is in the flags argument, - call remove_quoted_escapes to convert from internal to external form. - Fixes bug reported by Bo Andresen - -variables.c,builtins/{declare,setattr,type}.def - - use FUNC_MULTILINE in calls to named_function_string as appropriate - - add FUNC_EXTERNAL to calls to named_function_string as appropriate - - 5/27 - ---- -{make_cmd,variables}.c - - changes to enable the shell to compile when debugger support is - configured out (function_def hash table and access functions). Fixes - bug reported by Horst Wente - -builtins/help.def - - fix bug in `help' two-column printing to avoid referencing - shell_builtins[num_shell_builtins] - -error.c - - in get_name_for_error, use dollar_vars[0] if the name returned from - looking in $BASH_SOURCE[0] is the empty string as well as if it's - null - - 5/31 - ---- -arrayfunc.c - - change array_value_internal to set *RTYPE to 1 if the reference is - array[*] and 2 if the reference is array[@] - -subst.c - - in parameter_brace_expand_word, set the flags returned by the word - desc to include W_HASQUOTEDNULL if array_value returns QUOTED_NULL - for an array reference like x[*] and the word is quoted. Fixes bug - reported by Christophe Martin - - 6/1 - --- -jobs.c - - several changes to preserve errno if tcgetpgrp/tcgetattr/tcsetattr - fail, for subsequent error messages - - change initialize_job_control to turn off job control if the terminal - pgrp == -1 or is not equal to shell_pgrp (with an error message) - - in initialize_job_control, if the shell has been forced interactive - with -i, make sure stderr is hooked to a tty before using it as - the controlling terminal. If it's not, try to open /dev/tty and - assign it to shell_tty. Fixes problems reported by Derek Fawcus - - - 6/13 - ---- -support/shobj-conf - - changes to support shared object and shared library creation on AIX - 5.x and later versions. From Niklas Edmundsson - - 6/17 - ---- -builtins/mkbuiltins.c - - new array of builtins, posix_builtins, containing builtins listed - as special to the command search order by POSIX - - add POSIX_BUILTIN to the builtin flags if the builtin name is one - that's special to the posix command search order - -builtins.h - - new define, POSIX_BUILTIN, means that a builtin is special to the - posix command search order - - 6/22 - ---- -lib/readline/display.c - - new macro, WRAP_OFFSET, intended to replace W_OFFSET. Takes prompt - strings longer than one physical line with invisible characters on - the second line into account when calculating the number of - invisible characters on the current screen line - - use WRAP_OFFSET where appropriate (update_line, _rl_move_cursor_relative) - - change update_line to deal with adjusting _rl_last_c_pos in a - multibyte environment when the prompt has invisible chars on the - second line and redisplay has output the invisible characters - - change _rl_move_cursor_relative to adjust _rl_last_c_pos in a - multibyte environment when the prompt has invisible chars on the - second line and the redisplay draws the invisible character. Fixes - redisplay bug reported by Andreas Schwab - - - 7/11 - ---- - -lib/readline/rltty.c - - enable flush-output code for systems other than AIX 4.1. Problem - reported by Jan Kratochvil - - 7/12 - ---- -lib/readline/display.c - - set prompt_invis_chars_first_line from the portion of the prompt - following the final newline, instead of from the prefix. Fixes - bug reported on the Ubuntu bug list by dAniel hAhler - - - 7/13 - ---- -variables.c - - use native __QNX__ and __QNXNTO__ cpp defines instead of qnx and - qnx6, respectively. Patch from Sean Boudreau - -lib/sh/getcwd.c - - #undef HAVE_LSTAT on qnx, so it uses stat instead. Patch from - Sean Boudreau - - 7/21 - ---- -builtins/common.c - - change sh_invalidnum to be a little smarter about octal and hex - numbers and change the message appropriately. Bug originally - reported on coreutils list by Jürgen Niinre - - 7/26 - ---- -test.c - - make sure the string passed to test_unop has only a single character - following the `-'. Fixes bug reported by Michael A. Smith - - -parse.y - - better input validation: make sure a word looks like a conditional - unary operator (-X) before calling test_unop - - 7/28 - ---- -trap.c - - in trap_handler, if it's called directly from the signal handler - (e.g., SIGINT sighandler, set by set_sigint_handler), but the - trap disposition has been reset to the default between the - assignment and receipt of the signal, check that the signal is - trapped and issue a warning if the shell was compiled with - debugging enabled. Fixes bug reported by Fergus Henderson - - - 8/1 - --- -lib/readline/{util,histexpand}.c - - fixes for small memory leaks from Michael Snyder - - 8/18 - ---- -Makefile.in - - add dependency on builtins/builtext.h to nojobs.o list. Fixes - `make -j 5' issue reported by Chris MacGregor - -examples/loadables/Makefile.in - - add @LDFLAGS@ to SHOBJ_LDFLAGS assignment -- experimental. Suggested - by Mike Frysinger - -examples/loadables/{basename,cut,dirname,finfo,head,ln,logname,mkdir,pathchk,print,printenv,push,realpath,rmdir,sleep,tee,truefalse,tty,uname,unlink,whoami}.c - - fix up some includes. Fix from Mike Frysinger - - 8/21 - ---- -histexpand.c - - fix another memory leak in history_find_word. Bug report originally - from Michael Snyder ; test case suggested by Jim - Blandy - - 8/26 - ---- -subst.c - - change to do_assignment_internal to make an assignment to a variable - with the `noassign' internal attribute not a variable assignment - error. - - fix do_assignment_internal so assignment to a `noassign' variable - does not cause it to suddenly become visible if it's currently - invisible - - 9/3 - --- -stringlib.c - - change strsub to check whether or not temp is non-null before - trying to null-terminate it. Also make sure temp is allocated - even if the pattern and replacement strings are empty, and set - to a copy of string (like ${foo//}) - Bug report from Timo Lindfors - - 9/10 - ---- -{config.h,Makefile,configure}.in,aclocal.m4 - - new tests for fpurge and __fpurge - -lib/sh/fpurge.c, externs.h - - new file, fpurge(3) implementation with external decl in externs.h - -builtins/common.c - - add call to fpurge(stdout) to sh_chkwrite - -{redir,execute_cmd}.c - - add call to fpurge(stdout) after fflush(stdout) before changing - stdout file descriptor and after a builtin or function executes - - 9/12 - ---- -expr.c - - make sure noeval is set to 0 when a longjmp occurs, since it will - not be reset otherwise, and it can be set to 1 while processing - a {pre,post}-increment or {pre,post}-decrement token - - set noeval to 0 at the beginning of evalexp, since it's never - called recursively - - 9/14 - ---- -config-top.h - - new builder-modifiable define: DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS - Turning it on will cause errors from EPIPE to not be reported by - the normal shell write error message mechanism - -builtins/common.c - - if DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS is defined, don't print an - error message from sh_wrerror if errno == EPIPE. Suggestion from - Petr Sumbera - - 9/19 - ---- -{jobs,nojobs}.c,jobs.h - - add code to retry fork() after EAGAIN, with a progressively longer - sleep between attempts, up to FORKSLEEP_MAX (16) seconds. Suggested - by Martin Koeppe - - 9/21 - ---- -version.c - - change copyright year to 2007 - - 9/25 - ---- -pathexp.c - - change quote_string_for_globbing to add a backslash in front of a - backslash appearing in the pathname string, since the globbing - code will interpret backslashes as quoting characters internally. - Bug reported by on the debian list - (443685) - - 10/8 - ---- -lib/readline/display.c - - in update_line, make sure _rl_last_c_pos is > 0 before setting - cpos_adjusted (or we actually moved the cursor to column 0 in - _rl_move_cursor_relative). Fixes redisplay bug with prompt with - only invisible characters reported by dAniel hAhler - - - 10/10 - ----- -lib/readline/display.c - - in rl_redisplay, when calculating the new physical cursor position - in a multibyte locale (`tx'), do not call rl_backspace if tx ends - up < 0. Rest of fix for bug reported by dAniel hAhler - - - 10/12 - ----- -lib/sh/getcwd.c - - fix memory overwrite problem that's possible if buf is NULL and - passed size is greater than the pathname length. Reported by - Ian Campbell - -builtins/ulimit.def - - change the multiplier for the -c and -f options (`blocks') to 512, - the traditional value (and the one POSIX specifies). Bug reported - by Pete Graner - -braces.c - - pass process substitution through unchanged the same as command - substitution. Prompted by suggestion from Stephane Chazelas - - -lib/readline/input.c - - in rl_unget_char, fix off-by-one error when resetting pop_index if - it's < 0. Bug reported by Uwe Doering - -builtins/type.def - - change exit status of `type' to not successful if any of the - requested commands are not found. Reported by Stephane Chazleas - - -pcomplete.c - - change command_line_to_word_list to use rl_completer_word_break_characters - instead of the shell metacharacters to split words, so programmable - completion does the same thing readline does internally. Reported - by Vasily Tarasov - - 10/16 - ----- -bashline.c - - When completing a command name beginning with a tilde and containing - escaped specical characters, dequote the filename before prefixing - it to the matches, so the escapes are not quoted again. Reported - by neil@s-z.org - - 10/17 - ----- -expr.c - - in readtok(), don't reset lasttp if we've consumed the whitespace - at the end of the expression string. Fixes error message problem - reported by - - 11/1 - ---- -builtins/printf.def - - change asciicode() to return intmax_t; add multibyte character - support instead of assuming ASCII (depending on behavior of system - multibyte support functions). Fixes bug reported by Rich - Felker - - 11/5 - ---- -execute_cmd.c - - if redirections attached to a compound command fail, make sure to - set last_command_exit_value when returning EXECUTION_FAILURE. - Fixes bug reported separately by Andreas Schwab - and Paul Eggert - - 11/9 - ---- -builtins/read.def - - make sure the return value from get_word_from_string is freed if - non-null. Fixes memory leak bug reported by Lars Ellenberg - - - 11/10 - ----- -variables.c - - use getpid() as value of seeded_subshell to avoid problems with - random number generator not getting re-seeded correctly when - subshells are created. Fix from Tomas Janousek - -lib/readline/display.c - - in update_line(), when outputting characters at the end of the line, - e.g., when displaying the prompt string, adjust _rl_last_c_pos by - wrap_offset if the text we're drawing begins before the last - invisible character in the line. Similar to fix from 5/24. Fixes - bug reported by Miroslav Lichvar - - 11/14 - ----- -subst.c - - fix $[ expansion case to deal with extract_arithmetic_subst - returning NULL (if the `]' is missing) and return the construct - unchanged in that case. Fixes tab completion bug reported by - Heikki Hokkanen (debian bug 451263) - -lib/readline/mbutil.c - - fix _rl_find_next_mbchar_internal to deal with invalid multibyte - character sequences when finding non-zero-length chars. Fixes - bug reported by Morita Sho - - 11/15 - ----- -variables.c - - add new function `seedrand' to seed the bash random number - generator from more random data. Suggestion from Steve Grubb - - - replace the rng in brand() with a slightly better one from FreeBSD - (filtered through Mac OS X 10.5). Replacement suggested by - Steve Grubb - - 11/21 - ----- -configure.in - - darwin 9 also requires linking against libreadline.a and - libhistory.a because of Apple's questionable decision to ship a - libreadline "replacement" that doesn't provide all functions - -doc/{bash.1,bashref.texi} - - slight change to the text describing the effect of set -e when - in a || or && list - - 12/5 - ---- -jobs.c - - fix raw_job_exit_status to correct mixing of int/WAIT values (need - to return a WAIT) - - arrange so that children run as part of command substitutions also - set the SIGINT handler to wait_sigint_handler, since they effectively - don't do job control - - in wait_for, if a child run as part of a command substitution exits - due to SIGINT, resend the SIGINT to the waiting shell with kill(2). - This makes sure the exit status propagates - -doc/{bash.1,bashref.texi} - - tighten up the language describing when bash tries to see if its - stdin is a socket, so it can run the startup files. Suggested by - Vincent Lefevre - -eval.c - - in the DISCARD case of a longjmp to top_level, make sure - last_command_exit_value is set to EXECUTION_FAILURE if it's 0, - but leave existing non-zero values alone - -subst.c - - in command_substitute, don't reset pipeline_pgrp in the child - process -- this means that second and subsequent children spawned by - this comsub shell get put into the wrong process group, not the - shell's. Fix for bug reported by Ingo Molnar - - 12/6 - ---- -support/shobj-conf - - make sure the cases for darwin8.x (Mac OS X 10.4.x) are extended to - darwin9.x (Mac OS X 10.5.x). Fixes problem originally reported - against readline-5.2 by schneecrash@gmail.com - - 12/8 - ---- -subst.c - - make sure to add the results of (successful) tilde expansion as a - quoted string, to inhibit pathname expansion and word splitting. - From recent Austin Group interpretation. - -include/shtty.h, lib/sh/shtty.c - - add ttfd_onechar, ttfd_noecho, ttfd_eightbit, ttfd_nocanon, and - ttfd_cbreak to set tty attributes associated with a particular - file descriptor (which is presumed to point to a terminal). Support - for fix for bug reported by b_bashbug@thebellsplace.com - -lib/readline/display.c - - make sure we only use rl_invis_chars_first_line when the number of - physical characters exceeds the screen width, since that's the - only time expand_prompt sets it to a valid value - - 12/12 - ----- -builtins/set.def - - change set_minus_o_option to return EX_USAGE if an invalid option - name is supplied. All callers can handle it. - - change set_builtin to return what set_minus_o_option returns if it's - not EXECUTION_SUCCESS. This allows EX_USAGE errors to abort a - shell running in posix mode - - 12/14 - ----- -builtins/read.def - - generalize the calls to the tty attribute functions to maintain a - local copy of the terminal attributes and use the fd supplied as - the argument to the -u option (default 0). Fix for bug reported - by b_bashbug@thebellsplace.com - -doc/bashref.texi, lib/readline/doc/{history,rlman,rluser,rluserman}.texi - - Slight changes to conform to the latest FSF documentation standards. - Patch from Karl Berry - - 12/20 - ----- -execute_cmd.c - - after calling clear_unwind_protect_list, make sure we reset - parse_and_execute_level to 0, since there's nothing left to - restore it if top_level_cleanup tests it. Fixes bug reported - by Len Lattanzi - - 12/31 - ----- -lib/sh/getcwd.c - - new function, _path_checkino, checks whether the inode corresponding - to the path constructed from the first two arguments is the same as - the inode number passed as the third argument - - if BROKEN_DIRENT_D_INO is defined, meaning the d_ino/d_fileno - member of struct dirent doesn't contain valid values, use - _path_checkino instead of directly comparing against d_fileno. - Fixes Interix problem reported by Michael Haubenwallner - - - 1/7/2008 - -------- -array.c - - fix array_subrange to separate elements in returned string with - first char of $IFS if QUOTED is non-zero, since this indicates - the caller used ${array[@]:foo}. Fixes bug reported by Lea - Wiemann - - 1/8 - --- -subst.c - - new function returning a string containing the first character of - $IFS: char *ifs_firstchar(int *) - -subst.h - - extern declaration for ifs_firstchar() - -array.c - - call ifs_firstchar() to get first character of $IFS when needed - (array_subrange() and array_patsub()) - - 1/11 - ---- -lib/readline/display.c - - use sentinel variable set at end of init_line_structures to decide - whether to call it from rl_redisplay, since early SIGWINCH on - Mac OS X that hits during this function can cause _rl_wrapped_line - to be referenced before initialization. Fix for bug reported by - Len Lattanzi - -subst.[ch] - - skip_to_delim is now compiled into the shell all the time, not just - when readline is linked in - -subst.c - - use skip_to_delim to find the `/' denoting the end of a pattern - in pattern substitution, since it knows more shell syntax than - quoted_strchr and understands multibyte characters. Fixes bug - reported by Dmitry V Golovashkin - - 1/15 - ---- -subst.c - - add `flags' argument to skip_to_delim telling it whether or not to - set no_longjmp_on_fatal_error; set this flag when calling from the - readline completion code - -subst.h - - update extern declaration for skip_to_delim - - 1/17 - ---- -subst.c - - expand_prompt_string takes a third argument: the initial flags for - the WORD - -subst.h - - change extern declaration for expand_prompt_string to add third arg - -bashline.c - - pass W_NOCOMSUB as third argment to expand_prompt_string when - calling from bash_directory_completion_hook, since we don't want - to do command substitution from the completion code - -parse.y - - change call to expand_prompt_string - - 1/18 - ---- -doc/Makefile.in - - added an `install_builtins' rule to install the builtins.1 man page, - preprocessing it with sed to force `.so man1/bash.1', which some - versions of man require. Suggestion from Peter Breitenlohner - - - new target `install_everything' that will install normal documentation - and builtins man page - - changed uninstall target to remove bash_builtins page from man - directory - -lib/readline/vi_mode.c - - new function, rl_vi_insert_mode, which calls rl_vi_start_inserting - to make sure the value of `last command to repeat' is set correctly. - Fix from Thomas Janousek - - add support for redoing inserts made with the `I' command. Fix - from Thomas Janousek - - add support for redoing inserts made with the `A' command - -lib/readline/readline.h - - new extern declaration for rl_vi_insert_mode - -lib/readline/{misc,readline,vi_mode,vi_keymap}.c - - change calls to rl_vi_insertion_mode to rl_vi_insert_mode - - 1/19 - ---- -builtins/read.def - - change timeout behavior when not reading from a tty device to save - any partial input in the variable list, but still return failure. - This also causes variables specified as arguments to read to be - set to null when there is no input available. Fix inspired by - Brian Craft - - 1/21 - ---- -builtins/fc.def - - change computation of last_hist to use remember_on_history instead - of a hard-coded `1'. This keeps fc -l -1 in PROMPT_COMMAND from - looking too far back - - 1/25 - ---- -lib/readline/complete.c - - fix fnwidth to use string[pos] instead of *string when testing the - current character for a control character or rubout - - 2/2 - --- -general.c - - change posix_initialize to turn off source/. searching $PWD when - the file sourced is not found in $PATH. Fixes bug reported by - Paolo Bonzini and Eric Blake - - 2/9 - --- -builtins/*.def - - changes to text and formatting suggested by Jan Schampera - - - 2/16 - ---- -bashline.c - - change command_word_completion_function to use the word completion - found by readline, which matters only when ignoring case is on - and the completion found in the file system differs in case from - the text the user typed (this is what readline does for normal - filename completion). Fixes issue reported by Jian Wang - . - - 2/18 - ---- -builtins/source.def - - if the filename passed as an argument contains a `/', don't search - $PATH. Not sure why it wasn't like this before - - 2/21 - ---- -lib/readline/terminal.c - - change rl_crlf so that the MINT system on ATARI systems adds a - carriage return before the \n - - 2/22 - ---- -doc/{bash.1,bashref.texi} - - added text to the EXIT STATUS section noting that exit statuses - fall between 0 and 255, inclusive - -support/mkversion.sh - - output a #define for DEFAULT_COMPAT_LEVEL (${major}${minor}; e.g. 32) - to version.h - -version.c - - int variable, shell_compatibility_level, set to DEFAULT_COMPAT_LEVEL - by default - -builtins/shopt.def - - new shopt variable, compat31, sets shell_compatibility_level to 31 - (or back to default if unset) - -execute_cmd.c - - in execute_cond_node, restore bash-3.1 behavior of quoted rhs of - regexp matches if shell_compatibility_level == 31 - - 2/28 - ---- -lib/readline/rltty.c - - set readline_echoing_p = 1 if tcgetattr fails and sets errno to - EINVAL, as Linux does when the fd is a pipe. Reported by Mike - Frysinger - - 3/6 - --- -{MANIFEST,Makefile.in},lib/sh/{casemod,uconvert,ufuncs}.c - - new library sources from bash-4.0-devel tree - -lib/sh/spell.c - - moved cdspell() here from builtins/cd.def, renamed dirspell() - -externs.h - - new declarations for extern functions from new library files - - new extern declaration for lib/sh/spell.c:dirspell() - -builtins/cd.def - - call extern library function dirspell(); remove static cdspell() - -builtins/read.def - - when read times out, make sure input_string is null-terminated before - assigning any partial input read to the named variables - - 3/10 - ---- -lib/glob/xmbsrtowcs.c - - cut the number of memory allocations in xdupmbstowcs by not keeping - track of the indices if the caller hasn't asked for it - - 3/17 - ---- -builtins/fc.def - - make sure the adjustment to i in fc_gethnum uses the same formula - fc_builtin uses to calculate last_hist - - make sure that every time fc_gethnum is called, the fc command last - in the history list has not yet been deleted, since fc_gethnum - assumes that it has not. Fix from John Haxby - -lib/readline/complete.c - - new private library function, _rl_reset_completion_state(), used to - reset any completion state internal to the library when a signal - is received - - call _rl_reset_completion_state() before returning from - rl_complete_internal - -lib/readline/rlprivate.h - - new extern declaration for _rl_reset_completion_state - -lib/readline/signals.c - - call _rl_reset_completion_state from rl_signal_handler on SIGINT. - This fixes one of the problems identified by Mika Fischer - - -pcomplete.c - - programmable_completions now saves pointer to the compspec it's - working with in new global variable CURCS - - new function, pcomp_set_readline_variables, that sets or unsets - readline variables based on a passed flags value (COPT_FILENAMES, - etc.) - - new function, pcomp_set_compspec_options, to set or unset bits in - the options word of a passed compspec (default CURCS) - - only call bash_dequote_filename (via rl_filename_dequoting_function) - from pcomp_filename_completion_function if the readline state - word indicates word completion is in progress - -pcomplete.h - - new extern declaration for curcs - - new extern declaration for pcomp_set_readline_variables - - new extern declaration for pcomp_set_compspec_options - -bashline.c - - fix bash_dequote_filename to implement shell quoting conventions: - 1. Inhibit backslash stripping within single quotes - 2. Inhibit backslash stripping within double quotes only if - the following character is one of the special ones - - call pcomp_set_readline_variables from attempt_shell_completion - instead of doing the equivalent inline - - 3/18 - ---- -bracecomp.c - - make sure we sort array of matches in byte order (using strcmp). so - the brace calculations work correctly even when the locale orders - characters like aAbBcC...zZ. Fixes bug reported by Torsten Nahm - - - 3/20 - ---- -lib/readline/{rltty,signals}.c - - move block_sigint and release_sigint from rltty.c to signals.c; add - _rl_ prefix to make them public to the library; change callers. - From Jan Kratchovil - -lib/readline/rlprivate.h - - new extern declarations for _rl_block_sigint and _rl_release_sigint - -lib/readline/display.c - - add calls to _rl_block_sigint and _rl_release_sigint to rl_redisplay, - since it maniupluates global data structures. Fix from Jan - Kratchovil - -builtins/printf.def - - change calls to asprintf and manually adding to vbuf to use calls - to vsnprintf against vbuf directly -- if the number of characters - to be written overflows the buffer, realloc the buffer and use - vsnprintf again. This should reduce the memory used by printf. - Idea from Yuya Katayama - -lib/readline/doc/rltech.texi - - documented rest of readline's state flags, including RL_STATE_CALLBACK - - documented rl_save_state and rl_restore_state - - 3/27 - ---- -lib/readline/{rlprivate.h,{display,readline,rltty,terminal,text}.c} - - rename readline_echoing_p to _rl_echoing_p for namespace consistency - -lib/readline/{rlprivate.h,{callback,readline,util}.c} - - rename readline_top_level to _rl_top_level for namespace consistency - -builtins/ulimit.def - - new -b (socket buffer size) and -T (number of threads) options - -array.c - - fix bug in calculation of the array element assignment string length: - use length of `is' instead of `indstr'. Reported as ubuntu bug - #202885 by John McCabe-Dansted - -builtins/setattr.def - - new function, show_all_var_attributes, displays attributes and - values for all shell variables (or shell functions) in a reusable - format - -builtins/common.h - - new extern declaration for show_all_var_attributes - -builtins/declare.def - - change `declare -p' to print out all variable attributes and values, - and `declare -fp' to print out all function attributes and - definitions. Inspired by request from John Love-Jensen - - -doc/{bash.1,bashref.texi} - - document new -b and -T options to ulimit - - tighten up language describing AND and OR lists - - add description of new behavior of `declare -p' - - 3/28 - ---- -pcomplete.c - - rename curcs -> pcomp_curcs - - new global completion variable, pcomp_curcmd, the current command - name being completed - -builtins/complete.def - - new builtin, compopt, allows completion options for command names - supplied as arguments or the current completion being executed to - be modified. Suggested by Mika Fischer - - 3/30 - ---- -doc/{bash.1,bashref.texi},lib/readline/doc/rluser.texi - - document new compopt builtin - - 4/5 - --- -support/shobj-conf - - change solaris10 stanza to use -fPIC to fix 64-bit sparc_v9/solaris10 - compilations. Fix from Fabian Groffen - -builtins/read.def - - added `-i text' option, inserts `text' into line if using readline. - Suggested by many, used some ideas from Kevin Pulo - -doc/{bash.1,bashref.texi} - - document new `-i text' option to read builtin - - 4/7 - --- -lib/readline/bind.c - - new settable variable, `history-size', sets the max number of - entries in the history list - -doc/bash.1,lib/readline/doc/{rluser.texi,readline.3} - - document new `history-size' settable readline variable - - 4/8 - --- -builtins/complete.def - - change build_actions calling sequence to take a struct with `other' - (non-action) flag arguments (-p, -r) - - add support for `-E' option to build_actions and complete builtin -- - modifies or displays (internal) `_EmptycmD_' completion spec - -bashline.c - - change attempt_shell_completion to try programmable completion on an - `empty' command line and return the results - -doc/bash.1,lib/readline/doc/rluser.texi - - documented new `-E' option to `complete' - - 4/9 - --- -bashhist.c - - new variable, `enable_history_list', used to reflect setting of - `-o history' option - - change bash_history_{enable,disable,reinit} to set enable_history_list - as well as remember_on_history - -builtins/set.def - - use `enable_history_list' instead of `remember_on_history' to keep - value of `-o history' option - -builtins/evalstring.c - - instead of unwind-protecting remember_on_history, use a function to - restore it to the value of `enable_history_list' after - parse_and_execute runs the commands in the string. This allows - history to be turned off in a startup file, for instance. Problem - reported by Dan Jacobson - - 4/11 - ---- -bashline.c - - limited support for completing command words with globbing characters - (only a single match completed on TAB, absolute or relative - pathnames supported, no $PATH searching, some support for displaying - possible matches, can be used with menu completion). - Suggested by Harald Koenig - -print_cmd.c - - change redirection printing to output r_err_and_out as `&>file', - since the man page says that's the preferred form - - 4/12 - ---- -builtins/*.def - - change long doc so the first line is a short description - - add `Exit Status:' section to each longdoc describing exit values - -builtins/help.def - - new `-d' option to print short description of each utility - - new `-m' option to print description of each builtin in a - pseudo-manpage format (inspired by ksh93) - -doc/{bash.1,bashref.texi} - - document new `-d' and `-m' options to `help' - -builtins/mapfile.def - - new builtin, `mapfile', imported from bash-4.0-devel branch - -tests/{mapfile.{data,right,tests},run-mapfile} - - tests for `mapfile' builtin - -doc/{bash.1,bashref.texi} - - added description of `mapfile' builtin - -MANIFEST,Makefile.in,builtins/Makefile.in - - added entries for mapfile source files - -arrayfunc.[ch] - - new function, bind_array_element, to support mapfile builtin - - 4/20 - ---- -expr.c - - fix operator precendence in expcond(): term after the `:' is - a conditional-expression, not a logical-OR-expression (using C - terminology). Bug reported by - - 4/22 - ---- -bashintl.h - - new P_ define for using ngettext to decide on plural forms - (currently unused) - - 4/25 - ---- -execute_cmd.c - - in execute_disk_command, if the command is not found, search for - a shell function named `command_not_found_handle' and call it - with the words in the command as arguments. Inspired by Debian - feature. - -doc/{bash.1,bashref.texi} - - document new command_not_found_handle behavior in COMMAND EXECUTION - section - -configure.in - - change default version to bash-4.0-devel - - 4/28 - ---- -variables.c - - change push_func_var and push_exported_var to call - stupidly_hack_special_variables if the temporary variable is going - to be disposed. This undoes any internal changes caused by a local - variable assignment in the environment or in a shell function. Bug - reported by Morita Sho in - http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=478096 - - 5/3 - --- -builtins/fc.def - - fixed a problem caused by change of 1/21 to use remember_on_history, - since it's turned off by parse_and_execute(), but can cause the - last command in history to be deleted and leave last_hist pointing - beyond the end of the history list. edit_and_execute_command can - do this. - -bashline.c - - new define, RL_BOOLEAN_VAR_VALUE, to take a readline boolean variable - and get its value as 0 or 1 (consider making readline global) - - put tty back into canonical mode before calling parse_and_execute in - edit_and_execute_command and then back into raw mode after it - returns. Fixes problem identified by . - - 5/4 - --- -lib/glob/glob.c - - code to support `globstar' option: GX_GLOBSTAR and two internal - flags. Changes to skipname, glob_vector, mbskipname, glob_filename. - New function finddirs(). - -lib/glob/glob.h - - new defines to support globstar code - -builtins/shopt.def - - new shell option, `globstar', enables special handling of `**' in - glob patterns -- matches all directories recursively - -pathexp.h - - extern declaration for glob_star - -pathexp.c - - break inline code out of quote_globbing_chars into a separate - function to decide whether a character is a globbing char: - glob_char_p - - change shell_glob_filename to call glob_filename with the - GX_GLOBSTAR flag if glob_star is set - -doc/{bash.1,bashref.texi} - - document new `globstar' shell option - -arrayfunc.c - - new function, broken out of quote_array_assignment_chars: - quote_assign; extended from old code to make sure that globbing - chars and chars in $IFS are quoted when displaying assignment - statements, especially in compound array assignments - - 5/5 - --- -bashline.c - - new variable, dircomplete_spelling, controls spelling correction - of directory names when doing filename completion - - change bash_directory_completion_hook to incorporate spelling - correction if initial canonicalization of directory name fails - -builtins/shopt.def - - new shell option, `dirspell', enables and disables spelling - correction of directory names during word completion - -builtins/read.def - - support for fractional timeout values (ival.uval); uses uconvert - and falarm/setitimer - -config.h.in - - new `HAVE_SETITIMER' define - -configure.in - - look for setitimer(2), define HAVE_SETITIMER if found - -doc/{bash.1,bashref.texi} - - document new `dirspell' shopt option - - document new fractional values to `read -t timeout' - - 5/6 - --- -assoc.[ch] - - new files, basic support for associative array implementation - -general.h - - new extern declarations for sh_openpipe, sh_closepipe, trim_pathname - -general.c - - new functions: sh_openpipe to create a pipe and move the file - descriptors to a high range; sh_closepipe, to close pipe fds and - clean up, and trim_pathname, to replace portions of a pathname - with `...' (for prompting) - -jobs.c - - don't set last_asynchronous_pid in child shell (messes up $!, among - other things) - -parse.y,parser.h - - moved definitions of parser flags to parser.h - -array.c - - imported array_modcase (case-changing operations on arrays) from - 4.0-devel branch - -array.h - - new extern declaration for array_modcase - -lib/readline/complete.c - - new variable, rl_menu_completion_entry_function, generator for - rl_menu_complete - - new menu completion `browsing' implementation, with several - improvements over the old code. Inspired by Sami - -lib/readline/readline.h - - extern declaration for rl_menu_completion_entry_function - - 5/8 - --- -lib/readline/complete.c - - add support for a third argument to fnprint and print_filename, - which supports replacing a specified portion of the pathnames - printed when displaying possible completions with a `...' (or - `___', if the prefix would be confused with a portion of the - filename) - - new variable, _rl_completion_prefix_display_length, sets the - number of characters in a common prefix to be replaced with an - ellipsis when displaying possible completions - - add support to _rl_display_match_list to find the length of the - common prefix of all items being displayed, and passing that - value to print_filename for possible replacement with an ellipsis - if that length is longer than _rl_completion_prefix_display_length - -lib/readline/bind.c - - add support for retrieving value of history-size variable to - _rl_get_string_variable_value - - new bindable variable, completion-prefix-display-length. When - displaying possible completions, matches with a common prefix - longer than this value have the common prefix replaced with an - ellipsis - - support for retrieving value of completion-prefix-display-length - variable to _rl_get_string_variable_value - - new bindable variable, revert-all-at-newline: if enabled, causes - all changes in history lines to be undone before readline returns - after processing a newline - -doc/bash.1,lib/readline/doc/{readline.3,rluser.texi} - - document new `completion-prefix-display-length' variable - - document new `revert-all-at-newline' variable - -execute_cmd.c - - change execute_builtin to not inherit the `-e' flag into commands - executed by the `command' or `source/.' builtins if we are supposed - to be ignoring the return value. This is like `eval'. Fixes bug - reported by Hiroshi Fujishima - - 5/10 - ---- -variables.c - - when reading the initial environment, don't create variables with - names that are not valid shell identifiers. Fixes bug reported by - Stephane Chazleas - - 5/13 - ---- -subst.c - - fix string_quote_removal to gracefully handle the case where a - backslash is the final character in the string (leaves the backslash - in place). Fixes bug reported by Ian Robertson - - - 5/16 - ---- -support/checkbashisms - - Perl script that purports to check for bash-specific features in a - shell script. Lifted from Debian via ubuntu - - 5/20 - ---- -lib/readline/display.c - - in update_line, when deciding whether or not to adjust _rl_last_c_pos - in a multibyte environment after printing the last line of a multiline - prompt with invisible characters on the first and last lines, use - the number of inivisible chars on the first line in the calculation - deciding whether or not we're past the last invisible character and - need to adjust the cursor position. Old code used the number of - invisible chars on the last prompt line. Fixes bug reported by - stuff@slinkp.com. - - in update_line, when fixing _rl_last_c_pos after drawing the first - line of the prompt, use the number of invisible chars on the first - line as the offset, instead of the total number of invisible chars - - use prompt_multibyte_characters, the number of multibyte chars in - the prompt string, to short-circuit some relatively expensive - multibyte text processing in rl_redisplay - - 5/21 - ---- -variables.c - - new function, reinit_special_variables(), a hook for special - vars that need their hook functions called when they're unset as - a result of the shell reinitializing itself to run a script - -shell.c - - shell_reinitialize now calls reinit_special_variables - - shell_reinitialize now calls bashline_reset - -variables.h - - new extern declaration for reinit_special_variables - -bashline.c - - new function, bashline_reset(), called when the shell reinitializes - in shell_reinitialize. Right now, just resets - bash_readline_initialized to 0. - -bashline.h - - new extern declaration for bashline_reset() - - 5/23 - ---- -bashhist.c - - new function, bash_clear_history, clears the history and resets any - associated internal bash state - -bashhist.h - - extern declaration for bash_clear_history - -builtins/history.def - - call bash_clear_history instead of clear_history for `history -c'. - Fixes part of problem reported by Scott McDermott - - - decrement history_lines_this_session in delete_histent, called for - `history -d' - -builtins/history.def,bashhist.[ch] - - move delete_histent() to bashhist.c; rename to bash_delete_histent - - move delete_last_history() to bashhist.c; rename to - bash_delete_last_history() - - 5/25 - ---- -braces.c - - add another parameter to mkseq(), the number of digits to put into - each member of a numeric sequence (width), changes to determine - any zero-padding go into expand_seqterm - - changes to expand_seqterm to allow user-specified increments - -bashline.[ch],shell.c,sig.c - - switched names of bashline_reinitialize and bashline_reset to better - reflect their functions - - when searching $PATH for directories to use for command completion, - make sure to free `current_path' before going out of scope - - new bindable function `dabbrev-expand', which is more or less - menu completion using dynamic history completion as the generator - - changes to bash_execute_unix_command to set variables for the - executed command like programmable completion: READLINE_LINE - (rl_line_buffer) and READLINE_POINT (rl_point) - - change to bash_execute_unix_command to allow the executed command - to change the readline line buffer by modifying the value of - READLINE_LINE and to change rl_point by modifying the value of - READLINE_POINT - -common.h - - new SEVAL_ defines for later parse_string changes from 4.0-devel - branch - -command.h - - new defines for new &>> r_append_err_and_out redirection - -builtins/evalstring.c - - new function, parse_string, parses a command from a passed string - and returns the number of characters consumed. For satisfying - Posix rules when parsing command substitutions, from bash-4.0-devel - branch - - split out common prolog code from parse_string and - parse_and_execute into a separate function called from both - -parse.y - - small changes to add symbols needed for parse_string - - parser change to add `|&' as synonym for `2>&1 |'; translation is - performed at parse time so |& never shows up in output of - print_command, for instance. Picked up from zsh, merged in from - bash-4.0-devel branch - -parse.y,{redir,copy_cmd,dispose_cmd,make_cmd,print_cmd}.c - - implement new &>> r_append_err_and_out (like >>foo 2>&1); merged - in from bash-4.0-devel branch - -doc/{bash.1,bashref.texi},lib/readline/doc/rluser.texi - - document new optional increment in brace expansion - - document new zero-padded fixed-width integer brace expansion - - document new `dabbrev-expand' bindable readline command - - document new effects of `bind -x' setting and reading the values of - READLINE_LINE and READLINE_POINT - - document new |& synonym for `2>&1 |' pipeline operator - - 5/26 - ---- -parse.y - recognize new ;& and ;;& case action list terminator tokens and - implement them in the grammar, setting CASEPAT_FALLTHROUGH and - CASEPAT_TESTNEXT flags as appropriate - -print_cmd.c - - print new ;& and ;;& case clause action list terminators as - appropriate - -execute_cmd.c - - implement new case clause action list terminators: - ;& - fall through to actions associated with next pattern list - ;;& - fall through to tests in next pattern list - -doc/{bash.1,bashref.texi} - - document new ;& and ;;& case clause action list terminators - - 5/28 - ---- -jobs.c - - change waitchld so it treats SIGCHLD like SIGINT if `wait' is being - executed, and allows wait to jump out before running any trap set - on SIGCHLD. Fixes debian bug #483016 reported by Miroslav Rudisin - - - run_sigchld_trap is no longer static, so the trap code in trap.c - can call it - - change run_sigchld_trap to call set_impossible_sigchld_trap instead - of just using a call to restore_default_signal - -jobs.h - - new extern declaration for run_sigchld_trap - -trap.c - - fix run_pending_traps to run a SIGCHLD trap if the trap handler isn't - set to IMPOSSIBLE_TRAP_HANDLER - - in trap_handler, don't reset the SIGCHLD trap handler to trap_handler - if MUST_REINSTALL_SIGHANDLERS is defined - - new function, set_impossible_sigchld_handler, sets the trap string - associated with SIGCHLD to IMPOSSIBLE_TRAP_HANDLER; used as a sentinel - by run_sigchld_trap and maybe_set_sigchld_handler - - change maybe_set_sigchld_handler to set the SIGCHLD trap string only - if the current value is IMPOSSIBLE_TRAP_HANDLER. This ensures that - any traps on SIGCHLD set in a SIGCHLD handler will persist. Fixes - debian bug #483016 reported by Miroslav Rudisin - - -trap.h - - new extern declaration for set_impossible_sigchld_trap - - 5/31 - ---- -parse.y - - new function: parse_comsub(), parses $(...) by parsing command - between parens and making sure the next token is `)'. From - the bash-4.0-devel branch - - new function: xparse_dolparen, helper function for parsing - command substitutions in $(...). Called from subst.c to extract - a command substitution during word expansion. From bash-4.0-devel - branch - - new function: rewind_input_stream(). Rewinds bash_input.location.string - back to where it was before the shell parsed a $() command - substitution. From bash-4.0-devel branch - - changes to parse_matched_pair to combine most of the flag variables - (was_dollar, in_comment, and so on) into a local flags word - - 6/2 - --- -parse.y - - call trim_pathname, which retains only the last $PROMPT_DIRTRIM - directories and replaces the intervening characters with `...', - when expanding \w and \W - -doc/{bash.1,bashref.texi} - - document the effect of setting PROMPT_DIRTRIM - - 6/3 - --- -builtins/ulimit.def - - make the multiplier (block size) for -c and -f 512 bytes only if in - Posix mode and 1024 bytes otherwise (as in previous versions). Uses - POSIXBLK and BLOCK_SIZE defines to parameterize size based on value - of posixly_correct - -doc/bashref.texi - - document this addition to posix mode - -builtins/common.c - - change get_numeric_arg to have a calling sequence and return value - more closely mimicking general.c:legal_number(), with the addition - of a flags word - - add extra value for `fatal' argument to get_numeric_arg to force it - to return failure to the caller rather than longjmping - -builtins/common.h - - change prototype declaration for get_numeric_arg - -builtins/{break,shift}.def - - change calls to get_numeric_arg to deal with new semantics and calling - sequence - -builtins/history.def - - display_history now returns an int - - change calling sequence for get_numeric_arg in display_history - - display_history now returns failure to the caller if get_numeric_arg - detects an invalid number, rather than jumping back to the top level - - use value returned by display_history as return status of history - builtin, filtered through sh_chkwrite - - history no longer aborts compound commands on invalid arguments. - fixes problem reported by Chu Li - -{braces,subst}.c - - extract_command_subst now takes a third flags argument; passed flags - are ORd into flags passed to other functions; changed callers - -subst.h - - move SX_* defines here from subst.c so parse.y:xparse_dolparen can - see them and behave appropriately - - extract_command_subst now takes a third flags argument; change - prototype - -subst.c - - change extract_command_subst to call xparse_dolparen when extracting - a $() construct - - change calls to extract_delimited_string to extract_command_subst - as appropriate - - if command_substitute returns a NULL word desc, don't call - dispose_word_desc on it - -parse.y - - change xparse_dolparen to use the SX_* flags now in subst.h - - 6/16 - ---- -subst.c - - in quote_list, set W_HASQUOTEDNULL flag in the word if quote_string - turns "" into CTLNUL - - in dequote_list, turn off W_HASQUOTEDNULL flag in the word if - dequote_string turns CTLNUL into "" - - new function, string_list_pos_params, encapsulates everything - needed to turn the positional parameters or an array indexed with - '@' or '*' into a string, including taking care of quoting and - using the first char of $IFS, when used in another expansion like - pattern removal or pattern substitution - - change list_remove_pattern, pos_params, pos_params_pat_subst to - call string_list_pos_params. Fixes problems reported by - Stephane Chazelas - - 6/22 - ---- -variables.h - - include assoc.h for associative arrays - - defines for case-modifying expansions and associative array variables - - sh_var_assign_func_t functions now take an extra char * parameter - - 6/25 - ---- -variables.c - - change declarations and definitions of sh_var_assign_func_t functions - to add the extra char * parameter: null_assign, null_array_assign, - assign_seconds, assign_random, assign_lineno, assign_subshell, - assign_dirstack - - change calls to var->assign_func to add extra char * argument - - broke part of body of dispose_variable out into a new function, - dispose_variable_value, which knows how to free all kinds of shell - variable data - - changes to deal with variables with the internal `nofree' attribute - -arrayfunc.c - - change calls to var->assign_func to add extra char * argument - - bind_array_var_internal now takes an extra `char *key' argument - - additions for associative array implementation; from bash-4.0-devel - tree - -arrayfunc.[ch],subst.c - - expand_compound_array_assignment now takes the variable as the first - argument (SHELL_VAR *); changed function definition and callers - -builtins/set.def - - changes to handle associative arrays in `unset' - -{execute_cmd,command}.h - - definitions for coproc implementation; from bash-4.0-devel tree - -variables.c - - new functions for associative arrays: make_new_assoc_variable, - make_local_assoc_variable - - 6/26 - ---- -variables.c - - more infrastructure for associative arrays; from bash-4.0-devel tree - - infrastructure for handling assignments to variables with - case-modifying attributes; from bash-4.0-devel tree - -config.h.in - - add #defines controlling case-modifying variable attributes and word - expansions - -configure.in - - add enable options for case-modifying variable attributes and word - expansions (--enable-casemod-attributes and --enable-casemod-expansions, - respectively); from bash-4.0-devel tree - -execute_cmd.c - - add code to fix_assignment_words to handle assignment statements to - "assignment builtins" that seem to be associative arrays. Imperfect - -subst.c - - array_remove_pattern now takes a SHELL_VAR * as its first argument - instead of an ARRAY *; from the bash-4.0-devel tree - - changes to array_length_reference for associative arrays; from the - bash-4.0-devel tree - - changes to get_var_and_type for associative arrays; from the - bash-4.0-devel tree - - changes to parameter_brace_substring for associative arrays; from the - bash-4.0-devel tree - - changes to param_expand for associative arrays; from the - bash-4.0-devel tree - -builtins/declare.def - - changes for associative arrays: new `-A' option, changes to make - local and global associative array variables; from the bash-4.0-devel - tree - - 6/27 - ---- -execute_cmd.c - - in execute_command_internal, when short-circuiting execution - because `breaking' or `continuing' is non-zero, preserve the exit - status by returning `last_command_exit_value' instead of an - unconditional EXECUTION_SUCCESS. Fixes bug reported by Roman - Rakus - - 6/28 - ---- -variables.c - - fix get_var_and_type to appropriately handle references like - ${varname[0]}, where `varname' is a scalar variable - -make_cmd.[ch],parse.y - - make_here_document now takes a second argument: the current line - number; changed caller (gather_here_documents) - -builtins/setattr.def - - added support for associative arrays and the `-A' variable attribute - option; from the bash-4.0-devel tree - -subst.c - - change code that transforms `declare -A xxx=(yyy)' to perform the - internal `declare -A xxx' before doing the variable assignment, - because associative arrays have to be declared before being assigned - to as such; uses new function make_internal_declare - - 6/30 - ---- -subst.[ch] - - dequote_escapes is now external; add declaration in subst.h - - remove_quoted_nulls is now external; add declaration in subst.h - -array.[ch] - - new functions for completeness: array_dequote, array_dequote_escapes, - array_remove_quoted_nulls - - array_subrange now calls array_remove_quoted_nulls for "${array[*]}". - Fixes bug reported by Vitor De Araujo - - array_patsub now calls array_remove_quoted_nulls for "${array[*]}" - - array_modcase now calls array_remove_quoted_nulls for "${array[*]}" - - array_patsub now handles the mflags&MATCH_QUOTED case appropriately - (that implies "${array[@]}") - -subst.c - - new functions for case-modifying word expansion suppport: - pos_params_casemod, parameter_brace_casemod; from bash-4.0-devel branch - -assoc.c - - new functions for completeness: assoc_remove_quoted_nulls - - assoc_patsub now calls assoc_remove_quoted_nulls for "${assoc[*]}" - - assoc_modcase now calls assoc_remove_quoted_nulls for "${array[*]}" - - assoc_patsub now handles the mflags&MATCH_QUOTED case appropriately - (that implies "${assoc[@]}") - - 7/1 - --- -assoc.[ch] - - new function, assoc_subrange: takes a hash table, converts it to a - word list, and performs the subrange and indexing on that list - - new functions for completeness: assoc_dequote, assoc_dequote_escapes - -subst.c - - verify_substring_values now takes the variable SHELL_VAR * as its - new first argument; changed callers - - change verify_substring_values to handle associative arrays using the - number of elements as the upper bound - - brought in code to do case-modifying word expansions from - bash-4.0-devel branch, conditional on CASEMOD_EXPANSIONS - -input.c - - if the read(2) in getc_with_restart returns -1/EAGAIN, turn off - non-blocking mode on the file descriptor and try again. Fixes - problem reported by Glynn Clements - - 7/2 - --- -doc/{bash.1,bashref.texi} - - documented new case-modifying word expansions - -make_cmd.c - - change make_here_document to display a warning message including the - start line of a here document if it ends up delimited by EOF. - Addresses issue raised by Richard Neill - -subst.c - - in do_assignment_internal, make sure the `invisible' attribute is - unset before returning success - - 7/3 - --- -config-top.h - - add `CASEMOD_CAPCASE' define to include or exclude the ~[~] word - expansion and the `capcase' variable attribute (declare -c) - -builtins/declare.def - - add support for manipulating the case-modifying attributes (new - declare -clu); from bash-4.0-devel branch - -builtins/setattr.def - - add support for reporting case-modifying attributes (-clu attributes); - from bash-4.0-devel branch - -doc/{bash.1,bashref.texi} - - specify that the read builtin timing out results in a return value - greater than 128 - - document new `-l' and `-u' options to declare/typeset/local. Leave - `-c' undocumented for now - - 7/4 - --- -make_cmd.[ch] - - make_coproc_command: construct a coproc; from bash-4.0-devel tree - -dispose_cmd.c - - dispose coproc command; from bash-4.0-devel tree - -copy_cmd.c - - copy a coproc command; from bash-4.0-devel tree - -print_cmd.c - - print a coproc command; from bash-4.0-devel tree - -shell.c - - dispoe the current coproc on shell exit; from bash-4.0-devel tree - -redir.c - - when closing redirects as part of user redirections, check whether - or not active coprocess fds are being closed and close the coproc - if so; from bash-4.0-devel tree - -config.h.in - - add define for COPROCESS_SUPPORT to include coprocesses - -configure.in - - add support for configuring coprocesses into and out of the build - -jobs.c - - in waitchld, check whether or not a coproc processs has exited; - from the bash-4.0-devel tree - - 7/5 - --- -doc/bashref.texi - - document new --enable-coprocesses option that includes coprocess - support - -execute_cmd.c - - add functions for coprocess support, including execute_coproc and - code to call it when command->type == cm_coproc; from - bash-4.0-devel tree - -lib/sh/fdprintf.c - - new library function fdprintf(int fd, const char *format, ...); - printf to a file descriptor - -{configure,config.h}.in - - support for detecting fdprintf and compiling in replacement - -Makefile.in,lib/sh/Makefile.in - - add rules to include fdprintf.o - -doc/{bash.1,bashref.texi} - - documented coprocesses and `coproc' reserved word - - 7/7 - --- -subst.c - - fix array_length_reference to use MB_STRLEN instead of STRLEN, so - multibyte characters in array values are computed correctly. Fixes - bug reported by Wang Xin - - 7/10 - ---- -jobs.c - - new function, maybe_give_terminal_to (old, new, flags), sets the - terminal pgrp to NEW if and only if it's currently set to OLD - - call maybe_give_terminal_to when the parent sets the terminal pgrp - to the pipeline pgrp in stop_pipeline, so we don't give the - terminal to the new job's pgrp unless it's currently owned by the - shell. Fixes race condition described by Joe Peterson - , where parent bash may change tty pgrp after a - grandchild (interactive bash child of su) has changed it to - something else. The call to maybe_give_terminal_to makes explicit - a previously-implicit assumption - -aclocal.m4 - - remove dependency on writable /tmp by creating directories in - build directory - -shell.c - - make changes to how bash sets no_line_editing and running_under_emacs - to deal with various emacs terminal emulators; use better check - for `eterm', since bash sends $PWD to eterm with control sequences - that confuse other programs. Problem reported by Micah Cowan - - - - 7/12 - ---- -print_cmd.c - - break code that prints here-documents into two functions: - print_heredoc_header, which prints the operator and delimiter, and - print_heredoc_body, which prints the body text and closing delimiter - - change print_redirection to call print_heredoc_{header,body} - - sentinel variable, printing_connection, used when printing a command - of type `connection' (|, &&, ||, etc.) - - change print_redirection_list to save any here documents it finds - while printing a connection and save them in `deferred_heredocs' - - new function, print_deferred_heredocs, called from print_redirection - in the cm_connection case, calls print_heredoc_header for all the - here documents, then prints the operator (|, &&, ||, etc.), then - the here-document body. This preserves syntactic correctness; the - old code printed the control operator after the body of the here - document. Fixes bug reported by - - 7/16 - ---- -locale.c - - in set_locale_var, print a warning message if setlocale() fails any - time it's called -- required some code restructuring - - 7/19 - ---- -support/shobj-conf - - support for mingw32, contributed by Carlo Bramix - - - 7/23 - ---- -execute_cmd.c - - added support (currently unused) to manage a list of coprocs - - 7/25 - ---- -bashline.c - - add extern declarations for literal_history and force_append_history - -builtins/shopt.def - - include "bashhist.h" instead of having extern declarations for the - appropriate history variables - -parser.h - - new parser_state value: PST_HEREDOC, set when reading body of here- - document in parse.y:read_secondary_line - -parse.y - - set PST_HEREDOC bit in parser_state when reading a secondary line - for the body of a here-document - - change read_secondary_line to save lines in the body of a here- - document in the shell history list if remember_on_history is - set. Fixes bug reported by Gene Golub - - 8/4 - --- -configure.in - - changed to 4.0-alpha - -lib/readline/readline.h - - changed constants to reflect readline-6.0 version - - 8/11 - ---- -lib/readline/signals.c - - make sure we don't use SIGWINCH without checking whether or not it's - defined. Fix from Pedro Alves - - 8/12 - ---- - -COPYING - - updated to GPLv3; edits in every file with a copyright or license - declaration to update to gpl3 - -version.c - - update extended version info to latest gnu standard - - 8/17 - ---- -subst.c - - change exp_jump_to_top_level to only call top_level_cleanup if - parse_and_execute_level is 0. If it's not, the longjmp to - parse_and_execute will run the unwind-protect stack. Fixes bug - most recently reported by Roman Rakus - - 8/18 - ---- -support/config.{guess,sub} - - updated to newer versions from autoconf-2.62 distribution - - 8/20 - ---- -subst.c - - fixed parameter_brace_substring to differentiate between indexed and - associative arrays when computing second offset, instead of - assuming indexed array - - 8/21 - ---- -support/xcase.c - - simple program to convert input from lower to uppercase and vice - versa. Now used by coproc test suite, since `tr -u' is not - portable. - - 8/22 - ---- -doc/bash.1 - - fixed description of the bindable edit-and-execute commands to note - they check $VISUAL first, instead of $FCEDIT. Fixed bug reported - by - -[bash-4.0-alpha frozen] - - 8/28 - ---- -[bash-4.0-alpha released] - - 9/1 - --- -builtins/evalstring.c - - fixed typo in parse_string (ostring used uninitialized). Bug - reported by Andreas Schwab - -subst.c - - fix return value of parameter_brace_expand to set the - W_HASQUOTEDNULL flag in the returned WORD_DESC * if the return value - from parameter_brace_remove_pattern is a quoted null string. Fixes - bug reported by Andreas Schwab - - set the W_HASQUOTEDNULL flag in the return value from - parameter_brace_expand if the return value from parameter_brace_patsub - is a quoted null string - - 9/6 - --- -builtins/read.def - - change read -t 0 to return success if there is input available to be - read -- allows scripts to poll for input. Uses input_avail libsh - function - - 9/9 - --- -externs.h - - fix extern fpurge declaration -- use HAVE_DECL_FPURGE instead of - NEED_FPURGE_DECL, since the former is set by `configure' - -jobs.h - - add extern declaration for close_pgrp_pipe - - add a new job state JNONE (-1) to the enum - -jobs.c - - include execute_cmd.h for extern declarations for coproc functions - -subst.c - - include builtins/builtext.h for extern declarations for functions - implementing builtins (e.g., declare_builtin) - -arrayfunc.c - - include "pathexp.h" for extern declaration for glob_char_p - -braces.c - - add extern declaration for `asprintf' - -lib/readline/rlprivate.h - - add extern declarations for _rl_trace, _rl_tropen - -lib/sh/zgetline.c - - add extern declarations for zread, zreadc - -lib/sh/mktime.c - - include "bashansi.h" for string function declarations - -builtins/common.h - - add extern declaration for parse_string - -trap.c - - include jobs.h for extern declaration for run_sigchld_trap - -general.c - - fix call to strtoimax in legal_number; if ep == string when function - returns, the number was not converted, even if errno is not set. - Fix from Paul Jarc - - 9/11 - ---- -[prayers for the victims of 9/11/2001] - -builtins/return.def - - call no_options, as Posix requires. This also has the effect of - disallowing negative return values unless they're prefixed by `--' - - 9/13 - ---- -builtins/bind.def - - add an error message when bind is used without line editing active, - instead of just returning an error status - -variables.c - - make sure make_local_variable never creates visible variables with - a value, whether or not a variable with the same name existed in a - previous context. This is consistent with ksh93. Fix from - - - 9/16 - ---- -execute_cmd.c - - add call to CHECK_TERMSIG in shell_execve after the call to execve - returns. Recommended by Roman Rakus - - add QUIT check in execute_connection after executing first command - in a `&' connection - - 9/22 - ---- -execute_cmd.c - - new semaphore variable, executing_list, incremented every time a - list (command1;command2 or command1 || command2 or command1 && - command2) is executed; used as sentinel for rest of shell - -sig.c,builtins/evalstring.c - - set executing_list to 0 when throwing execution back to top level; - make sure to unwind-protect it in appropriate places - -jobs.c - - if a pipeline is killed by SIGINT while executing a list (when - executing_list is non-zero), make sure the shell acts as if an - interrupt occurred. The behavior is dependent on the shell - compatibility level being > 32 (bash-4.0 and above) - - 9/23 - ---- -redir.c - - don't bother reporting an error with a file descriptor, even if - the errno is EBADF, if the redirection error (e.g., NOCLOBBER) - can't have anything to do with the fd. Fixes bug reported by - "David A. Harding" , debian bug #499633. - - 9/24 - ---- -builtins/declare.def - - make `declare [option] var' (and the `typeset' equivalent) create - invisible variables, instead of assigning the null string to a - visible variable. Fixes bug reported by Bernd Eggink - - 9/25 - ---- -builtins/common.[ch] - - new function, builtin_warning(), like builtin_error but for warning - messages - -builtins/bind.def - - experimental: print a warning, but go on, if line editing not active - when bind is invoked. Suggested by Rocky Bernstein - - - 10/3 - ---- -test.c - - use same_file instead of directly comparing st_dev and st_ino when - comparing files in filecomp(). From mingw32 patches submitted - by Hector Chu - - 10/4 - ---- - -redir.c - - in redirection_error(), use `error' instead of errno when comparing - against EBADF. From mingw32 patches submitted by Hector Chu - - -shell.c - - in unset_bash_input(), reset bash_input.type to st_none after - closing the default buffered fd. From mingw32 patches submitted - by Hector Chu - -builtins/cd.def - - ignore CDPATH when in privileged mode. Suggested by Paul Jarc - - -variables.c - - change sv_globignore to only act if privileged mode is not enabled. - Suggested by Paul Jarc - -doc/bash.1,bashref.texi - - document new treatment of CDPATH and GLOBIGNORE when privileged - mode is enabled - -builtins/read.def - - change prompt printing to occur after terminal is set to no-echo - mode. Based on suggestion from Stephane Chazelas - - -lib/readline/signals.c - - new variables to keep track of special characters corresponding to - SIGINT, SIGQUIT, and SIGTSTP - - new variable to keep track of whether tty is echoing control - characters corresponding to SIGINT, SIGQUIT, and SIGTSTP - - new function, _rl_echo_signal_char(int sig) to display the tty - special char generating SIGINT, SIGQUIT, or SIGTSTP. Based on - idea and code from Joe Peterson - - call rl_echo_signal_char in rl_signal_handler: if the terminal - settings indicate it, readline will echo characters that generate - keyboard signals - -lib/readline/rltty.c - - set _rl_intr_char, _rl_quit_char, and _rl_susp_char to special - characters that generate signals from keyboard - - set _rl_echoctl if ECHOCTL tty flag is set - -lib/readline/rlprivate.h - - extern declarations for _rl_intr_char, _rl_quit_char, and - _rl_susp_char - - extern declaration for _rl_echoctl - -lib/readline/readline.h - - extern declaration for rl_echo_signal_char() - -lib/readline/doc/rltech.texi - - document rl_echo_signal_handler(): available for applications - that install their own signal handlers - - 10/5 - ---- -execute_cmd.c - - fix errexit logic to not cause the shell to exit when a command in - a pipeline fails. Fixes bug reported by Marcin Owsiany - - - 10/14 - ----- -builtins/evalstring.c - - don't short-circuit execution in parse_and_execute if we want to - run an exit trap. Fixes bug reported by Steffen Kiess - - - 10/18 - ----- -parse.y - - fix error production to only call YYACCEPT if the shell is currently - interactive and not in parse_and_execute (so parser errors in - things like eval will correctly set $?). Fixes bug reported by - marco-oweber@gmx.de - -execute_cmd.c - - make sure variable name errors in execute_for_command and non- - identifier function names in execute_intern_function set the - return status to EX_BADUSAGE (2), not EX_USAGE (258) - -parser.h - - new parser state, PST_REPARSE - -parse.y - - turn PST_REPARSE on in parse_string_to_word_list - - in parse_matched_pair, if parsing a single-quoted string and - PST_REPARSE is set, don't requote CTLESC or CTLNUL. Fixes bug with - compound array assignment using $'\x7f' reported by Antonio Macchi - - - 10/23 - ----- -configure.in - - define LOCAL_LDFLAGS as `-z interpose' on Solaris 8, 9, and 10 to - allow the bash malloc to interpose the libc malloc when called by - library functions pre-bound to the libc malloc. Suggested by - Serge Dussud - - 10/26 - ----- -doc/bash.1 - - add single-sentence descriptions to rest of parameter expansions. - Suggested by Ken Irving - - 10/27 - ----- -subst.c - - rearrange code in skip_to_delims to allow quote characters and other - shell expansion characters to be delimiters - - add new flags value for inverting search: skip to the next character - NOT in the set of delimiters passed as an argument - -subst.h - - define for new SD_INVERT flag value for skip_to_delims - - 10/28 - ----- -bashline.c - - new bindable functions: shell-forward-word and shell-backward-word. - Like forward-word and backward-word, but understand shell quoting - and use shell metacharacters and whitespace as delimiters. - Suggested by Andre Majorel - - new bindable functions: shell-kill-word and shell-backward-kill-word. - Like kill-word and backward-kill-word, but understand shell quoting - and use shell metacharacters and whitespace as delimiters. - Suggested by Andre Majorel - -doc/bash.1,lib/readline/doc/rluser.texi - - documented shell-forward-word and shell-backward-word - - documented shell-kill-word and shell-backward-kill-word - - 11/1 - ---- -redir.c - - add extra argument to add_undo_redirect: fdbase. FD used to save - a file descriptor must be > fdbase if fdbase >= SHELL_FD_BASE. A - value of -1 for fdbase means to just use SHELL_FD_BASE. Fixes bug - with 0<&10 reported by Clark Jian Wang - - 11/5 - ---- -unwind_prot.c - - new function: have_unwind_protects(); returns 1 if unwind_protect_list - is not empty - -unwind_prot.h - - extern declaration for have_unwind_protects - -builtins/evalstring.c - - in parse_and_execute_cleanup, make sure that we don't call - run_unwind_frame and expect it to decrement parse_and_execute_level - if there's no unwind_protect_list, since there's a while loop in - throw_to_top_level that calls parse_and_execute_cleanup as long as - parse_and_execute_level is non-zero - - 11/9 - ---- -variables.c - - fix the assign function for COMP_WORDBREAKS to allocate new memory - to store as the variable's value, to avoid freeing memory twice - if the variable is unset after rl_completer_word_break_characters - is freed and reallocated. Fix from Mike Stroyan - - 11/20 - ----- -general.c - - new 'file_exists(fn)' primitive; just calls stat(2) - -general.h - - new extern declaration for file_exists - -bashline.c - - add `~' to rl_filename_quote_characters so make_quoted_replacement - will call bash_quote_filename for words containing `~'. Then - bash_quote_filename can make choices based on that - - change quote_word_break_chars to backslash-quote the tilde in a - filename with a leading tilde that exists in the current directory, - since we want to inhibit tilde expansion in this case - -execute_cmd.c - - call file_isdir from shell_execve instead of stat(2) directly - -bashhist.c - - use file_exists and file_isdir primitives instead of calling stat - - 11/21 - ----- -redir.c - - When undoing saving of non-standard file descriptors (>=3) using - file descriptors >= SHELL_FD_BASE, we set the saving fd to be - close-on-exec and use a flag (RX_SAVCLEXEC) to decide how to set - close-on-exec when the fd is restored. Set flag in add_undo_redirect, - check in do_redirection_internal. Fixes problem reported by Andreas - Schwab - - 11/26 - ----- -subst.c - - fix param_expand to have expansions of $@ and $* exit the shell if - there are no positional parameters and `set -u' is enabled. Fixes - bug reported by Dan Jacobson - - 11/27 - ----- -lib/readline/display.c - - fix update_line to not call space_to_eol if current cursor position - (_rl_last_c_pos) indicates that we're already at end of line. - Partial fix for bug reported by Mike Frysinger - - in update_line, don't call insert_some_chars if that will start - before the last invisible character in the prompt string and not - draw the entire prompt string. More of the partial fix for bug - reported by Mike Frysinger - - fix update_line to adjust _rl_last_c_pos by wrap_offset when adding - characters beginning before the last invisible character in the - prompt. New code is same as previously existed in a different code - path. Rest of fix for bug from Mike Frysinger - - fix assignment of newline breaks (inv_lbreaks) to correctly account - for prompts longer than two screen lines containing invisible - characters. The assumption is that part of the invisible characters - are on the first line (prompt_invis_chars_first_line) and the - remainder are on the last (wrap_offset - prompt_invis_chars_first_line). - Fix is in rl_redisplay. part of fix for bug reported by - "Wesley J. Landaker" in - http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=265182 - [TENTATIVE] - - fix _rl_move_cursor_relative to correctly offset `dpos' by `woff' - when there are invisible characters on lines after the second by - using (_rl_screenwidth*_rl_last_v_pos) when seeing whether or not - we just wrote some invisible characters. Rest of fix for bug - reported in http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=265182 - [TENTATIVE] - - 12/11 - ----- -sig.c - - reset the execution context before running the exit trap in - termsig_handler - -general.c - - set and unset terminate_immediately like interrupt_immediately in - bash_tilde_expand - -builtins/read.def - - change terminate_immediately to a counter instead of a flag, as - interrupt_immediately is used - -lib/readline/display.c - - slight change to fix from 11/27 to deal with prompts longer than a - screen line where the invisible characters all appear after the - line wrap. Fixes bug reported by Andreas Schwab - -builtins/{echo,printf}.def - - increment terminate_immediately at entry; decrement before returning. - Fix for bug reported by Ralf.Wildenhues@gmx.de - - 12/16 - ----- -subst.c - - fix off-by-one error in /dev/fd version of add_fifo_list; make - sure we add to totfds when it is == fd, not just when fd > totfds. - Fixes bug reported by marciso@gmail.com - -[bash-4.0-beta2 frozen] - - 12/29 - ----- -doc/{bash.1,bashref.texi} - - document more clearly that when not in Posix mode, command - substitution does not inherit the -e option. From bug report from - Freddy Vulto - -{execute_cmd,sig,builtins/evalstring}.c - - sentinel variable to keep track of whether or not we're supposed to - ignore the failure status of a command executed in a command - substitution even if the `-e' option is set: comsub_ignore_return - - increment and decrement comsub_ignore_return in execute_simple_command - before calling expand_words - - in parse_and_execute, if comsub_ignore_return is non-zero and the - SUBSHELL_COMSUB bit is set in subshell_environment, enable the - CMD_IGNORE_RETURN flag in every command executed from the passed - string. Fixes problem reported by Freddy Vulto - - make sure to reset comsub_ignore_return every time we throw to the - top level, like executing_list flag - - 1/2/2009 - -------- -parse.y - - fix to rewind_input_stream to handle case of $(...) command - substitution followed by a quoted literal newline. Report and fix - from Andreas Schwab - - 1/7 - --- - -subst.c - - fix match_wpattern and match_upattern to prefix a `*' to the - pattern even if it starts with a `*(' (if extglob is enabled) - before checking whether or not it can match anywhere in the - string. Fixes bug reported by os@sernet.de. - -[bash-4.0-rc1 frozen] - - 1/9 - --- -locale.c - - since setlocale() doesn't set errno to anything meaningful, - don't include the strerror() result in the error message if - it fails - - make sure the error messages printed when setlocale fails are - localizable - - 1/11 - ---- -lib/readline/histexpand.c - - make sure that every time history_no_expand_chars is tested, we - also call the history_inhibit_expansion_function if it's set. - Fixes bug reported by Yang Zhang - - 1/12 - ---- -trap.c - - make sure to call parse_and_execute with the SEVAL_RESETLINE bit - set in the flags so it will reset the line number when running - the trap commands. Partial fix for bug reported by - peter360@fastmail.us - - 1/14 - ---- -builtins/reserved.def - - document `coproc' so it can be used with `help' builtin. Pointed - out by Pierre Gaston - -lib/sh/casemod.c - - added two new flags: CASE_UPFIRST and CASE_LOWFIRST to casemod - the first character of the passed string and pass the rest - through unchanged. Fixes bug reported by Jan Schampera - - -externs.h - - new defines for CASE_UPFIRST and CASE_LOWFIRST - -subst.c - - use CASE_UPFIRST for ^ and CASE_LOWFIRST for , casemod operators - -builtins/mapfile.def - - call zreset() before calling first zgetline(), to clean out any - remaining data in local buffer used by zreadc. Fixes bug - reported by Pierre Gaston - - 1/15 - ---- -lib/sh/zread.c - - renamed zreadintr to zreadretry -- not perfect, but better - - new functions: zreadintr, which just calls read so it can be - interruptible, and zreadcintr, which is like zreadc but uses - zreadintr to fill the buffer - -lib/sh/zgetline.c - - in zgetline, when zread/zreadc return <= 0, make sure line is - non-null before assigning to line[nr] - -builtins/mapfile.def - - return an error right away if the supplied array variable name - refers to a readonly or noassign array - - set interrupt_immediately so calls to zgetline can be - interrupted. Fixes bug reported by Pierre Gaston - - - if interactive, pass the SEVAL_INTERACT and SEVAL_NOHIST flags - to parse_and_execute when calling callbacks. Fixes bug reported - by Pierre Gaston - - add `readarray' as a synonym for mapfile - -doc/{bash.1,bashref.texi} - - document behavior of mapfile builtin adding index of array element - to be assigned as additional argument to callback string. Reported - by Pierre Gaston - - document readarray as synonym for mapfile - -builtins/common.c - - new error function, sh_ttyerror(set), prints an error message having - to do with setting or getting terminal attributes - -builtins/read.def - - print error message if read fails to set terminal attributes - - 1/16 - ---- -execute_cmd.c - - new function, coproc_reap, calls coproc_dispose if sh_coproc is - marked as COPROC_DEAD - - new function, cpl_reap, disposes coprocs marked as COPROC_DEAD - from coproc list - - change coproc_pidchk to just mark the coproc as dead instead of - calling coproc_dispose, so we don't call unsafe functions from - a signal handler. Fixes bug reported by Andreas Schwab - - -execute_cmd.h - - new extern declaration for coproc_reap - -command.h - - new flags for c_flags member of a struct coproc - -{jobs,nojobs}.c - - add call to coproc_reap in cleanup_dead_jobs, which will do the - right queueing or blocking of SIGCHLD - -trap.c - - modify change from 1/12 to not reset the line number when running - the DEBUG and RETURN traps - - 1/18 - ---- -lib/sh/casemod.c - - change default operations to work on entire passed string instead - of breaking into words at non-alpha-numerics. Use new - CASE_USEWORDS flag to enable by-word behavior. Fixes bug reported - by Jan Schampera - -builtins/printf.def - - in vbprintf, bracket each call to vsnprintf (which uses the args - passed to vbprintf) with SH_VA_START and va_end, so we can - reninitialize the argument list for each call. This is actually - what the C standard requires. Fixes bug that caused printf -b - to `ignore' first % format specifier if it came first in the - string. Reported by David Leverton - -builtins/mapfile.def - - start the line count at 1, since it doesn't get incremented before - (or after) reading the first line, so things like - `mapfile -n 5 -c 1 -C 'echo foo' array < file' work right and call - the callback after the first line is read. Fixes bug reported by - Pierre Gaston - - 1/22 - ---- -lib/readline/complete.c - - set _rl_interrupt_immediately non-zero before reading from the file - system or calling an application-defined completion function - -lib/readline/signals.c - - renamed rl_signal_handler to _rl_handle_signal; new version of - rl_signal_handler that just calls _rl_handle_signal (for now) - - new function _rl_signal_handler that calls _rl_handle_signal without - any checking - -lib/readline/rlprivate.h - - new extern declaration for _rl_signal_handler - - new define, RL_CHECK_SIGNALS, checks whether or not _rl_caught_signal - is set and calls _rl_signal_handler if so - -lib/readline/{bind,input,readline}.c - - add RL_CHECK_SIGNALS in appropriate places - -lib/readline/signals.c - - change rl_signal_handler to set a flag and return rather than - run through the entire signal handling process. If - _rl_interrupt_immediately is set, call the signal handling code - right away instead of setting the flag. Initial fix for crash - bug reported by Roman Rakus - -aclocal.m4 - - new macro, BASH_TYPE_SIG_ATOMIC_T, tests for sig_atomic_t in - , defines as int if not defined - -configure.in - - call BASH_TYPE_SIG_ATOMIC_T - - call AC_C_VOLATILE - -config.h.in - - empty define for sig_atomic_t - - empty define for volatile - - 1/27 - ---- -subst.c - - audit calls to add_character and change to add_ifs_character (which - quotes characters in $IFS). Affects primarily `:', `=', and `~'. - Fixes bug reported by Jan Schampera ; fix - suggested by Stephane Chazelas - - 2/1 - --- -configure.in - - call AC_C_RESTRICT - -config.h.in - - add empty defintion for `restrict' - -pcomplete.c - - use unwind_protects around call to execute_shell_function in - gen_shell_function_matches to prevent data corruption if - throw_to_top_level is called. Bug report and fix from - werner@suse.de. - -execute_cmd.c - - don't clamp CPU usage at 100% in print_formatted_time. Bug reported - by Linda Walsh - - 2/5 - --- -locale.c - - in set_locale_var, set errno to 0 before calling setlocale(), and - print strerror (errno) if setlocale fails and errno ends up non-zero - - 2/6 - --- -configure.in - - backed out of solaris change from 10/23/2008 (adding `-z interpose' - to LDFLAGS) due to solaris updates to fix a linker problem. - Updatted by Serge Dussud - - 2/12 - ---- -execute_cmd.c - - change execute_connection so failure of a pipeline will cause the - shell to exit if -e is on. From discussion on austin-group - mailing list - - change execute_command_internal so failure of a user-specified - subshell will cause the shell to exit if -e is on. From discussion - on austin-group mailing list diff --git a/CWRU/POSIX.NOTES.old b/CWRU/POSIX.NOTES.old deleted file mode 100644 index 1707ab10c..000000000 --- a/CWRU/POSIX.NOTES.old +++ /dev/null @@ -1,82 +0,0 @@ -Starting bash with the `--posix' command-line option or executing -`set -o posix' while bash is running will cause bash to conform more -closely to the Posix.2 standard by changing the behavior to match that -specified by Posix.2 in areas where the bash default differs. - -The following list is what's changed when `posix mode' is in effect: - -1. When a command in the hash table no longer exists, bash will re-search - $PATH to find the new location. This is also available with - `shopt -s checkhash'. - -2. The >& redirection does not redirect stdout and stderr. - -3. The message printed by the job control code and builtins when a job - exits with a non-zero status is `Done(status)'. - -4. Reserved words may not be aliased. - -5. The Posix.2 PS1 and PS2 expansions of `!' -> history number and - `!!' -> `!' are enabled, and parameter expansion is performed on - the value regardless of the setting of the `promptvars' option. - -6. Interactive comments are enabled by default. (Note that bash has - them on by default anyway.) - -7. The Posix.2 startup files are executed ($ENV) rather than the normal - bash files. - -8. Tilde expansion is only performed on assignments preceding a command - name, rather than on all assignment statements on the line. - -9. The default history file is ~/.sh_history (default value of $HISTFILE). - -10. The output of `kill -l' prints all the signal names on a single line, - separated by spaces. - -11. Non-interactive shells exit if `file' in `. file' is not found. - -12. Redirection operators do not perform pathname expansion on the word - in the redirection unless the shell is interactive - -13. Function names must be valid shell identifiers. That is, they may not - contain characters other than letters, digits, and underscores, and - may not start with a digit. Declaring a function with an illegal name - causes a fatal syntax error in non-interactive shells. - -14. Posix.2 `special' builtins are found before shell functions during command - lookup. - -15. If a Posix.2 special builtin returns an error status, a non-interactive - shell exits. The fatal errors are those listed in the POSIX.2 standard, - and include things like passing incorrect options, redirection errors, - variable assignment errors for assignments preceding the command name, - and so on. - -16. The environment passed to executed commands is not sorted. Neither is - the output of `set'. This is not strictly Posix.2 behavior, but sh - does it this way. Ksh does not. It's not necessary to sort the - environment; no program should rely on it being sorted. - -17. If the `cd' builtin finds a directory to change to using $CDPATH, the - value it assigns to $PWD does not contain any symbolic links, as if - `cd -P' had been executed. - -18. A non-interactive shell exits with an error status if a variable - assignment error occurs when no command name follows the assignment - statements. A variable assignment error occurs, for example, when - trying to assign a value to a read-only variable. - -19. A non-interactive shell exits with an error status if the iteration - variable in a for statement or the selection variable in a select - statement is a read-only variable. - -20. Process substitution is not available. - -21. Assignment statements preceding POSIX.2 `special' builtins persist in - the shell environment after the builtin completes. - -There is other Posix.2 behavior that bash does not implement. Specifically: - -1. Assignment statements affect the execution environment of all builtins, - not just special ones. 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 ecb95fc86..000000000 --- a/MANIFEST~ +++ /dev/null @@ -1,1090 +0,0 @@ -# -# Master distribution manifest for bash -# -# -# Filename type -# -CWRU d -CWRU/misc d -builtins d -cross-build d -doc d -examples 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/tilde 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 755 -Makefile.in f -config-top.h f -config-bot.h f -config.h.in f -aclocal.m4 f -array.c f -arrayfunc.c f -assoc.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 -assoc.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/mapfile.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/x86-beos.cache 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/casemod.c f -lib/sh/clktck.c f -lib/sh/clock.c f -lib/sh/eaccess.c f -lib/sh/fdprintf.c f -lib/sh/fmtullong.c f -lib/sh/fmtulong.c f -lib/sh/fmtumax.c f -lib/sh/fpurge.c f -lib/sh/getcwd.c f -lib/sh/getenv.c f -lib/sh/inet_aton.c f -lib/sh/input_avail.c f -lib/sh/itos.c f -lib/sh/mailstat.c f -lib/sh/makepath.c f -lib/sh/mbscmp.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/strnlen.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/uconvert.c f -lib/sh/ufuncs.c f -lib/sh/vprint.c f -lib/sh/wcsdup.c f -lib/sh/winsize.c f -lib/sh/xstrchr.c f -lib/sh/zcatfd.c f -lib/sh/zgetline.c f -lib/sh/zmapfd.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/tilde/README f -lib/tilde/Makefile.in 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/README f -po/Rules-builtins f -po/Rules-quot f -po/bash.pot f -po/boldquot.sed f -po/en@boldquot.gmo f -po/en@boldquot.header f -po/en@boldquot.po f -po/en@quot.gmo f -po/en@quot.header f -po/en@quot.po f -po/af.gmo f -po/af.po f -po/bg.gmo f -po/bg.po f -po/ca.gmo f -po/ca.po f -po/cs.gmo f -po/cs.po f -po/de.gmo f -po/de.po f -po/eo.gmo f -po/eo.po f -po/es.gmo f -po/es.po f -po/et.gmo f -po/et.po f -po/fr.gmo f -po/fr.po f -po/hu.gmo f -po/hu.po f -po/id.gmo f -po/id.po f -po/ja.gmo f -po/ja.po f -po/lt.gmo f -po/lt.po f -po/nl.gmo f -po/nl.po f -po/pl.gmo f -po/pl.po f -po/pt_BR.gmo f -po/pt_BR.po f -po/ro.gmo f -po/ro.po f -po/ru.gmo f -po/ru.po f -po/sk.gmo f -po/sk.po f -po/sv.gmo f -po/sv.po f -po/tr.gmo f -po/tr.po f -po/vi.gmo f -po/vi.po f -po/zh_TW.gmo f -po/zh_TW.po 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/audit-patch 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/checkbashisms f 755 -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/signames.c f -support/bashbug.sh f -support/man2html.c f -support/recho.c f -support/zecho.c f -support/xcase.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/INDEX.txt f -examples/INDEX.html f -examples/obashdb/PERMISSION f -examples/obashdb/README f -examples/obashdb/bashdb f -examples/obashdb/bashdb.el f -examples/complete/bash_completion 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/mypid.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/timeout2 f -examples/scripts/timeout3 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/COPYRIGHT f -tests/alias.tests f -tests/alias.right f -tests/appendop.tests f -tests/appendop.right f -tests/arith-for.tests f -tests/arith-for.right f -tests/arith.tests f -tests/arith.right f -tests/arith1.sub f -tests/arith2.sub f -tests/array.tests f -tests/array.right f -tests/array1.sub f -tests/array2.sub f -tests/array3.sub f -tests/array4.sub f -tests/array5.sub f -tests/array6.sub f -tests/array7.sub f -tests/array8.sub f -tests/array9.sub f -tests/array-at-star f -tests/array2.right f -tests/assoc.tests f -tests/assoc.right f -tests/assoc1.sub f -tests/assoc2.sub f -tests/assoc3.sub f -tests/assoc4.sub 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/source6.sub f -tests/case.tests f -tests/case.right f -tests/casemod.tests f -tests/casemod.right f -tests/comsub.tests f -tests/comsub.right f -tests/comsub-eof.tests f -tests/comsub-eof0.sub f -tests/comsub-eof1.sub f -tests/comsub-eof2.sub f -tests/comsub-eof3.sub f -tests/comsub-eof.right f -tests/comsub-posix.tests f -tests/comsub-posix.right f -tests/comsub-posix1.sub f -tests/cond.tests f -tests/cond.right f -tests/cond-regexp.sub f -tests/coproc.tests f -tests/coproc.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-at1.sub f -tests/dollar-at2.sub f -tests/dollar-star1.sub f -tests/dollar-star2.sub f -tests/dollar-star3.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/exec8.sub f -tests/exp.tests f -tests/exp.right f -tests/exp1.sub f -tests/exp2.sub f -tests/extglob.tests f -tests/extglob.right f -tests/extglob1.sub f -tests/extglob2.tests f -tests/extglob2.right f -tests/extglob3.tests f -tests/extglob3.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 444 -tests/history1.sub f -tests/ifs.tests f -tests/ifs.right f -tests/ifs-posix.tests f -tests/ifs-posix.right f -tests/input-line.sh f -tests/input-line.sub f -tests/input.right f -tests/intl.tests f -tests/intl1.sub f -tests/intl.right f -tests/iquote.tests f -tests/iquote.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/jobs4.sub f -tests/jobs.right f -tests/mapfile.data f -tests/mapfile.right f -tests/mapfile.tests 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-exp5.sub f -tests/new-exp6.sub f -tests/new-exp7.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/nquote5.tests f -tests/nquote5.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/read5.sub f -tests/read6.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/redir7.sub f -tests/redir8.sub f -tests/redir9.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-appendop f -tests/run-arith-for f -tests/run-arith f -tests/run-array f -tests/run-array2 f -tests/run-assoc f -tests/run-braces f -tests/run-builtins f -tests/run-case f -tests/run-casemod f -tests/run-comsub f -tests/run-comsub-eof f -tests/run-comsub-posix f -tests/run-cond f -tests/run-coproc 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-extglob3 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-ifs-posix f -tests/run-input-test f -tests/run-intl f -tests/run-iquote f -tests/run-invert f -tests/run-jobs f -tests/run-mapfile 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-nquote5 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-tilde2 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/tilde2.tests f -tests/tilde2.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/type1.sub 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.save1 b/Makefile.in.save1 deleted file mode 100644 index e89181814..000000000 --- a/Makefile.in.save1 +++ /dev/null @@ -1,1461 +0,0 @@ -# Makefile for bash-3.1, version 2.159 -# -# Copyright (C) 1996-2005 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@ -SIZE = @SIZE@ - -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@ @CROSS_COMPILE@ -CPPFLAGS = @CPPFLAGS@ -CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ -LOCAL_CFLAGS = @LOCAL_CFLAGS@ ${DEBUG} ${MALLOC_DEBUG} -DEFS = @DEFS@ -LOCAL_DEFS = @LOCAL_DEFS@ - -LOCALE_DEFS = -DLOCALEDIR='"$(localedir)"' -DPACKAGE='"$(PACKAGE)"' - -LOCAL_LIBS = @LOCAL_LIBS@ -LIBS = $(BUILTINS_LIB) $(LIBRARIES) @LIBS@ -LIBS_FOR_BUILD = - -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) - -# Maybe add: -Wextra -GCC_LINT_FLAGS = -O -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wno-parentheses \ - -Wcast-align -Wstrict-prototypes -Wconversion -Wformat \ - -Wformat-nonliteral -Wmissing-braces -Wuninitialized \ - -Wmissing-declarations -Winline \ - -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 \ - ${SH_LIBSRC}/strnlen.c ${SH_LIBSRC}/winsize.c \ - ${SH_LIBSRC}/eaccess.c ${SH_LIBSRC}/wcsdup.c \ - ${SH_LIBSRC}/zmapfd.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 = @TILDE_LIB@ -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@ -SIGNAMES_O = @SIGNAMES_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 $(SIGNAMES_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 mksignames.o signames.o buildsignames.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 ${LIBS_FOR_BUILD} - -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) all) || exit 1 - -${LIBINTL_H}: ${INTL_LIBRARY} - -signames.o: $(SUPPORT_SRC)signames.c - $(RM) $@ - $(CC) $(CCFLAGS) -c $(SUPPORT_SRC)signames.c - -buildsignames.o: $(SUPPORT_SRC)signames.c - $(RM) $@ - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -o $@ -c $(SUPPORT_SRC)signames.c - -mksignames.o: $(SUPPORT_SRC)mksignames.c - $(RM) $@ - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -c $(SUPPORT_SRC)mksignames.c - -mksignames$(EXEEXT): mksignames.o buildsignames.o - $(RM) $@ - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ mksignames.o buildsignames.o ${LIBS_FOR_BUILD} - -mksyntax$(EXEEXT): ${srcdir}/mksyntax.c config.h syntax.h ${BASHINCDIR}/chartypes.h - $(RM) $@ - ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} -o $@ ${srcdir}/mksyntax.c ${LIBS_FOR_BUILD} - -# make a list of signals for the local system -- this is done when we're -# *not* cross-compiling -lsignames.h: mksignames$(EXEEXT) - $(RM) $@ - ./mksignames$(EXEEXT) $@ - -# 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$(EXEEXT) -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 -C - -#newversion: mkversion -# $(RM) .build -# ./mkversion -dir $(srcdir) -dist -# mv -f newversion.h version.h -# $(MAKE) -f $(srcdir)/Makefile $(MFLAGS) srcdir=$(srcdir) - -doc documentation: force - @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) ) - -info dvi ps: force - @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) CFLAGS='$(CCFLAGS)' $@ ) - -force: - -TAGS: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - etags $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - -tags: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - ctags -x $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) > $@ - -# Targets that actually do things not part of the build - -installdirs: - @${SHELL} $(SUPPORT_SRC)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 - -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) pathnames.h - -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 pathnames.h - -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 ${LIBS_FOR_BUILD} - -zecho$(EXEEXT): $(SUPPORT_SRC)zecho.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)zecho.c ${LIBS_FOR_BUILD} - -printenv$(EXEEXT): $(SUPPORT_SRC)printenv.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)printenv.c ${LIBS_FOR_BUILD} - -test tests check: force $(Program) $(TESTS_SUPPORT) - @-test -d tests || mkdir tests - @cp $(TESTS_SUPPORT) tests - @( cd $(srcdir)/tests && \ - PATH=$(BUILD_DIR)/tests:$$PATH 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 - -signames.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.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/Makefile.in~ b/Makefile.in~ deleted file mode 100644 index 13997ea27..000000000 --- a/Makefile.in~ +++ /dev/null @@ -1,1490 +0,0 @@ -# Makefile for bash-4.0, version 3.4 -# -# Copyright (C) 1996-2008 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 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# 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@ - -datarootdir = @datarootdir@ - -bindir = @bindir@ -libdir = @libdir@ -infodir = @infodir@ -includedir = @includedir@ -datadir = @datadir@ -localedir = @localedir@ - -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@ -SIZE = @SIZE@ - -INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALLMODE= -m 0755 -INSTALLMODE2 = -m 0555 - -TESTSCRIPT = @TESTSCRIPT@ - -DEBUGGER_START_FILE = @DEBUGGER_START_FILE@ - -#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@ @CROSS_COMPILE@ -CPPFLAGS = @CPPFLAGS@ -CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ -LOCAL_CFLAGS = @LOCAL_CFLAGS@ ${DEBUG} ${MALLOC_DEBUG} -DEFS = @DEFS@ -LOCAL_DEFS = @LOCAL_DEFS@ - -LOCALE_DEFS = -DLOCALEDIR='"$(localedir)"' -DPACKAGE='"$(PACKAGE)"' - -LOCAL_LIBS = @LOCAL_LIBS@ -LIBS = $(BUILTINS_LIB) $(LIBRARIES) @LIBS@ -LIBS_FOR_BUILD = - -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) - -# Maybe add: -Wextra -GCC_LINT_FLAGS = -O -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wno-parentheses \ - -Wcast-align -Wstrict-prototypes -Wconversion -Wformat \ - -Wformat-nonliteral -Wmissing-braces -Wuninitialized \ - -Wmissing-declarations -Winline \ - -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 \ - ${SH_LIBSRC}/strnlen.c ${SH_LIBSRC}/winsize.c \ - ${SH_LIBSRC}/eaccess.c ${SH_LIBSRC}/wcsdup.c \ - ${SH_LIBSRC}/zmapfd.c ${SH_LIBSRC}/fpurge.c \ - ${SH_LIBSRC}/zgetline.c ${SH_LIBSRC}/mbscmp.c \ - ${SH_LIBSRC}/casemod.c ${SH_LIBSRC}/uconvert.c \ - ${SH_LIBSRC}/ufuncs.c ${SH_LIBSRC}/fdprintf.c \ - ${SH_LIBSRC}/input_avail.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 = @TILDE_LIB@ -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 assoc.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 assoc.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@ -SIGNAMES_O = @SIGNAMES_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 assoc.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 $(SIGNAMES_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 \ - $(DEFSRC)/mapfile.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 $(DEFDIR)/mapfile.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 mksignames.o signames.o buildsignames.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 ${LIBS_FOR_BUILD} - -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) all) || exit 1 - -${LIBINTL_H}: ${INTL_DEP} - -signames.o: $(SUPPORT_SRC)signames.c - $(RM) $@ - $(CC) $(CCFLAGS) -c $(SUPPORT_SRC)signames.c - -buildsignames.o: $(SUPPORT_SRC)signames.c - $(RM) $@ - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -o $@ -c $(SUPPORT_SRC)signames.c - -mksignames.o: $(SUPPORT_SRC)mksignames.c - $(RM) $@ - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -DBUILDTOOL -c $(SUPPORT_SRC)mksignames.c - -mksignames$(EXEEXT): mksignames.o buildsignames.o - $(RM) $@ - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ mksignames.o buildsignames.o ${LIBS_FOR_BUILD} - -mksyntax$(EXEEXT): ${srcdir}/mksyntax.c config.h syntax.h ${BASHINCDIR}/chartypes.h - $(RM) $@ - ${CC_FOR_BUILD} ${CCFLAGS_FOR_BUILD} -o $@ ${srcdir}/mksyntax.c ${LIBS_FOR_BUILD} - -# make a list of signals for the local system -- this is done when we're -# *not* cross-compiling -lsignames.h: mksignames$(EXEEXT) - $(RM) $@ - ./mksignames$(EXEEXT) $@ - -# 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$(EXEEXT) -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 - -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 - -pathnames.h: Makefile $(srcdir)/pathnames.h.in - @sed -e 's|@DEBUGGER_START_FILE\@|${DEBUGGER_START_FILE}|g' $(srcdir)/pathnames.h.in > pathnames.tmp - @if test -f $@; then \ - cmp -s pathnames.tmp $@ || mv pathnames.tmp $@; \ - else \ - mv pathnames.tmp $@; \ - fi - @${RM} pathnames.tmp - -# 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 -C - -#newversion: mkversion -# $(RM) .build -# ./mkversion -dir $(srcdir) -dist -# mv -f newversion.h version.h -# $(MAKE) -f $(srcdir)/Makefile $(MFLAGS) srcdir=$(srcdir) - -doc documentation: force - @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) ) - -info dvi ps: force - @(cd $(DOCDIR) ; $(MAKE) $(MFLAGS) CFLAGS='$(CCFLAGS)' $@ ) - -force: - -TAGS: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - etags $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - -tags: $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) - ctags -x $(SOURCES) $(BUILTIN_C_SRC) $(LIBRARY_SOURCE) > $@ - -# Targets that actually do things not part of the build - -installdirs: - @${SHELL} $(SUPPORT_SRC)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 - -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) pathnames.h - -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 pathnames.h - -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 ${LIBS_FOR_BUILD} - -zecho$(EXEEXT): $(SUPPORT_SRC)zecho.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)zecho.c ${LIBS_FOR_BUILD} - -printenv$(EXEEXT): $(SUPPORT_SRC)printenv.c - @$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(SUPPORT_SRC)printenv.c ${LIBS_FOR_BUILD} - -test tests check: force $(Program) $(TESTS_SUPPORT) - @-test -d tests || mkdir tests - @cp $(TESTS_SUPPORT) tests - @( cd $(srcdir)/tests && \ - PATH=$(BUILD_DIR)/tests:$$PATH 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 bashline.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 -nojobs.o: $(DEFDIR)/builtext.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 -assoc.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h -assoc.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h -assoc.o: command.h ${BASHINCDIR}/stdc.h error.h -assoc.o: general.h xmalloc.h bashtypes.h variables.h arrayfunc.h conftypes.h -assoc.o: assoc.h hashlib.h -assoc.o: quit.h ${BASHINCDIR}/maxpath.h unwind_prot.h dispose_cmd.h -assoc.o: make_cmd.h subst.h sig.h pathnames.h externs.h -assoc.o: $(DEFSRC)/common.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 - -signames.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.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 -builtins/mapfile.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h xmalloc.h ${BASHINCDIR}/maxpath.h -builtins/mapfile.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h -builtins/mapfile.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h unwind_prot.h variables.h arrayfunc.h conftypes.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/mapfile.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -builtins/mkbuiltins.o: ${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/mapfile.o: $(DEFSRC)/mapfile.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-4.0~ b/NEWS-4.0~ deleted file mode 100644 index 9e922214d..000000000 --- a/NEWS-4.0~ +++ /dev/null @@ -1,1394 +0,0 @@ -o When using substring expansion on the positional parameters, a starting - index of 0 now causes $0 to be prefixed to the list. - -o There is a new variable, $BASHPID, which always returns the process id of - the current shell. - -o There is a new `autocd' option that, when enabled, causes bash to attempt - to `cd' to a directory name that is supplied as the first word of a - simple command. - -o There is a new `checkjobs' option that causes the shell to check for and - report any running or stopped jobs at exit. - -o The programmable completion code exports a new COMP_TYPE variable, set to - a character describing the type of completion being attempted. - -o The programmable completion code exports a new COMP_KEY variable, set to - the character that caused the completion to be invoked (e.g., TAB). - -o The programmable completion code now uses the same set of characters as - readline when breaking the command line into a list of words. - -o The block multiplier for the ulimit -c and -f options is now 512 when in - Posix mode, as Posix specifies. - -o Changed the behavior of the read builtin to save any partial input received - in the specified variable when the read builtin times out. This also - results in variables specified as arguments to read to be set to the empty - string when there is no input available. When the read builtin times out, - it returns an exit status greater than 128. - -o The shell now has the notion of a `compatibility level', controlled by - new variables settable by `shopt'. Setting this variable currently - restores the bash-3.1 behavior when processing quoted strings on the rhs - of the `=~' operator to the `[[' command. - -o The `ulimit' builtin now has new -b (socket buffer size) and -T (number - of threads) options. - -o There is a new `compopt' builtin that allows completion functions to modify - completion options for existing completions or the completion currently - being executed. - -o The `read' builtin has a new -i option which inserts text into the reply - buffer when using readline. - -o A new `-E' option to the complete builtin allows control of the default - behavior for completion on an empty line. - -o There is now limited support for completing command name words containing - globbing characters. - -o The `help' builtin now has a new -d option, to display a short description, - and a -m option, to print help information in a man page-like format. - -o There is a new `mapfile' builtin to populate an array with lines from a - given file. - -o If a command is not found, the shell attempts to execute a shell function - named `command_not_found_handle', supplying the command words as the - function arguments. - -o There is a new shell option: `globstar'. When enabled, the globbing code - treats `**' specially -- it matches all directories (and files within - them, when appropriate) recursively. - -o There is a new shell option: `dirspell'. When enabled, the filename - completion code performs spelling correction on directory names during - completion. - -o The `-t' option to the `read' builtin now supports fractional timeout - values. - -o Brace expansion now allows zero-padding of expanded numeric values and - will add the proper number of zeroes to make sure all values contain the - same number of digits. - -o There is a new bash-specific bindable readline function: `dabbrev-expand'. - It uses menu completion on a set of words taken from the history list. - -o The command assigned to a key sequence with `bind -x' now sets two new - variables in the environment of the executed command: READLINE_LINE_BUFFER - and READLINE_POINT. The command can change the current readline line - and cursor position by modifying READLINE_LINE_BUFFER and READLINE_POINT, - respectively. - -o There is a new >>& redirection operator, which appends the standard output - and standard error to the named file. - -o The parser now understands `|&' as a synonym for `2>&1 |', which redirects - the standard error for a command through a pipe. - -o The new `;&' case statement action list terminator causes execution to - continue with the action associated with the next pattern in the - statement rather than terminating the command. - -o The new `;;&' case statement action list terminator causes the shell to - test the next set of patterns after completing execution of the current - action, rather than terminating the command. - -o The shell understands a new variable: PROMPT_DIRTRIM. When set to an - integer value greater than zero, prompt expansion of \w and \W will - retain only that number of trailing pathname components and replace - the intervening characters with `...'. - -o There are new case-modifying word expansions: uppercase (^[^]) and - lowercase (,[,]). They can work on either the first character or - array element, or globally. They accept an optional shell pattern - that determines which characters to modify. There is an optionally- - configured feature to include capitalization operators. - -o The shell provides associative array variables, with the appropriate - support to create, delete, assign values to, and expand them. - -o The `declare' builtin now has new -l (convert value to lowercase upon - assignment) and -u (convert value to uppercase upon assignment) options. - There is an optionally-configurable -c option to capitalize a value at - assignment. - -o There is a new `coproc' reserved word that specifies a coprocess: an - asynchronous command run with two pipes connected to the creating shell. - Coprocs can be named. The input and output file descriptors and the - PID of the coprocess are available to the calling shell in variables - with coproc-specific names. - -o A value of 0 for the -t option to `read' now returns success if there is - input available to be read from the specified file descriptor. - -o CDPATH and GLOBIGNORE are ignored when the shell is running in privileged - mode. - -o New bindable readline functions shell-forward-word and shell-backward-word, - which move forward and backward words delimited by shell metacharacters - and honor shell quoting. - -o New bindable readline functions shell-backward-kill-word and shell-kill-word - which kill words backward and forward, but use the same word boundaries - as shell-forward-word and shell-backward-word. - -2. New Features in Readline - -a. A new variable, rl_sort_completion_matches; allows applications to inhibit - match list sorting (but beware: some things don't work right if - applications do this). - -b. A new variable, rl_completion_invoking_key; allows applications to discover - the key that invoked rl_complete or rl_menu_complete. - -c. The functions rl_block_sigint and rl_release_sigint are now public and - available to calling applications who want to protect critical sections - (like redisplay). - -d. The functions rl_save_state and rl_restore_state are now public and - available to calling applications; documented rest of readline's state - flag values. - -e. A new user-settable variable, `history-size', allows setting the maximum - number of entries in the history list. - -f. There is a new implementation of menu completion, with several improvements - over the old; the most notable improvement is a better `completions - browsing' mode. - -g. The menu completion code now uses the rl_menu_completion_entry_function - variable, allowing applications to provide their own menu completion - generators. - -h. There is support for replacing a prefix of a pathname with a `...' when - displaying possible completions. This is controllable by setting the - `completion-prefix-display-length' variable. Matches with a common prefix - longer than this value have the common prefix replaced with `...'. - -i. There is a new `revert-all-at-newline' variable. If enabled, readline will - undo all outstanding changes to all history lines when `accept-line' is - executed. - -j. If the kernel supports it, readline displays special characters - corresponding to a keyboard-generated signal when the signal is received. - -------------------------------------------------------------------------------- -This is a terse description of the new features added to bash-3.2 since -the release of bash-3.1. As always, the manual page (doc/bash.1) is -the place to look for complete descriptions. - -1. New Features in Bash - -a. Changed the parameter pattern replacement functions to not anchor the - pattern at the beginning of the string if doing global replacement - that - combination doesn't make any sense. - -b. When running in `word expansion only' mode (--wordexp option), inhibit - process substitution. - -c. Loadable builtins now work on MacOS X 10.[34]. - -d. Shells running in posix mode no longer set $HOME, as POSIX requires. - -e. The code that checks for binary files being executed as shell scripts now - checks only for NUL rather than any non-printing character. - -f. Quoting the string argument to the [[ command's =~ operator now forces - string matching, as with the other pattern-matching operators. - -2. New Features in Readline - -a. Calling applications can now set the keyboard timeout to 0, allowing - poll-like behavior. - -b. The value of SYS_INPUTRC (configurable at compilation time) is now used as - the default last-ditch startup file. - -c. The history file reading functions now allow windows-like \r\n line - terminators. - -------------------------------------------------------------------------------- -This is a terse description of the new features added to bash-3.1 since -the release of bash-3.0. As always, the manual page (doc/bash.1) is -the place to look for complete descriptions. - -1. New Features in Bash - -a. Bash now understands LC_TIME as a special variable so that time display - tracks the current locale. - -b. BASH_ARGC, BASH_ARGV, BASH_SOURCE, and BASH_LINENO are no longer created - as `invisible' variables and may not be unset. - -c. In POSIX mode, if `xpg_echo' option is enabled, the `echo' builtin doesn't - try to interpret any options at all, as POSIX requires. - -d. The `bg' builtin now accepts multiple arguments, as POSIX seems to specify. - -e. Fixed vi-mode word completion and glob expansion to perform tilde - expansion. - -f. The `**' mathematic exponentiation operator is now right-associative. - -g. The `ulimit' builtin has new options: -i (max number of pending signals), - -q (max size of POSIX message queues), and -x (max number of file locks). - -h. A bare `%' once again expands to the current job when used as a job - specifier. - -i. The `+=' assignment operator (append to the value of a string or array) is - now supported for assignment statements and arguments to builtin commands - that accept assignment statements. - -j. BASH_COMMAND now preserves its value when a DEBUG trap is executed. - -k. The `gnu_errfmt' option is enabled automatically if the shell is running - in an emacs terminal window. - -l. New configuration option: --single-help-strings. Causes long help text - to be written as a single string; intended to ease translation. - -m. The COMP_WORDBREAKS variable now causes the list of word break characters - to be emptied when the variable is unset. - -n. An unquoted expansion of $* when $IFS is empty now causes the positional - parameters to be concatenated if the expansion doesn't undergo word - splitting. - -o. Bash now inherits $_ from the environment if it appears there at startup. - -p. New shell option: nocasematch. If non-zero, shell pattern matching ignores - case when used by `case' and `[[' commands. - -q. The `printf' builtin takes a new option: -v var. That causes the output - to be placed into var instead of on stdout. - -r. By default, the shell no longer reports processes dying from SIGPIPE. - -s. Bash now sets the extern variable `environ' to the export environment it - creates, so C library functions that call getenv() (and can't use the - shell-provided replacement) get current values of environment variables. - -t. A new configuration option, `--enable-strict-posix-default', which will - build bash to be POSIX conforming by default. - -u. If compiled for strict POSIX conformance, LINES and COLUMNS may now - override the true terminal size. - -2. New Features in Readline - -a. The key sequence sent by the keypad `delete' key is now automatically - bound to delete-char. - -b. A negative argument to menu-complete now cycles backward through the - completion list. - -c. A new bindable readline variable: bind-tty-special-chars. If non-zero, - readline will bind the terminal special characters to their readline - equivalents when it's called (on by default). - -d. New bindable command: vi-rubout. Saves deleted text for possible - reinsertion, as with any vi-mode `text modification' command; `X' is bound - to this in vi command mode. - -e. A new external application-controllable variable that allows the LINES - and COLUMNS environment variables to set the window size regardless of - what the kernel returns: rl_prefer_env_winsize - -------------------------------------------------------------------------------- -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. The parameter pattern removal and substitution expansions are now much - faster and more efficient when using multibyte characters. - -nn. The `jobs', `kill', and `wait' builtins now accept job control notation - even if job control is not enabled. - -oo. 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/NEWS~ b/NEWS~ deleted file mode 100644 index f4b81f0b2..000000000 --- a/NEWS~ +++ /dev/null @@ -1,1395 +0,0 @@ -This is a terse description of the new features added to bash-4.0 since -the release of bash-3.2. As always, the manual page (doc/bash.1) is -the place to look for complete descriptions. - -1. New Features in Bash - -a. When using substring expansion on the positional parameters, a starting - index of 0 now causes $0 to be prefixed to the list. - -b. The `help' builtin now prints its columns with entries sorted vertically - rather than horizontally. - -c. There is a new variable, $BASHPID, which always returns the process id of - the current shell. - -d. There is a new `autocd' option that, when enabled, causes bash to attempt - to `cd' to a directory name that is supplied as the first word of a - simple command. - -e. There is a new `checkjobs' option that causes the shell to check for and - report any running or stopped jobs at exit. - -f. The programmable completion code exports a new COMP_TYPE variable, set to - a character describing the type of completion being attempted. - -g. The programmable completion code exports a new COMP_KEY variable, set to - the character that caused the completion to be invoked (e.g., TAB). - -h. If creation of a child process fails due to insufficient resources, bash - will try again several times before reporting failure. - -i. The programmable completion code now uses the same set of characters as - readline when breaking the command line into a list of words. - -j. The block multiplier for the ulimit -c and -f options is now 512 when in - Posix mode, as Posix specifies. - -k. Changed the behavior of the read builtin to save any partial input received - in the specified variable when the read builtin times out. This also - results in variables specified as arguments to read to be set to the empty - string when there is no input available. When the read builtin times out, - it returns an exit status greater than 128. - -l. The shell now has the notion of a `compatibility level', controlled by - new variables settable by `shopt'. Setting this variable currently - restores the bash-3.1 behavior when processing quoted strings on the rhs - of the `=~' operator to the `[[' command. - -m. The `ulimit' builtin now has new -b (socket buffer size) and -T (number - of threads) options. - -n. The -p option to `declare' now displays all variable values and attributes - (or function values and attributes if used with -f). - -o. There is a new `compopt' builtin that allows completion functions to modify - completion options for existing completions or the completion currently - being executed. - -p. The `read' builtin has a new -i option which inserts text into the reply - buffer when using readline. - -q. A new `-E' option to the complete builtin allows control of the default - behavior for completion on an empty line. - -r. There is now limited support for completing command name words containing - globbing characters. - -s. Changed format of internal help documentation for all builtins to roughly - follow man page format. - -t. The `help' builtin now has a new -d option, to display a short description, - and a -m option, to print help information in a man page-like format. - -u. There is a new `mapfile' builtin to populate an array with lines from a - given file. - -v. If a command is not found, the shell attempts to execute a shell function - named `command_not_found_handle', supplying the command words as the - function arguments. - -w. There is a new shell option: `globstar'. When enabled, the globbing code - treats `**' specially -- it matches all directories (and files within - them, when appropriate) recursively. - -x. There is a new shell option: `dirspell'. When enabled, the filename - completion code performs spelling correction on directory names during - completion. - -y. The `-t' option to the `read' builtin now supports fractional timeout - values. - -z. Brace expansion now allows zero-padding of expanded numeric values and - will add the proper number of zeroes to make sure all values contain the - same number of digits. - -aa. There is a new bash-specific bindable readline function: `dabbrev-expand'. - It uses menu completion on a set of words taken from the history list. - -bb. The command assigned to a key sequence with `bind -x' now sets two new - variables in the environment of the executed command: READLINE_LINE_BUFFER - and READLINE_POINT. The command can change the current readline line - and cursor position by modifying READLINE_LINE_BUFFER and READLINE_POINT, - respectively. - -cc. There is a new >>& redirection operator, which appends the standard output - and standard error to the named file. - -dd. The parser now understands `|&' as a synonym for `2>&1 |', which redirects - the standard error for a command through a pipe. - -ee. The new `;&' case statement action list terminator causes execution to - continue with the action associated with the next pattern in the - statement rather than terminating the command. - -ff. The new `;;&' case statement action list terminator causes the shell to - test the next set of patterns after completing execution of the current - action, rather than terminating the command. - -gg. The shell understands a new variable: PROMPT_DIRTRIM. When set to an - integer value greater than zero, prompt expansion of \w and \W will - retain only that number of trailing pathname components and replace - the intervening characters with `...'. - -hh. There are new case-modifying word expansions: uppercase (^[^]) and - lowercase (,[,]). They can work on either the first character or - array element, or globally. They accept an optional shell pattern - that determines which characters to modify. There is an optionally- - configured feature to include capitalization operators. - -ii. The shell provides associative array variables, with the appropriate - support to create, delete, assign values to, and expand them. - -jj. The `declare' builtin now has new -l (convert value to lowercase upon - assignment) and -u (convert value to uppercase upon assignment) options. - There is an optionally-configurable -c option to capitalize a value at - assignment. - -kk. There is a new `coproc' reserved word that specifies a coprocess: an - asynchronous command run with two pipes connected to the creating shell. - Coprocs can be named. The input and output file descriptors and the - PID of the coprocess are available to the calling shell in variables - with coproc-specific names. - -2. New Features in Readline - -a. A new variable, rl_sort_completion_matches; allows applications to inhibit - match list sorting (but beware: some things don't work right if - applications do this). - -b. A new variable, rl_completion_invoking_key; allows applications to discover - the key that invoked rl_complete or rl_menu_complete. - -c. The functions rl_block_sigint and rl_release_sigint are now public and - available to calling applications who want to protect critical sections - (like redisplay). - -d. The functions rl_save_state and rl_restore_state are now public and - available to calling applications; documented rest of readline's state - flag values. - -e. A new user-settable variable, `history-size', allows setting the maximum - number of entries in the history list. - -f. There is a new implementation of menu completion, with several improvements - over the old; the most notable improvement is a better `completions - browsing' mode. - -g. The menu completion code now uses the rl_menu_completion_entry_function - variable, allowing applications to provide their own menu completion - generators. - -h. There is support for replacing a prefix of a pathname with a `...' when - displaying possible completions. This is controllable by setting the - `completion-prefix-display-length' variable. Matches with a common prefix - longer than this value have the common prefix replaced with `...'. - -i. There is a new `revert-all-at-newline' variable. If enabled, readline will - undo all outstanding changes to all history lines when `accept-line' is - executed. - -------------------------------------------------------------------------------- -This is a terse description of the new features added to bash-3.2 since -the release of bash-3.1. As always, the manual page (doc/bash.1) is -the place to look for complete descriptions. - -1. New Features in Bash - -a. Changed the parameter pattern replacement functions to not anchor the - pattern at the beginning of the string if doing global replacement - that - combination doesn't make any sense. - -b. When running in `word expansion only' mode (--wordexp option), inhibit - process substitution. - -c. Loadable builtins now work on MacOS X 10.[34]. - -d. Shells running in posix mode no longer set $HOME, as POSIX requires. - -e. The code that checks for binary files being executed as shell scripts now - checks only for NUL rather than any non-printing character. - -f. Quoting the string argument to the [[ command's =~ operator now forces - string matching, as with the other pattern-matching operators. - -2. New Features in Readline - -a. Calling applications can now set the keyboard timeout to 0, allowing - poll-like behavior. - -b. The value of SYS_INPUTRC (configurable at compilation time) is now used as - the default last-ditch startup file. - -c. The history file reading functions now allow windows-like \r\n line - terminators. - -------------------------------------------------------------------------------- -This is a terse description of the new features added to bash-3.1 since -the release of bash-3.0. As always, the manual page (doc/bash.1) is -the place to look for complete descriptions. - -1. New Features in Bash - -a. Bash now understands LC_TIME as a special variable so that time display - tracks the current locale. - -b. BASH_ARGC, BASH_ARGV, BASH_SOURCE, and BASH_LINENO are no longer created - as `invisible' variables and may not be unset. - -c. In POSIX mode, if `xpg_echo' option is enabled, the `echo' builtin doesn't - try to interpret any options at all, as POSIX requires. - -d. The `bg' builtin now accepts multiple arguments, as POSIX seems to specify. - -e. Fixed vi-mode word completion and glob expansion to perform tilde - expansion. - -f. The `**' mathematic exponentiation operator is now right-associative. - -g. The `ulimit' builtin has new options: -i (max number of pending signals), - -q (max size of POSIX message queues), and -x (max number of file locks). - -h. A bare `%' once again expands to the current job when used as a job - specifier. - -i. The `+=' assignment operator (append to the value of a string or array) is - now supported for assignment statements and arguments to builtin commands - that accept assignment statements. - -j. BASH_COMMAND now preserves its value when a DEBUG trap is executed. - -k. The `gnu_errfmt' option is enabled automatically if the shell is running - in an emacs terminal window. - -l. New configuration option: --single-help-strings. Causes long help text - to be written as a single string; intended to ease translation. - -m. The COMP_WORDBREAKS variable now causes the list of word break characters - to be emptied when the variable is unset. - -n. An unquoted expansion of $* when $IFS is empty now causes the positional - parameters to be concatenated if the expansion doesn't undergo word - splitting. - -o. Bash now inherits $_ from the environment if it appears there at startup. - -p. New shell option: nocasematch. If non-zero, shell pattern matching ignores - case when used by `case' and `[[' commands. - -q. The `printf' builtin takes a new option: -v var. That causes the output - to be placed into var instead of on stdout. - -r. By default, the shell no longer reports processes dying from SIGPIPE. - -s. Bash now sets the extern variable `environ' to the export environment it - creates, so C library functions that call getenv() (and can't use the - shell-provided replacement) get current values of environment variables. - -t. A new configuration option, `--enable-strict-posix-default', which will - build bash to be POSIX conforming by default. - -u. If compiled for strict POSIX conformance, LINES and COLUMNS may now - override the true terminal size. - -2. New Features in Readline - -a. The key sequence sent by the keypad `delete' key is now automatically - bound to delete-char. - -b. A negative argument to menu-complete now cycles backward through the - completion list. - -c. A new bindable readline variable: bind-tty-special-chars. If non-zero, - readline will bind the terminal special characters to their readline - equivalents when it's called (on by default). - -d. New bindable command: vi-rubout. Saves deleted text for possible - reinsertion, as with any vi-mode `text modification' command; `X' is bound - to this in vi command mode. - -e. A new external application-controllable variable that allows the LINES - and COLUMNS environment variables to set the window size regardless of - what the kernel returns: rl_prefer_env_winsize - -------------------------------------------------------------------------------- -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. The parameter pattern removal and substitution expansions are now much - faster and more efficient when using multibyte characters. - -nn. The `jobs', `kill', and `wait' builtins now accept job control notation - even if job control is not enabled. - -oo. 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/NOTES~ b/NOTES~ deleted file mode 100644 index 31a7eebca..000000000 --- a/NOTES~ +++ /dev/null @@ -1,340 +0,0 @@ -Platform-Specific Configuration and Operation Notes -=================================================== - -1. configure --without-gnu-malloc on: - - alpha running OSF/1, Linux, or NetBSD (malloc needs 8-byte alignment; - bash malloc has 8-byte alignment now, but I have no alphas to test on) - - next running NeXT/OS - - all machines running SunOS YP code: SunOS4, SunOS5, HP/UX, if you - have problems with username completion or tilde expansion for - usernames found via YP/NIS - - linux (optional, but don't do it if you're using Doug Lea's malloc) - - QNX 4.2 - other OSF/1 machines (KSR/1, HP, IBM AIX/ESA) - AIX - sparc SVR4, SVR4.2 (ICL reference port) - DG/UX - Cray - - NetBSD/sparc (malloc needs 8-byte alignment; bash malloc has 8-byte - alignment now, but I have no NetBSD machines to test on) - - BSD/OS 2.1, 3.x if you want to use loadable builtins - - Motorola m68k machines running System V.3. There is a file descriptor - leak caused by using the bash malloc because closedir(3) needs to read - freed memory to find the file descriptor to close - -2. Configure using shlicc2 on BSD/OS 2.1 and BSD/OS 3.x to use loadable - builtins - -3. Bash cannot be built in a directory separate from the source directory - using configure --srcdir=... unless the version of `make' you're using - does $VPATH handling right. The script support/mkclone can be used to - create a `build tree' using symlinks to get around this. - -4. I've had reports that username completion (as well as tilde expansion - and \u prompt expansion) does not work on IRIX 5.3 when linking with - -lnsl. This is only a problem when you're running NIS, since - apparently -lnsl supports only /etc/passwd and not the NIS functions - for retrieving usernames and passwords. Editing the Makefile after - configure runs and removing the `-lnsl' from the assignment to `LIBS' - fixes the problem. - -5. There is a problem with the `makewhatis' script in older (pre-7.0) - versions of Red Hat Linux. Running `makewhatis' with bash-2.0 or - later versions results in error messages like this: - - /usr/sbin/makewhatis: cd: manpath: No such file or directory - /usr/sbin/makewhatis: manpath/whatis: No such file or directory - chmod: manpath/whatis: No such file or directory - /usr/sbin/makewhatis: cd: catpath: No such file or directory - /usr/sbin/makewhatis: catpath/whatis: No such file or directory - chmod: catpath/whatis: No such file or directory - - The problem is with `makewhatis'. Red Hat (and possibly other - Linux distributors) uses a construct like this in the code: - - eval path=$"$pages"path - - to do indirect variable expansion. This `happened to work' in - bash-1.14 and previous versions, but that was more an accident - of implementation than anything else -- it was never supported - and certainly is not portable. - - Bash-2.0 has a new feature that gives a new meaning to $"...". - This is explained more completely in item 1 in the COMPAT file. - - The three lines in the `makewhatis' script that need to be changed - look like this: - - eval $topath=$"$topath":$name - [...] - eval path=$"$pages"path - [...] - eval path=$"$pages"path - - The portable way to write this code is - - eval $topath="\$$topath":$name - eval path="\$$pages"path - eval path="\$$pages"path - - You could also experiment with another new bash feature: ${!var}. - This does indirect variable expansion, making the use of eval - unnecessary. - -6. There is a problem with syslogd on many Linux distributions (Red Hat - and Slackware are two that I have received reports about). syslogd - sends a SIGINT to its parent process, which is waiting for the daemon - to finish its initialization. The parent process then dies due to - the SIGINT, and bash reports it, causing unexpected console output - while the system is booting that looks something like - - starting daemons: syslogd/etc/rc.d/rc.M: line 29: 38 Interrupt ${NET}/syslogd - - Bash-2.0 reports events such as processes dying in scripts due to - signals when the standard output is a tty. Bash-1.14.x and previous - versions did not report such events. - - This should probably be reported as a bug to whatever Linux distributor - people see the problem on. In my opinion, syslogd should be changed to - use some other method of communication, or the wrapper function (which - appeared to be `daemon' when I looked at it some time ago) or script - (which appeared to be `syslog') should catch SIGINT, since it's an - expected event, and exit cleanly. - -7. Several people have reported that `dip' (a program for SLIP/PPP - on Linux) does not work with bash-2.0 installed as /bin/sh. - - I don't run any Linux boxes myself, and do not have the dip - code handy to look at, but the `problem' with bash-2.0, as - it has been related to me, is that bash requires the `-p' - option to be supplied at invocation if it is to run setuid - or setgid. - - This means, among other things, that setuid or setgid programs - which call system(3) (a horrendously bad practice in any case) - relinquish their setuid/setgid status in the child that's forked - to execute /bin/sh. - - The following is an *unofficial* patch to bash-2.0 that causes it - to not require `-p' to run setuid or setgid if invoked as `sh'. - It has been reported to work on Linux. It will make your system - vulnerable to bogus system(3) calls in setuid executables. - ---- ../bash-2.0.orig/shell.c Wed Dec 18 14:16:30 1996 -+++ shell.c Fri Mar 7 13:12:03 1997 -@@ -347,7 +347,7 @@ - if (posixly_correct) - posix_initialize (posixly_correct); - -- if (running_setuid && privileged_mode == 0) -+ if (running_setuid && privileged_mode == 0 && act_like_sh == 0) - disable_priv_mode (); - - /* Need to get the argument to a -c option processed in the - -8. Some people have asked about binding all of the keys in a PC-keyboard- - style numeric keypad to readline functions. Here's something I - received from the gnu-win32 list that may help. Insert the following - lines into ~/.inputrc: - -# home key -"\e[1~":beginning-of-line -# insert key -"\e[2~":kill-whole-line -# del key -"\e[3~":delete-char -# end key -"\e[4~":end-of-line -# pgup key -"\e[5~":history-search-forward -# pgdn key -"\e[6~":history-search-backward - -9. Hints for building under Minix 2.0 (Contributed by Terry R. McConnell, - ) - - The version of /bin/sh distributed with Minix is not up to the job of - running the configure script. The easiest solution is to swap /bin/sh - with /usr/bin/ash. Then use chmem(1) to increase the memory allocated - to /bin/sh. The following settings are known to work: - - text data bss stack memory - 63552 9440 3304 65536 141832 /bin/sh - - If you have problems with make or yacc it may be worthwhile first to - install the GNU versions of these utilities before attempting to build - bash. (As of this writing, all of these utilities are available for the - i386 as pre-built binaries via anonymous ftp at math.syr.edu in the - pub/mcconnell/minix directory. Note that the GNU version of yacc is called - bison.) - - Unless you want to see lots of warnings about old-style declarations, - do LOCAL_CFLAGS=-wo; export LOCAL_CFLAGS before running configure. - (These warnings are harmless, but annoying.) - - configure will insist that you supply a host type. For example, do - ./configure --host=i386-pc-minix. - - Minix does not support the system calls required for a proper - implementation of ulimit(). The `ulimit' builtin will not be available. - - Configure will fail to notice that many things like uid_t are indeed - typedef'd in , because it uses egrep for this purpose - and minix has no egrep. You could try making a link /usr/bin/egrep --> - /usr/bin/grep. Better is to install the GNU version of grep in - /usr/local/bin and make the link /usr/local/bin/egrep -->/usr/local/bin/grep. - (These must be hard links, of course, since Minix does not support - symbolic links.) - - You will see many warnings of the form: - warning: unknown s_type: 98 - I have no idea what this means, but it doesn't seem to matter. - -10. If you do not have /usr/ccs/bin in your PATH when building on SunOS 5.x - (Solaris 2), the configure script will be unable to find `ar' and - `ranlib' (of course, ranlib is unnecessary). Make sure your $PATH - includes /usr/ccs/bin on SunOS 5.x. This generally manifests itself - with libraries not being built and make reporting errors like - `cr: not found' when library construction is attempted. - -11. Building a statically-linked bash on Solaris 2.5.x, 2.6, 7, or 8 is - complicated. - - It's not possible to build a completely statically-linked binary, since - part of the C library depends on dynamic linking. The following recipe - assumes that you're using gcc and the Solaris ld (/usr/ccs/bin/ld) on - Solaris 2.5.x or 2.6: - - configure --enable-static-link - make STATIC_LD= LOCAL_LIBS='-Wl,-B,dynamic -ldl -Wl,-B,static' - - This should result in a bash binary that depends only on libdl.so: - - thor(2)$ ldd bash - libdl.so.1 => /usr/lib/libdl.so.1 - - If you're using the Sun C Compiler (Sun WorkShop C Compiler version - 4.2 was what I used), you should be able to get away with using - - configure --enable-static-link - make STATIC_LD= LOCAL_LIBS='-B dynamic -ldl -B static' - - If you want to completely remove any dependence on /usr, perhaps - to put a copy of bash in /sbin and have it available when /usr is - not mounted, force the build process to use the shared dl.so library - in /etc/lib. - - For gcc, this would be something like - - configure --enable-static-link - make STATIC_LD= LOCAL_LIBS='-Wl,-B,dynamic -Wl,-R/etc/lib -ldl -Wl,-B,static' - - For Sun's WS4.2 cc - - configure --enable-static-link - make STATIC_LD= LOCAL_LIBS='-B dynamic -R/etc/lib -ldl -B static' - - seems to work, at least on Solaris 2.5.1: - - thor(2)$ ldd bash - libdl.so.1 => /etc/lib/libdl.so.1 - - On Solaris 7 (Solaris 8, using the version of gcc on the free software - CD-ROM), the following recipe appears to work for gcc: - - configure --enable-static-link - make STATIC_LD='-Wl,-Bstatic' LOCAL_LIBS='-Wl,-Bdynamic -Wl,-R/etc/lib -ldl -Wl,-Bstatic' - - thor.ins.cwru.edu(2)$ ldd bash - libdl.so.1 => /etc/lib/libdl.so.1 - - Make the analogous changes if you are running Sun's C Compiler. - - I have received word that adding -L/etc/lib (or the equivalent - -Wl,-L/etc/lib) might also be necessary, in addition to the -R/etc/lib. - - On later versions of Solaris, it may be necessary to add -lnsl before - -ldl; statically-linked versions of bash using libnsl are not guaranteed - to work correctly on future versions of Solaris. - -12. Configuring bash to build it in a cross environment. Currently only - two native versions can be compiled this way, cygwin32 and x86 BeOS. - For BeOS, you would configure it like this: - - export RANLIB=i586-beos-ranlib - export AR=i586-beos-ar - export CC=i586-beos-gcc - configure i586-beos - - Similarly for cygwin32. - -13. Bash-2.05 has reverted to the bash-2.03 behavior of honoring the current - locale setting when processing ranges within pattern matching bracket - expressions ([A-Z]). This is what POSIX.2 and SUSv2 specify. - - The behavior of the matcher in bash-2.05 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'. - - 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. - -14. Building on Interix (nee OpenNT), which Microsoft bought from Softway - Systems and has seemingly abandoned (thanks to Kevin Moore for this item). - - 1. cp cross-build/opennt.cache config.cache - - 2. If desired, edit pathnames.h to set the values of SYS_PROFILE and - DEFAULT_HOSTS_FILE appropriately. - - 3. export CONFIG_SHELL=$INTERIX_ROOT/bin/sh - - 4. ./configure --prefix=$INTERIX_ROOT/usr/local (or wherever you - want it). - - 5. make; make install; enjoy - -15. Configure with `CC=xlc' if you don't have gcc on AIX 4.2 and later - versions. `xlc' running in `cc' mode has trouble compiling error.c. - -16. Configure --disable-multibyte on NetBSD versions (1.4 through at least - 1.6.1) that include wctype.h but do not define wctype_t. - -17. Do NOT use bison-1.75. It builds a non-working parser. The most - obvious effect is that constructs like "for i; do echo $i; done" don't - loop over the positional parameters. - -18. I have received reports that using -O2 with the MIPSpro results in a - binary that fails in strange ways. Using -O1 seems to work. diff --git a/README~ b/README~ deleted file mode 100644 index 3abd64287..000000000 --- a/README~ +++ /dev/null @@ -1,90 +0,0 @@ -Introduction -============ - -This is GNU Bash, version 4.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 POSIX for a discussion of how the Bash defaults differ -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 previous widely-distributed versions, bash-2.05b and -bash-3.2. 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 as published by the Free Software Foundation, -version 3 of the License. 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.ramey@case.edu diff --git a/aclocal.m4~ b/aclocal.m4~ deleted file mode 100644 index ec25ea868..000000000 --- a/aclocal.m4~ +++ /dev/null @@ -1,4020 +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 -#if !HAVE_DECL_SYS_SIGLIST -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("bash-aclocal", 0700); -if (err < 0) { - perror("mkdir"); - exit(1); -} -unlink("bash-aclocal/not_a_directory"); -fd = open("bash-aclocal/not_a_directory", O_WRONLY|O_CREAT|O_EXCL, 0666); -write(fd, "\n", 1); -close(fd); -dir = opendir("bash-aclocal/not_a_directory"); -unlink("bash-aclocal/not_a_directory"); -rmdir("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_TYPE_SIG_ATOMIC_T, -[AC_CACHE_CHECK(for sig_atomic_t in signal.h, ac_cv_have_sig_atomic_t, -[AC_TRY_LINK([ -#include -],[ sig_atomic_t x; ], -ac_cv_have_sig_atomic_t=yes, ac_cv_have_sig_atomic_t=no)) -if test "$ac_cv_have_sig_atomic_t" = "no" -then - AC_CHECK_TYPE(sig_atomic_t,int) -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() will dynamically allocate memory with 0 size]) -AC_CACHE_VAL(bash_cv_getcwd_malloc, -[AC_TRY_RUN([ -#include -#ifdef HAVE_UNISTD_H -#include -#endif - -main() -{ - char *xpwd; - xpwd = getcwd(0, 0); - exit (xpwd == 0); -} -], bash_cv_getcwd_malloc=yes, bash_cv_getcwd_malloc=no, - [AC_MSG_WARN(cannot check whether getcwd allocates memory when cross-compiling -- defaulting to no) - bash_cv_getcwd_malloc=no] -)]) -AC_MSG_RESULT($bash_cv_getcwd_malloc) -if test $bash_cv_getcwd_malloc = no; 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("bash-aclocal", 0700); -if (err < 0) { - perror ("mkdir"); - exit(1); -} -fd = mknod ("bash-aclocal/sh-np-autoconf", 0666 | S_IFIFO, 0); -if (fd == -1) { - rmdir ("bash-aclocal"); - exit (1); -} -close(fd); -unlink ("bash-aclocal/sh-np-autoconf"); -rmdir ("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, -[bash_cv_dev_fd="" -if test -d /dev/fd && (exec test -r /dev/fd/0 < /dev/null) ; then -# check for systems like FreeBSD 5 that only provide /dev/fd/[012] - if (exec test -r /dev/fd/3 3 -#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 -dnl geez, I wish I didn't have to check for all of this stuff separately -dnl -AC_DEFUN(BASH_CHECK_MULTIBYTE, -[ -AC_CHECK_HEADERS(wctype.h) -AC_CHECK_HEADERS(wchar.h) -AC_CHECK_HEADERS(langinfo.h) - -AC_CHECK_FUNC(mbrlen, AC_DEFINE(HAVE_MBRLEN)) -AC_CHECK_FUNC(mbscmp, AC_DEFINE(HAVE_MBSCMP)) -AC_CHECK_FUNC(mbsrtowcs, AC_DEFINE(HAVE_MBSRTOWCS)) - -AC_CHECK_FUNC(wcrtomb, AC_DEFINE(HAVE_WCRTOMB)) -AC_CHECK_FUNC(wcscoll, AC_DEFINE(HAVE_WCSCOLL)) -AC_CHECK_FUNC(wcsdup, AC_DEFINE(HAVE_WCSDUP)) -AC_CHECK_FUNC(wcwidth, AC_DEFINE(HAVE_WCWIDTH)) -AC_CHECK_FUNC(wctype, AC_DEFINE(HAVE_WCTYPE)) - -dnl checks for both mbrtowc and mbstate_t -AC_FUNC_MBRTOWC -if test $ac_cv_func_mbrtowc = yes; then - AC_DEFINE(HAVE_MBSTATE_T) -fi - -AC_CHECK_FUNCS(iswlower iswupper towlower towupper iswctype) - -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 check for wchar_t in -AC_CACHE_CHECK([for wchar_t in wchar.h], bash_cv_type_wchar_t, -[AC_TRY_COMPILE( -[#include -], -[ - wchar_t foo; - foo = 0; -], bash_cv_type_wchar_t=yes, bash_cv_type_wchar_t=no)]) -if test $bash_cv_type_wchar_t = yes; then - AC_DEFINE(HAVE_WCHAR_T, 1, [systems should define this type here]) -fi - -dnl check for wctype_t in -AC_CACHE_CHECK([for wctype_t in wctype.h], bash_cv_type_wctype_t, -[AC_TRY_COMPILE( -[#include ], -[ - wctype_t foo; - foo = 0; -], bash_cv_type_wctype_t=yes, bash_cv_type_wctype_t=no)]) -if test $bash_cv_type_wctype_t = yes; then - AC_DEFINE(HAVE_WCTYPE_T, 1, [systems should define this type here]) -fi - -dnl check for wint_t in -AC_CACHE_CHECK([for wint_t in wctype.h], bash_cv_type_wint_t, -[AC_TRY_COMPILE( -[#include ], -[ - wint_t foo; - foo = 0; -], bash_cv_type_wint_t=yes, bash_cv_type_wint_t=no)]) -if test $bash_cv_type_wint_t = yes; then - AC_DEFINE(HAVE_WINT_T, 1, [systems should define this type here]) -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 - -extern int rl_gnu_readline_p; - -main() -{ - FILE *fp; - fp = fopen("conftest.rlv", "w"); - if (fp == 0) - exit(1); - if (rl_gnu_readline_p != 1) - fprintf(fp, "0.0\n"); - else - 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 -]) - -AC_DEFUN(BASH_CHECK_WCONTINUED, -[ -AC_MSG_CHECKING(whether WCONTINUED flag to waitpid is unavailable or available but broken) -AC_CACHE_VAL(bash_cv_wcontinued_broken, -[AC_TRY_RUN([ -#include -#include -#include -#include - -#ifndef errno -extern int errno; -#endif -main() -{ - int x; - - x = waitpid(-1, (int *)0, WNOHANG|WCONTINUED); - if (x == -1 && errno == EINVAL) - exit (1); - else - exit (0); -} -], bash_cv_wcontinued_broken=no,bash_cv_wcontinued_broken=yes, - [AC_MSG_WARN(cannot check WCONTINUED if cross compiling -- defaulting to no) - bash_cv_wcontinued_broken=no] -)]) -AC_MSG_RESULT($bash_cv_wcontinued_broken) -if test $bash_cv_wcontinued_broken = yes; then -AC_DEFINE(WCONTINUED_BROKEN) -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 localeconv 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 -]) - -dnl From gnulib -AC_DEFUN([BASH_FUNC_FPURGE], -[ - AC_CHECK_FUNCS_ONCE([fpurge]) - AC_CHECK_FUNCS_ONCE([__fpurge]) - AC_CHECK_DECLS([fpurge], , , [#include ]) -]) diff --git a/alias.c~ b/alias.c~ deleted file mode 100644 index 1aa9cb11b..000000000 --- a/alias.c~ +++ /dev/null @@ -1,574 +0,0 @@ -/* alias.c -- Not a full alias, but just the kind that we use in the - shell. Csh style alias is somewhere else (`over there, in a box'). */ - -/* Copyright (C) 1987-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" - -#if defined (ALIAS) - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include "chartypes.h" -#include "bashansi.h" -#include "command.h" -#include "general.h" -#include "externs.h" -#include "alias.h" - -#if defined (PROGRAMMABLE_COMPLETION) -# include "pcomplete.h" -#endif - -#define ALIAS_HASH_BUCKETS 16 /* must be power of two */ - -typedef int sh_alias_map_func_t __P((alias_t *)); - -static void free_alias_data __P((PTR_T)); -static alias_t **map_over_aliases __P((sh_alias_map_func_t *)); -static void sort_aliases __P((alias_t **)); -static int qsort_alias_compare __P((alias_t **, alias_t **)); - -#if defined (READLINE) -static int skipquotes __P((char *, int)); -static int skipws __P((char *, int)); -static int rd_token __P((char *, int)); -#endif - -/* Non-zero means expand all words on the line. Otherwise, expand - after first expansion if the expansion ends in a space. */ -int alias_expand_all = 0; - -/* The list of aliases that we have. */ -HASH_TABLE *aliases = (HASH_TABLE *)NULL; - -void -initialize_aliases () -{ - if (!aliases) - aliases = hash_create (ALIAS_HASH_BUCKETS); -} - -/* Scan the list of aliases looking for one with NAME. Return NULL - if the alias doesn't exist, else a pointer to the alias_t. */ -alias_t * -find_alias (name) - char *name; -{ - BUCKET_CONTENTS *al; - - if (aliases == 0) - return ((alias_t *)NULL); - - al = hash_search (name, aliases, 0); - return (al ? (alias_t *)al->data : (alias_t *)NULL); -} - -/* Return the value of the alias for NAME, or NULL if there is none. */ -char * -get_alias_value (name) - char *name; -{ - alias_t *alias; - - if (aliases == 0) - return ((char *)NULL); - - alias = find_alias (name); - return (alias ? alias->value : (char *)NULL); -} - -/* Make a new alias from NAME and VALUE. If NAME can be found, - then replace its value. */ -void -add_alias (name, value) - char *name, *value; -{ - BUCKET_CONTENTS *elt; - alias_t *temp; - int n; - - if (!aliases) - { - initialize_aliases (); - temp = (alias_t *)NULL; - } - else - temp = find_alias (name); - - if (temp) - { - free (temp->value); - temp->value = savestring (value); - temp->flags &= ~AL_EXPANDNEXT; - n = value[strlen (value) - 1]; - if (n == ' ' || n == '\t') - temp->flags |= AL_EXPANDNEXT; - } - else - { - temp = (alias_t *)xmalloc (sizeof (alias_t)); - temp->name = savestring (name); - temp->value = savestring (value); - temp->flags = 0; - - n = value[strlen (value) - 1]; - if (n == ' ' || n == '\t') - temp->flags |= AL_EXPANDNEXT; - - elt = hash_insert (savestring (name), aliases, HASH_NOSRCH); - elt->data = temp; -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_aliases); -#endif - } -} - -/* Delete a single alias structure. */ -static void -free_alias_data (data) - PTR_T data; -{ - register alias_t *a; - - a = (alias_t *)data; - free (a->value); - free (a->name); - free (data); -} - -/* Remove the alias with name NAME from the alias table. Returns - the number of aliases left in the table, or -1 if the alias didn't - exist. */ -int -remove_alias (name) - char *name; -{ - BUCKET_CONTENTS *elt; - - if (aliases == 0) - return (-1); - - elt = hash_remove (name, aliases, 0); - if (elt) - { - free_alias_data (elt->data); - free (elt->key); /* alias name */ - free (elt); /* XXX */ -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_aliases); -#endif - return (aliases->nentries); - } - return (-1); -} - -/* Delete all aliases. */ -void -delete_all_aliases () -{ - if (aliases == 0) - return; - - hash_flush (aliases, free_alias_data); - hash_dispose (aliases); - aliases = (HASH_TABLE *)NULL; -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_aliases); -#endif -} - -/* Return an array of aliases that satisfy the conditions tested by FUNCTION. - If FUNCTION is NULL, return all aliases. */ -static alias_t ** -map_over_aliases (function) - sh_alias_map_func_t *function; -{ - register int i; - register BUCKET_CONTENTS *tlist; - alias_t *alias, **list; - int list_index; - - i = HASH_ENTRIES (aliases); - if (i == 0) - return ((alias_t **)NULL); - - list = (alias_t **)xmalloc ((i + 1) * sizeof (alias_t *)); - for (i = list_index = 0; i < aliases->nbuckets; i++) - { - for (tlist = hash_items (i, aliases); tlist; tlist = tlist->next) - { - alias = (alias_t *)tlist->data; - - if (!function || (*function) (alias)) - { - list[list_index++] = alias; - list[list_index] = (alias_t *)NULL; - } - } - } - return (list); -} - -static void -sort_aliases (array) - alias_t **array; -{ - qsort (array, strvec_len ((char **)array), sizeof (alias_t *), (QSFUNC *)qsort_alias_compare); -} - -static int -qsort_alias_compare (as1, as2) - alias_t **as1, **as2; -{ - int result; - - if ((result = (*as1)->name[0] - (*as2)->name[0]) == 0) - result = strcmp ((*as1)->name, (*as2)->name); - - return (result); -} - -/* Return a sorted list of all defined aliases */ -alias_t ** -all_aliases () -{ - alias_t **list; - - if (aliases == 0 || HASH_ENTRIES (aliases) == 0) - return ((alias_t **)NULL); - - list = map_over_aliases ((sh_alias_map_func_t *)NULL); - if (list) - sort_aliases (list); - return (list); -} - -char * -alias_expand_word (s) - char *s; -{ - alias_t *r; - - r = find_alias (s); - return (r ? savestring (r->value) : (char *)NULL); -} - -/* Readline support functions -- expand all aliases in a line. */ - -#if defined (READLINE) - -/* Return non-zero if CHARACTER is a member of the class of characters - that are self-delimiting in the shell (this really means that these - characters delimit tokens). */ -#define self_delimiting(character) (member ((character), " \t\n\r;|&()")) - -/* Return non-zero if CHARACTER is a member of the class of characters - that delimit commands in the shell. */ -#define command_separator(character) (member ((character), "\r\n;|&(")) - -/* If this is 1, we are checking the next token read for alias expansion - because it is the first word in a command. */ -static int command_word; - -/* This is for skipping quoted strings in alias expansions. */ -#define quote_char(c) (((c) == '\'') || ((c) == '"')) - -/* Consume a quoted string from STRING, starting at string[START] (so - string[START] is the opening quote character), and return the index - of the closing quote character matching the opening quote character. - This handles single matching pairs of unquoted quotes; it could afford - to be a little smarter... This skips words between balanced pairs of - quotes, words where the first character is quoted with a `\', and other - backslash-escaped characters. */ - -static int -skipquotes (string, start) - char *string; - int start; -{ - register int i; - int delimiter = string[start]; - - /* i starts at START + 1 because string[START] is the opening quote - character. */ - for (i = start + 1 ; string[i] ; i++) - { - if (string[i] == '\\') - { - i++; /* skip backslash-quoted quote characters, too */ - continue; - } - - if (string[i] == delimiter) - return i; - } - return (i); -} - -/* Skip the white space and any quoted characters in STRING, starting at - START. Return the new index into STRING, after zero or more characters - have been skipped. */ -static int -skipws (string, start) - char *string; - int start; -{ - register int i; - int pass_next, backslash_quoted_word; - unsigned char peekc; - - /* skip quoted strings, in ' or ", and words in which a character is quoted - with a `\'. */ - i = backslash_quoted_word = pass_next = 0; - - /* Skip leading whitespace (or separator characters), and quoted words. - But save it in the output. */ - - for (i = start; string[i]; i++) - { - if (pass_next) - { - pass_next = 0; - continue; - } - - if (whitespace (string[i])) - { - backslash_quoted_word = 0; /* we are no longer in a backslash-quoted word */ - continue; - } - - if (string[i] == '\\') - { - peekc = string[i+1]; - if (ISLETTER (peekc)) - backslash_quoted_word++; /* this is a backslash-quoted word */ - else - pass_next++; - continue; - } - - /* This only handles single pairs of non-escaped quotes. This - overloads backslash_quoted_word to also mean that a word like - ""f is being scanned, so that the quotes will inhibit any expansion - of the word. */ - if (quote_char(string[i])) - { - i = skipquotes (string, i); - /* This could be a line that contains a single quote character, - in which case skipquotes () terminates with string[i] == '\0' - (the end of the string). Check for that here. */ - if (string[i] == '\0') - break; - - peekc = string[i + 1]; - if (ISLETTER (peekc)) - backslash_quoted_word++; - continue; - } - - /* If we're in the middle of some kind of quoted word, let it - pass through. */ - if (backslash_quoted_word) - continue; - - /* If this character is a shell command separator, then set a hint for - alias_expand that the next token is the first word in a command. */ - - if (command_separator (string[i])) - { - command_word++; - continue; - } - break; - } - return (i); -} - -/* Characters that may appear in a token. Basically, anything except white - space and a token separator. */ -#define token_char(c) (!((whitespace (string[i]) || self_delimiting (string[i])))) - -/* Read from START in STRING until the next separator character, and return - the index of that separator. Skip backslash-quoted characters. Call - skipquotes () for quoted strings in the middle or at the end of tokens, - so all characters show up (e.g. foo'' and foo""bar) */ -static int -rd_token (string, start) - char *string; - int start; -{ - register int i; - - /* From here to next separator character is a token. */ - for (i = start; string[i] && token_char (string[i]); i++) - { - if (string[i] == '\\') - { - i++; /* skip backslash-escaped character */ - continue; - } - - /* If this character is a quote character, we want to call skipquotes - to get the whole quoted portion as part of this word. That word - will not generally match an alias, even if te unquoted word would - have. The presence of the quotes in the token serves then to - inhibit expansion. */ - if (quote_char (string[i])) - { - i = skipquotes (string, i); - /* This could be a line that contains a single quote character, - in which case skipquotes () terminates with string[i] == '\0' - (the end of the string). Check for that here. */ - if (string[i] == '\0') - break; - - /* Now string[i] is the matching quote character, and the - quoted portion of the token has been scanned. */ - continue; - } - } - return (i); -} - -/* Return a new line, with any aliases substituted. */ -char * -alias_expand (string) - char *string; -{ - register int i, j, start; - char *line, *token; - int line_len, tl, real_start, expand_next, expand_this_token; - alias_t *alias; - - line_len = strlen (string) + 1; - line = (char *)xmalloc (line_len); - token = (char *)xmalloc (line_len); - - line[0] = i = 0; - expand_next = 0; - command_word = 1; /* initialized to expand the first word on the line */ - - /* Each time through the loop we find the next word in line. If it - has an alias, substitute the alias value. If the value ends in ` ', - then try again with the next word. Else, if there is no value, or if - the value does not end in space, we are done. */ - - for (;;) - { - - token[0] = 0; - start = i; - - /* Skip white space and quoted characters */ - i = skipws (string, start); - - if (start == i && string[i] == '\0') - { - free (token); - return (line); - } - - /* copy the just-skipped characters into the output string, - expanding it if there is not enough room. */ - j = strlen (line); - tl = i - start; /* number of characters just skipped */ - RESIZE_MALLOCED_BUFFER (line, j, (tl + 1), line_len, (tl + 50)); - strncpy (line + j, string + start, tl); - line[j + tl] = '\0'; - - real_start = i; - - command_word = command_word || (command_separator (string[i])); - expand_this_token = (command_word || expand_next); - expand_next = 0; - - /* Read the next token, and copy it into TOKEN. */ - start = i; - i = rd_token (string, start); - - tl = i - start; /* token length */ - - /* If tl == 0, but we're not at the end of the string, then we have a - single-character token, probably a delimiter */ - if (tl == 0 && string[i] != '\0') - { - tl = 1; - i++; /* move past it */ - } - - strncpy (token, string + start, tl); - token [tl] = '\0'; - - /* If there is a backslash-escaped character quoted in TOKEN, - then we don't do alias expansion. This should check for all - other quoting characters, too. */ - if (xstrchr (token, '\\')) - expand_this_token = 0; - - /* If we should be expanding here, if we are expanding all words, or if - we are in a location in the string where an expansion is supposed to - take place, see if this word has a substitution. If it does, then do - the expansion. Note that we defer the alias value lookup until we - are sure we are expanding this token. */ - - if ((token[0]) && - (expand_this_token || alias_expand_all) && - (alias = find_alias (token))) - { - char *v; - int vlen, llen; - - v = alias->value; - vlen = strlen (v); - llen = strlen (line); - - /* +3 because we possibly add one more character below. */ - RESIZE_MALLOCED_BUFFER (line, llen, (vlen + 3), line_len, (vlen + 50)); - - strcpy (line + llen, v); - - if ((expand_this_token && vlen && whitespace (v[vlen - 1])) || - alias_expand_all) - expand_next = 1; - } - else - { - int llen, tlen; - - llen = strlen (line); - tlen = i - real_start; /* tlen == strlen(token) */ - - RESIZE_MALLOCED_BUFFER (line, llen, (tlen + 1), line_len, (llen + tlen + 50)); - - strncpy (line + llen, string + real_start, tlen); - line[llen + tlen] = '\0'; - } - command_word = 0; - } -} -#endif /* READLINE */ -#endif /* ALIAS */ diff --git a/array.c.save b/array.c.save deleted file mode 100644 index 1e1b90f82..000000000 --- a/array.c.save +++ /dev/null @@ -1,966 +0,0 @@ -/* - * array.c - functions to create, destroy, access, and manipulate arrays - * of strings. - * - * Arrays are sparse doubly-linked lists. An element's index is stored - * with it. - * - * Chet Ramey - * chet@ins.cwru.edu - */ - -/* Copyright (C) 1997-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 (ARRAY_VARS) - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include "bashansi.h" - -#include "shell.h" -#include "array.h" -#include "builtins/common.h" - -#define ADD_BEFORE(ae, new) \ - do { \ - ae->prev->next = new; \ - new->prev = ae->prev; \ - ae->prev = new; \ - new->next = ae; \ - } while(0) - -static char *array_to_string_internal __P((ARRAY_ELEMENT *, ARRAY_ELEMENT *, char *, int)); - -ARRAY * -array_create() -{ - ARRAY *r; - ARRAY_ELEMENT *head; - - r =(ARRAY *)xmalloc(sizeof(ARRAY)); - r->type = array_indexed; - r->max_index = -1; - r->num_elements = 0; - head = array_create_element(-1, (char *)NULL); /* dummy head */ - head->prev = head->next = head; - r->head = head; - return(r); -} - -void -array_flush (a) -ARRAY *a; -{ - register ARRAY_ELEMENT *r, *r1; - - if (a == 0) - return; - for (r = element_forw(a->head); r != a->head; ) { - r1 = element_forw(r); - array_dispose_element(r); - r = r1; - } - a->head->next = a->head->prev = a->head; - a->max_index = -1; - a->num_elements = 0; -} - -void -array_dispose(a) -ARRAY *a; -{ - if (a == 0) - return; - array_flush (a); - array_dispose_element(a->head); - free(a); -} - -ARRAY * -array_copy(a) -ARRAY *a; -{ - ARRAY *a1; - ARRAY_ELEMENT *ae, *new; - - if (a == 0) - return((ARRAY *) NULL); - a1 = array_create(); - a1->type = a->type; - a1->max_index = a->max_index; - a1->num_elements = a->num_elements; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - new = array_create_element(element_index(ae), element_value(ae)); - ADD_BEFORE(a1->head, new); - } - return(a1); -} - -/* - * Make and return a new array composed of the elements in array A from - * S to E, inclusive. - */ -ARRAY * -array_slice(array, s, e) -ARRAY *array; -ARRAY_ELEMENT *s, *e; -{ - ARRAY *a; - ARRAY_ELEMENT *p, *n; - int i; - arrayind_t mi; - - a = array_create (); - a->type = array->type; - - for (p = s, i = 0; p != e; p = element_forw(p), i++) { - n = array_create_element (element_index(p), element_value(p)); - ADD_BEFORE(a->head, n); - mi = element_index(n); - } - a->num_elements = i; - a->max_index = mi; - return a; -} - -/* - * Walk the array, calling FUNC once for each element, with the array - * element as the argument. - */ -void -array_walk(a, func, udata) -ARRAY *a; -sh_ae_map_func_t *func; -void *udata; -{ - register ARRAY_ELEMENT *ae; - - if (a == 0 || array_empty(a)) - return; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) - if ((*func)(ae, udata) < 0) - return; -} - -/* - * Shift the array A N elements to the left. Delete the first N elements - * and subtract N from the indices of the remaining elements. If FLAGS - * does not include AS_DISPOSE, this returns a singly-linked null-terminated - * list of elements so the caller can dispose of the chain. If FLAGS - * includes AS_DISPOSE, this function disposes of the shifted-out elements - * and returns NULL. - */ -ARRAY_ELEMENT * -array_shift(a, n, flags) -ARRAY *a; -int n, flags; -{ - register ARRAY_ELEMENT *ae, *ret; - register int i; - - if (a == 0 || array_empty(a) || n <= 0) - return ((ARRAY_ELEMENT *)NULL); - - for (i = 0, ret = ae = element_forw(a->head); ae != a->head && i < n; ae = element_forw(ae), i++) - ; - if (ae == a->head) { - /* Easy case; shifting out all of the elements */ - if (flags & AS_DISPOSE) { - array_flush (a); - return ((ARRAY_ELEMENT *)NULL); - } - for (ae = ret; element_forw(ae) != a->head; ae = element_forw(ae)) - ; - element_forw(ae) = (ARRAY_ELEMENT *)NULL; - a->head->next = a->head->prev = a->head; - a->max_index = -1; - a->num_elements = 0; - return ret; - } - /* - * ae now points to the list of elements we want to retain. - * ret points to the list we want to either destroy or return. - */ - ae->prev->next = (ARRAY_ELEMENT *)NULL; /* null-terminate RET */ - - a->head->next = ae; /* slice RET out of the array */ - ae->prev = a->head; - - for ( ; ae != a->head; ae = element_forw(ae)) - element_index(ae) -= n; /* renumber retained indices */ - - a->num_elements -= n; /* modify bookkeeping information */ - a->max_index -= n; - - if (flags & AS_DISPOSE) { - for (ae = ret; ae; ) { - ret = element_forw(ae); - array_dispose_element(ae); - ae = ret; - } - return ((ARRAY_ELEMENT *)NULL); - } - - return ret; -} - -/* - * Shift array A right N indices. If S is non-null, it becomes the value of - * the new element 0. Returns the number of elements in the array after the - * shift. - */ -int -array_rshift (a, n, s) -ARRAY *a; -int n; -char *s; -{ - register ARRAY_ELEMENT *ae, *new; - - if (a == 0 || (array_empty(a) && s == 0)) - return 0; - else if (n <= 0) - return (a->num_elements); - - ae = element_forw(a->head); - if (s) { - new = array_create_element(0, s); - ADD_BEFORE(ae, new); - a->num_elements++; - if (array_num_elements(a) == 1) /* array was empty */ - return 1; - } - - /* - * Renumber all elements in the array except the one we just added. - */ - for ( ; ae != a->head; ae = element_forw(ae)) - element_index(ae) += n; - - a->max_index = element_index(a->head->prev); - - return (a->num_elements); -} - -ARRAY_ELEMENT * -array_unshift_element(a) -ARRAY *a; -{ - return (array_shift (a, 1, 0)); -} - -int -array_shift_element(a, v) -ARRAY *a; -char *v; -{ - return (array_rshift (a, 1, v)); -} - -ARRAY * -array_quote(array) -ARRAY *array; -{ - ARRAY_ELEMENT *a; - char *t; - - if (array == 0 || array_head(array) == 0 || array_empty(array)) - return (ARRAY *)NULL; - for (a = element_forw(array->head); a != array->head; a = element_forw(a)) { - t = quote_string (a->value); - FREE(a->value); - a->value = t; - } - return array; -} - -ARRAY * -array_quote_escapes(array) -ARRAY *array; -{ - ARRAY_ELEMENT *a; - char *t; - - if (array == 0 || array_head(array) == 0 || array_empty(array)) - return (ARRAY *)NULL; - for (a = element_forw(array->head); a != array->head; a = element_forw(a)) { - t = quote_escapes (a->value); - FREE(a->value); - a->value = t; - } - return array; -} - -/* - * Return a string whose elements are the members of array A beginning at - * index START and spanning NELEM members. Null elements are counted. - * Since arrays are sparse, unset array elements are not counted. - */ -char * -array_subrange (a, start, nelem, starsub, quoted) -ARRAY *a; -arrayind_t start, nelem; -int starsub, quoted; -{ - ARRAY *a2; - ARRAY_ELEMENT *h, *p; - arrayind_t i; - char *ifs, sep[2], *t; - - p = a ? array_head (a) : 0; - if (p == 0 || array_empty (a) || start > array_max_index(a)) - return ((char *)NULL); - - /* - * Find element with index START. If START corresponds to an unset - * element (arrays can be sparse), use the first element whose index - * is >= START. If START is < 0, we count START indices back from - * the end of A (not elements, even with sparse arrays -- START is an - * index). - */ - for (p = element_forw(p); p != array_head(a) && start > element_index(p); p = element_forw(p)) - ; - - if (p == a->head) - return ((char *)NULL); - - /* Starting at P, take NELEM elements, inclusive. */ - for (i = 0, h = p; p != a->head && i < nelem; i++, p = element_forw(p)) - ; - - a2 = array_slice(a, h, p); - - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - array_quote(a2); - else - array_quote_escapes(a2); - - if (starsub && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) { - /* ${array[*]} */ - ifs = getifs(); - sep[0] = ifs ? *ifs : '\0'; - } else if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) { - /* ${array[@]}. Use ' ' to make sure the right splitting is - performed even when $IFS is "" */ - ifs = getifs(); - sep[0] = (ifs && *ifs) ? *ifs : ' '; - } else - sep[0] = ' '; - sep[1] = '\0'; - - t = array_to_string (a2, sep, 0); - array_dispose(a2); - - return t; -} - -char * -array_patsub (a, pat, rep, mflags) -ARRAY *a; -char *pat, *rep; -int mflags; -{ - ARRAY *a2; - ARRAY_ELEMENT *e; - char *t, *ifs, sifs[2]; - - if (a == 0 || array_head(a) == 0 || array_empty(a)) - return ((char *)NULL); - - a2 = array_copy(a); - for (e = element_forw(a2->head); e != a2->head; e = element_forw(e)) { - t = pat_subst(element_value(e), pat, rep, mflags); - FREE(element_value(e)); - e->value = t; - } - - if (mflags & MATCH_QUOTED) - array_quote(a2); - else - array_quote_escapes(a2); - if (mflags & MATCH_STARSUB) { - ifs = getifs(); - sifs[0] = ifs ? *ifs : '\0'; - sifs[1] = '\0'; - t = array_to_string (a2, sifs, 0); - } else - t = array_to_string (a2, " ", 0); - array_dispose (a2); - - return t; -} - -/* - * Allocate and return a new array element with index INDEX and value - * VALUE. - */ -ARRAY_ELEMENT * -array_create_element(indx, value) -arrayind_t indx; -char *value; -{ - ARRAY_ELEMENT *r; - - r = (ARRAY_ELEMENT *)xmalloc(sizeof(ARRAY_ELEMENT)); - r->ind = indx; - r->value = value ? savestring(value) : (char *)NULL; - r->next = r->prev = (ARRAY_ELEMENT *) NULL; - return(r); -} - -#ifdef INCLUDE_UNUSED -ARRAY_ELEMENT * -array_copy_element(ae) -ARRAY_ELEMENT *ae; -{ - return(ae ? array_create_element(element_index(ae), element_value(ae)) - : (ARRAY_ELEMENT *) NULL); -} -#endif - -void -array_dispose_element(ae) -ARRAY_ELEMENT *ae; -{ - if (ae) { - FREE(ae->value); - free(ae); - } -} - -/* - * Add a new element with index I and value V to array A (a[i] = v). - */ -int -array_insert(a, i, v) -ARRAY *a; -arrayind_t i; -char *v; -{ - register ARRAY_ELEMENT *new, *ae; - - if (a == 0) - return(-1); - new = array_create_element(i, v); - if (i > array_max_index(a)) { - /* - * Hook onto the end. This also works for an empty array. - * Fast path for the common case of allocating arrays - * sequentially. - */ - ADD_BEFORE(a->head, new); - a->max_index = i; - a->num_elements++; - return(0); - } - /* - * Otherwise we search for the spot to insert it. - */ - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - if (element_index(ae) == i) { - /* - * Replacing an existing element. - */ - array_dispose_element(new); - free(element_value(ae)); - ae->value = v ? savestring(v) : (char *)NULL; - return(0); - } else if (element_index(ae) > i) { - ADD_BEFORE(ae, new); - a->num_elements++; - return(0); - } - } - return (-1); /* problem */ -} - -/* - * Delete the element with index I from array A and return it so the - * caller can dispose of it. - */ -ARRAY_ELEMENT * -array_remove(a, i) -ARRAY *a; -arrayind_t i; -{ - register ARRAY_ELEMENT *ae; - - if (a == 0 || array_empty(a)) - return((ARRAY_ELEMENT *) NULL); - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) - if (element_index(ae) == i) { - ae->next->prev = ae->prev; - ae->prev->next = ae->next; - a->num_elements--; - if (i == array_max_index(a)) - a->max_index = element_index(ae->prev); - return(ae); - } - return((ARRAY_ELEMENT *) NULL); -} - -/* - * Return the value of a[i]. - */ -char * -array_reference(a, i) -ARRAY *a; -arrayind_t i; -{ - register ARRAY_ELEMENT *ae; - - if (a == 0 || array_empty(a)) - return((char *) NULL); - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) - if (element_index(ae) == i) - return(element_value(ae)); - return((char *) NULL); -} - -/* Convenience routines for the shell to translate to and from the form used - by the rest of the code. */ - -WORD_LIST * -array_to_word_list(a) -ARRAY *a; -{ - WORD_LIST *list; - ARRAY_ELEMENT *ae; - - if (a == 0 || array_empty(a)) - return((WORD_LIST *)NULL); - list = (WORD_LIST *)NULL; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) - list = make_word_list (make_bare_word(element_value(ae)), list); - return (REVERSE_LIST(list, WORD_LIST *)); -} - -ARRAY * -array_from_word_list (list) -WORD_LIST *list; -{ - ARRAY *a; - - if (list == 0) - return((ARRAY *)NULL); - a = array_create(); - return (array_assign_list (a, list)); -} - -WORD_LIST * -array_keys_to_word_list(a) -ARRAY *a; -{ - WORD_LIST *list; - ARRAY_ELEMENT *ae; - char *t; - - if (a == 0 || array_empty(a)) - return((WORD_LIST *)NULL); - list = (WORD_LIST *)NULL; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - t = itos(element_index(ae)); - list = make_word_list (make_bare_word(t), list); - free(t); - } - return (REVERSE_LIST(list, WORD_LIST *)); -} - -ARRAY * -array_assign_list (array, list) -ARRAY *array; -WORD_LIST *list; -{ - register WORD_LIST *l; - register arrayind_t i; - - for (l = list, i = 0; l; l = l->next, i++) - array_insert(array, i, l->word->word); - return array; -} - -char ** -array_to_argv (a) -ARRAY *a; -{ - char **ret, *t; - int i; - ARRAY_ELEMENT *ae; - - if (a == 0 || array_empty(a)) - return ((char **)NULL); - ret = strvec_create (array_num_elements (a) + 1); - i = 0; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - t = element_value (ae); - ret[i++] = t ? savestring (t) : (char *)NULL; - } - ret[i] = (char *)NULL; - return (ret); -} - -/* - * Return a string that is the concatenation of the elements in A from START - * to END, separated by SEP. - */ -static char * -array_to_string_internal (start, end, sep, quoted) -ARRAY_ELEMENT *start, *end; -char *sep; -int quoted; -{ - char *result, *t; - ARRAY_ELEMENT *ae; - int slen, rsize, rlen, reg; - - if (start == end) /* XXX - should not happen */ - return ((char *)NULL); - - slen = strlen(sep); - result = NULL; - for (rsize = rlen = 0, ae = start; ae != end; ae = element_forw(ae)) { - if (rsize == 0) - result = (char *)xmalloc (rsize = 64); - if (element_value(ae)) { - t = quoted ? quote_string(element_value(ae)) : element_value(ae); - reg = strlen(t); - RESIZE_MALLOCED_BUFFER (result, rlen, (reg + slen + 2), - rsize, rsize); - strcpy(result + rlen, t); - rlen += reg; - if (quoted && t) - free(t); - /* - * Add a separator only after non-null elements. - */ - if (element_forw(ae) != end) { - strcpy(result + rlen, sep); - rlen += slen; - } - } - } - if (result) - result[rlen] = '\0'; /* XXX */ - return(result); -} - -char * -array_to_assign (a, quoted) -ARRAY *a; -int quoted; -{ - char *result, *valstr, *is; - char indstr[INT_STRLEN_BOUND(intmax_t) + 1]; - ARRAY_ELEMENT *ae; - int rsize, rlen, elen; - - if (a == 0 || array_empty (a)) - return((char *)NULL); - - result = (char *)xmalloc (rsize = 128); - result[0] = '('; - rlen = 1; - - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - is = inttostr (element_index(ae), indstr, sizeof(indstr)); - valstr = element_value (ae) ? sh_double_quote (element_value(ae)) - : (char *)NULL; - elen = STRLEN (indstr) + 8 + STRLEN (valstr); - RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize); - - result[rlen++] = '['; - strcpy (result + rlen, is); - rlen += STRLEN (is); - result[rlen++] = ']'; - result[rlen++] = '='; - if (valstr) { - strcpy (result + rlen, valstr); - rlen += STRLEN (valstr); - } - - if (element_forw(ae) != a->head) - result[rlen++] = ' '; - - FREE (valstr); - } - RESIZE_MALLOCED_BUFFER (result, rlen, 1, rsize, 8); - result[rlen++] = ')'; - result[rlen] = '\0'; - if (quoted) { - /* This is not as efficient as it could be... */ - valstr = sh_single_quote (result); - free (result); - result = valstr; - } - return(result); -} - -char * -array_to_string (a, sep, quoted) -ARRAY *a; -char *sep; -int quoted; -{ - if (a == 0) - return((char *)NULL); - if (array_empty(a)) - return(savestring("")); - return (array_to_string_internal (element_forw(a->head), a->head, sep, quoted)); -} - -#if defined (INCLUDE_UNUSED) || defined (TEST_ARRAY) -/* - * Return an array consisting of elements in S, separated by SEP - */ -ARRAY * -array_from_string(s, sep) -char *s, *sep; -{ - ARRAY *a; - WORD_LIST *w; - - if (s == 0) - return((ARRAY *)NULL); - w = list_string (s, sep, 0); - if (w == 0) - return((ARRAY *)NULL); - a = array_from_word_list (w); - return (a); -} -#endif - -#if defined (TEST_ARRAY) -/* - * To make a running version, compile -DTEST_ARRAY and link with: - * xmalloc.o syntax.o lib/malloc/libmalloc.a lib/sh/libsh.a - */ -int interrupt_immediately = 0; - -int -signal_is_trapped(s) -int s; -{ - return 0; -} - -void -fatal_error(const char *s, ...) -{ - fprintf(stderr, "array_test: fatal memory error\n"); - abort(); -} - -void -programming_error(const char *s, ...) -{ - fprintf(stderr, "array_test: fatal programming error\n"); - abort(); -} - -WORD_DESC * -make_bare_word (s) -const char *s; -{ - WORD_DESC *w; - - w = (WORD_DESC *)xmalloc(sizeof(WORD_DESC)); - w->word = s ? savestring(s) : savestring (""); - w->flags = 0; - return w; -} - -WORD_LIST * -make_word_list(x, l) -WORD_DESC *x; -WORD_LIST *l; -{ - WORD_LIST *w; - - w = (WORD_LIST *)xmalloc(sizeof(WORD_LIST)); - w->word = x; - w->next = l; - return w; -} - -WORD_LIST * -list_string(s, t, i) -char *s, *t; -int i; -{ - char *r, *a; - WORD_LIST *wl; - - if (s == 0) - return (WORD_LIST *)NULL; - r = savestring(s); - wl = (WORD_LIST *)NULL; - a = strtok(r, t); - while (a) { - wl = make_word_list (make_bare_word(a), wl); - a = strtok((char *)NULL, t); - } - return (REVERSE_LIST (wl, WORD_LIST *)); -} - -GENERIC_LIST * -list_reverse (list) -GENERIC_LIST *list; -{ - register GENERIC_LIST *next, *prev; - - for (prev = 0; list; ) { - next = list->next; - list->next = prev; - prev = list; - list = next; - } - return prev; -} - -char * -pat_subst(s, t, u, i) -char *s, *t, *u; -int i; -{ - return ((char *)NULL); -} - -char * -quote_string(s) -char *s; -{ - return savestring(s); -} - -print_element(ae) -ARRAY_ELEMENT *ae; -{ - char lbuf[INT_STRLEN_BOUND (intmax_t) + 1]; - - printf("array[%s] = %s\n", - inttostr (element_index(ae), lbuf, sizeof (lbuf)), - element_value(ae)); -} - -print_array(a) -ARRAY *a; -{ - printf("\n"); - array_walk(a, print_element, (void *)NULL); -} - -main() -{ - ARRAY *a, *new_a, *copy_of_a; - ARRAY_ELEMENT *ae, *aew; - char *s; - - a = array_create(); - array_insert(a, 1, "one"); - array_insert(a, 7, "seven"); - array_insert(a, 4, "four"); - array_insert(a, 1029, "one thousand twenty-nine"); - array_insert(a, 12, "twelve"); - array_insert(a, 42, "forty-two"); - print_array(a); - s = array_to_string (a, " ", 0); - printf("s = %s\n", s); - copy_of_a = array_from_string(s, " "); - printf("copy_of_a:"); - print_array(copy_of_a); - array_dispose(copy_of_a); - printf("\n"); - free(s); - ae = array_remove(a, 4); - array_dispose_element(ae); - ae = array_remove(a, 1029); - array_dispose_element(ae); - array_insert(a, 16, "sixteen"); - print_array(a); - s = array_to_string (a, " ", 0); - printf("s = %s\n", s); - copy_of_a = array_from_string(s, " "); - printf("copy_of_a:"); - print_array(copy_of_a); - array_dispose(copy_of_a); - printf("\n"); - free(s); - array_insert(a, 2, "two"); - array_insert(a, 1029, "new one thousand twenty-nine"); - array_insert(a, 0, "zero"); - array_insert(a, 134, ""); - print_array(a); - s = array_to_string (a, ":", 0); - printf("s = %s\n", s); - copy_of_a = array_from_string(s, ":"); - printf("copy_of_a:"); - print_array(copy_of_a); - array_dispose(copy_of_a); - printf("\n"); - free(s); - new_a = array_copy(a); - print_array(new_a); - s = array_to_string (new_a, ":", 0); - printf("s = %s\n", s); - copy_of_a = array_from_string(s, ":"); - free(s); - printf("copy_of_a:"); - print_array(copy_of_a); - array_shift(copy_of_a, 2, AS_DISPOSE); - printf("copy_of_a shifted by two:"); - print_array(copy_of_a); - ae = array_shift(copy_of_a, 2, 0); - printf("copy_of_a shifted by two:"); - print_array(copy_of_a); - for ( ; ae; ) { - aew = element_forw(ae); - array_dispose_element(ae); - ae = aew; - } - array_rshift(copy_of_a, 1, (char *)0); - printf("copy_of_a rshift by 1:"); - print_array(copy_of_a); - array_rshift(copy_of_a, 2, "new element zero"); - printf("copy_of_a rshift again by 2 with new element zero:"); - print_array(copy_of_a); - s = array_to_assign(copy_of_a, 0); - printf("copy_of_a=%s\n", s); - free(s); - ae = array_shift(copy_of_a, array_num_elements(copy_of_a), 0); - for ( ; ae; ) { - aew = element_forw(ae); - array_dispose_element(ae); - ae = aew; - } - array_dispose(copy_of_a); - printf("\n"); - array_dispose(a); - array_dispose(new_a); -} - -#endif /* TEST_ARRAY */ -#endif /* ARRAY_VARS */ diff --git a/array.c~ b/array.c~ deleted file mode 100644 index f42012957..000000000 --- a/array.c~ +++ /dev/null @@ -1,1005 +0,0 @@ -/* - * array.c - functions to create, destroy, access, and manipulate arrays - * of strings. - * - * Arrays are sparse doubly-linked lists. An element's index is stored - * with it. - * - * Chet Ramey - * chet@ins.cwru.edu - */ - -/* Copyright (C) 1997-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 (ARRAY_VARS) - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include "bashansi.h" - -#include "shell.h" -#include "array.h" -#include "builtins/common.h" - -#define ADD_BEFORE(ae, new) \ - do { \ - ae->prev->next = new; \ - new->prev = ae->prev; \ - ae->prev = new; \ - new->next = ae; \ - } while(0) - -static char *array_to_string_internal __P((ARRAY_ELEMENT *, ARRAY_ELEMENT *, char *, int)); - -ARRAY * -array_create() -{ - ARRAY *r; - ARRAY_ELEMENT *head; - - r =(ARRAY *)xmalloc(sizeof(ARRAY)); - r->type = array_indexed; - r->max_index = -1; - r->num_elements = 0; - head = array_create_element(-1, (char *)NULL); /* dummy head */ - head->prev = head->next = head; - r->head = head; - return(r); -} - -void -array_flush (a) -ARRAY *a; -{ - register ARRAY_ELEMENT *r, *r1; - - if (a == 0) - return; - for (r = element_forw(a->head); r != a->head; ) { - r1 = element_forw(r); - array_dispose_element(r); - r = r1; - } - a->head->next = a->head->prev = a->head; - a->max_index = -1; - a->num_elements = 0; -} - -void -array_dispose(a) -ARRAY *a; -{ - if (a == 0) - return; - array_flush (a); - array_dispose_element(a->head); - free(a); -} - -ARRAY * -array_copy(a) -ARRAY *a; -{ - ARRAY *a1; - ARRAY_ELEMENT *ae, *new; - - if (a == 0) - return((ARRAY *) NULL); - a1 = array_create(); - a1->type = a->type; - a1->max_index = a->max_index; - a1->num_elements = a->num_elements; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - new = array_create_element(element_index(ae), element_value(ae)); - ADD_BEFORE(a1->head, new); - } - return(a1); -} - -/* - * Make and return a new array composed of the elements in array A from - * S to E, inclusive. - */ -ARRAY * -array_slice(array, s, e) -ARRAY *array; -ARRAY_ELEMENT *s, *e; -{ - ARRAY *a; - ARRAY_ELEMENT *p, *n; - int i; - arrayind_t mi; - - a = array_create (); - a->type = array->type; - - for (p = s, i = 0; p != e; p = element_forw(p), i++) { - n = array_create_element (element_index(p), element_value(p)); - ADD_BEFORE(a->head, n); - mi = element_index(n); - } - a->num_elements = i; - a->max_index = mi; - return a; -} - -/* - * Walk the array, calling FUNC once for each element, with the array - * element as the argument. - */ -void -array_walk(a, func, udata) -ARRAY *a; -sh_ae_map_func_t *func; -void *udata; -{ - register ARRAY_ELEMENT *ae; - - if (a == 0 || array_empty(a)) - return; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) - if ((*func)(ae, udata) < 0) - return; -} - -/* - * Shift the array A N elements to the left. Delete the first N elements - * and subtract N from the indices of the remaining elements. If FLAGS - * does not include AS_DISPOSE, this returns a singly-linked null-terminated - * list of elements so the caller can dispose of the chain. If FLAGS - * includes AS_DISPOSE, this function disposes of the shifted-out elements - * and returns NULL. - */ -ARRAY_ELEMENT * -array_shift(a, n, flags) -ARRAY *a; -int n, flags; -{ - register ARRAY_ELEMENT *ae, *ret; - register int i; - - if (a == 0 || array_empty(a) || n <= 0) - return ((ARRAY_ELEMENT *)NULL); - - for (i = 0, ret = ae = element_forw(a->head); ae != a->head && i < n; ae = element_forw(ae), i++) - ; - if (ae == a->head) { - /* Easy case; shifting out all of the elements */ - if (flags & AS_DISPOSE) { - array_flush (a); - return ((ARRAY_ELEMENT *)NULL); - } - for (ae = ret; element_forw(ae) != a->head; ae = element_forw(ae)) - ; - element_forw(ae) = (ARRAY_ELEMENT *)NULL; - a->head->next = a->head->prev = a->head; - a->max_index = -1; - a->num_elements = 0; - return ret; - } - /* - * ae now points to the list of elements we want to retain. - * ret points to the list we want to either destroy or return. - */ - ae->prev->next = (ARRAY_ELEMENT *)NULL; /* null-terminate RET */ - - a->head->next = ae; /* slice RET out of the array */ - ae->prev = a->head; - - for ( ; ae != a->head; ae = element_forw(ae)) - element_index(ae) -= n; /* renumber retained indices */ - - a->num_elements -= n; /* modify bookkeeping information */ - a->max_index -= n; - - if (flags & AS_DISPOSE) { - for (ae = ret; ae; ) { - ret = element_forw(ae); - array_dispose_element(ae); - ae = ret; - } - return ((ARRAY_ELEMENT *)NULL); - } - - return ret; -} - -/* - * Shift array A right N indices. If S is non-null, it becomes the value of - * the new element 0. Returns the number of elements in the array after the - * shift. - */ -int -array_rshift (a, n, s) -ARRAY *a; -int n; -char *s; -{ - register ARRAY_ELEMENT *ae, *new; - - if (a == 0 || (array_empty(a) && s == 0)) - return 0; - else if (n <= 0) - return (a->num_elements); - - ae = element_forw(a->head); - if (s) { - new = array_create_element(0, s); - ADD_BEFORE(ae, new); - a->num_elements++; - if (array_num_elements(a) == 1) /* array was empty */ - return 1; - } - - /* - * Renumber all elements in the array except the one we just added. - */ - for ( ; ae != a->head; ae = element_forw(ae)) - element_index(ae) += n; - - a->max_index = element_index(a->head->prev); - - return (a->num_elements); -} - -ARRAY_ELEMENT * -array_unshift_element(a) -ARRAY *a; -{ - return (array_shift (a, 1, 0)); -} - -int -array_shift_element(a, v) -ARRAY *a; -char *v; -{ - return (array_rshift (a, 1, v)); -} - -ARRAY * -array_quote(array) -ARRAY *array; -{ - ARRAY_ELEMENT *a; - char *t; - - if (array == 0 || array_head(array) == 0 || array_empty(array)) - return (ARRAY *)NULL; - for (a = element_forw(array->head); a != array->head; a = element_forw(a)) { - t = quote_string (a->value); - FREE(a->value); - a->value = t; - } - return array; -} - -ARRAY * -array_quote_escapes(array) -ARRAY *array; -{ - ARRAY_ELEMENT *a; - char *t; - - if (array == 0 || array_head(array) == 0 || array_empty(array)) - return (ARRAY *)NULL; - for (a = element_forw(array->head); a != array->head; a = element_forw(a)) { - t = quote_escapes (a->value); - FREE(a->value); - a->value = t; - } - return array; -} - -/* - * Return a string whose elements are the members of array A beginning at - * index START and spanning NELEM members. Null elements are counted. - * Since arrays are sparse, unset array elements are not counted. - */ -char * -array_subrange (a, start, nelem, starsub, quoted) -ARRAY *a; -arrayind_t start, nelem; -int starsub, quoted; -{ - ARRAY *a2; - ARRAY_ELEMENT *h, *p; - arrayind_t i; - char *ifs, *sep, *t; - - p = a ? array_head (a) : 0; - if (p == 0 || array_empty (a) || start > array_max_index(a)) - return ((char *)NULL); - - /* - * Find element with index START. If START corresponds to an unset - * element (arrays can be sparse), use the first element whose index - * is >= START. If START is < 0, we count START indices back from - * the end of A (not elements, even with sparse arrays -- START is an - * index). - */ - for (p = element_forw(p); p != array_head(a) && start > element_index(p); p = element_forw(p)) - ; - - if (p == a->head) - return ((char *)NULL); - - /* Starting at P, take NELEM elements, inclusive. */ - for (i = 0, h = p; p != a->head && i < nelem; i++, p = element_forw(p)) - ; - - a2 = array_slice(a, h, p); - - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - array_quote(a2); - else - array_quote_escapes(a2); - - if (starsub && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) { - /* ${array[*]} */ - sep = ifs_firstchar ((int *)NULL); - } else if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) { - /* ${array[@]} */ - sep = ifs_firstchar ((int *)NULL); - ifs = getifs (); - if (ifs == 0 || *ifs == 0) { - sep[0] = ' '; - sep[1] = '\0'; - } - } else { - sep = xmalloc (2); - sep[0] = ' '; - sep[1] = '\0'; - } - - t = array_to_string (a2, sep, 0); - array_dispose(a2); - free (sep); - - return t; -} - -char * -array_patsub (a, pat, rep, mflags) -ARRAY *a; -char *pat, *rep; -int mflags; -{ - ARRAY *a2; - ARRAY_ELEMENT *e; - char *t, *sifs; - - if (a == 0 || array_head(a) == 0 || array_empty(a)) - return ((char *)NULL); - - a2 = array_copy(a); - for (e = element_forw(a2->head); e != a2->head; e = element_forw(e)) { - t = pat_subst(element_value(e), pat, rep, mflags); - FREE(element_value(e)); - e->value = t; - } - - if (mflags & MATCH_QUOTED) - array_quote(a2); - else - array_quote_escapes(a2); - if (mflags & MATCH_STARSUB) { - sifs = ifs_firstchar((int *)NULL); - t = array_to_string (a2, sifs, 0); - free(sifs); - } else - t = array_to_string (a2, " ", 0); - array_dispose (a2); - - return t; -} - -char * -array_modcase (a, pat, modop, mflags) -ARRAY *a; -char *pat; -int modop; -int mflags; -{ - ARRAY *a2; - ARRAY_ELEMENT *e; - char *t, *ifs, sifs[2]; - - if (a == 0 || array_head(a) == 0 || array_empty(a)) - return ((char *)NULL); - - a2 = array_copy(a); - for (e = element_forw(a2->head); e != a2->head; e = element_forw(e)) { - t = sh_modcase(element_value(e), pat, modop); - FREE(element_value(e)); - e->value = t; - } - - if (mflags & MATCH_QUOTED) - array_quote(a2); - else - array_quote_escapes(a2); - if (mflags & MATCH_STARSUB) { - sifs = ifs_firstchar((int *)NULL); - t = array_to_string (a2, sifs, 0); - free(sifs); - } else - t = array_to_string (a2, " ", 0); - array_dispose (a2); - - return t; -} -/* - * Allocate and return a new array element with index INDEX and value - * VALUE. - */ -ARRAY_ELEMENT * -array_create_element(indx, value) -arrayind_t indx; -char *value; -{ - ARRAY_ELEMENT *r; - - r = (ARRAY_ELEMENT *)xmalloc(sizeof(ARRAY_ELEMENT)); - r->ind = indx; - r->value = value ? savestring(value) : (char *)NULL; - r->next = r->prev = (ARRAY_ELEMENT *) NULL; - return(r); -} - -#ifdef INCLUDE_UNUSED -ARRAY_ELEMENT * -array_copy_element(ae) -ARRAY_ELEMENT *ae; -{ - return(ae ? array_create_element(element_index(ae), element_value(ae)) - : (ARRAY_ELEMENT *) NULL); -} -#endif - -void -array_dispose_element(ae) -ARRAY_ELEMENT *ae; -{ - if (ae) { - FREE(ae->value); - free(ae); - } -} - -/* - * Add a new element with index I and value V to array A (a[i] = v). - */ -int -array_insert(a, i, v) -ARRAY *a; -arrayind_t i; -char *v; -{ - register ARRAY_ELEMENT *new, *ae; - - if (a == 0) - return(-1); - new = array_create_element(i, v); - if (i > array_max_index(a)) { - /* - * Hook onto the end. This also works for an empty array. - * Fast path for the common case of allocating arrays - * sequentially. - */ - ADD_BEFORE(a->head, new); - a->max_index = i; - a->num_elements++; - return(0); - } - /* - * Otherwise we search for the spot to insert it. - */ - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - if (element_index(ae) == i) { - /* - * Replacing an existing element. - */ - array_dispose_element(new); - free(element_value(ae)); - ae->value = v ? savestring(v) : (char *)NULL; - return(0); - } else if (element_index(ae) > i) { - ADD_BEFORE(ae, new); - a->num_elements++; - return(0); - } - } - return (-1); /* problem */ -} - -/* - * Delete the element with index I from array A and return it so the - * caller can dispose of it. - */ -ARRAY_ELEMENT * -array_remove(a, i) -ARRAY *a; -arrayind_t i; -{ - register ARRAY_ELEMENT *ae; - - if (a == 0 || array_empty(a)) - return((ARRAY_ELEMENT *) NULL); - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) - if (element_index(ae) == i) { - ae->next->prev = ae->prev; - ae->prev->next = ae->next; - a->num_elements--; - if (i == array_max_index(a)) - a->max_index = element_index(ae->prev); - return(ae); - } - return((ARRAY_ELEMENT *) NULL); -} - -/* - * Return the value of a[i]. - */ -char * -array_reference(a, i) -ARRAY *a; -arrayind_t i; -{ - register ARRAY_ELEMENT *ae; - - if (a == 0 || array_empty(a)) - return((char *) NULL); - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) - if (element_index(ae) == i) - return(element_value(ae)); - return((char *) NULL); -} - -/* Convenience routines for the shell to translate to and from the form used - by the rest of the code. */ - -WORD_LIST * -array_to_word_list(a) -ARRAY *a; -{ - WORD_LIST *list; - ARRAY_ELEMENT *ae; - - if (a == 0 || array_empty(a)) - return((WORD_LIST *)NULL); - list = (WORD_LIST *)NULL; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) - list = make_word_list (make_bare_word(element_value(ae)), list); - return (REVERSE_LIST(list, WORD_LIST *)); -} - -ARRAY * -array_from_word_list (list) -WORD_LIST *list; -{ - ARRAY *a; - - if (list == 0) - return((ARRAY *)NULL); - a = array_create(); - return (array_assign_list (a, list)); -} - -WORD_LIST * -array_keys_to_word_list(a) -ARRAY *a; -{ - WORD_LIST *list; - ARRAY_ELEMENT *ae; - char *t; - - if (a == 0 || array_empty(a)) - return((WORD_LIST *)NULL); - list = (WORD_LIST *)NULL; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - t = itos(element_index(ae)); - list = make_word_list (make_bare_word(t), list); - free(t); - } - return (REVERSE_LIST(list, WORD_LIST *)); -} - -ARRAY * -array_assign_list (array, list) -ARRAY *array; -WORD_LIST *list; -{ - register WORD_LIST *l; - register arrayind_t i; - - for (l = list, i = 0; l; l = l->next, i++) - array_insert(array, i, l->word->word); - return array; -} - -char ** -array_to_argv (a) -ARRAY *a; -{ - char **ret, *t; - int i; - ARRAY_ELEMENT *ae; - - if (a == 0 || array_empty(a)) - return ((char **)NULL); - ret = strvec_create (array_num_elements (a) + 1); - i = 0; - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - t = element_value (ae); - ret[i++] = t ? savestring (t) : (char *)NULL; - } - ret[i] = (char *)NULL; - return (ret); -} - -/* - * Return a string that is the concatenation of the elements in A from START - * to END, separated by SEP. - */ -static char * -array_to_string_internal (start, end, sep, quoted) -ARRAY_ELEMENT *start, *end; -char *sep; -int quoted; -{ - char *result, *t; - ARRAY_ELEMENT *ae; - int slen, rsize, rlen, reg; - - if (start == end) /* XXX - should not happen */ - return ((char *)NULL); - - slen = strlen(sep); - result = NULL; - for (rsize = rlen = 0, ae = start; ae != end; ae = element_forw(ae)) { - if (rsize == 0) - result = (char *)xmalloc (rsize = 64); - if (element_value(ae)) { - t = quoted ? quote_string(element_value(ae)) : element_value(ae); - reg = strlen(t); - RESIZE_MALLOCED_BUFFER (result, rlen, (reg + slen + 2), - rsize, rsize); - strcpy(result + rlen, t); - rlen += reg; - if (quoted && t) - free(t); - /* - * Add a separator only after non-null elements. - */ - if (element_forw(ae) != end) { - strcpy(result + rlen, sep); - rlen += slen; - } - } - } - if (result) - result[rlen] = '\0'; /* XXX */ - return(result); -} - -char * -array_to_assign (a, quoted) -ARRAY *a; -int quoted; -{ - char *result, *valstr, *is; - char indstr[INT_STRLEN_BOUND(intmax_t) + 1]; - ARRAY_ELEMENT *ae; - int rsize, rlen, elen; - - if (a == 0 || array_empty (a)) - return((char *)NULL); - - result = (char *)xmalloc (rsize = 128); - result[0] = '('; - rlen = 1; - - for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { - is = inttostr (element_index(ae), indstr, sizeof(indstr)); - valstr = element_value (ae) ? sh_double_quote (element_value(ae)) - : (char *)NULL; - elen = STRLEN (is) + 8 + STRLEN (valstr); - RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize); - - result[rlen++] = '['; - strcpy (result + rlen, is); - rlen += STRLEN (is); - result[rlen++] = ']'; - result[rlen++] = '='; - if (valstr) { - strcpy (result + rlen, valstr); - rlen += STRLEN (valstr); - } - - if (element_forw(ae) != a->head) - result[rlen++] = ' '; - - FREE (valstr); - } - RESIZE_MALLOCED_BUFFER (result, rlen, 1, rsize, 8); - result[rlen++] = ')'; - result[rlen] = '\0'; - if (quoted) { - /* This is not as efficient as it could be... */ - valstr = sh_single_quote (result); - free (result); - result = valstr; - } - return(result); -} - -char * -array_to_string (a, sep, quoted) -ARRAY *a; -char *sep; -int quoted; -{ - if (a == 0) - return((char *)NULL); - if (array_empty(a)) - return(savestring("")); - return (array_to_string_internal (element_forw(a->head), a->head, sep, quoted)); -} - -#if defined (INCLUDE_UNUSED) || defined (TEST_ARRAY) -/* - * Return an array consisting of elements in S, separated by SEP - */ -ARRAY * -array_from_string(s, sep) -char *s, *sep; -{ - ARRAY *a; - WORD_LIST *w; - - if (s == 0) - return((ARRAY *)NULL); - w = list_string (s, sep, 0); - if (w == 0) - return((ARRAY *)NULL); - a = array_from_word_list (w); - return (a); -} -#endif - -#if defined (TEST_ARRAY) -/* - * To make a running version, compile -DTEST_ARRAY and link with: - * xmalloc.o syntax.o lib/malloc/libmalloc.a lib/sh/libsh.a - */ -int interrupt_immediately = 0; - -int -signal_is_trapped(s) -int s; -{ - return 0; -} - -void -fatal_error(const char *s, ...) -{ - fprintf(stderr, "array_test: fatal memory error\n"); - abort(); -} - -void -programming_error(const char *s, ...) -{ - fprintf(stderr, "array_test: fatal programming error\n"); - abort(); -} - -WORD_DESC * -make_bare_word (s) -const char *s; -{ - WORD_DESC *w; - - w = (WORD_DESC *)xmalloc(sizeof(WORD_DESC)); - w->word = s ? savestring(s) : savestring (""); - w->flags = 0; - return w; -} - -WORD_LIST * -make_word_list(x, l) -WORD_DESC *x; -WORD_LIST *l; -{ - WORD_LIST *w; - - w = (WORD_LIST *)xmalloc(sizeof(WORD_LIST)); - w->word = x; - w->next = l; - return w; -} - -WORD_LIST * -list_string(s, t, i) -char *s, *t; -int i; -{ - char *r, *a; - WORD_LIST *wl; - - if (s == 0) - return (WORD_LIST *)NULL; - r = savestring(s); - wl = (WORD_LIST *)NULL; - a = strtok(r, t); - while (a) { - wl = make_word_list (make_bare_word(a), wl); - a = strtok((char *)NULL, t); - } - return (REVERSE_LIST (wl, WORD_LIST *)); -} - -GENERIC_LIST * -list_reverse (list) -GENERIC_LIST *list; -{ - register GENERIC_LIST *next, *prev; - - for (prev = 0; list; ) { - next = list->next; - list->next = prev; - prev = list; - list = next; - } - return prev; -} - -char * -pat_subst(s, t, u, i) -char *s, *t, *u; -int i; -{ - return ((char *)NULL); -} - -char * -quote_string(s) -char *s; -{ - return savestring(s); -} - -print_element(ae) -ARRAY_ELEMENT *ae; -{ - char lbuf[INT_STRLEN_BOUND (intmax_t) + 1]; - - printf("array[%s] = %s\n", - inttostr (element_index(ae), lbuf, sizeof (lbuf)), - element_value(ae)); -} - -print_array(a) -ARRAY *a; -{ - printf("\n"); - array_walk(a, print_element, (void *)NULL); -} - -main() -{ - ARRAY *a, *new_a, *copy_of_a; - ARRAY_ELEMENT *ae, *aew; - char *s; - - a = array_create(); - array_insert(a, 1, "one"); - array_insert(a, 7, "seven"); - array_insert(a, 4, "four"); - array_insert(a, 1029, "one thousand twenty-nine"); - array_insert(a, 12, "twelve"); - array_insert(a, 42, "forty-two"); - print_array(a); - s = array_to_string (a, " ", 0); - printf("s = %s\n", s); - copy_of_a = array_from_string(s, " "); - printf("copy_of_a:"); - print_array(copy_of_a); - array_dispose(copy_of_a); - printf("\n"); - free(s); - ae = array_remove(a, 4); - array_dispose_element(ae); - ae = array_remove(a, 1029); - array_dispose_element(ae); - array_insert(a, 16, "sixteen"); - print_array(a); - s = array_to_string (a, " ", 0); - printf("s = %s\n", s); - copy_of_a = array_from_string(s, " "); - printf("copy_of_a:"); - print_array(copy_of_a); - array_dispose(copy_of_a); - printf("\n"); - free(s); - array_insert(a, 2, "two"); - array_insert(a, 1029, "new one thousand twenty-nine"); - array_insert(a, 0, "zero"); - array_insert(a, 134, ""); - print_array(a); - s = array_to_string (a, ":", 0); - printf("s = %s\n", s); - copy_of_a = array_from_string(s, ":"); - printf("copy_of_a:"); - print_array(copy_of_a); - array_dispose(copy_of_a); - printf("\n"); - free(s); - new_a = array_copy(a); - print_array(new_a); - s = array_to_string (new_a, ":", 0); - printf("s = %s\n", s); - copy_of_a = array_from_string(s, ":"); - free(s); - printf("copy_of_a:"); - print_array(copy_of_a); - array_shift(copy_of_a, 2, AS_DISPOSE); - printf("copy_of_a shifted by two:"); - print_array(copy_of_a); - ae = array_shift(copy_of_a, 2, 0); - printf("copy_of_a shifted by two:"); - print_array(copy_of_a); - for ( ; ae; ) { - aew = element_forw(ae); - array_dispose_element(ae); - ae = aew; - } - array_rshift(copy_of_a, 1, (char *)0); - printf("copy_of_a rshift by 1:"); - print_array(copy_of_a); - array_rshift(copy_of_a, 2, "new element zero"); - printf("copy_of_a rshift again by 2 with new element zero:"); - print_array(copy_of_a); - s = array_to_assign(copy_of_a, 0); - printf("copy_of_a=%s\n", s); - free(s); - ae = array_shift(copy_of_a, array_num_elements(copy_of_a), 0); - for ( ; ae; ) { - aew = element_forw(ae); - array_dispose_element(ae); - ae = aew; - } - array_dispose(copy_of_a); - printf("\n"); - array_dispose(a); - array_dispose(new_a); -} - -#endif /* TEST_ARRAY */ -#endif /* ARRAY_VARS */ diff --git a/array.h~ b/array.h~ deleted file mode 100644 index 687bd3c9b..000000000 --- a/array.h~ +++ /dev/null @@ -1,113 +0,0 @@ -/* array.h -- definitions for the interface exported by array.c that allows - the rest of the shell to manipulate array variables. */ - -/* Copyright (C) 1997 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 _ARRAY_H_ -#define _ARRAY_H_ - -#include "stdc.h" - -typedef intmax_t arrayind_t; - -enum atype {array_indexed, array_assoc}; - -typedef struct array { - enum atype type; - arrayind_t max_index, num_elements; - struct array_element *head; -} ARRAY; - -typedef struct array_element { - arrayind_t ind; - char *value; - struct array_element *next, *prev; -} ARRAY_ELEMENT; - -typedef int sh_ae_map_func_t __P((ARRAY_ELEMENT *, void *)); - -/* Basic operations on entire arrays */ -extern ARRAY *array_create __P((void)); -extern void array_flush __P((ARRAY *)); -extern void array_dispose __P((ARRAY *)); -extern ARRAY *array_copy __P((ARRAY *)); -extern ARRAY *array_slice __P((ARRAY *, ARRAY_ELEMENT *, ARRAY_ELEMENT *)); -extern void array_walk __P((ARRAY *, sh_ae_map_func_t *, void *)); - -extern ARRAY_ELEMENT *array_shift __P((ARRAY *, int, int)); -extern int array_rshift __P((ARRAY *, int, char *)); -extern ARRAY_ELEMENT *array_unshift_element __P((ARRAY *)); -extern int array_shift_element __P((ARRAY *, char *)); -extern ARRAY *array_quote __P((ARRAY *)); -extern ARRAY *array_quote_escapes __P((ARRAY *)); - -extern char *array_subrange __P((ARRAY *, arrayind_t, arrayind_t, int, int)); -extern char *array_patsub __P((ARRAY *, char *, char *, int)); -extern char *array_modcase __P((ARRAY *, char *, int, int)); - -/* Basic operations on array elements. */ -extern ARRAY_ELEMENT *array_create_element __P((arrayind_t, char *)); -extern ARRAY_ELEMENT *array_copy_element __P((ARRAY_ELEMENT *)); -extern void array_dispose_element __P((ARRAY_ELEMENT *)); - -extern int array_insert __P((ARRAY *, arrayind_t, char *)); -extern ARRAY_ELEMENT *array_remove __P((ARRAY *, arrayind_t)); -extern char *array_reference __P((ARRAY *, arrayind_t)); - -/* Converting to and from arrays */ -extern WORD_LIST *array_to_word_list __P((ARRAY *)); -extern ARRAY *array_from_word_list __P((WORD_LIST *)); -extern WORD_LIST *array_keys_to_word_list __P((ARRAY *)); - -extern ARRAY *array_assign_list __P((ARRAY *, WORD_LIST *)); - -extern char **array_to_argv __P((ARRAY *)); - -extern char *array_to_assign __P((ARRAY *, int)); -extern char *array_to_string __P((ARRAY *, char *, int)); -extern ARRAY *array_from_string __P((char *, char *)); - -/* Flags for array_shift */ -#define AS_DISPOSE 0x01 - -#define array_num_elements(a) ((a)->num_elements) -#define array_max_index(a) ((a)->max_index) -#define array_head(a) ((a)->head) -#define array_empty(a) ((a)->num_elements == 0) - -#define element_value(ae) ((ae)->value) -#define element_index(ae) ((ae)->ind) -#define element_forw(ae) ((ae)->next) -#define element_back(ae) ((ae)->prev) - -/* Convenience */ -#define array_push(a,v) \ - do { array_rshift ((a), 1, (v)); } while (0) -#define array_pop(a) \ - do { array_dispose_element (array_shift ((a), 1, 0)); } while (0) - -#define GET_ARRAY_FROM_VAR(n, v, a) \ - do { \ - (v) = find_variable (n); \ - (a) = ((v) && array_p ((v))) ? array_cell (v) : (ARRAY *)0; \ - } while (0) - -#define ALL_ELEMENT_SUB(c) ((c) == '@' || (c) == '*') - -#endif /* _ARRAY_H_ */ diff --git a/arrayfunc.c~ b/arrayfunc.c~ deleted file mode 100644 index 2fa2dba51..000000000 --- a/arrayfunc.c~ +++ /dev/null @@ -1,1054 +0,0 @@ -/* arrayfunc.c -- High-level array functions used by other parts of the shell. */ - -/* Copyright (C) 2001-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include "config.h" - -#if defined (ARRAY_VARS) - -#if defined (HAVE_UNISTD_H) -# include -#endif -#include - -#include "bashintl.h" - -#include "shell.h" - -#include "shmbutil.h" - -#include "builtins/common.h" - -extern char *this_command_name; -extern int last_command_exit_value; -extern int array_needs_making; - -static SHELL_VAR *bind_array_var_internal __P((SHELL_VAR *, arrayind_t, char *, char *, int)); - -static char *quote_assign __P((const char *)); -static void quote_array_assignment_chars __P((WORD_LIST *)); -static char *array_value_internal __P((char *, int, int, int *)); - -/* Standard error message to use when encountering an invalid array subscript */ -const char * const bash_badsub_errmsg = N_("bad array subscript"); - -/* **************************************************************** */ -/* */ -/* Functions to manipulate array variables and perform assignments */ -/* */ -/* **************************************************************** */ - -/* Convert a shell variable to an array variable. The original value is - saved as array[0]. */ -SHELL_VAR * -convert_var_to_array (var) - SHELL_VAR *var; -{ - char *oldval; - ARRAY *array; - - oldval = value_cell (var); - array = array_create (); - if (oldval) - array_insert (array, 0, oldval); - - FREE (value_cell (var)); - var_setarray (var, array); - - /* these aren't valid anymore */ - var->dynamic_value = (sh_var_value_func_t *)NULL; - var->assign_func = (sh_var_assign_func_t *)NULL; - - INVALIDATE_EXPORTSTR (var); - if (exported_p (var)) - array_needs_making++; - - VSETATTR (var, att_array); - VUNSETATTR (var, att_invisible); - - return var; -} - -/* Convert a shell variable to an array variable. The original value is - saved as array[0]. */ -SHELL_VAR * -convert_var_to_assoc (var) - SHELL_VAR *var; -{ - char *oldval; - HASH_TABLE *hash; - - oldval = value_cell (var); - hash = assoc_create (0); - if (oldval) - assoc_insert (hash, "0", oldval); - - FREE (value_cell (var)); - var_setassoc (var, hash); - - /* these aren't valid anymore */ - var->dynamic_value = (sh_var_value_func_t *)NULL; - var->assign_func = (sh_var_assign_func_t *)NULL; - - INVALIDATE_EXPORTSTR (var); - if (exported_p (var)) - array_needs_making++; - - VSETATTR (var, att_assoc); - VUNSETATTR (var, att_invisible); - - return var; -} - -static SHELL_VAR * -bind_array_var_internal (entry, ind, key, value, flags) - SHELL_VAR *entry; - arrayind_t ind; - char *key; - char *value; - int flags; -{ - SHELL_VAR *dentry; - char *newval; - - /* If we're appending, we need the old value of the array reference, so - fake out make_variable_value with a dummy SHELL_VAR */ - if (flags & ASS_APPEND) - { - dentry = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR)); - dentry->name = savestring (entry->name); - if (assoc_p (entry)) - newval = assoc_reference (assoc_cell (entry), key); - else - newval = array_reference (array_cell (entry), ind); - if (newval) - dentry->value = savestring (newval); - else - { - dentry->value = (char *)xmalloc (1); - dentry->value[0] = '\0'; - } - dentry->exportstr = 0; - dentry->attributes = entry->attributes & ~(att_array|att_assoc|att_exported); - /* Leave the rest of the members uninitialized; the code doesn't look - at them. */ - newval = make_variable_value (dentry, value, flags); - dispose_variable (dentry); - } - else - newval = make_variable_value (entry, value, flags); - - if (entry->assign_func) - (*entry->assign_func) (entry, newval, ind, key); - else if (assoc_p (entry)) - assoc_insert (assoc_cell (entry), key, newval); - else - array_insert (array_cell (entry), ind, newval); - FREE (newval); - - return (entry); -} - -/* Perform an array assignment name[ind]=value. If NAME already exists and - is not an array, and IND is 0, perform name=value instead. If NAME exists - and is not an array, and IND is not 0, convert it into an array with the - existing value as name[0]. - - If NAME does not exist, just create an array variable, no matter what - IND's value may be. */ -SHELL_VAR * -bind_array_variable (name, ind, value, flags) - char *name; - arrayind_t ind; - char *value; - int flags; -{ - SHELL_VAR *entry; - - entry = var_lookup (name, shell_variables); - - if (entry == (SHELL_VAR *) 0) - entry = make_new_array_variable (name); - else if (readonly_p (entry) || noassign_p (entry)) - { - if (readonly_p (entry)) - err_readonly (name); - return (entry); - } - else if (array_p (entry) == 0) - entry = convert_var_to_array (entry); - - /* ENTRY is an array variable, and ARRAY points to the value. */ - return (bind_array_var_internal (entry, ind, 0, value, flags)); -} - -SHELL_VAR * -bind_array_element (entry, ind, value, flags) - SHELL_VAR *entry; - arrayind_t ind; - char *value; - int flags; -{ - return (bind_array_var_internal (entry, ind, 0, value, flags)); -} - -SHELL_VAR * -bind_assoc_variable (entry, name, key, value, flags) - SHELL_VAR *entry; - char *name; - char *key; - char *value; - int flags; -{ - SHELL_VAR *dentry; - char *newval; - - if (readonly_p (entry) || noassign_p (entry)) - { - if (readonly_p (entry)) - err_readonly (name); - return (entry); - } - - return (bind_array_var_internal (entry, 0, key, value, flags)); -} - -/* Parse NAME, a lhs of an assignment statement of the form v[s], and - assign VALUE to that array element by calling bind_array_variable(). */ -SHELL_VAR * -assign_array_element (name, value, flags) - char *name, *value; - int flags; -{ - char *sub, *vname, *akey; - arrayind_t ind; - int sublen; - SHELL_VAR *entry; - - vname = array_variable_name (name, &sub, &sublen); - - if (vname == 0) - return ((SHELL_VAR *)NULL); - - if ((ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']') || (sublen <= 1)) - { - free (vname); - err_badarraysub (name); - return ((SHELL_VAR *)NULL); - } - - entry = find_variable (vname); - - if (entry && assoc_p (entry)) - { - sub[sublen-1] = '\0'; - akey = expand_assignment_string_to_string (sub, 0); /* [ */ - sub[sublen-1] = ']'; - if (akey == 0 || *akey == 0) - { - free (vname); - err_badarraysub (name); - return ((SHELL_VAR *)NULL); - } - entry = bind_assoc_variable (entry, vname, akey, value, flags); - } - else - { - ind = array_expand_index (sub, sublen); - if (ind < 0) - { - free (vname); - err_badarraysub (name); - return ((SHELL_VAR *)NULL); - } - entry = bind_array_variable (vname, ind, value, flags); - } - - free (vname); - return (entry); -} - -/* Find the array variable corresponding to NAME. If there is no variable, - create a new array variable. If the variable exists but is not an array, - convert it to an indexed array. If FLAGS&1 is non-zero, an existing - variable is checked for the readonly or noassign attribute in preparation - for assignment (e.g., by the `read' builtin). If FLAGS&2 is non-zero, we - create an associative array. */ -SHELL_VAR * -find_or_make_array_variable (name, flags) - char *name; - int flags; -{ - SHELL_VAR *var; - - var = find_variable (name); - - if (var == 0) - var = (flags & 2) ? make_new_assoc_variable (name) : make_new_array_variable (name); - else if ((flags & 1) && (readonly_p (var) || noassign_p (var))) - { - if (readonly_p (var)) - err_readonly (name); - return ((SHELL_VAR *)NULL); - } - else if ((flags & 2) && array_p (var)) - { - report_error (_("%s: cannot convert indexed to associative array"), name); - return ((SHELL_VAR *)NULL); - } - else if (array_p (var) == 0 && assoc_p (var) == 0) - var = convert_var_to_array (var); - - return (var); -} - -/* Perform a compound assignment statement for array NAME, where VALUE is - the text between the parens: NAME=( VALUE ) */ -SHELL_VAR * -assign_array_from_string (name, value, flags) - char *name, *value; - int flags; -{ - SHELL_VAR *var; - int vflags; - - vflags = 1; - if (flags & ASS_MKASSOC) - vflags |= 2; - - var = find_or_make_array_variable (name, vflags); - if (var == 0) - return ((SHELL_VAR *)NULL); - - return (assign_array_var_from_string (var, value, flags)); -} - -/* Sequentially assign the indices of indexed array variable VAR from the - words in LIST. */ -SHELL_VAR * -assign_array_var_from_word_list (var, list, flags) - SHELL_VAR *var; - WORD_LIST *list; - int flags; -{ - register arrayind_t i; - register WORD_LIST *l; - ARRAY *a; - - a = array_cell (var); - i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0; - - for (l = list; l; l = l->next, i++) - if (var->assign_func) - (*var->assign_func) (var, l->word->word, i, 0); - else - array_insert (a, i, l->word->word); - return var; -} - -WORD_LIST * -expand_compound_array_assignment (var, value, flags) - SHELL_VAR *var; - char *value; - int flags; -{ - WORD_LIST *list, *nlist; - char *val; - int ni; - - /* I don't believe this condition is ever true any more. */ - if (*value == '(') /*)*/ - { - ni = 1; - val = extract_array_assignment_list (value, &ni); - if (val == 0) - return (WORD_LIST *)NULL; - } - else - val = value; - - /* Expand the value string into a list of words, performing all the - shell expansions including pathname generation and word splitting. */ - /* First we split the string on whitespace, using the shell parser - (ksh93 seems to do this). */ - list = parse_string_to_word_list (val, 1, "array assign"); - - /* If we're using [subscript]=value, we need to quote each [ and ] to - prevent unwanted filename expansion. */ - if (list) - quote_array_assignment_chars (list); - - /* Now that we've split it, perform the shell expansions on each - word in the list. */ - nlist = list ? expand_words_no_vars (list) : (WORD_LIST *)NULL; - - dispose_words (list); - - if (val != value) - free (val); - - return nlist; -} - -void -assign_compound_array_list (var, nlist, flags) - SHELL_VAR *var; - WORD_LIST *nlist; - int flags; -{ - ARRAY *a; - HASH_TABLE *h; - WORD_LIST *list; - char *w, *val, *nval; - int len, iflags; - arrayind_t ind, last_ind; - char *akey; - - a = (var && array_p (var)) ? array_cell (var) : (ARRAY *)0; - h = (var && assoc_p (var)) ? assoc_cell (var) : (HASH_TABLE *)0; - - akey = (char *)0; - ind = 0; - - /* Now that we are ready to assign values to the array, kill the existing - value. */ - if ((flags & ASS_APPEND) == 0) - { - if (array_p (var) && a) - array_flush (a); - else if (assoc_p (var) && h) - assoc_flush (h); - } - - last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0; - - for (list = nlist; list; list = list->next) - { - iflags = flags; - w = list->word->word; - - /* We have a word of the form [ind]=value */ - if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[') - { - len = skipsubscript (w, 0); - - /* XXX - changes for `+=' */ - if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '='))) - { - if (assoc_p (var)) - { - err_badarraysub (w); - continue; - } - nval = make_variable_value (var, w, flags); - if (var->assign_func) - (*var->assign_func) (var, nval, last_ind, 0); - else - array_insert (a, last_ind, nval); - FREE (nval); - last_ind++; - continue; - } - - if (len == 1) - { - err_badarraysub (w); - continue; - } - - if (ALL_ELEMENT_SUB (w[1]) && len == 2) - { - if (assoc_p (var)) - report_error (_("%s: invalid associative array key"), w); - else - report_error (_("%s: cannot assign to non-numeric index"), w); - continue; - } - - if (array_p (var)) - { - ind = array_expand_index (w + 1, len); - if (ind < 0) - { - err_badarraysub (w); - continue; - } - - last_ind = ind; - } - else if (assoc_p (var)) - { - akey = substring (w, 1, len); - if (akey == 0 || *akey == 0) - { - err_badarraysub (w); - continue; - } - } - - /* XXX - changes for `+=' -- just accept the syntax. ksh93 doesn't do this */ - if (w[len + 1] == '+' && w[len + 2] == '=') - { - iflags |= ASS_APPEND; - val = w + len + 3; - } - else - val = w + len + 2; - } - else if (assoc_p (var)) - { - report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w); - continue; - } - else /* No [ind]=value, just a stray `=' */ - { - ind = last_ind; - val = w; - } - - if (integer_p (var)) - this_command_name = (char *)NULL; /* no command name for errors */ - bind_array_var_internal (var, ind, akey, val, iflags); - last_ind++; - } -} - -/* Perform a compound array assignment: VAR->name=( VALUE ). The - VALUE has already had the parentheses stripped. */ -SHELL_VAR * -assign_array_var_from_string (var, value, flags) - SHELL_VAR *var; - char *value; - int flags; -{ - WORD_LIST *nlist; - - if (value == 0) - return var; - - nlist = expand_compound_array_assignment (var, value, flags); - assign_compound_array_list (var, nlist, flags); - - if (nlist) - dispose_words (nlist); - return (var); -} - -/* Quote globbing chars and characters in $IFS before the `=' in an assignment - statement (usually a compound array assignment) to protect them from - unwanted filename expansion or word splitting. */ -static char * -quote_assign (string) - const char *string; -{ - size_t slen; - int saw_eq; - char *temp, *t; - const char *s, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - t = temp = (char *)xmalloc (slen * 2 + 1); - saw_eq = 0; - for (s = string; *s; ) - { - if (*s == '=') - saw_eq = 1; - if (saw_eq == 0 && (glob_char_p (s) || isifs (*s))) - *t++ = '\\'; - - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return temp; -} - -/* For each word in a compound array assignment, if the word looks like - [ind]=value, quote globbing chars and characters in $IFS before the `='. */ -static void -quote_array_assignment_chars (list) - WORD_LIST *list; -{ - char *nword; - WORD_LIST *l; - - for (l = list; l; l = l->next) - { - if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0') - continue; /* should not happen, but just in case... */ - /* Don't bother if it doesn't look like [ind]=value */ - if (l->word->word[0] != '[' || xstrchr (l->word->word, '=') == 0) /* ] */ - continue; - nword = quote_assign (l->word->word); - free (l->word->word); - l->word->word = nword; - } -} - -/* This function assumes s[i] == '['; returns with s[ret] == ']' if - an array subscript is correctly parsed. */ -int -skipsubscript (s, i) - const char *s; - int i; -{ - int count, c; -#if defined (HANDLE_MULTIBYTE) - mbstate_t state, state_bak; - size_t slength, mblength; -#endif - -#if defined (HANDLE_MULTIBYTE) - memset (&state, '\0', sizeof (mbstate_t)); - slength = strlen (s + i); -#endif - - count = 1; - while (count) - { - /* Advance one (possibly multibyte) character in S starting at I. */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1) - { - state_bak = state; - mblength = mbrlen (s + i, slength, &state); - - if (MB_INVALIDCH (mblength)) - { - state = state_bak; - i++; - slength--; - } - else if (MB_NULLWCH (mblength)) - return i; - else - { - i += mblength; - slength -= mblength; - } - } - else -#endif - ++i; - - c = s[i]; - - if (c == 0) - break; - else if (c == '[') - count++; - else if (c == ']') - count--; - } - - return i; -} - -/* This function is called with SUB pointing to just after the beginning - `[' of an array subscript and removes the array element to which SUB - expands from array VAR. A subscript of `*' or `@' unsets the array. */ -int -unbind_array_element (var, sub) - SHELL_VAR *var; - char *sub; -{ - int len; - arrayind_t ind; - char *akey; - ARRAY_ELEMENT *ae; - - len = skipsubscript (sub, 0); - if (sub[len] != ']' || len == 0) - { - builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg)); - return -1; - } - sub[len] = '\0'; - - if (ALL_ELEMENT_SUB (sub[0]) && sub[1] == 0) - { - unbind_variable (var->name); - return (0); - } - - if (assoc_p (var)) - { - akey = expand_assignment_string_to_string (sub, 0); /* [ */ - if (akey == 0 || *akey == 0) - { - builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg)); - return -1; - } - assoc_remove (assoc_cell (var), akey); - } - else - { - ind = array_expand_index (sub, len+1); - if (ind < 0) - { - builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg)); - return -1; - } - ae = array_remove (array_cell (var), ind); - if (ae) - array_dispose_element (ae); - } - - return 0; -} - -/* Format and output an array assignment in compound form VAR=(VALUES), - suitable for re-use as input. */ -void -print_array_assignment (var, quoted) - SHELL_VAR *var; - int quoted; -{ - char *vstr; - - vstr = array_to_assign (array_cell (var), quoted); - - if (vstr == 0) - printf ("%s=%s\n", var->name, quoted ? "'()'" : "()"); - else - { - printf ("%s=%s\n", var->name, vstr); - free (vstr); - } -} - -/* Format and output an associative array assignment in compound form - VAR=(VALUES), suitable for re-use as input. */ -void -print_assoc_assignment (var, quoted) - SHELL_VAR *var; - int quoted; -{ - char *vstr; - - vstr = assoc_to_assign (assoc_cell (var), quoted); - - if (vstr == 0) - printf ("%s=%s\n", var->name, quoted ? "'()'" : "()"); - else - { - printf ("%s=%s\n", var->name, vstr); - free (vstr); - } -} - -/***********************************************************************/ -/* */ -/* Utility functions to manage arrays and their contents for expansion */ -/* */ -/***********************************************************************/ - -/* Return 1 if NAME is a properly-formed array reference v[sub]. */ -int -valid_array_reference (name) - char *name; -{ - char *t; - int r, len; - - t = xstrchr (name, '['); /* ] */ - if (t) - { - *t = '\0'; - r = legal_identifier (name); - *t = '['; - if (r == 0) - return 0; - /* Check for a properly-terminated non-blank subscript. */ - len = skipsubscript (t, 0); - if (t[len] != ']' || len == 1) - return 0; - for (r = 1; r < len; r++) - if (whitespace (t[r]) == 0) - return 1; - return 0; - } - return 0; -} - -/* Expand the array index beginning at S and extending LEN characters. */ -arrayind_t -array_expand_index (s, len) - char *s; - int len; -{ - char *exp, *t; - int expok; - arrayind_t val; - - exp = (char *)xmalloc (len); - strncpy (exp, s, len - 1); - exp[len - 1] = '\0'; - t = expand_arith_string (exp, 0); - this_command_name = (char *)NULL; - val = evalexp (t, &expok); - free (t); - free (exp); - if (expok == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - - top_level_cleanup (); - jump_to_top_level (DISCARD); - } - return val; -} - -/* Return the name of the variable specified by S without any subscript. - If SUBP is non-null, return a pointer to the start of the subscript - in *SUBP. If LENP is non-null, the length of the subscript is returned - in *LENP. This returns newly-allocated memory. */ -char * -array_variable_name (s, subp, lenp) - char *s, **subp; - int *lenp; -{ - char *t, *ret; - int ind, ni; - - t = xstrchr (s, '['); - if (t == 0) - { - if (subp) - *subp = t; - if (lenp) - *lenp = 0; - return ((char *)NULL); - } - ind = t - s; - ni = skipsubscript (s, ind); - if (ni <= ind + 1 || s[ni] != ']') - { - err_badarraysub (s); - if (subp) - *subp = t; - if (lenp) - *lenp = 0; - return ((char *)NULL); - } - - *t = '\0'; - ret = savestring (s); - *t++ = '['; /* ] */ - - if (subp) - *subp = t; - if (lenp) - *lenp = ni - ind; - - return ret; -} - -/* Return the variable specified by S without any subscript. If SUBP is - non-null, return a pointer to the start of the subscript in *SUBP. - If LENP is non-null, the length of the subscript is returned in *LENP. */ -SHELL_VAR * -array_variable_part (s, subp, lenp) - char *s, **subp; - int *lenp; -{ - char *t; - SHELL_VAR *var; - - t = array_variable_name (s, subp, lenp); - if (t == 0) - return ((SHELL_VAR *)NULL); - var = find_variable (t); - - free (t); - return (var == 0 || invisible_p (var)) ? (SHELL_VAR *)0 : var; -} - -/* Return a string containing the elements in the array and subscript - described by S. If the subscript is * or @, obeys quoting rules akin - to the expansion of $* and $@ including double quoting. If RTYPE - is non-null it gets 1 if the array reference is name[*], 2 if the - reference is name[@], and 0 otherwise. */ -static char * -array_value_internal (s, quoted, allow_all, rtype) - char *s; - int quoted, allow_all, *rtype; -{ - int len; - arrayind_t ind; - char *akey; - char *retval, *t, *temp; - WORD_LIST *l; - SHELL_VAR *var; - - var = array_variable_part (s, &t, &len); - - /* Expand the index, even if the variable doesn't exist, in case side - effects are needed, like ${w[i++]} where w is unset. */ -#if 0 - if (var == 0) - return (char *)NULL; -#endif - - if (len == 0) - return ((char *)NULL); /* error message already printed */ - - /* [ */ - if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') - { - if (rtype) - *rtype = (t[0] == '*') ? 1 : 2; - if (allow_all == 0) - { - err_badarraysub (s); - return ((char *)NULL); - } - else if (var == 0 || value_cell (var) == 0) - return ((char *)NULL); - else if (array_p (var) == 0 && assoc_p (var) == 0) - l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL); - else if (assoc_p (var)) - { - l = assoc_to_word_list (assoc_cell (var)); - if (l == (WORD_LIST *)NULL) - return ((char *)NULL); - } - else - { - l = array_to_word_list (array_cell (var)); - if (l == (WORD_LIST *)NULL) - return ((char *) NULL); - } - - if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - { - temp = string_list_dollar_star (l); - retval = quote_string (temp); - free (temp); - } - else /* ${name[@]} or unquoted ${name[*]} */ - retval = string_list_dollar_at (l, quoted); - - dispose_words (l); - } - else - { - if (rtype) - *rtype = 0; - if (var == 0 || array_p (var) || assoc_p (var) == 0) - { - ind = array_expand_index (t, len); - if (ind < 0) - { -index_error: - if (var) - err_badarraysub (var->name); - else - { - t[-1] = '\0'; - err_badarraysub (s); - t[-1] = '['; /* ] */ - } - return ((char *)NULL); - } - } - else if (assoc_p (var)) - { - t[len - 1] = '\0'; - akey = expand_assignment_string_to_string (t, 0); /* [ */ - t[len - 1] = ']'; - if (akey == 0 || *akey == 0) - goto index_error; - } - - if (var == 0) - return ((char *)NULL); - if (array_p (var) == 0 && assoc_p (var) == 0) - return (ind == 0 ? value_cell (var) : (char *)NULL); - else if (assoc_p (var)) - retval = assoc_reference (assoc_cell (var), akey); - else - retval = array_reference (array_cell (var), ind); - } - - return retval; -} - -/* Return a string containing the elements described by the array and - subscript contained in S, obeying quoting for subscripts * and @. */ -char * -array_value (s, quoted, rtype) - char *s; - int quoted, *rtype; -{ - return (array_value_internal (s, quoted, 1, rtype)); -} - -/* Return the value of the array indexing expression S as a single string. - If ALLOW_ALL is 0, do not allow `@' and `*' subscripts. This is used - by other parts of the shell such as the arithmetic expression evaluator - in expr.c. */ -char * -get_array_value (s, allow_all, rtype) - char *s; - int allow_all, *rtype; -{ - return (array_value_internal (s, 0, allow_all, rtype)); -} - -char * -array_keys (s, quoted) - char *s; - int quoted; -{ - int len; - char *retval, *t, *temp; - WORD_LIST *l; - SHELL_VAR *var; - - var = array_variable_part (s, &t, &len); - - /* [ */ - if (var == 0 || ALL_ELEMENT_SUB (t[0]) == 0 || t[1] != ']') - return (char *)NULL; - - if (array_p (var) == 0 && assoc_p (var) == 0) - l = add_string_to_list ("0", (WORD_LIST *)NULL); - else if (assoc_p (var)) - l = assoc_keys_to_word_list (assoc_cell (var)); - else - l = array_keys_to_word_list (array_cell (var)); - if (l == (WORD_LIST *)NULL) - return ((char *) NULL); - - if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - { - temp = string_list_dollar_star (l); - retval = quote_string (temp); - free (temp); - } - else /* ${!name[@]} or unquoted ${!name[*]} */ - retval = string_list_dollar_at (l, quoted); - - dispose_words (l); - return retval; -} -#endif /* ARRAY_VARS */ diff --git a/arrayfunc.h~ b/arrayfunc.h~ deleted file mode 100644 index 3ac1f386c..000000000 --- a/arrayfunc.h~ +++ /dev/null @@ -1,59 +0,0 @@ -/* arrayfunc.h -- declarations for miscellaneous array functions in arrayfunc.c */ - -/* Copyright (C) 2001-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 (_ARRAYFUNC_H_) -#define _ARRAYFUNC_H_ - -/* Must include variables.h before including this file. */ - -#if defined (ARRAY_VARS) - -extern SHELL_VAR *convert_var_to_array __P((SHELL_VAR *)); - -extern SHELL_VAR *bind_array_variable __P((char *, arrayind_t, char *, int)); -extern SHELL_VAR *bind_array_element _P((SHELL_VAR *, arrayind_t, char *, int)); -extern SHELL_VAR *assign_array_element __P((char *, char *, int)); - -extern SHELL_VAR *find_or_make_array_variable __P((char *, int)); - -extern SHELL_VAR *assign_array_from_string __P((char *, char *, int)); -extern SHELL_VAR *assign_array_var_from_word_list __P((SHELL_VAR *, WORD_LIST *, int)); - -extern WORD_LIST *expand_compound_array_assignment __P((char *, int)); -extern void assign_compound_array_list __P((SHELL_VAR *, WORD_LIST *, int)); -extern SHELL_VAR *assign_array_var_from_string __P((SHELL_VAR *, char *, int)); - -extern int unbind_array_element __P((SHELL_VAR *, char *)); -extern int skipsubscript __P((const char *, int)); -extern void print_array_assignment __P((SHELL_VAR *, int)); - -extern arrayind_t array_expand_index __P((char *, int)); -extern int valid_array_reference __P((char *)); -extern char *array_value __P((char *, int, int *)); -extern char *get_array_value __P((char *, int, int *)); - -extern char *array_keys __P((char *, int)); - -extern char *array_variable_name __P((char *, char **, int *)); -extern SHELL_VAR *array_variable_part __P((char *, char **, int *)); - -#endif - -#endif /* !_ARRAYFUNC_H_ */ diff --git a/assoc.c~ b/assoc.c~ deleted file mode 100644 index b74f04c72..000000000 --- a/assoc.c~ +++ /dev/null @@ -1,370 +0,0 @@ -/* - * assoc.c - functions to manipulate associative arrays - * - * Associative arrays are standard shell hash tables. - * - * Chet Ramey - * chet@ins.cwru.edu - */ - -/* Copyright (C) 2007 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 (ARRAY_VARS) - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include "bashansi.h" - -#include "shell.h" -#include "array.h" -#include "assoc.h" -#include "builtins/common.h" - -static WORD_LIST *assoc_to_word_list_internal __P((HASH_TABLE *, int)); - -/* assoc_create == hash_create */ - -void -assoc_dispose (hash) - HASH_TABLE *hash; -{ - if (hash) - { - hash_flush (hash, 0); - hash_dispose (hash); - } -} - -void -assoc_flush (hash) - HASH_TABLE *hash; -{ - hash_flush (hash, 0); -} - -int -assoc_insert (hash, key, value) - HASH_TABLE *hash; - char *key; - char *value; -{ - BUCKET_CONTENTS *b; - - b = hash_search (key, hash, HASH_CREATE); - if (b == 0) - return -1; - FREE (b->data); - b->data = value ? savestring (value) : (char *)0; - return (0); -} - -void -assoc_remove (hash, string) - HASH_TABLE *hash; - char *string; -{ - BUCKET_CONTENTS *b; - - b = hash_remove (string, hash, 0); - if (b) - { - free ((char *)b->data); - free (b->key); - free (b); - } -} - -char * -assoc_reference (hash, string) - HASH_TABLE *hash; - char *string; -{ - BUCKET_CONTENTS *b; - - if (hash == 0) - return (char *)0; - - b = hash_search (string, hash, 0); - return (b ? (char *)b->data : 0); -} - -/* Quote the data associated with each element of the hash table ASSOC, - using quote_string */ -HASH_TABLE * -assoc_quote (h) - HASH_TABLE *h; -{ - int i; - BUCKET_CONTENTS *tlist; - char *t; - - if (h == 0 || assoc_empty (h)) - return ((HASH_TABLE *)NULL); - - for (i = 0; i < h->nbuckets; i++) - for (tlist = hash_items (i, h); tlist; tlist = tlist->next) - { - t = quote_string ((char *)tlist->data); - FREE (tlist->data); - tlist->data = t; - } - - return h; -} - -/* Quote escape characters in the data associated with each element - of the hash table ASSOC, using quote_escapes */ -HASH_TABLE * -assoc_quote_escapes (h) - HASH_TABLE *h; -{ - int i; - BUCKET_CONTENTS *tlist; - char *t; - - if (h == 0 || assoc_empty (h)) - return ((HASH_TABLE *)NULL); - - for (i = 0; i < h->nbuckets; i++) - for (tlist = hash_items (i, h); tlist; tlist = tlist->next) - { - t = quote_escapes ((char *)tlist->data); - FREE (tlist->data); - tlist->data = t; - } - - return h; -} - -char * -assoc_patsub (h, pat, rep, mflags) - HASH_TABLE *h; - char *pat, *rep; - int mflags; -{ - BUCKET_CONTENTS *tlist; - int i; - HASH_TABLE *h2; - char *t, *ifs, sifs[2]; - - if (h == 0 || assoc_empty (h)) - return ((char *)NULL); - - h2 = assoc_copy (h); - for (i = 0; i < h2->nbuckets; i++) - for (tlist = hash_items (i, h2); tlist; tlist = tlist->next) - { - t = pat_subst ((char *)tlist->data, pat, rep, mflags); - FREE (tlist->data); - tlist->data = t; - } - - if (mflags & MATCH_STARSUB) - { - ifs = getifs(); - sifs[0] = ifs ? *ifs : '\0'; - sifs[1] = '\0'; - t = assoc_to_string (h2, sifs, (mflags & MATCH_QUOTED)); - } - else - t = assoc_to_string (h2, " ", (mflags & MATCH_QUOTED)); - - assoc_dispose (h2); - - return t; -} - -char * -assoc_modcase (h, pat, modop, mflags) - HASH_TABLE *h; - char *pat; - int modop; - int mflags; -{ - BUCKET_CONTENTS *tlist; - int i; - HASH_TABLE *h2; - char *t, *ifs, sifs[2]; - - if (h == 0 || assoc_empty (h)) - return ((char *)NULL); - - h2 = assoc_copy (h); - for (i = 0; i < h2->nbuckets; i++) - for (tlist = hash_items (i, h2); tlist; tlist = tlist->next) - { - t = sh_modcase ((char *)tlist->data, pat, modop); - FREE (tlist->data); - tlist->data = t; - } - - if (mflags & MATCH_STARSUB) - { - ifs = getifs(); - sifs[0] = ifs ? *ifs : '\0'; - sifs[1] = '\0'; - t = assoc_to_string (h2, sifs, (mflags & MATCH_QUOTED)); - } - else - t = assoc_to_string (h2, " ", (mflags & MATCH_QUOTED)); - - assoc_dispose (h2); - - return t; -} - -char * -assoc_to_assign (hash, quoted) - HASH_TABLE *hash; - int quoted; -{ - char *ret; - char *istr, *vstr; - int i, rsize, rlen, elen; - BUCKET_CONTENTS *tlist; - - if (hash == 0 || assoc_empty (hash)) - return (char *)0; - - ret = xmalloc (rsize = 128); - ret[0] = '('; - rlen = 1; - - for (i = 0; i < hash->nbuckets; i++) - for (tlist = hash_items (i, hash); tlist; tlist = tlist->next) - { - istr = tlist->key; - vstr = tlist->data ? sh_double_quote ((char *)tlist->data) : (char *)0; - - elen = STRLEN (istr) + 8 + STRLEN (vstr); - RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize); - - ret[rlen++] = '['; - strcpy (ret+rlen, istr); - rlen += STRLEN (istr); - ret[rlen++] = ']'; - ret[rlen++] = '='; - if (vstr) - { - strcpy (ret + rlen, vstr); - rlen += STRLEN (vstr); - } - ret[rlen++] = ' '; - - FREE (vstr); - } - - RESIZE_MALLOCED_BUFFER (ret, rlen, 1, rsize, 8); - ret[rlen++] = ')'; - ret[rlen] = '\0'; - - if (quoted) - { - vstr = sh_single_quote (ret); - free (ret); - ret = vstr; - } - - return ret; -} - -static WORD_LIST * -assoc_to_word_list_internal (h, t) - HASH_TABLE *h; - int t; -{ - WORD_LIST *list; - int i; - BUCKET_CONTENTS *tlist; - char *w; - - if (h == 0 || assoc_empty (h)) - return((WORD_LIST *)NULL); - list = (WORD_LIST *)NULL; - - for (i = 0; i < h->nbuckets; i++) - for (tlist = hash_items (i, h); tlist; tlist = tlist->next) - { - w = (t == 0) ? (char *)tlist->data : (char *)tlist->key; - list = make_word_list (make_bare_word(w), list); - } - return (REVERSE_LIST(list, WORD_LIST *)); -} - -WORD_LIST * -assoc_to_word_list (h) - HASH_TABLE *h; -{ - return (assoc_to_word_list_internal (h, 0)); -} - -WORD_LIST * -assoc_keys_to_word_list (h) - HASH_TABLE *h; -{ - return (assoc_to_word_list_internal (h, 1)); -} - -char * -assoc_to_string (h, sep, quoted) - HASH_TABLE *h; - char *sep; - int quoted; -{ - BUCKET_CONTENTS *tlist; - int i; - char *result, *t, *w; - WORD_LIST *list, *l; - - if (h == 0) - return ((char *)NULL); - if (assoc_empty (h)) - return (savestring ("")); - - result = NULL; - list = NULL; - /* This might be better implemented directly, but it's simple to implement - by converting to a word list first, possibly quoting the data, then - using list_string */ - for (i = 0; i < h->nbuckets; i++) - for (tlist = hash_items (i, h); tlist; tlist = tlist->next) - { - w = (char *)tlist->data; - if (w == 0) - continue; - t = quoted ? quote_string (w) : savestring (w); - list = make_word_list (make_bare_word(t), list); - FREE (t); - } - - l = REVERSE_LIST(list, WORD_LIST *); - - result = l ? string_list_internal (l, sep) : savestring (""); - return result; -} - -#endif /* ARRAY_VARS */ diff --git a/assoc.h~ b/assoc.h~ deleted file mode 100644 index 82ac45d24..000000000 --- a/assoc.h~ +++ /dev/null @@ -1,54 +0,0 @@ -/* assoc.h -- definitions for the interface exported by assoc.c that allows - the rest of the shell to manipulate associative array variables. */ - -/* Copyright (C) 2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 _ASSOC_H_ -#define _ASSOC_H_ - -#include "stdc.h" -#include "hashlib.h" - -#define assoc_empty(h) ((h)->nentries == 0) -#define assoc_num_elements(h) ((h)->nentries) - -#define assoc_create(n) (hash_create((n))) - -#define assoc_copy(h) (hash_copy((h), 0)) - -extern void assoc_dispose __P((HASH_TABLE *)); -extern void assoc_flush __P((HASH_TABLE *)); - -extern int assoc_insert __P((HASH_TABLE *, char *, char *)); -extern void assoc_remove __P((HASH_TABLE *, char *)); - -extern char *assoc_reference __P((HASH_TABLE *, char *)); - -extern char *assoc_patsub __P((HASH_TABLE *, char *, char *, int)); -extern char *assoc_modcase __P((HASH_TABLE *, char *, int, int)); - -extern HASH_TABLE *assoc_quote __P((HASH_TABLE *)); - -extern char *assoc_to_assign __P((HASH_TABLE *, int)); - -extern WORD_LIST *assoc_to_word_list __P((HASH_TABLE *)); -extern WORD_LIST *assoc_keys_to_word_list __P((HASH_TABLE *)); - -extern char *assoc_to_string __P((HASH_TABLE *, char *, int)); -#endif /* _ASSOC_H_ */ diff --git a/bash-20060316/CWRU/CWRU.chlog~ b/bash-20060316/CWRU/CWRU.chlog~ deleted file mode 100644 index ba886933c..000000000 --- a/bash-20060316/CWRU/CWRU.chlog~ +++ /dev/null @@ -1,13200 +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 - -[bash-3.0 frozen] - - 7/27 - ---- -doc/Makefile.in - - small fixes - -[bash-3.0-released] - - 7/28 - ---- -array.c - - in array_insert(), make sure the value to be added is non-NULL before - calling savestring() on it - -builtins/reserved.def - - fix description of `CDPATH' - -lib/readline/display.c - - when expanding a prompt that spans multiple lines with embedded - newlines, set prompt_physical_chars from the portion after the - final newline, not the preceding portion. Bug reported by - "Ralf S. Engelschall" - -make_cmd.c - - explicitly declare `lineno' in function prologue for make_case_command - -builtins/evalfile.c - - include `trap.h' for declaration for run_return_trap - -bashline.c - - fix a `return' without a value in enable_hostname_completion - -general.c - - include test.h for extern declaration for test_eaccess - -externs.h - - add declaration for zcatfd - -tests/{history,histexp}.tests - - unset HISTFILESIZE to avoid problems if a value of 0 is inherited - from the environment - - 7/30 - ---- -bashline.c - - small changes to glob_expand_word to perform tilde expansion before - attempting globbing - -builtins/Makefile.in - - fix the install-help target to not cd into the `helpfiles' - subdirectory, so a value of $INSTALL_DATA containing a relative - pathname (e.g., .././support/install.sh) remains valid - - 7/31 - ---- -subst.c - - new function, mbstrlen(s), returns length of a multibyte character - string - -include/shmbutil.h - - new macro, MB_STRLEN(s), calls mbstrlen or STRLEN as appropriate - -builtins/trap.def - - small change so that a first argument that's a valid signal number - (digits only -- no symbolic names) will be treated as a signal and - reverted back to the original handling disposition. Fixes debian - complaints - -subst.c - - call MB_STRLEN instead of STRLEN where appropriate in - parameter_brace_expand_length to handle multibyte characters properly - - call MB_STRLEN instead of strlen in verify_substring_values so that - negative substrings of strings with multibyte chars work properly - - 8/1 - --- -jobs.c - - describe_pid needs to write to stderr, not stdout (POSIX) - - start_job, since it's only used by builtins (fg/bg), needs to write - its output to stdout, not stderr (POSIX) - -sig.c - - add an `orig_flags' member to struct terminating_signal so the - original signal handling flags (SA_RESTART, etc.) can be preserved - on POSIX systems - - make sure to preserve the signal flags state in - initialize_terminating_signals and reset them for child processes - in reset_terminating_signals - -builtins/fc.def - - fixed an off-by-one error that caused `fc -l' to list one too many - history entries - - in posix mode, `fc' should not list any indication as to whether or - not history lines have been modified (POSIX) - - when in posix mode, the default editor for `fc' should be `ed' (POSIX) - -doc/bashref.texi - - updated the description of `trap' behavior when given a first - argument that is a valid signal number - - noted that `fc -l' won't indicate whether a history entry has been - modified if the shell is in posix mode - -builtins/command.def - - fixed bug: `command -v' is supposed to be silent if a command is not - found - -builtins/hash.def - - `hash' should print its `hash table empty' message to stderr - -lib/readline/misc.c - - back out 7/7 change to _rl_maybe_save_line; it breaks emacs-mode ^P - -general.c - - changed base_pathname so that it will return reasonable results for - non-absolute pathnames -- this is what is intended by all of its - callers - -arrayfunc.c - - fix array_variable_part to return NULL if it finds an invisible - variable in the hash table. Fixes seg fault caused by referring to - unset local variable using array notation - -{locale,variables}.c - - support LC_TIME as a special locale variable so HISTTIMEFORMAT tracks - the current locale - - 8/2 - --- -variables.c - - fixed small memory leak in makunbound() when a local array variable - is unset. Fix from William Park - -lib/readline/display.c - - fixed a problem when computing the number of invisible characters on - the first line of a prompt whose length exceeds the screen width - (should only happen when invisible characters occur after the - line wrap). Bug reported by agriffis@gentoo.org - -builtins/command.def - - `command -V' passes a new flag, CDESC_ABSPATH, which means to convert - to an absolute path - -builtins/type.def - - in posix mode, `type' and `command -v/-V' should not report - non-executable files, even if the execution code will attempt to - run them. Other posix shells do this - -doc/bashref.texi - - add note to POSIX Mode section describing behavior of type and command - when finding a non-executable file - -execute_cmd.c - - force extended_glob to 1 before calling binary_test in - execute_cond_node so that the right extended pattern matching gets - performed - - 8/3 - --- -braces.c - - make sure lhs[0] and rhs[0] are cast to `unsigned char' so chars - with values > 128 are handled correctly - -builtins/printf.def - - change bexpand() and printstr() to handle strings with a leading - '\0' whose length is non-zero, since that's valid input for the - `%b' format specifier - -subst.c - - fix a couple of instances of find_variable that didn't check the - result for an invisible variable - -variables.c - - BASH_ARGC, BASH_ARGV, BASH_SOURCE, BASH_LINENO no longer created as - invisible vars - -pcomplete.c - - make sure COMP_WORDS is not invisible when bind_comp_words returns - - ditto for COMPREPLY in gen_shell_function_matches - - 8/4 - --- -braces.c - - fix problem where ${ was ignored but did not increment the open - brace count. Bug reported by Tim Waugh - -variables.c - - if make_local_variable finds a variable in the correct context in - the right variable scope, make sure it's not invisible before - returning it - - 8/5 - --- -builtins/trap.def - - fixed usage message to show `action' as not optional, though it - actually is when not in posix mode (for a single argument) - - 8/7 - --- -configure.in - - kfreebsd-gnu has had its sbrk() problems fixed, and no longer needs - to be configured --without-gnu-malloc - -lib/readline/vi_mode.c - - in rl_vi_search, free any saved history line before starting the - search, so failure leaves you at that line, not the last line in - the history (assuming the current line is not the last history line). - Fix from llattanzi@apple.com to replace fix of 7/7 - - 8/9 - --- -support/Makefile.in - - renamed `mostly-clean' target to `mostlyclean' - - 8/11 - ---- -lib/readline/vi_mode.c - - make same change for EOL in multibyte character case of - rl_vi_change_char - - 8/12 - ---- -subst.c - - in verify_substring_values, fix off-by-one error checking bounds of - `offset', esp. in array values (e.g., getting the highest element - of an array) - - 8/16 - ---- -aclocal.m4 - - change BASH_CHECK_DEV_FD to make sure that file descriptors > 2 are - accessible via /dev/fd, unlike FreeBSD 5.x - -lib/sh/strftime.c - - make sure `zone' is initialized with gettimeofday before it is used - - work around HPUX lack of `altzone' and differing definitions of - `timezone' - -lib/malloc/malloc.c - - internal_memalign and memalign now take a `size_t' as their first - argument, which seems to be the prevailing standard - -lib/malloc/{malloc.c,shmalloc.h} - - change sh_memalign to take a `size_t' as its first argument - -builtins/echo.def - - if posixly_correct and xpg_echo are both set, don't try to interpret - any arguments at all, as POSIX/XOPEN requires (fix inspired by Paul - Eggert) - -doc/bashref.texi - - amend description of bash posix mode to include new echo behavior - -builtins/fg_bg.def - - allow bg to take multiple job arguments, as posix seems to specify, - placing them all in the background, returning the status of the last - one as the status of `bg' - -lib/readline/vi_mode - - fix _rl_vi_change_mbchar_case (multibyte-char version of `~' - command) to have the right behavior at EOL -- handle case where vi - mode backs up at the end of the line - - 8/18 - ---- -array.c - - check for an empty array in array_rshift before shifting elements - and adjusting max_index - - check for null array in array_subrange - -jobs.c - - fix raw_job_exit_status to not ignore exit status of the last - process in the pipeline when `set -o pipefail' is enabled - - 8/19 - ---- -lib/readline/mbutil.c - - make sure _rl_find_next_mbchar_internal has a valid multibyte - character before it checks whether or not it's a zero-width - wide character and adjusts point accordingly - - 8/24 - ---- -bashline.c - - new function, bash_directory_expansion, duplicates the expansions - performed on the directory name by rl_filename_completion_function - - call bash_directory_expansion in command_word_completion_function - if we decide we're doing tilde expansion (and any other - canonicalization) on the directory name being completed - - 8/25 - ---- -configure.in - - use new-style AC_CHECK_HEADER to check for sys/ptem.h (which requires - sys/stream.h). The correct checks are in the code, but autoconf - complains if sys/stream.h is not included, rather than simply - checking for the header's presence - - 8/26 - ---- -builtins/hash.def - - fix a bug that prevented `hash -d' from working right (as soon as - hash removed a command from the table, the bug caused it to be added - right back) - - 8/27 - ---- -doc/{bash.1,bashref.texi} - - explicitly note that conditional primaries that operate on files - operate on the targets of symbolic links rather than the links - themselves - - 8/30 - ---- -lib/readline/display.c - - fix multibyte calculation of `physchars' in prompt expansion, to - handle double-width multibyte characters correctly - - changes to rl_redisplay to handle prompts longer than the screenwidth - that might contain double-width multibyte characters. Fixes from - Tomohiro Kubota - - 9/6 - --- -subst.c - - change word_list_split to avoid really bad behavior caused by calling - list_append for each split word -- as the list gets long, you have - to traverse it every time. Keep a pointer to the end of the list and - and just tack onto it - - 9/8 - --- -lib/readline/complete.c - - change fnprint to calculate the displayed width of a filename in - the same way as fnwidth - -subst.c - - in verify_substring_values, when expanding ${array[@]:offset}, make - sure negative offsets count from one greater than the array's - maximum index so things like ${x[@}: -1} work to give the last element - (requires fixing array tests) - -builtins/common.c - - new error function, sh_wrerror(), for builtins to call when a write - error occurs - -builtins/common.h - - extern declaration for sh_wrerror() - -builtins/cd.def - - change builtin_error call to use sh_wrerror() - -builtins/echo.def - - report write errors with sh_wrerror() instead of just returning - failure - -builtins/printf.def - - change printstr to return failure (-1) or success (0) indication - rather than void - - report write errors when printstr() fails, return failure - - if any of the PF/printf calls fail, report write error and return - failure - -execute_cmd.c - - change execute_in_subshell so the subshell command inherits the - command timing flags from the enclosing COMMAND * - - 9/11 - ---- -[prayers for the victims of 9/11/2001] - -lib/sh/strnlen.c - - new file, implementation of GNU libc extension function strnlen - -lib/sh/Makefile.in, {config.h,configure,Makefile}.in, MANIFEST - - changes for strnlen - -configure.in - - version changed to 3.1-devel - -doc/bash.1, lib/readline/doc/rluser.texi - - added description of `-o plusdirs' to complete/compgen (thanks, - Arnold) - -parse.y - - new parser_state flag, PST_ASSIGNOK, if set indicates we're parsing - arguments to a builtin that accepts assignment statement arguments - - turn on PST_ASSIGNOK in read_token_word when appropriate - - turn off PST_ASSIGNOK in read_token when appropriate - - don't attempt to parse a compound assignment specially unless we're - in a position where an assignment statement is acceptable, or - PST_ASSIGNOK is set - - 9/13 - ---- -variables.c - - make BASH_ARGC, BASH_ARGV, BASH_LINENO, and BASH_SOURCE - non-unsettable, since the shell uses those values internally - -expr.c - - make exponentiation right-associative, as is apparently correct - - 9/16 - ---- -arrayfunc.c - - make sure convert_var_to_array marks the environment as needing - recreation if the converted variable was exported - - 9/17 - ---- -braces.c - - mark ${ as introducing an additional level of braces only if it's - not in a quoted string -- quoted strings are handled before brace - matching is done - -parse.y - - fixed an obscure problem in history_delimiting_chars where the `in' - in a case statement could have a semicolon added after it, if the - `case word' was on a previous line - -support/config.guess - - support for newest versions of tandem non-stop kernel - -lib/readline/display.c - - in compute_lcd_of_matches, explicitly cast `text' to `char *' before - passing it to rl_filename_dequoting_function - -lib/readline/terminal.c - - bind the key sequence sent by the keypad `delete' key to delete-char - (same as ^D in emacs mode) - -builtins/ulimit.def - - in print_all_limits, don't print anything if get_limit returns - -1/EINVAL, indicating that the kernel doesn't support that particular - limit - - add -i (max number of pending signals), -q (max size of posix msg - queues), -x (max number of file locks) for systems (Linux) that - support them - -doc/{bash.1,bashref.texi} - - fix description of correspondence between FUNCNAME, BASH_LINENO, - and BASH_SOURCE indices in description of BASH_LINENO - - 9/18 - ---- -lib/sh/shquote.c - - don't quote CTLESC and CTLNUL with CTLESC in sh_backslash_quote, as - long as the resultant string never gets sent to the word expansion - functions without going through the shell parser - -externs.h - - add extern declarations for strnlen and strpbkrk from lib/sh - -subst.[ch] - - changes to handle case where IFS consists of multibyte characters. - Changed: string_extract_verbatim, split_at_delims, - string_list_dollar_star, string_list_dollar_at, list_string, - get_word_from_string, setifs - - 9/19 - ---- -mailcheck.c - - change file_mod_date_changed to reset the cached mail file data if - the file size drops to zero - -lib/readline/complete.c - - change append_to_match so that a non-zero value for - rl_completion_suppress_append will cause no `/' to be appended to a - directory name - -bashline.c - - experimental change to suppress appending a slash for a completed - filename that is found in PATH as well as a directory in the current - directory under certain circumstances: a single instance found in - $PATH when `.' is not in $PATH, and multiple instances found in the - $PATH, even when `.' is in the $PATH - - 9/24 - ---- -command.h - - new word flag: W_ASSIGNRHS, means word is rhs of assignment statement - - new word flag: W_NOTILDE, means word is not to be tilde expanded - - new word flag (internal): W_ITILDE, means the next character is a - tilde that should be expanded - -general.c - - new set of tilde suffixes for use when parsing the RHS of an - assignment statement and =~ should not be subject to tilde expansion - - if ASSIGN_P argument to bash_tilde_expand is 2, use tilde prefixes - for parsing RHS of assignment statement - -general.[ch] - - new function bash_tilde_find_word, drop-in replacement for - tilde_find_word - -subst.c - - call bash_tilde_expand with secord argument of 2 when expanding rhs - of an assignment statement, so tildes after second and subsequent - `=' in an assignment are not expanded - - new function, expand_string_assignment, to expand the rhs of an - assignment statement - - add `~' to EXP_CHAR, the characters that will cause the word - expansion functions to be called - - move tilde expansion into expand_word_internal instead of many - different calls to bash_tilde_expand scattered across different - functions. NOTE: This means that double quotes surrounding a - {paramOPword} expansion will cause tilde expansion to NOT be - performed on `word'. I think this is right, what POSIX specifies, - and consistent with the behavior of other characters in the rhs - -execute_cmd.c - - take out calls to bash_tilde_expand before calling word expansion - functions - - 9/26 - ---- -execute_cmd.c - - make sure to call UNBLOCK_CHILD before returning on a pipe creation - failure in execute_pipeline - - 9/27 - ---- -variables.c - - change get_bash_command to deal with the_printed_command_except_trap - being NULL - -execute_cmd.c - - fix execute_simple_command to deal with the_printed_command being - NULL when assigning to the_printed_command_except_trap -- fixes - seg fault in savestring() - -parse.y - - change the parser so that the closing `)' in a compound variable - assignment delimits a token -- ksh93 does it this way - -doc/{bash.1,bashref.texi} - - change description of tilde expansion to note that expansion is - attempted only after the first =~ in an assignment statement - -builtins/declare.def - - when assigning to an array variable with declare -a x=(...), make - sure the last character in the rhs of the variable assignment is - `)', not just that it appears somewhere - - 9/28 - ---- -command.h - - add a `W_NOEXPAND' flag to inhibit all expansion except quote removal - - add a `W_COMPASSIGN' flag to denote a word is a compound assignment - statement - -parse.y - - set W_COMPASSIGN on words that appear to be compound assignments - -subst.c - - pass W_NOXPAND and W_COMPASSIGN through end of expand_word_internal - -subst.[ch] - - new function, expand_assignment_string_to_string, calls - expand_string_assignment and then string_list on the result - -variables.c - - assign_in_env now calls expand_assignment_string_to_string - - 9/30 - ---- -builtins/common.c - - change get_job_spec so the null job `%' once again means the current - job - - 10/1 - ---- -subst.c - - do_assignment_internal now takes a WORD_DESC * as its first - argument, and uses its `word' member as the assignment string - - change expand_word_list_internal to call do_word_assignment instead - of do_assignment, passing it `word' instead of, e.g., `word->word' - - change extract_array_assignment_list to just return the passed - string minus a trailing `)' if the last character is a right - paren - - change do_assignment_internal to call extract_array_assignment_list - -subst.[ch] - - change do_assignment and do_assignment_no_expand to take a `char *' - instead of `const char *' first argument; change extern prototypes - - new function, do_word_assignment, takes a WORD_DESC * and calls - do_assignment_internal on it; add extern declaration with prototype - -general.h - - new typedef, sh_wassign_func_t, like sh_assign_func_t but takes a - WORD_DESC * as its first argument - -variables.[ch] - - assign_in_env now takes a WORD_DESC * as its first argument - - 10/2 - ---- -command.h - - new word flag, W_ASSNBLTIN, denotes that the word is a builtin - command (in a command position) that takes assignment statements - as arguments, like `declare' - - new word flags, W_ASSIGNARG, denotes that word is an assignment - statement given as argument to assignment builtin - -execute_cmd.c - - set W_ASSNBLTIN flag in fix_assignment_words if necessary (if there - are any arguments that are assignment statements) - - set W_ASSIGNARG flag in fix_assignment_words if necessary - -subst.c - - new function, do_compound_assignment, encapsulates the necessary - code to perform a compound array assignment (including creation of - local variables); called from do_assignment_internal - - to fix the double-expansion problem with compound array assignments - that are arguments to builtins like `declare', changed - shell_expand_word_list to treat those arguments like assignment - statements (with proper creation of local variables inside shell - functions) and pass the attribute-setting portion of the statement - onto the builtin. This is what ksh93 appears to do, from inspection - of the `ksh93 -x' output - -execute_cmd.c - - fix execute_simple_command: in case of pipeline or async command, - when forking early, set `subshell_environment' so that it can contain - both SUBSHELL_PIPE and SUBSHELL_ASYNC -- the two should not be - mutually exclusive. Fixes bug reported by pierre.humblet@ieee.org - - remove references to last_pid, old_command_subst_pid; use NO_PID as - a sentinel value to decide whether or not a child process has been - created and needs to be waited for. Submitted by - pierre.humblet@ieee.org to fix recycling-pid problem on cygwin - -doc/{bash.1,bashref.texi} - - fixed documentation of `@(pattern)' extended globbing operator -- - it succeeds if the string matches one of the patterns, not exactly - one. This is what ksh93 does, too - -lib/readline/complete.c - - fixed rl_menu_complete so that a negative argument cycles backwards - through the list - - 10/3 - ---- -subst.c - - use W_COMPASSIGN flag in do_assignment_internal instead of deciding - lexically which assignments are compound array assignments - - 10/6 - ---- -support/shobj-conf - - additions for System V.5 from Boyd Gerber - -subst.c - - in command_substitute, if subshell_environment includes - SUBSHELL_ASYNC, call make_child with the `async_p' argument set to - non-zero. This keeps command substitutions for async commands or - pipelines from trying to give the terminal back to the shell's - pgrp. make sure to save and restore last_asynchronous_pid. Fix - suggested by - - 10/7 - ---- -config.h.in - - add a placeholder definition for WCONTINUED_BROKEN - - 10/9 - ---- -aclocal.m4 - - add BASH_CHECK_WCONTINUED, checks for glibc bug where WCONTINUED is - defined but rejected as invalid by waitpid(2) - -configure.in - - add call to BASH_CHECK_WCONTINUED, defines WCONTINUED_BROKEN - -redir.c - - experimental change to add_undo_redirect to save manipulations to - file descriptors >= SHELL_FD_BASE (10) on the list of redirections - to be undone even if `exec' causes the list to be discarded - -doc/{bash.1,bashref.texi} - - note that redirections using file descriptors > 9 should be used - carefully, because they might conflict with file descriptors the - shell uses internally - - 10/11 - ----- -parse.y - - fix pipeline_command production to handle case where `pipeline' - as `argument' of `!' or `time' is null (e.g., a syntax error not - handled by the grammar) - - 10/13 - ----- -lib/readline/readline.c - - new internal variable, _rl_bind_stty_chars; if non-zero, bind the - terminal special characters to readline equivalents at startup - - change readline_default_bindings() and reset_default_bindings() to - understand _rl_bind_stty_chars - -lib/readline/rlprivate.h - - new extern declaration for _rl_bind_stty_chars - -lib/readline/rltty.c - - change rl_prep_terminal to add support for _rl_bind_stty_chars - - 10/15 - ----- -lib/readline/bind.c - - new bindable variable, `bind-tty-special-chars', bound to value of - _rl_bind_stty_chars - -doc/bash.1,lib/readline/doc/{readline.3,rluser.texi} - - documented new readline variable `bind-tty-special-chars' - -builtins/pushd.def - - make the first check for option `--' skip the rest of option - checking - - 10/16 - ----- -lib/readline/shell.c - - change sh_set_lines_and_columns to prefer setenv, which has - predictable memory allocation behavior, to putenv, which does not - - 10/19 - ----- -variables.c - - change push_exported_var so that a tempenv variable has to have the - export attribute set (which they all do -- something to look at) and - the `propagate' attribute set to be propagated down to the next - scope - -execute_cmd.c - - change execute_builtin so that if CMD_COMMAND_BUILTIN is set in the - passed flags argument, call pop_scope with a value that says the - builtin is not special, since `command' means that preceding variable - assignments don't persist in the environment. Fixes problem with - variable assignments preceding command preceding special builtin - keeping those variable assignments around (when in posix mode) - - 10/20 - ----- -lib/sh/shquote.c - - new function, sh_mkdoublequoted, brackets a given string with - double quotes and returns a new string. Flags argument, if non- - zero, means to quote embedded double quotes with backslashes - -externs.h - - new extern declaration for sh_mkdoublequoted - -parse.y - - use sh_mkdoublequoted after calling localeexpand() - -lib/sh/strtrans.c - - change ansicstr to understand that (flags & 4) != 0 means to remove - backslash from unrecognized escape sequences - -general.c - - fix logic problem in assignment() that caused non-variable-starter - characters to be allowed, resulting in things like `1=xxx' creating - a variable `1' in the hash table - - 10/21 - ----- -bashline.c - - don't call programmable_completions with an assignment statement - argument - - 10/22 - ----- -lib/readline/rltty.c - - in prepare_terminal_settings, turn echoing on (readline_echoing_p) - if get_tty_settings fails because the input is not a terminal - - 10/24 - ----- -lib/readline/util.c - - include rlmbutil.h for multibyte definitions - - new function, _rl_walphabetic, wide char version of rl_alphabetic - -lib/readline/mbutil.c - - new function, _rl_char_value(buf, ind), returns value of (possibly - multibyte) character at buf[ind] - -lib/readline/rlmbutil.h - - extern defines for _rl_walphabetic and _rl_char_value for when - multibyte chars are not being used - - new wrapper definitions for _rl_find_next_mbchar (MB_NEXTCHAR) and - _rl_find_prev_mbchar (MB_PREVCHAR) that try to avoid unneeded - function calls - -lib/readline/text.c - - fix rl_foward_word to work with multibyte characters (or in a - multibyte locale) using above utility functions - - fix rl_backward_word to work with multibyte characters (or in a - multibyte locale) using above utility functions - - 10/26 - ----- -parse.y - - fix parse_matched_pair so that it doesn't swallow \ when - parsing a $'...' construct (call shell_getc with different arg) - - 10/28 - ----- -lib/glob/glob.c - - after some (compiled-in) threshold, glob_vector will stop using - alloca to allocate `struct globval's and will switch to using - malloc, with appropriate cleanup before returning - -subst.c - - don't expand tildes after `=' in expand_word_internal, even if the - W_TILDEEXP flag is set, unless it's the first tilde in a word - marked W_ASSIGNMENT - - 10/31 - ----- -lib/readline/text.c - - make sure rl_point doesn't go below 0 in rl_delete_horizontal_space - (from SUSE, but not sent in) - -shell.c - - make sure shell_is_restricted skips over a single leading `-' in - the shell name (from SUSE, but not sent in) - -lib/readline/display.c - - disable `fast redisplay' at the end of the line if in a locale that - supports multibyte characters (from SUSE, but not sent in) - -lib/readline/histexpand.c - - fix a problem with finding the delimiter of a `?' substring when - compiled for multibyte characters (from SUSE, but not sent in) - - 11/1 - ---- -lib/readline/display.c - - correct some assignments to _rl_last_c_pos: when in a multibyte - locale, it's used as an absolute cursor position; when not using - multibyte characters, it's a buffer offset. I should have caught - this when the multibyte character support was donated - - 11/5 - ---- -general.c - - change `assignment()' to accept `+=' assignment operator - -arrayfunc.[ch] - - bind_array_variable and assign_array_element both take a new `flags' - argument - - assign_array_var_from_string, assign_array_from_string, and - assign_array_var_from_word_list now all take a new `flags' argument - - change assign_array_var_from_word_list to understand how to append - to an array variable - - change assign_array_var_from_string to understand how to append - to an array variable. It does not unset the previous value if - appending, allowing both old values to be changed and new ones to - be added - -subst.h - - new flag #defines to use for evaluating assignment statements - -{subst,variables}.c, builtins/{declare,read}.def - - change callers of assign_array_element and bind_array_variable - - change do_compound_assignment to understand assignment flags - - change do_assignment_internal to set assignment flags and pass them - to underlying functions - -pcomplete.c,builtins/{declare,read}.def - - fix callers of assign_array_var_from_string, assign_array_var_from_word_list - -variables.[ch] - - make_variable_value now takes a new `flags' argument - - make_variable_value now understands how to append to a particular - variable, using the old value - - bind_variable_value now takes a new `flags' argument - - change make_variable_value to understand ASS_APPEND flag - - bind_variable now takes a new `flags' argument - - bind_variable_internal now takes a new `flags' argument - -arrayfunc.c - - change callers of make_variable_value to add flags arg - -builtins/declare.def - - change callers of bind_variable_value to add flags arg - -{execute_cmd,mailcheck,pcomplete,shell,subst,variables}.c,parse.y -builtins/{cd,command,declare,getopts,read,set,setattr}.def - - change callers of bind_variable to add flags arg - -variables.c - - change callers of bind_variable_internal - - change bind_variable_internal to pass assignment flags on to - make_variable_value - - change assign_in_env to treat `var+=value' like `var=value' - -arrayfunc.c - - break code that actually constructs the new value and assigns it - to a particular array index out into a new functions: - bind_array_var_internal. This fakes out make_variable_value by - passing a dummy SHELL_VAR * so it can do proper appending and other - += processing - - changes to assign_array_var_from_string to accept and process as if - they were `standalone' assignment statements array assignment words - of the form [ind]+=val - - 11/7 - ---- -builtins/declare.def - - added support for `declare [flags] var+=value'. `Flags' are applied - before the assignment is performed, which has implications for things - like `-i' -- if -i is supplied, arithmetic evaluation and increment - will be performed - -builtins/setattr.def - - add support for `+=' assignment for rest of `assignment builtins': - export, readonly - - 11/12 - ----- -lib/readline/display.c - - make sure prompt_physical_chars and prompt_invis_chars_first_line - are reset to 0 if the prompt string passed to rl_expand_prompt is - NULL or empty - - 11/14 - ----- -{configure,config.h}.in - - check for `raise', define HAVE_RAISE if available - -lib/intl/dcigettext.c - - make sure `raise' is defined if HAVE_RAISE is not before - eval-plurah.h is included - -lib/malloc/trace.c - - put extern declaration for imalloc_fopen inside the MALLOC_TRACE - #ifdef - - 11/16 - ----- -lib/intl/Makefile.in - - make sure SHELL is defined to cpp - -lib/intl/dcigettext.c - - make sure we use getcwd() even if HAVE_GETCWD is not defined after - including config.h; if SHELL is defined, #define HAVE_GETCWD - - 11/18 - ----- -trap.[ch] - - new function, int signal_in_progress(int sig), returns TRUE if the - trap handler for signal SIG is currently executing - - 11/19 - ----- -redir.c - - slightly change do_redirection_internal to set the close-on-exec - flag for file descriptors > 2 used to save file descriptors < 2 - using explicit redirections (e.g., `exec 3>&1'). This keeps file - descriptors pointing to pipes from being left open but doesn't - change the shell's file descriptor semantics - - 11/20 - ----- -doc/{bash.1,bashref.texi} - - correct some minor typos, forwarded from doko@debian.org - - 11/22 - ----- -doc/bash.1,lib/readline/doc/{readline.3,rluser.texi} - - documented detail that yank-last-arg and yank-nth-arg use the history - arg expansion code (and, as a result, are subject to restrictions - of the history-comment character) - - 11/23 - ----- -execute_cmd.c - - changes so that BASH_COMMAND preserves its value into a DEBUG trap: - for commands, arithmetic for command expressions, select commands, - case commands, (( commands, [[ commands, simple commands - - 11/24 - ----- -doc/{bash.1,bashref.texi} - - changed description of `set' builtin slightly so that it is clear - that only variables are displayed in posix mode and that read-only - variables can't be reset by simply sourcing the output of `set' - -lib/sh/strftime.c - - don't try to redefine `inline' if it's already defined - - 11/26 - ----- -execute_cmd.c - - fix execute_function to check funcname_a after function execution, - since FUNCNAME can be changed or unset within a function - - 11/27 - ----- -builtins/evalfile.c - - make same changes as 11/26, this time to _evalfile - -execute_cmd.c - - change execute_function to run the return trap after a function - completes execution even if the shell is compiled without DEBUGGER - defined - -trap.c - - change reset_or_restore_signal_handlers so that the RETURN trap is - not inherited by command substitution when DEBUGGER is not defined - - 11/30 - ----- -lib/readline/misc.c - - fix memory leaks in _rl_free_history_entry and rl_maybe_replace_line - caused by not freeing `timestamp' member of history entry - - make sure timestamp is initialized to NULL in rl_maybe_save_line - - 12/1 - ---- -execute_cmd.c - - fix execute_function so a function calling `return' will run the - RETURN trap, if one's defined - -doc/{bash.1,bashref.texi} - - fix description of RETURN trap in various places to indicate that it's - only inherited by shell functions if function tracing is on globally - or has been enabled for that function - - fix documentation to indicate that the DEBUG and RETURN traps are - inherited under the same conditions - -execute_cmd.c - - a function does not inherit the RETURN trap if a DEBUG trap is - currently running - - 12/2 - ---- -lib/glob/xmbsrtowcs.c - - change xmbsrtowcs to handle the one case where malloc can fail - (though it should not matter) -- don't try to free a null pointer - - 12/9 - ---- -subst.c - - fix get_var_and_type to handle var[@], where `var' is a scalar - variable, identically to var -- all calling expansions can now - handle var[@] like var. Bug reported by agriffis@gentoo.org - - 12/10 - ----- -lib/readline/bind.c - - make new-style "\M-x" keybindings obey `convert-meta' settings - (bug reported by twaugh@redhat.com) - - 12/14 - ----- -builtins/set.def - - added description of `-' option to help text - -builtins/shopt.def - - fix bug that caused `gnu_errfmt' to not be compiled in unless - READLINE is defined - - 12/16 - ----- -subst.c - - fixed a typo in string_extract_verbatim in first call to MBLEN - (used `slen - 1' instead of `slen - i') - - 12/17 - ----- -subst.c - - avoid some calls to strlen if the value is only being used for - ADVANCE_CHAR and MB_CUR_MAX == 1 (since ADVANCE_CHAR doesn't need - it unless multibyte characters are possible) - - change string_extract_verbatim so it takes the length of the string - as a parameter, so we don't have to recompute the length of the same - string over and over again when doing word splitting (that kills if - it's a long string) - - 12/18 - ----- -subst.c - - in string_list_dollar_star, make sure to null-terminate the - separator if the character is longer than one byte - - 12/22 - ----- -doc/{bash.1,bashref.texi} - - changed text in quoting section explaining that double quotes do - not prevent history expansion from taking place, and that backslashes - escaping ! are not removed - - 12/28 - ----- -shell.c - - set gnu_error_format to 1 if running under emacs. This should allow - the emacs `next-error' stuff to work, at least for interactive shells - -parse.y - - change yy_stream_get to set interrupt_immediately before calling - getc_with_restart when the shell is interactive. This avoids the - synchronization problem caused by the call to QUIT in read_a_line, - which results in the first character after a SIGINT/^C to be - dropped - - 12/30 - ----- -builtins/mkbuiltins.c - - changes to write long documentation to arrays as a single string by - default, rather than an array of strings -- enabled by default - - new option, -S, to restore old behavior of writing multiple strings - for long documentation - - changes to avoid filenames written when the separate-filenames option - (-H) has been supplied being run through gettext - -configure.in - - new cofiguration option, --enable-single-help-strings (on by default), - causes help text to be stored as a single string (or smaller set than - one string per line) - -builtins/Makefile.in - - pass `-S' to mkbuiltins if single-help-strings is turned off - -doc/bashref.texi - - documented new `single-help-strings' configure option - - 1/3/2005 - -------- -jobs.c - - make wait_for return a non-zero status if the job or processed - waited for is suspended. Returns 128 + stop signal. This fixes - the problem with `echo one && sleep 5 && echo two' displaying - `two' after the sleep is suspended - - 1/5 - --- -print_cmd.c - - change indirection_level_string so the code duplicates the first - character of $PS4 to indicate the indirection level, rather than - the first byte - - 1/8 - --- -variables.c - - new special variable hook function for COMP_WORDBREAKS; sets - rl_completer_word_break_characters back to NULL when the variable - is unset - - change bind_variable_value to understand dynamic variables with - assign_function set, and handle them correctly. If the variable is - being appended to, use make_variable_value to create the new - value - - change bind_variable_internal to understand dynamic variables with - assign_function set, and handle them the same way - - RANDOM and LINENO now get the integer attribute, so appending works - as expected - - ditto for HISTCMD, MAILCHECK, OPTIND - -lib/readline/display.c - - change _rl_make_prompt_for_search to set prompt_physical_chars - appropriately - - rl_save_prompt and rl_restore_prompt save and restore - prompt_prefix_length - - change redraw_prompt to use rl_save_prompt and rl_restore_prompt - - change rl_restore_prompt to set the `save' variables back to - NULL/0 so code can check whether or not the prompt has been saved - - change rl_message and rl_clear_message to save and restore the - prompt if the caller has not already done it (using a simple - semaphore-like variable) - - change rl_message to call expand_prompt, so that local_prompt and - local_prompt prefix are set before calling the redisplay functions, - in case the prompt is longer than a screenwidth (fixes bug - reported to debian by epl@unimelb.edu.au) - -lib/readline/doc/rltech.texi - - make sure to note that rl_save_prompt should be called before - rl_message, and rl_restore_prompt before rl_clear_message - -pcomplete.c - - make sure to save and restore the parser state around the call to - execute_shell_function in gen_shell_function_matches. Fixes bug - reported by a050106.1.keeLae3x@captaincrumb.com (cute) - -lib/readline/readline.c - - fix _rl_dispatch_subseq in the case where we're recursing back up - the chain (r == -2) and we encounter a key shadowed by a keymap, - but originally bound to self-insert. Calling rl_dispatch with - ANYOTHERKEY as the first argument will call rl_insert, but with - ANYOTHERKEY (256) as the char to insert. Use the shadow keymap - and set things up to dispatch to rl_insert with the shadowed key - as the argument. Fixes the bug reported by Thomas Glanzmann - (sithglan@stud.uni-erlangen.de) - - 1/13 - ---- -command.h - - new word flag: W_HASQUOTEDNULL - -make_cmd.c - - new function to allocate a WORD_DESC * without doing anything with a - containing string: alloc_word_desc - -make_cmd.h - - extern declaration for alloc_word_desc - -dispose_cmd.c - - new function to just free a WORD_DESC * without freeing the contained - string: dispose_word_desc - -dispose_cmd.h - - extern declaration for dispose_word_desc - -subst.c - - change some places to use alloc_word_desc - - make same changes to word_list_quote_removal as were made to - word_list_split - - set W_HASQUOTEDNULL when a word is created with w->word[0] == - CTLNUL and w->word[1] == '\0' - -subst.c - - parameter_brace_expand_word now returns a WORD_DESC * -- changed - callers to understand - - parameter_brace_expand_indir now returns a WORD_DESC * -- changed - callers to understand - - parameter_brace_expand_rhs now returns a WORD_DESC * -- changed - callers to understand - - remove W_HASQUOTEDNULL from a word's flags when remove_quoted_nulls - is called on the word's enclosed string - - 1/15 - ---- -subst.c - - param_expand now returns a WORD_DESC * -- changed callers to - understand - - parameter_brace_expand now returns a WORD_DESC * -- changed - callers to understand - - in expand_word_internal, only call remove_quoted_nulls after a word - is returned with W_HASQUOTEDNULL - - changes to pass W_HASQUOTEDNULL flag out of expand_word_internal; - changed callers to call remove_quoted_nulls only if return value has - W_HASQUOTEDNULL set. This is a mostly-complete fix for the - long-standing CTLNUL confusion between a quoted null expansion and - the expansion of a variable with a literal '\177' in its value - - change string_list_dollar_at to compute the separator character the - same way as string_list_dollar_star: using the already-computed - values generated in setifs() - - when expanding unquoted $*, if $IFS is empty, check whether or not - we're eventually going to split the results (e.g., on the rhs of an - assignment statement) and concatenate the positional parameters as - if the expansion were within double quotes if we're not going to - split - -tests/iquote.tests - - test cases based on old bug reports about the quoted-null vs. 0177 - problem the recent code fixes - - 1/16 - ---- -dispose_cmd.c - - set w->word to 0 before putting a WORD_DESC * back in the cache in - dispose_word_desc; changed callers to delete those assignments - -variables.c - - change assign_random and get_random_value so that the random number - generator only gets re-seeded once in a subshell environment, and - assigning a value to RANDOM counts as seeding the generator. This - makes the sequences a little more predictable - - 1/20 - ---- -lib/readline/history.c - - fix replace_history_entry, remove_history to return NULL if - passed index is < 0 - - 1/22 - ---- -lib/sh/netconn.c - - fix isnetconn() to understand that getpeername can return ENOTCONN - to indicate that an fd is not a socket - -configure.in - - set BUILD_DIR to contain backslashes to escape any spaces in the - directory name -- this is what make will accept in targets and - prerequisites, so it's better than trying to use double quotes - - set SIZE to the appropriate value if some cross-compiling tool - chain is being used; `size' by default (can be overridden by - SIZE environment variable) - -Makefile.in - - use $(SIZE) instead of size; set SIZE from configure - - 1/31 - ---- -arrayfunc.c - - in array_value_internal, return NULL right away if the variable's - value is NULL, instead of passing a null string to add_string_to_list - - 2/1 - --- -jobs.h - - new struct to hold stats and counters for child processes and jobs - - change some uses of global and static variables to use members of - new struct (struct jobstats) - - 2/2 - --- - -jobs.[ch] - - change PRUNNING to PALIVE - - new define INVALID_JOB - - new macro get_job_by_jid(ind), currently expands to jobs[ind] - - new define J_JOBSTATE, operates on a JOB * like JOBSTATE operates on - a job index - - new function, reset_job_indices, called from delete_job if - js.j_lastj or js.j_firstj are removed - - change various functions to keep counters and stats in struct jobstats - -pcomplete.c, builtins/common.c, builtins/{exit,fg_bg,jobs,kill,wait}.def - - change global variables (e.g., job_slots) to struct members - (e.g., js.j_jobslots) - - use INVALID_JOB define where appropriate - - use get_job_by_jid and J_JOBSTATE where appropriate - -trap.c - - change reset_or_restore_signal_handler to not free the exit trap - string if the function pointer is reset_signal, which is used when - the trap strings shouldn't be freed, like in command substitution - - 2/4 - --- -jobs.c - - new function, realloc_jobs_list, copies jobs array to newly-allocated - memory shrinking (or growing) size to have next multiple of JOB_SLOTS - greater than js.j_njobs - - change compact_jobs_list to just call reap_dead_jobs and then - realloc_jobs_list, simplifying it considerably - - discard_pipeline now returns `int': the number of processes freed - - slightly changed the logic deciding whether or not to call - compact_jobs_list: now non-interactive shells will compact the - list if it reaches MAX_JOBS_IN_ARRAY in size - -parse.y - - move test for backslash-newline after pop_string in shell_getc so - that things like - - ((echo 5) \ - (echo 6)) - - work right - - 2/8 - --- -jobs.h - - new structs for holding status of exited background processes, as - POSIX specifies - - new job flag: J_ASYNC - -jobs.c - - new functions to manipulate struct holding status of exited - background processes - - new members in struct jobstats to hold pointer to last created job - and last created asynchronous job - - initialize js.c_childmax in initialize_job_control - - if the `async' arg to stop_pipeline is non-null, set the J_ASYNC - flag in the job struct - - set js.j_last_made_job and js.j_last_asynchronous_job in - stop_pipeline - - new function: find_last_proc, returns the PROCESS * to the last proc - in a job's pipeline - - changed find_last_pid to call find_last_proc - - change delete_job to call bgp_add on the last proc of the job being - deleted - - change delete_all_jobs and wait_for_background_pids to call bgp_clear - - 2/9 - --- -jobs.c - - change wait_for_single_pid to look for pid in bgpids.list (using - bgp_search()) if find_pipeline returns NULL - - 2/10 - ---- -support/shobj-conf - - change the solaris-gcc stanza so that it auto-selects the appropriate - options for ld depending on which `ld' gcc says it's going to run - - 2/11 - ---- -jobs.h - - add support for PS_RECYCLED as a process state, add PRECYCLED macro - to test it. Change PALIVE and PRUNNING macros to not count processes - in PS_RECYCLED state - -execute_cmd.c - - restore use of last_pid as sentinel value; use NO_PID as sentinel - only if RECYCLES_PIDS is defined - -jobs.c - - change find_job to return a pointer to the PROCESS the desired pid - belongs to, analogous to find_pipeline returning pointer to JOB - - change find_job callers to add extra argument - - change running_only arguments to find_pipeline and find_job to - alive_only, since we don't want recycled pids returned here and it - better describes the result - - new function find_process, calls find_pipeline and searches the - returned pipeline for the PROCESS * describing the desired pid - - in make_child, if fork() returns the same pid as the value of - last_asynchronous_pid when RECYCLES_PIDS is defined, avoid pid - aliasing by resetting last_asynchronous_pid to 1 - - use PRUNNING instead of child->running, since we, for the most - part, don't want to consider recycled pids (e.g., in make_child()) - - call find_process instead of find_pipeline in waitchld() - - use PEXITED(p) instead of testing p->running == PS_DONE - - in make_child, call bgp_delete to remove a just-created pid from the - last of saved pid statuses - - in add_process, check whether or not pid being added is already in - the_pipeline or the jobs list (using find_process) and mark it as - recycled if so - - This set of fixes mostly came from Pierre Humblet - to fix pid aliasing and reuse problems on - cygwin - -variables.c - - set $_ from the environment if we get it there, set to $0 by - default if not in env - -doc/{bashref.texi,bash.1} - - a couple of clarifying changes to the description of $_ based on - comments from Glenn Morris - - 2/15 - ---- -shell.c - - use strstr instead of strmatch when checking whether $EMACS contains - `term' -- simpler and faster - - 2/18 - ---- -builtins/cd.def - - implement posix requirement that `pwd -P' set $PWD to a directory - name containing no symlinks - - add new function, setpwd(), just sets (and changes exported value) - of PWD - -doc/bashref.texi - - add note to posix mode section about pwd -P setting $PWD - -doc{bash.1,bashref.texi} - - added note that BASH_ARGC and BASH_ARGV are only set in extended - debug mode - - expand description of extdebug option to include everything changed - by extended debug mode - - 2/19 - ---- -pathexp.h - - new flag macro, FNMATCH_IGNCASE, evaluates to FNM_CASEFOLD if the - match_ignore_case variable is non-zero - -execute_cmd.c - - new variable, match_ignore_case - - change call to strmatch() in execute_case_command so it includes - FNMATCH_IGNCASE - -test.c - - change call to strmatch() in patcomp() so that pattern matching - calls for [[ ... ]] obey the match_ignore_case variable - -lib/sh/shmatch.c - - if match_ignore_case is set, enable REG_ICASE in the regexp match - flags - -builtins/shopt.def - - new settable option, `nocasematch', controls the match_ignore_case - variable. Currently alters pattern matching for case and [[ ... ]] - commands (==, !=, and =~ operators) - -doc/{bashref.texi,bash.1} - - updated descriptions of [[ and case to include reference to - nocasematch option - - 2/22 - ---- -builtins/mkbuiltins.c - - add `times' to the list of posix special builtins - - 2/23 - ---- -builtins/cd.def - - posix mode no longer turns on effect of -P option on $PWD if a - directory is chosen from CDPATH - -doc/bashref.texi - - clarified that in posix mode, reserved words are not alias expanded - only in a reserved word context - - removed item about cd, $CDPATH, and -P from posix mode section - - 2/24 - ---- -builtins/reserved.def - - minor cleanups to the description of `if' - - 3/2 - --- -subst.c - - change list_string and get_word_from_string to explicitly treat an - IFS character that is not space, tab, or newline *and any adjacent - IFS white space* as a single delimiter, as SUSv3/XPG6 says - -builtins/read.def - - check whether or not the number of fields is exactly the same as - the number of variables instead of just assigning the rest of the - line (minus any trailing IFS white space) to the last variable. - This parses a field and checks whether or not it consumes all of - the input (including any trailing field delimiters), falling back - to the previous behavior if it does not. This is what POSIX.2 - specifies, I believe (and the consensus of the austin-group list). - This requires a few tests in read.tests to be changed: backslashes - escaping IFS whitespace characters at the end of input cause the - whitespace characters to be preserved in the value assigned to the - variable, and the trailing non-whitespace field delimiter issue - - 3/7 - --- -configure.in - - add -D_POSIX_SOURCE to the LOCAL_CFLAGS for Interix - - 3/8 - --- -bashline.c - - make bash_directory_expansion a void function, since it doesn't have - any return value - - 3/9 - --- -builtins/read.def - - when testing for a pipe, use `fd' instead of hard-coding 0, since we - can read from other file descriptors now - -lib/sh/zread.c - - in zsyncfd, only set lind and lused to 0 if the lseek succeeds. - If the lseek fails, we might steal input from other programs, but - a failed lseek won't cause us to erroneously discard input - - 3/11 - ---- -builtins/evalstring.c - - don't allow parse_and_execute to short-circuit and call exec() if - the command's return value is being inverted - - 3/15 - ---- -builtins/printf.def - - new macro PC to call putchar and increment number of chars printed - - fixes bug in computation of value for %n format char - - `tw' is now a global var so printstr can modify it using PC() - - convert PF macro to use asprintf into a local buffer - Preparation for printf -v var - - add code to add the text printed to a `variable buffer' if -v option - supplied. The buffer grows as needed - - printf now takes a `-v var' option to put the output into the variable - VAR rather than sending it to stdout. It does not: - print partial output on error (e.g., format string error) - handle NULs in the variable value, as usual - - 3/16 - ---- -parse.y - - fix bug in prompt string decoding that caused a core dump when PS1 - contained \W and PWD was unset (null pointer deref) - -builtins/printf.def - - changed -v var behavior so it stores partial output into the named - variable upon an error - - 3/24 - ---- -lib/readline/bind.c - - bool_to_int now takes a `const char *' argument - -support/{printenv,recho,zecho}.c - - include config.h - - include "bashansi.h" for appropriate extern function declarations - -configure.in - - on MacOS X 10.4, compensate for loader not allowing static library - to override existing system dynamic library when compiling -dynamic - (affects readline and history libraries); so use absolute pathname - instead of -lreadline as library name - -lib/glob/{glob,sm_loop,smatch}.c - - make sure to cast arguments to (char *) or (unsigned char *) as - appropriate to avoid gcc4 warnings - -lib/glob/smatch.c - - collsym (single-byte version) now takes a (CHAR *) first argument to - match callers; cast argument to strncmp appropriately - -lib/sh/snprintf.c - - fix ldfallback and dfallback to handle width and precision specs in - the format passed to sprintf() - - fix STAR_ARGS macro to deal with negative field widths and precisions - - 3/25 - ---- -builtins/printf.def - - since a negative precision in a "x.x[fFgGeE]" format specifier should - be allowed but treated as if the precision were missing, let it - through - -lib/sh/snprintf.c - - fix * code to deal with a negative precision by treating it as if - the `.' and any digit string in the precision had not been specified - - fix format parsing code to deal with a negative inline precision, - e.g., "%4.-4f" by treating it as if the `'. and any digit string in - the precision had not been specified - - a `+' in a format specifier should only act as a flag if it comes - before a `.' (otherwise it is ignored) - -lib/readline/vi_mode.c - - new function, rl_vi_rubout, to rl_rubout as rl_vi_delete is to - rl_delete; saves deleted text for possible reinsertion as with any - vi-mode `text modification' command (fixes problem with `X' reported - by beat.wieland@gmx.ch) - -lib/readline/vi_keymap.c - - bind `X' in vi command mode to rl_vi_rubout - -lib/readline/funmap.c - - add a bindable `vi-rubout' command, runs rl_vi_rubout - -lib/readline/text.c - - rewrote internals of _rl_rubout_char to make structure cleaner - -lib/readline/{complete,text}.c - - changed code to remove #ifdef HANDLE_MULTIBYTE where possible - - 3/28 - ---- -lib/readline/examples/rl.c - - include instead of posixstat.h if READLINE_LIBRARY not - defined - -subst.c - - fix mbstrlen to treat invalid multibyte sequences as sequences of - single-byte characters - - 4/8 - --- -configure.in - - default SIZE to `:' if cross-compiling and an appropriate size for - the target is not found - - 4/11 - ---- -subst.c - - change match_upattern and match_wpattern to check whether or not the - supplied pattern matches anywhere in the supplied string, prefixing - and appending the pattern with `*' if necessary. If it doesn't we - can short-circuit immediately rather than waste time doing up to - N-1 unsuccessful calls to strmatch/wcsmatch (which kills for long - strings, even if the pattern is short) - - 4/12 - ---- -configure.in - - make sure the special case for MacOS X 10.4 only kicks in if the - `--with-installed-readline' option isn't supplied - -lib/readline/{callback,readline,signals}.c - - make sure rl_prep_term_function and rl_deprep_term_function aren't - dereferenced if NULL (as the documentation says) - -builtins/mkbuiltins.c - - don't bother with the special HAVE_BCOPY code; just use straight - assignments - -builtins/ulimit.def - - use _POSIX_PIPE_BUF in pipesize() if it's defined and PIPE_BUF is - not - - 4/13 - ---- -execute_cmd.c - - add cm_function_def to the list of control structures for which - child processes are forked when pipes come in or out - - 4/14 - ---- -builtins/read.def - - make sure the ^As added for internal quoting are not counted as - characters read when -n is supplied - - 4/20 - ---- -redir.c - - fix redir_open so that the repeat open on failure that AFS support - adds restores the correct value of errno for any error message - - 4/26 - ---- - -Makefile.in - - make sure mksignames and mksyntax are invoked with the $(EXEEXT) - extension - - 4/28 - ---- -lib/readline/readline.h - - new state variable: RL_STATE_CALLBACK, means readline is using the - callback interface - -lib/readline/callback.c - - set RL_STATE_CALLBACK in rl_callback_handler_install, unset in - rl_callback_handler_remove - - 4/29 - ---- -config-top.h - - DONT_REPORT_SIGPIPE is now on by default, since it apparently - interferes with scripts - -configure.in - - arrange things so PGRP_PIPE is defined on Linux-2.4+ and version 3 - kernels (ones that apparently schedule children to run before their - parent) - - 4/30 - ---- -builtins/caller.def - - add call to no_options, so it can handle `--' option - -doc/{bash.1,bashref.texi} - - note explicitly that test, :, true, and false don't understand -- - as meaning the end of options - - 5/7 - --- -support/shobj-conf - - darwin 8 needs the same LDFLAGS setting as darwin 7 - -parse.y - - in save_parser_state, make sure we cast the return value from - xmalloc() to the right type - - remove casts to (char *) in calls to yyerror() - -lib/readline/signals.c - - make SIGQUIT and SIGALRM code conditional on their definition - - use raise() to send a signal if we don't have kill() - -lib/readline/display.c - - some MS-DOS and MINGW changes from the cygwin and mingw folks - -config.h.in - - add HAVE_PWD_H for - - add HAVE_FCNTL, HAVE_KILL for respective system calls - - add HAVE_GETPW{ENT,NAM,UID} for passwd functions - -configure.in - - add check for - - add checks for fcntl, kill system calls - - add checks for getpw{ent,nam,uid} C library functions - - pass a flag indicating we're cross compiling through to - CFLAGS_FOR_BUILD in Makefile.in - -lib/readline/complete.c - - guard inclusion of with HAVE_PWD_H - - don't provide a missing declaration for getpwent if we don't have it - - guard calls to {get,end}pwent with HAVE_GETPWENT - -lib/readline/shell.c - - guard inclusion of with HAVE_PWD_H - - guard inclusion of with HAVE_FCNTL_H - - don't provide a missing declaration for getpwuid if we don't have it - - guard calls to getpwuid with HAVE_GETPWUID - - don't bother with body of sh_unset_nodelay_mode if we don't have - fcntl - -lib/tilde/tilde.c - - guard inclusion of with HAVE_PWD_H - - guard calls to getpw{nam,uid} with HAVE_GETPW{NAM,UID} - - guard calls to {get,end}pwent with HAVE_GETPWENT - -Makefile.in,builtins/Makefile.in - - @CROSS_COMPILE@ is substituted into CFLAGS_FOR_BUILD (equal to - -DCROSS_COMPILING if bash is being cross-compiled) - - 5/9 - --- -aclocal.m4 - - print version as `0.0' in RL_LIB_READLINE_VERSION if the - `rl_gnu_readline_p' variable isn't 1 (accept no imitations) - - 5/11 - ---- -lib/readline/rlprivate.h - - definition of a readline `search context', to be use for incremental - search initially and other types of search later. Original from - Bob Rossi as part of work on incremental searching problems when - using callback interface - -lib/readline/isearch.c - - functions to allocate and free search contexts - - function to take a search context and a character just read and - `dispatch' on it: change search parameters, add to search string, - search further, etc. - - isearch is now completely context-driven: a search context is - allocated and passed to the rest of the functions - - 5/12 - ---- -lib/readline/isearch.c - - an additional `isearch cleanup' function that can be called from - the callback interface functions when the search is to be terminated - - an additional `isearch callback' function that can be called from - rl_callback_read_char when input is available - - short-circuit from rl_search_history after initialization if - the callback interface is being used - -lib/readline/callback.c - - in rl_callback_read_char(), if RL_STATE_ISEARCH is set, call - _rl_isearch_callback to read the character and dispatch on it. - If RL_STATE_ISEARCH is unset when that call returns, and there is - input pending, call rl_callback_read_char() again so we don't - have to wait for new input to pick it up - -support/shobj-conf,configure.in - - add support for dragonfly bsd, the same as freebsd - - 5/13-5/15 - --------- -lib/readline/callback.c - - support for readline functions to `register' a function that will - be called when more input is available, with a generic data - structure to encapsulate the arguments and parameters. Primarily - intended for functions that read a single additional character, - like quoted-insert - - support for callback code reading numeric arguments in a loop, - using readline state and an auxiliary variable - - support for callback code performing non-incremental searches using - the same search context struct as the isearch code - -lib/readline/{callback,display}.c - - if a callback function sets `_rl_redisplay_wanted', the redisplay - function will be called as soon as it returns - -lib/readline/input.c - - changes to _rl_read_mbchar to handle reading the null multibyte - character and translating it into '\0' - -lib/readline/misc.c - - break rl_digit_loop() into component functions that can be called - individually from the callback code more easily - - share some of the functions with rl_digit_loop1() in vi_mode.c - -lib/readline/readline.h - - change the version #defines to reflect readline 5.1 - -lib/readline/search.c - - break code into smaller functions that can be composed to work with - the callback code more easily - -lib/readline/text.c - - in rl_quoted_insert(), don't mess around with the tty signals if - running in `callback mode' - -lib/readline/vi_mode.c - - changed set-mark, goto-mark, change-char, and char-search to work - when called by callback functions - - 5/17 - ---- - -lib/readline/rlprivate.h - - new struct declaration for a `reading key sequence' context - -lib/readline/readline.c - - new variable, _rl_dispatching_keymap, keeps track of which keymap - we are currently searching - - functions to allocate and deallocate contexts for reading multi-char - key sequences - - 5/18 - ---- -lib/readline/rlprivate.h - - new struct defining a context for multiple-key key sequences (the - base case is escape-prefixed commands) - -lib/readline/readline.c - - change structure of _rl_dispatch_subseq to allow for callback code - to use it - rudimentary support for supporting the existing - recursion using a stack of contexts, each with a reference to the - previous - - fix so that ^G works when in callback mode - -lib/readline/callback.c - - call the appropriate multiple-key sequence callback if the state is - set - - 5/19 - ---- -lib/readline/readline.c - - broke code from _readline_internal_char after call to rl_dispatch - out into separate function: _rl_internal_char_cleanup, callable by - other parts of the code - - change _rl_internal_char_cleanup to unset _rl_want_redisplay after - it calls (*rl_redisplay_func) - -lib/readline/callback.c - - call _rl_internal_char_cleanup from rl_callback_read_char when - appropriate - - 5/24 - ---- -lib/readline/callback.c - - use _rl_dispatch_callback and a chain of _rl_keyseq_contexts to - simulate the recursion used to decode multicharacter key sequences - (even things like ESC- as meta-prefix) - - call setjmp in rl_callback_read_char to give things like rl_abort - a place to jump, since the saved location in readline() will not - be valid - - keep calling _rl_dispatch_callback from rl_callback_read_char while - we are still decoding a multi-key key sequence - - keep calling readline_internal_char from rl_callback_read_char while - we are reading characters from a macro - -lib/readline/macro.c - - use a slightly different strategy upon encountering the end of a macro - when using the callback interface: when the last character of a - macro is read, and we are reading a command, pop the macro off the - stack immediately so the loop in rl_callback_read_char terminates - when it should - -lib/readline/readline.c - - if longjmp() is called and we end up at the saved location while - using the callback interface, just return -- don't go back into a - blocking read - - new function to dispose a chain of rl_keyseq_cxts - - only read new input in _rl_dispatch_callback if the KSEQ_DISPATCHED - flag is not set in the current keyseq context -- if it is, we are - traversing the chain back up and should use what we already saved - - use -3 as a magic value from _rl_dispatch_subseq to indicate that - we're allocating a new context and moving downward in the chain - (a special return value for the benefit of _rl_dispatch_callback) - -lib/readline/rlprivate.h - - new extern declaration for _rl_keyseq_chain_dispose - - 6/1 - --- -builtins/read.def - - fixed a bug that occurred when reading a set number of chars and - the nth char is a backslash (read one too many). Bug reported by - Chris Morgan - -execute_cmd.c - - fix execute_builtin so the `unset' builtin also operates on the - temporary environment in POSIX mode (as well as source and eval), - so that unsetting variables in the temporary environment doesn't - leave them set when unset completes. Report by Eric Blake - - -array.c - - fix from William Park for array_rshift when shifting right on an - empty array -- corrects calculation of array->max_index - -builtins/exec.def - - if an exec fails and the execfail option is set, don't call - restart_job_control unless the shell is interactive or job_control - is set - -jobs.c - - add a run-time check for WCONTINUED being defined in header files - but rejected with EINVAL by waitpid(). Fix from Maciej Rozycki - - - 6/20 - ---- -bashhist.c - - make sure calls to sv_histchars are protected by #ifdef BANG_HISTORY - - ditto for calls to history_expand_line_internal - - 6/23 - ---- -doc/bashref.texi - - remove extra blank lines in @menu constructs - -variables.c - - assign export_env to environ (extern char **) every time it changes - (mostly in add_to_export_env define), so maybe getenv will work on - systems that don't allow it to be replaced - - 6/29 - ---- -bashline.c - - in bash_directory_completion_hook, be careful about not turning `/' - into `//' and `//' into `///' for benefit of those systems that treat - `//' as some sort of `network root'. Fix from Eric Blake - - -lib/readline/complete.c - - in to_print, do the right thing after stripping the trailing slash - from full_pathname: // doesn't turn into /, and /// doesn't become - //. Fix from Eric Blake - - 6/30 - ---- -lib/malloc/trace.c - - include if it's available for a definition of size_t - -jobs.c - - in wait_for, if a child process is marked as running but waitpid() - returns -1/ECHILD (e.g., when the bash process is being traced by - strace), make sure to increment c_reaped when marking the child as - dead - - in without_job_control, make sure to close the pgrp pipe after - calling start_pipeline - - 7/1 - --- -Makefile.in - - only remove pathnames.h when the other files created by running - configure are removed (e.g., Makefile). Fix from William Park - -lib/sh/shquote.c - - since backslash-newline disappears when within double quotes, don't - add a backslash in front of a newline in sh_double_quote. Problem - reported by William Park - -jobs.c - - in notify_of_job_status, don't print status messages about - terminated background processes unless job control is active - -bashhist.c - - new variable, hist_last_line_pushed, set to 0 in really_add_history - (used by `history -s' code) - -bashhist.h - - new extern declaration for history -s - -builtins/history.def - - don't remove last history entry in push_history if it was added by - a call to push_history -- use hist_last_line_pushed as a sentinel - and set it after adding history entry. This allows multiple - calls to history -s to work right: adding all lines to the history - rather than deleting all but the last. Bug reported by Matthias - Schniedermeyer - - pay attention to hist_last_line_pushed in expand_and_print_history() - so we don't delete an entry pushed by history -s - - 7/4 - --- -print_cmd.c - - fix print_arith_for_command to not print so many blanks between - expressions in ((...)) - -command.h - - new word flag: W_DQUOTE. Means word should be treated as if double - quoted - -make_cmd.c - - add W_DQUOTE to word flags in make_arith_for_expr - -parse.y - - add W_DQUOTE to word flags for (( ... )) arithmetic commands - -subst.c - - don't perform tilde expansion on a word with W_DQUOTE flag set - - don't perform process substitution on a word with W_DQUOTE flag set - -arrayfunc.c - - expand an array index within [...] the same way as an arithmetic - expansion between (( ... )) - -lib/readline/input.c - - use getch() instead of read() on mingw - -lib/readline/readline.c - - add a few key bindings for the arrow keys on mingw - -lib/readline/rldefs.h - - if on mingw, define NO_TTY_DRIVER - -lib/readline/rltty.c - - compile in the stub functions for _rl_{disable,restore}_tty_signals - if on mingw - - compile in stub function for rl_restart_output on mingw - - make sure enough functions and macros are defined to compile if - NO_TTY_DRIVER is defined (lightly tested - builds on MacOS X, at - least) - - 7/7 - --- -command.h - - add a `flags' member to the PATTERN_LIST structure - -make_cmd.c - - intialize the `flags' member of a PATTERN_LIST when it's created - -builtins/psize.c - - protect extern declaration of errno with usual #ifdef errno - -configure.in, variables.c - - changes for QNX 6.x - - 7/9 - --- -parse.y - - fix parse_matched_pair to handle single and double quoted strings - inside old-style command substitution (``) since they can each - quote the ` and embedded $-expansions. Report by Eric Blake - - -{configure,Makefile}.in - - TILDE_LIB is now substituted into Makefile by configure - -configure.in - - if configuring --with-installed-readline on cygwin, set TILDE_LIB - to the empty string to avoid multiply-defined symbols. Cygwin - doesn't allow undefined symbols in dynamic libraries. Report by - Eric Blake - - 7/11 - ---- -input.c - - in duplicate_buffered_stream, don't call free_buffered_stream if the - two buffered streams share the same b_buffer object (e.g., if they - had already been duplicated with a previous call). Fixes Debian bug - reported by eero17@bigfoot.com - - 7/12 - ---- -shell.c - - make set_shell_name more resistant to a NULL argument - - in bind_args, use < instead of != when counting the arguments and - making the arg list - - in main(), make sure arg_index is not initialized to a value greater - than argc - - 7/14 - ---- -lib/readline/display.c - - in expand_prompt, don't set the location of the last invisible - char if the sequence is zero length (\[\]) - - 7/15 - ---- -doc/{bash.1,bashref.texi} - - document that the shell uses $TMPDIR when creating temporary files - - 7/20 - ---- -[bash-3.1-alpha1 frozen] - - 7/29 - ---- -builtins/evalstring.c - - make sure that parse_and_execute saves and restores the value of - loop_level, so loops in sourced scripts and eval'd strings don't - mess up the shell's parser state - -bashline.c - - change command_subst_completion_function to suppress appending - any character to a unique completion, instead of a space, unless - the last word in the quoted command substitution completes to a - directory name. In that case we append the expected slash - - 8/1 - --- -builtins/printf.def - - make sure variables are initialized if their values are tested later - -[bash-3.1-alpha1 updated and re-frozen] - - 8/2 - --- -variables.c - - make sure to call stifle_history with an `int' instead of an intmax_t. - Sometimes it makes a difference - - 8/3 - --- -[bash-3.1-alpha1 released] - -support/mksignames.c - - add `SIGSTKFLT' (RHE3) - - add `SIGXRES' (Solaris 9) - - 8/4 - --- -builtins/ulimit.def - - fix typo to make `x' the right option for locks - - add new options to short help synopsis - -variables.c - - use get_variable_value instead of direct reference to value_cell - in make_variable_value when appending to the current value, so - references to array variables without subscripts will be equivalent - to element 0 - -lib/readline/text.c - - rewrote rl_change_case to correctly change the case of multibyte - characters where appropriate - - 8/5 - --- -configure.in - - remove call to obsolete macro AC_ACVERSION - - remove special calls to AC_CYGWIN and AC_MINGW32; AC_CANONICAL_HOST - takes care of those cases - -general.h - - include `chartypes.h' for definition of ISALPHA - - fix definitions of ABSPATH and RELPATH for cygwin - - fix definition of ISDIRSEP for cygwin to allow backslash as a - directory name separator - - 8/9 - --- -builtins/setattr.def - - when setting a variable from the temporary environment in - set_var_attribute (e.g., `LC_ALL=C export LC_ALL'), make sure to - call stupidly_hack_special_variables after binding the variable in - the current context - -builtins/printf.def - - make sure to call stupidly_hack_special_variables if using `printf -v' - to put formatted output in a shell variable - - 8/11 - ---- -support/shobj-conf - - new variable: SHLIB_LIBPREF, prefix for shared library name (defaults - to `lib' - - new variable: SHLIB_DLLVERSION, used on Cygwin to set the library - version number - - new variable: SHLIB_DOT, separator character between library name and - suffix and version information (defaults to `.') - - new stanza for cygwin to generate windows-compatible dll - - 8/14 - ---- -variables.c - - new special variable function for Cygwin, so the export environment - is remade when HOME is changed. The environment is the only way to - get information from the shell to cygwin dlls, for instanace, when - bash is compiled to use an already-installed libreadline - -variables.h - - new extern declaration for sv_home - - 8/15 - ---- -lib/readline/display.c - - call init_line_structures from rl_redisplay if vis_lbreaks == 0 - to avoid consequences of a poorly-timed SIGWINCH - - 8/16 - ---- -subst.c - - fix logic for performing tilde expansion when in posix mode (don't - rely on W_TILDEEXP flag always being set, because it won't be when - expanding the RHS of assignment statement). Use W_TILDEEXP only - when deciding to expand a word marked as W_ASSIGNMENT that doesn't - precede a command name - - 8/17 - ---- -execute_cmd.c - - in execute_function, when subshell == 1, don't short-cut by using - the command contained in the group command -- if you do, any - redirections attached to the group command (function) don't get - executed - -general.h - - new #define, FS_READABLE, indicates file is readable by current - user - -findcmd.c - - rewrote file_status to use S_xxx POSIX file mode bits and to add - support for FS_READABLE (affects ./source and searching $PATH for - scripts whose names are supplied as arguments on the command line) - - change find_path_file to look for readable files -- source requires - it - - change find_in_path_element to do the right thing when FS_READABLE - is supplied as a flag - -doc/bashref.texi - - remove note about posix non-compliance in `.': we now require and - look for readable files when searching $PATH - - 8/20 - ---- -subst.c - - fix setifs to handle case where passed variable is non-zero but - v->value == 0 (as in an unset local variable); treat IFS as unset - in this case - -jobs.c - - in kill_pid, if asked to killpg a process or pgrp whose pgrp is - recorded as the same as the shell's, just call killpg and let the - chips fall where they may -- there may be other processes in that - pgrp that are not children of the shell, so killing each process - in the pipeline will not do a complete job, and killpg'ing each - such process will send too many signals in the majority of cases - -builtins/cd.def - - in posix mode, pwd needs to check that the value it prints and `.' - are the same file - -builtins/read.def - - if reading input from stdin in a non-interactive shell and calling - `read', call sync_buffered_stream to seek backward in the input - stream if necessary (XXX - should we do this for all shell builtins?) - - 8/23 - ---- -builtins/cd.def - - in posix mode, if canonicalization of the absolute pathname fails - because the path length exceeds PATH_MAX, but the length of the passed - (non-absolute) pathname does not, attempt the chdir, just as when - not in posix mode - -builtins/type.def - - don't have describe_command call sh_makepath if the full path found - is already an absolute pathname (sh_makepath will stick $PWD onto the - front of it) - - 8/24 - ---- - -jobs.c - - in posix mode, don't have start_job print out and indication of - whether the job started by `bg' is the current or previous job - - change start_job to return success if a job to be resumed in the - background is already running. This means that bg won't fail when - asked to bg a background job, as SUSv3/XPG6 requires - - new function, init_job_stats, to zero out the global jobstats struct - -{jobs,nojobs}.c - - change kill_pid to handle pids < -1 by killing process groups - -jobs.h - - extern declaration for init_job_stats - -lib/readline/history.c - - check whether or not the history list is null in remove_history - -builtins/history.def - - delete_last_history is no longer static so fc builtin can use it - -builtins/fc.def - - use free_history_entry in fc_replhist instead of freeing struct - members individually - - call delete_last_history from fc_replhist instead of using inline - code - - if editing (-l not specified), make sure the fc command that caused - the editing is removed from the history list, as POSIX specifies - -builtins/kill.def - - just call kill_pid with any pid argument and let it handle pids < -1 - This is the only way to let kill_pid know whether a negative pid or - a job spec was supplied as an argument to kill - -builtins/fg_bg.def - - force fg_bg to return EXECUTION_SUCCESS explicitly if called by bg - and start_job returns successfully - - bg now returns success only if all the specified jobs were resumed - successfully - -execute_cmd.c - - call init_job_stats from initialize_subshell to zero out the global - job stats structure - - 8/25 - ---- -bashline.c - - change vi_edit_and_execute_command to just call vi when in posix - mode, instead of checking $FCEDIT and $EDITOR - -lib/readline/search.c - - if in vi_mode, call rl_free_undo_list in make_history_line_current - to dispose of undo list accumulated while reading the search string - (if this isn't done, since vi mode leaves the current history - position at the entry which matched the search, the call to - rl_revert_line in rl_internal_teardown will mangle the matched - history entry using a bogus rl_undo_list) - - call rl_free_undo_list after reading a non-incremental search string - into rl_line_buffer -- that undo list should be discarded - -lib/readline/rlprivate.h - - add UNDO_LIST * member to search context struct - -lib/readline/isearch.c - - initialize UNDO_LIST *save_undo_list member of search context struct - - 8/27 - ---- -lib/readline/bind.c - - change rl_parse_and_bind to strip whitespace from the end of a - variable value assignment before calling rl_variable_bind - -doc/bash.1,lib/readline/doc/{rluser.texi,readline.3} - - clarified the language concerning parsing values for boolean - variables in assignment statements - - 8/28 - ---- -lib/sh/pathphys.c - - fix small memory leak in sh_realpath reported by Eric Blake - - 8/31 - ---- -doc/bashref.texi - - add additional notes to posix mode section - - 9/3 - --- -parse.y - - if $'...' occurs within a ${...} parameter expansion within - double quotes, don't single-quote the expanded result -- the double - quotes will cause it to be expanded incorrectly - - 9/4 - --- -builtins/fc.def - - if STRICT_POSIX is defined, the posix mode default for the editor to - use is $FCEDIT, then ed - -shell.c - - if STRICT_POSIX is defined, initialize `posixly_correct' to 1 - -config.h.in - - add #undef STRICT_POSIX - - 9/5 - --- -configure.in - - add new option argument, --enable-strict-posix-default, configures - bash to be posix-conformant (including defaulting echo to posix - conformance) by default - -builtins/echo.def - - if STRICT_POSIX is defined, default echo to xpg-style - -doc/bashref.texi - - describe the --enable-strict-posix-default option to configure - - 9/10 - ---- -builtins/mkbuiltins.c - - change to not generate N_(""), because the translated empty string is - special to GNU gettext - - 9/13 - ---- -lib/readline/complete.c - - a negative value for rl_completion_query_items means to not ask - -lib/readline/doc/{{rltech,rluser}.texi,readline.3} - - documented new semantics for rl_completion_query_items/ - completion-query-items - - 9/14 - ---- -bashline.c - - bind M-TAB in emacs mode to dynamic-complete-history even if the - current binding is `tab-insert' (which is what it is by default), - not just if it's unbound - - 9/15 - ---- -eval.c - - call QUIT before calling dispose_command on current_command after - the `exec_done' label. If we dispose current_command first, the - longjmp might restore the value of current_command after we've - disposed it, and the subsequent call to dispose_command from the - DISCARD case will free memory twice - - 9/16 - ---- -lib/sh/strto[iu]max.c - - make sure the function being declared is not a cpp define before - defining it -- should fix problems on HP-UX - - 9/19 - ---- -Makefile.in - - make sure the binaries for the tests are at the front of $PATH - - 9/22 - ---- -parse.y - - new flag for parse_matched_pair: P_COMMAND, indicating that the - text being parsed is a command (`...`, $(...)) - - change calls to parse_matched_pair to include P_COMMAND where - appropriate - - if P_COMMAND flag is set and the text is unquoted, check for comments - and don't try to parse embedded quoted strings if in a comment (still - not exactly right yet) - - 9/24 - ---- -builtins/history.def - - if running history -n, don't count these new lines as history lines - for the current session if the `histappend' shell option is set. - If we're just appending to the history file, the issue that caused - history_lines_this_session to be recalculated doesn't apply -- the - history file won't be missing any entries - -lib/readline/isearch.c - - fix C-w handler for isearch string reader to handle multibyte chars - -lib/readline/rlmbutil.h - - new defines for _rl_to_wupper and _rl_to_wlower - -lib/readline/text.c - - use _rl_to_wupper and _rl_to_wlower as appropriate - - 9/26 - ---- -execute_cmd.c - - in shell_execve, if the exec fails due to E2BIG or ENOMEM, just print - the appropriate error message instead of checking out any interpreter - specified with #! - - 9/30 - ---- -bashhist.c - - make $HISTCMD available anytime remember_on_history is non-zero, - which indicates that we're saving commands to the history, and - let it evaluate to 1 if we're not - - 10/4 - ---- -lib/sh/snprintf.c - - in floating(), make sure d != 0 before calling chkinfnan -- gcc on the - version of Solaris 9 I have translates 0 to -inf on the call - -[bash-3.1-beta1 frozen] - - 10/6 - ---- -jobs.c - - set the_pipeline to NULL right away in cleanup_the_pipeline, and - dispose a copy of the pointer so we don't mess with the_pipeline - while we're in the process of destroying it - - block and unblock SIGCHLD around manipulating the_pipeline in - cleanup_the_pipeline - - 10/7 - ---- -[bash-3.1-beta1 released] - -lib/readline/isearch.c - - when switching directions, make sure we turn off the SF_REVERSE - flag in the search context's flags word if we're going from reverse - to forward i-search - -lib/readline/bind.c - - new function, rl_variable_value, returns a string representing a - bindable readline variable's value - - new auxiliary function, _rl_get_string_variable_value, encapsulates - everything needed to get a bindable string variable's value - - rewrote rl_variable_dumper to use _rl_get_string_variable_value - -lib/readline/readline.h - - new extern declaration for rl_variable_value - -lib/readline/doc/rltech.texi - - documented rl_variable_value - -bashline.c - - in command_word_completion_function, if readline sets - rl_completion_found_quote, but doesn't set rl_completion_quote_character, - we have an embedded quoted string or backslash-escaped character in - the passed text. We need to dequote that before calling - filename_completion_function. So far, this is in place only for - absolute program names (those containing a `/') - - in command_word_completion_function, use rl_variable_value to decide - whether or not we should ignore case, and use strncasecmp instead of - strncmp where appropriate - - 10/11 - ----- -builtins/fc.def - - fixed a typo when using POSIX_FC_EDIT_COMMAND - -redir.h - - new flag values for redirections: RX_INTERNAL and RX_USER (currently - unused) - -redir.c - - add_undo_redirect and add_undo_close_redirect now set RX_INTERNAL - flag when making new redirects - - in do_redirection_internal, only set file descriptors > 2 to CLEXEC - if they're marked as RX_INTERNAL - - 10/12 - ----- -jobs.c - - in wait_for_single_pid, if in posix mode, remove the waited-for pid - from the list of background pids, forgetting it entirely. POSIX - conformance tests test for this. - -lib/readline/{readline.h,vi_mode.c} - - new state flag, RL_STATE_VICMDONCE, set after entering vi command - mode the first time; reset on each call to readline() - - 10/13 - ----- -lib/readline/undo.c - - in rl_revert_line, make sure that revert-line in vi mode leaves - rl_point set to 0 no matter the state of the line buffer - -lib/readline/vi_mode.c - - when entering vi_command mode for the first time, free any existing - undo list so the previous insertions won't be undone by the `U' - command. This is how POSIX.2 says `U' should work (and the test - suite tests for it) - -lib/readline/bind.c - - change rl_parse_and_bind so only `set' commands involving boolean - readline variables have trailing whitespace stripped from the value - string - - 10/16 - ----- -lib/glob/sm_loop.c - - fix patscan() to correctly scan backslash-escaped characters - - 10/18 - ----- -lib/sh/{winsize.c,Makefile.in},{jobs,nojobs}.c,Makefile.in,externs.h - - moved get_new_window_size from jobs.c/nojobs.c to new file, - lib/sh/winsize.c, made function global - -{jobs,nojobs,sig}.c,{jobs,sig}.h - - moved SIGWINCH handling code to sig.c rather than duplicate it in - jobs.c and nojobs.c - - call set_sigwinch_handler from sig.c code rather than job control - signal initialization - -sig.[ch] - - new variable, sigwinch_received, acts like interrupt_state for - SIGWINCH, set by sigwinch_sighandler. sigwinch_sighandler no longer - calls get_new_window_size - -parse.y - - add call to get_new_window_size if sigwinch_received at top of - shell_getc - - 10/19 - ----- -lib/malloc/malloc.c - - to avoid orphaning memory on free if the right bucket is busy, use a - new function xplit(mem, bucket) to split the block into two or more - smaller ones and add those to the right bucket (appropriately marking - it as busy) - - audit bsplit(), bcoalesce(), and xsplit() for proper use of busy[], - since they're dealing with two separate buckets - - 10/22 - ----- -subst.c - - new flag for string_extract: EX_REQMATCH, means to return an error - if a matching/closing character is not found before EOS - - new static flag variables: extract_string_error and extract_string_fatal - - change expand_word_internal to check for new error returns from - string_extract and return errors if appropriate - - 10/23 - ----- -builtins/cd.def - - make sure we free TDIR in change_to_directory after calling - set_working_directory (which allocates new memory) and other places - we short-circuit and return - - 10/24 - ----- -subst.c - - modified fix from 10/22 to allow bare ` to pass through (for - some backwards compatibility and more correctness) - - 10/27 - ----- -conftypes.h - - make MacOS X use the RHAPSODY code that gets HOSTTYPE, et al. - at build rather than configure time, to support universal binaries - (fix from llattanzi@apple.com) - - 10/30 - ----- -builtins/evalstring.c - - make sure we don't turn on CMD_NO_FORK in parse_and_execute if - we're running a trap command on signal receipt or exit - -execute_cmd.c - - in shell_execve, improve the error message a little bit if the - interpreter name in a #! exec header ends with a ^M (as in a DOS- - format file) - - 11/1 - ---- -lib/readline/vi_mode.c - - fix vi-mode `r' command to leave the cursor in the right place - -[bash-3.1-rc1 frozen] - - 11/5 - ---- -execute_cmd.c - - make sure a DEBUG trap doesn't overwrite a command string passed to - make_child in execute_simple_command - -bashline.c - - rearrange some code in bash_quote_filename so filenames with leading - tildes containing spaces aren't tilde-expanded before being - returned to the caller - - 11/6 - ---- -lib/readline/display.c - - when deciding where to move the cursor in rl_redisplay and needing - to move the cursor back after moving it vertically and compensate - for invisible characters in the prompt string, make sure that - _rl_last_c_pos is treated as an absolute cursor position in a - multibyte locale and the wrap offset (number of invisible characters) - is added explicitly when deciding how many characters to backspace - - 11/10 - ----- -lib/readline/terminal.c - - _rl_set_screen_size now interprets a lines or columns argument < 0 - as an indication not to change the current value - - 11/11 - ----- - -lib/readline/terminal.c - - new function, rl_reset_screen_size, calls _rl_get_screen_size to - reset readline's idea of the terminal size - - don't call _rl_get_screen_size in _rl_init_terminal_io if both - _rl_screenheight and _rl_screenwidth are > 0 - - don't initialize _rl_screenheight and _rl_screenwidth to 0 in - _rl_init_terminal_io; let caller take care of it - - set _rl_screenheight and _rl_screenwidth to 0 before calling - _rl_init_terminal_io - -lib/readline/readline.h - - new extern declaration for rl_reset_screen_size - -lib/readline/doc/rltech.texi - - documented rl_reset_screen_size - -variables.c - - if readline is being used, compile in a special var function for - assignments to LINES and COLUMNS that calls rl_set_screen_size or - rl_reset_screen_size as appropriate. Only do this in posix mode - and only when STRICT_POSIX is defined at compile time - - new semaphore variable, winsize_assignment, set while doing an - assignment to LINES or COLUMNS - - new variable, winsize_assigned, says LINES or COLUMNS was assigned - to or found in the environment - - if in the middle of an assignment to LINES or COLUMNS, make - sh_set_lines_and_columns a no-op - -lib/sh/winsize.c - - get_new_window_size now takes two int * arguments, to return the - screen dimensions - -externs.h - - change extern declaration for get_new_window_size - -{jobs,nojobs}.c, parse.y - - change callers of get_new_window_size - - 11/12 - ----- -lib/readline/terminal.c - - new variable, rl_prefer_env_winsize, gives LINES and COLUMNS - precedence over values from the kernel when computing window size - -lib/readline/readline.h - - extern declaration for rl_prefer_env_winsize - -lib/readline/doc/rltech.texi - - document rl_prefer_env_winsize - - 11/13 - ----- -lib/readline/rltty.c - - change rl_prep_terminal to make sure we set and reset the tty - special characters in the vi insertion keymap if in vi mode. This - matters if we get accept-line for the previous line while in vi - command mode - - 11/14 - ----- -builtins/pushd.def - - make sure any call to cd_builtin includes a leading `--' from the - argument list (or constructs one) - - 11/16 - ----- -pcomplete.c - - fix small memory leak in gen_wordlist_matches - -[bash-3.1-rc2 frozen] - - 11/21 - ----- -[bash-3.1-rc2 released] - - 11/23 - ----- -lib/readline/display.c - - changes to rl_redisplay to compensate for update_line updating - _rl_last_c_pos without taking invisible characters in the line into - account. Important in multibyte locales where _rl_last_c_pos is an - absolute cursor position - - changes to _rl_move_cursor_relative to account for _rl_last_c_pos - being an absolute cursor position in a multibyte character locale - - rewrote _rl_move_cursor_relative to make it a little simpler - - 11/29 - ----- -lib/readline/display.c - - changes to rl_redisplay and update_line for update_line to communicate - upward that it took the number of invisible characters on the current - line into account when modifying _rl_last_c_pos - - in update_line, adjust _rl_last_c_pos by wrap_offset before calling - _rl_move_cursor_relative, so we pass correct information about the - true cursor position - - 12/1 - ---- -configure.in - - changed release status to `release' - -[bash-3.1 frozen] - - 12/8 - ---- -[bash-3.1 released] - - 12/9 - ---- -doc/{bash.1,version.texi},lib/readline/doc/version.texi - - remove `beta1' from man page footer and texinfo documents - -variables.c - - make sure winsize_assignment is protected by #ifdef READLINE, so - minimal shell will compile - -builtins/read.def - - make sure error cases free memory and run any unwind-protects to - avoid memory leaks - - 12/10 - ----- -execute_cmd.c - - change execute_command_internal to set $PIPESTATUS for ((...)) and - [[ ... ]] commands - -doc/{bash.1,bashref.texi,version.texi} - - add documentation for ulimit -[iqx] and bump revision date - - 12/12 - ----- -parse.y - - make sure parse_compound_assignment saves and restores the - PST_ASSIGNOK parser state flag around its calls to read_token. - Fixes bug reported by Mike Frysinger - - 12/13 - ----- -parse.y - - change parse_compound_assignment to save and restore the value of - last_read_token. Not sure why it was set unconditionally in the - first place after parsing the complete compound assignment - - 12/14 - ----- -lib/readline/text.c - - don't use return value of rl_kill_text (which always succeeds and - returns the number of characters killed) in rl_delete as an indication - of success or failure - - ditto for return value of rl_delete_text - -lib/readline/readline.c - - don't return the value of the called readline function as the return - value from _rl_dispatch_subseq; -1 means something different to the - callers (return 0 all the time to indicate that a readline function - was found and dispatched). Fix from Andreas Schwab for - bug in callback interface first reported by Mike Frysinger - -execute_cmd.c - - fixed a typo in execute_case_command - - 12/15 - ----- -aclocal.m4 - - add check for wctype() to BASH_CHECK_MULTIBYTE, define HAVE_WCTYPE - -config.h.in - - add HAVE_WCTYPE #define - -config-bot.h - - add HAVE_WCTYPE to the set of checks for HANDLE_MULTIBYTE. This - should catch the deficient NetBSD multibyte support - - 12/16 - ----- -parse.y - - use CTLESC instead of literal '\001' when decode_prompt_string - prefixes RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE - - 12/20 - ----- -lib/readline/display.c - - don't treat RL_PROMPT_START_IGNORE specially inside a sequence of - ignored characters - - keep track of the start of the current sequence of ignored - characters; make sure that an empty sequence of such characters - really is an empty sequence, not one that happens to end with '\001' - (RL_PROMPT_START_IGNORE) - - 12/21 - ----- -subst.c - - change expand_word_internal to process rest of `tilde-word' as a - regular part of the word if tilde expansion leaves the tilde-word - unchanged. This means that ~$USER expands to ~chet, which seems - more intuitive, and is effectively what bash-3.0 did - - 12/23 - ----- -subst.c - - when making a local array variable in do_compound_assignment, make - sure that we don't use a variable of the same name from a previous - context - -doc/bash.1 - - documented expansions for word and patterns in case statement - -builtins/ulimit.def,doc/{bashref.texi,bash.1} - - added new -e and -r (nice and rtprio) options to ulimit; documented - them - - 12/26 - ----- -variables.c - - use `hmax' instead of `num' in sv_histsize to avoid integer overflow - problems with intmax_t - -builtins/read.def - - add unwind-protect to restore rl_attempted_completion_function in - case of a timeout - -{bashline,variables}.c - - move initialization of HISTSIZE from initialization path to - load_history, so it can be overridden by a value assigned in a - startup file - -lib/readline/misc.c - - add a missing `return r' so that rl_digit_loop returns a meaningful - value - -lib/readline/{bind,callback,display,isearch,rltty,search,text,vi_mode}.c - - minor cleanups to satisfy compiler warnings, mostly removing unused - variables - - 12/27 - ----- -support/Makefile.in - - add LIBS_FOR_BUILD support; defaults to ${LIBS} - -Makefile.in - - add LIBS_FOR_BUILD with no default value; use when linking programs - using CC_FOR_BUILD (e.g., bashversion) - - 12/28 - ----- -lib/readline/bind.c - - fix rl_translate_keyseq bad translation of \M-\C-x sequences - -execute_cmd.c - - in execute_arith_command, if the expression expands to more than one - word, make sure we join the words into a single string and pass the - entire thing to evalexp() - -expr.c - - new functions: _is_arithop(c), returns true if C is a valid single- - character arithmetic operator; _is_multiop(c), returns true if C is - a token corresponding to a valid multi-character arithmetic operator - - if we encounter a character that isn't a valid arithmetic - operator, throw an error. Try to be intelligent about what type of - error message to print - -subst.c - - new function, expand_arith_string, calls expand_string_if_necessary; - used where an arithmetic expression needs to be expanded - -subst.h - - new extern declaration for expand_arith_string - -arrayfunc.c - - in array_expand_index, call expand_arith_string to expand the - subscript in a fashion consistent with other arithmetic expressions - -subst.c - - fix parameter_brace_patsub so that we don't try to anchor the pattern - at the beginning or end of the string if we're doing global - replacement -- that combination doesn't doesn't make sense, and - the changed behavior is compatible with ksh93 - -doc/{bash.1,bashref.texi} - - changed description of pattern substitution to match the new - semantics - -tests/new-exp.tests - - change tests to remove all ${pat//#rep} and ${pat//%rep} - expansions, since they don't mean the same thing anymore - - 12/29 - ----- -support/signames.c - - new file, initialize_signames() function from old mksignames.c. This - file builds the signal_names array - -support/mksignames.c - - strip out initialize_signames(), move to signames.c. This file only - writes signames.h - - set up to only write a stub signames.h if CROSS_COMPILING is defined, - with extern declaration for initialize_signames - - if not cross compiling, #define initialize_signames to nothing - -Makefile.in - - mksignames is now linked from mksignames.o and buildsignames.o - - add rules to build signames.o, assuming we're building it as part - of the shell (cross-compiling) - -trap.c - - call initialize_signames from initialize_traps - -configure.in - - set SIGNAMES_O to nothing (normal) or signames.o (cross-compiling), - substitute into Makefile - - don't set SIGNAMES_H if cross-compiling any more - - 12/30 - ----- -command.h - - new word flag: W_NOPROCSUB, inhibits process substitution on a word - -subst.c - - change expand_word_internal to suppress process substitution if the - word has the W_NOPROCSUB flag - -shell.c - - --wordexp turns on W_NOPROCSUB in addition to W_NOCOMSUB - -subst.c - - change string_list_dollar_at and string_list_dollar_star so that - MB_CUR_MAX is used to size an array only when using gcc, since gcc - can handle non-constant array sizes using a mechanism like alloca. - Other compilers, e.g. Sun's compiler, do not implement that - extension - - 12/31 - ----- -builtins/mkbuiltins.c - - when cross-compiling, don't include , since it's for the - target rather than the host system. Instead, choose a reasonable - set of default #defines based on a minimal POSIX system - -jobs.c - - change find_process to handle a NULL return value from find_pipeline - - return immediately from delete_job if jobs[index] is already NULL or - if it has a null pipeline associated with it - - in delete_job, if find_last_proc returns NULL, don't try to call - bgp_delete - - 1/7 - --- -doc/bash.1 - - patch from Tim Waugh to replace some literal single quotes with - \(aq, the groff special character for it - -jobs.c - - in realloc_jobs_list, make sure to zero out slots after j_lastj - in the new list - - 1/9 - --- -support/mksignames.c - - make sure to include to get right value of NSIG from - (usually) - - 1/10 - ---- -parse.y - - when calling parse_matched_pair on a $(...) command substitution, - don't pass the P_DQUOTE flag so that single quotes don't get - stripped from $'...' inside the command substitution. Bug report - and fix from Mike Stroyan - -jobs.c - - start maintaining true count of living children in js.c_living - - call reset_current in realloc_jobs_list, since old values for current - and previous job are most likely incorrect - - don't allocate a new list in realloc_jobs_list if the old size and - new size are the same; just compact the existing list - - make sure realloc_jobs_list updates value of js.j_njobs - - add some more itrace messages about non-null jobs after j_lastj in - jobs array - - 1/11 - ---- -bashjmp.h - - new value for second argument to longjmp: SIGEXIT. Reserved for - future use - - 1/12 - ---- -jobs.c - - add logic to make_child to figure out when pids wrap around - - turn second argument to delete_job into flags word, added flag to - prevent adding proc to bgpids list - - 1/13 - ---- -lib/readline/vi_mode.c - - move code that moves forward a character out of rl_vi_append_mode - into a separate function, _rl_vi_append_forward - - change _rl_vi_append_mode to save `a' as the last command, so it - can be redone properly - - new function _rl_vi_backup, moves point back a character taking - multibyte locales into account - - change rl_vi_redo to handle redoing an `a' command specially -- - it should be redone like `i' but after moving forward a character - - change rl_vi_redo to use _rl_vi_backup to move point backward - after redoing `i' or `a' - -jobs.c - - new function, delete_old_job (pid), checks whether or not PID is in - a job in the jobs list. If so, and the job is dead, it just removes - the job from the list. If so, and the job is not dead, it zeros - the pid in the appropriate PROCESS so pid aliasing doesn't occur - - make_child calls delete_old_job to potentially remove an already-used - instance of the pid just forked from the jobs list if pids have - wrapped around. Finally fixes the bug reported by Tim Waugh - - -trap.c - - new define, GETORIGSIG(sig), gets the original handling for SIG and - sets SIG_HARD_IGNORE if that handler is SIG_IGN - - call GETORIGSIG from initialize_traps, get_original_signal, and - set_signal - -jobs.c - - in wait_for, if the original SIGINT handler is SIG_IGN, don't set - the handler to wait_sigint_handler. This keeps scripts started in - the background (and ignoring SIGINT) from dying due to SIGINT while - they're waiting for a child to exit. Bug reported by Ingemar - Nilsson - -lib/readline/vi_mode.c - - don't save text to buffer unless undo pointer points to a record of - type UNDO_INSERT; zero it out instead. This fixes bug reported by - Craig Turner with redoing `ctd[ESC]' (empty - insert after change to) - -shell.c - - change set_shell_name so invocations like "-/bin/bash" are marked as - login shells - -doc/bash.1 - - add note about destroying functions with `unset -f' to the section - on shell functions - -lib/readline/terminal.c - - if readline hasn't been initialized (_rl_term_autowrap == -1, the - value it's now initialized with), call _rl_init_terminal_io from - _rl_set_screen_size before deciding whether or not to decrement - _rl_screenwidth. Fixes bug from Mike Frysinger - - 1/14 - ---- -lib/readline/input.c - - allow rl_set_keyboard_input_timeout to set the timeout to 0, for - applications that want to use select() like a poll without any - waiting - -lib/readline/doc/rltech.texi - - documented valid values for timeout in rl_set_keyboard_input_timeout - -jobs.c - - in stop_pipeline, don't have the parent shell call give_terminal_to - if subshell_environment contains SUBSHELL_ASYNC (no background - process should ever give the terminal to anything other than - shell_pgrp) - - in make_child, don't give the terminal away if subshell_environment - contains SUBSHELL_ASYNC - - 1/15 - ---- -subst.c - - in parameter_brace_expand, if extracting ${#varname}, only allow - `}' to end the expansion, since none of the other expansions are - valid. Fixes Debian bug reported by Jan Nordhorlz - - 1/17 - ---- -parse.y - - in parse_matched_pair, protect all character tests with the MBTEST - macro - - in parse_dparen, take out extra make_word after call to alloc_word_desc - (mem leak) - - 1/18 - ---- -parse.y - - in parse_matched_pair, add P_ALLOWESC to flags passed to recursive - parse_matched_pair call when encountering a single or double quote - inside a ``-style command substitution - -execute_cmd.c - - add call to QUIT at beginning of execute_command_internal; better - responsiveness to SIGINT - - 1/21 - ---- -lib/readline/bind.c - - change rl_invoking_keyseqs_in_map to honor the setting of - convert-meta when listing key bindings, since if convert-meta is off, - using '\M-' as the prefix for bindings in, for instance, - emacs-escape-keymap, is wrong. This affects `bind -p' output - - change rl_untranslate_keyseq to add '\e' instead of '\C-[' for - ESC - -execute_cmd.c - - add call to QUIT at end of execute_command - - 1/23 - ---- -lib/readline/display.c - - changed two places in update_line where a check of whether the cursor - is before the last invisible character in the prompt string to - differentiate between the multibyte character case (where - _rl_last_c_pos is a physical cursor position) and the single-byte - case (where it is a buffer index). This prevents many unnecessary - \r-redraw the line sequences. Reported by Dan Jacobson. - - 1/24 - ---- -quit.h - - wrap QUIT macro in do...while(0) like other compound statement - macros - - CHECK_TERMSIG define (placeholder for now); future use will be to - handle any received signals that should cause the shell to - terminate (e.g., SIGHUP) - -{input,jobs,nojobs}.c - - add calls to CHECK_TERMSIG where appropriate (reading input and - waiting for children) - - include quit.h if necessary - - 1/25 - ---- -parse.y - - undo change that makes `)' in a compound assignment delimit a token. - It messes up arithmetic expressions in assignments to `let', among - other things - -sig.h,{jobs,nojobs,sig,trap}.c,builtins/trap.def - - rename termination_unwind_protect to termsig_sighandler - -sig.c - - split termsig_sighandler into two functions: termsig_sighandler, which - runs as a signal handler and sets a flag noting that a terminating - signal was received, and termsig_handler, which runs when it is `safe' - to handle the signal and exit - - new terminate_immediately variable, similar to interrupt_immediately - - termsig_sighandler calls termsig_handler immediately if - terminate_immediately is non-zero - -quit.h - - change CHECK_TERMSIG macro to check terminating_signal and call - termsig_handler if it's non-zero - - add same check of terminating_signal and call to termsig_handler to - QUIT macro - -{jobs,nojobs}.c - - change call to termsig_sighandler to call termsig_handler directly, - as was intended - -parse.y,builtins/read.def - - set terminate_immediately to non-zero value when reading interactive - input, as is done with interrupt_immediately - - 1/26 - ---- -doc/{bash.1,bashref.texi} - - reworded the POSIX standard references to remove mention of POSIX.2 - or 1003.2 -- it's all the 1003.1 standard now. Recommended by - Arnold Robbins - - 1/27 - ---- -lib/readline/complete.c - - move call to filename dequoting function into - rl_filename_completion_function; call only if directory completion - hook isn't set. This means that directory-completion-hook now needs - to dequote the directory name. We don't want to dequote the directory - name before calling the directory-completion-hook. Bug reported by - Andrew Parker - -bashline.c - - add necessary directory name dequoting to bash_directory_completion_hook - and bash_directory_expansion - -lib/readline/doc/rltech.texi - - add note to description of rl_directory_completion_hook that it - needs to dequote the directory name even if no other expansions are - performed - - 1/28 - ---- -braces.c - - make sure that we skip over braces that don't start a valid matched - brace expansion construct in brace_expand -- there might be a valid - brace expansion after the unmatched `{' later in the string - - brace_gobbler now checks that when looking for a `}' to end a brace - expansion word, there is an unquoted `,' or `..' that's not inside - another pair of braces. Fixes the a{b{c,d}e}f problem reported by - Tim Waugh - -builtins/declare.def - - when not in posix mode, and operating on shell functions, typeset - and declare do not require their variable operands to be valid - shell identifiers. The other `attribute' builtins work this way. - Fixes inconsistency reported by Mike Frysinger - -{configure,config.h}.in - - add test for setregid, define HAVE_SETREGID and HAVE_DECL_SETREGID - as appropriate - - add test for eaccess, define HAVE_EACCESS if found - -lib/sh/eaccess.c - - new file, with sh_stat and sh_eaccess functions, moved from test.c - - renamed old sh_eaccess as sh_stataccess, since it uses the stat(2) - information to determine file accessibility - - new function, sh_euidaccess, to call when uid != euid or gid != egid; - temporarily swaps uid/euid and gid/egid around call to access - - rewrote sh_eaccess to call eaccess, access, sh_euidaccess or - sh_stataccess as appropriate. access(2) will take into account - things like ACLs, read-only file systems, file flags, and so on. - -lib/sh/Makefile.in,Makefile.in - - add necessary entries for eaccess.[co] - -test.c - - change calls to test_stat to call sh_stat - -{test,general}.c - - change calls to test_eaccess to call sh_eaccess - -externs.h - - new extern declaration for sh_eaccess - -test.[ch] - - remove test_stat and test_eaccess - - 1/29 - ---- -braces.c - - make change from 1/28 dependant on CSH_BRACE_COMPAT not being - defined (since old bash behavior is what csh does, defining - CSH_BRACE_COMPAT will produce old bash behavior) - - 1/30 - ---- -bashline.c - - last argument of bash_default_completion is now a flags word: - DEFCOMP_CMDPOS (in command position) is only current value - - attempt_shell_completion now computes flags before calling - bash_default_completion - - if no_empty_command_completion is set, bash does not attempt command - word completion even if not at the beginning of the line, as long - as the word to be completed is empty and start == end (catches - beginning of line and all whitespace preceding point) - - 2/4 - --- -lib/readline/display.c - - change _rl_make_prompt_for_search to use rl_prompt and append the - search character to it, so the call to expand_prompt in rl_message - will process the non-printing characters correctly. Bug reported - by Mike Stroyan - - 2/5 - --- -lib/readline/display.c - - fix off-by-one error when comparing against PROMPT_ENDING_INDEX, - which caused a prompt with invisible characters to be redrawn one - extra time in a multibyte locale. Change from <= to < fixes - multibyte locale, but I added 1 to single-byte definition of - PROMPT_ENDING_INDEX (worth checking) to compensate. Bug reported - by Egmont Koblinger - - 2/8 - --- -lib/readline/terminal.c - - call _emx_get_screensize with wr, wc like ioctl code for consistency - - new function, _win_get_screensize, gets screen dimensions using - standard Windows API for mingw32 (code from Denis Pilat) - - call _win_get_screensize from _rl_get_screen_size on mingw32 - -lib/readline/rlconf.h - - define SYS_INPUTRC (/etc/inputrc) as system-wide default inputrc - filename - -support/shobj-conf - - changes to make loadable builtins work on MacOS X 10.[34] - -builtins/pushd.def - - changes to make it work as a loadable builtin compiled with gcc4 - - 2/9 - --- -lib/readline/bind.c - - add SYS_INPUTRC as last-ditch default (if DEFAULT_INPUTRC does not - exist or can't be read) in rl_read_init_file - -lib/readline/doc/rluser.texi - - add description of /etc/inputrc as ultimate default startup file - - 2/10 - ---- -lib/readline/bind.c - - fix problem with rl_function_of_keyseq that returns a non-keymap - bound to a portion of the passed key sequence without processing - the entire thing. We can bind maps with existing non-map - functions using the ANYOTHERKEY binding code. - -variables.c - - shells running in posix mode do not set $HOME, as POSIX apparently - requires - - 2/15 - ---- -braces.c - - mkseq() now takes the increment as an argument; changed callers - - 2/16 - ---- -builtins/hash.def - - print `hash table empty' message to stdout instead of stderr - - 2/17 - ---- -lib/readline/readline.c - - when resetting rl_prompt in rl_set_prompt, make sure rl_display_prompt - is set when the function returns - - 2/18 - ---- -lib/readline/display.c - - further fixes to _rl_make_prompt_for_search from Eric Blake to deal - with multiple calls to expand_prompt - - 2/21 - ---- -builtins/hash.def - - don't print `hash table empty' message in posix mode - - 2/27 - ---- -lib/glob/sm_loop.c - - change extmatch() to turn off FNM_PERIOD in flags passed to recursive - calls to gmatch() when calling it with a substring after the start - of the string it receives. Changed `+', `*', `?, `@', and `!' cases - to do the right thing. Fixes bug reported by Benoit Vila - - -braces.c - - add QUIT; statements to mkseq to make large sequence generation - interruptible - - 2/28 - ---- -lib/glob/glob.c - - initialize nalloca in glob_vector - - 3/1 - --- -lib/glob/glob.c - - in glob_vector, when freeing up the linked list after some error, - make sure to set `tmplink' to 0 if `firstlink' is set to 0, else we - get multiple-free errors - - 3/5 - --- -trap.c - - inheritance of the DEBUG, RETURN, and ERR traps is now dependent - only on the `functrace' and `errtrace' shell options, as the - documentation says, rather than on whether or not the shell is in - debugging mode. Reported by Philip Susi - -parse.y - - in parse_matched_pair, don't recursively parse ${...} or other - ${...} constructs inside `` - - in parse_matched_pair, remove special code that recursively parses - quoted strings inside `` constructs. For Bourne shell compatibility - - 3/6 - --- -builtins/pushd.def - - let get_directory_stack take take an `int flags' argument and convert - $HOME to ~ if flags&1 is non-zero - -builtins/common.h - - change extern declaration for get_directory_stack - -variables.c - - call get_directory_stack with an arg of 0 to inhibit converting - $HOME to ~ in the result. Fixes cd ${DIRSTACK[1]} problem - reported by Len Lattanzi (cd fails because - the tildes won't be expanded after variable expansion) - -jobs.c - - changed hangup_all_jobs slightly so stopped jobs marked J_NOHUP - won't get a SIGCONT - -general.c - - changed check_binary_file() to check for a NUL byte instead of a - non-printable character. Might at some point want to check - entire (possibly multibyte) characters instead of just bytes. Hint - from ksh via David Korn - - 3/7 - --- -builtins/reserved.def - - changed runs of spaces to tabs in variables help text to make - indentation better when displayed - -builtins/mkbuiltins.c - - changes to avoid the annoying extra space that keeps gettext from - being passed an empty string - - 3/9 - --- -lib/glob/glob.c - - make sure globbing is interrupted if the shell receives a terminating - signal - - 3/14 - ---- -lib/readline/search.c - - call rl_message with format argument of "%" in _rl_nsearch_init - to avoid `%' characters in the prompt string from being interpreted - as format specifiers to vsnprintf/vsprintf diff --git a/bash-20060316/CWRU/POSIX.NOTES.old b/bash-20060316/CWRU/POSIX.NOTES.old deleted file mode 100644 index 1707ab10c..000000000 --- a/bash-20060316/CWRU/POSIX.NOTES.old +++ /dev/null @@ -1,82 +0,0 @@ -Starting bash with the `--posix' command-line option or executing -`set -o posix' while bash is running will cause bash to conform more -closely to the Posix.2 standard by changing the behavior to match that -specified by Posix.2 in areas where the bash default differs. - -The following list is what's changed when `posix mode' is in effect: - -1. When a command in the hash table no longer exists, bash will re-search - $PATH to find the new location. This is also available with - `shopt -s checkhash'. - -2. The >& redirection does not redirect stdout and stderr. - -3. The message printed by the job control code and builtins when a job - exits with a non-zero status is `Done(status)'. - -4. Reserved words may not be aliased. - -5. The Posix.2 PS1 and PS2 expansions of `!' -> history number and - `!!' -> `!' are enabled, and parameter expansion is performed on - the value regardless of the setting of the `promptvars' option. - -6. Interactive comments are enabled by default. (Note that bash has - them on by default anyway.) - -7. The Posix.2 startup files are executed ($ENV) rather than the normal - bash files. - -8. Tilde expansion is only performed on assignments preceding a command - name, rather than on all assignment statements on the line. - -9. The default history file is ~/.sh_history (default value of $HISTFILE). - -10. The output of `kill -l' prints all the signal names on a single line, - separated by spaces. - -11. Non-interactive shells exit if `file' in `. file' is not found. - -12. Redirection operators do not perform pathname expansion on the word - in the redirection unless the shell is interactive - -13. Function names must be valid shell identifiers. That is, they may not - contain characters other than letters, digits, and underscores, and - may not start with a digit. Declaring a function with an illegal name - causes a fatal syntax error in non-interactive shells. - -14. Posix.2 `special' builtins are found before shell functions during command - lookup. - -15. If a Posix.2 special builtin returns an error status, a non-interactive - shell exits. The fatal errors are those listed in the POSIX.2 standard, - and include things like passing incorrect options, redirection errors, - variable assignment errors for assignments preceding the command name, - and so on. - -16. The environment passed to executed commands is not sorted. Neither is - the output of `set'. This is not strictly Posix.2 behavior, but sh - does it this way. Ksh does not. It's not necessary to sort the - environment; no program should rely on it being sorted. - -17. If the `cd' builtin finds a directory to change to using $CDPATH, the - value it assigns to $PWD does not contain any symbolic links, as if - `cd -P' had been executed. - -18. A non-interactive shell exits with an error status if a variable - assignment error occurs when no command name follows the assignment - statements. A variable assignment error occurs, for example, when - trying to assign a value to a read-only variable. - -19. A non-interactive shell exits with an error status if the iteration - variable in a for statement or the selection variable in a select - statement is a read-only variable. - -20. Process substitution is not available. - -21. Assignment statements preceding POSIX.2 `special' builtins persist in - the shell environment after the builtin completes. - -There is other Posix.2 behavior that bash does not implement. Specifically: - -1. Assignment statements affect the execution environment of all builtins, - not just special ones. diff --git a/bash-20060316/CWRU/old/set.def.save b/bash-20060316/CWRU/old/set.def.save deleted file mode 100644 index 87b78d7cc..000000000 --- a/bash-20060316/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/bash-20060316/CWRU/save/unwind_prot.h.save b/bash-20060316/CWRU/save/unwind_prot.h.save deleted file mode 100644 index 998fd72b6..000000000 --- a/bash-20060316/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/bash-20060316/cross-build/cygwin32.cache.old b/bash-20060316/cross-build/cygwin32.cache.old deleted file mode 100644 index 640390fbf..000000000 --- a/bash-20060316/cross-build/cygwin32.cache.old +++ /dev/null @@ -1,42 +0,0 @@ -# This file is a shell script that caches the results of configure -# tests for CYGWIN32 so they don't need to be done when cross-compiling. - -# AC_FUNC_GETPGRP should also define GETPGRP_VOID -ac_cv_func_getpgrp_void=${ac_cv_func_getpgrp_void='yes'} -# AC_FUNC_SETVBUF_REVERSED should not define anything else -ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed='no'} -# on CYGWIN32, system calls do not restart -ac_cv_sys_restartable_syscalls=${ac_cv_sys_restartable_syscalls='no'} -bash_cv_sys_restartable_syscalls=${bash_cv_sys_restartable_syscalls='no'} - -# these may be necessary, but they are currently commented out -#ac_cv_c_bigendian=${ac_cv_c_bigendian='no'} -ac_cv_sizeof_char_p=${ac_cv_sizeof_char_p='4'} -ac_cv_sizeof_int=${ac_cv_sizeof_int='4'} -ac_cv_sizeof_long=${ac_cv_sizeof_long='4'} -ac_cv_sizeof_double=${ac_cv_sizeof_double='8'} - -bash_cv_dup2_broken=${bash_cv_dup2_broken='no'} -bash_cv_pgrp_pipe=${bash_cv_pgrp_pipe='no'} -bash_cv_type_rlimit=${bash_cv_type_rlimit='long'} -bash_cv_decl_under_sys_siglist=${bash_cv_decl_under_sys_siglist='no'} -bash_cv_under_sys_siglist=${bash_cv_under_sys_siglist='no'} -bash_cv_sys_siglist=${bash_cv_sys_siglist='no'} -bash_cv_opendir_not_robust=${bash_cv_opendir_not_robust='no'} -bash_cv_getenv_redef=${bash_cv_getenv_redef='yes'} -bash_cv_printf_declared=${bash_cv_printf_declared='yes'} -bash_cv_ulimit_maxfds=${bash_cv_ulimit_maxfds='no'} -bash_cv_getcwd_calls_popen=${bash_cv_getcwd_calls_popen='no'} -bash_cv_must_reinstall_sighandlers=${bash_cv_must_reinstall_sighandlers='no'} -bash_cv_job_control_missing=${bash_cv_job_control_missing='present'} -bash_cv_sys_named_pipes=${bash_cv_sys_named_pipes='missing'} -bash_cv_func_sigsetjmp=${bash_cv_func_sigsetjmp='missing'} -bash_cv_mail_dir=${bash_cv_mail_dir='unknown'} -bash_cv_func_strcoll_broken=${bash_cv_func_strcoll_broken='no'} - -bash_cv_type_int32_t=${bash_cv_type_int32_t='int'} -bash_cv_type_u_int32_t=${bash_cv_type_u_int32_t='int'} - -ac_cv_type_bits64_t=${ac_cv_type_bits64_t='no'} - -# end of cross-build/cygwin32.cache diff --git a/bash-20060316/doc/FAQ.orig b/bash-20060316/doc/FAQ.orig deleted file mode 100644 index 1cff3c8ef..000000000 --- a/bash-20060316/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/bash-20060316/doc/FAQ.save b/bash-20060316/doc/FAQ.save deleted file mode 100644 index 1cff3c8ef..000000000 --- a/bash-20060316/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/bash-20060316/doc/bash.1.orig b/bash-20060316/doc/bash.1.orig deleted file mode 100644 index 828ec966b..000000000 --- a/bash-20060316/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/bash-20060316/doc/bashref.texi.orig b/bash-20060316/doc/bashref.texi.orig deleted file mode 100644 index fdce9e3c7..000000000 --- a/bash-20060316/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/bash-20060316/eval.c~ b/bash-20060316/eval.c~ deleted file mode 100644 index 34a088ce0..000000000 --- a/bash-20060316/eval.c~ +++ /dev/null @@ -1,275 +0,0 @@ -/* eval.c -- reading and evaluating commands. */ - -/* Copyright (C) 1996 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - Bash is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with Bash; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "bashansi.h" -#include - -#include "bashintl.h" - -#include "shell.h" -#include "flags.h" -#include "trap.h" - -#include "builtins/common.h" - -#include "input.h" -#include "execute_cmd.h" - -#if defined (HISTORY) -# include "bashhist.h" -#endif - -extern int EOF_reached; -extern int indirection_level; -extern int posixly_correct; -extern int subshell_environment, running_under_emacs; -extern int last_command_exit_value, stdin_redir; -extern int need_here_doc; -extern int current_command_number, current_command_line_count, line_number; -extern int expand_aliases; - -static void send_pwd_to_eterm __P((void)); -static sighandler alrm_catcher __P((int)); - -/* Read and execute commands until EOF is reached. This assumes that - the input source has already been initialized. */ -int -reader_loop () -{ - int our_indirection_level; - COMMAND * volatile current_command; - - current_command = (COMMAND *)NULL; - USE_VAR(current_command); - - our_indirection_level = ++indirection_level; - - while (EOF_Reached == 0) - { - int code; - - code = setjmp (top_level); - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - if (interactive_shell && signal_is_ignored (SIGINT) == 0) - set_signal_handler (SIGINT, sigint_sighandler); - - if (code != NOT_JUMPED) - { - indirection_level = our_indirection_level; - - switch (code) - { - /* Some kind of throw to top_level has occured. */ - case FORCE_EOF: - case ERREXIT: - case EXITPROG: - current_command = (COMMAND *)NULL; - if (exit_immediately_on_error) - variable_context = 0; /* not in a function */ - EOF_Reached = EOF; - goto exec_done; - - case DISCARD: - last_command_exit_value = 1; - if (subshell_environment) - { - current_command = (COMMAND *)NULL; - EOF_Reached = EOF; - goto exec_done; - } - /* Obstack free command elements, etc. */ - if (current_command) - { - dispose_command (current_command); - current_command = (COMMAND *)NULL; - } - break; - - default: - command_error ("reader_loop", CMDERR_BADJUMP, code, 0); - } - } - - executing = 0; - if (temporary_env) - dispose_used_env_vars (); - -#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA) - /* Attempt to reclaim memory allocated with alloca (). */ - (void) alloca (0); -#endif - - if (read_command () == 0) - { - if (interactive_shell == 0 && read_but_dont_execute) - { - last_command_exit_value = EXECUTION_SUCCESS; - dispose_command (global_command); - global_command = (COMMAND *)NULL; - } - else if (current_command = global_command) - { - global_command = (COMMAND *)NULL; - current_command_number++; - - executing = 1; - stdin_redir = 0; - execute_command (current_command); - - exec_done: - QUIT; - - if (current_command) - { - dispose_command (current_command); - current_command = (COMMAND *)NULL; - } - } - } - else - { - /* Parse error, maybe discard rest of stream if not interactive. */ - if (interactive == 0) - EOF_Reached = EOF; - } - if (just_one_command) - EOF_Reached = EOF; - } - indirection_level--; - return (last_command_exit_value); -} - -static sighandler -alrm_catcher(i) - int i; -{ - printf (_("\007timed out waiting for input: auto-logout\n")); - bash_logout (); /* run ~/.bash_logout if this is a login shell */ - jump_to_top_level (EXITPROG); - SIGRETURN (0); -} - -/* Send an escape sequence to emacs term mode to tell it the - current working directory. */ -static void -send_pwd_to_eterm () -{ - char *pwd; - - pwd = get_string_value ("PWD"); - if (pwd == 0) - pwd = get_working_directory ("eterm"); - fprintf (stderr, "\032/%s\n", pwd); -} - -/* Call the YACC-generated parser and return the status of the parse. - Input is read from the current input stream (bash_input). yyparse - leaves the parsed command in the global variable GLOBAL_COMMAND. - This is where PROMPT_COMMAND is executed. */ -int -parse_command () -{ - int r; - char *command_to_execute; - - need_here_doc = 0; - run_pending_traps (); - - /* Allow the execution of a random command just before the printing - of each primary prompt. If the shell variable PROMPT_COMMAND - is set then the value of it is the command to execute. */ - if (interactive && bash_input.type != st_string) - { - command_to_execute = get_string_value ("PROMPT_COMMAND"); - if (command_to_execute) - execute_prompt_command (command_to_execute); - - if (running_under_emacs == 2) - send_pwd_to_eterm (); /* Yuck */ - } - - current_command_line_count = 0; - r = yyparse (); - - if (need_here_doc) - gather_here_documents (); - - return (r); -} - -/* Read and parse a command, returning the status of the parse. The command - is left in the globval variable GLOBAL_COMMAND for use by reader_loop. - This is where the shell timeout code is executed. */ -int -read_command () -{ - SHELL_VAR *tmout_var; - int tmout_len, result; - SigHandler *old_alrm; - - set_current_prompt_level (1); - global_command = (COMMAND *)NULL; - - /* Only do timeouts if interactive. */ - tmout_var = (SHELL_VAR *)NULL; - tmout_len = 0; - old_alrm = (SigHandler *)NULL; - - if (interactive) - { - tmout_var = find_variable ("TMOUT"); - - if (tmout_var && var_isset (tmout_var)) - { - tmout_len = atoi (value_cell (tmout_var)); - if (tmout_len > 0) - { - old_alrm = set_signal_handler (SIGALRM, alrm_catcher); - alarm (tmout_len); - } - } - } - - QUIT; - - current_command_line_count = 0; - result = parse_command (); - - if (interactive && tmout_var && (tmout_len > 0)) - { - alarm(0); - set_signal_handler (SIGALRM, old_alrm); - } - - return (result); -} diff --git a/bash-20060316/examples/scripts/adventure.sh.save1 b/bash-20060316/examples/scripts/adventure.sh.save1 deleted file mode 100755 index 4e2239396..000000000 --- a/bash-20060316/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/bash-20060316/include/memalloc.h.save b/bash-20060316/include/memalloc.h.save deleted file mode 100644 index a1a270699..000000000 --- a/bash-20060316/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/bash-20060316/input.h~ b/bash-20060316/input.h~ deleted file mode 100644 index 9a4dfd3f7..000000000 --- a/bash-20060316/input.h~ +++ /dev/null @@ -1,131 +0,0 @@ -/* input.h -- Structures and unions used for reading input. */ -/* Copyright (C) 1993 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#if !defined (_INPUT_H_) -#define _INPUT_H_ - -#include "stdc.h" - -/* Function pointers can be declared as (Function *)foo. */ -#if !defined (_FUNCTION_DEF) -# define _FUNCTION_DEF -typedef int Function (); -typedef void VFunction (); -typedef char *CPFunction (); /* no longer used */ -typedef char **CPPFunction (); /* no longer used */ -#endif /* _FUNCTION_DEF */ - -typedef int sh_cget_func_t __P((void)); /* sh_ivoidfunc_t */ -typedef int sh_cunget_func_t __P((int)); /* sh_intfunc_t */ - -enum stream_type {st_none, st_stdin, st_stream, st_string, st_bstream}; - -#if defined (BUFFERED_INPUT) - -/* Possible values for b_flag. */ -#undef B_EOF -#undef B_ERROR /* There are some systems with this define */ -#undef B_UNBUFF - -#define B_EOF 0x01 -#define B_ERROR 0x02 -#define B_UNBUFF 0x04 -#define B_WASBASHINPUT 0x08 - -/* A buffered stream. Like a FILE *, but with our own buffering and - synchronization. Look in input.c for the implementation. */ -typedef struct BSTREAM -{ - int b_fd; - char *b_buffer; /* The buffer that holds characters read. */ - size_t b_size; /* How big the buffer is. */ - size_t b_used; /* How much of the buffer we're using, */ - int b_flag; /* Flag values. */ - size_t b_inputp; /* The input pointer, index into b_buffer. */ -} BUFFERED_STREAM; - -#if 0 -extern BUFFERED_STREAM **buffers; -#endif - -extern int default_buffered_input; - -#endif /* BUFFERED_INPUT */ - -typedef union { - FILE *file; - char *string; -#if defined (BUFFERED_INPUT) - int buffered_fd; -#endif -} INPUT_STREAM; - -typedef struct { - enum stream_type type; - char *name; - INPUT_STREAM location; - sh_cget_func_t *getter; - sh_cunget_func_t *ungetter; -} BASH_INPUT; - -extern BASH_INPUT bash_input; - -/* Functions from parse.y whose use directly or indirectly depends on the - definitions in this file. */ -extern void initialize_bash_input __P((void)); -extern void init_yy_io __P((sh_cget_func_t *, sh_cunget_func_t *, enum stream_type, const char *, INPUT_STREAM)); -extern char *yy_input_name __P((void)); -extern void with_input_from_stdin __P((void)); -extern void with_input_from_string __P((char *, const char *)); -extern void with_input_from_stream __P((FILE *, const char *)); -extern void push_stream __P((int)); -extern void pop_stream __P((void)); -extern int stream_on_stack __P((enum stream_type)); -extern char *read_secondary_line __P((int)); -extern int find_reserved_word __P((char *)); -extern void gather_here_documents __P((void)); -extern void execute_variable_command __P((char *)); - -extern int *save_token_state __P((void)); -extern void restore_token_state __P((int *)); - -/* Functions from input.c */ -extern int getc_with_restart __P((FILE *)); -extern int ungetc_with_restart __P((int, FILE *)); - -#if defined (BUFFERED_INPUT) -/* Functions from input.c. */ -extern int fd_is_bash_input __P((int)); -extern int set_bash_input_fd __P((int)); -extern int save_bash_input __P((int, int)); -extern int check_bash_input __P((int)); -extern int duplicate_buffered_stream __P((int, int)); -extern BUFFERED_STREAM *fd_to_buffered_stream __P((int)); -extern BUFFERED_STREAM *set_buffered_stream __P((int, BUFFERED_STREAM *)); -extern BUFFERED_STREAM *open_buffered_stream __P((char *)); -extern void free_buffered_stream __P((BUFFERED_STREAM *)); -extern int close_buffered_stream __P((BUFFERED_STREAM *)); -extern int close_buffered_fd __P((int)); -extern int sync_buffered_stream __P((int)); -extern int buffered_getchar __P((void)); -extern int buffered_ungetchar __P((int)); -extern void with_input_from_buffered_stream __P((int, char *)); -#endif /* BUFFERED_INPUT */ - -#endif /* _INPUT_H_ */ diff --git a/bash-20060316/jobs.c.diff b/bash-20060316/jobs.c.diff deleted file mode 100644 index f1ea4e0cd..000000000 --- a/bash-20060316/jobs.c.diff +++ /dev/null @@ -1,521 +0,0 @@ -*** ../bash-3.1/jobs.c Fri Nov 11 23:13:27 2005 ---- jobs.c Wed Feb 1 13:55:38 2006 -*************** -*** 4,8 **** - control. */ - -! /* Copyright (C) 1989-2005 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. ---- 4,8 ---- - control. */ - -! /* Copyright (C) 1989-2006 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. -*************** -*** 78,82 **** - - #define DEFAULT_CHILD_MAX 32 -! #define MAX_JOBS_IN_ARRAY 4096 /* testing */ - - /* Take care of system dependencies that must be handled when waiting for ---- 78,90 ---- - - #define DEFAULT_CHILD_MAX 32 -! #if !defined (DEBUG) -! #define MAX_JOBS_IN_ARRAY 4096 /* production */ -! #else -! #define MAX_JOBS_IN_ARRAY 128 /* testing */ -! #endif -! -! /* Flag values for second argument to delete_job */ -! #define DEL_WARNSTOPPED 1 /* warn about deleting stopped jobs */ -! #define DEL_NOBGPID 2 /* don't add pgrp leader to bgpids */ - - /* Take care of system dependencies that must be handled when waiting for -*************** -*** 308,311 **** ---- 316,323 ---- - static char retcode_name_buffer[64]; - -+ /* flags to detect pid wraparound */ -+ static pid_t first_pid = NO_PID; -+ static int pid_wrap = -1; -+ - #if !defined (_POSIX_VERSION) - -*************** -*** 329,337 **** - #endif /* !_POSIX_VERSION */ - -! /* Initialize the global job stats structure. */ - void - init_job_stats () - { - js = zerojs; - } - ---- 341,351 ---- - #endif /* !_POSIX_VERSION */ - -! /* Initialize the global job stats structure and other bookkeeping variables */ - void - init_job_stats () - { - js = zerojs; -+ first_pid = NO_PID; -+ pid_wrap = -1; - } - -*************** -*** 620,625 **** - * the parent gives it away. - * - */ -! if (job_control && newjob->pgrp) - give_terminal_to (newjob->pgrp, 0); - } ---- 634,642 ---- - * the parent gives it away. - * -+ * Don't give the terminal away if this shell is an asynchronous -+ * subshell. -+ * - */ -! if (job_control && newjob->pgrp && (subshell_environment&SUBSHELL_ASYNC) == 0) - give_terminal_to (newjob->pgrp, 0); - } -*************** -*** 806,810 **** - QUEUE_SIGCHLD(os); - -! /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { ---- 823,827 ---- - QUEUE_SIGCHLD(os); - -! /* XXX could use js.j_firstj and js.j_lastj here */ - for (i = 0; i < js.j_jobslots; i++) - { -*************** -*** 812,815 **** ---- 829,834 ---- - if (i < js.j_firstj && jobs[i]) - itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("cleanup_dead_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - -*************** -*** 838,841 **** ---- 857,884 ---- - } - -+ static void -+ delete_old_job (pid) -+ pid_t pid; -+ { -+ PROCESS *p; -+ int job; -+ -+ job = find_job (pid, 0, &p); -+ if (job != NO_JOB) -+ { -+ #ifdef DEBUG -+ itrace ("delete_old_job: found pid %d in job %d with state %d", pid, job, jobs[job]->state); -+ #endif -+ if (JOBSTATE (job) == JDEAD) -+ delete_job (job, DEL_NOBGPID); -+ else -+ { -+ internal_warning (_("forked pid %d appears in running job %d"), pid, job); -+ if (p) -+ p->pid = 0; -+ } -+ } -+ } -+ - /* Reallocate and compress the jobs list. This returns with a jobs array - whose size is a multiple of JOB_SLOTS and can hold the current number of -*************** -*** 845,851 **** - { - sigset_t set, oset; -! int nsize, i, j; - JOB **nlist; - - nsize = ((js.j_njobs + JOB_SLOTS - 1) / JOB_SLOTS); - nsize *= JOB_SLOTS; ---- 888,895 ---- - { - sigset_t set, oset; -! int nsize, i, j, ncur, nprev; - JOB **nlist; - -+ ncur = nprev = NO_JOB; - nsize = ((js.j_njobs + JOB_SLOTS - 1) / JOB_SLOTS); - nsize *= JOB_SLOTS; -*************** -*** 855,869 **** - - BLOCK_CHILD (set, oset); -! nlist = (JOB **) xmalloc (nsize * sizeof (JOB *)); - for (i = j = 0; i < js.j_jobslots; i++) - if (jobs[i]) -! nlist[j++] = jobs[i]; - - js.j_firstj = 0; -! js.j_lastj = (j > 0) ? j - 1: 0; - js.j_jobslots = nsize; - -! free (jobs); -! jobs = nlist; - - UNBLOCK_CHILD (oset); ---- 899,947 ---- - - BLOCK_CHILD (set, oset); -! nlist = (js.j_jobslots == nsize) ? jobs : (JOB **) xmalloc (nsize * sizeof (JOB *)); -! - for (i = j = 0; i < js.j_jobslots; i++) - if (jobs[i]) -! { -! if (i == js.j_current) -! ncur = j; -! if (i == js.j_previous) -! nprev = j; -! nlist[j++] = jobs[i]; -! } -! -! #if defined (DEBUG) -! itrace ("realloc_jobs_list: resize jobs list from %d to %d", js.j_jobslots, nsize); -! itrace ("realloc_jobs_list: j_lastj changed from %d to %d", js.j_lastj, (j > 0) ? j - 1 : 0); -! itrace ("realloc_jobs_list: j_njobs changed from %d to %d", js.j_njobs, (j > 0) ? j - 1 : 0); -! #endif - - js.j_firstj = 0; -! js.j_lastj = (j > 0) ? j - 1 : 0; -! js.j_njobs = j; - js.j_jobslots = nsize; - -! /* Zero out remaining slots in new jobs list */ -! for ( ; j < nsize; j++) -! nlist[j] = (JOB *)NULL; -! -! if (jobs != nlist) -! { -! free (jobs); -! jobs = nlist; -! } -! -! if (ncur != NO_JOB) -! js.j_current = ncur; -! if (nprev != NO_JOB) -! js.j_previous = nprev; -! -! /* Need to reset these */ -! if (js.j_current == NO_JOB || js.j_previous == NO_JOB || js.j_current > js.j_lastj || js.j_previous > js.j_lastj) -! reset_current (); -! -! #ifdef DEBUG -! itrace ("realloc_jobs_list: reset js.j_current (%d) and js.j_previous (%d)", js.j_current, js.j_previous); -! #endif - - UNBLOCK_CHILD (oset); -*************** -*** 874,878 **** - the foreground process (subshell_environment != 0). Returns the first - available slot in the compacted list. If that value is js.j_jobslots, then -! the list needs to be reallocated. The jobs array is in new memory if - this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */ - static int ---- 952,956 ---- - the foreground process (subshell_environment != 0). Returns the first - available slot in the compacted list. If that value is js.j_jobslots, then -! the list needs to be reallocated. The jobs array may be in new memory if - this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */ - static int -*************** -*** 892,897 **** - with SIGCHLD blocked. */ - void -! delete_job (job_index, warn_stopped) -! int job_index, warn_stopped; - { - register JOB *temp; ---- 970,975 ---- - with SIGCHLD blocked. */ - void -! delete_job (job_index, dflags) -! int job_index, dflags; - { - register JOB *temp; -*************** -*** 903,918 **** - 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 == js.j_current || job_index == js.j_previous) - reset_current (); - -! proc = find_last_proc (job_index, 0); -! /* Could do this just for J_ASYNC jobs, but we save all. */ -! bgp_add (proc->pid, process_exit_status (proc->status)); - - jobs[job_index] = (JOB *)NULL; -- - if (temp == js.j_lastmade) - js.j_lastmade = 0; ---- 981,1001 ---- - return; - -! if ((dflags & DEL_WARNSTOPPED) && subshell_environment == 0 && STOPPED (job_index)) - internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp); - temp = jobs[job_index]; -+ if (temp == 0) -+ return; - if (job_index == js.j_current || job_index == js.j_previous) - reset_current (); - -! if ((dflags & DEL_NOBGPID) == 0) -! { -! proc = find_last_proc (job_index, 0); -! /* Could do this just for J_ASYNC jobs, but we save all. */ -! if (proc) -! bgp_add (proc->pid, process_exit_status (proc->status)); -! } - - jobs[job_index] = (JOB *)NULL; - if (temp == js.j_lastmade) - js.j_lastmade = 0; -*************** -*** 1092,1095 **** ---- 1175,1180 ---- - if (i < js.j_firstj && jobs[i]) - itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("map_over_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - if (jobs[i]) -*************** -*** 1224,1228 **** - PROCESS *p; - -! /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { ---- 1309,1313 ---- - PROCESS *p; - -! /* XXX could use js.j_firstj here, and should check js.j_lastj */ - for (i = 0; i < js.j_jobslots; i++) - { -*************** -*** 1230,1233 **** ---- 1315,1320 ---- - if (i < js.j_firstj && jobs[i]) - itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("find_job: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - if (jobs[i]) -*************** -*** 1656,1660 **** - 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); - ---- 1743,1747 ---- - shell's process group (we could be in the middle of a - pipeline, for example). */ -! if (async_p == 0 && pipeline_pgrp != shell_pgrp && ((subshell_environment&SUBSHELL_ASYNC) == 0)) - give_terminal_to (pipeline_pgrp, 0); - -*************** -*** 1698,1701 **** ---- 1785,1795 ---- - as the proper pgrp if this is the first child. */ - -+ if (first_pid == NO_PID) -+ first_pid = pid; -+ else if (pid_wrap == -1 && pid < first_pid) -+ pid_wrap = 0; -+ else if (pid_wrap == 0 && pid >= first_pid) -+ pid_wrap = 1; -+ - if (job_control) - { -*************** -*** 1731,1734 **** ---- 1825,1831 ---- - #endif - -+ if (pid_wrap > 0) -+ delete_old_job (pid); -+ - #if !defined (RECYCLES_PIDS) - /* Only check for saved status if we've saved more than CHILD_MAX -*************** -*** 1915,1919 **** - - p = jobs[job]->pipe; -! while (p->next != jobs[job]->pipe) - p = p->next; - ---- 2012,2016 ---- - - p = jobs[job]->pipe; -! while (p && p->next != jobs[job]->pipe) - p = p->next; - -*************** -*** 1999,2003 **** - - /* find first running job; if none running in foreground, break */ -! /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { ---- 2096,2100 ---- - - /* find first running job; if none running in foreground, break */ -! /* XXX could use js.j_firstj and js.j_lastj here */ - for (i = 0; i < js.j_jobslots; i++) - { -*************** -*** 2005,2008 **** ---- 2102,2107 ---- - if (i < js.j_firstj && jobs[i]) - itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("wait_for_background_pids: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0) -*************** -*** 2199,2203 **** - wait_sigint_received = 0; - if (job_control == 0) -! old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); - - termination_state = last_command_exit_value; ---- 2298,2306 ---- - wait_sigint_received = 0; - if (job_control == 0) -! { -! old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); -! if (old_sigint_handler == SIG_IGN) -! set_signal_handler (SIGINT, old_sigint_handler); -! } - - termination_state = last_command_exit_value; -*************** -*** 2266,2269 **** ---- 2369,2373 ---- - child->running = PS_DONE; - child->status = 0; /* XXX -- can't find true status */ -+ js.c_living = 0; /* no living child processes */ - if (job != NO_JOB) - { -*************** -*** 2317,2321 **** - itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp); - #endif -- - give_terminal_to (shell_pgrp, 0); - } ---- 2421,2424 ---- -*************** -*** 2866,2869 **** ---- 2969,2973 ---- - if (sigchld || block == 0) - waitpid_flags |= WNOHANG; -+ CHECK_TERMSIG; - pid = WAITPID (-1, &status, waitpid_flags); - -*************** -*** 2892,2895 **** ---- 2996,3000 ---- - /* If waitpid returns 0, there are running children. If it returns -1, - the only other error POSIX says it can return is EINTR. */ -+ CHECK_TERMSIG; - if (pid <= 0) - continue; /* jumps right to the test */ -*************** -*** 2898,2902 **** - run the trap if a process is just being continued. */ - if (WIFCONTINUED(status) == 0) -! children_exited++; - - /* Locate our PROCESS for this pid. */ ---- 3003,3010 ---- - run the trap if a process is just being continued. */ - if (WIFCONTINUED(status) == 0) -! { -! children_exited++; -! js.c_living--; -! } - - /* Locate our PROCESS for this pid. */ -*************** -*** 3123,3127 **** - restore_sigint_handler (); - if (temp_handler == SIG_DFL) -! termination_unwind_protect (SIGINT); - else if (temp_handler != SIG_IGN) - (*temp_handler) (SIGINT); ---- 3231,3235 ---- - restore_sigint_handler (); - if (temp_handler == SIG_DFL) -! termsig_handler (SIGINT); - else if (temp_handler != SIG_IGN) - (*temp_handler) (SIGINT); -*************** -*** 3638,3644 **** - if (i < js.j_firstj && jobs[i]) - itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - #endif - if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) -! delete_job (i, 1); - } - if (running_only == 0) ---- 3746,3754 ---- - if (i < js.j_firstj && jobs[i]) - itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("delete_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) -! delete_job (i, DEL_WARNSTOPPED); - } - if (running_only == 0) -*************** -*** 3692,3695 **** ---- 3802,3807 ---- - if (i < js.j_firstj && jobs[i]) - itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("count_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - if (jobs[i] && DEADJOB(i) == 0) -*************** -*** 3765,3768 **** ---- 3877,3882 ---- - if (i < js.j_firstj && jobs[i]) - itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - if (jobs[i] && DEADJOB (i)) -*************** -*** 3816,3819 **** ---- 3930,3935 ---- - if (i < js.j_firstj && jobs[i]) - itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - /* If marking this job as notified would drop us down below diff --git a/bash-20060316/lib/readline/doc/Makefile.old b/bash-20060316/lib/readline/doc/Makefile.old deleted file mode 100644 index 58d4dd762..000000000 --- a/bash-20060316/lib/readline/doc/Makefile.old +++ /dev/null @@ -1,76 +0,0 @@ -# This makefile for Readline library documentation is in -*- text -*- mode. -# Emacs likes it that way. -RM = rm -f - -MAKEINFO = makeinfo -TEXI2DVI = texi2dvi -TEXI2HTML = texi2html -QUIETPS = #set this to -q to shut up dvips -DVIPS = dvips -D 300 $(QUIETPS) -o $@ # tricky - -INSTALL_DATA = cp -infodir = /usr/local/info - -RLSRC = rlman.texinfo rluser.texinfo rltech.texinfo -HISTSRC = hist.texinfo hsuser.texinfo hstech.texinfo - -DVIOBJ = readline.dvi history.dvi -INFOOBJ = readline.info history.info -PSOBJ = readline.ps history.ps -HTMLOBJ = readline.html history.html - -all: info dvi html ps -nodvi: info html - -readline.dvi: $(RLSRC) - $(TEXI2DVI) rlman.texinfo - mv rlman.dvi readline.dvi - -readline.info: $(RLSRC) - $(MAKEINFO) --no-split -o $@ rlman.texinfo - -history.dvi: ${HISTSRC} - $(TEXI2DVI) hist.texinfo - mv hist.dvi history.dvi - -history.info: ${HISTSRC} - $(MAKEINFO) --no-split -o $@ hist.texinfo - -readline.ps: readline.dvi - $(RM) $@ - $(DVIPS) readline.dvi - -history.ps: history.dvi - $(RM) $@ - $(DVIPS) history.dvi - -readline.html: ${RLSRC} - $(TEXI2HTML) rlman.texinfo - sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman.html > readline.html - sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman_toc.html > readline_toc.html - $(RM) rlman.html rlman_toc.html - -history.html: ${HISTSRC} - $(TEXI2HTML) hist.texinfo - sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist.html > history.html - sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist_toc.html > history_toc.html - $(RM) hist.html hist_toc.html - -info: $(INFOOBJ) -dvi: $(DVIOBJ) -ps: $(PSOBJ) -html: $(HTMLOBJ) - -clean: - $(RM) *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \ - *.fns *.kys *.tps *.vrs *.o core - -distclean: clean -mostlyclean: clean - -maintainer-clean: clean - $(RM) *.dvi *.info *.info-* *.ps *.html - -install: info - ${INSTALL_DATA} readline.info $(infodir)/readline.info - ${INSTALL_DATA} history.info $(infodir)/history.info diff --git a/bash-20060316/lib/readline/isearch.c.orig b/bash-20060316/lib/readline/isearch.c.orig deleted file mode 100644 index c1ea5b308..000000000 --- a/bash-20060316/lib/readline/isearch.c.orig +++ /dev/null @@ -1,560 +0,0 @@ -/* **************************************************************** */ -/* */ -/* I-Search and Searching */ -/* */ -/* **************************************************************** */ - -/* Copyright (C) 1987-2002 Free Software Foundation, Inc. - - This file contains the Readline Library (the Library), a set of - routines for providing Emacs style line input to programs that ask - for it. - - The Library is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 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 - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif - -#include "rldefs.h" -#include "rlmbutil.h" - -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "xmalloc.h" - -/* Variables exported to other files in the readline library. */ -char *_rl_isearch_terminators = (char *)NULL; - -/* Variables imported from other files in the readline library. */ -extern HIST_ENTRY *_rl_saved_line_for_history; - -/* Forward declarations */ -static int rl_search_history PARAMS((int, int)); - -/* Last line found by the current incremental search, so we don't `find' - identical lines many times in a row. */ -static char *prev_line_found; - -/* Last search string and its length. */ -static char *last_isearch_string; -static int last_isearch_string_len; - -static char *default_isearch_terminators = "\033\012"; - -/* Search backwards through the history looking for a string which is typed - interactively. Start with the current line. */ -int -rl_reverse_search_history (sign, key) - int sign, key; -{ - return (rl_search_history (-sign, key)); -} - -/* Search forwards through the history looking for a string which is typed - interactively. Start with the current line. */ -int -rl_forward_search_history (sign, key) - int sign, key; -{ - return (rl_search_history (sign, key)); -} - -/* Display the current state of the search in the echo-area. - SEARCH_STRING contains the string that is being searched for, - DIRECTION is zero for forward, or 1 for reverse, - WHERE is the history list number of the current line. If it is - -1, then this line is the starting one. */ -static void -rl_display_search (search_string, reverse_p, where) - char *search_string; - int reverse_p, where; -{ - char *message; - int msglen, searchlen; - - searchlen = (search_string && *search_string) ? strlen (search_string) : 0; - - message = (char *)xmalloc (searchlen + 33); - msglen = 0; - -#if defined (NOTDEF) - if (where != -1) - { - sprintf (message, "[%d]", where + history_base); - msglen = strlen (message); - } -#endif /* NOTDEF */ - - message[msglen++] = '('; - - if (reverse_p) - { - strcpy (message + msglen, "reverse-"); - msglen += 8; - } - - strcpy (message + msglen, "i-search)`"); - msglen += 10; - - if (search_string) - { - strcpy (message + msglen, search_string); - msglen += searchlen; - } - - strcpy (message + msglen, "': "); - - rl_message ("%s", message); - free (message); - (*rl_redisplay_function) (); -} - -/* Search through the history looking for an interactively typed string. - This is analogous to i-search. We start the search in the current line. - DIRECTION is which direction to search; >= 0 means forward, < 0 means - backwards. */ -static int -rl_search_history (direction, invoking_key) - int direction, invoking_key; -{ - /* The string that the user types in to search for. */ - char *search_string; - - /* The current length of SEARCH_STRING. */ - int search_string_index; - - /* The amount of space that SEARCH_STRING has allocated to it. */ - int search_string_size; - - /* The list of lines to search through. */ - char **lines, *allocated_line; - - /* The length of LINES. */ - int hlen; - - /* Where we get LINES from. */ - HIST_ENTRY **hlist; - - register int i; - int orig_point, orig_mark, orig_line, last_found_line; - int c, found, failed, sline_len; - int n, wstart, wlen; -#if defined (HANDLE_MULTIBYTE) - char mb[MB_LEN_MAX]; -#endif - - /* The line currently being searched. */ - char *sline; - - /* Offset in that line. */ - int line_index; - - /* Non-zero if we are doing a reverse search. */ - int reverse; - - /* The list of characters which terminate the search, but are not - subsequently executed. If the variable isearch-terminators has - been set, we use that value, otherwise we use ESC and C-J. */ - char *isearch_terminators; - - RL_SETSTATE(RL_STATE_ISEARCH); - orig_point = rl_point; - orig_mark = rl_mark; - last_found_line = orig_line = where_history (); - reverse = direction < 0; - hlist = history_list (); - allocated_line = (char *)NULL; - - isearch_terminators = _rl_isearch_terminators ? _rl_isearch_terminators - : default_isearch_terminators; - - /* Create an arrary of pointers to the lines that we want to search. */ - rl_maybe_replace_line (); - i = 0; - if (hlist) - for (i = 0; hlist[i]; i++); - - /* Allocate space for this many lines, +1 for the current input line, - and remember those lines. */ - lines = (char **)xmalloc ((1 + (hlen = i)) * sizeof (char *)); - for (i = 0; i < hlen; i++) - lines[i] = hlist[i]->line; - - if (_rl_saved_line_for_history) - lines[i] = _rl_saved_line_for_history->line; - else - { - /* Keep track of this so we can free it. */ - allocated_line = (char *)xmalloc (1 + strlen (rl_line_buffer)); - strcpy (allocated_line, &rl_line_buffer[0]); - lines[i] = allocated_line; - } - - hlen++; - - /* The line where we start the search. */ - i = orig_line; - - rl_save_prompt (); - - /* Initialize search parameters. */ - search_string = (char *)xmalloc (search_string_size = 128); - *search_string = '\0'; - search_string_index = 0; - prev_line_found = (char *)0; /* XXX */ - - /* Normalize DIRECTION into 1 or -1. */ - direction = (direction >= 0) ? 1 : -1; - - rl_display_search (search_string, reverse, -1); - - sline = rl_line_buffer; - sline_len = strlen (sline); - line_index = rl_point; - - found = failed = 0; - for (;;) - { - rl_command_func_t *f = (rl_command_func_t *)NULL; - - /* Read a key and decide how to proceed. */ - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - c = _rl_read_mbstring (c, mb, MB_LEN_MAX); -#endif - - /* Translate the keys we do something with to opcodes. */ - if (c >= 0 && _rl_keymap[c].type == ISFUNC) - { - f = _rl_keymap[c].function; - - if (f == rl_reverse_search_history) - c = reverse ? -1 : -2; - else if (f == rl_forward_search_history) - c = !reverse ? -1 : -2; - else if (f == rl_rubout) - c = -3; - else if (c == CTRL ('G')) - c = -4; - else if (c == CTRL ('W')) /* XXX */ - c = -5; - else if (c == CTRL ('Y')) /* XXX */ - c = -6; - } - - /* The characters in isearch_terminators (set from the user-settable - variable isearch-terminators) are used to terminate the search but - not subsequently execute the character as a command. The default - value is "\033\012" (ESC and C-J). */ - if (strchr (isearch_terminators, c)) - { - /* ESC still terminates the search, but if there is pending - input or if input arrives within 0.1 seconds (on systems - with select(2)) it is used as a prefix character - with rl_execute_next. WATCH OUT FOR THIS! This is intended - to allow the arrow keys to be used like ^F and ^B are used - to terminate the search and execute the movement command. - XXX - since _rl_input_available depends on the application- - settable keyboard timeout value, this could alternatively - use _rl_input_queued(100000) */ - if (c == ESC && _rl_input_available ()) - rl_execute_next (ESC); - break; - } - -#define ENDSRCH_CHAR(c) \ - ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G'))) - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (c >= 0 && strlen (mb) == 1 && ENDSRCH_CHAR (c)) - { - /* This sets rl_pending_input to c; it will be picked up the next - time rl_read_key is called. */ - rl_execute_next (c); - break; - } - } - else -#endif - if (c >= 0 && ENDSRCH_CHAR (c)) - { - /* This sets rl_pending_input to c; it will be picked up the next - time rl_read_key is called. */ - rl_execute_next (c); - break; - } - - switch (c) - { - case -1: - if (search_string_index == 0) - { - if (last_isearch_string) - { - search_string_size = 64 + last_isearch_string_len; - search_string = (char *)xrealloc (search_string, search_string_size); - strcpy (search_string, last_isearch_string); - search_string_index = last_isearch_string_len; - rl_display_search (search_string, reverse, -1); - break; - } - continue; - } - else if (reverse) - --line_index; - else if (line_index != sline_len) - ++line_index; - else - rl_ding (); - break; - - /* switch directions */ - case -2: - direction = -direction; - reverse = direction < 0; - break; - - /* delete character from search string. */ - case -3: /* C-H, DEL */ - /* This is tricky. To do this right, we need to keep a - stack of search positions for the current search, with - sentinels marking the beginning and end. But this will - do until we have a real isearch-undo. */ - if (search_string_index == 0) - rl_ding (); - else - search_string[--search_string_index] = '\0'; - - break; - - case -4: /* C-G */ - rl_replace_line (lines[orig_line], 0); - rl_point = orig_point; - rl_mark = orig_mark; - rl_restore_prompt(); - rl_clear_message (); - if (allocated_line) - free (allocated_line); - free (lines); - RL_UNSETSTATE(RL_STATE_ISEARCH); - return 0; - - case -5: /* C-W */ - /* skip over portion of line we already matched */ - wstart = rl_point + search_string_index; - if (wstart >= rl_end) - { - rl_ding (); - break; - } - - /* if not in a word, move to one. */ - if (rl_alphabetic(rl_line_buffer[wstart]) == 0) - { - rl_ding (); - break; - } - n = wstart; - while (n < rl_end && rl_alphabetic(rl_line_buffer[n])) - n++; - wlen = n - wstart + 1; - if (search_string_index + wlen + 1 >= search_string_size) - { - search_string_size += wlen + 1; - search_string = (char *)xrealloc (search_string, search_string_size); - } - for (; wstart < n; wstart++) - search_string[search_string_index++] = rl_line_buffer[wstart]; - search_string[search_string_index] = '\0'; - break; - - case -6: /* C-Y */ - /* skip over portion of line we already matched */ - wstart = rl_point + search_string_index; - if (wstart >= rl_end) - { - rl_ding (); - break; - } - n = rl_end - wstart + 1; - if (search_string_index + n + 1 >= search_string_size) - { - search_string_size += n + 1; - search_string = (char *)xrealloc (search_string, search_string_size); - } - for (n = wstart; n < rl_end; n++) - search_string[search_string_index++] = rl_line_buffer[n]; - search_string[search_string_index] = '\0'; - break; - - default: - /* Add character to search string and continue search. */ - if (search_string_index + 2 >= search_string_size) - { - search_string_size += 128; - search_string = (char *)xrealloc (search_string, search_string_size); - } -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - int j, l; - for (j = 0, l = strlen (mb); j < l; ) - search_string[search_string_index++] = mb[j++]; - } - else -#endif - search_string[search_string_index++] = c; - search_string[search_string_index] = '\0'; - break; - } - - for (found = failed = 0;;) - { - int limit = sline_len - search_string_index + 1; - - /* Search the current line. */ - while (reverse ? (line_index >= 0) : (line_index < limit)) - { - if (STREQN (search_string, sline + line_index, search_string_index)) - { - found++; - break; - } - else - line_index += direction; - } - if (found) - break; - - /* Move to the next line, but skip new copies of the line - we just found and lines shorter than the string we're - searching for. */ - do - { - /* Move to the next line. */ - i += direction; - - /* At limit for direction? */ - if (reverse ? (i < 0) : (i == hlen)) - { - failed++; - break; - } - - /* We will need these later. */ - sline = lines[i]; - sline_len = strlen (sline); - } - while ((prev_line_found && STREQ (prev_line_found, lines[i])) || - (search_string_index > sline_len)); - - if (failed) - break; - - /* Now set up the line for searching... */ - line_index = reverse ? sline_len - search_string_index : 0; - } - - if (failed) - { - /* We cannot find the search string. Ding the bell. */ - rl_ding (); - i = last_found_line; - continue; /* XXX - was break */ - } - - /* We have found the search string. Just display it. But don't - actually move there in the history list until the user accepts - the location. */ - if (found) - { - prev_line_found = lines[i]; - rl_replace_line (lines[i], 0); - rl_point = line_index; - last_found_line = i; - rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i); - } - } - - /* The searching is over. The user may have found the string that she - was looking for, or else she may have exited a failing search. If - LINE_INDEX is -1, then that shows that the string searched for was - not found. We use this to determine where to place rl_point. */ - - /* First put back the original state. */ - strcpy (rl_line_buffer, lines[orig_line]); - - rl_restore_prompt (); - - /* Save the search string for possible later use. */ - FREE (last_isearch_string); - last_isearch_string = search_string; - last_isearch_string_len = search_string_index; - - if (last_found_line < orig_line) - rl_get_previous_history (orig_line - last_found_line, 0); - else - rl_get_next_history (last_found_line - orig_line, 0); - - /* If the string was not found, put point at the end of the last matching - line. If last_found_line == orig_line, we didn't find any matching - history lines at all, so put point back in its original position. */ - if (line_index < 0) - { - if (last_found_line == orig_line) - line_index = orig_point; - else - line_index = strlen (rl_line_buffer); - rl_mark = orig_mark; - } - - rl_point = line_index; - /* Don't worry about where to put the mark here; rl_get_previous_history - and rl_get_next_history take care of it. */ - - rl_clear_message (); - - FREE (allocated_line); - free (lines); - - RL_UNSETSTATE(RL_STATE_ISEARCH); - - return 0; -} diff --git a/bash-20060316/parse.y.save26 b/bash-20060316/parse.y.save26 deleted file mode 100644 index 97f603b7a..000000000 --- a/bash-20060316/parse.y.save26 +++ /dev/null @@ -1,4927 +0,0 @@ -/* Yacc grammar for bash. */ - -/* Copyright (C) 1989-2005 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file 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.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 - { - if ($2) - $2->flags |= CMD_INVERT_RETURN; - $$ = $2; - } - | timespec pipeline - { - if ($2) - $2->flags |= $1; - $$ = $2; - } - | timespec BANG pipeline - { - if ($3) - $3->flags |= $1|CMD_INVERT_RETURN; - $$ = $3; - } - | BANG timespec pipeline - { - if ($3) - $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 */ -#define PST_ASSIGNOK 0x4000 /* assignment statement ok in this context */ - -/* 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) - { - if (interactive) - interrupt_immediately++; - result = getc_with_restart (bash_input.location.file); - if (interactive) - interrupt_immediately--; - } - 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) - { - /* Allow immediate exit if interrupted during input. */ - QUIT; - - c = yy_getc (); - - /* 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 (sigwinch_received) - { - sigwinch_received = 0; - get_new_window_size (0, (int *)0, (int *)0); - } - - 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 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 MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n') - { - if (SHOULD_PROMPT ()) - prompt_again (); - line_number++; - goto restart_read; - } - - 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, 0); - 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 */ - - parser_state &= ~PST_ASSIGNOK; - - 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 */ - - parser_state &= ~PST_ASSIGNOK; - - 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, and returning - * correct error values if it reads EOF. - */ -#define P_FIRSTCLOSE 0x01 -#define P_ALLOWESC 0x02 -#define P_DQUOTE 0x04 -#define P_COMMAND 0x08 /* parsing a command, so look for comments */ - -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, in_comment, check_comment; - int pass_next_character, nestlen, ttranslen, start_lineno; - char *ret, *nestret, *ttrans; - int retind, retsize, rflags; - - count = 1; - pass_next_character = was_dollar = in_comment = 0; - check_comment = (flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 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) - { -#if 0 - ch = shell_getc ((qc != '\'' || (flags & P_ALLOWESC)) && pass_next_character == 0); -#else - ch = shell_getc (qc != '\'' && pass_next_character == 0); -#endif - 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 (in_comment) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if (ch == '\n') - in_comment = 0; - - continue; - } - /* Not exactly right yet */ - else if (check_comment && in_comment == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || whitespace (ret[retind -1]))) - in_comment = 1; - - 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); - - if ((rflags & P_DQUOTE) == 0) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else - { - nestret = ttrans; - nestlen = ttranslen; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - nestlen = ttranslen + 2; - 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); -add_nestret: - 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(qc == '`' && (ch == '"' || ch == '\'') && in_comment == 0) - { - nestret = parse_matched_pair (0, ch, ch, &nestlen, rflags); - goto add_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 & ~P_DQUOTE); - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - - goto add_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 = alloc_word_desc (); - wd->word = wval; - wd = make_word (wval); - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - return (ARITH_FOR_EXPRS); - } - else - return -1; /* ERROR */ - } -#endif - -#if defined (DPAREN_ARITHMETIC) - if (reserved_word_acceptable (last_read_token)) - { - sline = line_number; - - cmdtyp = parse_arith_cmd (&wval, 0); - if (cmdtyp == 1) /* arithmetic command */ - { - wd = alloc_word_desc (); - wd->word = wval; - wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - 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; -} - -/* XXX - possible changes here for `+=' */ -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; - - /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound - assignment. */ - int compound_assignment; - - /* 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 = compound_assignment = 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, (character == '`') ? P_COMMAND : 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, P_COMMAND); - 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); - ttranslen = strlen (ttok); - ttrans = ttok; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - ttranslen += 2; - 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 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && 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; - compound_assignment = 1; -#if 0 - goto next_character; -#else - goto got_token; /* ksh93 seems to do this */ -#endif - } - 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; - if (compound_assignment) - the_word->flags |= W_COMPASSIGN; - /* 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; - } - - if (command_token_position (last_read_token)) - { - struct builtin *b; - b = builtin_address_internal (token, 0); - if (b && (b->flags & ASSIGNMENT_BUILTIN)) - parser_state |= PST_ASSIGNOK; - else if (STREQ (token, "eval") || STREQ (token, "let")) - parser_state |= PST_ASSIGNOK; - } - - 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 ";"; - } - else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT)) - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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, t_string) == 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] = CTLESC; - 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 (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, orig_last_token, assignok; - char *saved_token, *ret; - - saved_token = token; - orig_token_size = token_buffer_size; - orig_line_number = line_number; - orig_last_token = last_read_token; - - last_read_token = WORD; /* WORD to allow reserved words here */ - - token = (char *)NULL; - token_buffer_size = 0; - - assignok = parser_state&PST_ASSIGNOK; /* XXX */ - - 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(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 = orig_last_token; /* XXX - was 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; - - if (assignok) - parser_state |= PST_ASSIGNOK; - - 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 = (sh_parser_state_t *)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/bash-20060316/parse.y~ b/bash-20060316/parse.y~ deleted file mode 100644 index 1edacd792..000000000 --- a/bash-20060316/parse.y~ +++ /dev/null @@ -1,4947 +0,0 @@ -/* Yacc grammar for bash. */ - -/* Copyright (C) 1989-2006 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file 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.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 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 - { - if ($2) - $2->flags |= CMD_INVERT_RETURN; - $$ = $2; - } - | timespec pipeline - { - if ($2) - $2->flags |= $1; - $$ = $2; - } - | timespec BANG pipeline - { - if ($3) - $3->flags |= $1|CMD_INVERT_RETURN; - $$ = $3; - } - | BANG timespec pipeline - { - if ($3) - $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 */ -#define PST_ASSIGNOK 0x4000 /* assignment statement ok in this context */ - -/* 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++; - } - terminate_immediately = 1; - - current_readline_line = readline (current_readline_prompt ? - current_readline_prompt : ""); - - terminate_immediately = 0; - 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) - { - if (interactive) - { - interrupt_immediately++; - terminate_immediately++; - } - result = getc_with_restart (bash_input.location.file); - if (interactive) - { - interrupt_immediately--; - terminate_immediately--; - } - } - 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) - { - /* Allow immediate exit if interrupted during input. */ - QUIT; - - c = yy_getc (); - - /* 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 (sigwinch_received) - { - sigwinch_received = 0; - get_new_window_size (0, (int *)0, (int *)0); - } - - 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 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 MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n') - { - if (SHOULD_PROMPT ()) - prompt_again (); - line_number++; - goto restart_read; - } - - 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, 0); - 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 */ - - parser_state &= ~PST_ASSIGNOK; - - 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 */ - - parser_state &= ~PST_ASSIGNOK; - - 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, and returning - * correct error values if it reads EOF. - */ -#define P_FIRSTCLOSE 0x01 -#define P_ALLOWESC 0x02 -#define P_DQUOTE 0x04 -#define P_COMMAND 0x08 /* parsing a command, so look for comments */ -#define P_BACKQUOTE 0x10 /* parsing a backquoted command substitution */ - -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, in_comment, check_comment; - int pass_next_character, backq_backslash, nestlen, ttranslen, start_lineno; - char *ret, *nestret, *ttrans; - int retind, retsize, rflags; - -/* itrace("parse_matched_pair: open = %c close = %c", open, close); */ - count = 1; - pass_next_character = backq_backslash = was_dollar = in_comment = 0; - check_comment = (flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 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 != '\'' && pass_next_character == 0 && backq_backslash == 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 (in_comment) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if (ch == '\n') - in_comment = 0; - - continue; - } - /* Not exactly right yet */ - else if MBTEST(check_comment && in_comment == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || whitespace (ret[retind - 1]))) - in_comment = 1; - - /* last char was backslash inside backquoted command substitution */ - if (backq_backslash) - { - backq_backslash = 0; - /* Placeholder for adding special characters */ - } - - 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--; - /* handle nested ${...} specially. */ - else if MBTEST(open != close && was_dollar && open == '{' && ch == open) /* } */ - count++; - 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++; -#if 0 - else if MBTEST((flags & P_BACKQUOTE) && ch == '\\') - backq_backslash++; -#endif - 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); - - if ((rflags & P_DQUOTE) == 0) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else - { - nestret = ttrans; - nestlen = ttranslen; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - nestlen = ttranslen + 2; - 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); -add_nestret: - 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); - } -#if 0 - else if MBTEST(qc == '`' && (ch == '"' || ch == '\'') && in_comment == 0) - { - /* Add P_BACKQUOTE so backslash quotes the next character and - shell_getc does the right thing with \. We do this for - a measure of backwards compatibility -- it's not strictly the - right POSIX thing. */ - nestret = parse_matched_pair (0, ch, ch, &nestlen, rflags|P_BACKQUOTE); - goto add_nestret; - } -#endif - else if MBTEST(open != '`' && 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 & ~P_DQUOTE); - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - - goto add_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 = alloc_word_desc (); - wd->word = wval; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - return (ARITH_FOR_EXPRS); - } - else - return -1; /* ERROR */ - } -#endif - -#if defined (DPAREN_ARITHMETIC) - if (reserved_word_acceptable (last_read_token)) - { - sline = line_number; - - cmdtyp = parse_arith_cmd (&wval, 0); - if (cmdtyp == 1) /* arithmetic command */ - { - wd = alloc_word_desc (); - wd->word = wval; - wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - 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; -} - -/* XXX - possible changes here for `+=' */ -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; - - /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound - assignment. */ - int compound_assignment; - - /* 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 = compound_assignment = 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, (character == '`') ? P_COMMAND : 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, P_COMMAND); - 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); - ttranslen = strlen (ttok); - ttrans = ttok; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - ttranslen += 2; - 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 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && 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; - compound_assignment = 1; -#if 1 - goto next_character; -#else - goto got_token; /* ksh93 seems to do this */ -#endif - } - 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; - if (compound_assignment) - the_word->flags |= W_COMPASSIGN; - /* 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; - } - - if (command_token_position (last_read_token)) - { - struct builtin *b; - b = builtin_address_internal (token, 0); - if (b && (b->flags & ASSIGNMENT_BUILTIN)) - parser_state |= PST_ASSIGNOK; - else if (STREQ (token, "eval") || STREQ (token, "let")) - parser_state |= PST_ASSIGNOK; - } - - 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 ";"; - } - else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT)) - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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, t_string) == 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] = CTLESC; - 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 (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, orig_last_token, assignok; - char *saved_token, *ret; - - saved_token = token; - orig_token_size = token_buffer_size; - orig_line_number = line_number; - orig_last_token = last_read_token; - - last_read_token = WORD; /* WORD to allow reserved words here */ - - token = (char *)NULL; - token_buffer_size = 0; - - assignok = parser_state&PST_ASSIGNOK; /* XXX */ - - 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(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 = orig_last_token; /* XXX - was 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; - - if (assignok) - parser_state |= PST_ASSIGNOK; - - 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 = (sh_parser_state_t *)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/bash-20060316/tests/cprint.right.save1 b/bash-20060316/tests/cprint.right.save1 deleted file mode 100644 index 6b711b8c5..000000000 --- a/bash-20060316/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/bash-20060316/tests/history.tests.save b/bash-20060316/tests/history.tests.save deleted file mode 100644 index 4a218c301..000000000 --- a/bash-20060316/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/bash-20060316/tests/misc/regress/log.orig b/bash-20060316/tests/misc/regress/log.orig deleted file mode 100644 index c1f1e1991..000000000 --- a/bash-20060316/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/bash-20060316/tests/misc/regress/shx.orig b/bash-20060316/tests/misc/regress/shx.orig deleted file mode 100644 index 4b3bf2b82..000000000 --- a/bash-20060316/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/bashhist.c~ b/bashhist.c~ deleted file mode 100644 index 5d15c518a..000000000 --- a/bashhist.c~ +++ /dev/null @@ -1,846 +0,0 @@ -/* bashhist.c -- bash interface to the GNU history library. */ - -/* Copyright (C) 1993-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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; -int enable_history_list = 1; /* value for `set -o history' */ - -/* 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; - -/* Set to 1 if builtins/history.def:push_history added the last history - entry. */ -int hist_last_line_pushed; - -#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; -#if defined (BANG_HISTORY) - sv_histchars ("histchars"); -#endif -} - -void -bash_history_reinit (interact) - int interact; -{ -#if defined (BANG_HISTORY) - history_expansion = interact != 0; - history_expansion_inhibited = 1; -#endif - remember_on_history = enable_history_list = 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 ("HISTSIZE", "500"); - sv_histsize ("HISTSIZE"); - - 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 (); - } -} - -void -bash_clear_history () -{ - clear_history (); - history_lines_this_session = 0; -} - -/* Delete and free the history list entry at offset I. */ -int -bash_delete_histent (i) - int i; -{ - HIST_ENTRY *discard; - - discard = remove_history (i); - if (discard) - free_history_entry (discard); - history_lines_this_session--; - - return 1; -} - -#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; - hist_last_line_pushed = 0; - add_history (line); - history_lines_this_session++; -} - -int -history_number () -{ - using_history (); - return (remember_on_history ? 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/bashhist.h~ b/bashhist.h~ deleted file mode 100644 index f83b33a11..000000000 --- a/bashhist.h~ +++ /dev/null @@ -1,70 +0,0 @@ -/* bashhist.h -- interface to the bash history functions in bashhist.c. */ - -/* Copyright (C) 1993 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#if !defined (_BASHHIST_H_) -#define _BASHHIST_H_ - -#include "stdc.h" - -/* Flag values for history_control */ -#define HC_IGNSPACE 0x01 -#define HC_IGNDUPS 0x02 -#define HC_ERASEDUPS 0x04 - -#define HC_IGNBOTH (HC_IGNSPACE|HC_IGNDUPS) - -extern int remember_on_history; -extern int enable_history_list; /* value for `set -o history' */ -extern int literal_history; /* controlled by `shopt lithist' */ -extern int history_lines_this_session; -extern int history_lines_in_file; -extern int history_expansion; -extern int history_control; -extern int command_oriented_history; -extern int current_command_first_line_saved; -extern int hist_last_line_added; -extern int hist_last_line_pushed; - -# if defined (BANG_HISTORY) -extern int history_expansion_inhibited; -# endif /* BANG_HISTORY */ - -extern void bash_initialize_history __P((void)); -extern void bash_history_reinit __P((int)); -extern void bash_history_disable __P((void)); -extern void bash_history_enable __P((void)); -extern void bash_clear_history __P((void)); -extern int bash_delete_histent __P((int)); -extern int bash_delete_last_history __P((void)); -extern void load_history __P((void)); -extern void save_history __P((void)); -extern int maybe_append_history __P((char *)); -extern int maybe_save_shell_history __P((void)); -extern char *pre_process_line __P((char *, int, int)); -extern void maybe_add_history __P((char *)); -extern void bash_add_history __P((char *)); -extern int check_add_history __P((char *, int)); -extern int history_number __P((void)); - -extern void setup_history_ignore __P((char *)); - -extern char *last_history_line __P((void)); - -#endif /* _BASHHIST_H_ */ diff --git a/bashline.c.save b/bashline.c.save deleted file mode 100644 index 3251a9b78..000000000 --- a/bashline.c.save +++ /dev/null @@ -1,3191 +0,0 @@ -/* bashline.c -- Bash's interface to the readline library. */ - -/* Copyright (C) 1987-2006 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - Bash is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with Bash; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#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 void bash_directory_expansion __P((char **)); -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; - -static int dot_in_path = 0; - -/* 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; - -/* Flag values for the final argument to bash_default_completion */ -#define DEFCOMP_CMDPOS 1 - -/* 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 old_value; - - /* 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 */ - - kseq[0] = TAB; - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tab_insert) - rl_bind_key_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}}\"" -#define POSIX_VI_EDIT_COMMAND "fc -e vi" - -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; -{ - if (posixly_correct) - return (edit_and_execute_command (count, c, VI_EDITING_MODE, POSIX_VI_EDIT_COMMAND)); - else - 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, SD_NOJMP)) <= 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, SD_NOJMP); - 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", SD_NOJMP); - - 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, dflags; - 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 && assignment (n, 0) == 0) - 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) - { - dflags = 0; - if (in_command_position) - dflags |= DEFCOMP_CMDPOS; - matches = bash_default_completion (text, start, end, qc, dflags); - } - - return matches; -} - -char ** -bash_default_completion (text, start, end, qc, compflags) - const char *text; - int start, end, qc, compflags; -{ - 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 == 0 && (compflags & DEFCOMP_CMDPOS)) - { - /* If END == START and text[0] == 0, we are trying to complete an empty - command word. */ - if (no_empty_command_completion && end == start && text[0] == '\0') - { - 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)) - - dot_in_path = 0; - 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; - else if (matches[1] == 0 && CMD_IS_DIR(matches[0]) && dot_in_path == 0) - /* If we found a single match, without looking in the current - directory (because it's not in $PATH), but the found name is - also a command in the current directory, suppress appending any - terminating character, since it's ambiguous. */ - { - rl_completion_suppress_append = 1; - 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 on - rl_completion_suppress_append 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_completion_suppress_append = 1; - rl_filename_completion_desired = 0; - } - } - } - - /* 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 char *dequoted_hint = (char *)NULL; - static char *directory_part = (char *)NULL; - static int path_index, hint_len, dequoted_len, istate, igncase; - static int mapping_over, local_index, searching_path, hint_is_dir; - static SHELL_VAR **varlist = (SHELL_VAR **)NULL; -#if defined (ALIAS) - static alias_t **alias_list = (alias_t **)NULL; -#endif /* ALIAS */ - char *temp; - - /* 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 (dequoted_hint && dequoted_hint != hint) - free (dequoted_hint); - if (hint) - free (hint); - - mapping_over = searching_path = 0; - hint_is_dir = CMD_IS_DIR (hint_text); - val = (char *)NULL; - - temp = rl_variable_value ("completion-ignore-case"); - igncase = strcmp (temp, "on") == 0; - - /* 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); - - dequoted_hint = hint; - /* If readline's completer found a quote character somewhere, but - didn't set the quote character, there must have been a quote - character embedded in the filename. It can't be at the start of - the filename, so we need to dequote the filename before we look - in the file system for it. */ - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - free (hint); - hint = dequoted_hint; - } - dequoted_len = hint_len = strlen (hint); - - if (filename_hint) - free (filename_hint); - - filename_hint = savestring (hint); - - mapping_over = 4; - istate = 0; - goto inner; - } - - dequoted_hint = hint = savestring (hint_text); - dequoted_len = hint_len = strlen (hint); - - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - dequoted_len = strlen (dequoted_hint); - } - - path = get_string_value ("PATH"); - path_index = dot_in_path = 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++; - } - - /* If the text passed is a directory in the current directory, return it - as a possible match. Executables in directories in the current - directory can be specified using relative pathnames and successfully - executed even when `.' is not in $PATH. */ - if (hint_is_dir) - { - hint_is_dir = 0; /* only return the hint text once */ - return (savestring (hint_text)); - } - - /* 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); - - searching_path = 1; - 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 (current_path[0] == '.' && current_path[1] == '\0') - dot_in_path = 1; - - if (filename_hint) - free (filename_hint); - - filename_hint = sh_makepath (current_path, hint, 0); - } - - 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; - - if (absolute_program (hint)) - { - if (igncase == 0) - match = strncmp (val, hint, hint_len) == 0; - else - match = strncasecmp (val, hint, hint_len) == 0; - - /* If we performed tilde expansion, restore the original - filename. */ - if (*hint_text == '~') - { - int l, tl, vl, dl, dl2; - char *rd, *dh; - - dh = bash_dequote_filename ((char *)hint_text, 0); - - vl = strlen (val); - tl = strlen (dh); - - rd = savestring (filename_hint); - bash_directory_expansion (&rd); - dl = strlen (rd); - l = vl - dl; /* # of chars added */ - free (rd); - - temp = (char *)xmalloc (l + 2 + tl); - strcpy (temp, dh); - strcpy (temp + tl, val + vl - l); - free (dh); - } - else - temp = savestring (val); - freetemp = 1; - } - else - { - temp = strrchr (val, '/'); - - if (temp) - { - temp++; - if (igncase == 0) - freetemp = match = strncmp (temp, hint, hint_len) == 0; - else - freetemp = match = strncasecmp (temp, hint, hint_len) == 0; - if (match) - temp = savestring (temp); - } - else - freetemp = match = 0; - } - -#if 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)) -#else - /* If we have found a match, and it is an executable file, return it. - We don't return directory names when searching $PATH, since the - bash execution code won't find executables in directories which - appear in directories in $PATH when they're specified using - relative pathnames. */ - if (match && (searching_path ? executable_file (val) : executable_or_directory (val))) -#endif - { - 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 there's a single match and it's a directory, set the append char - to the expected `/'. Otherwise, don't append anything. */ - if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) - rl_completion_append_character = '/'; - else - rl_completion_suppress_append = 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; *alist; alist++) - { - aentry = *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 /* BANG_HISTORY */ - -/* History and alias expand the line. */ -static int -history_and_alias_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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 = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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. NAME undergoes tilde expansion. */ -static int -test_for_directory (name) - const char *name; -{ - char *fn; - int r; - - fn = bash_tilde_expand (name, 0); - r = file_isdir (fn); - free (fn); - - return (r); -} - -/* 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; -} - -/* Simulate the expansions that will be performed by - rl_filename_completion_function. This must be called with the address of - a pointer to malloc'd memory. */ -static void -bash_directory_expansion (dirname) - char **dirname; -{ - char *d, *nd; - - d = savestring (*dirname); - - if (rl_directory_rewrite_hook) - (*rl_directory_rewrite_hook) (&d); - - if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d)) - { - free (*dirname); - *dirname = d; - } - else if (rl_completion_found_quote) - { - nd = bash_dequote_filename (d, rl_completion_quote_character); - free (*dirname); - free (d); - *dirname = nd; - } -} - -/* 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 (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; - } - -#if defined (HAVE_LSTAT) - if (should_expand_dirname && lstat (local_dirname, &sb) == 0) -#else - if (should_expand_dirname && stat (local_dirname, &sb) == 0) -#endif - should_expand_dirname = 0; - - if (should_expand_dirname) - { - new_dirname = savestring (local_dirname); - wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* 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; - } - } - else - { - /* Dequote the filename even if we don't expand it. */ - new_dirname = bash_dequote_filename (local_dirname, rl_completion_quote_character); - free (local_dirname); - local_dirname = *dirname = new_dirname; - } - - if (no_symbolic_links == 0 && (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); - if (len2 > 2) /* don't append `/' to `/' or `//' */ - { - 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, *ttext; - - if (state == 0) - { - rl_filename_completion_desired = 1; - FREE (matches); - if (globorig != globtext) - FREE (globorig); - FREE (globtext); - - ttext = bash_tilde_expand (text, 0); - - if (rl_explicit_arg) - { - globorig = savestring (ttext); - glen = strlen (ttext); - globtext = (char *)xmalloc (glen + 2); - strcpy (globtext, ttext); - globtext[glen] = '*'; - globtext[glen+1] = '\0'; - } - else - globtext = globorig = savestring (ttext); - - if (ttext != text) - free (ttext); - - 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. */ - - 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 (s, '\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 (s, '!')) - cs = COMPLETE_BSQUOTE; - - if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && xstrchr (s, '!')) - { - cs = COMPLETE_BSQUOTE; - *qcp = '\0'; - } -#endif - - /* Don't tilde-expand backslash-quoted filenames, since only single and - double quotes inhibit tilde expansion. */ - mtext = s; - if (mtext[0] == '~' && rtype == SINGLE_MATCH && cs != COMPLETE_BSQUOTE) - mtext = bash_tilde_expand (s, 0); - - 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; - - qc = rl_dispatching ? rl_completion_quote_character : 0; - 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/bashline.c.save1 b/bashline.c.save1 deleted file mode 100644 index ca968a41f..000000000 --- a/bashline.c.save1 +++ /dev/null @@ -1,3245 +0,0 @@ -/* bashline.c -- Bash's interface to the readline library. */ - -/* Copyright (C) 1987-2006 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - Bash is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with Bash; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#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 void bash_directory_expansion __P((char **)); -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; - -static int dot_in_path = 0; - -/* 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; - -/* Flag values for the final argument to bash_default_completion */ -#define DEFCOMP_CMDPOS 1 - -/* 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 old_value; - - /* 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 */ - - kseq[0] = TAB; - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tab_insert) - rl_bind_key_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}}\"" -#define POSIX_VI_EDIT_COMMAND "fc -e vi" - -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; -{ - if (posixly_correct) - return (edit_and_execute_command (count, c, VI_EDITING_MODE, POSIX_VI_EDIT_COMMAND)); - else - 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, SD_NOJMP)) <= 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, SD_NOJMP); - 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", SD_NOJMP); - - 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, dflags; - 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 == 0 && (in_command_position == 0 || text[0] == '\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 == 0 && e == s && text[0] == '\0') - prog_complete_matches = programmable_completions ("_EmptycmD_", text, s, e, &foundcs); - else if (e > s && assignment (n, 0) == 0) - 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 or - compopt. */ - if (foundcs) - { - pcomp_set_readline_variables (foundcs, 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) - { - dflags = 0; - if (in_command_position) - dflags |= DEFCOMP_CMDPOS; - matches = bash_default_completion (text, start, end, qc, dflags); - } - - return matches; -} - -char ** -bash_default_completion (text, start, end, qc, compflags) - const char *text; - int start, end, qc, compflags; -{ - 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 == 0 && (compflags & DEFCOMP_CMDPOS)) - { - /* If END == START and text[0] == 0, we are trying to complete an empty - command word. */ - if (no_empty_command_completion && end == start && text[0] == '\0') - { - 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)) - - dot_in_path = 0; - 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; - else if (matches[1] == 0 && CMD_IS_DIR(matches[0]) && dot_in_path == 0) - /* If we found a single match, without looking in the current - directory (because it's not in $PATH), but the found name is - also a command in the current directory, suppress appending any - terminating character, since it's ambiguous. */ - { - rl_completion_suppress_append = 1; - 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 on - rl_completion_suppress_append 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_completion_suppress_append = 1; - rl_filename_completion_desired = 0; - } - } - } - - /* 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 char *dequoted_hint = (char *)NULL; - static char *directory_part = (char *)NULL; - static int path_index, hint_len, dequoted_len, istate, igncase; - static int mapping_over, local_index, searching_path, hint_is_dir; - static SHELL_VAR **varlist = (SHELL_VAR **)NULL; -#if defined (ALIAS) - static alias_t **alias_list = (alias_t **)NULL; -#endif /* ALIAS */ - char *temp; - - /* 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 (dequoted_hint && dequoted_hint != hint) - free (dequoted_hint); - if (hint) - free (hint); - - mapping_over = searching_path = 0; - hint_is_dir = CMD_IS_DIR (hint_text); - val = (char *)NULL; - - temp = rl_variable_value ("completion-ignore-case"); - igncase = strcmp (temp, "on") == 0; - - /* 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); - directory_part = savestring (hint_text); - temp = strchr (directory_part, '/'); - if (temp) - *temp = 0; - else - { - free (directory_part); - directory_part = (char *)NULL; - } - } - else - hint = savestring (hint_text); - - dequoted_hint = hint; - /* If readline's completer found a quote character somewhere, but - didn't set the quote character, there must have been a quote - character embedded in the filename. It can't be at the start of - the filename, so we need to dequote the filename before we look - in the file system for it. */ - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - free (hint); - hint = dequoted_hint; - } - dequoted_len = hint_len = strlen (hint); - - if (filename_hint) - free (filename_hint); - - filename_hint = savestring (hint); - - mapping_over = 4; - istate = 0; - goto inner; - } - - dequoted_hint = hint = savestring (hint_text); - dequoted_len = hint_len = strlen (hint); - - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - dequoted_len = strlen (dequoted_hint); - } - - path = get_string_value ("PATH"); - path_index = dot_in_path = 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++; - } - - /* If the text passed is a directory in the current directory, return it - as a possible match. Executables in directories in the current - directory can be specified using relative pathnames and successfully - executed even when `.' is not in $PATH. */ - if (hint_is_dir) - { - hint_is_dir = 0; /* only return the hint text once */ - return (savestring (hint_text)); - } - - /* 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 == 0) - { - 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); - - searching_path = 1; - 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 (current_path[0] == '.' && current_path[1] == '\0') - dot_in_path = 1; - - if (filename_hint) - free (filename_hint); - - filename_hint = sh_makepath (current_path, hint, 0); - } - - inner: - val = rl_filename_completion_function (filename_hint, istate); - istate = 1; - - if (glob_pattern_p (hint)) - { - char **temp; - - if (state > 0) - return ((char *)NULL); - temp = shell_glob_filename (hint); - if (GLOB_FAILED (temp)) - return ((char *)NULL); - if (temp && temp[1]) /* multiple matches are bad */ - { - strvec_dispose (temp); - return ((char *)NULL); - } - val = temp[0]; - free (temp); - if (val && (searching_path ? executable_file (val) : executable_or_directory (val))) - return (val); - free (val); - return ((char *)NULL); - } - - 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; - - if (absolute_program (hint)) - { - if (igncase == 0) - match = strncmp (val, hint, hint_len) == 0; - else - match = strncasecmp (val, hint, hint_len) == 0; - - /* If we performed tilde expansion, restore the original - filename. */ - if (*hint_text == '~') - { - int l, vl, dl, dl2, xl; - char *rd, *dh2, *expdir; - - vl = strlen (val); - - rd = savestring (filename_hint); - bash_directory_expansion (&rd); - dl = strlen (rd); - free (rd); - - dh2 = directory_part ? bash_dequote_filename (directory_part, 0) : 0; - bash_directory_expansion (&dh2); - dl2 = strlen (dh2); - - expdir = bash_tilde_expand (directory_part, 0); - xl = strlen (expdir); - free (expdir); - - /* - dh2 = unexpanded but dequoted tilde-prefix - dl = length of entire passed filename - dl2 = length of tilde-prefix - expdir = tilde-expanded tilde-prefix - xl = length of expanded tilde-prefix - l = length of remainder after tilde-prefix - */ - l = (vl - xl) + 1; - - temp = (char *)xmalloc (dl2 + 2 + l); - strcpy (temp, dh2); - strcpy (temp + dl2, val + xl); - - free (dh2); - } - else - temp = savestring (val); - freetemp = 1; - } - else - { - temp = strrchr (val, '/'); - - if (temp) - { - temp++; - if (igncase == 0) - freetemp = match = strncmp (temp, hint, hint_len) == 0; - else - freetemp = match = strncasecmp (temp, hint, hint_len) == 0; - if (match) - temp = savestring (temp); - } - else - freetemp = match = 0; - } - -#if 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)) -#else - /* If we have found a match, and it is an executable file, return it. - We don't return directory names when searching $PATH, since the - bash execution code won't find executables in directories which - appear in directories in $PATH when they're specified using - relative pathnames. */ - if (match && (searching_path ? executable_file (val) : executable_or_directory (val))) -#endif - { - 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 there's a single match and it's a directory, set the append char - to the expected `/'. Otherwise, don't append anything. */ - if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) - rl_completion_append_character = '/'; - else - rl_completion_suppress_append = 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; *alist; alist++) - { - aentry = *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 /* BANG_HISTORY */ - -/* History and alias expand the line. */ -static int -history_and_alias_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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 = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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. NAME undergoes tilde expansion. */ -static int -test_for_directory (name) - const char *name; -{ - char *fn; - int r; - - fn = bash_tilde_expand (name, 0); - r = file_isdir (fn); - free (fn); - - return (r); -} - -/* 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; -} - -/* Simulate the expansions that will be performed by - rl_filename_completion_function. This must be called with the address of - a pointer to malloc'd memory. */ -static void -bash_directory_expansion (dirname) - char **dirname; -{ - char *d, *nd; - - d = savestring (*dirname); - - if (rl_directory_rewrite_hook) - (*rl_directory_rewrite_hook) (&d); - - if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d)) - { - free (*dirname); - *dirname = d; - } - else if (rl_completion_found_quote) - { - nd = bash_dequote_filename (d, rl_completion_quote_character); - free (*dirname); - free (d); - *dirname = nd; - } -} - -/* 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 (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; - } - -#if defined (HAVE_LSTAT) - if (should_expand_dirname && lstat (local_dirname, &sb) == 0) -#else - if (should_expand_dirname && stat (local_dirname, &sb) == 0) -#endif - should_expand_dirname = 0; - - if (should_expand_dirname) - { - new_dirname = savestring (local_dirname); - wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* 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; - } - } - else - { - /* Dequote the filename even if we don't expand it. */ - new_dirname = bash_dequote_filename (local_dirname, rl_completion_quote_character); - free (local_dirname); - local_dirname = *dirname = new_dirname; - } - - if (no_symbolic_links == 0 && (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); - if (len2 > 2) /* don't append `/' to `/' or `//' */ - { - 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, *ttext; - - if (state == 0) - { - rl_filename_completion_desired = 1; - FREE (matches); - if (globorig != globtext) - FREE (globorig); - FREE (globtext); - - ttext = bash_tilde_expand (text, 0); - - if (rl_explicit_arg) - { - globorig = savestring (ttext); - glen = strlen (ttext); - globtext = (char *)xmalloc (glen + 2); - strcpy (globtext, ttext); - globtext[glen] = '*'; - globtext[glen+1] = '\0'; - } - else - globtext = globorig = savestring (ttext); - - if (ttext != text) - free (ttext); - - 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-escaped characters to pass through unscathed. */ - if (*p == '\\') - { - /* Backslashes are preserved within single quotes. */ - if (quoted == '\'') - *r++ = *p; - /* Backslashes are preserved within double quotes unless the - character is one that is defined to be escaped */ - else if (quoted == '"' && ((sh_syntaxtab[p[1]] & CBSDQUOTE) == 0)) - *r++ = *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. */ - - 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 (s, '\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 (s, '!')) - cs = COMPLETE_BSQUOTE; - - if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && xstrchr (s, '!')) - { - cs = COMPLETE_BSQUOTE; - *qcp = '\0'; - } -#endif - - /* Don't tilde-expand backslash-quoted filenames, since only single and - double quotes inhibit tilde expansion. */ - mtext = s; - if (mtext[0] == '~' && rtype == SINGLE_MATCH && cs != COMPLETE_BSQUOTE) - mtext = bash_tilde_expand (s, 0); - - 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; - - qc = rl_dispatching ? rl_completion_quote_character : 0; - 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/bashline.c.save2 b/bashline.c.save2 deleted file mode 100644 index d39d22131..000000000 --- a/bashline.c.save2 +++ /dev/null @@ -1,3256 +0,0 @@ -/* bashline.c -- Bash's interface to the readline library. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 void bash_directory_expansion __P((char **)); -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; - -static int dot_in_path = 0; - -/* 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; - -/* Flag values for the final argument to bash_default_completion */ -#define DEFCOMP_CMDPOS 1 - -/* 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 old_value; - - /* 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 */ - - kseq[0] = TAB; - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tab_insert) - rl_bind_key_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}}\"" -#define POSIX_VI_EDIT_COMMAND "fc -e vi" - -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; -{ - if (posixly_correct) - return (edit_and_execute_command (count, c, VI_EDITING_MODE, POSIX_VI_EDIT_COMMAND)); - else - 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, SD_NOJMP)) <= 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, SD_NOJMP); - 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", SD_NOJMP); - - 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, dflags; - 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 == 0 && (in_command_position == 0 || text[0] == '\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 == 0 && e == s && text[0] == '\0') - prog_complete_matches = programmable_completions ("_EmptycmD_", text, s, e, &foundcs); - else if (e > s && assignment (n, 0) == 0) - 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 or - compopt. */ - if (foundcs) - { - pcomp_set_readline_variables (foundcs, 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) - { - dflags = 0; - if (in_command_position) - dflags |= DEFCOMP_CMDPOS; - matches = bash_default_completion (text, start, end, qc, dflags); - } - - return matches; -} - -char ** -bash_default_completion (text, start, end, qc, compflags) - const char *text; - int start, end, qc, compflags; -{ - 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 == 0 && (compflags & DEFCOMP_CMDPOS)) - { - /* If END == START and text[0] == 0, we are trying to complete an empty - command word. */ - if (no_empty_command_completion && end == start && text[0] == '\0') - { - 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)) - - dot_in_path = 0; - 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; - else if (matches[1] == 0 && CMD_IS_DIR(matches[0]) && dot_in_path == 0) - /* If we found a single match, without looking in the current - directory (because it's not in $PATH), but the found name is - also a command in the current directory, suppress appending any - terminating character, since it's ambiguous. */ - { - rl_completion_suppress_append = 1; - 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 on - rl_completion_suppress_append 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_completion_suppress_append = 1; - rl_filename_completion_desired = 0; - } - } - } - - /* 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 char *dequoted_hint = (char *)NULL; - static char *directory_part = (char *)NULL; - static int path_index, hint_len, dequoted_len, istate, igncase; - static int mapping_over, local_index, searching_path, hint_is_dir; - static int old_glob_ignore_case; - static SHELL_VAR **varlist = (SHELL_VAR **)NULL; -#if defined (ALIAS) - static alias_t **alias_list = (alias_t **)NULL; -#endif /* ALIAS */ - char *temp; - - /* We have to map over the possibilities for command words. If we have - no state, then make one just for that purpose. */ - if (state == 0) - { - if (dequoted_hint && dequoted_hint != hint) - free (dequoted_hint); - if (hint) - free (hint); - - mapping_over = searching_path = 0; - hint_is_dir = CMD_IS_DIR (hint_text); - val = (char *)NULL; - - temp = rl_variable_value ("completion-ignore-case"); - igncase = strcmp (temp, "on") == 0; - - old_glob_ignore_case = glob_ignore_case; - - /* 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); - directory_part = savestring (hint_text); - temp = strchr (directory_part, '/'); - if (temp) - *temp = 0; - else - { - free (directory_part); - directory_part = (char *)NULL; - } - } - else - hint = savestring (hint_text); - - dequoted_hint = hint; - /* If readline's completer found a quote character somewhere, but - didn't set the quote character, there must have been a quote - character embedded in the filename. It can't be at the start of - the filename, so we need to dequote the filename before we look - in the file system for it. */ - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - free (hint); - hint = dequoted_hint; - } - dequoted_len = hint_len = strlen (hint); - - if (filename_hint) - free (filename_hint); - - filename_hint = savestring (hint); - - mapping_over = 4; - istate = 0; - goto inner; - } - - dequoted_hint = hint = savestring (hint_text); - dequoted_len = hint_len = strlen (hint); - - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - dequoted_len = strlen (dequoted_hint); - } - - path = get_string_value ("PATH"); - path_index = dot_in_path = 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++; - } - - /* If the text passed is a directory in the current directory, return it - as a possible match. Executables in directories in the current - directory can be specified using relative pathnames and successfully - executed even when `.' is not in $PATH. */ - if (hint_is_dir) - { - hint_is_dir = 0; /* only return the hint text once */ - return (savestring (hint_text)); - } - - /* 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 == 0) - { - 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); - - searching_path = 1; - 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 (current_path[0] == '.' && current_path[1] == '\0') - dot_in_path = 1; - - if (filename_hint) - free (filename_hint); - - filename_hint = sh_makepath (current_path, hint, 0); - } - - inner: - val = rl_filename_completion_function (filename_hint, istate); - istate = 1; - - /* Limited support for completing command words with globbing chars. Only - a single match (multiple matches that end up reducing the number of - characters in the common prefix are bad) will ever be returned. */ - if (glob_pattern_p (hint)) - { - char **temp; - - if (state > 0) - { - glob_ignore_case = old_glob_ignore_case; - return ((char *)NULL); - } - glob_ignore_case = igncase; - temp = shell_glob_filename (hint); - glob_ignore_case = old_glob_ignore_case; - if (GLOB_FAILED (temp)) - return ((char *)NULL); - if (temp && temp[1]) /* multiple matches are bad */ - { - strvec_dispose (temp); - return ((char *)NULL); - } - val = temp[0]; - free (temp); - if (val && executable_or_directory (val)) - return (val); - free (val); - return ((char *)NULL); - } - - 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; - - if (absolute_program (hint)) - { - if (igncase == 0) - match = strncmp (val, hint, hint_len) == 0; - else - match = strncasecmp (val, hint, hint_len) == 0; - - /* If we performed tilde expansion, restore the original - filename. */ - if (*hint_text == '~') - { - int l, vl, dl, dl2, xl; - char *rd, *dh2, *expdir; - - vl = strlen (val); - - rd = savestring (filename_hint); - bash_directory_expansion (&rd); - dl = strlen (rd); - free (rd); - - dh2 = directory_part ? bash_dequote_filename (directory_part, 0) : 0; - bash_directory_expansion (&dh2); - dl2 = strlen (dh2); - - expdir = bash_tilde_expand (directory_part, 0); - xl = strlen (expdir); - free (expdir); - - /* - dh2 = unexpanded but dequoted tilde-prefix - dl = length of entire passed filename - dl2 = length of tilde-prefix - expdir = tilde-expanded tilde-prefix - xl = length of expanded tilde-prefix - l = length of remainder after tilde-prefix - */ - l = (vl - xl) + 1; - - temp = (char *)xmalloc (dl2 + 2 + l); - strcpy (temp, dh2); - strcpy (temp + dl2, val + xl); - - free (dh2); - } - else - temp = savestring (val); - freetemp = 1; - } - else - { - temp = strrchr (val, '/'); - - if (temp) - { - temp++; - if (igncase == 0) - freetemp = match = strncmp (temp, hint, hint_len) == 0; - else - freetemp = match = strncasecmp (temp, hint, hint_len) == 0; - if (match) - temp = savestring (temp); - } - else - freetemp = match = 0; - } - -#if 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)) -#else - /* If we have found a match, and it is an executable file, return it. - We don't return directory names when searching $PATH, since the - bash execution code won't find executables in directories which - appear in directories in $PATH when they're specified using - relative pathnames. */ - if (match && (searching_path ? executable_file (val) : executable_or_directory (val))) -#endif - { - 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 there's a single match and it's a directory, set the append char - to the expected `/'. Otherwise, don't append anything. */ - if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) - rl_completion_append_character = '/'; - else - rl_completion_suppress_append = 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; *alist; alist++) - { - aentry = *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 /* BANG_HISTORY */ - -/* History and alias expand the line. */ -static int -history_and_alias_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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 = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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. NAME undergoes tilde expansion. */ -static int -test_for_directory (name) - const char *name; -{ - char *fn; - int r; - - fn = bash_tilde_expand (name, 0); - r = file_isdir (fn); - free (fn); - - return (r); -} - -/* 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; -} - -/* Simulate the expansions that will be performed by - rl_filename_completion_function. This must be called with the address of - a pointer to malloc'd memory. */ -static void -bash_directory_expansion (dirname) - char **dirname; -{ - char *d, *nd; - - d = savestring (*dirname); - - if (rl_directory_rewrite_hook) - (*rl_directory_rewrite_hook) (&d); - - if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d)) - { - free (*dirname); - *dirname = d; - } - else if (rl_completion_found_quote) - { - nd = bash_dequote_filename (d, rl_completion_quote_character); - free (*dirname); - free (d); - *dirname = nd; - } -} - -/* 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 (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; - } - -#if defined (HAVE_LSTAT) - if (should_expand_dirname && lstat (local_dirname, &sb) == 0) -#else - if (should_expand_dirname && stat (local_dirname, &sb) == 0) -#endif - should_expand_dirname = 0; - - if (should_expand_dirname) - { - new_dirname = savestring (local_dirname); - wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* 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; - } - } - else - { - /* Dequote the filename even if we don't expand it. */ - new_dirname = bash_dequote_filename (local_dirname, rl_completion_quote_character); - free (local_dirname); - local_dirname = *dirname = new_dirname; - } - - if (no_symbolic_links == 0 && (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); - if (len2 > 2) /* don't append `/' to `/' or `//' */ - { - 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, *ttext; - - if (state == 0) - { - rl_filename_completion_desired = 1; - FREE (matches); - if (globorig != globtext) - FREE (globorig); - FREE (globtext); - - ttext = bash_tilde_expand (text, 0); - - if (rl_explicit_arg) - { - globorig = savestring (ttext); - glen = strlen (ttext); - globtext = (char *)xmalloc (glen + 2); - strcpy (globtext, ttext); - globtext[glen] = '*'; - globtext[glen+1] = '\0'; - } - else - globtext = globorig = savestring (ttext); - - if (ttext != text) - free (ttext); - - 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-escaped characters to pass through unscathed. */ - if (*p == '\\') - { - /* Backslashes are preserved within single quotes. */ - if (quoted == '\'') - *r++ = *p; - /* Backslashes are preserved within double quotes unless the - character is one that is defined to be escaped */ - else if (quoted == '"' && ((sh_syntaxtab[p[1]] & CBSDQUOTE) == 0)) - *r++ = *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. */ - - 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 (s, '\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 (s, '!')) - cs = COMPLETE_BSQUOTE; - - if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && xstrchr (s, '!')) - { - cs = COMPLETE_BSQUOTE; - *qcp = '\0'; - } -#endif - - /* Don't tilde-expand backslash-quoted filenames, since only single and - double quotes inhibit tilde expansion. */ - mtext = s; - if (mtext[0] == '~' && rtype == SINGLE_MATCH && cs != COMPLETE_BSQUOTE) - mtext = bash_tilde_expand (s, 0); - - 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; - - qc = rl_dispatching ? rl_completion_quote_character : 0; - 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/bashline.c.save3 b/bashline.c.save3 deleted file mode 100644 index 84506abf9..000000000 --- a/bashline.c.save3 +++ /dev/null @@ -1,3273 +0,0 @@ -/* bashline.c -- Bash's interface to the readline library. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 void bash_directory_expansion __P((char **)); -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; - -static int dot_in_path = 0; - -/* 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; - -/* Flag values for the final argument to bash_default_completion */ -#define DEFCOMP_CMDPOS 1 - -/* 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 old_value; - - /* 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 */ - - kseq[0] = TAB; - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tab_insert) - rl_bind_key_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}}\"" -#define POSIX_VI_EDIT_COMMAND "fc -e vi" - -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; -{ - if (posixly_correct) - return (edit_and_execute_command (count, c, VI_EDITING_MODE, POSIX_VI_EDIT_COMMAND)); - else - 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, SD_NOJMP)) <= 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, SD_NOJMP); - 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", SD_NOJMP); - - 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, dflags; - 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 == 0 && (in_command_position == 0 || text[0] == '\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 == 0 && e == s && text[0] == '\0') - prog_complete_matches = programmable_completions ("_EmptycmD_", text, s, e, &foundcs); - else if (e > s && assignment (n, 0) == 0) - 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 or - compopt. */ - if (foundcs) - { - pcomp_set_readline_variables (foundcs, 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) - { - dflags = 0; - if (in_command_position) - dflags |= DEFCOMP_CMDPOS; - matches = bash_default_completion (text, start, end, qc, dflags); - } - - return matches; -} - -char ** -bash_default_completion (text, start, end, qc, compflags) - const char *text; - int start, end, qc, compflags; -{ - 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 == 0 && (compflags & DEFCOMP_CMDPOS)) - { - /* If END == START and text[0] == 0, we are trying to complete an empty - command word. */ - if (no_empty_command_completion && end == start && text[0] == '\0') - { - 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)) - - dot_in_path = 0; - 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; - else if (matches[1] == 0 && CMD_IS_DIR(matches[0]) && dot_in_path == 0) - /* If we found a single match, without looking in the current - directory (because it's not in $PATH), but the found name is - also a command in the current directory, suppress appending any - terminating character, since it's ambiguous. */ - { - rl_completion_suppress_append = 1; - 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 on - rl_completion_suppress_append 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_completion_suppress_append = 1; - rl_filename_completion_desired = 0; - } - } - } - - /* 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 char *dequoted_hint = (char *)NULL; - static char *directory_part = (char *)NULL; - static char **glob_matches = (char **)NULL; - static int path_index, hint_len, dequoted_len, istate, igncase; - static int mapping_over, local_index, searching_path, hint_is_dir; - static int old_glob_ignore_case; - static SHELL_VAR **varlist = (SHELL_VAR **)NULL; -#if defined (ALIAS) - static alias_t **alias_list = (alias_t **)NULL; -#endif /* ALIAS */ - char *temp; - - /* We have to map over the possibilities for command words. If we have - no state, then make one just for that purpose. */ - if (state == 0) - { - if (dequoted_hint && dequoted_hint != hint) - free (dequoted_hint); - if (hint) - free (hint); - - mapping_over = searching_path = 0; - hint_is_dir = CMD_IS_DIR (hint_text); - val = (char *)NULL; - - temp = rl_variable_value ("completion-ignore-case"); - igncase = strcmp (temp, "on") == 0; - - if (glob_matches) - { - strvec_dispose (glob_matches); - glob_matches = (char **)NULL; - } - - if (glob_pattern_p (hint_text)) - { - hint = (*hint_text == '~') ? bash_tilde_expand (hint_text, 0) : savestring (hint_text); - - old_glob_ignore_case = glob_ignore_case; - - local_index = 0; - mapping_over = 5; - goto globword; - } - - /* 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); - directory_part = savestring (hint_text); - temp = strchr (directory_part, '/'); - if (temp) - *temp = 0; - else - { - free (directory_part); - directory_part = (char *)NULL; - } - } - else - hint = savestring (hint_text); - - dequoted_hint = hint; - /* If readline's completer found a quote character somewhere, but - didn't set the quote character, there must have been a quote - character embedded in the filename. It can't be at the start of - the filename, so we need to dequote the filename before we look - in the file system for it. */ - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - free (hint); - hint = dequoted_hint; - } - dequoted_len = hint_len = strlen (hint); - - if (filename_hint) - free (filename_hint); - - filename_hint = savestring (hint); - - mapping_over = 4; - istate = 0; - goto inner; - } - - dequoted_hint = hint = savestring (hint_text); - dequoted_len = hint_len = strlen (hint); - - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - dequoted_len = strlen (dequoted_hint); - } - - path = get_string_value ("PATH"); - path_index = dot_in_path = 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++; - } - -globword: - /* Limited support for completing command words with globbing chars. Only - a single match (multiple matches that end up reducing the number of - characters in the common prefix are bad) will ever be returned. */ - if (glob_pattern_p (hint)) - { - if (state > 0) - { - glob_ignore_case = old_glob_ignore_case; - return ((char *)NULL); - } - glob_ignore_case = igncase; - glob_matches = shell_glob_filename (hint); - glob_ignore_case = old_glob_ignore_case; - if (GLOB_FAILED (glob_matches)) - return ((char *)NULL); - if (glob_matches && glob_matches[1]) /* multiple matches are bad */ - { - strvec_dispose (glob_matches); - glob_matches = (char **)NULL; - return ((char *)NULL); - } - val = glob_matches[0]; - free (glob_matches); - glob_matches = (char **)NULL; - if (val && executable_or_directory (val)) - return (val); - free (val); - return ((char *)NULL); - } - - /* If the text passed is a directory in the current directory, return it - as a possible match. Executables in directories in the current - directory can be specified using relative pathnames and successfully - executed even when `.' is not in $PATH. */ - if (hint_is_dir) - { - hint_is_dir = 0; /* only return the hint text once */ - return (savestring (hint_text)); - } - - /* 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 == 0) - { - 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); - - searching_path = 1; - 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 (current_path[0] == '.' && current_path[1] == '\0') - dot_in_path = 1; - - if (filename_hint) - free (filename_hint); - - filename_hint = sh_makepath (current_path, hint, 0); - } - - 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; - - if (absolute_program (hint)) - { - if (igncase == 0) - match = strncmp (val, hint, hint_len) == 0; - else - match = strncasecmp (val, hint, hint_len) == 0; - - /* If we performed tilde expansion, restore the original - filename. */ - if (*hint_text == '~') - { - int l, vl, dl, dl2, xl; - char *rd, *dh2, *expdir; - - vl = strlen (val); - - rd = savestring (filename_hint); - bash_directory_expansion (&rd); - dl = strlen (rd); - free (rd); - - dh2 = directory_part ? bash_dequote_filename (directory_part, 0) : 0; - bash_directory_expansion (&dh2); - dl2 = strlen (dh2); - - expdir = bash_tilde_expand (directory_part, 0); - xl = strlen (expdir); - free (expdir); - - /* - dh2 = unexpanded but dequoted tilde-prefix - dl = length of entire passed filename - dl2 = length of tilde-prefix - expdir = tilde-expanded tilde-prefix - xl = length of expanded tilde-prefix - l = length of remainder after tilde-prefix - */ - l = (vl - xl) + 1; - - temp = (char *)xmalloc (dl2 + 2 + l); - strcpy (temp, dh2); - strcpy (temp + dl2, val + xl); - - free (dh2); - } - else - temp = savestring (val); - freetemp = 1; - } - else - { - temp = strrchr (val, '/'); - - if (temp) - { - temp++; - if (igncase == 0) - freetemp = match = strncmp (temp, hint, hint_len) == 0; - else - freetemp = match = strncasecmp (temp, hint, hint_len) == 0; - if (match) - temp = savestring (temp); - } - else - freetemp = match = 0; - } - -#if 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)) -#else - /* If we have found a match, and it is an executable file, return it. - We don't return directory names when searching $PATH, since the - bash execution code won't find executables in directories which - appear in directories in $PATH when they're specified using - relative pathnames. */ - if (match && (searching_path ? executable_file (val) : executable_or_directory (val))) -#endif - { - 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 there's a single match and it's a directory, set the append char - to the expected `/'. Otherwise, don't append anything. */ - if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) - rl_completion_append_character = '/'; - else - rl_completion_suppress_append = 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; *alist; alist++) - { - aentry = *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 /* BANG_HISTORY */ - -/* History and alias expand the line. */ -static int -history_and_alias_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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 = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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. NAME undergoes tilde expansion. */ -static int -test_for_directory (name) - const char *name; -{ - char *fn; - int r; - - fn = bash_tilde_expand (name, 0); - r = file_isdir (fn); - free (fn); - - return (r); -} - -/* 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; -} - -/* Simulate the expansions that will be performed by - rl_filename_completion_function. This must be called with the address of - a pointer to malloc'd memory. */ -static void -bash_directory_expansion (dirname) - char **dirname; -{ - char *d, *nd; - - d = savestring (*dirname); - - if (rl_directory_rewrite_hook) - (*rl_directory_rewrite_hook) (&d); - - if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d)) - { - free (*dirname); - *dirname = d; - } - else if (rl_completion_found_quote) - { - nd = bash_dequote_filename (d, rl_completion_quote_character); - free (*dirname); - free (d); - *dirname = nd; - } -} - -/* 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 (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; - } - -#if defined (HAVE_LSTAT) - if (should_expand_dirname && lstat (local_dirname, &sb) == 0) -#else - if (should_expand_dirname && stat (local_dirname, &sb) == 0) -#endif - should_expand_dirname = 0; - - if (should_expand_dirname) - { - new_dirname = savestring (local_dirname); - wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* 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; - } - } - else - { - /* Dequote the filename even if we don't expand it. */ - new_dirname = bash_dequote_filename (local_dirname, rl_completion_quote_character); - free (local_dirname); - local_dirname = *dirname = new_dirname; - } - - if (no_symbolic_links == 0 && (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); - if (len2 > 2) /* don't append `/' to `/' or `//' */ - { - 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, *ttext; - - if (state == 0) - { - rl_filename_completion_desired = 1; - FREE (matches); - if (globorig != globtext) - FREE (globorig); - FREE (globtext); - - ttext = bash_tilde_expand (text, 0); - - if (rl_explicit_arg) - { - globorig = savestring (ttext); - glen = strlen (ttext); - globtext = (char *)xmalloc (glen + 2); - strcpy (globtext, ttext); - globtext[glen] = '*'; - globtext[glen+1] = '\0'; - } - else - globtext = globorig = savestring (ttext); - - if (ttext != text) - free (ttext); - - 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-escaped characters to pass through unscathed. */ - if (*p == '\\') - { - /* Backslashes are preserved within single quotes. */ - if (quoted == '\'') - *r++ = *p; - /* Backslashes are preserved within double quotes unless the - character is one that is defined to be escaped */ - else if (quoted == '"' && ((sh_syntaxtab[p[1]] & CBSDQUOTE) == 0)) - *r++ = *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. */ - - 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 (s, '\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 (s, '!')) - cs = COMPLETE_BSQUOTE; - - if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && xstrchr (s, '!')) - { - cs = COMPLETE_BSQUOTE; - *qcp = '\0'; - } -#endif - - /* Don't tilde-expand backslash-quoted filenames, since only single and - double quotes inhibit tilde expansion. */ - mtext = s; - if (mtext[0] == '~' && rtype == SINGLE_MATCH && cs != COMPLETE_BSQUOTE) - mtext = bash_tilde_expand (s, 0); - - 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; - - qc = rl_dispatching ? rl_completion_quote_character : 0; - 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/bashline.c.save4 b/bashline.c.save4 deleted file mode 100644 index 43f73d4cb..000000000 --- a/bashline.c.save4 +++ /dev/null @@ -1,3279 +0,0 @@ -/* bashline.c -- Bash's interface to the readline library. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 void bash_directory_expansion __P((char **)); -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; - -static int dot_in_path = 0; - -/* 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; - -/* Flag values for the final argument to bash_default_completion */ -#define DEFCOMP_CMDPOS 1 - -/* 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 old_value; - - /* 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 */ - - kseq[0] = TAB; - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tab_insert) - rl_bind_key_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}}\"" -#define POSIX_VI_EDIT_COMMAND "fc -e vi" - -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; -{ - if (posixly_correct) - return (edit_and_execute_command (count, c, VI_EDITING_MODE, POSIX_VI_EDIT_COMMAND)); - else - 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, SD_NOJMP)) <= 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, SD_NOJMP); - 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", SD_NOJMP); - - 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, dflags; - 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 == 0 && (in_command_position == 0 || text[0] == '\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 == 0 && e == s && text[0] == '\0') - prog_complete_matches = programmable_completions ("_EmptycmD_", text, s, e, &foundcs); - else if (e > s && assignment (n, 0) == 0) - 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 or - compopt. */ - if (foundcs) - { - pcomp_set_readline_variables (foundcs, 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) - { - dflags = 0; - if (in_command_position) - dflags |= DEFCOMP_CMDPOS; - matches = bash_default_completion (text, start, end, qc, dflags); - } - - return matches; -} - -char ** -bash_default_completion (text, start, end, qc, compflags) - const char *text; - int start, end, qc, compflags; -{ - 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 == 0 && (compflags & DEFCOMP_CMDPOS)) - { - /* If END == START and text[0] == 0, we are trying to complete an empty - command word. */ - if (no_empty_command_completion && end == start && text[0] == '\0') - { - 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)) - - dot_in_path = 0; - 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; - else if (matches[1] == 0 && CMD_IS_DIR(matches[0]) && dot_in_path == 0) - /* If we found a single match, without looking in the current - directory (because it's not in $PATH), but the found name is - also a command in the current directory, suppress appending any - terminating character, since it's ambiguous. */ - { - rl_completion_suppress_append = 1; - 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 on - rl_completion_suppress_append 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_completion_suppress_append = 1; - rl_filename_completion_desired = 0; - } - } - } - - /* 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 char *dequoted_hint = (char *)NULL; - static char *directory_part = (char *)NULL; - static char **glob_matches = (char **)NULL; - static int path_index, hint_len, dequoted_len, istate, igncase; - static int mapping_over, local_index, searching_path, hint_is_dir; - static int old_glob_ignore_case; - static SHELL_VAR **varlist = (SHELL_VAR **)NULL; -#if defined (ALIAS) - static alias_t **alias_list = (alias_t **)NULL; -#endif /* ALIAS */ - char *temp; - - /* We have to map over the possibilities for command words. If we have - no state, then make one just for that purpose. */ - if (state == 0) - { - if (dequoted_hint && dequoted_hint != hint) - free (dequoted_hint); - if (hint) - free (hint); - - mapping_over = searching_path = 0; - hint_is_dir = CMD_IS_DIR (hint_text); - val = (char *)NULL; - - temp = rl_variable_value ("completion-ignore-case"); - igncase = strcmp (temp, "on") == 0; - - if (glob_matches) - { - free (glob_matches); - glob_matches = (char **)NULL; - } - - if (glob_pattern_p (hint_text)) - { - hint = (*hint_text == '~') ? bash_tilde_expand (hint_text, 0) : savestring (hint_text); - dequoted_hint = hint; - - old_glob_ignore_case = glob_ignore_case; - - local_index = 0; - mapping_over = 5; - goto globword; - } - - /* 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); - directory_part = savestring (hint_text); - temp = strchr (directory_part, '/'); - if (temp) - *temp = 0; - else - { - free (directory_part); - directory_part = (char *)NULL; - } - } - else - hint = savestring (hint_text); - - dequoted_hint = hint; - /* If readline's completer found a quote character somewhere, but - didn't set the quote character, there must have been a quote - character embedded in the filename. It can't be at the start of - the filename, so we need to dequote the filename before we look - in the file system for it. */ - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - free (hint); - hint = dequoted_hint; - } - dequoted_len = hint_len = strlen (hint); - - if (filename_hint) - free (filename_hint); - - filename_hint = savestring (hint); - - mapping_over = 4; - istate = 0; - goto inner; - } - - dequoted_hint = hint = savestring (hint_text); - dequoted_len = hint_len = strlen (hint); - - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - dequoted_len = strlen (dequoted_hint); - } - - path = get_string_value ("PATH"); - path_index = dot_in_path = 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++; - } - -globword: - /* Limited support for completing command words with globbing chars. Only - a single match (multiple matches that end up reducing the number of - characters in the common prefix are bad) will ever be returned on - regular completion. */ - if (glob_pattern_p (hint)) - { - if (state == 0) - { - glob_ignore_case = igncase; - glob_matches = shell_glob_filename (hint); - glob_ignore_case = old_glob_ignore_case; - - if (GLOB_FAILED (glob_matches)) - { - glob_matches = (char **)NULL; - return ((char *)NULL); - } - - if (glob_matches && glob_matches[1] && rl_completion_type == TAB) /* multiple matches are bad */ - return ((char *)NULL); - - local_index = 0; - } - - while (val = glob_matches[local_index++]) - { - if (executable_or_directory (val)) - return (val); - free (val); - } - - glob_ignore_case = old_glob_ignore_case; - return ((char *)NULL); - } - - /* If the text passed is a directory in the current directory, return it - as a possible match. Executables in directories in the current - directory can be specified using relative pathnames and successfully - executed even when `.' is not in $PATH. */ - if (hint_is_dir) - { - hint_is_dir = 0; /* only return the hint text once */ - return (savestring (hint_text)); - } - - /* 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 == 0) - { - 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); - - searching_path = 1; - 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 (current_path[0] == '.' && current_path[1] == '\0') - dot_in_path = 1; - - if (filename_hint) - free (filename_hint); - - filename_hint = sh_makepath (current_path, hint, 0); - } - - 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; - - if (absolute_program (hint)) - { - if (igncase == 0) - match = strncmp (val, hint, hint_len) == 0; - else - match = strncasecmp (val, hint, hint_len) == 0; - - /* If we performed tilde expansion, restore the original - filename. */ - if (*hint_text == '~') - { - int l, vl, dl, dl2, xl; - char *rd, *dh2, *expdir; - - vl = strlen (val); - - rd = savestring (filename_hint); - bash_directory_expansion (&rd); - dl = strlen (rd); - free (rd); - - dh2 = directory_part ? bash_dequote_filename (directory_part, 0) : 0; - bash_directory_expansion (&dh2); - dl2 = strlen (dh2); - - expdir = bash_tilde_expand (directory_part, 0); - xl = strlen (expdir); - free (expdir); - - /* - dh2 = unexpanded but dequoted tilde-prefix - dl = length of entire passed filename - dl2 = length of tilde-prefix - expdir = tilde-expanded tilde-prefix - xl = length of expanded tilde-prefix - l = length of remainder after tilde-prefix - */ - l = (vl - xl) + 1; - - temp = (char *)xmalloc (dl2 + 2 + l); - strcpy (temp, dh2); - strcpy (temp + dl2, val + xl); - - free (dh2); - } - else - temp = savestring (val); - freetemp = 1; - } - else - { - temp = strrchr (val, '/'); - - if (temp) - { - temp++; - if (igncase == 0) - freetemp = match = strncmp (temp, hint, hint_len) == 0; - else - freetemp = match = strncasecmp (temp, hint, hint_len) == 0; - if (match) - temp = savestring (temp); - } - else - freetemp = match = 0; - } - -#if 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)) -#else - /* If we have found a match, and it is an executable file, return it. - We don't return directory names when searching $PATH, since the - bash execution code won't find executables in directories which - appear in directories in $PATH when they're specified using - relative pathnames. */ - if (match && (searching_path ? executable_file (val) : executable_or_directory (val))) -#endif - { - 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 there's a single match and it's a directory, set the append char - to the expected `/'. Otherwise, don't append anything. */ - if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) - rl_completion_append_character = '/'; - else - rl_completion_suppress_append = 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; *alist; alist++) - { - aentry = *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 /* BANG_HISTORY */ - -/* History and alias expand the line. */ -static int -history_and_alias_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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 = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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. NAME undergoes tilde expansion. */ -static int -test_for_directory (name) - const char *name; -{ - char *fn; - int r; - - fn = bash_tilde_expand (name, 0); - r = file_isdir (fn); - free (fn); - - return (r); -} - -/* 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; -} - -/* Simulate the expansions that will be performed by - rl_filename_completion_function. This must be called with the address of - a pointer to malloc'd memory. */ -static void -bash_directory_expansion (dirname) - char **dirname; -{ - char *d, *nd; - - d = savestring (*dirname); - - if (rl_directory_rewrite_hook) - (*rl_directory_rewrite_hook) (&d); - - if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d)) - { - free (*dirname); - *dirname = d; - } - else if (rl_completion_found_quote) - { - nd = bash_dequote_filename (d, rl_completion_quote_character); - free (*dirname); - free (d); - *dirname = nd; - } -} - -/* 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 (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; - } - -#if defined (HAVE_LSTAT) - if (should_expand_dirname && lstat (local_dirname, &sb) == 0) -#else - if (should_expand_dirname && stat (local_dirname, &sb) == 0) -#endif - should_expand_dirname = 0; - - if (should_expand_dirname) - { - new_dirname = savestring (local_dirname); - wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* 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; - } - } - else - { - /* Dequote the filename even if we don't expand it. */ - new_dirname = bash_dequote_filename (local_dirname, rl_completion_quote_character); - free (local_dirname); - local_dirname = *dirname = new_dirname; - } - - if (no_symbolic_links == 0 && (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); - if (len2 > 2) /* don't append `/' to `/' or `//' */ - { - 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, *ttext; - - if (state == 0) - { - rl_filename_completion_desired = 1; - FREE (matches); - if (globorig != globtext) - FREE (globorig); - FREE (globtext); - - ttext = bash_tilde_expand (text, 0); - - if (rl_explicit_arg) - { - globorig = savestring (ttext); - glen = strlen (ttext); - globtext = (char *)xmalloc (glen + 2); - strcpy (globtext, ttext); - globtext[glen] = '*'; - globtext[glen+1] = '\0'; - } - else - globtext = globorig = savestring (ttext); - - if (ttext != text) - free (ttext); - - 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-escaped characters to pass through unscathed. */ - if (*p == '\\') - { - /* Backslashes are preserved within single quotes. */ - if (quoted == '\'') - *r++ = *p; - /* Backslashes are preserved within double quotes unless the - character is one that is defined to be escaped */ - else if (quoted == '"' && ((sh_syntaxtab[p[1]] & CBSDQUOTE) == 0)) - *r++ = *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. */ - - 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 (s, '\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 (s, '!')) - cs = COMPLETE_BSQUOTE; - - if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && xstrchr (s, '!')) - { - cs = COMPLETE_BSQUOTE; - *qcp = '\0'; - } -#endif - - /* Don't tilde-expand backslash-quoted filenames, since only single and - double quotes inhibit tilde expansion. */ - mtext = s; - if (mtext[0] == '~' && rtype == SINGLE_MATCH && cs != COMPLETE_BSQUOTE) - mtext = bash_tilde_expand (s, 0); - - 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; - - qc = rl_dispatching ? rl_completion_quote_character : 0; - 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/bashline.c.save5 b/bashline.c.save5 deleted file mode 100644 index b3b10c0ab..000000000 --- a/bashline.c.save5 +++ /dev/null @@ -1,3321 +0,0 @@ -/* bashline.c -- Bash's interface to the readline library. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 char *restore_tilde __P((char *, char *)); - -static void bash_directory_expansion __P((char **)); -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; - -static int dot_in_path = 0; - -/* 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; - -/* Flag values for the final argument to bash_default_completion */ -#define DEFCOMP_CMDPOS 1 - -/* 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 old_value; - - /* 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 */ - - kseq[0] = TAB; - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tab_insert) - rl_bind_key_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}}\"" -#define POSIX_VI_EDIT_COMMAND "fc -e vi" - -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; -{ - if (posixly_correct) - return (edit_and_execute_command (count, c, VI_EDITING_MODE, POSIX_VI_EDIT_COMMAND)); - else - 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, SD_NOJMP)) <= 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, SD_NOJMP); - 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", SD_NOJMP); - - 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, dflags; - 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 == 0 && (in_command_position == 0 || text[0] == '\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 == 0 && e == s && text[0] == '\0') - prog_complete_matches = programmable_completions ("_EmptycmD_", text, s, e, &foundcs); - else if (e > s && assignment (n, 0) == 0) - 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 or - compopt. */ - if (foundcs) - { - pcomp_set_readline_variables (foundcs, 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) - { - dflags = 0; - if (in_command_position) - dflags |= DEFCOMP_CMDPOS; - matches = bash_default_completion (text, start, end, qc, dflags); - } - - return matches; -} - -char ** -bash_default_completion (text, start, end, qc, compflags) - const char *text; - int start, end, qc, compflags; -{ - 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 == 0 && (compflags & DEFCOMP_CMDPOS)) - { - /* If END == START and text[0] == 0, we are trying to complete an empty - command word. */ - if (no_empty_command_completion && end == start && text[0] == '\0') - { - 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)) - - dot_in_path = 0; - 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; - else if (matches[1] == 0 && CMD_IS_DIR(matches[0]) && dot_in_path == 0) - /* If we found a single match, without looking in the current - directory (because it's not in $PATH), but the found name is - also a command in the current directory, suppress appending any - terminating character, since it's ambiguous. */ - { - rl_completion_suppress_append = 1; - 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 on - rl_completion_suppress_append 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_completion_suppress_append = 1; - rl_filename_completion_desired = 0; - } - } - } - - /* 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 char *dequoted_hint = (char *)NULL; - static char *directory_part = (char *)NULL; - static char **glob_matches = (char **)NULL; - static int path_index, hint_len, dequoted_len, istate, igncase; - static int mapping_over, local_index, searching_path, hint_is_dir; - static int old_glob_ignore_case, globpat; - static SHELL_VAR **varlist = (SHELL_VAR **)NULL; -#if defined (ALIAS) - static alias_t **alias_list = (alias_t **)NULL; -#endif /* ALIAS */ - char *temp; - - /* We have to map over the possibilities for command words. If we have - no state, then make one just for that purpose. */ - if (state == 0) - { - if (dequoted_hint && dequoted_hint != hint) - free (dequoted_hint); - if (hint) - free (hint); - - mapping_over = searching_path = 0; - hint_is_dir = CMD_IS_DIR (hint_text); - val = (char *)NULL; - - temp = rl_variable_value ("completion-ignore-case"); - igncase = strcmp (temp, "on") == 0; - - if (glob_matches) - { - free (glob_matches); - glob_matches = (char **)NULL; - } - - globpat = glob_pattern_p (hint_text); - - /* 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 (globpat || 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); - directory_part = savestring (hint_text); - temp = strchr (directory_part, '/'); - if (temp) - *temp = 0; - else - { - free (directory_part); - directory_part = (char *)NULL; - } - } - else - hint = savestring (hint_text); - - dequoted_hint = hint; - /* If readline's completer found a quote character somewhere, but - didn't set the quote character, there must have been a quote - character embedded in the filename. It can't be at the start of - the filename, so we need to dequote the filename before we look - in the file system for it. */ - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - free (hint); - hint = dequoted_hint; - } - dequoted_len = hint_len = strlen (hint); - - if (filename_hint) - free (filename_hint); - - filename_hint = savestring (hint); - - istate = 0; - - if (globpat) - { - mapping_over = 5; - goto globword; - } - else - { - mapping_over = 4; - goto inner; - } - } - - dequoted_hint = hint = savestring (hint_text); - dequoted_len = hint_len = strlen (hint); - - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - dequoted_len = strlen (dequoted_hint); - } - - path = get_string_value ("PATH"); - path_index = dot_in_path = 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++; - } - -globword: - /* Limited support for completing command words with globbing chars. Only - a single match (multiple matches that end up reducing the number of - characters in the common prefix are bad) will ever be returned on - regular completion. */ - if (glob_pattern_p (hint)) - { - if (state == 0) - { - glob_ignore_case = igncase; - glob_matches = shell_glob_filename (hint); - glob_ignore_case = old_glob_ignore_case; - - if (GLOB_FAILED (glob_matches)) - { - glob_matches = (char **)NULL; - return ((char *)NULL); - } - - if (glob_matches && glob_matches[1] && rl_completion_type == TAB) /* multiple matches are bad */ - return ((char *)NULL); - - local_index = 0; - } - - while (val = glob_matches[local_index++]) - { - if (executable_or_directory (val)) - return (val); - free (val); - } - - glob_ignore_case = old_glob_ignore_case; - return ((char *)NULL); - } - - /* If the text passed is a directory in the current directory, return it - as a possible match. Executables in directories in the current - directory can be specified using relative pathnames and successfully - executed even when `.' is not in $PATH. */ - if (hint_is_dir) - { - hint_is_dir = 0; /* only return the hint text once */ - return (savestring (hint_text)); - } - - /* 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 == 0) - { - 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); - - searching_path = 1; - 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 (current_path[0] == '.' && current_path[1] == '\0') - dot_in_path = 1; - - if (filename_hint) - free (filename_hint); - - filename_hint = sh_makepath (current_path, hint, 0); - } - - 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; - - if (absolute_program (hint)) - { - if (igncase == 0) - match = strncmp (val, hint, hint_len) == 0; - else - match = strncasecmp (val, hint, hint_len) == 0; - - /* If we performed tilde expansion, restore the original - filename. */ - if (*hint_text == '~') - { - int l, vl, dl2, xl; - char *dh2, *expdir; - - vl = strlen (val); - -#if 0 - /* XXX -- don't need this or RD or DL */ - rd = savestring (filename_hint); - bash_directory_expansion (&rd); - dl = strlen (rd); - free (rd); -#endif - - dh2 = directory_part ? bash_dequote_filename (directory_part, 0) : 0; - bash_directory_expansion (&dh2); - dl2 = strlen (dh2); - - expdir = bash_tilde_expand (directory_part, 0); - xl = strlen (expdir); - free (expdir); - - /* - dh2 = unexpanded but dequoted tilde-prefix - dl2 = length of tilde-prefix - expdir = tilde-expanded tilde-prefix - xl = length of expanded tilde-prefix - l = length of remainder after tilde-prefix - */ - l = (vl - xl) + 1; - - temp = (char *)xmalloc (dl2 + 2 + l); - strcpy (temp, dh2); - strcpy (temp + dl2, val + xl); - - free (dh2); - } - else - temp = savestring (val); - freetemp = 1; - } - else - { - temp = strrchr (val, '/'); - - if (temp) - { - temp++; - if (igncase == 0) - freetemp = match = strncmp (temp, hint, hint_len) == 0; - else - freetemp = match = strncasecmp (temp, hint, hint_len) == 0; - if (match) - temp = savestring (temp); - } - else - freetemp = match = 0; - } - -#if 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)) -#else - /* If we have found a match, and it is an executable file, return it. - We don't return directory names when searching $PATH, since the - bash execution code won't find executables in directories which - appear in directories in $PATH when they're specified using - relative pathnames. */ - if (match && (searching_path ? executable_file (val) : executable_or_directory (val))) -#endif - { - 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 there's a single match and it's a directory, set the append char - to the expected `/'. Otherwise, don't append anything. */ - if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) - rl_completion_append_character = '/'; - else - rl_completion_suppress_append = 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; *alist; alist++) - { - aentry = *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 /* BANG_HISTORY */ - -/* History and alias expand the line. */ -static int -history_and_alias_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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 = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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. NAME undergoes tilde expansion. */ -static int -test_for_directory (name) - const char *name; -{ - char *fn; - int r; - - fn = bash_tilde_expand (name, 0); - r = file_isdir (fn); - free (fn); - - return (r); -} - -/* 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; -} - -/* Replace a tilde-prefix in VAL with a `~', assuming the user typed it. VAL - is an expanded filename. DIRECTORY_PART is the leading directory portion - of the un-tilde-expanded version of VAL. */ -static char * -restore_tilde (val, directory_part) - char *val, *directory_part; -{ - int l, vl, dl2, xl; - char *dh2, *expdir, *ret; - - vl = strlen (val); - - /* We need to duplicate the expansions readline performs on the directory - portion before passing it to our completion function. */ - dh2 = directory_part ? bash_dequote_filename (directory_part, 0) : 0; - bash_directory_expansion (&dh2); - dl2 = strlen (dh2); - - expdir = bash_tilde_expand (directory_part, 0); - xl = strlen (expdir); - free (expdir); - - /* - dh2 = unexpanded but dequoted tilde-prefix - dl2 = length of tilde-prefix - expdir = tilde-expanded tilde-prefix - xl = length of expanded tilde-prefix - l = length of remainder after tilde-prefix - */ - l = (vl - xl) + 1; - - ret = (char *)xmalloc (dl2 + 2 + l); - strcpy (ret, dh2); - strcpy (ret + dl2, val + xl); - - free (dh2); - return (ret); -} - -/* Simulate the expansions that will be performed by - rl_filename_completion_function. This must be called with the address of - a pointer to malloc'd memory. */ -static void -bash_directory_expansion (dirname) - char **dirname; -{ - char *d, *nd; - - d = savestring (*dirname); - - if (rl_directory_rewrite_hook) - (*rl_directory_rewrite_hook) (&d); - - if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d)) - { - free (*dirname); - *dirname = d; - } - else if (rl_completion_found_quote) - { - nd = bash_dequote_filename (d, rl_completion_quote_character); - free (*dirname); - free (d); - *dirname = nd; - } -} - -/* 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 (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; - } - -#if defined (HAVE_LSTAT) - if (should_expand_dirname && lstat (local_dirname, &sb) == 0) -#else - if (should_expand_dirname && stat (local_dirname, &sb) == 0) -#endif - should_expand_dirname = 0; - - if (should_expand_dirname) - { - new_dirname = savestring (local_dirname); - wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* 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; - } - } - else - { - /* Dequote the filename even if we don't expand it. */ - new_dirname = bash_dequote_filename (local_dirname, rl_completion_quote_character); - free (local_dirname); - local_dirname = *dirname = new_dirname; - } - - if (no_symbolic_links == 0 && (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); - if (len2 > 2) /* don't append `/' to `/' or `//' */ - { - 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, *ttext; - - if (state == 0) - { - rl_filename_completion_desired = 1; - FREE (matches); - if (globorig != globtext) - FREE (globorig); - FREE (globtext); - - ttext = bash_tilde_expand (text, 0); - - if (rl_explicit_arg) - { - globorig = savestring (ttext); - glen = strlen (ttext); - globtext = (char *)xmalloc (glen + 2); - strcpy (globtext, ttext); - globtext[glen] = '*'; - globtext[glen+1] = '\0'; - } - else - globtext = globorig = savestring (ttext); - - if (ttext != text) - free (ttext); - - 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-escaped characters to pass through unscathed. */ - if (*p == '\\') - { - /* Backslashes are preserved within single quotes. */ - if (quoted == '\'') - *r++ = *p; - /* Backslashes are preserved within double quotes unless the - character is one that is defined to be escaped */ - else if (quoted == '"' && ((sh_syntaxtab[p[1]] & CBSDQUOTE) == 0)) - *r++ = *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. */ - - 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 (s, '\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 (s, '!')) - cs = COMPLETE_BSQUOTE; - - if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && xstrchr (s, '!')) - { - cs = COMPLETE_BSQUOTE; - *qcp = '\0'; - } -#endif - - /* Don't tilde-expand backslash-quoted filenames, since only single and - double quotes inhibit tilde expansion. */ - mtext = s; - if (mtext[0] == '~' && rtype == SINGLE_MATCH && cs != COMPLETE_BSQUOTE) - mtext = bash_tilde_expand (s, 0); - - 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; - - qc = rl_dispatching ? rl_completion_quote_character : 0; - 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/bashline.c~ b/bashline.c~ deleted file mode 100644 index 28dd18c63..000000000 --- a/bashline.c~ +++ /dev/null @@ -1,3372 +0,0 @@ -/* bashline.c -- Bash's interface to the readline library. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 - -#define RL_BOOLEAN_VARIABLE_VALUE(s) ((s)[0] == 'o' && (s)[1] == 'n' && (s)[2] == '\0') - -#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 char *restore_tilde __P((char *, char *)); - -static void bash_directory_expansion __P((char **)); -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 int bash_dabbrev_expand __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 array_needs_making; -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; - -/* Perform spelling correction on directory names during word completion */ -int dircomplete_spelling = 0; - -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; - -static int dot_in_path = 0; - -/* 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; - -/* Flag values for the final argument to bash_default_completion */ -#define DEFCOMP_CMDPOS 1 - -/* 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 old_value; - - /* 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); - rl_add_defun ("dabbrev-expand", bash_dabbrev_expand, -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 */ - - kseq[0] = TAB; - kseq[1] = '\0'; - func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tab_insert) - rl_bind_key_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; -} - -void -bashline_reinitialize () -{ - bash_readline_initialized = 0; -} - -/* 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_reset () -{ - 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}}\"" -#define POSIX_VI_EDIT_COMMAND "fc -e vi" - -static int -edit_and_execute_command (count, c, editing_mode, edit_command) - int count, c, editing_mode; - char *edit_command; -{ - char *command, *metaval; - int r, cclc, rrs, metaflag; - - 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); - } - - metaval = rl_variable_value ("input-meta"); - metaflag = RL_BOOLEAN_VARIABLE_VALUE (metaval); - - /* 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. */ - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); - r = parse_and_execute (command, (editing_mode == VI_EDITING_MODE) ? "v" : "C-xC-e", SEVAL_NOHIST); - if (rl_prep_term_function) - (*rl_prep_term_function) (metaflag); - - 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; -{ - if (posixly_correct) - return (edit_and_execute_command (count, c, VI_EDITING_MODE, POSIX_VI_EDIT_COMMAND)); - else - 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, SD_NOJMP)) <= 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, SD_NOJMP); - 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", SD_NOJMP); - - 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, dflags; - 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 == 0 && (in_command_position == 0 || text[0] == '\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 == 0 && e == s && text[0] == '\0') - prog_complete_matches = programmable_completions ("_EmptycmD_", text, s, e, &foundcs); - else if (e > s && assignment (n, 0) == 0) - 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 or - compopt. */ - if (foundcs) - { - pcomp_set_readline_variables (foundcs, 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) - { - dflags = 0; - if (in_command_position) - dflags |= DEFCOMP_CMDPOS; - matches = bash_default_completion (text, start, end, qc, dflags); - } - - return matches; -} - -char ** -bash_default_completion (text, start, end, qc, compflags) - const char *text; - int start, end, qc, compflags; -{ - 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 == 0 && (compflags & DEFCOMP_CMDPOS)) - { - /* If END == START and text[0] == 0, we are trying to complete an empty - command word. */ - if (no_empty_command_completion && end == start && text[0] == '\0') - { - 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)) - - dot_in_path = 0; - 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; - else if (matches[1] == 0 && CMD_IS_DIR(matches[0]) && dot_in_path == 0) - /* If we found a single match, without looking in the current - directory (because it's not in $PATH), but the found name is - also a command in the current directory, suppress appending any - terminating character, since it's ambiguous. */ - { - rl_completion_suppress_append = 1; - 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 on - rl_completion_suppress_append 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_completion_suppress_append = 1; - rl_filename_completion_desired = 0; - } - } - } - - /* 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 char *dequoted_hint = (char *)NULL; - static char *directory_part = (char *)NULL; - static char **glob_matches = (char **)NULL; - static int path_index, hint_len, dequoted_len, istate, igncase; - static int mapping_over, local_index, searching_path, hint_is_dir; - static int old_glob_ignore_case, globpat; - static SHELL_VAR **varlist = (SHELL_VAR **)NULL; -#if defined (ALIAS) - static alias_t **alias_list = (alias_t **)NULL; -#endif /* ALIAS */ - char *temp; - - /* We have to map over the possibilities for command words. If we have - no state, then make one just for that purpose. */ - if (state == 0) - { - if (dequoted_hint && dequoted_hint != hint) - free (dequoted_hint); - if (hint) - free (hint); - - mapping_over = searching_path = 0; - hint_is_dir = CMD_IS_DIR (hint_text); - val = (char *)NULL; - - temp = rl_variable_value ("completion-ignore-case"); - igncase = RL_BOOLEAN_VARIABLE_VALUE (temp); - - if (glob_matches) - { - free (glob_matches); - glob_matches = (char **)NULL; - } - - globpat = glob_pattern_p (hint_text); - - /* 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 (globpat || 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); - directory_part = savestring (hint_text); - temp = strchr (directory_part, '/'); - if (temp) - *temp = 0; - else - { - free (directory_part); - directory_part = (char *)NULL; - } - } - else - hint = savestring (hint_text); - - dequoted_hint = hint; - /* If readline's completer found a quote character somewhere, but - didn't set the quote character, there must have been a quote - character embedded in the filename. It can't be at the start of - the filename, so we need to dequote the filename before we look - in the file system for it. */ - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - free (hint); - hint = dequoted_hint; - } - dequoted_len = hint_len = strlen (hint); - - if (filename_hint) - free (filename_hint); - - filename_hint = savestring (hint); - - istate = 0; - - if (globpat) - { - mapping_over = 5; - goto globword; - } - else - { - mapping_over = 4; - goto inner; - } - } - - dequoted_hint = hint = savestring (hint_text); - dequoted_len = hint_len = strlen (hint); - - if (rl_completion_found_quote && rl_completion_quote_character == 0) - { - dequoted_hint = bash_dequote_filename (hint, 0); - dequoted_len = strlen (dequoted_hint); - } - - path = get_string_value ("PATH"); - path_index = dot_in_path = 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++; - } - -globword: - /* Limited support for completing command words with globbing chars. Only - a single match (multiple matches that end up reducing the number of - characters in the common prefix are bad) will ever be returned on - regular completion. */ - if (glob_pattern_p (hint)) - { - if (state == 0) - { - glob_ignore_case = igncase; - glob_matches = shell_glob_filename (hint); - glob_ignore_case = old_glob_ignore_case; - - if (GLOB_FAILED (glob_matches) || glob_matches == 0) - { - glob_matches = (char **)NULL; - return ((char *)NULL); - } - - local_index = 0; - - if (glob_matches[1] && rl_completion_type == TAB) /* multiple matches are bad */ - return ((char *)NULL); - } - - while (val = glob_matches[local_index++]) - { - if (executable_or_directory (val)) - { - if (*hint_text == '~') - { - temp = restore_tilde (val, directory_part); - free (val); - val = temp; - } - return (val); - } - free (val); - } - - glob_ignore_case = old_glob_ignore_case; - return ((char *)NULL); - } - - /* If the text passed is a directory in the current directory, return it - as a possible match. Executables in directories in the current - directory can be specified using relative pathnames and successfully - executed even when `.' is not in $PATH. */ - if (hint_is_dir) - { - hint_is_dir = 0; /* only return the hint text once */ - return (savestring (hint_text)); - } - - /* 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 == 0) - { - char *current_path; - - /* Get the next directory from the path. If there is none, then we - are all done. */ - if (path == 0 || path[path_index] == 0 || - (current_path = extract_colon_unit (path, &path_index)) == 0) - return ((char *)NULL); - - searching_path = 1; - 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 (current_path[0] == '.' && current_path[1] == '\0') - dot_in_path = 1; - - if (filename_hint) - free (filename_hint); - - filename_hint = sh_makepath (current_path, hint, 0); - free (current_path); /* XXX */ - } - - 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; - - if (absolute_program (hint)) - { - if (igncase == 0) - match = strncmp (val, hint, hint_len) == 0; - else - match = strncasecmp (val, hint, hint_len) == 0; - - /* If we performed tilde expansion, restore the original - filename. */ - if (*hint_text == '~') - temp = restore_tilde (val, directory_part); - else - temp = savestring (val); - freetemp = 1; - } - else - { - temp = strrchr (val, '/'); - - if (temp) - { - temp++; - if (igncase == 0) - freetemp = match = strncmp (temp, hint, hint_len) == 0; - else - freetemp = match = strncasecmp (temp, hint, hint_len) == 0; - if (match) - temp = savestring (temp); - } - else - freetemp = match = 0; - } - -#if 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)) -#else - /* If we have found a match, and it is an executable file, return it. - We don't return directory names when searching $PATH, since the - bash execution code won't find executables in directories which - appear in directories in $PATH when they're specified using - relative pathnames. */ - if (match && (searching_path ? executable_file (val) : executable_or_directory (val))) -#endif - { - 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 there's a single match and it's a directory, set the append char - to the expected `/'. Otherwise, don't append anything. */ - if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) - rl_completion_append_character = '/'; - else - rl_completion_suppress_append = 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; *alist; alist++) - { - aentry = *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 /* BANG_HISTORY */ - -/* History and alias expand the line. */ -static int -history_and_alias_expand_line (count, ignore) - int count, ignore; -{ - char *new_line; - - new_line = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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 = 0; -#if defined (BANG_HISTORY) - new_line = history_expand_line_internal (rl_line_buffer); -#endif - -#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. NAME undergoes tilde expansion. */ -static int -test_for_directory (name) - const char *name; -{ - char *fn; - int r; - - fn = bash_tilde_expand (name, 0); - r = file_isdir (fn); - free (fn); - - return (r); -} - -/* 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; -} - -/* Replace a tilde-prefix in VAL with a `~', assuming the user typed it. VAL - is an expanded filename. DIRECTORY_PART is the tilde-prefix portion - of the un-tilde-expanded version of VAL (what the user typed). */ -static char * -restore_tilde (val, directory_part) - char *val, *directory_part; -{ - int l, vl, dl2, xl; - char *dh2, *expdir, *ret; - - vl = strlen (val); - - /* We need to duplicate the expansions readline performs on the directory - portion before passing it to our completion function. */ - dh2 = directory_part ? bash_dequote_filename (directory_part, 0) : 0; - bash_directory_expansion (&dh2); - dl2 = strlen (dh2); - - expdir = bash_tilde_expand (directory_part, 0); - xl = strlen (expdir); - free (expdir); - - /* - dh2 = unexpanded but dequoted tilde-prefix - dl2 = length of tilde-prefix - expdir = tilde-expanded tilde-prefix - xl = length of expanded tilde-prefix - l = length of remainder after tilde-prefix - */ - l = (vl - xl) + 1; - - ret = (char *)xmalloc (dl2 + 2 + l); - strcpy (ret, dh2); - strcpy (ret + dl2, val + xl); - - free (dh2); - return (ret); -} - -/* Simulate the expansions that will be performed by - rl_filename_completion_function. This must be called with the address of - a pointer to malloc'd memory. */ -static void -bash_directory_expansion (dirname) - char **dirname; -{ - char *d, *nd; - - d = savestring (*dirname); - - if (rl_directory_rewrite_hook) - (*rl_directory_rewrite_hook) (&d); - - if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d)) - { - free (*dirname); - *dirname = d; - } - else if (rl_completion_found_quote) - { - nd = bash_dequote_filename (d, rl_completion_quote_character); - free (*dirname); - free (d); - *dirname = nd; - } -} - -/* 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 (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; - } - -#if defined (HAVE_LSTAT) - if (should_expand_dirname && lstat (local_dirname, &sb) == 0) -#else - if (should_expand_dirname && stat (local_dirname, &sb) == 0) -#endif - should_expand_dirname = 0; - - if (should_expand_dirname) - { - new_dirname = savestring (local_dirname); - wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* 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; - } - } - else - { - /* Dequote the filename even if we don't expand it. */ - new_dirname = bash_dequote_filename (local_dirname, rl_completion_quote_character); - free (local_dirname); - local_dirname = *dirname = new_dirname; - } - - if (no_symbolic_links == 0 && (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); - - /* Try spelling correction if initial canonicalization fails. */ - if (temp2 == 0 && dircomplete_spelling) - { - temp2 = dirspell (temp1); - if (temp2) - { - free (temp1); - temp1 = temp2; - temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); - return_value = temp2 != 0; - } - } - /* If we can't canonicalize, bail. */ - if (temp2 == 0) - { - free (temp1); - return 1; - } - len1 = strlen (temp1); - if (temp1[len1 - 1] == '/') - { - len2 = strlen (temp2); - if (len2 > 2) /* don't append `/' to `/' or `//' */ - { - 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; -} - -static int -bash_dabbrev_expand (count, key) - int count, key; -{ - int r; - rl_compentry_func_t *orig_func; - rl_completion_func_t *orig_attempt_func; - - orig_func = rl_menu_completion_entry_function; - orig_attempt_func = rl_attempted_completion_function; - - rl_menu_completion_entry_function = history_completion_generator; - rl_attempted_completion_function = (rl_completion_func_t *)NULL; - rl_filename_completion_desired = 0; - - /* XXX - use rl_completion_mode here? */ - if (rl_last_func == bash_dabbrev_expand) - rl_last_func = rl_menu_complete; - r = rl_menu_complete (count, key); - - rl_last_func = bash_dabbrev_expand; - rl_menu_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, *ttext; - - if (state == 0) - { - rl_filename_completion_desired = 1; - FREE (matches); - if (globorig != globtext) - FREE (globorig); - FREE (globtext); - - ttext = bash_tilde_expand (text, 0); - - if (rl_explicit_arg) - { - globorig = savestring (ttext); - glen = strlen (ttext); - globtext = (char *)xmalloc (glen + 2); - strcpy (globtext, ttext); - globtext[glen] = '*'; - globtext[glen+1] = '\0'; - } - else - globtext = globorig = savestring (ttext); - - if (ttext != text) - free (ttext); - - 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-escaped characters to pass through unscathed. */ - if (*p == '\\') - { - /* Backslashes are preserved within single quotes. */ - if (quoted == '\'') - *r++ = *p; - /* Backslashes are preserved within double quotes unless the - character is one that is defined to be escaped */ - else if (quoted == '"' && ((sh_syntaxtab[p[1]] & CBSDQUOTE) == 0)) - *r++ = *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. */ - - 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 (s, '\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 (s, '!')) - cs = COMPLETE_BSQUOTE; - - if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && - history_expansion_inhibited == 0 && xstrchr (s, '!')) - { - cs = COMPLETE_BSQUOTE; - *qcp = '\0'; - } -#endif - - /* Don't tilde-expand backslash-quoted filenames, since only single and - double quotes inhibit tilde expansion. */ - mtext = s; - if (mtext[0] == '~' && rtype == SINGLE_MATCH && cs != COMPLETE_BSQUOTE) - mtext = bash_tilde_expand (s, 0); - - 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; - sh_parser_state_t ps; - char *cmd, *value, *l; - SHELL_VAR *v; - char ibuf[INT_STRLEN_BOUND(int) + 1]; - - /* 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 */ - - v = bind_variable ("READLINE_LINE", rl_line_buffer, 0); - if (v) - VSETATTR (v, att_exported); - l = value_cell (v); - value = inttostr (rl_point, ibuf, sizeof (ibuf)); - v = bind_int_variable ("READLINE_POINT", value); - if (v) - VSETATTR (v, att_exported); - array_needs_making = 1; - - save_parser_state (&ps); - parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE); - restore_parser_state (&ps); - - v = find_variable ("READLINE_LINE"); - if (value_cell (v) != l) - maybe_make_readline_line (value_cell (v)); - - unbind_variable ("READLINE_LINE"); - unbind_variable ("READLINE_POINT"); - array_needs_making = 1; - - /* 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; - - qc = rl_dispatching ? rl_completion_quote_character : 0; - 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/bashline.h~ b/bashline.h~ deleted file mode 100644 index cd84d879f..000000000 --- a/bashline.h~ +++ /dev/null @@ -1,50 +0,0 @@ -/* bashline.h -- interface to the bash readline functions in bashline.c. */ - -/* Copyright (C) 1993 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#if !defined (_BASHLINE_H_) -#define _BASHLINE_H_ - -#include "stdc.h" - -extern int bash_readline_initialized; - -extern void posix_readline_initialize __P((int)); -extern int enable_hostname_completion __P((int)); -extern void initialize_readline __P((void)); -extern void bashline_reset __P((void)); -extern void bashline_reinitialize __P((void)); -extern int bash_re_edit __P((char *)); - -extern int bind_keyseq_to_unix_command __P((char *)); - -extern char **bash_default_completion __P((const char *, int, int, int, int)); - -/* Used by programmable completion code. */ -extern char *command_word_completion_function __P((const char *, int)); -extern char *bash_groupname_completion_function __P((const char *, int)); -extern char *bash_servicename_completion_function __P((const char *, int)); - -extern char **get_hostname_list __P((void)); -extern void clear_hostname_list __P((void)); - -extern char **bash_directory_completion_matches __P((const char *)); -extern char *bash_dequote_text __P((const char *)); - -#endif /* _BASHLINE_H_ */ diff --git a/braces.c~ b/braces.c~ deleted file mode 100644 index 7ba1057f2..000000000 --- a/braces.c~ +++ /dev/null @@ -1,678 +0,0 @@ -/* braces.c -- code for doing word expansion in curly braces. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -/* Stuff in curly braces gets expanded before all other shell expansions. */ - -#include "config.h" - -#if defined (BRACE_EXPANSION) - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "bashansi.h" - -#if defined (SHELL) -# include "shell.h" -#endif /* SHELL */ - -#include "general.h" -#include "shmbutil.h" -#include "chartypes.h" - -#define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n') - -#define BRACE_SEQ_SPECIFIER ".." - -/* Basic idea: - - Segregate the text into 3 sections: preamble (stuff before an open brace), - postamble (stuff after the matching close brace) and amble (stuff after - preamble, and before postamble). Expand amble, and then tack on the - expansions to preamble. Expand postamble, and tack on the expansions to - the result so far. - */ - -/* The character which is used to separate arguments. */ -static const int brace_arg_separator = ','; - -#if defined (__P) -static int brace_gobbler __P((char *, size_t, int *, int)); -static char **expand_amble __P((char *, size_t, int)); -static char **expand_seqterm __P((char *, size_t)); -static char **mkseq __P((int, int, int, int, int)); -static char **array_concat __P((char **, char **)); -#else -static int brace_gobbler (); -static char **expand_amble (); -static char **expand_seqterm (); -static char **mkseq(); -static char **array_concat (); -#endif - -#if 0 -static void -dump_result (a) - char **a; -{ - int i; - - for (i = 0; a[i]; i++) - printf ("dump_result: a[%d] = -%s-\n", i, a[i]); -} -#endif - -/* Return an array of strings; the brace expansion of TEXT. */ -char ** -brace_expand (text) - char *text; -{ - register int start; - size_t tlen; - char *preamble, *postamble, *amble; - size_t alen; - char **tack, **result; - int i, j, c, c1; - - DECLARE_MBSTATE; - - /* Find the text of the preamble. */ - tlen = strlen (text); - i = 0; -#if defined (CSH_BRACE_COMPAT) - c = brace_gobbler (text, tlen, &i, '{'); /* } */ -#else - /* Make sure that when we exit this loop, c == 0 or text[i] begins a - valid brace expansion sequence. */ - do - { - c = brace_gobbler (text, tlen, &i, '{'); /* } */ - c1 = c; - /* Verify that c begins a valid brace expansion word. If it doesn't, we - go on. Loop stops when there are no more open braces in the word. */ - if (c) - { - start = j = i + 1; /* { */ - c = brace_gobbler (text, tlen, &j, '}'); - if (c == 0) /* it's not */ - { - i++; - c = c1; - continue; - } - else /* it is */ - { - c = c1; - break; - } - } - else - break; - } - while (c); -#endif /* !CSH_BRACE_COMPAT */ - - preamble = (char *)xmalloc (i + 1); - strncpy (preamble, text, i); - preamble[i] = '\0'; - - result = (char **)xmalloc (2 * sizeof (char *)); - result[0] = preamble; - result[1] = (char *)NULL; - - /* Special case. If we never found an exciting character, then - the preamble is all of the text, so just return that. */ - if (c != '{') - return (result); - - /* Find the amble. This is the stuff inside this set of braces. */ - start = ++i; - c = brace_gobbler (text, tlen, &i, '}'); - - /* What if there isn't a matching close brace? */ - if (c == 0) - { -#if defined (NOTDEF) - /* Well, if we found an unquoted BRACE_ARG_SEPARATOR between START - and I, then this should be an error. Otherwise, it isn't. */ - j = start; - while (j < i) - { - if (text[j] == '\\') - { - j++; - ADVANCE_CHAR (text, tlen, j); - continue; - } - - if (text[j] == brace_arg_separator) - { /* { */ - strvec_dispose (result); - report_error ("no closing `%c' in %s", '}', text); - throw_to_top_level (); - } - ADVANCE_CHAR (text, tlen, j); - } -#endif - free (preamble); /* Same as result[0]; see initialization. */ - result[0] = savestring (text); - return (result); - } - -#if defined (SHELL) - amble = substring (text, start, i); - alen = i - start; -#else - amble = (char *)xmalloc (1 + (i - start)); - strncpy (amble, &text[start], (i - start)); - alen = i - start; - amble[alen] = '\0'; -#endif - -#if defined (SHELL) - INITIALIZE_MBSTATE; - - /* If the amble does not contain an unquoted BRACE_ARG_SEPARATOR, then - just return without doing any expansion. */ - j = 0; - while (amble[j]) - { - if (amble[j] == '\\') - { - j++; - ADVANCE_CHAR (amble, alen, j); - continue; - } - - if (amble[j] == brace_arg_separator) - break; - - ADVANCE_CHAR (amble, alen, j); - } - - if (amble[j] == 0) - { - tack = expand_seqterm (amble, alen); - if (tack) - goto add_tack; - else - { - free (amble); - free (preamble); - result[0] = savestring (text); - return (result); - } - } -#endif /* SHELL */ - - tack = expand_amble (amble, alen, 0); -add_tack: - result = array_concat (result, tack); - free (amble); - strvec_dispose (tack); - - postamble = text + i + 1; - - tack = brace_expand (postamble); - result = array_concat (result, tack); - strvec_dispose (tack); - - return (result); -} - -/* Expand the text found inside of braces. We simply try to split the - text at BRACE_ARG_SEPARATORs into separate strings. We then brace - expand each slot which needs it, until there are no more slots which - need it. */ -static char ** -expand_amble (text, tlen, flags) - char *text; - size_t tlen; - int flags; -{ - char **result, **partial; - char *tem; - int start, i, c; - - DECLARE_MBSTATE; - - result = (char **)NULL; - - start = i = 0; - c = 1; - while (c) - { - c = brace_gobbler (text, tlen, &i, brace_arg_separator); -#if defined (SHELL) - tem = substring (text, start, i); -#else - tem = (char *)xmalloc (1 + (i - start)); - strncpy (tem, &text[start], (i - start)); - tem[i- start] = '\0'; -#endif - - partial = brace_expand (tem); - - if (!result) - result = partial; - else - { - register int lr, lp, j; - - lr = strvec_len (result); - lp = strvec_len (partial); - - result = strvec_resize (result, lp + lr + 1); - - for (j = 0; j < lp; j++) - result[lr + j] = partial[j]; - - result[lr + j] = (char *)NULL; - free (partial); - } - free (tem); - ADVANCE_CHAR (text, tlen, i); - start = i; - } - return (result); -} - -#define ST_BAD 0 -#define ST_INT 1 -#define ST_CHAR 2 -#define ST_ZINT 3 - -static char ** -mkseq (start, end, incr, type, width) - int start, end, incr, type, width; -{ - int n, i; - char **result, *t; - - n = abs (end - start) + 1; - result = strvec_create (n + 1); - - if (incr == 0) - incr = 1; - - if (start > end && incr > 0) - incr = -incr; - else if (start < end && incr < 0) - incr = -incr; - - /* Make sure we go through the loop at least once, so {3..3} prints `3' */ - i = 0; - n = start; - do - { -#if defined (SHELL) - QUIT; /* XXX - memory leak here */ -#endif - if (type == ST_INT) - result[i++] = itos (n); - else if (type == ST_ZINT) - { - int len; - len = asprintf (&t, "%0*d", width, n); - result[i++] = t; - } - else - { - t = (char *)xmalloc (2); - t[0] = n; - t[1] = '\0'; - result[i++] = t; - } - n += incr; - if ((incr < 0 && n < end) || (incr > 0 && n > end)) - break; - } - while (1); - - result[i] = (char *)0; - return (result); -} - -static char ** -expand_seqterm (text, tlen) - char *text; - size_t tlen; -{ - char *t, *lhs, *rhs; - int i, lhs_t, rhs_t, lhs_v, rhs_v, incr, lhs_l, rhs_l, width; - intmax_t tl, tr; - char **result, *ep; - - t = strstr (text, BRACE_SEQ_SPECIFIER); - if (t == 0) - return ((char **)NULL); - - lhs_l = t - text; /* index of start of BRACE_SEQ_SPECIFIER */ - lhs = substring (text, 0, lhs_l); - rhs = substring (text, lhs_l + sizeof(BRACE_SEQ_SPECIFIER) - 1, tlen); - - if (lhs[0] == 0 || rhs[0] == 0) - { - free (lhs); - free (rhs); - return ((char **)NULL); - } - - /* Now figure out whether LHS and RHS are integers or letters. Both - sides have to match. */ - lhs_t = (legal_number (lhs, &tl)) ? ST_INT : - ((ISALPHA (lhs[0]) && lhs[1] == 0) ? ST_CHAR : ST_BAD); - - /* Decide on rhs and whether or not it looks like the user specified - an increment */ - ep = 0; - if (ISDIGIT (rhs[0]) || ((rhs[0] == '+' || rhs[0] == '-') && ISDIGIT (rhs[1]))) - { - rhs_t = ST_INT; - tr = strtoimax (rhs, &ep, 10); - if (ep && *ep != 0 && *ep != '.') - rhs_t = ST_BAD; /* invalid */ - } - else if (ISALPHA (rhs[0]) && (rhs[1] == 0 || rhs[1] == '.')) - { - rhs_t = ST_CHAR; - ep = rhs + 1; - } - else - { - rhs_t = ST_BAD; - ep = 0; - } - - incr = 1; - if (rhs_t != ST_BAD) - { - if (ep && *ep == '.' && ep[1] == '.' && ep[2]) - incr = strtoimax (ep + 2, &ep, 10); - if (*ep != 0) - rhs_t = ST_BAD; /* invalid incr */ - } - - if (lhs_t != rhs_t || lhs_t == ST_BAD || rhs_t == ST_BAD) - { - free (lhs); - free (rhs); - return ((char **)NULL); - } - - /* OK, we have something. It's either a sequence of integers, ascending - or descending, or a sequence or letters, ditto. Generate the sequence, - put it into a string vector, and return it. */ - - if (lhs_t == ST_CHAR) - { - lhs_v = (unsigned char)lhs[0]; - rhs_v = (unsigned char)rhs[0]; - width = 1; - } - else - { - lhs_v = tl; /* integer truncation */ - rhs_v = tr; - - /* Decide whether or not the terms need zero-padding */ - rhs_l = tlen - lhs_l - sizeof (BRACE_SEQ_SPECIFIER) + 1; - width = 0; - if (lhs_l > 1 && lhs[0] == '0') - width = lhs_l, lhs_t = ST_ZINT; - if (lhs_l > 2 && lhs[0] == '-' && lhs[1] == '0') - width = lhs_l, lhs_t = ST_ZINT; - if (rhs_l > 1 && rhs[0] == '0' && width < rhs_l) - width = rhs_l, lhs_t = ST_ZINT; - if (rhs_l > 2 && rhs[0] == '-' && rhs[1] == '0' && width < rhs_l) - width = rhs_l, lhs_t = ST_ZINT; - } - - result = mkseq (lhs_v, rhs_v, incr, lhs_t, width); - - free (lhs); - free (rhs); - - return (result); -} - -/* Start at INDEX, and skip characters in TEXT. Set INDEX to the - index of the character matching SATISFY. This understands about - quoting. Return the character that caused us to stop searching; - this is either the same as SATISFY, or 0. */ -/* If SATISFY is `}', we are looking for a brace expression, so we - should enforce the rules that govern valid brace expansions: - 1) to count as an arg separator, a comma or `..' has to be outside - an inner set of braces. -*/ -static int -brace_gobbler (text, tlen, indx, satisfy) - char *text; - size_t tlen; - int *indx; - int satisfy; -{ - register int i, c, quoted, level, commas, pass_next; -#if defined (SHELL) - int si; - char *t; -#endif - DECLARE_MBSTATE; - - level = quoted = pass_next = 0; -#if defined (CSH_BRACE_COMPAT) - commas = 1; -#else - commas = (satisfy == '}') ? 0 : 1; -#endif - - i = *indx; - while (c = text[i]) - { - if (pass_next) - { - pass_next = 0; - ADVANCE_CHAR (text, tlen, i); - continue; - } - - /* A backslash escapes the next character. This allows backslash to - escape the quote character in a double-quoted string. */ - if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`')) - { - pass_next = 1; - i++; - continue; - } - -#if defined (SHELL) - /* If compiling for the shell, treat ${...} like \{...} */ - if (c == '$' && text[i+1] == '{' && quoted != '\'') /* } */ - { - pass_next = 1; - i++; - if (quoted == 0) - level++; - continue; - } -#endif - - if (quoted) - { - if (c == quoted) - quoted = 0; - ADVANCE_CHAR (text, tlen, i); - continue; - } - - if (c == '"' || c == '\'' || c == '`') - { - quoted = c; - i++; - continue; - } - -#if defined (SHELL) - /* Pass new-style command and process substitutions through unchanged. */ - if ((c == '$' || c == '<' || c == '>') && text[i+1] == '(') /* ) */ - { - si = i + 2; - t = extract_command_subst (text, &si, 0); - i = si; - free (t); - i++; - continue; - } -#endif - - if (c == satisfy && level == 0 && quoted == 0 && commas > 0) - { - /* We ignore an open brace surrounded by whitespace, and also - an open brace followed immediately by a close brace preceded - by whitespace. */ - if (c == '{' && - ((!i || brace_whitespace (text[i - 1])) && - (brace_whitespace (text[i + 1]) || text[i + 1] == '}'))) - { - i++; - continue; - } - - break; - } - - if (c == '{') - level++; - else if (c == '}' && level) - level--; -#if !defined (CSH_BRACE_COMPAT) - else if (satisfy == '}' && c == brace_arg_separator && level == 0) - commas++; - else if (satisfy == '}' && STREQN (text+i, BRACE_SEQ_SPECIFIER, 2) && - text[i+2] != satisfy && level == 0) - commas++; -#endif - - ADVANCE_CHAR (text, tlen, i); - } - - *indx = i; - return (c); -} - -/* Return a new array of strings which is the result of appending each - string in ARR2 to each string in ARR1. The resultant array is - len (arr1) * len (arr2) long. For convenience, ARR1 (and its contents) - are free ()'ed. ARR1 can be NULL, in that case, a new version of ARR2 - is returned. */ -static char ** -array_concat (arr1, arr2) - char **arr1, **arr2; -{ - register int i, j, len, len1, len2; - register char **result; - - if (arr1 == 0) - return (strvec_copy (arr2)); - - if (arr2 == 0) - return (strvec_copy (arr1)); - - len1 = strvec_len (arr1); - len2 = strvec_len (arr2); - - result = (char **)xmalloc ((1 + (len1 * len2)) * sizeof (char *)); - - len = 0; - for (i = 0; i < len1; i++) - { - int strlen_1 = strlen (arr1[i]); - - for (j = 0; j < len2; j++) - { - result[len] = (char *)xmalloc (1 + strlen_1 + strlen (arr2[j])); - strcpy (result[len], arr1[i]); - strcpy (result[len] + strlen_1, arr2[j]); - len++; - } - free (arr1[i]); - } - free (arr1); - - result[len] = (char *)NULL; - return (result); -} - -#if defined (TEST) -#include - -fatal_error (format, arg1, arg2) - char *format, *arg1, *arg2; -{ - report_error (format, arg1, arg2); - exit (1); -} - -report_error (format, arg1, arg2) - char *format, *arg1, *arg2; -{ - fprintf (stderr, format, arg1, arg2); - fprintf (stderr, "\n"); -} - -main () -{ - char example[256]; - - for (;;) - { - char **result; - int i; - - fprintf (stderr, "brace_expand> "); - - if ((!fgets (example, 256, stdin)) || - (strncmp (example, "quit", 4) == 0)) - break; - - if (strlen (example)) - example[strlen (example) - 1] = '\0'; - - result = brace_expand (example); - - for (i = 0; result[i]; i++) - printf ("%s\n", result[i]); - - free_array (result); - } -} - -/* - * Local variables: - * compile-command: "gcc -g -Bstatic -DTEST -o brace_expand braces.c general.o" - * end: - */ - -#endif /* TEST */ -#endif /* BRACE_EXPANSION */ diff --git a/builtins.h~ b/builtins.h~ deleted file mode 100644 index 265fc6c37..000000000 --- a/builtins.h~ +++ /dev/null @@ -1,62 +0,0 @@ -/* builtins.h -- What a builtin looks like, and where to find them. */ - -/* Copyright (C) 1987-2007 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "command.h" -#include "general.h" - -#if defined (ALIAS) -#include "alias.h" -#endif - -/* Flags describing various things about a builtin. */ -#define BUILTIN_ENABLED 0x01 /* This builtin is enabled. */ -#define BUILTIN_DELETED 0x02 /* This has been deleted with enable -d. */ -#define STATIC_BUILTIN 0x04 /* This builtin is not dynamically loaded. */ -#define SPECIAL_BUILTIN 0x08 /* This is a Posix `special' builtin. */ -#define ASSIGNMENT_BUILTIN 0x10 /* This builtin takes assignment statements. */ -#define POSIX_BUILTIN 0x20 /* This builtins is special in the Posix command search order. */ - -#define BASE_INDENT 4 -#define MAN_INDENT 2 - -/* The thing that we build the array of builtins out of. */ -struct builtin { - char *name; /* The name that the user types. */ - sh_builtin_func_t *function; /* The address of the invoked function. */ - int flags; /* One of the #defines above. */ - char * const *long_doc; /* NULL terminated array of strings. */ - const char *short_doc; /* Short version of documenation. */ - char *handle; /* for future use */ -}; - -/* Found in builtins.c, created by builtins/mkbuiltins. */ -extern int num_shell_builtins; /* Number of shell builtins. */ -extern struct builtin static_shell_builtins[]; -extern struct builtin *shell_builtins; -extern struct builtin *current_builtin; diff --git a/builtins/Makefile.in~ b/builtins/Makefile.in~ deleted file mode 100644 index 14348fabb..000000000 --- a/builtins/Makefile.in~ +++ /dev/null @@ -1,644 +0,0 @@ -# This Makefile for building libbuiltins.a is in -*- text -*- for Emacs. -# -# Copyright (C) 1996-2005 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. - -PACKAGE = @PACKAGE_NAME@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_VERSION = @PACKAGE_VERSION@ - -# -SHELL = @MAKE_SHELL@ -RANLIB = @RANLIB@ -CC = @CC@ -CC_FOR_BUILD = @CC_FOR_BUILD@ -AR = @AR@ -ARFLAGS = @ARFLAGS@ -RM = rm -f -CP = cp - -EXEEXT = @EXEEXT@ - -prefix = @prefix@ - -srcdir = @srcdir@ -VPATH = .:@srcdir@ -topdir = @top_srcdir@ - -datarootdir = @datarootdir@ - -includedir = @includedir@ -datadir = @datadir@ -localedir = @localedir@ - -# Support an alternate destination root directory for package building -DESTDIR = - -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -BUILD_DIR = @BUILD_DIR@ - -LIBBUILD = ${BUILD_DIR}/lib - -PROFILE_FLAGS = @PROFILE_FLAGS@ -CFLAGS = @CFLAGS@ -CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ @CROSS_COMPILE@ -CPPFLAGS = @CPPFLAGS@ -CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ -LOCAL_CFLAGS = @LOCAL_CFLAGS@ ${DEBUG} -DEFS = @DEFS@ -LOCAL_DEFS = @LOCAL_DEFS@ - -LIBS = @LIBS@ -LDFLAGS = @LDFLAGS@ $(LOCAL_LDFLAGS) $(CFLAGS) -LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ $(LOCAL_LDFLAGS) $(CFLAGS_FOR_BUILD) -LOCAL_LDFLAGS = @LOCAL_LDFLAGS@ -#LIBS_FOR_BUILD = @LIBS_FOR_BUILD@ -LIBS_FOR_BUILD = $(LIBS) - -BASHINCDIR = ${topdir}/include - -RL_INCLUDEDIR = @RL_INCLUDEDIR@ - -INTL_LIBSRC = ${topdir}/lib/intl -INTL_BUILDDIR = ${LIBBUILD}/intl -INTL_LIBDIR = ${INTL_BUILDDIR} -INTL_LIBRARY = ${INTL_BUILDDIR}/libintl.a -INTL_INC = @INTL_INC@ -INTL_DEP = @INTL_DEP@ -LIBINTL_H = @LIBINTL_H@ - -HELPDIR = @HELPDIR@ -MKDIRS = ${topdir}/support/mkdirs - -INCLUDES = -I. -I.. @RL_INCLUDE@ -I$(topdir) -I$(BASHINCDIR) -I$(topdir)/lib -I$(srcdir) ${INTL_INC} - -BASE_CCFLAGS = ${PROFILE_FLAGS} $(DEFS) $(LOCAL_DEFS) $(SYSTEM_FLAGS) \ - ${INCLUDES} $(LOCAL_CFLAGS) - -CCFLAGS = $(BASE_CCFLAGS) $(CPPFLAGS) $(CFLAGS) - -CCFLAGS_FOR_BUILD = $(BASE_CCFLAGS) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) - -GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual \ - -Wcast-align -Wstrict-prototypes -Wconversion \ - -Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic - -MKBUILTINS = mkbuiltins$(EXEEXT) -DIRECTDEFINE = -D $(srcdir) -HELPDIRDEFINE = @HELPDIRDEFINE@ -HELPSTRINGS = @HELPSTRINGS@ - -# xxx this is bad style -RL_LIBSRC = $(topdir)/lib/readline - -.SUFFIXES: -.SUFFIXES: .def .c .o -# How to make a .o file from a .def file. -.def.o: - $(RM) $@ - ./$(MKBUILTINS) $(DIRECTDEFINE) $< - $(CC) -c $(CCFLAGS) $*.c || ( $(RM) $*.c ; exit 1 ) - $(RM) $*.c - -# How to make a .c file from a .def file. -.def.c: - $(RM) $@ - ./$(MKBUILTINS) $(DIRECTDEFINE) $< - -# default rule for making a .o file from a .c file -.c.o: - $(RM) $@ - $(CC) -c $(CCFLAGS) $< - -DEFSRC = $(srcdir)/alias.def $(srcdir)/bind.def $(srcdir)/break.def \ - $(srcdir)/builtin.def $(srcdir)/caller.def \ - $(srcdir)/cd.def $(srcdir)/colon.def \ - $(srcdir)/command.def $(srcdir)/declare.def $(srcdir)/echo.def \ - $(srcdir)/enable.def $(srcdir)/eval.def $(srcdir)/getopts.def \ - $(srcdir)/exec.def $(srcdir)/exit.def $(srcdir)/fc.def \ - $(srcdir)/fg_bg.def $(srcdir)/hash.def $(srcdir)/help.def \ - $(srcdir)/history.def $(srcdir)/jobs.def $(srcdir)/kill.def \ - $(srcdir)/let.def $(srcdir)/read.def $(srcdir)/return.def \ - $(srcdir)/set.def $(srcdir)/setattr.def $(srcdir)/shift.def \ - $(srcdir)/source.def $(srcdir)/suspend.def $(srcdir)/test.def \ - $(srcdir)/times.def $(srcdir)/trap.def $(srcdir)/type.def \ - $(srcdir)/ulimit.def $(srcdir)/umask.def $(srcdir)/wait.def \ - $(srcdir)/reserved.def $(srcdir)/pushd.def $(srcdir)/shopt.def \ - $(srcdir)/printf.def $(srcdir)/complete.def $(srcdir)/mapfile.def - -STATIC_SOURCE = common.c evalstring.c evalfile.c getopt.c bashgetopt.c \ - getopt.h - -OFILES = builtins.o \ - alias.o bind.o break.o builtin.o caller.o cd.o colon.o command.o \ - common.o declare.o echo.o enable.o eval.o evalfile.o \ - evalstring.o exec.o exit.o fc.o fg_bg.o hash.o help.o history.o - jobs.o kill.o let.o mapfile.o \ - pushd.o read.o return.o set.o setattr.o shift.o source.o \ - suspend.o test.o times.o trap.o type.o ulimit.o umask.o \ - wait.o getopts.o shopt.o printf.o getopt.o bashgetopt.o complete.o - -CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h - -all: $(MKBUILTINS) libbuiltins.a - -libbuiltins.a: $(MKBUILTINS) $(OFILES) builtins.o - $(RM) $@ - $(AR) $(ARFLAGS) $@ $(OFILES) - -$(RANLIB) $@ - -builtext.h builtins.c: $(MKBUILTINS) $(DEFSRC) - @-if test -f builtins.c; then mv -f builtins.c old-builtins.c; fi - @-if test -f builtext.h; then mv -f builtext.h old-builtext.h; fi - ./$(MKBUILTINS) -externfile builtext.h -structfile builtins.c \ - -noproduction $(DIRECTDEFINE) $(HELPDIRDEFINE) $(HELPSTRINGS) $(DEFSRC) - @-if cmp -s old-builtext.h builtext.h 2>/dev/null; then \ - mv old-builtext.h builtext.h; \ - else \ - $(RM) old-builtext.h; \ - fi - @-if cmp -s old-builtins.c builtins.c 2>/dev/null; then \ - mv old-builtins.c builtins.c; \ - else \ - $(RM) old-builtins.c; \ - fi - -helpdoc: $(MKBUILTINS) $(DEFSRC) - ./$(MKBUILTINS) ${HELPDIRDEFINE} -noproduction $(DIRECTDEFINE) $(DEFSRC) - -install-help: - @-if test -n "${HELPDIR}" && test -d helpfiles ; then \ - test -d $(DESTDIR)${HELPDIR} || ${SHELL} ${MKDIRS} $(DESTDIR)$(HELPDIR) ;\ - ( for f in helpfiles/*; do \ - echo installing $$f; \ - ${INSTALL_DATA} $$f $(DESTDIR)$(HELPDIR); \ - done; ) ; \ - fi - -install: @HELPINSTALL@ - -mkbuiltins.o: ../config.h -mkbuiltins.o: mkbuiltins.c - $(RM) $@ - $(CC_FOR_BUILD) -c $(CCFLAGS_FOR_BUILD) $< - -mkbuiltins$(EXEEXT): mkbuiltins.o - $(CC_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $(MKBUILTINS) mkbuiltins.o $(LIBS_FOR_BUILD) - -# rules for deficient makes, like SunOS -mkbuiltins.o: mkbuiltins.c -builtins.o: builtins.c -common.o: common.c -bashgetopt.o: bashgetopt.c -getopt.o: getopt.c -evalstring.o: evalstring.c -evalfile.o: evalfile.c - -ulimit.o: pipesize.h - -pipesize.h: psize.aux - $(SHELL) $(srcdir)/psize.sh > $@ - -psize.aux: psize.c - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(srcdir)/psize.c - -documentation: builtins.texi - -builtins.texi: $(MKBUILTINS) - ./$(MKBUILTINS) -documentonly $(DEFSRC) - -clean: - $(RM) $(OFILES) $(CREATED_FILES) $(MKBUILTINS) mkbuiltins.o libbuiltins.a - -test -d helpfiles && $(RM) -r helpfiles - -mostlyclean: - $(RM) $(OFILES) libbuiltins.a - -distclean maintainer-clean: clean - $(RM) Makefile - -$(OFILES): $(MKBUILTINS) ../config.h - -../version.h: ../config.h ../Makefile Makefile - -( cd ${BUILD_DIR} && ${MAKE} ${MFLAGS} version.h ) - -# maintainer special - for now -po: builtins.c - xgettext -L C -o $(topdir)/po/builtins.pot --keyword='N_' builtins.c 2>/dev/null - -${LIBINTL_H}: - @echo making $@ in ${INTL_BUILDDIR} - @(cd ${INTL_BUILDDIR} && \ - $(MAKE) $(MFLAGS) libintl.h) || exit 1 - -# dependencies - -alias.o: alias.def -bind.o: bind.def -break.o: break.def -builtin.o: builtin.def -caller.o: caller.def -cd.o: cd.def -colon.o: colon.def -command.o: command.def -declare.o: declare.def -echo.o: echo.def -enable.o: enable.def -eval.o: eval.def -exec.o: exec.def -exit.o: exit.def -fc.o: fc.def -fg_bg.o: fg_bg.def -hash.o: hash.def -help.o: help.def -history.o: history.def -jobs.o: jobs.def -kill.o: kill.def -let.o: let.def -mapfile.o: mapfile.def -printf.o: printf.def -pushd.o: pushd.def -read.o: read.def -return.o: return.def -set.o: set.def -setattr.o: setattr.def -shift.o: shift.def -shopt.o: shopt.def -source.o: source.def -suspend.o: suspend.def -test.o: test.def -times.o: times.def -trap.o: trap.def -type.o: type.def -ulimit.o: ulimit.def -umask.o: umask.def -wait.o: wait.def -getopts.o: getopts.def -reserved.o: reserved.def -complete.o: complete.def - -# C files -bashgetopt.o: ../config.h $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h -bashgetopt.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/bashjmp.h -bashgetopt.o: $(topdir)/command.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/error.h -bashgetopt.o: $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/quit.h $(BASHINCDIR)/maxpath.h -bashgetopt.o: $(topdir)/unwind_prot.h $(topdir)/dispose_cmd.h -bashgetopt.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/sig.h -bashgetopt.o: ../pathnames.h $(topdir)/externs.h $(srcdir)/common.h -bashgetopt.o: $(BASHINCDIR)/chartypes.h -common.o: $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h -common.o: $(topdir)/shell.h $(topdir)/syntax.h ../config.h $(topdir)/bashjmp.h $(BASHINCDIR)/posixjmp.h -common.o: $(topdir)/sig.h $(topdir)/command.h -common.o: $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/stdc.h $(BASHINCDIR)/memalloc.h -common.o: $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/input.h -common.o: $(topdir)/siglist.h $(topdir)/bashhist.h $(topdir)/quit.h -common.o: $(topdir)/unwind_prot.h $(BASHINCDIR)/maxpath.h $(topdir)/jobs.h -common.o: $(topdir)/builtins.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -common.o: $(topdir)/subst.h $(topdir)/execute_cmd.h $(topdir)/error.h -common.o: $(topdir)/externs.h ../pathnames.h ./builtext.h -common.o: $(BASHINCDIR)/chartypes.h -evalfile.o: $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h ${BASHINCDIR}/filecntl.h -evalfile.o: $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h -evalfile.o: $(topdir)/shell.h $(topdir)/syntax.h ../config.h $(topdir)/bashjmp.h -evalfile.o: $(topdir)/command.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/error.h -evalfile.o: $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/quit.h $(BASHINCDIR)/maxpath.h -evalfile.o: $(topdir)/unwind_prot.h $(topdir)/dispose_cmd.h -evalfile.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/sig.h -evalfile.o: ../pathnames.h $(topdir)/externs.h -evalfile.o: $(topdir)/jobs.h $(topdir)/builtins.h $(topdir)/flags.h -evalfile.o: $(topdir)/input.h $(topdir)/execute_cmd.h -evalfile.o: $(topdir)/bashhist.h $(srcdir)/common.h -evalstring.o: ../config.h $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h -evalstring.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/bashjmp.h $(BASHINCDIR)/posixjmp.h -evalstring.o: $(topdir)/sig.h $(topdir)/command.h $(topdir)/siglist.h -evalstring.o: $(BASHINCDIR)/memalloc.h $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/input.h -evalstring.o: $(topdir)/quit.h $(topdir)/unwind_prot.h -evalstring.o: $(BASHINCDIR)/maxpath.h $(topdir)/jobs.h $(topdir)/builtins.h -evalstring.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h -evalstring.o: $(topdir)/externs.h $(topdir)/jobs.h $(topdir)/builtins.h -evalstring.o: $(topdir)/flags.h $(topdir)/input.h $(topdir)/execute_cmd.h -evalstring.o: $(topdir)/bashhist.h $(srcdir)/common.h -evalstring.o: $(topdir)/trap.h $(topdir)/redir.h -getopt.o: ../config.h $(BASHINCDIR)/memalloc.h -getopt.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/bashjmp.h $(topdir)/command.h -getopt.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/error.h $(topdir)/variables.h $(topdir)/conftypes.h -getopt.o: $(topdir)/quit.h $(BASHINCDIR)/maxpath.h $(topdir)/unwind_prot.h -getopt.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h -getopt.o: $(topdir)/sig.h ../pathnames.h $(topdir)/externs.h -getopt.o: $(srcdir)/getopt.h -mkbuiltins.o: ../config.h $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h -mkbuiltins.o: ${BASHINCDIR}/filecntl.h -mkbuiltins.o: $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h - -# def files -alias.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -alias.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/maxpath.h -alias.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -alias.o: $(topdir)/subst.h $(topdir)/externs.h $(srcdir)/common.h -alias.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -bind.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h -bind.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -bind.o: $(topdir)/subst.h $(topdir)/externs.h $(srcdir)/bashgetopt.h -bind.o: $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/maxpath.h $(topdir)/bashline.h -bind.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -break.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -break.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -break.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -break.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -break.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -builtin.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -builtin.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/externs.h -builtin.o: $(topdir)/quit.h $(srcdir)/common.h $(BASHINCDIR)/maxpath.h -builtin.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h -builtin.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -builtin.o: $(srcdir)/bashgetopt.h -caller.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h -caller.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/quit.h $(topdir)/dispose_cmd.h -caller.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/externs.h -caller.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -caller.o: $(srcdir)/common.h $(BASHINCDIR)/maxpath.h ./builtext.h -caller.o: ${BASHINCDIR}/chartypes.h $(topdir)/bashtypes.h -cd.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h -cd.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/quit.h $(topdir)/dispose_cmd.h -cd.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/externs.h -cd.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -cd.o: $(srcdir)/common.h $(BASHINCDIR)/maxpath.h -command.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -command.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/externs.h -command.o: $(topdir)/quit.h $(srcdir)/bashgetopt.h $(BASHINCDIR)/maxpath.h -command.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h -command.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -declare.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -declare.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -declare.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -declare.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -declare.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -declare.o: $(topdir)/arrayfunc.h $(srcdir)/bashgetopt.h -declare.o: ./builtext.h -echo.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h -echo.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/externs.h -echo.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -echo.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -echo.o: $(BASHINCDIR)/maxpath.h -enable.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -enable.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -enable.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -enable.o: $(topdir)/subst.h $(topdir)/externs.h -enable.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -enable.o: $(BASHINCDIR)/maxpath.h -enable.o: $(topdir)/pcomplete.h -eval.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -eval.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -eval.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -eval.o: $(topdir)/subst.h $(topdir)/externs.h -eval.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -eval.o: $(BASHINCDIR)/maxpath.h -exec.o: $(topdir)/bashtypes.h -exec.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -exec.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -exec.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -exec.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/flags.h -exec.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -exec.o: $(srcdir)/common.h $(topdir)/execute_cmd.h $(BASHINCDIR)/maxpath.h -exec.o: $(topdir)/findcmd.h $(topdir)/jobs.h -exit.o: $(topdir)/bashtypes.h -exit.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -exit.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -exit.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -exit.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/jobs.h -exit.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -exit.o: $(BASHINCDIR)/maxpath.h ./builtext.h -fc.o: $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h -fc.o: $(topdir)/builtins.h $(topdir)/command.h $(srcdir)/bashgetopt.h -fc.o: $(topdir)/bashhist.h -fc.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h -fc.o: $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/maxpath.h -fc.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -fc.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/shell.h $(topdir)/syntax.h -fc.o: $(topdir)/flags.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -fc.o: $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h $(BASHINCDIR)/chartypes.h -fg_bg.o: $(topdir)/bashtypes.h $(srcdir)/bashgetopt.h -fg_bg.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -fg_bg.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -fg_bg.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -fg_bg.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -fg_bg.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -fg_bg.o: $(topdir)/jobs.h -getopts.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -getopts.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -getopts.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -getopts.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -getopts.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -hash.o: $(topdir)/builtins.h $(topdir)/command.h $(topdir)/quit.h -hash.o: $(topdir)/findcmd.h $(topdir)/hashlib.h -hash.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -hash.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -hash.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -hash.o: $(srcdir)/common.h $(BASHINCDIR)/maxpath.h -help.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -help.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -help.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -help.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -help.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -help.o: ${srcdir}/common.h -history.o: $(topdir)/bashtypes.h -history.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -history.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -history.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -history.o: $(topdir)/subst.h $(topdir)/externs.h -history.o: ${BASHINCDIR}/filecntl.h $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h -history.o: $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/bashhist.h $(BASHINCDIR)/maxpath.h -inlib.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -inlib.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -inlib.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -inlib.o: $(BASHINCDIR)/maxpath.h $(topdir)/subst.h $(topdir)/externs.h -inlib.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -jobs.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h -jobs.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/quit.h $(srcdir)/bashgetopt.h -jobs.o: $(BASHINCDIR)/maxpath.h $(topdir)/externs.h $(topdir)/jobs.h -jobs.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h -jobs.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -kill.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h -kill.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/externs.h -kill.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -kill.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/trap.h $(topdir)/unwind_prot.h -kill.o: $(topdir)/variables.h $(topdir)/conftypes.h $(BASHINCDIR)/maxpath.h -kill.o: $(topdir)/jobs.h -let.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -let.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -let.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -let.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -let.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -printf.o: ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/bashjmp.h -printf.o: $(topdir)/command.h $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -printf.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -printf.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/sig.h -printf.o: ../pathnames.h $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h -printf.o: $(topdir)/variables.h $(topdir)/conftypes.h $(BASHINCDIR)/stdc.h $(srcdir)/bashgetopt.h -printf.o: $(topdir)/bashtypes.h ${srcdir}/common.h $(BASHINCDIR)/chartypes.h -pushd.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -pushd.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -pushd.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -pushd.o: $(topdir)/subst.h $(topdir)/externs.h -pushd.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -pushd.o: $(BASHINCDIR)/maxpath.h $(srcdir)/common.h ./builtext.h -read.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -read.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -read.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -read.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -read.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -read.o: $(BASHINCDIR)/shtty.h -read.o: $(topdir)/arrayfunc.h -return.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -return.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -return.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -return.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -return.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -set.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -set.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/externs.h -set.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -set.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -set.o: $(BASHINCDIR)/maxpath.h $(topdir)/error.h -set.o: $(topdir)/arrayfunc.h -setattr.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -setattr.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/maxpath.h -setattr.o: $(topdir)/quit.h $(srcdir)/common.h $(srcdir)/bashgetopt.h -setattr.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h -setattr.o: $(topdir)/externs.h -setattr.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -setattr.o: $(topdir)/arrayfunc.h -shift.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -shift.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -shift.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -shift.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -shift.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -source.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -source.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/findcmd.h -source.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -source.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -source.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -source.o: $(srcdir)/bashgetopt.h $(topdir)/flags.h $(topdir)/trap.h -suspend.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -suspend.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -suspend.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -suspend.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -suspend.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -suspend.o: $(topdir)/jobs.h -test.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -test.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -test.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -test.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -test.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -test.o: $(topdir)/test.h -times.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -times.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -times.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -times.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -times.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -times.o: $(BASHINCDIR)/posixtime.h -trap.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -trap.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/externs.h -trap.o: $(topdir)/quit.h $(srcdir)/common.h $(BASHINCDIR)/maxpath.h -trap.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h -trap.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -trap.o: $(topdir)/findcmd.h -type.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -type.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -type.o: $(topdir)/quit.h $(srcdir)/common.h $(BASHINCDIR)/maxpath.h -type.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h -type.o: $(topdir)/externs.h $(topdir)/hashcmd.h -type.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -ulimit.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -ulimit.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -ulimit.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -ulimit.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -ulimit.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -umask.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -umask.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -umask.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -umask.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -umask.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -umask.o: $(BASHINCDIR)/chartypes.h -wait.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -wait.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -wait.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -wait.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -wait.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -wait.o: $(topdir)/jobs.h -wait.o: $(BASHINCDIR)/chartypes.h -shopt.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -shopt.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -shopt.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -shopt.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -shopt.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h -shopt.o: $(srcdir)/common.h $(srcdir)/bashgetopt.h - -complete.o: ../config.h -complete.o: ${topdir}/shell.h $(topdir)/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h ${topdir}/sig.h -complete.o: ${topdir}/unwind_prot.h ${topdir}/variables.h -complete.o: ${topdir}/bashtypes.h ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h -complete.o: ${topdir}/builtins.h -complete.o: ${topdir}/pcomplete.h -complete.o: ${srcdir}/common.h ${srcdir}/bashgetopt.h -mapfile.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h -mapfile.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h -mapfile.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h -mapfile.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h -mapfile.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/variables.h $(topdir)/conftypes.h -mapfile.o: $(topdir)/arrayfunc.h - -#bind.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h - -# libintl dependencies -bind.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -break.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -caller.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -cd.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -common.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -complete.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -declare.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -enable.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -evalfile.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -exec.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -exit.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -fc.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -fg_bg.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -getopt.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -hash.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -help.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -history.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -inlib.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -jobs.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -kill.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -let.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -mapfile.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -mkbuiltins.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -printf.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -pushd.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -read.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -return.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -set.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -setattr.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -shift.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -shopt.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -source.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -suspend.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -type.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -ulimit.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h -umask.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h diff --git a/builtins/alias.def~ b/builtins/alias.def~ deleted file mode 100644 index 2dae1aad9..000000000 --- a/builtins/alias.def~ +++ /dev/null @@ -1,241 +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-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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] ... ] -Define or display aliases. - -Without arguments, `alias' prints the list of aliases in the reusable -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. - -Options: - -p Print all defined aliases in a reusable format - -Alias returns true unless a NAME is supplied 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 "../bashintl.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 (sh_chkwrite (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++; - } - else - 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 each NAME from the list of defined aliases. - -Options: - -a remove all alias definitions. - -Return success unless a NAME is not an existing alias. -$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/bind.def~ b/builtins/bind.def~ deleted file mode 100644 index e1040cd8a..000000000 --- a/builtins/bind.def~ +++ /dev/null @@ -1,325 +0,0 @@ -This file is bind.def, from which is created bind.c. -It implements the builtin "bind" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Bash is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Bash. If not, see . - -$PRODUCES bind.c - -#include - -$BUILTIN bind -$DEPENDS_ON READLINE -$FUNCTION bind_builtin -$SHORT_DOC bind [-lpvsPVS] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x keyseq:shell-command] [keyseq:readline-function or readline-command] -Set Readline key bindings and variables. - -Bind a key sequence to a Readline function or a macro, or set a -Readline variable. The non-option argument syntax is equivalent to -that found in ~/.inputrc, but must be passed as a single argument: -e.g., bind '"\C-x\C-r": re-read-init-file'. - -Options: - -m keymap Use KEYMAP as the keymap for the duration of this - command. Acceptable keymap names are emacs, - emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move, - vi-command, and vi-insert. - -l List names of functions. - -P List function names and bindings. - -p List functions and bindings in a form that can be - reused as input. - -S List key sequences that invoke macros and their values - -s List key sequences that invoke macros and their values - in a form that can be reused as input. - -V List variable names and values - -v List variable names and values in a form that can - be reused as input. - -q function-name Query about which keys invoke the named function. - -u function-name Unbind all keys which are bound to the named function. - -r keyseq Remove the binding for KEYSEQ. - -f filename Read key bindings from FILENAME. - -x keyseq:shell-command Cause SHELL-COMMAND to be executed when - KEYSEQ is entered. - -Exit Status: -bind returns 0 unless an unrecognized option is given or an error occurs. -$END - -#if defined (READLINE) - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#include -#include - -#include "../bashintl.h" - -#include "../shell.h" -#include "../bashline.h" -#include "bashgetopt.h" -#include "common.h" - -static int query_bindings __P((char *)); -static int unbind_command __P((char *)); - -extern int no_line_editing; - -#define BIND_RETURN(x) do { return_code = x; goto bind_exit; } while (0) - -#define LFLAG 0x0001 -#define PFLAG 0x0002 -#define FFLAG 0x0004 -#define VFLAG 0x0008 -#define QFLAG 0x0010 -#define MFLAG 0x0020 -#define RFLAG 0x0040 -#define PPFLAG 0x0080 -#define VVFLAG 0x0100 -#define SFLAG 0x0200 -#define SSFLAG 0x0400 -#define UFLAG 0x0800 -#define XFLAG 0x1000 - -int -bind_builtin (list) - WORD_LIST *list; -{ - int return_code; - Keymap kmap, saved_keymap; - int flags, opt; - char *initfile, *map_name, *fun_name, *unbind_name, *remove_seq, *cmd_seq; - - if (no_line_editing) - return (EXECUTION_FAILURE); - - kmap = saved_keymap = (Keymap) NULL; - flags = 0; - initfile = map_name = fun_name = unbind_name = remove_seq = (char *)NULL; - return_code = EXECUTION_SUCCESS; - - if (!bash_readline_initialized) - initialize_readline (); - - begin_unwind_frame ("bind_builtin"); - unwind_protect_var (rl_outstream); - - rl_outstream = stdout; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "lvpVPsSf:q:u:m:r:x:")) != EOF) - { - switch (opt) - { - case 'l': - flags |= LFLAG; - break; - case 'v': - flags |= VFLAG; - break; - case 'p': - flags |= PFLAG; - break; - case 'f': - flags |= FFLAG; - initfile = list_optarg; - break; - case 'm': - flags |= MFLAG; - map_name = list_optarg; - break; - case 'q': - flags |= QFLAG; - fun_name = list_optarg; - break; - case 'u': - flags |= UFLAG; - unbind_name = list_optarg; - break; - case 'r': - flags |= RFLAG; - remove_seq = list_optarg; - break; - case 'V': - flags |= VVFLAG; - break; - case 'P': - flags |= PPFLAG; - break; - case 's': - flags |= SFLAG; - break; - case 'S': - flags |= SSFLAG; - break; - case 'x': - flags |= XFLAG; - cmd_seq = list_optarg; - break; - default: - builtin_usage (); - BIND_RETURN (EX_USAGE); - } - } - - list = loptend; - - /* First, see if we need to install a special keymap for this - command. Then start on the arguments. */ - - if ((flags & MFLAG) && map_name) - { - kmap = rl_get_keymap_by_name (map_name); - if (!kmap) - { - builtin_error (_("`%s': invalid keymap name"), map_name); - BIND_RETURN (EXECUTION_FAILURE); - } - } - - if (kmap) - { - saved_keymap = rl_get_keymap (); - rl_set_keymap (kmap); - } - - /* XXX - we need to add exclusive use tests here. It doesn't make sense - to use some of these options together. */ - /* Now hack the option arguments */ - if (flags & LFLAG) - rl_list_funmap_names (); - - if (flags & PFLAG) - rl_function_dumper (1); - - if (flags & PPFLAG) - rl_function_dumper (0); - - if (flags & SFLAG) - rl_macro_dumper (1); - - if (flags & SSFLAG) - rl_macro_dumper (0); - - if (flags & VFLAG) - rl_variable_dumper (1); - - if (flags & VVFLAG) - rl_variable_dumper (0); - - if ((flags & FFLAG) && initfile) - { - if (rl_read_init_file (initfile) != 0) - { - builtin_error (_("%s: cannot read: %s"), initfile, strerror (errno)); - BIND_RETURN (EXECUTION_FAILURE); - } - } - - if ((flags & QFLAG) && fun_name) - return_code = query_bindings (fun_name); - - if ((flags & UFLAG) && unbind_name) - return_code = unbind_command (unbind_name); - - if ((flags & RFLAG) && remove_seq) - { - if (rl_set_key (remove_seq, (rl_command_func_t *)NULL, rl_get_keymap ()) != 0) - { - builtin_error (_("`%s': cannot unbind"), remove_seq); - BIND_RETURN (EXECUTION_FAILURE); - } - } - - if (flags & XFLAG) - return_code = bind_keyseq_to_unix_command (cmd_seq); - - /* Process the rest of the arguments as binding specifications. */ - while (list) - { - rl_parse_and_bind (list->word->word); - list = list->next; - } - - bind_exit: - if (saved_keymap) - rl_set_keymap (saved_keymap); - - run_unwind_frame ("bind_builtin"); - - return (sh_chkwrite (return_code)); -} - -static int -query_bindings (name) - char *name; -{ - rl_command_func_t *function; - char **keyseqs; - int j; - - function = rl_named_function (name); - if (function == 0) - { - builtin_error (_("`%s': unknown function name"), name); - return EXECUTION_FAILURE; - } - - keyseqs = rl_invoking_keyseqs (function); - - if (!keyseqs) - { - printf (_("%s is not bound to any keys.\n"), name); - return EXECUTION_FAILURE; - } - - printf (_("%s can be invoked via "), name); - for (j = 0; j < 5 && keyseqs[j]; j++) - printf ("\"%s\"%s", keyseqs[j], keyseqs[j + 1] ? ", " : ".\n"); - if (keyseqs[j]) - printf ("...\n"); - strvec_dispose (keyseqs); - return EXECUTION_SUCCESS; -} - -static int -unbind_command (name) - char *name; -{ - rl_command_func_t *function; - - function = rl_named_function (name); - if (function == 0) - { - builtin_error (_("`%s': unknown function name"), name); - return EXECUTION_FAILURE; - } - - rl_unbind_function_in_map (function, rl_get_keymap ()); - return EXECUTION_SUCCESS; -} -#endif /* READLINE */ diff --git a/builtins/break.def~ b/builtins/break.def~ deleted file mode 100644 index 4f4c6c4b6..000000000 --- a/builtins/break.def~ +++ /dev/null @@ -1,142 +0,0 @@ -This file is break.def, from which is created break.c. -It implements the builtins "break" and "continue" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 break.c - -$BUILTIN break -$FUNCTION break_builtin -$SHORT_DOC break [n] -Exit for, while, or until loops. - -Exit a FOR, WHILE or UNTIL loop. If N is specified, break N enclosing -loops. - -Exit Status: -The exit status is 0 unless N is not greater than or equal to 1. -$END -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashintl.h" - -#include "../shell.h" -#include "common.h" - -extern char *this_command_name; -extern int posixly_correct; - -static int check_loop_level __P((void)); - -/* The depth of while's and until's. */ -int loop_level = 0; - -/* Non-zero when a "break" instruction is encountered. */ -int breaking = 0; - -/* Non-zero when we have encountered a continue instruction. */ -int continuing = 0; - -/* Set up to break x levels, where x defaults to 1, but can be specified - as the first argument. */ -int -break_builtin (list) - WORD_LIST *list; -{ - intmax_t newbreak; - - if (check_loop_level () == 0) - return (EXECUTION_SUCCESS); - - newbreak = get_numeric_arg (list, 1); - - if (newbreak <= 0) - { - sh_erange (list->word->word, _("loop count")); - breaking = loop_level; - return (EXECUTION_FAILURE); - } - - if (newbreak > loop_level) - newbreak = loop_level; - - breaking = newbreak; - - return (EXECUTION_SUCCESS); -} - -$BUILTIN continue -$FUNCTION continue_builtin -$SHORT_DOC continue [n] -Resume for, while, or until loops. - -Resumes the next iteration of the enclosing FOR, WHILE or UNTIL loop. -If N is specified, resumes the Nth enclosing loop. - -Exit Status: -The exit status is 0 unless the shell is not executing a loop. -$END - -/* Set up to continue x levels, where x defaults to 1, but can be specified - as the first argument. */ -int -continue_builtin (list) - WORD_LIST *list; -{ - intmax_t newcont; - - if (check_loop_level () == 0) - return (EXECUTION_SUCCESS); - - newcont = get_numeric_arg (list, 1); - - if (newcont <= 0) - { - sh_erange (list->word->word, _("loop count")); - breaking = loop_level; - return (EXECUTION_FAILURE); - } - - if (newcont > loop_level) - newcont = loop_level; - - continuing = newcont; - - return (EXECUTION_SUCCESS); -} - -/* Return non-zero if a break or continue command would be okay. - Print an error message if break or continue is meaningless here. */ -static int -check_loop_level () -{ -#if defined (BREAK_COMPLAINS) - if (loop_level == 0 && posixly_correct == 0) - builtin_error (_("only meaningful in a `for', `while', or `until' loop")); -#endif /* BREAK_COMPLAINS */ - - return (loop_level); -} diff --git a/builtins/builtin.def~ b/builtins/builtin.def~ deleted file mode 100644 index cd5147b3a..000000000 --- a/builtins/builtin.def~ +++ /dev/null @@ -1,82 +0,0 @@ -This file is builtin.def, from which is created builtin.c. -It implements the builtin "builtin" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 builtin.c - -$BUILTIN builtin -$FUNCTION builtin_builtin -$SHORT_DOC builtin [shell-builtin [arg ...]] -Execute shell builtins. - -Execute SHELL-BUILTIN with arguments ARGs without performing command -lookup. This is useful when you wish to reimplement a shell builtin -as a shell function, but need to execute the builtin within the function. -$END -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../shell.h" -#include "common.h" -#include "bashgetopt.h" - -extern char *this_command_name; - -/* Run the command mentioned in list directly, without going through the - normal alias/function/builtin/filename lookup process. */ -int -builtin_builtin (list) - WORD_LIST *list; -{ - sh_builtin_func_t *function; - register char *command; - - if (no_options (list)) - return (EX_USAGE); - list = loptend; /* skip over possible `--' */ - - if (list == 0) - return (EXECUTION_SUCCESS); - - command = list->word->word; -#if defined (DISABLED_BUILTINS) - function = builtin_address (command); -#else /* !DISABLED_BUILTINS */ - function = find_shell_builtin (command); -#endif /* !DISABLED_BUILTINS */ - - if (!function) - { - sh_notbuiltin (command); - return (EXECUTION_FAILURE); - } - else - { - this_command_name = command; - list = list->next; - return ((*function) (list)); - } -} diff --git a/builtins/caller.def~ b/builtins/caller.def~ deleted file mode 100644 index cb468ad3d..000000000 --- a/builtins/caller.def~ +++ /dev/null @@ -1,150 +0,0 @@ -This file is caller.def, from which is created caller.c. It implements the -builtin "caller" in Bash. - -Copyright (C) 2002-2008 Rocky Bernstein for Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 caller.c - -$BUILTIN caller -$FUNCTION caller_builtin -$DEPENDS_ON DEBUGGER -$SHORT_DOC caller [expr] -Return the context of the current subroutine call. - -Without EXPR, returns "$line $filename". With EXPR, returns -"$line $subroutine $filename"; this extra information can be used to -provide a stack trace. - -The value of EXPR indicates how many call frames to go back before the -current one; the top frame is frame 0. -$END - -#include -#include -#include "chartypes.h" -#include "bashtypes.h" - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include - -#include "../bashintl.h" - -#include "../shell.h" -#include "common.h" -#include "builtext.h" -#include "bashgetopt.h" - -#ifdef LOADABLE_BUILTIN -# include "builtins.h" -#endif - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -int -caller_builtin (list) - WORD_LIST *list; -{ -#if !defined (ARRAY_VARS) - printf ("1 NULL\n"); - return (EXECUTION_FAILURE); -#else - SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v; - ARRAY *funcname_a, *bash_source_a, *bash_lineno_a; - char *funcname_s, *source_s, *lineno_s; - intmax_t num; - - 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); - - if (bash_lineno_a == 0 || array_empty (bash_lineno_a)) - return (EXECUTION_FAILURE); - - if (bash_source_a == 0 || array_empty (bash_source_a)) - return (EXECUTION_FAILURE); - - if (no_options (list)) - return (EX_USAGE); - list = loptend; /* skip over possible `--' */ - - /* If there is no argument list, then give short form: line filename. */ - if (list == 0) - { - lineno_s = array_reference (bash_lineno_a, 0); - source_s = array_reference (bash_source_a, 1); - printf("%s %s\n", lineno_s ? lineno_s : "NULL", source_s ? source_s : "NULL"); - return (EXECUTION_SUCCESS); - } - - if (funcname_a == 0 || array_empty (funcname_a)) - return (EXECUTION_FAILURE); - - if (legal_number (list->word->word, &num)) - { - lineno_s = array_reference (bash_lineno_a, num); - source_s = array_reference (bash_source_a, num+1); - funcname_s = array_reference (funcname_a, num+1); - - if (lineno_s == NULL|| source_s == NULL || funcname_s == NULL) - return (EXECUTION_FAILURE); - - printf("%s %s %s\n", lineno_s, funcname_s, source_s); - } - else - { - sh_invalidnum (list->word->word); - builtin_usage (); - return (EXECUTION_FAILURE); - } - - return (EXECUTION_SUCCESS); -#endif -} - -#ifdef LOADABLE_BUILTIN -static char *caller_doc[] = { -N_("Returns the context of the current subroutine call.\n\ - \n\ - Without EXPR, returns "$line $filename". With EXPR, returns\n\ - "$line $subroutine $filename"; this extra information can be used to\n\ - provide a stack trace.\n\ - \n\ - The value of EXPR indicates how many call frames to go back before the\n\ - current one; the top frame is frame 0."), - (char *)NULL -}; - -struct builtin caller_struct = { - "caller", - caller_builtin, - BUILTIN_ENABLED, - caller_doc, - "caller [EXPR]", - 0 -}; - -#endif /* LOADABLE_BUILTIN */ diff --git a/builtins/cd.def~ b/builtins/cd.def~ deleted file mode 100644 index 4a0508019..000000000 --- a/builtins/cd.def~ +++ /dev/null @@ -1,513 +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-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Bash is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Bash. If not, see . - -$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 const char * const bash_getcwd_errstr; - -static int bindpwd __P((int)); -static void setpwd __P((char *)); -static char *resetpwd __P((char *)); -static int change_to_directory __P((char *, int)); - -/* 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 shell working directory. - -Change the current directory to DIR. The default DIR is the value of the -HOME shell variable. - -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. 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, -the word is assumed to be a variable name. If that variable has a value, -its value is used for DIR. - -Options: - -L force symbolic links to be followed - -P use the physical directory structure without following symbolic - links - -The default is to follow symbolic links, as if `-L' were specified. - -Exit Status: -Returns 0 if the directory is changed; non-zero otherwise. -$END - -/* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */ -static void -setpwd (dirname) - char *dirname; -{ - int old_anm; - SHELL_VAR *tvar; - - old_anm = array_needs_making; - tvar = bind_variable ("PWD", dirname ? dirname : "", 0); - if (old_anm == 0 && array_needs_making && exported_p (tvar)) - { - update_export_env_inplace ("PWD=", 4, dirname ? dirname : ""); - array_needs_making = 0; - } -} - -static int -bindpwd (no_symlinks) - int no_symlinks; -{ - char *dirname, *pwdvar; - int old_anm, r; - SHELL_VAR *tvar; - - r = sh_chkwrite (EXECUTION_SUCCESS); - -#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, 0); - if (old_anm == 0 && array_needs_making && exported_p (tvar)) - { - update_export_env_inplace ("OLDPWD=", 7, pwdvar); - array_needs_making = 0; - } - - setpwd (dirname); - - if (dirname && dirname != the_current_working_directory) - free (dirname); - - return (r); -} - -/* 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); -#if 0 - /* Posix.2 says that after using CDPATH, the resultant - value of $PWD will not contain `.' or `..'. */ - return (bindpwd (posixly_correct || no_symlinks)); -#else - return (bindpwd (no_symlinks)); -#endif - } - 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 = dirspell (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 [-LP] -Print the name of the current working directory. - -Options: - -L print the value of $PWD if it names the current working - directory - -P print the physical directory, without any symbolic links - -By default, `pwd' behaves as if `-L' were specified. - -Exit Status: -Returns 0 unless an invalid option is given or the current directory -cannot be read. -$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, pflag; - - verbatim_pwd = no_symbolic_links; - pflag = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "LP")) != -1) - { - switch (opt) - { - case 'P': - verbatim_pwd = pflag = 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) || - (posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0)) - directory = resetpwd ("pwd"); - -#undef tcwd - - if (directory) - { - printf ("%s\n", directory); - /* This is dumb but posix-mandated. */ - if (posixly_correct && pflag) - setpwd (directory); - if (directory != the_current_working_directory) - free (directory); - return (sh_chkwrite (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, ndlen, dlen; - - 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); - - ndlen = strlen (newdir); - dlen = strlen (t); - - /* 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 && (errno != ENAMETOOLONG || ndlen > PATH_MAX)) - { -#if defined ENAMETOOLONG - if (errno != ENOENT && errno != ENAMETOOLONG) -#else - if (errno != ENOENT) -#endif - errno = ENOTDIR; - free (tdir); - 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); - - free (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) - { - free (tdir); - 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; -} diff --git a/builtins/colon.def~ b/builtins/colon.def~ deleted file mode 100644 index 7f5bed553..000000000 --- a/builtins/colon.def~ +++ /dev/null @@ -1,59 +0,0 @@ -This file is colon.def, from which is created colon.c. -It implements the builtin ":" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 colon.c - -$BUILTIN : -$DOCNAME colon -$FUNCTION colon_builtin -$SHORT_DOC : -Null command. - -No effect; the command does nothing. Returns a successful exit value. -$END - -$BUILTIN true -$FUNCTION colon_builtin -$SHORT_DOC true -Return a successful result. -$END - -$BUILTIN false -$FUNCTION false_builtin -$SHORT_DOC false -Return an unsuccessful result. -$END - -/* Return a successful result. */ -int -colon_builtin (ignore) - char *ignore; -{ - return (0); -} - -/* Return an unsuccessful result. */ -int -false_builtin (ignore) - char *ignore; -{ - return (1); -} diff --git a/builtins/command.def~ b/builtins/command.def~ deleted file mode 100644 index 02e058bd2..000000000 --- a/builtins/command.def~ +++ /dev/null @@ -1,212 +0,0 @@ -This file is command.def, from which is created command.c. -It implements the builtin "command" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 command.c - -$BUILTIN command -$FUNCTION command_builtin -$SHORT_DOC command [-pVv] command [arg ...] -Execute a simple command or display information about commands. - -Runs COMMAND with ARGS suppressing shell function lookup, or display -information about the specified COMMANDs. Can be used to invoke commands -on disk when a function with the same name exists. - -Options: - -p use a default value for PATH that is guaranteed to find all of - the standard utilities - -v print a description of COMMAND similar to the `type' builtin - -V print a more verbose description of each COMMAND -$END - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashansi.h" - -#include "../shell.h" -#include "../execute_cmd.h" -#include "../flags.h" -#include "bashgetopt.h" -#include "common.h" - -#if defined (_CS_PATH) && defined (HAVE_CONFSTR) && !HAVE_DECL_CONFSTR -extern size_t confstr __P((int, char *, size_t)); -#endif - -extern int subshell_environment; - -static void restore_path __P((char *)); -static char *get_standard_path __P((void)); - -/* Run the commands mentioned in LIST without paying attention to shell - functions. */ -int -command_builtin (list) - WORD_LIST *list; -{ - int result, verbose, use_standard_path, opt; - char *old_path, *standard_path; - COMMAND *command; - - verbose = use_standard_path = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "pvV")) != -1) - { - switch (opt) - { - case 'p': - use_standard_path = 1; - break; - case 'V': - verbose = CDESC_SHORTDESC|CDESC_ABSPATH; /* look in common.h for constants */ - break; - case 'v': - verbose = CDESC_REUSABLE; /* ditto */ - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - if (list == 0) - return (EXECUTION_SUCCESS); - - if (verbose) - { - int found, any_found; - - for (any_found = 0; list; list = list->next) - { - found = describe_command (list->word->word, verbose); - - if (found == 0 && verbose != CDESC_REUSABLE) - sh_notfound (list->word->word); - - any_found += found; - } - return (any_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE); - } - -#if defined (RESTRICTED_SHELL) - if (use_standard_path && restricted) - { - sh_restricted ("-p"); - return (EXECUTION_FAILURE); - } -#endif - - begin_unwind_frame ("command_builtin"); - - /* We don't want this to be reparsed (consider command echo 'foo &'), so - just make a simple_command structure and call execute_command with it. */ - if (use_standard_path) - { - old_path = get_string_value ("PATH"); - /* If old_path is NULL, $PATH is unset. If so, we want to make sure - it's unset after this command completes. */ - if (old_path) - old_path = savestring (old_path); - add_unwind_protect ((Function *)restore_path, old_path); - - standard_path = get_standard_path (); - bind_variable ("PATH", standard_path ? standard_path : "", 0); - FREE (standard_path); - } - -#define COMMAND_BUILTIN_FLAGS (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION | CMD_COMMAND_BUILTIN) - - command = make_bare_simple_command (); - command->value.Simple->words = (WORD_LIST *)copy_word_list (list); - command->value.Simple->redirects = (REDIRECT *)NULL; - command->flags |= COMMAND_BUILTIN_FLAGS; - command->value.Simple->flags |= COMMAND_BUILTIN_FLAGS; -#if 0 - /* This breaks for things like ( cd /tmp ; command z ababa ; echo next ) - or $(command echo a ; command echo b;) or even - { command echo a; command echo b; } & */ - /* If we're in a subshell, see if we can get away without forking - again, since we've already forked to run this builtin. */ - if (subshell_environment) - { - command->flags |= CMD_NO_FORK; - command->value.Simple->flags |= CMD_NO_FORK; - } -#endif - add_unwind_protect ((char *)dispose_command, command); - result = execute_command (command); - - run_unwind_frame ("command_builtin"); - - return (result); -} - -/* Restore the value of the $PATH variable after replacing it when - executing `command -p'. */ -static void -restore_path (var) - char *var; -{ - if (var) - { - bind_variable ("PATH", var, 0); - free (var); - } - else - unbind_variable ("PATH"); -} - -/* Return a value for PATH that is guaranteed to find all of the standard - utilities. This uses Posix.2 configuration variables, if present. It - uses a value defined in config.h as a last resort. */ -static char * -get_standard_path () -{ -#if defined (_CS_PATH) && defined (HAVE_CONFSTR) - char *p; - size_t len; - - len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0); - if (len > 0) - { - p = (char *)xmalloc (len + 2); - *p = '\0'; - confstr (_CS_PATH, p, len); - return (p); - } - else - return (savestring (STANDARD_UTILS_PATH)); -#else /* !_CS_PATH || !HAVE_CONFSTR */ -# if defined (CS_PATH) - return (savestring (CS_PATH)); -# else - return (savestring (STANDARD_UTILS_PATH)); -# endif /* !CS_PATH */ -#endif /* !_CS_PATH || !HAVE_CONFSTR */ -} diff --git a/builtins/common.c~ b/builtins/common.c~ deleted file mode 100644 index fae866ec0..000000000 --- a/builtins/common.c~ +++ /dev/null @@ -1,886 +0,0 @@ -/* common.c - utility functions for all builtins */ - -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#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" - -#define NEED_FPURGE_DECL - -#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 const char * const 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. */ - -static void -builtin_error_prolog () -{ - 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); -} - -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; - - builtin_error_prolog (); - - SH_VA_START (args, format); - - vfprintf (stderr, format, args); - va_end (args); - fprintf (stderr, "\n"); -} - -void -#if defined (PREFER_STDARG) -builtin_warning (const char *format, ...) -#else -builtin_warning (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - - builtin_error_prolog (); - fprintf (stderr, _("warning: ")); - - 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")); - top_level_cleanup (); - 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; -{ - char *msg; - - if (*s == '0' && isdigit (s[1])) - msg = _("invalid octal number"); - else if (*s == '0' && s[1] == 'x') - msg = _("invalid hex number"); - else - msg = _("invalid number"); - builtin_error ("%s: %s", s, msg); -} - -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); -} - -void -sh_wrerror () -{ -#if defined (DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS) && defined (EPIPE) - if (errno != EPIPE) -#endif /* DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS && EPIPE */ - builtin_error (_("write error: %s"), strerror (errno)); -} - -void -sh_ttyerror () -{ - builtin_error (_("error getting terminal attributes: %s"), strerror (errno)); -} - -int -sh_chkwrite (s) - int s; -{ - fflush (stdout); - if (ferror (stdout)) - { - sh_wrerror (); - fpurge (stdout); - clearerr (stdout); - return (EXECUTION_FAILURE); - } - return (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 1, call throw_to_top_level, which exits the - shell; if it's 2, call jump_to_top_level (DISCARD), which aborts the - current command; if FATAL is 0, return an indication of an invalid - number by setting *NUMOK == 0 and return -1. */ -int -get_numeric_arg (list, fatal, count) - WORD_LIST *list; - int fatal; - intmax_t *count; -{ - char *arg; - - if (count) - *count = 1; - - if (list && list->word && ISOPTION (list->word->word, '-')) - list = list->next; - - if (list) - { - arg = list->word->word; - if (arg == 0 || (legal_number (arg, count) == 0)) - { - sh_neednumarg (list->word->word ? list->word->word : "`'"); - if (fatal == 0) - return 0; - else if (fatal == 1) /* fatal == 1; abort */ - throw_to_top_level (); - else /* fatal == 2; discard current command */ - { - top_level_cleanup (); - jump_to_top_level (DISCARD); - } - } - no_args (list->next); - } - - return (1); -} - -/* 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; -{ - if (no_symbolic_links) - { - FREE (the_current_working_directory); - the_current_working_directory = (char *)NULL; - } - - if (the_current_working_directory == 0) - { -#if defined (GETCWD_BROKEN) - the_current_working_directory = getcwd (0, PATH_MAX); -#else - the_current_working_directory = getcwd (0, 0); -#endif - if (the_current_working_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)); - 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; - register JOB *j; - - job = NO_JOB; - wl = strlen (name); - for (i = js.j_jobslots - 1; i >= 0; i--) - { - j = get_job_by_jid (i); - if (j == 0 || ((flags & JM_STOPPED) && J_JOBSTATE(j) != JSTOPPED)) - continue; - - p = j->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 != j->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 (js.j_current); - - word = list->word->word; - - if (*word == '\0') - return (NO_JOB); - - if (*word == '%') - word++; - - if (DIGIT (*word) && all_digits (word)) - { - job = atoi (word); - return (job > js.j_jobslots ? NO_JOB : job - 1); - } - - jflags = 0; - switch (*word) - { - case 0: - case '%': - case '+': - return (js.j_current); - - case '-': - return (js.j_previous); - - 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 < 5) - 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 a3835ca22..000000000 --- a/builtins/common.h~ +++ /dev/null @@ -1,169 +0,0 @@ -/* common.h -- extern declarations for functions defined in common.c. */ - -/* 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 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#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 -#define SEVAL_PARSEONLY 0x020 -#define SEVAL_NOLONGJMP 0x040 - -/* 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 */ -#define CDESC_ABSPATH 0x080 /* convert to absolute path, no ./ */ - -/* 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_warning __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 void sh_wrerror __P((void)); -extern int sh_chkwrite __P((int)); - -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 int get_numeric_arg __P((WORD_LIST *, int, intmax_t *)); -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_all_var_attributes __P((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((int)); - -/* Functions from evalstring.c */ -extern int parse_and_execute __P((char *, const char *, int)); -extern void parse_and_execute_cleanup __P((void)); -extern int parse_string __P((char *, const char *, int, char **)); - -/* 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/complete.def~ b/builtins/complete.def~ deleted file mode 100644 index 0ed13c1a8..000000000 --- a/builtins/complete.def~ +++ /dev/null @@ -1,830 +0,0 @@ -This file is complete.def, from which is created complete.c. -It implements the builtins "complete", "compgen", and "compopt" in Bash. - -Copyright (C) 1999-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 complete.c - -$BUILTIN complete -$DEPENDS_ON PROGRAMMABLE_COMPLETION -$FUNCTION complete_builtin -$SHORT_DOC complete [-abcdefgjksuv] [-pr] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...] -Specify how arguments are to be completed by Readline. - -For each NAME, specify how arguments are to be completed. If no options -are supplied, existing completion specifications are printed in a way that -allows them to be reused as input. - -Options: - -p print existing completion specifications in a reusable format - -r remove a completion specification for each NAME, or, if no - NAMEs are supplied, all completion specifications - -When completion is attempted, the actions are applied in the order the -uppercase-letter options are listed above. - -Exit Status: -Returns success unless an invalid option is supplied or an error occurs. -$END - -#include - -#include - -#include "../bashtypes.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../builtins.h" -#include "../pcomplete.h" -#include "../bashline.h" - -#include "common.h" -#include "bashgetopt.h" - -#include - -#define STRDUP(x) ((x) ? savestring (x) : (char *)NULL) - -/* Structure containing all the non-action (binary) options; filled in by - build_actions(). */ -struct _optflags { - int pflag; - int rflag; - int Eflag; -}; - -static int find_compact __P((char *)); -static int find_compopt __P((char *)); - -static int build_actions __P((WORD_LIST *, struct _optflags *, unsigned long *, unsigned long *)); - -static int remove_cmd_completions __P((WORD_LIST *)); - -static int print_one_completion __P((char *, COMPSPEC *)); -static int print_compitem __P((BUCKET_CONTENTS *)); -static void print_compopts __P((const char *, COMPSPEC *, int)); -static void print_all_completions __P((void)); -static int print_cmd_completions __P((WORD_LIST *)); - -static char *Garg, *Warg, *Parg, *Sarg, *Xarg, *Farg, *Carg; - -static const struct _compacts { - const char * const actname; - int actflag; - int actopt; -} compacts[] = { - { "alias", CA_ALIAS, 'a' }, - { "arrayvar", CA_ARRAYVAR, 0 }, - { "binding", CA_BINDING, 0 }, - { "builtin", CA_BUILTIN, 'b' }, - { "command", CA_COMMAND, 'c' }, - { "directory", CA_DIRECTORY, 'd' }, - { "disabled", CA_DISABLED, 0 }, - { "enabled", CA_ENABLED, 0 }, - { "export", CA_EXPORT, 'e' }, - { "file", CA_FILE, 'f' }, - { "function", CA_FUNCTION, 0 }, - { "helptopic", CA_BUILTIN, 0 }, /* for now */ - { "hostname", CA_HOSTNAME, 0 }, - { "group", CA_GROUP, 'g' }, - { "job", CA_JOB, 'j' }, - { "keyword", CA_KEYWORD, 'k' }, - { "running", CA_RUNNING, 0 }, - { "service", CA_SERVICE, 's' }, - { "setopt", CA_SETOPT, 0 }, - { "shopt", CA_SHOPT, 0 }, - { "signal", CA_SIGNAL, 0 }, - { "stopped", CA_STOPPED, 0 }, - { "user", CA_USER, 'u' }, - { "variable", CA_VARIABLE, 'v' }, - { (char *)NULL, 0, 0 }, -}; - -/* This should be a STRING_INT_ALIST */ -const static struct _compopt { - const char * const optname; - int optflag; -} compopts[] = { - { "bashdefault", COPT_BASHDEFAULT }, - { "default", COPT_DEFAULT }, - { "dirnames", COPT_DIRNAMES }, - { "filenames",COPT_FILENAMES}, - { "nospace", COPT_NOSPACE }, - { "plusdirs", COPT_PLUSDIRS }, - { (char *)NULL, 0 }, -}; - -static int -find_compact (name) - char *name; -{ - register int i; - - for (i = 0; compacts[i].actname; i++) - if (STREQ (name, compacts[i].actname)) - return i; - return -1; -} - -static int -find_compopt (name) - char *name; -{ - register int i; - - for (i = 0; compopts[i].optname; i++) - if (STREQ (name, compopts[i].optname)) - return i; - return -1; -} - -/* Build the actions and compspec options from the options specified in LIST. - ACTP is a pointer to an unsigned long in which to place the bitmap of - actions. OPTP is a pointer to an unsigned long in which to place the - btmap of compspec options (arguments to `-o'). PP, if non-null, gets 1 - if -p is supplied; RP, if non-null, gets 1 if -r is supplied. - If either is null, the corresponding option generates an error. - This also sets variables corresponding to options that take arguments as - a side effect; the caller should ensure that those variables are set to - NULL before calling build_actions. Return value: - EX_USAGE = bad option - EXECUTION_SUCCESS = some options supplied - EXECUTION_FAILURE = no options supplied -*/ - -static int -build_actions (list, flagp, actp, optp) - WORD_LIST *list; - struct _optflags *flagp; - unsigned long *actp, *optp; -{ - int opt, ind, opt_given; - unsigned long acts, copts; - - acts = copts = (unsigned long)0L; - opt_given = 0; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "abcdefgjko:prsuvA:G:W:P:S:X:F:C:E")) != -1) - { - opt_given = 1; - switch (opt) - { - case 'r': - if (flagp) - { - flagp->rflag = 1; - break; - } - else - { - sh_invalidopt ("-r"); - builtin_usage (); - return (EX_USAGE); - } - - case 'p': - if (flagp) - { - flagp->pflag = 1; - break; - } - else - { - sh_invalidopt ("-p"); - builtin_usage (); - return (EX_USAGE); - } - - case 'a': - acts |= CA_ALIAS; - break; - case 'b': - acts |= CA_BUILTIN; - break; - case 'c': - acts |= CA_COMMAND; - break; - case 'd': - acts |= CA_DIRECTORY; - break; - case 'e': - acts |= CA_EXPORT; - break; - case 'f': - acts |= CA_FILE; - break; - case 'g': - acts |= CA_GROUP; - break; - case 'j': - acts |= CA_JOB; - break; - case 'k': - acts |= CA_KEYWORD; - break; - case 's': - acts |= CA_SERVICE; - break; - case 'u': - acts |= CA_USER; - break; - case 'v': - acts |= CA_VARIABLE; - break; - case 'o': - ind = find_compopt (list_optarg); - if (ind < 0) - { - sh_invalidoptname (list_optarg); - return (EX_USAGE); - } - copts |= compopts[ind].optflag; - break; - case 'A': - ind = find_compact (list_optarg); - if (ind < 0) - { - builtin_error (_("%s: invalid action name"), list_optarg); - return (EX_USAGE); - } - acts |= compacts[ind].actflag; - break; - case 'C': - Carg = list_optarg; - break; - case 'E': - if (flagp) - { - flagp->Eflag = 1; - break; - } - else - { - sh_invalidopt ("-E"); - builtin_usage (); - return (EX_USAGE); - } - case 'F': - Farg = list_optarg; - break; - case 'G': - Garg = list_optarg; - break; - case 'P': - Parg = list_optarg; - break; - case 'S': - Sarg = list_optarg; - break; - case 'W': - Warg = list_optarg; - break; - case 'X': - Xarg = list_optarg; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - - *actp = acts; - *optp = copts; - - return (opt_given ? EXECUTION_SUCCESS : EXECUTION_FAILURE); -} - -/* Add, remove, and display completion specifiers. */ -int -complete_builtin (list) - WORD_LIST *list; -{ - int opt_given, rval; - unsigned long acts, copts; - COMPSPEC *cs; - struct _optflags oflags; - WORD_LIST *l, *wl; - - if (list == 0) - { - print_all_completions (); - return (EXECUTION_SUCCESS); - } - - oflags.pflag = oflags.rflag = oflags.Eflag = 0; - - acts = copts = (unsigned long)0L; - Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL; - cs = (COMPSPEC *)NULL; - - /* Build the actions from the arguments. Also sets the [A-Z]arg variables - as a side effect if they are supplied as options. */ - rval = build_actions (list, &oflags, &acts, &copts); - if (rval == EX_USAGE) - return (rval); - opt_given = rval != EXECUTION_FAILURE; - - list = loptend; - - wl = oflags.Eflag ? make_word_list (make_bare_word ("_EmptycmD_"), (WORD_LIST *)NULL) : 0; - - /* -p overrides everything else */ - if (oflags.pflag || (list == 0 && opt_given == 0)) - { - if (wl) - { - rval = print_cmd_completions (wl); - dispose_words (wl); - return rval; - } - else if (list == 0) - { - print_all_completions (); - return (EXECUTION_SUCCESS); - } - return (print_cmd_completions (list)); - } - - /* next, -r overrides everything else. */ - if (oflags.rflag) - { - if (wl) - { - rval = remove_cmd_completions (wl); - dispose_words (wl); - return rval; - } - else if (list == 0) - { - progcomp_flush (); - return (EXECUTION_SUCCESS); - } - return (remove_cmd_completions (list)); - } - - if (wl == 0 && list == 0 && opt_given) - { - builtin_usage (); - return (EX_USAGE); - } - - /* If we get here, we need to build a compspec and add it for each - remaining argument. */ - cs = compspec_create (); - cs->actions = acts; - cs->options = copts; - - cs->globpat = STRDUP (Garg); - cs->words = STRDUP (Warg); - cs->prefix = STRDUP (Parg); - cs->suffix = STRDUP (Sarg); - cs->funcname = STRDUP (Farg); - cs->command = STRDUP (Carg); - cs->filterpat = STRDUP (Xarg); - - for (rval = EXECUTION_SUCCESS, l = wl ? wl : list ; l; l = l->next) - { - /* Add CS as the compspec for the specified commands. */ - if (progcomp_insert (l->word->word, cs) == 0) - rval = EXECUTION_FAILURE; - } - - dispose_words (wl); - return (rval); -} - -static int -remove_cmd_completions (list) - WORD_LIST *list; -{ - WORD_LIST *l; - int ret; - - for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next) - { - if (progcomp_remove (l->word->word) == 0) - { - builtin_error (_("%s: no completion specification"), l->word->word); - ret = EXECUTION_FAILURE; - } - } - return ret; -} - -#define SQPRINTARG(a, f) \ - do { \ - if (a) \ - { \ - x = sh_single_quote (a); \ - printf ("%s %s ", f, x); \ - free (x); \ - } \ - } while (0) - -#define PRINTARG(a, f) \ - do { \ - if (a) \ - printf ("%s %s ", f, a); \ - } while (0) - -#define PRINTOPT(a, f) \ - do { \ - if (acts & a) \ - printf ("%s ", f); \ - } while (0) - -#define PRINTACT(a, f) \ - do { \ - if (acts & a) \ - printf ("-A %s ", f); \ - } while (0) - -#define PRINTCOMPOPT(a, f) \ - do { \ - if (copts & a) \ - printf ("-o %s ", f); \ - } while (0) - -#define XPRINTCOMPOPT(a, f) \ - do { \ - if (copts & a) \ - printf ("-o %s ", f); \ - else \ - printf ("+o %s ", f); \ - } while (0) - -static int -print_one_completion (cmd, cs) - char *cmd; - COMPSPEC *cs; -{ - unsigned long acts, copts; - char *x; - - printf ("complete "); - - copts = cs->options; - - /* First, print the -o options. */ - PRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault"); - PRINTCOMPOPT (COPT_DEFAULT, "default"); - PRINTCOMPOPT (COPT_DIRNAMES, "dirnames"); - PRINTCOMPOPT (COPT_FILENAMES, "filenames"); - PRINTCOMPOPT (COPT_NOSPACE, "nospace"); - PRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs"); - - acts = cs->actions; - - /* simple flags next */ - PRINTOPT (CA_ALIAS, "-a"); - PRINTOPT (CA_BUILTIN, "-b"); - PRINTOPT (CA_COMMAND, "-c"); - PRINTOPT (CA_DIRECTORY, "-d"); - PRINTOPT (CA_EXPORT, "-e"); - PRINTOPT (CA_FILE, "-f"); - PRINTOPT (CA_GROUP, "-g"); - PRINTOPT (CA_JOB, "-j"); - PRINTOPT (CA_KEYWORD, "-k"); - PRINTOPT (CA_SERVICE, "-s"); - PRINTOPT (CA_USER, "-u"); - PRINTOPT (CA_VARIABLE, "-v"); - - /* now the rest of the actions */ - PRINTACT (CA_ARRAYVAR, "arrayvar"); - PRINTACT (CA_BINDING, "binding"); - PRINTACT (CA_DISABLED, "disabled"); - PRINTACT (CA_ENABLED, "enabled"); - PRINTACT (CA_FUNCTION, "function"); - PRINTACT (CA_HELPTOPIC, "helptopic"); - PRINTACT (CA_HOSTNAME, "hostname"); - PRINTACT (CA_RUNNING, "running"); - PRINTACT (CA_SETOPT, "setopt"); - PRINTACT (CA_SHOPT, "shopt"); - PRINTACT (CA_SIGNAL, "signal"); - PRINTACT (CA_STOPPED, "stopped"); - - /* now the rest of the arguments */ - - /* arguments that require quoting */ - SQPRINTARG (cs->globpat, "-G"); - SQPRINTARG (cs->words, "-W"); - SQPRINTARG (cs->prefix, "-P"); - SQPRINTARG (cs->suffix, "-S"); - SQPRINTARG (cs->filterpat, "-X"); - - SQPRINTARG (cs->command, "-C"); - - /* simple arguments that don't require quoting */ - PRINTARG (cs->funcname, "-F"); - - printf ("%s\n", cmd); - - return (0); -} - -static void -print_compopts (cmd, cs, full) - const char *cmd; - COMPSPEC *cs; - int full; -{ - int copts; - - printf ("compopt "); - copts = cs->options; - - if (full) - { - XPRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault"); - XPRINTCOMPOPT (COPT_DEFAULT, "default"); - XPRINTCOMPOPT (COPT_DIRNAMES, "dirnames"); - XPRINTCOMPOPT (COPT_FILENAMES, "filenames"); - XPRINTCOMPOPT (COPT_NOSPACE, "nospace"); - XPRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs"); - } - else - { - PRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault"); - PRINTCOMPOPT (COPT_DEFAULT, "default"); - PRINTCOMPOPT (COPT_DIRNAMES, "dirnames"); - PRINTCOMPOPT (COPT_FILENAMES, "filenames"); - PRINTCOMPOPT (COPT_NOSPACE, "nospace"); - PRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs"); - } - - printf ("%s\n", cmd); -} - -static int -print_compitem (item) - BUCKET_CONTENTS *item; -{ - COMPSPEC *cs; - char *cmd; - - cmd = item->key; - cs = (COMPSPEC *)item->data; - - return (print_one_completion (cmd, cs)); -} - -static void -print_all_completions () -{ - progcomp_walk (print_compitem); -} - -static int -print_cmd_completions (list) - WORD_LIST *list; -{ - WORD_LIST *l; - COMPSPEC *cs; - int ret; - - for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next) - { - cs = progcomp_search (l->word->word); - if (cs) - print_one_completion (l->word->word, cs); - else - { - builtin_error (_("%s: no completion specification"), l->word->word); - ret = EXECUTION_FAILURE; - } - } - - return (sh_chkwrite (ret)); -} - -$BUILTIN compgen -$DEPENDS_ON PROGRAMMABLE_COMPLETION -$FUNCTION compgen_builtin -$SHORT_DOC compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word] -Display possible completions depending on the options. - -Intended to be used from within a shell function generating possible -completions. If the optional WORD argument is supplied, matches against -WORD are generated. - -Exit Status: -Returns success unless an invalid option is supplied or an error occurs. -$END - -int -compgen_builtin (list) - WORD_LIST *list; -{ - int rval; - unsigned long acts, copts; - COMPSPEC *cs; - STRINGLIST *sl; - char *word, **matches; - - if (list == 0) - return (EXECUTION_SUCCESS); - - acts = copts = (unsigned long)0L; - Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL; - cs = (COMPSPEC *)NULL; - - /* Build the actions from the arguments. Also sets the [A-Z]arg variables - as a side effect if they are supplied as options. */ - rval = build_actions (list, (struct _optflags *)NULL, &acts, &copts); - if (rval == EX_USAGE) - return (rval); - if (rval == EXECUTION_FAILURE) - return (EXECUTION_SUCCESS); - - list = loptend; - - word = (list && list->word) ? list->word->word : ""; - - if (Farg) - builtin_error (_("warning: -F option may not work as you expect")); - if (Carg) - builtin_error (_("warning: -C option may not work as you expect")); - - /* If we get here, we need to build a compspec and evaluate it. */ - cs = compspec_create (); - cs->actions = acts; - cs->options = copts; - cs->refcount = 1; - - cs->globpat = STRDUP (Garg); - cs->words = STRDUP (Warg); - cs->prefix = STRDUP (Parg); - cs->suffix = STRDUP (Sarg); - cs->funcname = STRDUP (Farg); - cs->command = STRDUP (Carg); - cs->filterpat = STRDUP (Xarg); - - rval = EXECUTION_FAILURE; - sl = gen_compspec_completions (cs, "compgen", word, 0, 0); - - /* If the compspec wants the bash default completions, temporarily - turn off programmable completion and call the bash completion code. */ - if ((sl == 0 || sl->list_len == 0) && (copts & COPT_BASHDEFAULT)) - { - matches = bash_default_completion (word, 0, 0, 0, 0); - sl = completions_to_stringlist (matches); - strvec_dispose (matches); - } - - /* This isn't perfect, but it's the best we can do, given what readline - exports from its set of completion utility functions. */ - if ((sl == 0 || sl->list_len == 0) && (copts & COPT_DEFAULT)) - { - matches = rl_completion_matches (word, rl_filename_completion_function); - sl = completions_to_stringlist (matches); - strvec_dispose (matches); - } - - if (sl) - { - if (sl->list && sl->list_len) - { - rval = EXECUTION_SUCCESS; - strlist_print (sl, (char *)NULL); - } - strlist_dispose (sl); - } - - compspec_dispose (cs); - return (rval); -} - -$BUILTIN compopt -$DEPENDS_ON PROGRAMMABLE_COMPLETION -$FUNCTION compopt_builtin -$SHORT_DOC compopt [-o|+o option] [name ...] -Modify or display completion options. - -Modify the completion options for each NAME, or, if no NAMEs are supplied, -the completion currently begin executed. If no OPTIONs are givenm, print -the completion options for each NAME or the current completion specification. - -Options: - -o option Set completion option OPTION for each NAME - -Using `+o' instead of `-o' turns off the specified option. - -Arguments: - -Each NAME refers to a command for which a completion specification must -have previously been defined using the `complete' builtin. If no NAMEs -are supplied, compopt must be called by a function currently generating -completions, and the options for that currently-executing completion -generator are modified. - -Exit Status: -Returns success unless an invalid option is supplied or NAME does not -have a completion specification defined. -$END - -int -compopt_builtin (list) - WORD_LIST *list; -{ - int opts_on, opts_off, *opts, opt, oind, ret, Eflag; - WORD_LIST *l; - COMPSPEC *cs; - - opts_on = opts_off = 0; - ret = EXECUTION_SUCCESS; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "+o:")) != EOF) - { - opts = (list_opttype == '-') ? &opts_on : &opts_off; - - switch (opt) - { - case 'o': - oind = find_compopt (list_optarg); - if (oind < 0) - { - sh_invalidoptname (list_optarg); - return (EX_USAGE); - } - *opts |= compopts[oind].optflag; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - if (list == 0) - { - if (RL_ISSTATE (RL_STATE_COMPLETING) == 0 || pcomp_curcs == 0) - { - builtin_error (_("not currently executing completion function")); - return (EXECUTION_FAILURE); - } - cs = pcomp_curcs; - - if (opts_on == 0 && opts_off == 0) - { - print_compopts (pcomp_curcmd, cs, 1); - return (sh_chkwrite (ret)); - } - - /* Set the compspec options */ - pcomp_set_compspec_options (cs, opts_on, 1); - pcomp_set_compspec_options (cs, opts_off, 0); - - /* And change the readline variables the options control */ - pcomp_set_readline_variables (opts_on, 1); - pcomp_set_readline_variables (opts_off, 0); - - return (ret); - } - - for (l = list; l; l = l->next) - { - cs = progcomp_search (l->word->word); - if (cs == 0) - { - builtin_error (_("%s: no completion specification"), l->word->word); - ret = EXECUTION_FAILURE; - continue; - } - if (opts_on == 0 && opts_off == 0) - { - print_compopts (l->word->word, cs, 1); - continue; /* XXX -- fill in later */ - } - - /* Set the compspec options */ - pcomp_set_compspec_options (cs, opts_on, 1); - pcomp_set_compspec_options (cs, opts_off, 0); - } - - return (ret); -} diff --git a/builtins/declare.def~ b/builtins/declare.def~ deleted file mode 100644 index 52fa829cb..000000000 --- a/builtins/declare.def~ +++ /dev/null @@ -1,551 +0,0 @@ -This file is declare.def, from which is created declare.c. -It implements the builtins "declare" and "local" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Bash is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Bash. If not, see . - -$PRODUCES declare.c - -$BUILTIN declare -$FUNCTION declare_builtin -$SHORT_DOC declare [-aAfFilrtux] [-p] [name[=value] ...] -Set variable values and attributes. - -Declare variables and give them attributes. If no NAMEs are given, -display the attributes and values of all variables. - -Options: - -f restrict action or display to function names and definitions - -F restrict display to function names only (plus line number and - source file when debugging) - -p display the attributes and value of each NAME - -Options which set attributes: - -a to make NAMEs indexed arrays (if supported) - -A to make NAMEs associative arrays (if supported) - -i to make NAMEs have the `integer' attribute - -l to convert NAMEs to lower case on assignment - -r to make NAMEs readonly - -t to make NAMEs have the `trace' attribute - -u to convert NAMEs to upper case on assignment - -x to make NAMEs export - -Using `+' instead of `-' turns off the given attribute. - -Variables with the integer attribute have arithmetic evaluation (see -the `let' command) performed when the variable is assigned a value. - -When used in a function, `declare' makes NAMEs local, as with the `local' -command. - -Exit Status: -Returns success unless an invalid option is supplied or an error occurs. -$END - -$BUILTIN typeset -$FUNCTION declare_builtin -$SHORT_DOC typeset [-aAfFilrtux] [-p] name[=value] ... -Set variable values and attributes. - -Obsolete. See `help declare'. -$END - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "common.h" -#include "builtext.h" -#include "bashgetopt.h" - -extern int array_needs_making; -extern int posixly_correct; - -static int declare_internal __P((register WORD_LIST *, int)); - -/* Declare or change variable attributes. */ -int -declare_builtin (list) - register WORD_LIST *list; -{ - return (declare_internal (list, 0)); -} - -$BUILTIN local -$FUNCTION local_builtin -$SHORT_DOC local [option] name[=value] ... -Define local variables. - -Create a local variable called NAME, and give it VALUE. OPTION can -be any option accepted by `declare'. - -Local variables can only be used within a function; they are visible -only to the function where they are defined and its children. - -Exit Status: -Returns success unless an invalid option is supplied, an error occurs, -or the shell is not executing a function. -$END -int -local_builtin (list) - register WORD_LIST *list; -{ - if (variable_context) - return (declare_internal (list, 1)); - else - { - builtin_error (_("can only be used in a function")); - return (EXECUTION_FAILURE); - } -} - -#if defined (ARRAY_VARS) -# define DECLARE_OPTS "+acfilprtuxAF" -#else -# define DECLARE_OPTS "+cfilprtuxF" -#endif - -/* The workhorse function. */ -static int -declare_internal (list, local_var) - register WORD_LIST *list; - int local_var; -{ - int flags_on, flags_off, *flags; - int any_failed, assign_error, pflag, nodefs, opt; - char *t, *subscript_start; - SHELL_VAR *var; - FUNCTION_DEF *shell_fn; - - flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, DECLARE_OPTS)) != EOF) - { - flags = list_opttype == '+' ? &flags_off : &flags_on; - - switch (opt) - { - case 'a': -#if defined (ARRAY_VARS) - *flags |= att_array; - break; -#else - builtin_usage (); - return (EX_USAGE); -#endif - case 'A': -#if defined (ARRAY_VARS) - *flags |= att_assoc; - break; -#else - builtin_usage (); - return (EX_USAGE); -#endif - case 'p': - if (local_var == 0) - pflag++; - break; - case 'F': - nodefs++; - *flags |= att_function; - break; - case 'f': - *flags |= att_function; - break; - case 'i': - *flags |= att_integer; - break; - case 'r': - *flags |= att_readonly; - break; - case 't': - *flags |= att_trace; - break; - case 'x': - *flags |= att_exported; - array_needs_making = 1; - break; -#if defined (CASEMOD_ATTRS) -# if defined (CASEMOD_CAPCASE) - case 'c': - *flags |= att_capcase; - if (flags == &flags_on) - flags_off |= att_uppercase|att_lowercase; - break; -# endif - case 'l': - *flags |= att_lowercase; - if (flags == &flags_on) - flags_off |= att_capcase|att_uppercase; - break; - case 'u': - *flags |= att_uppercase; - if (flags == &flags_on) - flags_off |= att_capcase|att_lowercase; - break; -#endif /* CASEMOD_ATTRS */ - default: - builtin_usage (); - return (EX_USAGE); - } - } - - list = loptend; - - /* If there are no more arguments left, then we just want to show - some variables. */ - if (list == 0) /* declare -[aAfFirtx] */ - { - /* Show local variables defined at this context level if this is - the `local' builtin. */ - if (local_var) - { - register SHELL_VAR **vlist; - register int i; - - vlist = all_local_variables (); - - if (vlist) - { - for (i = 0; vlist[i]; i++) - print_assignment (vlist[i]); - - free (vlist); - } - } - else if (pflag && (flags_on == 0 || flags_on == att_function)) - show_all_var_attributes (flags_on == 0, nodefs); - else if (flags_on == 0) - return (set_builtin ((WORD_LIST *)NULL)); - else - set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs); - - return (sh_chkwrite (EXECUTION_SUCCESS)); - } - - if (pflag) /* declare -p [-aAfFirtx] name [name...] */ - { - for (any_failed = 0; list; list = list->next) - { - pflag = show_name_attributes (list->word->word, nodefs); - if (pflag) - { - sh_notfound (list->word->word); - any_failed++; - } - } - return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS)); - } - -#define NEXT_VARIABLE() free (name); list = list->next; continue - - /* There are arguments left, so we are making variables. */ - while (list) /* declare [-aAfFirx] name [name ...] */ - { - char *value, *name; - int offset, aflags; -#if defined (ARRAY_VARS) - int making_array_special, compound_array_assign, simple_array_assign; -#endif - - name = savestring (list->word->word); - offset = assignment (name, 0); - aflags = 0; - - if (offset) /* declare [-aAfFirx] name=value */ - { - name[offset] = '\0'; - value = name + offset + 1; - if (name[offset - 1] == '+') - { - aflags |= ASS_APPEND; - name[offset - 1] = '\0'; - } - } - else - value = ""; - -#if defined (ARRAY_VARS) - compound_array_assign = simple_array_assign = 0; - subscript_start = (char *)NULL; - if (t = strchr (name, '[')) /* ] */ - { - subscript_start = t; - *t = '\0'; - making_array_special = 1; - } - else - making_array_special = 0; -#endif - - /* If we're in posix mode or not looking for a shell function (since - shell function names don't have to be valid identifiers when the - shell's not in posix mode), check whether or not the argument is a - valid, well-formed shell identifier. */ - if ((posixly_correct || (flags_on & att_function) == 0) && legal_identifier (name) == 0) - { - sh_invalidid (name); - assign_error++; - NEXT_VARIABLE (); - } - - /* If VARIABLE_CONTEXT has a non-zero value, then we are executing - inside of a function. This means we should make local variables, - not global ones. */ - - /* XXX - this has consequences when we're making a local copy of a - variable that was in the temporary environment. Watch out - for this. */ - if (variable_context && ((flags_on & att_function) == 0)) - { -#if defined (ARRAY_VARS) - if (flags_on & att_assoc) - var = make_local_assoc_variable (name); - else if ((flags_on & att_array) || making_array_special) - var = make_local_array_variable (name); - else -#endif - var = make_local_variable (name); - if (var == 0) - { - any_failed++; - NEXT_VARIABLE (); - } - } - else - var = (SHELL_VAR *)NULL; - - /* If we are declaring a function, then complain about it in some way. - We don't let people make functions by saying `typeset -f foo=bar'. */ - - /* There should be a way, however, to let people look at a particular - function definition by saying `typeset -f foo'. */ - - if (flags_on & att_function) - { - if (offset) /* declare -f [-rix] foo=bar */ - { - builtin_error (_("cannot use `-f' to make functions")); - free (name); - return (EXECUTION_FAILURE); - } - else /* declare -f [-rx] name [name...] */ - { - var = find_function (name); - - if (var) - { - if (readonly_p (var) && (flags_off & att_readonly)) - { - builtin_error (_("%s: readonly function"), name); - any_failed++; - NEXT_VARIABLE (); - } - - /* declare -[Ff] name [name...] */ - if (flags_on == att_function && flags_off == 0) - { -#if defined (DEBUGGER) - if (nodefs && debugging_mode) - { - shell_fn = find_function_def (var->name); - if (shell_fn) - printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file); - else - printf ("%s\n", var->name); - } - else -#endif /* DEBUGGER */ - { - t = nodefs ? var->name - : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL); - printf ("%s\n", t); - any_failed = sh_chkwrite (any_failed); - } - } - else /* declare -[fF] -[rx] name [name...] */ - { - VSETATTR (var, flags_on); - VUNSETATTR (var, flags_off); - } - } - else - any_failed++; - NEXT_VARIABLE (); - } - } - else /* declare -[aAirx] name [name...] */ - { - /* Non-null if we just created or fetched a local variable. */ - if (var == 0) - var = find_variable (name); - - if (var == 0) - { -#if defined (ARRAY_VARS) - if (flags_on & att_assoc) - var = make_new_assoc_variable (name); - else if ((flags_on & att_array) || making_array_special) - var = make_new_array_variable (name); - else -#endif - - if (offset) - var = bind_variable (name, "", 0); - else - { - var = bind_variable (name, (char *)NULL, 0); - VSETATTR (var, att_invisible); - } -#endif - } - - /* Cannot use declare +r to turn off readonly attribute. */ - if (readonly_p (var) && (flags_off & att_readonly)) - { - sh_readonly (name); - any_failed++; - NEXT_VARIABLE (); - } - - /* Cannot use declare to assign value to readonly or noassign - variable. */ - if ((readonly_p (var) || noassign_p (var)) && offset) - { - if (readonly_p (var)) - sh_readonly (name); - assign_error++; - NEXT_VARIABLE (); - } - -#if defined (ARRAY_VARS) - if ((making_array_special || (flags_on & (att_array|att_assoc)) || array_p (var) || assoc_p (var)) && offset) - { - int vlen; - vlen = STRLEN (value); - - if (value[0] == '(' && value[vlen-1] == ')') - compound_array_assign = 1; - else - simple_array_assign = 1; - } - - /* Cannot use declare +a name or declare +A name to remove an - array variable. */ - if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var))) - { - builtin_error (_("%s: cannot destroy array variables in this way"), name); - any_failed++; - NEXT_VARIABLE (); - } - - if ((flags_on & att_array) && assoc_p (var)) - { - builtin_error (_("%s: cannot convert associative to indexed array"), name); - any_failed++; - NEXT_VARIABLE (); - } - if ((flags_on & att_assoc) && array_p (var)) - { - builtin_error (_("%s: cannot convert indexed to associative array"), name); - any_failed++; - NEXT_VARIABLE (); - } - - /* declare -A name[[n]] makes name an associative array variable. */ - if (flags_on & att_assoc) - { - if (assoc_p (var) == 0) - var = convert_var_to_assoc (var); - } - /* declare -a name[[n]] or declare name[n] makes name an indexed - array variable. */ - else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0) - var = convert_var_to_array (var); -#endif /* ARRAY_VARS */ - - VSETATTR (var, flags_on); - VUNSETATTR (var, flags_off); - -#if defined (ARRAY_VARS) - if (offset && compound_array_assign) - assign_array_var_from_string (var, value, aflags); - else if (simple_array_assign && subscript_start) - { - /* declare [-a] name[N]=value */ - *subscript_start = '['; /* ] */ - var = assign_array_element (name, value, 0); /* XXX - not aflags */ - *subscript_start = '\0'; - } - else if (simple_array_assign) - /* let bind_array_variable take care of this. */ - bind_array_variable (name, 0, value, aflags); - else -#endif - /* bind_variable_value duplicates the essential internals of - bind_variable() */ - if (offset) - bind_variable_value (var, value, aflags); - - /* If we found this variable in the temporary environment, as with - `var=value declare -x var', make sure it is treated identically - to `var=value export var'. Do the same for `declare -r' and - `readonly'. Preserve the attributes, except for att_tempvar. */ - /* XXX -- should this create a variable in the global scope, or - modify the local variable flags? ksh93 has it modify the - global scope. - Need to handle case like in set_var_attribute where a temporary - variable is in the same table as the function local vars. */ - if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var)) - { - SHELL_VAR *tv; - char *tvalue; - - tv = find_tempenv_variable (var->name); - if (tv) - { - tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring (""); - tv = bind_variable (var->name, tvalue, 0); - tv->attributes |= var->attributes & ~att_tempvar; - if (tv->context > 0) - VSETATTR (tv, att_propagate); - free (tvalue); - } - VSETATTR (var, att_propagate); - } - } - - stupidly_hack_special_variables (name); - - NEXT_VARIABLE (); - } - - return (assign_error ? EX_BADASSIGN - : ((any_failed == 0) ? EXECUTION_SUCCESS - : EXECUTION_FAILURE)); -} diff --git a/builtins/echo.def~ b/builtins/echo.def~ deleted file mode 100644 index ecfe43800..000000000 --- a/builtins/echo.def~ +++ /dev/null @@ -1,195 +0,0 @@ -This file is echo.def, from which is created echo.c. -It implements the builtin "echo" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Bash is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Bash. If not, see . - -$PRODUCES echo.c -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "../bashansi.h" - -#include -#include "../shell.h" - -#include "common.h" - -$BUILTIN echo -$FUNCTION echo_builtin -$DEPENDS_ON V9_ECHO -$SHORT_DOC echo [-neE] [arg ...] -Write arguments to the standard output. - -Display the ARGs on the standard output followed by a newline. - -Options: - -n do not append a newline - -e enable interpretation of the following backslash escapes - -E explicitly suppress interpretation of backslash escapes - -`echo' interprets the following backslash-escaped characters: - \a alert (bell) - \b backspace - \c suppress further output - \e escape character - \f form feed - \n new line - \r carriage return - \t horizontal tab - \v vertical tab - \\ backslash - \0nnn the character whose ASCII code is NNN (octal). NNN can be - 0 to 3 octal digits - \xHH the eight-bit character whose value is HH (hexadecimal). HH - can be one or two hex digits - -Exit Status: -Returns success unless a write error occurs. -$END - -$BUILTIN echo -$FUNCTION echo_builtin -$DEPENDS_ON !V9_ECHO -$SHORT_DOC echo [-n] [arg ...] -Write arguments to the standard output. - -Display the ARGs on the standard output followed by a newline. - -Options: - -n do not append a newline - -Exit Status: -Returns success unless a write error occurs. -$END - -#if defined (V9_ECHO) -# define VALID_ECHO_OPTIONS "neE" -#else /* !V9_ECHO */ -# define VALID_ECHO_OPTIONS "n" -#endif /* !V9_ECHO */ - -/* System V machines already have a /bin/sh with a v9 behaviour. We - give Bash the identical behaviour for these machines so that the - existing system shells won't barf. Regrettably, the SUS v2 has - standardized the Sys V echo behavior. This variable is external - so that we can have a `shopt' variable to control it at runtime. */ -#if defined (DEFAULT_ECHO_TO_XPG) || defined (STRICT_POSIX) -int xpg_echo = 1; -#else -int xpg_echo = 0; -#endif /* DEFAULT_ECHO_TO_XPG */ - -extern int posixly_correct; - -/* Print the words in LIST to standard output. If the first word is - `-n', then don't print a trailing newline. We also support the - echo syntax from Version 9 Unix systems. */ -int -echo_builtin (list) - WORD_LIST *list; -{ - int display_return, do_v9, i, len; - char *temp, *s; - - do_v9 = xpg_echo; - display_return = 1; - - if (posixly_correct && xpg_echo) - goto just_echo; - - for (; list && (temp = list->word->word) && *temp == '-'; list = list->next) - { - /* If it appears that we are handling options, then make sure that - all of the options specified are actually valid. Otherwise, the - string should just be echoed. */ - temp++; - - for (i = 0; temp[i]; i++) - { - if (strchr (VALID_ECHO_OPTIONS, temp[i]) == 0) - break; - } - - /* echo - and echo - both mean to just echo the arguments. */ - if (*temp == 0 || temp[i]) - break; - - /* All of the options in TEMP are valid options to ECHO. - Handle them. */ - while (i = *temp++) - { - switch (i) - { - case 'n': - display_return = 0; - break; -#if defined (V9_ECHO) - case 'e': - do_v9 = 1; - break; - case 'E': - do_v9 = 0; - break; -#endif /* V9_ECHO */ - default: - goto just_echo; /* XXX */ - } - } - } - -just_echo: - - clearerr (stdout); /* clear error before writing and testing success */ - - while (list) - { - i = len = 0; - temp = do_v9 ? ansicstr (list->word->word, STRLEN (list->word->word), 1, &i, &len) - : list->word->word; - if (temp) - { - if (do_v9) - { - for (s = temp; len > 0; len--) - putchar (*s++); - } - else - printf ("%s", temp); -#if defined (SunOS5) - fflush (stdout); /* Fix for bug in SunOS 5.5 printf(3) */ -#endif - } - if (do_v9 && temp) - free (temp); - list = list->next; - if (i) - { - display_return = 0; - break; - } - if (list) - putchar(' '); - } - - if (display_return) - putchar ('\n'); - return (sh_chkwrite (EXECUTION_SUCCESS)); -} diff --git a/builtins/enable.def~ b/builtins/enable.def~ deleted file mode 100644 index e1cd5e4fe..000000000 --- a/builtins/enable.def~ +++ /dev/null @@ -1,481 +0,0 @@ -This file is enable.def, from which is created enable.c. -It implements the builtin "enable" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 enable.c - -$BUILTIN enable -$FUNCTION enable_builtin -$SHORT_DOC enable [-a] [-dnps] [-f filename] [name ...] -Enable and disable shell builtins. - -Enables and disables builtin shell commands. Disabling allows you to -execute a disk command which has the same name as a shell builtin -without using a full pathname. - -Options: - -a print a list of builtins showing whether or not each is enabled - -n disable each NAME or display a list of disabled builtins - -p print the list of builtins in a reusable format - -s print only the names of Posix `special' builtins - -Options controlling dynamic loading: - -f Load builtin NAME from shared object FILENAME - -d Remove a builtin loaded with -f - -Without options, each NAME is enabled. - -To use the `test' found in $PATH instead of the shell builtin -version, type `enable -n test'. -$END - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../builtins.h" -#include "../flags.h" -#include "common.h" -#include "bashgetopt.h" - -#if defined (PROGRAMMABLE_COMPLETION) -# include "../pcomplete.h" -#endif - -#define ENABLED 1 -#define DISABLED 2 -#define SPECIAL 4 - -#define AFLAG 0x01 -#define DFLAG 0x02 -#define FFLAG 0x04 -#define NFLAG 0x08 -#define PFLAG 0x10 -#define SFLAG 0x20 - -#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) -static int dyn_load_builtin __P((WORD_LIST *, int, char *)); -#endif - -#if defined (HAVE_DLCLOSE) -static int dyn_unload_builtin __P((char *)); -static void delete_builtin __P((struct builtin *)); -static int local_dlclose __P((void *)); -#endif - -static void list_some_builtins __P((int)); -static int enable_shell_command __P((char *, int)); - -/* Enable/disable shell commands present in LIST. If list is not specified, - then print out a list of shell commands showing which are enabled and - which are disabled. */ -int -enable_builtin (list) - WORD_LIST *list; -{ - int result, flags; - int opt, filter; -#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) - char *filename; -#endif - - result = EXECUTION_SUCCESS; - flags = 0; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "adnpsf:")) != -1) - { - switch (opt) - { - case 'a': - flags |= AFLAG; - break; - case 'n': - flags |= NFLAG; - break; - case 'p': - flags |= PFLAG; - break; - case 's': - flags |= SFLAG; - break; - case 'f': -#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) - flags |= FFLAG; - filename = list_optarg; - break; -#else - builtin_error (_("dynamic loading not available")); - return (EX_USAGE); -#endif -#if defined (HAVE_DLCLOSE) - case 'd': - flags |= DFLAG; - break; -#else - builtin_error (_("dynamic loading not available")); - return (EX_USAGE); -#endif /* HAVE_DLCLOSE */ - default: - builtin_usage (); - return (EX_USAGE); - } - } - - list = loptend; - -#if defined (RESTRICTED_SHELL) - /* Restricted shells cannot load new builtins. */ - if (restricted && (flags & (FFLAG|DFLAG))) - { - sh_restricted ((char *)NULL); - return (EXECUTION_FAILURE); - } -#endif - - if (list == 0 || (flags & PFLAG)) - { - filter = (flags & AFLAG) ? (ENABLED | DISABLED) - : (flags & NFLAG) ? DISABLED : ENABLED; - - if (flags & SFLAG) - filter |= SPECIAL; - - list_some_builtins (filter); - } -#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) - else if (flags & FFLAG) - { - filter = (flags & NFLAG) ? DISABLED : ENABLED; - if (flags & SFLAG) - filter |= SPECIAL; - - result = dyn_load_builtin (list, filter, filename); -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_builtins); -#endif - } -#endif -#if defined (HAVE_DLCLOSE) - else if (flags & DFLAG) - { - while (list) - { - opt = dyn_unload_builtin (list->word->word); - if (opt == EXECUTION_FAILURE) - result = EXECUTION_FAILURE; - list = list->next; - } -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_builtins); -#endif - } -#endif - else - { - while (list) - { - opt = enable_shell_command (list->word->word, flags & NFLAG); - - if (opt == EXECUTION_FAILURE) - { - sh_notbuiltin (list->word->word); - result = EXECUTION_FAILURE; - } - list = list->next; - } - } - return (result); -} - -/* List some builtins. - FILTER is a mask with two slots: ENABLED and DISABLED. */ -static void -list_some_builtins (filter) - int filter; -{ - register int i; - - for (i = 0; i < num_shell_builtins; i++) - { - if (shell_builtins[i].function == 0 || (shell_builtins[i].flags & BUILTIN_DELETED)) - continue; - - if ((filter & SPECIAL) && - (shell_builtins[i].flags & SPECIAL_BUILTIN) == 0) - continue; - - if ((filter & ENABLED) && (shell_builtins[i].flags & BUILTIN_ENABLED)) - printf ("enable %s\n", shell_builtins[i].name); - else if ((filter & DISABLED) && - ((shell_builtins[i].flags & BUILTIN_ENABLED) == 0)) - printf ("enable -n %s\n", shell_builtins[i].name); - } -} - -/* Enable the shell command NAME. If DISABLE_P is non-zero, then - disable NAME instead. */ -static int -enable_shell_command (name, disable_p) - char *name; - int disable_p; -{ - struct builtin *b; - - b = builtin_address_internal (name, 1); - if (b == 0) - return (EXECUTION_FAILURE); - - if (disable_p) - b->flags &= ~BUILTIN_ENABLED; -#if defined (RESTRICTED_SHELL) - else if (restricted && ((b->flags & BUILTIN_ENABLED) == 0)) - { - sh_restricted ((char *)NULL); - return (EXECUTION_FAILURE); - } -#endif - else - b->flags |= BUILTIN_ENABLED; - -#if defined (PROGRAMMABLE_COMPLETION) - set_itemlist_dirty (&it_enabled); - set_itemlist_dirty (&it_disabled); -#endif - - return (EXECUTION_SUCCESS); -} - -#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) - -#if defined (HAVE_DLFCN_H) -# include -#endif - -static int -dyn_load_builtin (list, flags, filename) - WORD_LIST *list; - int flags; - char *filename; -{ - WORD_LIST *l; - void *handle; - - int total, size, new, replaced; - char *struct_name, *name; - struct builtin **new_builtins, *b, *new_shell_builtins, *old_builtin; - - if (list == 0) - return (EXECUTION_FAILURE); - -#ifndef RTLD_LAZY -#define RTLD_LAZY 1 -#endif - -#if defined (_AIX) - handle = dlopen (filename, RTLD_NOW|RTLD_GLOBAL); -#else - handle = dlopen (filename, RTLD_LAZY); -#endif /* !_AIX */ - - if (handle == 0) - { - builtin_error (_("cannot open shared object %s: %s"), filename, dlerror ()); - return (EXECUTION_FAILURE); - } - - for (new = 0, l = list; l; l = l->next, new++) - ; - new_builtins = (struct builtin **)xmalloc (new * sizeof (struct builtin *)); - - /* For each new builtin in the shared object, find it and its describing - structure. If this is overwriting an existing builtin, do so, otherwise - save the loaded struct for creating the new list of builtins. */ - for (replaced = new = 0; list; list = list->next) - { - name = list->word->word; - - size = strlen (name); - struct_name = (char *)xmalloc (size + 8); - strcpy (struct_name, name); - strcpy (struct_name + size, "_struct"); - - b = (struct builtin *)dlsym (handle, struct_name); - if (b == 0) - { - builtin_error (_("cannot find %s in shared object %s: %s"), - struct_name, filename, dlerror ()); - free (struct_name); - continue; - } - - free (struct_name); - - b->flags &= ~STATIC_BUILTIN; - if (flags & SPECIAL) - b->flags |= SPECIAL_BUILTIN; - b->handle = handle; - - if (old_builtin = builtin_address_internal (name, 1)) - { - replaced++; - FASTCOPY ((char *)b, (char *)old_builtin, sizeof (struct builtin)); - } - else - new_builtins[new++] = b; - } - - if (replaced == 0 && new == 0) - { - free (new_builtins); - dlclose (handle); - return (EXECUTION_FAILURE); - } - - if (new) - { - total = num_shell_builtins + new; - size = (total + 1) * sizeof (struct builtin); - - new_shell_builtins = (struct builtin *)xmalloc (size); - FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins, - num_shell_builtins * sizeof (struct builtin)); - for (replaced = 0; replaced < new; replaced++) - FASTCOPY ((char *)new_builtins[replaced], - (char *)&new_shell_builtins[num_shell_builtins + replaced], - sizeof (struct builtin)); - - new_shell_builtins[total].name = (char *)0; - new_shell_builtins[total].function = (sh_builtin_func_t *)0; - new_shell_builtins[total].flags = 0; - - if (shell_builtins != static_shell_builtins) - free (shell_builtins); - - shell_builtins = new_shell_builtins; - num_shell_builtins = total; - initialize_shell_builtins (); - } - - free (new_builtins); - return (EXECUTION_SUCCESS); -} -#endif - -#if defined (HAVE_DLCLOSE) -static void -delete_builtin (b) - struct builtin *b; -{ - int ind, size; - struct builtin *new_shell_builtins; - - /* XXX - funky pointer arithmetic - XXX */ -#ifdef __STDC__ - ind = b - shell_builtins; -#else - ind = ((int)b - (int)shell_builtins) / sizeof (struct builtin); -#endif - size = num_shell_builtins * sizeof (struct builtin); - new_shell_builtins = (struct builtin *)xmalloc (size); - - /* Copy shell_builtins[0]...shell_builtins[ind - 1] to new_shell_builtins */ - if (ind) - FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins, - ind * sizeof (struct builtin)); - /* Copy shell_builtins[ind+1]...shell_builtins[num_shell_builtins to - new_shell_builtins, starting at ind. */ - FASTCOPY ((char *)(&shell_builtins[ind+1]), - (char *)(&new_shell_builtins[ind]), - (num_shell_builtins - ind) * sizeof (struct builtin)); - - if (shell_builtins != static_shell_builtins) - free (shell_builtins); - - /* The result is still sorted. */ - num_shell_builtins--; - shell_builtins = new_shell_builtins; -} - -/* Tenon's MachTen has a dlclose that doesn't return a value, so we - finesse it with a local wrapper. */ -static int -local_dlclose (handle) - void *handle; -{ -#if !defined (__MACHTEN__) - return (dlclose (handle)); -#else /* __MACHTEN__ */ - dlclose (handle); - return ((dlerror () != NULL) ? -1 : 0); -#endif /* __MACHTEN__ */ -} - -static int -dyn_unload_builtin (name) - char *name; -{ - struct builtin *b; - void *handle; - int ref, i; - - b = builtin_address_internal (name, 1); - if (b == 0) - { - sh_notbuiltin (name); - return (EXECUTION_FAILURE); - } - if (b->flags & STATIC_BUILTIN) - { - builtin_error (_("%s: not dynamically loaded"), name); - return (EXECUTION_FAILURE); - } - - handle = (void *)b->handle; - for (ref = i = 0; i < num_shell_builtins; i++) - { - if (shell_builtins[i].handle == b->handle) - ref++; - } - - /* Don't remove the shared object unless the reference count of builtins - using it drops to zero. */ - if (ref == 1 && local_dlclose (handle) != 0) - { - builtin_error (_("%s: cannot delete: %s"), name, dlerror ()); - return (EXECUTION_FAILURE); - } - - /* Now remove this entry from the builtin table and reinitialize. */ - delete_builtin (b); - - return (EXECUTION_SUCCESS); -} -#endif diff --git a/builtins/eval.def~ b/builtins/eval.def~ deleted file mode 100644 index 8892def2f..000000000 --- a/builtins/eval.def~ +++ /dev/null @@ -1,56 +0,0 @@ -This file is eval.def, from which is created eval.c. -It implements the builtin "eval" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 eval.c - -$BUILTIN eval -$FUNCTION eval_builtin -$SHORT_DOC eval [arg ...] -Execute arguments as a shell command. - -Combine ARGs into a single string, use the result as input to the shell, -and execute the resulting commands. -$END - -#include -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../shell.h" -#include "bashgetopt.h" -#include "common.h" - -/* Parse the string that these words make, and execute the command found. */ -int -eval_builtin (list) - WORD_LIST *list; -{ - if (no_options (list)) - return (EX_USAGE); - list = loptend; /* skip over possible `--' */ - - /* Note that parse_and_execute () frees the string it is passed. */ - return (list ? parse_and_execute (string_list (list), "eval", SEVAL_NOHIST) : EXECUTION_SUCCESS); -} diff --git a/builtins/evalfile.c~ b/builtins/evalfile.c~ deleted file mode 100644 index a78235b14..000000000 --- a/builtins/evalfile.c~ +++ /dev/null @@ -1,329 +0,0 @@ -/* Copyright (C) 1996-2006 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "../bashtypes.h" -#include "posixstat.h" -#include "filecntl.h" - -#include -#include -#include - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../jobs.h" -#include "../builtins.h" -#include "../flags.h" -#include "../input.h" -#include "../execute_cmd.h" -#include "../trap.h" - -#if defined (HISTORY) -# include "../bashhist.h" -#endif - -#include - -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif - -/* Flags for _evalfile() */ -#define FEVAL_ENOENTOK 0x001 -#define FEVAL_BUILTIN 0x002 -#define FEVAL_UNWINDPROT 0x004 -#define FEVAL_NONINT 0x008 -#define FEVAL_LONGJMP 0x010 -#define FEVAL_HISTORY 0x020 -#define FEVAL_CHECKBINARY 0x040 -#define FEVAL_REGFILE 0x080 -#define FEVAL_NOPUSHARGS 0x100 - -extern int posixly_correct; -extern int indirection_level, subshell_environment; -extern int return_catch_flag, return_catch_value; -extern int last_command_exit_value; - -/* How many `levels' of sourced files we have. */ -int sourcelevel = 0; - -static int -_evalfile (filename, flags) - const char *filename; - int flags; -{ - volatile int old_interactive; - procenv_t old_return_catch; - int return_val, fd, result, pflags; - ssize_t nr; /* return value from read(2) */ - char *string; - struct stat finfo; - size_t file_size; - sh_vmsg_func_t *errfunc; -#if defined (ARRAY_VARS) - SHELL_VAR *funcname_v, *nfv, *bash_source_v, *bash_lineno_v; - ARRAY *funcname_a, *bash_source_a, *bash_lineno_a; -# if defined (DEBUGGER) - SHELL_VAR *bash_argv_v, *bash_argc_v; - ARRAY *bash_argv_a, *bash_argc_a; -# endif - char *t, tt[2]; -#endif - - USE_VAR(pflags); - -#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); -# if defined (DEBUGGER) - GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a); - GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a); -# endif -#endif - - fd = open (filename, O_RDONLY); - - if (fd < 0 || (fstat (fd, &finfo) == -1)) - { -file_error_and_exit: - if (((flags & FEVAL_ENOENTOK) == 0) || errno != ENOENT) - file_error (filename); - - if (flags & FEVAL_LONGJMP) - { - last_command_exit_value = 1; - jump_to_top_level (EXITPROG); - } - - return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE - : ((errno == ENOENT) ? 0 : -1)); - } - - errfunc = ((flags & FEVAL_BUILTIN) ? builtin_error : internal_error); - - if (S_ISDIR (finfo.st_mode)) - { - (*errfunc) (_("%s: is a directory"), filename); - return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); - } - else if ((flags & FEVAL_REGFILE) && S_ISREG (finfo.st_mode) == 0) - { - (*errfunc) (_("%s: not a regular file"), filename); - return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); - } - - file_size = (size_t)finfo.st_size; - /* Check for overflow with large files. */ - if (file_size != finfo.st_size || file_size + 1 < file_size) - { - (*errfunc) (_("%s: file is too large"), filename); - return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); - } - -#if defined (__CYGWIN__) && defined (O_TEXT) - setmode (fd, O_TEXT); -#endif - - if (S_ISREG (finfo.st_mode) && file_size <= SSIZE_MAX) - { - string = (char *)xmalloc (1 + file_size); - nr = read (fd, string, file_size); - if (nr >= 0) - string[nr] = '\0'; - } - else - nr = zmapfd (fd, &string, 0); - - return_val = errno; - close (fd); - errno = return_val; - - if (nr < 0) /* XXX was != file_size, not < 0 */ - { - free (string); - goto file_error_and_exit; - } - - if (result == 0) - { - free (string); - return ((flags & FEVAL_BUILTIN) ? EXECUTION_SUCCESS : 1); - } - - if ((flags & FEVAL_CHECKBINARY) && - check_binary_file (string, (result > 80) ? 80 : result)) - { - free (string); - (*errfunc) (_("%s: cannot execute binary file"), filename); - return ((flags & FEVAL_BUILTIN) ? EX_BINARY_FILE : -1); - } - - if (flags & FEVAL_UNWINDPROT) - { - begin_unwind_frame ("_evalfile"); - - unwind_protect_int (return_catch_flag); - unwind_protect_jmp_buf (return_catch); - if (flags & FEVAL_NONINT) - unwind_protect_int (interactive); - unwind_protect_int (sourcelevel); - } - else - { - COPY_PROCENV (return_catch, old_return_catch); - if (flags & FEVAL_NONINT) - old_interactive = interactive; - } - - if (flags & FEVAL_NONINT) - interactive = 0; - - return_catch_flag++; - sourcelevel++; - -#if defined (ARRAY_VARS) - array_push (bash_source_a, (char *)filename); - t = itos (executing_line_number ()); - array_push (bash_lineno_a, t); - free (t); - array_push (funcname_a, "source"); /* not exactly right */ -# if defined (DEBUGGER) - /* Have to figure out a better way to do this when `source' is supplied - arguments */ - if ((flags & FEVAL_NOPUSHARGS) == 0) - { - array_push (bash_argv_a, (char *)filename); - tt[0] = '1'; tt[1] = '\0'; - array_push (bash_argc_a, tt); - } -# endif -#endif - - /* set the flags to be passed to parse_and_execute */ - pflags = SEVAL_RESETLINE; - pflags |= (flags & FEVAL_HISTORY) ? 0 : SEVAL_NOHIST; - - if (flags & FEVAL_BUILTIN) - result = EXECUTION_SUCCESS; - - return_val = setjmp (return_catch); - - /* If `return' was seen outside of a function, but in the script, then - force parse_and_execute () to clean up. */ - if (return_val) - { - parse_and_execute_cleanup (); - result = return_catch_value; - } - else - result = parse_and_execute (string, filename, pflags); - - if (flags & FEVAL_UNWINDPROT) - run_unwind_frame ("_evalfile"); - else - { - if (flags & FEVAL_NONINT) - interactive = old_interactive; - return_catch_flag--; - sourcelevel--; - COPY_PROCENV (old_return_catch, return_catch); - } - -#if defined (ARRAY_VARS) - /* These two variables cannot be unset, and cannot be affected by the - sourced file. */ - array_pop (bash_source_a); - array_pop (bash_lineno_a); - - /* FUNCNAME can be unset, and so can potentially be changed by the - sourced file. */ - GET_ARRAY_FROM_VAR ("FUNCNAME", nfv, funcname_a); - if (nfv == funcname_v) - array_pop (funcname_a); -# if defined (DEBUGGER) - if ((flags & FEVAL_NOPUSHARGS) == 0) - { - array_pop (bash_argc_a); - array_pop (bash_argv_a); - } -# endif -#endif - - return ((flags & FEVAL_BUILTIN) ? result : 1); -} - -int -maybe_execute_file (fname, force_noninteractive) - const char *fname; - int force_noninteractive; -{ - char *filename; - int result, flags; - - filename = bash_tilde_expand (fname, 0); - flags = FEVAL_ENOENTOK; - if (force_noninteractive) - flags |= FEVAL_NONINT; - result = _evalfile (filename, flags); - free (filename); - return result; -} - -#if defined (HISTORY) -int -fc_execute_file (filename) - const char *filename; -{ - int flags; - - /* We want these commands to show up in the history list if - remember_on_history is set. */ - flags = FEVAL_ENOENTOK|FEVAL_HISTORY|FEVAL_REGFILE; - return (_evalfile (filename, flags)); -} -#endif /* HISTORY */ - -int -source_file (filename, sflags) - const char *filename; - int sflags; -{ - int flags, rval; - - flags = FEVAL_BUILTIN|FEVAL_UNWINDPROT|FEVAL_NONINT; - if (sflags) - flags |= FEVAL_NOPUSHARGS; - /* POSIX shells exit if non-interactive and file error. */ - if (posixly_correct && !interactive_shell) - flags |= FEVAL_LONGJMP; - rval = _evalfile (filename, flags); - - run_return_trap (); - return rval; -} diff --git a/builtins/evalstring.c~ b/builtins/evalstring.c~ deleted file mode 100644 index 419f1432e..000000000 --- a/builtins/evalstring.c~ +++ /dev/null @@ -1,486 +0,0 @@ -/* evalstring.c - evaluate a string as one or more shell commands. - -/* Copyright (C) 1996-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include - -#include - -#include "filecntl.h" -#include "../bashansi.h" - -#include "../shell.h" -#include "../jobs.h" -#include "../builtins.h" -#include "../flags.h" -#include "../input.h" -#include "../execute_cmd.h" -#include "../redir.h" -#include "../trap.h" - -#include - -#if defined (HISTORY) -# include "../bashhist.h" -#endif - -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif - -#define IS_BUILTIN(s) (builtin_address_internal(s, 0) != (struct builtin *)NULL) - -extern int indirection_level, subshell_environment; -extern int line_number; -extern int current_token, shell_eof_token; -extern int last_command_exit_value; -extern int running_trap; -extern int loop_level; -extern int executing_list; -extern int posixly_correct; - -int parse_and_execute_level = 0; - -static int cat_file __P((REDIRECT *)); - -#define PE_TAG "parse_and_execute top" -#define PS_TAG "parse_string top" - -#if defined (HISTORY) -static void -set_history_remembering () -{ - remember_on_history = enable_history_list; -} -#endif - -/* How to force parse_and_execute () to clean up after itself. */ -void -parse_and_execute_cleanup () -{ - if (running_trap) - { - run_trap_cleanup (running_trap - 1); - unfreeze_jobs_list (); - } - run_unwind_frame (PE_TAG); -} - -static void -parse_prologue (string, flags, tag) - char *string; - int flags; - char *tag; -{ - char *orig_string; - int x; - - orig_string = string; - /* Unwind protect this invocation of parse_and_execute (). */ - begin_unwind_frame (tag); - unwind_protect_int (parse_and_execute_level); - unwind_protect_jmp_buf (top_level); - unwind_protect_int (indirection_level); - unwind_protect_int (line_number); - unwind_protect_int (loop_level); - unwind_protect_int (executing_list); - if (flags & (SEVAL_NONINT|SEVAL_INTERACT)) - unwind_protect_int (interactive); - -#if defined (HISTORY) - if (parse_and_execute_level == 0) - add_unwind_protect (set_history_remembering, (char *)NULL); - else - unwind_protect_int (remember_on_history); /* can be used in scripts */ -# if defined (BANG_HISTORY) - if (interactive_shell) - unwind_protect_int (history_expansion_inhibited); -# endif /* BANG_HISTORY */ -#endif /* HISTORY */ - - if (interactive_shell) - { - x = get_current_prompt_level (); - add_unwind_protect (set_current_prompt_level, x); - } - - add_unwind_protect (pop_stream, (char *)NULL); - if (orig_string && ((flags & SEVAL_NOFREE) == 0)) - add_unwind_protect (xfree, orig_string); - end_unwind_frame (); - - if (flags & (SEVAL_NONINT|SEVAL_INTERACT)) - interactive = (flags & SEVAL_NONINT) ? 0 : 1; - -#if defined (HISTORY) - if (flags & SEVAL_NOHIST) - bash_history_disable (); -#endif /* HISTORY */ -} - -/* Parse and execute the commands in STRING. Returns whatever - execute_command () returns. This frees STRING. FLAGS is a - flags word; look in common.h for the possible values. Actions - are: - (flags & SEVAL_NONINT) -> interactive = 0; - (flags & SEVAL_INTERACT) -> interactive = 1; - (flags & SEVAL_NOHIST) -> call bash_history_disable () - (flags & SEVAL_NOFREE) -> don't free STRING when finished - (flags & SEVAL_RESETLINE) -> reset line_number to 1 -*/ - -int -parse_and_execute (string, from_file, flags) - char *string; - const char *from_file; - int flags; -{ - int code, lreset; - volatile int should_jump_to_top_level, last_result; - COMMAND *volatile command; - - parse_prologue (string, flags, PE_TAG); - - parse_and_execute_level++; - - lreset = flags & SEVAL_RESETLINE; - - /* Reset the line number if the caller wants us to. If we don't reset the - line number, we have to subtract one, because we will add one just - before executing the next command (resetting the line number sets it to - 0; the first line number is 1). */ - push_stream (lreset); - if (lreset == 0) - line_number--; - - indirection_level++; - - code = should_jump_to_top_level = 0; - last_result = EXECUTION_SUCCESS; - - with_input_from_string (string, from_file); - while (*(bash_input.location.string)) - { - command = (COMMAND *)NULL; - - if (interrupt_state) - { - last_result = EXECUTION_FAILURE; - break; - } - - /* Provide a location for functions which `longjmp (top_level)' to - jump to. This prevents errors in substitution from restarting - the reader loop directly, for example. */ - code = setjmp (top_level); - - if (code) - { - should_jump_to_top_level = 0; - switch (code) - { - case FORCE_EOF: - case ERREXIT: - case EXITPROG: - if (command) - run_unwind_frame ("pe_dispose"); - /* Remember to call longjmp (top_level) after the old - value for it is restored. */ - should_jump_to_top_level = 1; - goto out; - - case DISCARD: - if (command) - run_unwind_frame ("pe_dispose"); - last_result = last_command_exit_value = EXECUTION_FAILURE; /* XXX */ - if (subshell_environment) - { - should_jump_to_top_level = 1; - goto out; - } - else - { -#if 0 - dispose_command (command); /* pe_dispose does this */ -#endif - continue; - } - - default: - command_error ("parse_and_execute", CMDERR_BADJUMP, code, 0); - break; - } - } - - if (parse_command () == 0) - { - if ((flags & SEVAL_PARSEONLY) || (interactive_shell == 0 && read_but_dont_execute)) - { - last_result = EXECUTION_SUCCESS; - dispose_command (global_command); - global_command = (COMMAND *)NULL; - } - else if (command = global_command) - { - struct fd_bitmap *bitmap; - - bitmap = new_fd_bitmap (FD_BITMAP_SIZE); - begin_unwind_frame ("pe_dispose"); - add_unwind_protect (dispose_fd_bitmap, bitmap); - add_unwind_protect (dispose_command, command); /* XXX */ - - global_command = (COMMAND *)NULL; - -#if defined (ONESHOT) - /* - * IF - * we were invoked as `bash -c' (startup_state == 2) AND - * parse_and_execute has not been called recursively AND - * we're not running a trap AND - * we have parsed the full command (string == '\0') AND - * we have a simple command without redirections AND - * the command is not being timed AND - * the command's return status is not being inverted - * THEN - * tell the execution code that we don't need to fork - */ - if (startup_state == 2 && parse_and_execute_level == 1 && - running_trap == 0 && - *bash_input.location.string == '\0' && - command->type == cm_simple && - signal_is_trapped (EXIT_TRAP) == 0 && - command->redirects == 0 && command->value.Simple->redirects == 0 && - ((command->flags & CMD_TIME_PIPELINE) == 0) && - ((command->flags & CMD_INVERT_RETURN) == 0)) - { - command->flags |= CMD_NO_FORK; - command->value.Simple->flags |= CMD_NO_FORK; - } -#endif /* ONESHOT */ - - /* See if this is a candidate for $( type == cm_simple && !command->redirects && - (command->flags & CMD_TIME_PIPELINE) == 0 && - command->value.Simple->words == 0 && - command->value.Simple->redirects && - command->value.Simple->redirects->next == 0 && - command->value.Simple->redirects->instruction == r_input_direction) - { - int r; - r = cat_file (command->value.Simple->redirects); - last_result = (r < 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS; - } - else - last_result = execute_command_internal - (command, 0, NO_PIPE, NO_PIPE, bitmap); - - dispose_command (command); - dispose_fd_bitmap (bitmap); - discard_unwind_frame ("pe_dispose"); - } - } - else - { - last_result = EXECUTION_FAILURE; - - /* Since we are shell compatible, syntax errors in a script - abort the execution of the script. Right? */ - break; - } - } - - out: - - run_unwind_frame (PE_TAG); - - if (interrupt_state && parse_and_execute_level == 0) - { - /* An interrupt during non-interactive execution in an - interactive shell (e.g. via $PROMPT_COMMAND) should - not cause the shell to exit. */ - interactive = interactive_shell; - throw_to_top_level (); - } - - if (should_jump_to_top_level) - jump_to_top_level (code); - - return (last_result); -} - -/* Parse a command contained in STRING according to FLAGS and return the - number of characters consumed from the string. If non-NULL, set *ENDP - to the position in the string where the parse ended. Used to validate - command substitutions during parsing to obey Posix rules about finding - the end of the command and balancing parens. */ -int -parse_string (string, from_file, flags, endp) - char *string; - const char *from_file; - int flags; - char **endp; -{ - int code, nc; - volatile int should_jump_to_top_level; - COMMAND *volatile command, *oglobal; - char *ostring; - - parse_prologue (string, flags, PS_TAG); - - /* Reset the line number if the caller wants us to. If we don't reset the - line number, we have to subtract one, because we will add one just - before executing the next command (resetting the line number sets it to - 0; the first line number is 1). */ - push_stream (0); - - code = should_jump_to_top_level = 0; - oglobal = global_command; - ostring = string; - - with_input_from_string (string, from_file); - while (*(bash_input.location.string)) - { - command = (COMMAND *)NULL; - -#if 0 - if (interrupt_state) - break; -#endif - - /* Provide a location for functions which `longjmp (top_level)' to - jump to. */ - code = setjmp (top_level); - - if (code) - { -#if defined (DEBUG) -itrace("parse_string: longjmp executed: code = %d", code); -#endif - should_jump_to_top_level = 0; - switch (code) - { - case FORCE_EOF: - case ERREXIT: - case EXITPROG: - case DISCARD: /* XXX */ - if (command) - dispose_command (command); - /* Remember to call longjmp (top_level) after the old - value for it is restored. */ - should_jump_to_top_level = 1; - goto out; - - default: - command_error ("parse_string", CMDERR_BADJUMP, code, 0); - break; - } - } - - if (parse_command () == 0) - { - dispose_command (global_command); - global_command = (COMMAND *)NULL; - } - else - { - if ((flags & SEVAL_NOLONGJMP) == 0) - { - should_jump_to_top_level = 1; - code = DISCARD; - } - else - reset_parser (); /* XXX - sets token_to_read */ - break; - } - - if (current_token == yacc_EOF || current_token == shell_eof_token) - break; - } - - out: - - global_command = oglobal; - nc = bash_input.location.string - ostring; - if (endp) - *endp = bash_input.location.string; - - run_unwind_frame (PS_TAG); - - if (should_jump_to_top_level) - jump_to_top_level (code); - - return (nc); -} - -/* Handle a $( < file ) command substitution. This expands the filename, - returning errors as appropriate, then just cats the file to the standard - output. */ -static int -cat_file (r) - REDIRECT *r; -{ - char *fn; - int fd, rval; - - if (r->instruction != r_input_direction) - return -1; - - /* Get the filename. */ - if (posixly_correct && !interactive_shell) - disallow_filename_globbing++; - fn = redirection_expand (r->redirectee.filename); - if (posixly_correct && !interactive_shell) - disallow_filename_globbing--; - - if (fn == 0) - { - redirection_error (r, AMBIGUOUS_REDIRECT); - return -1; - } - - fd = open(fn, O_RDONLY); - if (fd < 0) - { - file_error (fn); - free (fn); - return -1; - } - - rval = zcatfd (fd, 1, fn); - - free (fn); - close (fd); - - return (rval); -} diff --git a/builtins/exec.def~ b/builtins/exec.def~ deleted file mode 100644 index b87b7ad53..000000000 --- a/builtins/exec.def~ +++ /dev/null @@ -1,234 +0,0 @@ -This file is exec.def, from which is created exec.c. -It implements the builtin "exec" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 exec.c - -$BUILTIN exec -$FUNCTION exec_builtin -$SHORT_DOC exec [-cl] [-a name] [command [arguments ...]] [redirection ...] -Replace the shell with the given command. - -Execute COMMAND, replacing this shell with the specified program. -ARGUMENTS become the arguments to COMMAND. If COMMAND is not specified, -any redirections take effect in the current shell. - -Options: - -a name pass NAME as the zeroth argument to COMMAND - -c execute COMMAND with an empty environment - -l place a dash in the zeroth argument to COMMAND - -If the command cannot be executed, a non-interactive shell exits, unless -the shell option `execfail' is set. -$END - -#include - -#include "../bashtypes.h" -#include "posixstat.h" -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../execute_cmd.h" -#include "../findcmd.h" -#if defined (JOB_CONTROL) -# include "../jobs.h" -#endif -#include "../flags.h" -#include "../trap.h" -#if defined (HISTORY) -# include "../bashhist.h" -#endif -#include "common.h" -#include "bashgetopt.h" - -/* Not all systems declare ERRNO in errno.h... and some systems #define it! */ -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int subshell_environment; -extern REDIRECT *redirection_undo_list; - -int no_exit_on_failed_exec; - -/* If the user wants this to look like a login shell, then - prepend a `-' onto NAME and return the new name. */ -static char * -mkdashname (name) - char *name; -{ - char *ret; - - ret = (char *)xmalloc (2 + strlen (name)); - ret[0] = '-'; - strcpy (ret + 1, name); - return ret; -} - -int -exec_builtin (list) - WORD_LIST *list; -{ - int exit_value = EXECUTION_FAILURE; - int cleanenv, login, opt; - char *argv0, *command, **args, **env, *newname, *com2; - - cleanenv = login = 0; - argv0 = (char *)NULL; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "cla:")) != -1) - { - switch (opt) - { - case 'c': - cleanenv = 1; - break; - case 'l': - login = 1; - break; - case 'a': - argv0 = list_optarg; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - /* First, let the redirections remain. */ - dispose_redirects (redirection_undo_list); - redirection_undo_list = (REDIRECT *)NULL; - - if (list == 0) - return (EXECUTION_SUCCESS); - -#if defined (RESTRICTED_SHELL) - if (restricted) - { - sh_restricted ((char *)NULL); - return (EXECUTION_FAILURE); - } -#endif /* RESTRICTED_SHELL */ - - args = strvec_from_word_list (list, 1, 0, (int *)NULL); - - /* A command with a slash anywhere in its name is not looked up in $PATH. */ - command = absolute_program (args[0]) ? args[0] : search_for_command (args[0]); - - if (command == 0) - { - sh_notfound (args[0]); - exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */ - goto failed_exec; - } - - com2 = full_pathname (command); - if (com2) - { - if (command != args[0]) - free (command); - command = com2; - } - - if (argv0) - { - free (args[0]); - args[0] = login ? mkdashname (argv0) : savestring (argv0); - } - else if (login) - { - newname = mkdashname (args[0]); - free (args[0]); - args[0] = newname; - } - - /* Decrement SHLVL by 1 so a new shell started here has the same value, - preserving the appearance. After we do that, we need to change the - exported environment to include the new value. */ - if (cleanenv == 0) - adjust_shell_level (-1); - - if (cleanenv) - env = (char **)NULL; - else - { - maybe_make_export_env (); - env = export_env; - } - -#if defined (HISTORY) - if (interactive_shell && subshell_environment == 0) - maybe_save_shell_history (); -#endif /* HISTORY */ - - restore_original_signals (); - -#if defined (JOB_CONTROL) - if (subshell_environment == 0) - end_job_control (); -#endif /* JOB_CONTROL */ - - shell_execve (command, args, env); - - /* We have to set this to NULL because shell_execve has called realloc() - to stuff more items at the front of the array, which may have caused - the memory to be freed by realloc(). We don't want to free it twice. */ - args = (char **)NULL; - if (cleanenv == 0) - adjust_shell_level (1); - - if (executable_file (command) == 0) - { - builtin_error (_("%s: cannot execute: %s"), command, strerror (errno)); - exit_value = EX_NOEXEC; /* As per Posix.2, 3.14.6 */ - } - else - file_error (command); - -failed_exec: - FREE (command); - - if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0)) - exit_shell (exit_value); - - if (args) - strvec_dispose (args); - - initialize_traps (); - initialize_signals (1); - -#if defined (JOB_CONTROL) - if (interactive_shell || job_control) - restart_job_control (); -#endif /* JOB_CONTROL */ - - return (exit_value); -} diff --git a/builtins/exit.def~ b/builtins/exit.def~ deleted file mode 100644 index c42915c58..000000000 --- a/builtins/exit.def~ +++ /dev/null @@ -1,169 +0,0 @@ -This file is exit.def, from which is created exit.c. -It implements the builtins "exit", and "logout" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 exit.c - -$BUILTIN exit -$FUNCTION exit_builtin -$SHORT_DOC exit [n] -Exit the shell. - -Exits the shell with a status of N. If N is omitted, the exit status -is that of the last command executed. -$END - -#include - -#include "../bashtypes.h" -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "../bashintl.h" - -#include "../shell.h" -#include "../jobs.h" - -#include "common.h" -#include "builtext.h" /* for jobs_builtin */ - -extern int check_jobs_at_exit; -extern int last_command_exit_value; -extern int running_trap, trap_saved_exit_value; -extern int subshell_environment; -extern sh_builtin_func_t *this_shell_builtin; -extern sh_builtin_func_t *last_shell_builtin; - -static int exit_or_logout __P((WORD_LIST *)); -static int sourced_logout; - -int -exit_builtin (list) - WORD_LIST *list; -{ - if (interactive) - { - fprintf (stderr, login_shell ? _("logout\n") : "exit\n"); - fflush (stderr); - } - - return (exit_or_logout (list)); -} - -$BUILTIN logout -$FUNCTION logout_builtin -$SHORT_DOC logout [n] -Exit a login shell. - -Exits a login shell with exit status N. Returns an error if not executed -in a login shell. -$END - -/* How to logout. */ -int -logout_builtin (list) - WORD_LIST *list; -{ - if (login_shell == 0 /* && interactive */) - { - builtin_error (_("not login shell: use `exit'")); - return (EXECUTION_FAILURE); - } - else - return (exit_or_logout (list)); -} - -static int -exit_or_logout (list) - WORD_LIST *list; -{ - int exit_value; - -#if defined (JOB_CONTROL) - int exit_immediate_okay, stopmsg; - - exit_immediate_okay = (interactive == 0 || - last_shell_builtin == exit_builtin || - last_shell_builtin == logout_builtin || - last_shell_builtin == jobs_builtin); - - /* Check for stopped jobs if the user wants to. */ - if (exit_immediate_okay == 0) - { - register int i; - for (i = stopmsg = 0; i < js.j_jobslots; i++) - if (jobs[i] && STOPPED (i)) - stopmsg = JSTOPPED; - else if (check_jobs_at_exit && stopmsg == 0 && RUNNING (i)) - stopmsg = JRUNNING; - - if (stopmsg == JSTOPPED) - fprintf (stderr, _("There are stopped jobs.\n")); - else if (stopmsg == JRUNNING) - fprintf (stderr, _("There are running jobs.\n")); - - if (stopmsg && check_jobs_at_exit) - list_all_jobs (JLIST_STANDARD); - - if (stopmsg) - { - /* This is NOT superfluous because EOF can get here without - going through the command parser. Set both last and this - so that either `exit', `logout', or ^D will work to exit - immediately if nothing intervenes. */ - this_shell_builtin = last_shell_builtin = exit_builtin; - return (EXECUTION_FAILURE); - } - } -#endif /* JOB_CONTROL */ - - /* Get return value if present. This means that you can type - `logout 5' to a shell, and it returns 5. */ - - /* If we're running the exit trap (running_trap == 1, since running_trap - gets set to SIG+1), and we don't have a argument given to `exit' - (list == 0), use the exit status we saved before running the trap - commands (trap_saved_exit_value). */ - exit_value = (running_trap == 1 && list == 0) ? trap_saved_exit_value : get_exitstat (list); - - bash_logout (); - - last_command_exit_value = exit_value; - - /* Exit the program. */ - jump_to_top_level (EXITPROG); - /*NOTREACHED*/ -} - -void -bash_logout () -{ - /* Run our `~/.bash_logout' file if it exists, and this is a login shell. */ - if (login_shell && sourced_logout++ == 0 && subshell_environment == 0) - { - maybe_execute_file ("~/.bash_logout", 1); -#ifdef SYS_BASH_LOGOUT - maybe_execute_file (SYS_BASH_LOGOUT, 1); -#endif - } -} diff --git a/builtins/fc.def~ b/builtins/fc.def~ deleted file mode 100644 index 32cd57acb..000000000 --- a/builtins/fc.def~ +++ /dev/null @@ -1,654 +0,0 @@ -This file is fc.def, from which is created fc.c. -It implements the builtin "fc" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 fc.c - -$BUILTIN fc -$FUNCTION fc_builtin -$DEPENDS_ON HISTORY -$SHORT_DOC fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command] -Display or execute commands from the history list. - -fc is used to list or edit and re-execute commands from the history list. -FIRST and LAST can be numbers specifying the range, or FIRST can be a -string, which means the most recent command beginning with that -string. - -Options: - -e ENAME select which editor to use. Default is FCEDIT, then EDITOR, - then vi - -l list lines instead of editing - -n omit line numbers when listing - -r reverse the order of the lines (newest listed first) - -With the `fc -s [pat=rep ...] [command]' format, COMMAND is -re-executed after the substitution OLD=NEW is performed. - -A useful alias to use with this is r='fc -s', so that typing `r cc' -runs the last command beginning with `cc' and typing `r' re-executes -the last command. - -Exit Status: -Returns success or status of executed command; non-zero if an error occurs. -$END - -#include - -#if defined (HISTORY) -#ifndef _MINIX -# include -#endif -#include "../bashtypes.h" -#include "posixstat.h" -#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include - -#include "../bashansi.h" -#include "../bashintl.h" -#include - -#include "../shell.h" -#include "../builtins.h" -#include "../flags.h" -#include "../bashhist.h" -#include "maxpath.h" -#include -#include "bashgetopt.h" -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int current_command_line_count; -extern int literal_history; -extern int posixly_correct; - -extern int unlink __P((const char *)); - -extern FILE *sh_mktmpfp __P((char *, int, char **)); -extern int delete_last_history __P((void)); - -/* **************************************************************** */ -/* */ -/* The K*rn shell style fc command (Fix Command) */ -/* */ -/* **************************************************************** */ - -/* fc builtin command (fix command) for Bash for those who - like K*rn-style history better than csh-style. - - fc [-e ename] [-nlr] [first] [last] - - FIRST and LAST can be numbers specifying the range, or FIRST can be - a string, which means the most recent command beginning with that - string. - - -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR, - then the editor which corresponds to the current readline editing - mode, then vi. - - -l means list lines instead of editing. - -n means no line numbers listed. - -r means reverse the order of the lines (making it newest listed first). - - fc -e - [pat=rep ...] [command] - fc -s [pat=rep ...] [command] - - Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's. -*/ - -/* Data structure describing a list of global replacements to perform. */ -typedef struct repl { - struct repl *next; - char *pat; - char *rep; -} REPL; - -/* Accessors for HIST_ENTRY lists that are called HLIST. */ -#define histline(i) (hlist[(i)]->line) -#define histdata(i) (hlist[(i)]->data) - -#define FREE_RLIST() \ - do { \ - for (rl = rlist; rl; ) { \ - REPL *r; \ - r = rl->next; \ - if (rl->pat) \ - free (rl->pat); \ - if (rl->rep) \ - free (rl->rep); \ - free (rl); \ - rl = r; \ - } \ - } while (0) - -static char *fc_dosubs __P((char *, REPL *)); -static char *fc_gethist __P((char *, HIST_ENTRY **)); -static int fc_gethnum __P((char *, HIST_ENTRY **)); -static int fc_number __P((WORD_LIST *)); -static void fc_replhist __P((char *)); -#ifdef INCLUDE_UNUSED -static char *fc_readline __P((FILE *)); -static void fc_addhist __P((char *)); -#endif - -/* String to execute on a file that we want to edit. */ -#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}" -#if defined (STRICT_POSIX) -# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}" -#else -# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}" -#endif - -int -fc_builtin (list) - WORD_LIST *list; -{ - register int i; - register char *sep; - int numbering, reverse, listing, execute; - int histbeg, histend, last_hist, retval, opt; - FILE *stream; - REPL *rlist, *rl; - char *ename, *command, *newcom, *fcedit; - HIST_ENTRY **hlist; - char *fn; - - numbering = 1; - reverse = listing = execute = 0; - ename = (char *)NULL; - - /* Parse out the options and set which of the two forms we're in. */ - reset_internal_getopt (); - lcurrent = list; /* XXX */ - while (fc_number (loptend = lcurrent) == 0 && - (opt = internal_getopt (list, ":e:lnrs")) != -1) - { - switch (opt) - { - case 'n': - numbering = 0; - break; - - case 'l': - listing = 1; - break; - - case 'r': - reverse = 1; - break; - - case 's': - execute = 1; - break; - - case 'e': - ename = list_optarg; - break; - - default: - builtin_usage (); - return (EX_USAGE); - } - } - - list = loptend; - - if (ename && (*ename == '-') && (ename[1] == '\0')) - execute = 1; - - /* The "execute" form of the command (re-run, with possible string - substitutions). */ - if (execute) - { - rlist = (REPL *)NULL; - while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL)) - { - *sep++ = '\0'; - rl = (REPL *)xmalloc (sizeof (REPL)); - rl->next = (REPL *)NULL; - rl->pat = savestring (list->word->word); - rl->rep = savestring (sep); - - if (rlist == NULL) - rlist = rl; - else - { - rl->next = rlist; - rlist = rl; - } - list = list->next; - } - - /* If we have a list of substitutions to do, then reverse it - to get the replacements in the proper order. */ - - rlist = REVERSE_LIST (rlist, REPL *); - - hlist = history_list (); - - /* If we still have something in list, it is a command spec. - Otherwise, we use the most recent command in time. */ - command = fc_gethist (list ? list->word->word : (char *)NULL, hlist); - - if (command == NULL) - { - builtin_error (_("no command found")); - if (rlist) - FREE_RLIST (); - - return (EXECUTION_FAILURE); - } - - if (rlist) - { - newcom = fc_dosubs (command, rlist); - free (command); - FREE_RLIST (); - command = newcom; - } - - fprintf (stderr, "%s\n", command); - fc_replhist (command); /* replace `fc -s' with command */ - return (parse_and_execute (command, "fc", SEVAL_NOHIST)); - } - - /* This is the second form of the command (the list-or-edit-and-rerun - form). */ - hlist = history_list (); - if (hlist == 0) - return (EXECUTION_SUCCESS); - for (i = 0; hlist[i]; i++); - - /* With the Bash implementation of history, the current command line - ("fc blah..." and so on) is already part of the history list by - the time we get to this point. This just skips over that command - and makes the last command that this deals with be the last command - the user entered before the fc. We need to check whether the - line was actually added (HISTIGNORE may have caused it to not be), - so we check hist_last_line_added. */ - - last_hist = i - remember_on_history - hist_last_line_added; - - if (list) - { - histbeg = fc_gethnum (list->word->word, hlist); - list = list->next; - - if (list) - histend = fc_gethnum (list->word->word, hlist); - else - histend = listing ? last_hist : histbeg; - } - else - { - /* The default for listing is the last 16 history items. */ - if (listing) - { - histend = last_hist; - histbeg = histend - 16 + 1; /* +1 because loop below uses >= */ - if (histbeg < 0) - histbeg = 0; - } - else - /* For editing, it is the last history command. */ - histbeg = histend = last_hist; - } - - /* "When not listing, the fc command that caused the editing shall not be - entered into the history list." */ - if (listing == 0 && hist_last_line_added) - { - delete_last_history (); - /* If we're editing a single command -- the last command in the - history -- and we just removed the dummy command added by - edit_and_execute_command (), we need to check whether or not we - just removed the last command in the history and need to back - the pointer up. remember_on_history is off because we're running - in parse_and_execute(). */ - if (histbeg == histend && histend == last_hist && hlist[last_hist] == 0) - last_hist = histbeg = --histend; - } - - /* We print error messages for line specifications out of range. */ - if ((histbeg < 0) || (histend < 0)) - { - sh_erange ((char *)NULL, _("history specification")); - return (EXECUTION_FAILURE); - } - - if (histend < histbeg) - { - i = histend; - histend = histbeg; - histbeg = i; - - reverse = 1; - } - - if (listing) - stream = stdout; - else - { - numbering = 0; - stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn); - if (stream == 0) - { - builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno)); - FREE (fn); - return (EXECUTION_FAILURE); - } - } - - for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++) - { - QUIT; - if (numbering) - fprintf (stream, "%d", i + history_base); - if (listing) - { - if (posixly_correct) - fputs ("\t", stream); - else - fprintf (stream, "\t%c", histdata (i) ? '*' : ' '); - } - fprintf (stream, "%s\n", histline (i)); - } - - if (listing) - return (sh_chkwrite (EXECUTION_SUCCESS)); - - fflush (stream); - if (ferror (stream)) - { - sh_wrerror (); - fclose (stream); - return (EXECUTION_FAILURE); - } - fclose (stream); - - /* Now edit the file of commands. */ - if (ename) - { - command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2); - sprintf (command, "%s %s", ename, fn); - } - else - { - fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND; - command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn)); - sprintf (command, "%s %s", fcedit, fn); - } - retval = parse_and_execute (command, "fc", SEVAL_NOHIST); - if (retval != EXECUTION_SUCCESS) - { - unlink (fn); - free (fn); - return (EXECUTION_FAILURE); - } - - /* Make sure parse_and_execute doesn't turn this off, even though a - call to parse_and_execute farther up the function call stack (e.g., - if this is called by vi_edit_and_execute_command) may have already - called bash_history_disable. */ - remember_on_history = 1; - - /* Turn on the `v' flag while fc_execute_file runs so the commands - will be echoed as they are read by the parser. */ - begin_unwind_frame ("fc builtin"); - add_unwind_protect ((Function *)xfree, fn); - add_unwind_protect (unlink, fn); - unwind_protect_int (echo_input_at_read); - echo_input_at_read = 1; - - retval = fc_execute_file (fn); - - run_unwind_frame ("fc builtin"); - - return (retval); -} - -/* Return 1 if LIST->word->word is a legal number for fc's use. */ -static int -fc_number (list) - WORD_LIST *list; -{ - char *s; - - if (list == 0) - return 0; - s = list->word->word; - if (*s == '-') - s++; - return (legal_number (s, (intmax_t *)NULL)); -} - -/* Return an absolute index into HLIST which corresponds to COMMAND. If - COMMAND is a number, then it was specified in relative terms. If it - is a string, then it is the start of a command line present in HLIST. */ -static int -fc_gethnum (command, hlist) - char *command; - HIST_ENTRY **hlist; -{ - int sign, n, clen; - register int i, j; - register char *s; - - sign = 1; - /* Count history elements. */ - for (i = 0; hlist[i]; i++); - - /* With the Bash implementation of history, the current command line - ("fc blah..." and so on) is already part of the history list by - the time we get to this point. This just skips over that command - and makes the last command that this deals with be the last command - the user entered before the fc. We need to check whether the - line was actually added (HISTIGNORE may have caused it to not be), - so we check hist_last_line_added. This needs to agree with the - calculation of last_hist in fc_builtin above. */ - i -= remember_on_history + hist_last_line_added; - - /* No specification defaults to most recent command. */ - if (command == NULL) - return (i); - - /* Otherwise, there is a specification. It can be a number relative to - the current position, or an absolute history number. */ - s = command; - - /* Handle possible leading minus sign. */ - if (s && (*s == '-')) - { - sign = -1; - s++; - } - - if (s && DIGIT(*s)) - { - n = atoi (s); - n *= sign; - - /* If the value is negative or zero, then it is an offset from - the current history item. */ - if (n < 0) - { - n += i + 1; - return (n < 0 ? 0 : n); - } - else if (n == 0) - return (i); - else - { - n -= history_base; - return (i < n ? i : n); - } - } - - clen = strlen (command); - for (j = i; j >= 0; j--) - { - if (STREQN (command, histline (j), clen)) - return (j); - } - return (-1); -} - -/* Locate the most recent history line which begins with - COMMAND in HLIST, and return a malloc()'ed copy of it. */ -static char * -fc_gethist (command, hlist) - char *command; - HIST_ENTRY **hlist; -{ - int i; - - if (hlist == 0) - return ((char *)NULL); - - i = fc_gethnum (command, hlist); - - if (i >= 0) - return (savestring (histline (i))); - else - return ((char *)NULL); -} - -#ifdef INCLUDE_UNUSED -/* Read the edited history lines from STREAM and return them - one at a time. This can read unlimited length lines. The - caller should free the storage. */ -static char * -fc_readline (stream) - FILE *stream; -{ - register int c; - int line_len = 0, lindex = 0; - char *line = (char *)NULL; - - while ((c = getc (stream)) != EOF) - { - if ((lindex + 2) >= line_len) - line = (char *)xrealloc (line, (line_len += 128)); - - if (c == '\n') - { - line[lindex++] = '\n'; - line[lindex++] = '\0'; - return (line); - } - else - line[lindex++] = c; - } - - if (!lindex) - { - if (line) - free (line); - - return ((char *)NULL); - } - - if (lindex + 2 >= line_len) - line = (char *)xrealloc (line, lindex + 3); - - line[lindex++] = '\n'; /* Finish with newline if none in file */ - line[lindex++] = '\0'; - return (line); -} -#endif - -/* Perform the SUBS on COMMAND. - SUBS is a list of substitutions, and COMMAND is a simple string. - Return a pointer to a malloc'ed string which contains the substituted - command. */ -static char * -fc_dosubs (command, subs) - char *command; - REPL *subs; -{ - register char *new, *t; - register REPL *r; - - for (new = savestring (command), r = subs; r; r = r->next) - { - t = strsub (new, r->pat, r->rep, 1); - free (new); - new = t; - } - return (new); -} - -/* Use `command' to replace the last entry in the history list, which, - by this time, is `fc blah...'. The intent is that the new command - become the history entry, and that `fc' should never appear in the - history list. This way you can do `r' to your heart's content. */ -static void -fc_replhist (command) - char *command; -{ - int n; - - if (command == 0 || *command == '\0') - return; - - n = strlen (command); - if (command[n - 1] == '\n') - command[n - 1] = '\0'; - - if (command && *command) - { - delete_last_history (); - maybe_add_history (command); /* Obeys HISTCONTROL setting. */ - } -} - -#ifdef INCLUDE_UNUSED -/* Add LINE to the history, after removing a single trailing newline. */ -static void -fc_addhist (line) - char *line; -{ - register int n; - - if (line == 0 || *line == 0) - return; - - n = strlen (line); - - if (line[n - 1] == '\n') - line[n - 1] = '\0'; - - if (line && *line) - maybe_add_history (line); /* Obeys HISTCONTROL setting. */ -} -#endif - -#endif /* HISTORY */ diff --git a/builtins/fg_bg.def~ b/builtins/fg_bg.def~ deleted file mode 100644 index 96b806542..000000000 --- a/builtins/fg_bg.def~ +++ /dev/null @@ -1,181 +0,0 @@ -This file is fg_bg.def, from which is created fg_bg.c. -It implements the builtins "bg" and "fg" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 fg_bg.c - -$BUILTIN fg -$FUNCTION fg_builtin -$DEPENDS_ON JOB_CONTROL -$SHORT_DOC fg [job_spec] -Move job to the foreground. - -Place the job identified by JOB_SPEC in the foreground, making it the -current job. If JOB_SPEC is not present, the shell's notion of the -current job is used. -$END - -#include - -#include "../bashtypes.h" -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "../bashintl.h" - -#include "../shell.h" -#include "../jobs.h" -#include "common.h" -#include "bashgetopt.h" - -#if defined (JOB_CONTROL) -extern char *this_command_name; - -static int fg_bg __P((WORD_LIST *, int)); - -/* How to bring a job into the foreground. */ -int -fg_builtin (list) - WORD_LIST *list; -{ - int fg_bit; - register WORD_LIST *t; - - if (job_control == 0) - { - sh_nojobs ((char *)NULL); - return (EXECUTION_FAILURE); - } - - if (no_options (list)) - return (EX_USAGE); - list = loptend; - - /* If the last arg on the line is '&', then start this job in the - background. Else, fg the job. */ - for (t = list; t && t->next; t = t->next) - ; - fg_bit = (t && t->word->word[0] == '&' && t->word->word[1] == '\0') == 0; - - return (fg_bg (list, fg_bit)); -} -#endif /* JOB_CONTROL */ - -$BUILTIN bg -$FUNCTION bg_builtin -$DEPENDS_ON JOB_CONTROL -$SHORT_DOC bg [job_spec ...] -Move jobs to the background. - -Place the jobs identified by each JOB_SPEC in the background, as if they -had been started with `&'. If JOB_SPEC is not present, the shell's notion -of the current job is used. -$END - -#if defined (JOB_CONTROL) -/* How to put a job into the background. */ -int -bg_builtin (list) - WORD_LIST *list; -{ - int r; - - if (job_control == 0) - { - sh_nojobs ((char *)NULL); - return (EXECUTION_FAILURE); - } - - if (no_options (list)) - return (EX_USAGE); - list = loptend; - - /* This relies on the fact that fg_bg() takes a WORD_LIST *, but only acts - on the first member (if any) of that list. */ - r = EXECUTION_SUCCESS; - do - { - if (fg_bg (list, 0) == EXECUTION_FAILURE) - r = EXECUTION_FAILURE; - if (list) - list = list->next; - } - while (list); - - return r; -} - -/* How to put a job into the foreground/background. */ -static int -fg_bg (list, foreground) - WORD_LIST *list; - int foreground; -{ - sigset_t set, oset; - int job, status, old_async_pid; - JOB *j; - - BLOCK_CHILD (set, oset); - job = get_job_spec (list); - - if (INVALID_JOB (job)) - { - if (job != DUP_JOB) - sh_badjob (list ? list->word->word : _("current")); - - goto failure; - } - - j = get_job_by_jid (job); - /* Or if j->pgrp == shell_pgrp. */ - if (IS_JOBCONTROL (job) == 0) - { - builtin_error (_("job %d started without job control"), job + 1); - goto failure; - } - - if (foreground == 0) - { - old_async_pid = last_asynchronous_pid; - last_asynchronous_pid = j->pgrp; /* As per Posix.2 5.4.2 */ - } - - status = start_job (job, foreground); - - if (status >= 0) - { - /* win: */ - UNBLOCK_CHILD (oset); - return (foreground ? status : EXECUTION_SUCCESS); - } - else - { - if (foreground == 0) - last_asynchronous_pid = old_async_pid; - - failure: - UNBLOCK_CHILD (oset); - return (EXECUTION_FAILURE); - } -} -#endif /* JOB_CONTROL */ diff --git a/builtins/getopts.def~ b/builtins/getopts.def~ deleted file mode 100644 index 8af649894..000000000 --- a/builtins/getopts.def~ +++ /dev/null @@ -1,326 +0,0 @@ -This file is getopts.def, from which is created getopts.c. -It implements the builtin "getopts" 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 getopts.c - -$BUILTIN getopts -$FUNCTION getopts_builtin -$SHORT_DOC getopts optstring name [arg] -Parse option arguments. - -Getopts is used by shell procedures to parse positional parameters -as options. - -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, 0); - 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, 0); - - /* 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) - { - unbind_variable ("OPTARG"); - 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, 0); - } - 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, 0); - } - else - { - ret = getopts_bind_variable (name, "?"); - unbind_variable ("OPTARG"); - } - return (ret); - } - - bind_variable ("OPTARG", sh_optarg, 0); - - 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/hash.def~ b/builtins/hash.def~ deleted file mode 100644 index dc71b1d0d..000000000 --- a/builtins/hash.def~ +++ /dev/null @@ -1,279 +0,0 @@ -This file is hash.def, from which is created hash.c. -It implements the builtin "hash" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 hash.c - -$BUILTIN hash -$FUNCTION hash_builtin -$SHORT_DOC hash [-lr] [-p pathname] [-dt] [name ...] -Remember or display program locations. - -Determine and remember the full pathname of each command NAME. If -no arguments are given, information about remembered commands is displayed. - -Options: - -d forget the remembered location of each NAME - -l display in a format that may be reused as input - -p pathname use PATHNAME is the full pathname of NAME - -r forget all remembered locations - -t print the remembered location of each NAME, preceding - each location with the corresponding NAME if multiple - NAMEs are given -Arguments: - NAME Each NAME is searched for in $PATH and added to the list - of remembered commands. -$END - -#include - -#include - -#include "../bashtypes.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../builtins.h" -#include "../flags.h" -#include "../findcmd.h" -#include "../hashcmd.h" -#include "common.h" -#include "bashgetopt.h" - -extern int posixly_correct; -extern int dot_found_in_search; -extern char *this_command_name; - -static int add_hashed_command __P((char *, int)); -static int print_hash_info __P((BUCKET_CONTENTS *)); -static int print_portable_hash_info __P((BUCKET_CONTENTS *)); -static int print_hashed_commands __P((int)); -static int list_hashed_filename_targets __P((WORD_LIST *, int)); - -/* Print statistics on the current state of hashed commands. If LIST is - not empty, then rehash (or hash in the first place) the specified - commands. */ -int -hash_builtin (list) - WORD_LIST *list; -{ - int expunge_hash_table, list_targets, list_portably, delete, opt; - char *w, *pathname; - - if (hashing_enabled == 0) - { - builtin_error (_("hashing disabled")); - return (EXECUTION_FAILURE); - } - - expunge_hash_table = list_targets = list_portably = delete = 0; - pathname = (char *)NULL; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "dlp:rt")) != -1) - { - switch (opt) - { - case 'd': - delete = 1; - break; - case 'l': - list_portably = 1; - break; - case 'p': - pathname = list_optarg; - break; - case 'r': - expunge_hash_table = 1; - break; - case 't': - list_targets = 1; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - /* hash -t requires at least one argument. */ - if (list == 0 && list_targets) - { - sh_needarg ("-t"); - return (EXECUTION_FAILURE); - } - - /* We want hash -r to be silent, but hash -- to print hashing info, so - we test expunge_hash_table. */ - if (list == 0 && expunge_hash_table == 0) - { - opt = print_hashed_commands (list_portably); - if (opt == 0 && posixly_correct == 0) - printf (_("%s: hash table empty\n"), this_command_name); - - return (EXECUTION_SUCCESS); - } - - if (expunge_hash_table) - phash_flush (); - - /* If someone runs `hash -r -t xyz' he will be disappointed. */ - if (list_targets) - return (list_hashed_filename_targets (list, list_portably)); - -#if defined (RESTRICTED_SHELL) - if (restricted && pathname && strchr (pathname, '/')) - { - sh_restricted (pathname); - return (EXECUTION_FAILURE); - } -#endif - - for (opt = EXECUTION_SUCCESS; list; list = list->next) - { - /* Add, remove or rehash the specified commands. */ - w = list->word->word; - if (pathname) - { - if (is_directory (pathname)) - { -#ifdef EISDIR - builtin_error ("%s: %s", pathname, strerror (EISDIR)); -#else - builtin_error (_("%s: is a directory"), pathname); -#endif - opt = EXECUTION_FAILURE; - } - else - phash_insert (w, pathname, 0, 0); - } - else if (absolute_program (w)) - continue; - else if (delete) - { - if (phash_remove (w)) - { - sh_notfound (w); - opt = EXECUTION_FAILURE; - } - } - else if (add_hashed_command (w, 0)) - opt = EXECUTION_FAILURE; - } - - fflush (stdout); - return (opt); -} - -static int -add_hashed_command (w, quiet) - char *w; - int quiet; -{ - int rv; - char *full_path; - - rv = 0; - if (find_function (w) == 0 && find_shell_builtin (w) == 0) - { - full_path = find_user_command (w); - if (full_path && executable_file (full_path)) - phash_insert (w, full_path, dot_found_in_search, 0); - else - { - if (quiet == 0) - sh_notfound (w); - rv++; - } - FREE (full_path); - } - return (rv); -} - -/* Print information about current hashed info. */ -static int -print_hash_info (item) - BUCKET_CONTENTS *item; -{ - printf ("%4d\t%s\n", item->times_found, pathdata(item)->path); - return 0; -} - -static int -print_portable_hash_info (item) - BUCKET_CONTENTS *item; -{ - printf ("builtin hash -p %s %s\n", pathdata(item)->path, item->key); - return 0; -} - -static int -print_hashed_commands (fmt) - int fmt; -{ - if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0) - return (0); - - if (fmt == 0) - printf (_("hits\tcommand\n")); - hash_walk (hashed_filenames, fmt ? print_portable_hash_info : print_hash_info); - return (1); -} - -static int -list_hashed_filename_targets (list, fmt) - WORD_LIST *list; - int fmt; -{ - int all_found, multiple; - char *target; - WORD_LIST *l; - - all_found = 1; - multiple = list->next != 0; - - for (l = list; l; l = l->next) - { - target = phash_search (l->word->word); - if (target == 0) - { - all_found = 0; - sh_notfound (l->word->word); - continue; - } - if (fmt) - printf ("builtin hash -p %s %s\n", target, l->word->word); - else - { - if (multiple) - printf ("%s\t", l->word->word); - printf ("%s\n", target); - } - } - - return (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE); -} diff --git a/builtins/help.def.save1 b/builtins/help.def.save1 deleted file mode 100644 index 7984b780d..000000000 --- a/builtins/help.def.save1 +++ /dev/null @@ -1,207 +0,0 @@ -This file is help.def, from which is created help.c. -It implements the builtin "help" 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 help.c - -$BUILTIN help -$FUNCTION help_builtin -$DEPENDS_ON HELP_BUILTIN -$SHORT_DOC help [-s] [pattern ...] -Display helpful information about builtin commands. If PATTERN is -specified, gives detailed help on all commands matching PATTERN, -otherwise a list of the builtins is printed. The -s option -restricts the output for each builtin command matching PATTERN to -a short usage synopsis. -$END - -#include - -#if defined (HELP_BUILTIN) -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include - -#include - -#include "../bashintl.h" - -#include "../shell.h" -#include "../builtins.h" -#include "../pathexp.h" -#include "common.h" -#include "bashgetopt.h" - -#include -#include - -#ifndef errno -extern int errno; -#endif - -static void show_builtin_command_help __P((void)); -static void show_longdoc __P((int)); - -/* Print out a list of the known functions in the shell, and what they do. - If LIST is supplied, print out the list which matches for each pattern - specified. */ -int -help_builtin (list) - WORD_LIST *list; -{ - register int i; - char *pattern, *name; - int plen, match_found, sflag; - - sflag = 0; - reset_internal_getopt (); - while ((i = internal_getopt (list, "s")) != -1) - { - switch (i) - { - case 's': - sflag = 1; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - if (list == 0) - { - show_shell_version (0); - show_builtin_command_help (); - return (EXECUTION_SUCCESS); - } - - /* We should consider making `help bash' do something. */ - - if (glob_pattern_p (list->word->word)) - { - if (list->next) - printf (_("Shell commands matching keywords `")); - else - printf (_("Shell commands matching keyword `")); - print_word_list (list, ", "); - printf ("'\n\n"); - } - - for (match_found = 0, pattern = ""; list; list = list->next) - { - pattern = list->word->word; - plen = strlen (pattern); - - for (i = 0; name = shell_builtins[i].name; i++) - { - QUIT; - if ((strncmp (pattern, name, plen) == 0) || - (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH)) - { - printf ("%s: %s\n", name, shell_builtins[i].short_doc); - - if (sflag == 0) - show_longdoc (i); - - match_found++; - } - } - } - - if (match_found == 0) - { - builtin_error (_("no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'."), pattern, pattern, pattern); - return (EXECUTION_FAILURE); - } - - fflush (stdout); - return (EXECUTION_SUCCESS); -} - -/* By convention, enforced by mkbuiltins.c, if separate help files are being - used, the long_doc array contains one string -- the full pathname of the - help file for this builtin. */ -static void -show_longdoc (i) - int i; -{ - register int j; - char * const *doc; - int fd; - - doc = shell_builtins[i].long_doc; - - if (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL) - { - fd = open (doc[0], O_RDONLY); - if (fd == -1) - { - builtin_error (_("%s: cannot open: %s"), doc[0], strerror (errno)); - return; - } - zcatfd (fd, 1, doc[0]); - close (fd); - } - else - for (j = 0; doc[j]; j++) - printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j])); -} - -static void -show_builtin_command_help () -{ - int i, j; - char blurb[36]; - - printf ( -_("These shell commands are defined internally. Type `help' to see this list.\n\ -Type `help name' to find out more about the function `name'.\n\ -Use `info bash' to find out more about the shell in general.\n\ -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")); - - for (i = 0; i < num_shell_builtins; i++) - { - QUIT; - blurb[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*'; - strncpy (blurb + 1, shell_builtins[i].short_doc, 37); - blurb[38] = '\0'; - printf ("%s", blurb); - - if (i % 2) - printf ("\n"); - else - for (j = strlen (blurb); j < 40; j++) - putc (' ', stdout); - } - if (i % 2) - printf ("\n"); -} -#endif /* HELP_BUILTIN */ diff --git a/builtins/help.def.save2 b/builtins/help.def.save2 deleted file mode 100644 index f376fc33a..000000000 --- a/builtins/help.def.save2 +++ /dev/null @@ -1,217 +0,0 @@ -This file is help.def, from which is created help.c. -It implements the builtin "help" 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 help.c - -$BUILTIN help -$FUNCTION help_builtin -$DEPENDS_ON HELP_BUILTIN -$SHORT_DOC help [-s] [pattern ...] -Display helpful information about builtin commands. If PATTERN is -specified, gives detailed help on all commands matching PATTERN, -otherwise a list of the builtins is printed. The -s option -restricts the output for each builtin command matching PATTERN to -a short usage synopsis. -$END - -#include - -#if defined (HELP_BUILTIN) -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include - -#include - -#include "../bashintl.h" - -#include "../shell.h" -#include "../builtins.h" -#include "../pathexp.h" -#include "common.h" -#include "bashgetopt.h" - -#include -#include - -#ifndef errno -extern int errno; -#endif - -static void show_builtin_command_help __P((void)); -static void show_longdoc __P((int)); - -/* Print out a list of the known functions in the shell, and what they do. - If LIST is supplied, print out the list which matches for each pattern - specified. */ -int -help_builtin (list) - WORD_LIST *list; -{ - register int i; - char *pattern, *name; - int plen, match_found, sflag; - - sflag = 0; - reset_internal_getopt (); - while ((i = internal_getopt (list, "s")) != -1) - { - switch (i) - { - case 's': - sflag = 1; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - if (list == 0) - { - show_shell_version (0); - show_builtin_command_help (); - return (EXECUTION_SUCCESS); - } - - /* We should consider making `help bash' do something. */ - - if (glob_pattern_p (list->word->word)) - { - if (list->next) - printf (_("Shell commands matching keywords `")); - else - printf (_("Shell commands matching keyword `")); - print_word_list (list, ", "); - printf ("'\n\n"); - } - - for (match_found = 0, pattern = ""; list; list = list->next) - { - pattern = list->word->word; - plen = strlen (pattern); - - for (i = 0; name = shell_builtins[i].name; i++) - { - QUIT; - if ((strncmp (pattern, name, plen) == 0) || - (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH)) - { - printf ("%s: %s\n", name, shell_builtins[i].short_doc); - - if (sflag == 0) - show_longdoc (i); - - match_found++; - } - } - } - - if (match_found == 0) - { - builtin_error (_("no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'."), pattern, pattern, pattern); - return (EXECUTION_FAILURE); - } - - fflush (stdout); - return (EXECUTION_SUCCESS); -} - -/* By convention, enforced by mkbuiltins.c, if separate help files are being - used, the long_doc array contains one string -- the full pathname of the - help file for this builtin. */ -static void -show_longdoc (i) - int i; -{ - register int j; - char * const *doc; - int fd; - - doc = shell_builtins[i].long_doc; - - if (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL) - { - fd = open (doc[0], O_RDONLY); - if (fd == -1) - { - builtin_error (_("%s: cannot open: %s"), doc[0], strerror (errno)); - return; - } - zcatfd (fd, 1, doc[0]); - close (fd); - } - else - for (j = 0; doc[j]; j++) - printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j])); -} - -static void -show_builtin_command_help () -{ - int i, j; - int width; - char *t, blurb[128]; - - printf ( -_("These shell commands are defined internally. Type `help' to see this list.\n\ -Type `help name' to find out more about the function `name'.\n\ -Use `info bash' to find out more about the shell in general.\n\ -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")); - - t = get_string_value ("COLUMNS"); - width = (t && *t) ? atoi (t) : 80; - if (width <= 0) - width = 80; - - width /= 2; - if (width > sizeof (blurb)) - width = sizeof (blurb); - - for (i = 0; i < num_shell_builtins; i++) - { - QUIT; - blurb[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*'; - strncpy (blurb + 1, shell_builtins[i].short_doc, width - 2); - blurb[width - 1] = '\0'; - printf ("%s", blurb); - - if (i % 2) - printf ("\n"); - else - for (j = strlen (blurb); j < width; j++) - putc (' ', stdout); - } - if (i % 2) - printf ("\n"); -} -#endif /* HELP_BUILTIN */ diff --git a/builtins/help.def~ b/builtins/help.def~ deleted file mode 100644 index cfca07480..000000000 --- a/builtins/help.def~ +++ /dev/null @@ -1,378 +0,0 @@ -This file is help.def, from which is created help.c. -It implements the builtin "help" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 help.c - -$BUILTIN help -$FUNCTION help_builtin -$DEPENDS_ON HELP_BUILTIN -$SHORT_DOC help [-ds] [pattern ...] -Display information about builtin commands. - -Displays brief summaries of builtin commands. If PATTERN is -specified, gives detailed help on all commands matching PATTERN, -otherwise the list of help topics is printed. - -Options: - -d output short description for each topic - -m display usage in pseudo-manpage format - -s output only a short usage synopsis for each topic matching - PATTERN - -Arguments: - PATTERN Pattern specifiying a help topic - -Exit Status: -Returns success unless PATTERN is not found or an invalid option is given. -$END - -#include - -#if defined (HELP_BUILTIN) -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include - -#include - -#include "../bashintl.h" - -#include "../shell.h" -#include "../builtins.h" -#include "../pathexp.h" -#include "common.h" -#include "bashgetopt.h" - -#include -#include - -#ifndef errno -extern int errno; -#endif - -static void show_builtin_command_help __P((void)); -static int open_helpfile __P((char *)); -static void show_desc __P((char *, int)); -static void show_manpage __P((char *, int)); -static void show_longdoc __P((int)); - -/* Print out a list of the known functions in the shell, and what they do. - If LIST is supplied, print out the list which matches for each pattern - specified. */ -int -help_builtin (list) - WORD_LIST *list; -{ - register int i; - char *pattern, *name; - int plen, match_found, sflag, dflag, mflag; - - dflag = sflag = mflag = 0; - reset_internal_getopt (); - while ((i = internal_getopt (list, "dms")) != -1) - { - switch (i) - { - case 'd': - dflag = 1; - break; - case 'm': - mflag = 1; - break; - case 's': - sflag = 1; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - if (list == 0) - { - show_shell_version (0); - show_builtin_command_help (); - return (EXECUTION_SUCCESS); - } - - /* We should consider making `help bash' do something. */ - - if (glob_pattern_p (list->word->word)) - { - if (list->next) - printf (_("Shell commands matching keywords `")); - else - printf (_("Shell commands matching keyword `")); - print_word_list (list, ", "); - printf ("'\n\n"); - } - - for (match_found = 0, pattern = ""; list; list = list->next) - { - pattern = list->word->word; - plen = strlen (pattern); - - for (i = 0; name = shell_builtins[i].name; i++) - { - QUIT; - if ((strncmp (pattern, name, plen) == 0) || - (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH)) - { - match_found++; - if (dflag) - { - show_desc (name, i); - continue; - } - else if (mflag) - { - show_manpage (name, i); - continue; - } - - printf ("%s: %s\n", name, shell_builtins[i].short_doc); - - if (sflag == 0) - show_longdoc (i); - } - } - } - - if (match_found == 0) - { - builtin_error (_("no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'."), pattern, pattern, pattern); - return (EXECUTION_FAILURE); - } - - fflush (stdout); - return (EXECUTION_SUCCESS); -} - -static int -open_helpfile (name) - char *name; -{ - int fd; - - fd = open (name, O_RDONLY); - if (fd == -1) - { - builtin_error (_("%s: cannot open: %s"), name, strerror (errno)); - return -1; - } - return fd; -} - -/* By convention, enforced by mkbuiltins.c, if separate help files are being - used, the long_doc array contains one string -- the full pathname of the - help file for this builtin. */ -static void -show_longdoc (i) - int i; -{ - register int j; - char * const *doc; - int fd; - - doc = shell_builtins[i].long_doc; - - if (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL) - { - fd = open_helpfile (doc[0]); - zcatfd (fd, 1, doc[0]); - close (fd); - } - else - for (j = 0; doc[j]; j++) - printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j])); -} - -static void -show_desc (name, i) - char *name; - int i; -{ - register int j; - char **doc, *line; - int fd, usefile; - - doc = (char **)shell_builtins[i].long_doc; - - usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL); - if (usefile) - { - fd = open_helpfile (doc[0]); - zmapfd (fd, &line, doc[0]); - close (fd); - } - else - line = doc ? doc[0] : (char *)NULL; - - printf ("%s - ", name); - for (j = 0; line && line[j]; j++) - { - putchar (line[j]); - if (line[j] == '\n') - break; - } - - fflush (stdout); - - if (usefile) - free (line); -} - -/* Print builtin help in pseudo-manpage format. */ -static void -show_manpage (name, i) - char *name; - int i; -{ - register int j; - char **doc, *line; - int fd, usefile; - - doc = (char **)shell_builtins[i].long_doc; - - usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL); - if (usefile) - { - fd = open_helpfile (doc[0]); - zmapfd (fd, &line, doc[0]); - close (fd); - } - else - line = doc ? _(doc[0]) : (char *)NULL; - - /* NAME */ - printf ("NAME\n"); - printf ("%*s%s - ", BASE_INDENT, " ", name); - for (j = 0; line && line[j]; j++) - { - putchar (line[j]); - if (line[j] == '\n') - break; - } - printf ("\n"); - - /* SYNOPSIS */ - printf ("SYNOPSIS\n"); - printf ("%*s%s\n\n", BASE_INDENT, " ", shell_builtins[i].short_doc); - - /* DESCRIPTION */ - printf ("DESCRIPTION\n"); - if (usefile == 0) - { - for (j = 0; doc[j]; j++) - printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j])); - } - else - { - for (j = 0; line && line[j]; j++) - { - putchar (line[j]); - if (line[j] == '\n') - printf ("%*s", BASE_INDENT, " "); - } - } - putchar ('\n'); - - /* SEE ALSO */ - printf ("SEE ALSO\n"); - printf ("%*sbash(1)\n\n", BASE_INDENT, " "); - - /* IMPLEMENTATION */ - printf ("IMPLEMENTATION\n"); - printf ("%*s", BASE_INDENT, " "); - show_shell_version (0); - printf ("%*s", BASE_INDENT, " "); - printf (_("Copyright (C) 2008 Free Software Foundation, Inc.\n")); - printf ("%*s", BASE_INDENT, " "); - printf (_("License: GNU General Public License, version 2\n")); - - fflush (stdout); - if (usefile) - free (line); -} - -static void -show_builtin_command_help () -{ - int i, j; - int height, width; - char *t, blurb[128]; - - printf ( -_("These shell commands are defined internally. Type `help' to see this list.\n\ -Type `help name' to find out more about the function `name'.\n\ -Use `info bash' to find out more about the shell in general.\n\ -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")); - - t = get_string_value ("COLUMNS"); - width = (t && *t) ? atoi (t) : 80; - if (width <= 0) - width = 80; - - width /= 2; - if (width > sizeof (blurb)) - width = sizeof (blurb); - height = (num_shell_builtins + 1) / 2; /* number of rows */ - - for (i = 0; i < height; i++) - { - QUIT; - - /* first column */ - blurb[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*'; - strncpy (blurb + 1, shell_builtins[i].short_doc, width - 2); - blurb[width - 2] = '>'; /* indicate truncation */ - blurb[width - 1] = '\0'; - printf ("%s", blurb); - if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins)) - { - printf ("\n"); - break; - } - - /* two spaces */ - for (j = strlen (blurb); j < width; j++) - putc (' ', stdout); - - /* second column */ - blurb[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*'; - strncpy (blurb + 1, shell_builtins[i+height].short_doc, width - 3); - blurb[width - 3] = '>'; /* indicate truncation */ - blurb[width - 2] = '\0'; - printf ("%s\n", blurb); - } -} -#endif /* HELP_BUILTIN */ diff --git a/builtins/history.def~ b/builtins/history.def~ deleted file mode 100644 index 31f72e70b..000000000 --- a/builtins/history.def~ +++ /dev/null @@ -1,408 +0,0 @@ -This file is history.def, from which is created history.c. -It implements the builtin "history" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 history.c - -$BUILTIN history -$FUNCTION history_builtin -$DEPENDS_ON HISTORY -$SHORT_DOC history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg [arg...] -Display or manipulate the history list. - -Display the history list with line numbers, prefixing each modified -entry with a `*'. An argument of N lists only the last N entries. - -Options: - -c clear the history list by deleting all of the entries - -d offset delete the history entry at offset OFFSET. - - -a append history lines from this session to the history file - -n read all history lines not already read from the history file - -r read the history file and append the contents to the history - list - -w write the current history to the history file - and append them to the history list - - -p perform history expansion on each ARG and display the result - without storing it in the history list - -s append the ARGs to the history list as a single entry - -If FILENAME is given, it is used as the history file. Otherwise, -if $HISTFILE has a value, that is used, else ~/.bash_history. - -If the $HISTTIMEFORMAT variable is set and not null, its value is used -as a format string for strftime(3) to print the time stamp associated -with each displayed history entry. No time stamps are printed otherwise. - -Exit Status: -Returns success unless an invalid option is given or an error occurs. -$END - -#include - -#if defined (HISTORY) -#include "../bashtypes.h" -#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "posixstat.h" -#include "filecntl.h" -#include -#include -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../bashhist.h" -#include -#include "bashgetopt.h" -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif - -extern int current_command_line_count; -extern int force_append_history; /* shopt -s histappend */ - -int delete_last_history __P((void)); - -static char *histtime __P((HIST_ENTRY *, const char *)); -static void display_history __P((WORD_LIST *)); -static void push_history __P((WORD_LIST *)); -static int expand_and_print_history __P((WORD_LIST *)); - -#define AFLAG 0x01 -#define RFLAG 0x02 -#define WFLAG 0x04 -#define NFLAG 0x08 -#define SFLAG 0x10 -#define PFLAG 0x20 -#define CFLAG 0x40 -#define DFLAG 0x80 - -int -history_builtin (list) - WORD_LIST *list; -{ - int flags, opt, result, old_history_lines, obase; - char *filename, *delete_arg; - intmax_t delete_offset; - - flags = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "acd:npsrw")) != -1) - { - switch (opt) - { - case 'a': - flags |= AFLAG; - break; - case 'c': - flags |= CFLAG; - break; - case 'n': - flags |= NFLAG; - break; - case 'r': - flags |= RFLAG; - break; - case 'w': - flags |= WFLAG; - break; - case 's': - flags |= SFLAG; - break; - case 'd': - flags |= DFLAG; - delete_arg = list_optarg; - break; - case 'p': -#if defined (BANG_HISTORY) - flags |= PFLAG; -#endif - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG); - if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG) - { - builtin_error (_("cannot use more than one of -anrw")); - return (EXECUTION_FAILURE); - } - - /* clear the history, but allow other arguments to add to it again. */ - if (flags & CFLAG) - { - bash_clear_history (); - if (list == 0) - return (EXECUTION_SUCCESS); - } - - if (flags & SFLAG) - { - if (list) - push_history (list); - return (EXECUTION_SUCCESS); - } -#if defined (BANG_HISTORY) - else if (flags & PFLAG) - { - if (list) - return (expand_and_print_history (list)); - return (sh_chkwrite (EXECUTION_SUCCESS)); - } -#endif - else if (flags & DFLAG) - { - if ((legal_number (delete_arg, &delete_offset) == 0) - || (delete_offset < history_base) - || (delete_offset > (history_base + history_length))) - { - sh_erange (delete_arg, _("history position")); - return (EXECUTION_FAILURE); - } - opt = delete_offset; - result = bash_delete_histent (opt - history_base); - /* Since remove_history changes history_length, this can happen if - we delete the last history entry. */ - if (where_history () > history_length) - history_set_pos (history_length); - return (result ? EXECUTION_SUCCESS : EXECUTION_FAILURE); - } - else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0) - { - display_history (list); - return (sh_chkwrite (EXECUTION_SUCCESS)); - } - - filename = list ? list->word->word : get_string_value ("HISTFILE"); - result = EXECUTION_SUCCESS; - - if (flags & AFLAG) /* Append session's history to file. */ - result = maybe_append_history (filename); - else if (flags & WFLAG) /* Write entire history. */ - result = write_history (filename); - else if (flags & RFLAG) /* Read entire file. */ - result = read_history (filename); - else if (flags & NFLAG) /* Read `new' history from file. */ - { - /* Read all of the lines in the file that we haven't already read. */ - old_history_lines = history_lines_in_file; - obase = history_base; - - using_history (); - result = read_history_range (filename, history_lines_in_file, -1); - using_history (); - - history_lines_in_file = where_history (); - - /* If we're rewriting the history file at shell exit rather than just - appending the lines from this session to it, the question is whether - we reset history_lines_this_session to 0, losing any history entries - we had before we read the new entries from the history file, or - whether we count the new entries we just read from the file as - history lines added during this session. - Right now, we do the latter. This will cause these history entries - to be written to the history file along with any intermediate entries - we add when we do a `history -a', but the alternative is losing - them altogether. */ - if (force_append_history == 0) - history_lines_this_session += history_lines_in_file - old_history_lines + - history_base - obase; - } - - return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS); -} - -/* Accessors for HIST_ENTRY lists that are called HLIST. */ -#define histline(i) (hlist[(i)]->line) -#define histdata(i) (hlist[(i)]->data) - -static char * -histtime (hlist, histtimefmt) - HIST_ENTRY *hlist; - const char *histtimefmt; -{ - static char timestr[128]; - time_t t; - - t = history_get_time (hlist); - if (t) - strftime (timestr, sizeof (timestr), histtimefmt, localtime (&t)); - else - strcpy (timestr, "??"); - return timestr; -} - -static void -display_history (list) - WORD_LIST *list; -{ - register int i; - intmax_t limit; - HIST_ENTRY **hlist; - char *histtimefmt, *timestr; - - if (list) - { - limit = get_numeric_arg (list, 0); - if (limit < 0) - limit = -limit; - } - else - limit = -1; - - hlist = history_list (); - - if (hlist) - { - for (i = 0; hlist[i]; i++) - ; - - if (0 <= limit && limit < i) - i -= limit; - else - i = 0; - - - histtimefmt = get_string_value ("HISTTIMEFORMAT"); - - while (hlist[i]) - { - QUIT; - - timestr = (histtimefmt && *histtimefmt) ? histtime (hlist[i], histtimefmt) : (char *)NULL; - printf ("%5d%c %s%s\n", i + history_base, - histdata(i) ? '*' : ' ', - ((timestr && *timestr) ? timestr : ""), - histline(i)); - i++; - } - } -} - -int -delete_last_history () -{ - register int i; - HIST_ENTRY **hlist, *histent; - int r; - - hlist = history_list (); - if (hlist == NULL) - return 0; - - for (i = 0; hlist[i]; i++) - ; - i--; - - /* History_get () takes a parameter that must be offset by history_base. */ - histent = history_get (history_base + i); /* Don't free this */ - if (histent == NULL) - return 0; - - r = bash_delete_histent (i); - - if (where_history () > history_length) - history_set_pos (history_length); - - return r; -} - -/* Remove the last entry in the history list and add each argument in - LIST to the history. */ -static void -push_history (list) - WORD_LIST *list; -{ - char *s; - - /* Delete the last history entry if it was a single entry added to the - history list (generally the `history -s' itself), or if `history -s' - is being used in a compound command and the compound command was - added to the history as a single element (command-oriented history). - If you don't want history -s to remove the compound command from the - history, change #if 0 to #if 1 below. */ -#if 0 - if (hist_last_line_pushed == 0 && hist_last_line_added && delete_last_history () == 0) -#else - if (hist_last_line_pushed == 0 && - (hist_last_line_added || - (current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history)) - && delete_last_history () == 0) -#endif - return; - - s = string_list (list); - /* Call check_add_history with FORCE set to 1 to skip the check against - current_command_line_count. If history -s is used in a compound - command, the above code will delete the compound command's history - entry and this call will add the line to the history as a separate - entry. Without FORCE=1, if current_command_line_count were > 1, the - line would be appended to the entry before the just-deleted entry. */ - check_add_history (s, 1); /* obeys HISTCONTROL, HISTIGNORE */ - - hist_last_line_pushed = 1; /* XXX */ - free (s); -} - -#if defined (BANG_HISTORY) -static int -expand_and_print_history (list) - WORD_LIST *list; -{ - char *s; - int r, result; - - if (hist_last_line_pushed == 0 && hist_last_line_added && delete_last_history () == 0) - return EXECUTION_FAILURE; - result = EXECUTION_SUCCESS; - while (list) - { - r = history_expand (list->word->word, &s); - if (r < 0) - { - builtin_error (_("%s: history expansion failed"), list->word->word); - result = EXECUTION_FAILURE; - } - else - { - fputs (s, stdout); - putchar ('\n'); - } - FREE (s); - list = list->next; - } - fflush (stdout); - return result; -} -#endif /* BANG_HISTORY */ -#endif /* HISTORY */ diff --git a/builtins/inlib.def~ b/builtins/inlib.def~ deleted file mode 100644 index 9536f01c1..000000000 --- a/builtins/inlib.def~ +++ /dev/null @@ -1,78 +0,0 @@ -This file is inlib.def, from which is created inlib.c. -It implements the Apollo-specific builtin "inlib" 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 inlib.c -#include - -#include -#include "../shell.h" - -$BUILTIN inlib -$FUNCTION inlib_builtin -$DEPENDS_ON apollo -$SHORT_DOC inlib pathname [pathname...] -Install user-supplied library. - -Install a user-supplied library specified by pathname in the current -shell process. The library is used to resolve external references -in programs and libraries loaded after its installation. Note -that the library is not loaded into the address space unless it is -needed to resolve an external reference. The list of inlibed -libraries is passed to all children of the current shell. -$END - -#if defined (apollo) - -#include -#include - -inlib_builtin (list) - WORD_LIST *list; -{ - status_$t status; - int return_value; - short len; - - if (!list) - { - builtin_usage (); - return (EX_USAGE); - } - - return_value = EXECUTION_SUCCESS; - - while (list) - { - len = (short)strlen (list->word->word); - loader_$inlib (list->word->word, len, &status); - - if (status.all != status_$ok) - { - builtin_error (_("%s: inlib failed"), list->word->word); - return_value = EXECUTION_FAILURE; - } - - list = list->next; - } - - return (return_value); -} -#endif /* apollo */ diff --git a/builtins/jobs.def~ b/builtins/jobs.def~ deleted file mode 100644 index d42e20807..000000000 --- a/builtins/jobs.def~ +++ /dev/null @@ -1,292 +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-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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] -Display status of jobs. - -Lists the active jobs. JOBSPEC restricts output to that job. -Without options, the status of all active jobs is displayed. - -Options: - -l lists process IDs in addition to the normal information - -n list only processes that have changed status since the last - notification - -p lists process IDs only - -r restrict output to running jobs - -s restrict output to stopped jobs - -If -x is supplied, 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; - - 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 == 0 || get_job_by_jid (job) == 0) - { - 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; - JOB *j; - - /* 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 (INVALID_JOB (job)) - continue; - - j = get_job_by_jid (job); - free (l->word->word); - l->word->word = itos (j->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 ...] -Remove jobs from current shell. - -Removes each JOBSPEC argument from the table of active jobs. Without -any JOBSPECs, the shell uses its notion of the current job. - -Options: - -a remove all jobs if JOBSPEC is not supplied - -h mark each JOBSPEC so that SIGHUP is not sent to the job if the - shell receives a SIGHUP - -r 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 || INVALID_JOB (job)) - { - 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~ b/builtins/kill.def~ deleted file mode 100644 index 8c8ba3437..000000000 --- a/builtins/kill.def~ +++ /dev/null @@ -1,260 +0,0 @@ -This file is kill.def, from which is created kill.c. -It implements the builtin "kill" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 | jobspec ... or kill -l [sigspec] -Send a signal to a job. - -Send the processes identified by PID or JOBSPEC the signal named by -SIGSPEC or SIGNUM. If neither SIGSPEC nor SIGNUM is present, then -SIGTERM is assumed. - -Options: - -s sig SIG is a signal name - -n sig SIG is a signal number - -l list 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 allows processes to be killed if the limit -on processes that you can create is reached. -$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 (kill_pid (pid, sig, pid < -1) < 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; - JOB *j; - - BLOCK_CHILD (set, oset); - job = get_job_spec (list); - - if (INVALID_JOB (job)) - { - if (job != DUP_JOB) - sh_badjob (list->word->word); - UNBLOCK_CHILD (oset); - CONTINUE_OR_FAIL; - } - - j = get_job_by_jid (job); - /* 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) ? j->pgrp : j->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/let.def~ b/builtins/let.def~ deleted file mode 100644 index dae762d75..000000000 --- a/builtins/let.def~ +++ /dev/null @@ -1,130 +0,0 @@ -This file is let.def, from which is created let.c. -It implements the builtin "let" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 let -$FUNCTION let_builtin -$PRODUCES let.c -$SHORT_DOC let arg [arg ...] -Evaluate arithmetic expressions. - -Evaluate each ARG as an arithmetic expression. Evaluation is done in -fixed-width integers with no check for overflow, though division by 0 -is trapped and flagged as an error. The following list of operators is -grouped into levels of equal-precedence operators. The levels are listed -in order of decreasing precedence. - - id++, id-- variable post-increment, post-decrement - ++id, --id variable pre-increment, pre-decrement - -, + unary minus, plus - !, ~ logical and bitwise negation - ** exponentiation - *, /, % multiplication, division, remainder - +, - addition, subtraction - <<, >> left and right bitwise shifts - <=, >=, <, > comparison - ==, != equality, inequality - & bitwise AND - ^ bitwise XOR - | bitwise OR - && logical AND - || logical OR - expr ? expr : expr - conditional operator - =, *=, /=, %=, - +=, -=, <<=, >>=, - &=, ^=, |= assignment - -Shell variables are allowed as operands. The name of the variable -is replaced by its value (coerced to a fixed-width integer) within -an expression. The variable need not have its integer attribute -turned on to be used in an expression. - -Operators are evaluated in order of precedence. Sub-expressions in -parentheses are evaluated first and may override the precedence -rules above. - -If the last ARG evaluates to 0, let returns 1; 0 is returned -otherwise. -$END - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashintl.h" - -#include "../shell.h" -#include "common.h" - -/* Arithmetic LET function. */ -int -let_builtin (list) - WORD_LIST *list; -{ - intmax_t ret; - int expok; - - /* Skip over leading `--' argument. */ - if (list && list->word && ISOPTION (list->word->word, '-')) - list = list->next; - - if (list == 0) - { - builtin_error (_("expression expected")); - return (EXECUTION_FAILURE); - } - - for (; list; list = list->next) - { - ret = evalexp (list->word->word, &expok); - if (expok == 0) - return (EXECUTION_FAILURE); - } - - return ((ret == 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS); -} - -#ifdef INCLUDE_UNUSED -int -exp_builtin (list) - WORD_LIST *list; -{ - char *exp; - intmax_t ret; - int expok; - - if (list == 0) - { - builtin_error (_("expression expected")); - return (EXECUTION_FAILURE); - } - - exp = string_list (list); - ret = evalexp (exp, &expok); - (void)free (exp); - return (((ret == 0) || (expok == 0)) ? EXECUTION_FAILURE : EXECUTION_SUCCESS); -} -#endif diff --git a/builtins/mapfile.def~ b/builtins/mapfile.def~ deleted file mode 100644 index bb6c3d8f3..000000000 --- a/builtins/mapfile.def~ +++ /dev/null @@ -1,343 +0,0 @@ -This file is mapfile.def, from which is created mapfile.c. -It implements the builtin "mapfile" in Bash. - -Copyright (C) 2005-2006 Rocky Bernstein for Free Software Foundation, Inc. -Copyright (C) 2008,2009 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Bash is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Bash. If not, see . - -$PRODUCES mapfile.c - -$BUILTIN mapfile -$FUNCTION mapfile_builtin -$SHORT_DOC mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array] -Read lines from a file into an array variable. - -Read lines from the standard input into the array variable ARRAY, or from -file descriptor FD if the -u option is supplied. The variable MAPFILE is -the default ARRAY. - -Options: - -n count Copy at most COUNT lines. If COUNT is 0, all lines are copied. - -O origin Begin assigning to ARRAY at index ORIGIN. The default index is 0. - -s count Discard the first COUNT lines read. - -t Remove a trailing newline from each line read. - -u fd Read lines from file descriptor FD instead of the standard input. - -C callback Evaluate CALLBACK each time QUANTUM lines are read. - -c quantum Specify the number of lines read between each call to CALLBACK. - -Arguments: - ARRAY Array variable name to use for file data. - -If -C is supplied without -c, the default quantum is 5000. When -CALLBACK is evaluated, it is supplied the index of the next array -element to be assigned as an additional argument. - -If not supplied with an explicit origin, mapfile will clear ARRAY before -assigning to it. - -Exit Status: -Returns success unless an invalid option is given or ARRAY is readonly. -$END - -$BUILTIN readarray -$FUNCTION mapfile_builtin -$SHORT_DOC readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array] -Read lines from a file into an array variable. - -A synonym for `mapfile'. -$END - -#include - -#include "builtins.h" -#include "posixstat.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" - -#include -#include - -#include "../bashintl.h" -#include "../shell.h" -#include "common.h" -#include "bashgetopt.h" - -#if !defined (errno) -extern int errno; -#endif - -#if defined (ARRAY_VARS) - -#define DEFAULT_ARRAY_NAME "MAPFILE" - -/* The value specifying how frequently `mapfile' calls the callback. */ -#define DEFAULT_QUANTUM 5000 - -/* Values for FLAGS */ -#define MAPF_CLEARARRAY 0x01 -#define MAPF_CHOP 0x02 - -static int -run_callback(callback, current_index) - const char *callback; - unsigned int current_index; -{ - unsigned int execlen; - char *execstr; - int flags; - - execlen = strlen (callback) + 10; - /* 1 for space between %s and %d, - another 1 for the last nul char for C string. */ - execlen += 2; - execstr = xmalloc (execlen); - - flags = 0; -#if 0 - if (interactive) - flags |= SEVAL_NOHIST|SEVAL_INTERACT; -#endif - snprintf (execstr, execlen, "%s %d", callback, current_index); - return parse_and_execute(execstr, NULL, flags); -} - -static void -do_chop(line) - char * line; -{ - int length; - - length = strlen (line); - if (length && line[length-1] == '\n') - line[length-1] = '\0'; -} - -static int -mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_name, flags) - int fd; - long line_count_goal, origin, nskip, callback_quantum; - char *callback, *array_name; - int flags; -{ - char *line; - size_t line_length; - unsigned int array_index, line_count; - SHELL_VAR *entry; - int unbuffered_read; - - line = NULL; - line_length = 0; - unbuffered_read = 0; - - /* The following check should be done before reading any lines. Doing it - here allows us to call bind_array_element instead of bind_array_variable - and skip the variable lookup on every call. */ - entry = find_or_make_array_variable (array_name, 1); - if (entry == 0 || readonly_p (entry) || noassign_p (entry)) - { - if (readonly_p (entry)) - err_readonly (array_name); - - return (EXECUTION_FAILURE); - } - if (flags & MAPF_CLEARARRAY) - array_flush (array_cell (entry)); - -#ifndef __CYGWIN__ - unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE); -#else - unbuffered_read = 1; -#endif - - zreset (); - - /* Skip any lines at beginning of file? */ - for (line_count = 0; line_count < nskip; line_count++) - if (zgetline (fd, &line, &line_length, unbuffered_read) < 0) - break; - - line = 0; - line_length = 0; - - /* Reset the buffer for bash own stream */ - interrupt_immediately++; - for (array_index = origin, line_count = 1; - zgetline (fd, &line, &line_length, unbuffered_read) != -1; - array_index++, line_count++) - { - /* Have we exceeded # of lines to store? */ - if (line_count_goal != 0 && line_count >= line_count_goal) - break; - - /* Remove trailing newlines? */ - if (flags & MAPF_CHOP) - do_chop (line); - - /* Has a callback been registered and if so is it time to call it? */ - if (callback && line_count && (line_count % callback_quantum) == 0) - { - run_callback (callback, array_index); - - /* Reset the buffer for bash own stream. */ - if (unbuffered_read == 0) - zsyncfd (fd); - } - - bind_array_element (entry, array_index, line, 0); - } - - xfree (line); - - if (unbuffered_read == 0) - zsyncfd (fd); - - interrupt_immediately--; - return EXECUTION_SUCCESS; -} - -int -mapfile_builtin (list) - WORD_LIST *list; -{ - int opt, code, fd, clear_array, flags; - intmax_t intval; - long lines, origin, nskip, callback_quantum; - char *array_name, *callback; - - clear_array = 1; - fd = 0; - lines = origin = nskip = 0; - flags = MAPF_CLEARARRAY; - callback_quantum = DEFAULT_QUANTUM; - callback = 0; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "u:n:O:tC:c:s:")) != -1) - { - switch (opt) - { - 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 'n': - code = legal_number (list_optarg, &intval); - if (code == 0 || intval < 0 || intval != (unsigned)intval) - { - builtin_error (_("%s: invalid line count"), list_optarg); - return (EXECUTION_FAILURE); - } - else - lines = intval; - break; - - case 'O': - code = legal_number (list_optarg, &intval); - if (code == 0 || intval < 0 || intval != (unsigned)intval) - { - builtin_error (_("%s: invalid array origin"), list_optarg); - return (EXECUTION_FAILURE); - } - else - origin = intval; - flags &= ~MAPF_CLEARARRAY; - break; - case 't': - flags |= MAPF_CHOP; - break; - case 'C': - callback = list_optarg; - break; - case 'c': - code = legal_number (list_optarg, &intval); - if (code == 0 || intval < 0 || intval != (unsigned)intval) - { - builtin_error (_("%s: invalid callback quantum"), list_optarg); - return (EXECUTION_FAILURE); - } - else - callback_quantum = intval; - break; - case 's': - code = legal_number (list_optarg, &intval); - if (code == 0 || intval < 0 || intval != (unsigned)intval) - { - builtin_error (_("%s: invalid line count"), list_optarg); - return (EXECUTION_FAILURE); - } - else - nskip = intval; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - if (list == 0) - array_name = DEFAULT_ARRAY_NAME; - else if (list->word == 0 || list->word->word == 0) - { - builtin_error ("internal error: getting variable name"); - return (EXECUTION_FAILURE); - } - else if (list->word->word[0] == '\0') - { - builtin_error (_("empty array variable name")); - return (EX_USAGE); - } - else - array_name = list->word->word; - - if (legal_identifier (array_name) == 0 && valid_array_reference (array_name) == 0) - { - sh_invalidid (array_name); - return (EXECUTION_FAILURE); - } - - return mapfile (fd, lines, origin, nskip, callback_quantum, callback, array_name, flags); -} - -#else - -int -mapfile_builtin (list) - WORD_LIST *list; -{ - builtin_error (_("array variable support required")); - return (EXECUTION_FAILURE); -} - -#endif /* ARRAY_VARS */ diff --git a/builtins/mkbuiltins.c~ b/builtins/mkbuiltins.c~ deleted file mode 100644 index aef02807b..000000000 --- a/builtins/mkbuiltins.c~ +++ /dev/null @@ -1,1595 +0,0 @@ -/* mkbuiltins.c - Create builtins.c, builtext.h, and builtdoc.c from - a single source file called builtins.def. */ - -/* Copyright (C) 1987-2007 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 (CROSS_COMPILING) -# include -#else /* CROSS_COMPILING */ -/* A conservative set of defines based on POSIX/SUS3/XPG6 */ -# define HAVE_UNISTD_H -# define HAVE_STRING_H -# define HAVE_STDLIB_H - -# define HAVE_RENAME -#endif /* CROSS_COMPILING */ - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#ifndef _MINIX -# include "../bashtypes.h" -# if defined (HAVE_SYS_FILE_H) -# include -# endif -#endif - -#include "posixstat.h" -#include "filecntl.h" - -#include "../bashansi.h" -#include -#include - -#include "stdc.h" - -#define DOCFILE "builtins.texi" - -#ifndef errno -extern int errno; -#endif - -static char *xmalloc (), *xrealloc (); - -#if !defined (__STDC__) && !defined (strcpy) -extern char *strcpy (); -#endif /* !__STDC__ && !strcpy */ - -#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x)) -#define whitespace(c) (((c) == ' ') || ((c) == '\t')) - -/* Flag values that builtins can have. */ -#define BUILTIN_FLAG_SPECIAL 0x01 -#define BUILTIN_FLAG_ASSIGNMENT 0x02 -#define BUILTIN_FLAG_POSIX_BUILTIN 0x04 - -#define BASE_INDENT 4 - -/* If this stream descriptor is non-zero, then write - texinfo documentation to it. */ -FILE *documentation_file = (FILE *)NULL; - -/* Non-zero means to only produce documentation. */ -int only_documentation = 0; - -/* Non-zero means to not do any productions. */ -int inhibit_production = 0; - -/* Non-zero means to produce separate help files for each builtin, named by - the builtin name, in `./helpfiles'. */ -int separate_helpfiles = 0; - -/* Non-zero means to create single C strings for each `longdoc', with - embedded newlines, for ease of translation. */ -int single_longdoc_strings = 1; - -/* The name of a directory into which the separate external help files will - eventually be installed. */ -char *helpfile_directory; - -/* The name of a directory to precede the filename when reporting - errors. */ -char *error_directory = (char *)NULL; - -/* The name of the structure file. */ -char *struct_filename = (char *)NULL; - -/* The name of the external declaration file. */ -char *extern_filename = (char *)NULL; - -/* Here is a structure for manipulating arrays of data. */ -typedef struct { - int size; /* Number of slots allocated to array. */ - int sindex; /* Current location in array. */ - int width; /* Size of each element. */ - int growth_rate; /* How fast to grow. */ - char **array; /* The array itself. */ -} ARRAY; - -/* Here is a structure defining a single BUILTIN. */ -typedef struct { - char *name; /* The name of this builtin. */ - char *function; /* The name of the function to call. */ - char *shortdoc; /* The short documentation for this builtin. */ - char *docname; /* Possible name for documentation string. */ - ARRAY *longdoc; /* The long documentation for this builtin. */ - ARRAY *dependencies; /* Null terminated array of #define names. */ - int flags; /* Flags for this builtin. */ -} BUILTIN_DESC; - -/* Here is a structure which defines a DEF file. */ -typedef struct { - char *filename; /* The name of the input def file. */ - ARRAY *lines; /* The contents of the file. */ - int line_number; /* The current line number. */ - char *production; /* The name of the production file. */ - FILE *output; /* Open file stream for PRODUCTION. */ - ARRAY *builtins; /* Null terminated array of BUILTIN_DESC *. */ -} DEF_FILE; - -/* The array of all builtins encountered during execution of this code. */ -ARRAY *saved_builtins = (ARRAY *)NULL; - -/* The Posix.2 so-called `special' builtins. */ -char *special_builtins[] = -{ - ":", ".", "source", "break", "continue", "eval", "exec", "exit", - "export", "readonly", "return", "set", "shift", "times", "trap", "unset", - (char *)NULL -}; - -/* The builtin commands that take assignment statements as arguments. */ -char *assignment_builtins[] = -{ - "alias", "declare", "export", "local", "readonly", "typeset", - (char *)NULL -}; - -/* The builtin commands that are special to the POSIX search order. */ -char *posix_builtins[] = -{ - "alias", "bg", "cd", "command", "false", "fc", "fg", "getopts", "jobs", - "kill", "newgrp", "pwd", "read", "true", "umask", "unalias", "wait", - (char *)NULL -}; - -/* Forward declarations. */ -static int is_special_builtin (); -static int is_assignment_builtin (); -static int is_posix_builtin (); - -#if !defined (HAVE_RENAME) -static int rename (); -#endif - -void extract_info (); - -void file_error (); -void line_error (); - -void write_file_headers (); -void write_file_footers (); -void write_ifdefs (); -void write_endifs (); -void write_documentation (); -void write_longdocs (); -void write_builtins (); - -int write_helpfiles (); - -void free_defs (); -void add_documentation (); - -void must_be_building (); -void remove_trailing_whitespace (); - -#define document_name(b) ((b)->docname ? (b)->docname : (b)->name) - - -/* For each file mentioned on the command line, process it and - write the information to STRUCTFILE and EXTERNFILE, while - creating the production file if neccessary. */ -int -main (argc, argv) - int argc; - char **argv; -{ - int arg_index = 1; - FILE *structfile, *externfile; - char *documentation_filename, *temp_struct_filename; - - structfile = externfile = (FILE *)NULL; - documentation_filename = DOCFILE; - temp_struct_filename = (char *)NULL; - - while (arg_index < argc && argv[arg_index][0] == '-') - { - char *arg = argv[arg_index++]; - - if (strcmp (arg, "-externfile") == 0) - extern_filename = argv[arg_index++]; - else if (strcmp (arg, "-structfile") == 0) - struct_filename = argv[arg_index++]; - else if (strcmp (arg, "-noproduction") == 0) - inhibit_production = 1; - else if (strcmp (arg, "-document") == 0) - documentation_file = fopen (documentation_filename, "w"); - else if (strcmp (arg, "-D") == 0) - { - int len; - - if (error_directory) - free (error_directory); - - error_directory = xmalloc (2 + strlen (argv[arg_index])); - strcpy (error_directory, argv[arg_index]); - len = strlen (error_directory); - - if (len && error_directory[len - 1] != '/') - strcat (error_directory, "/"); - - arg_index++; - } - else if (strcmp (arg, "-documentonly") == 0) - { - only_documentation = 1; - documentation_file = fopen (documentation_filename, "w"); - } - else if (strcmp (arg, "-H") == 0) - { - separate_helpfiles = 1; - helpfile_directory = argv[arg_index++]; - } - else if (strcmp (arg, "-S") == 0) - single_longdoc_strings = 0; - else - { - fprintf (stderr, "%s: Unknown flag %s.\n", argv[0], arg); - exit (2); - } - } - - /* If there are no files to process, just quit now. */ - if (arg_index == argc) - exit (0); - - if (!only_documentation) - { - /* Open the files. */ - if (struct_filename) - { - temp_struct_filename = xmalloc (15); - sprintf (temp_struct_filename, "mk-%ld", (long) getpid ()); - structfile = fopen (temp_struct_filename, "w"); - - if (!structfile) - file_error (temp_struct_filename); - } - - if (extern_filename) - { - externfile = fopen (extern_filename, "w"); - - if (!externfile) - file_error (extern_filename); - } - - /* Write out the headers. */ - write_file_headers (structfile, externfile); - } - - if (documentation_file) - { - fprintf (documentation_file, "@c Table of builtins created with %s.\n", - argv[0]); - fprintf (documentation_file, "@ftable @asis\n"); - } - - /* Process the .def files. */ - while (arg_index < argc) - { - register char *arg; - - arg = argv[arg_index++]; - - extract_info (arg, structfile, externfile); - } - - /* Close the files. */ - if (!only_documentation) - { - /* Write the footers. */ - write_file_footers (structfile, externfile); - - if (structfile) - { - write_longdocs (structfile, saved_builtins); - fclose (structfile); - rename (temp_struct_filename, struct_filename); - } - - if (externfile) - fclose (externfile); - } - - if (separate_helpfiles) - { - write_helpfiles (saved_builtins); - } - - if (documentation_file) - { - fprintf (documentation_file, "@end ftable\n"); - fclose (documentation_file); - } - - exit (0); -} - -/* **************************************************************** */ -/* */ -/* Array Functions and Manipulators */ -/* */ -/* **************************************************************** */ - -/* Make a new array, and return a pointer to it. The array will - contain elements of size WIDTH, and is initialized to no elements. */ -ARRAY * -array_create (width) - int width; -{ - ARRAY *array; - - array = (ARRAY *)xmalloc (sizeof (ARRAY)); - array->size = 0; - array->sindex = 0; - array->width = width; - - /* Default to increasing size in units of 20. */ - array->growth_rate = 20; - - array->array = (char **)NULL; - - return (array); -} - -/* Copy the array of strings in ARRAY. */ -ARRAY * -copy_string_array (array) - ARRAY *array; -{ - register int i; - ARRAY *copy; - - if (!array) - return (ARRAY *)NULL; - - copy = array_create (sizeof (char *)); - - copy->size = array->size; - copy->sindex = array->sindex; - copy->width = array->width; - - copy->array = (char **)xmalloc ((1 + array->sindex) * sizeof (char *)); - - for (i = 0; i < array->sindex; i++) - copy->array[i] = savestring (array->array[i]); - - copy->array[i] = (char *)NULL; - - return (copy); -} - -/* Add ELEMENT to ARRAY, growing the array if neccessary. */ -void -array_add (element, array) - char *element; - ARRAY *array; -{ - if (array->sindex + 2 > array->size) - array->array = (char **)xrealloc - (array->array, (array->size += array->growth_rate) * array->width); - - array->array[array->sindex++] = element; - array->array[array->sindex] = (char *)NULL; -} - -/* Free an allocated array and data pointer. */ -void -array_free (array) - ARRAY *array; -{ - if (array->array) - free (array->array); - - free (array); -} - -/* **************************************************************** */ -/* */ -/* Processing a DEF File */ -/* */ -/* **************************************************************** */ - -/* The definition of a function. */ -typedef int Function (); -typedef int mk_handler_func_t __P((char *, DEF_FILE *, char *)); - -/* Structure handles processor directives. */ -typedef struct { - char *directive; - mk_handler_func_t *function; -} HANDLER_ENTRY; - -extern int builtin_handler __P((char *, DEF_FILE *, char *)); -extern int function_handler __P((char *, DEF_FILE *, char *)); -extern int short_doc_handler __P((char *, DEF_FILE *, char *)); -extern int comment_handler __P((char *, DEF_FILE *, char *)); -extern int depends_on_handler __P((char *, DEF_FILE *, char *)); -extern int produces_handler __P((char *, DEF_FILE *, char *)); -extern int end_handler __P((char *, DEF_FILE *, char *)); -extern int docname_handler __P((char *, DEF_FILE *, char *)); - -HANDLER_ENTRY handlers[] = { - { "BUILTIN", builtin_handler }, - { "DOCNAME", docname_handler }, - { "FUNCTION", function_handler }, - { "SHORT_DOC", short_doc_handler }, - { "$", comment_handler }, - { "COMMENT", comment_handler }, - { "DEPENDS_ON", depends_on_handler }, - { "PRODUCES", produces_handler }, - { "END", end_handler }, - { (char *)NULL, (mk_handler_func_t *)NULL } -}; - -/* Return the entry in the table of handlers for NAME. */ -HANDLER_ENTRY * -find_directive (directive) - char *directive; -{ - register int i; - - for (i = 0; handlers[i].directive; i++) - if (strcmp (handlers[i].directive, directive) == 0) - return (&handlers[i]); - - return ((HANDLER_ENTRY *)NULL); -} - -/* Non-zero indicates that a $BUILTIN has been seen, but not - the corresponding $END. */ -static int building_builtin = 0; - -/* Non-zero means to output cpp line and file information before - printing the current line to the production file. */ -int output_cpp_line_info = 0; - -/* The main function of this program. Read FILENAME and act on what is - found. Lines not starting with a dollar sign are copied to the - $PRODUCES target, if one is present. Lines starting with a dollar sign - are directives to this program, specifying the name of the builtin, the - function to call, the short documentation and the long documentation - strings. FILENAME can contain multiple $BUILTINs, but only one $PRODUCES - target. After the file has been processed, write out the names of - builtins found in each $BUILTIN. Plain text found before the $PRODUCES - is ignored, as is "$$ comment text". */ -void -extract_info (filename, structfile, externfile) - char *filename; - FILE *structfile, *externfile; -{ - register int i; - DEF_FILE *defs; - struct stat finfo; - size_t file_size; - char *buffer, *line; - int fd, nr; - - if (stat (filename, &finfo) == -1) - file_error (filename); - - fd = open (filename, O_RDONLY, 0666); - - if (fd == -1) - file_error (filename); - - file_size = (size_t)finfo.st_size; - buffer = xmalloc (1 + file_size); - - if ((nr = read (fd, buffer, file_size)) < 0) - file_error (filename); - - /* This is needed on WIN32, and does not hurt on Unix. */ - if (nr < file_size) - file_size = nr; - - close (fd); - - if (nr == 0) - { - fprintf (stderr, "mkbuiltins: %s: skipping zero-length file\n", filename); - return; - } - - /* Create and fill in the initial structure describing this file. */ - defs = (DEF_FILE *)xmalloc (sizeof (DEF_FILE)); - defs->filename = filename; - defs->lines = array_create (sizeof (char *)); - defs->line_number = 0; - defs->production = (char *)NULL; - defs->output = (FILE *)NULL; - defs->builtins = (ARRAY *)NULL; - - /* Build the array of lines. */ - i = 0; - while (i < file_size) - { - array_add (&buffer[i], defs->lines); - - while (buffer[i] != '\n' && i < file_size) - i++; - buffer[i++] = '\0'; - } - - /* Begin processing the input file. We don't write any output - until we have a file to write output to. */ - output_cpp_line_info = 1; - - /* Process each line in the array. */ - for (i = 0; line = defs->lines->array[i]; i++) - { - defs->line_number = i; - - if (*line == '$') - { - register int j; - char *directive; - HANDLER_ENTRY *handler; - - /* Isolate the directive. */ - for (j = 0; line[j] && !whitespace (line[j]); j++); - - directive = xmalloc (j); - strncpy (directive, line + 1, j - 1); - directive[j -1] = '\0'; - - /* Get the function handler and call it. */ - handler = find_directive (directive); - - if (!handler) - { - line_error (defs, "Unknown directive `%s'", directive); - free (directive); - continue; - } - else - { - /* Advance to the first non-whitespace character. */ - while (whitespace (line[j])) - j++; - - /* Call the directive handler with the FILE, and ARGS. */ - (*(handler->function)) (directive, defs, line + j); - } - free (directive); - } - else - { - if (building_builtin) - add_documentation (defs, line); - else if (defs->output) - { - if (output_cpp_line_info) - { - /* If we're handed an absolute pathname, don't prepend - the directory name. */ - if (defs->filename[0] == '/') - fprintf (defs->output, "#line %d \"%s\"\n", - defs->line_number + 1, defs->filename); - else - fprintf (defs->output, "#line %d \"%s%s\"\n", - defs->line_number + 1, - error_directory ? error_directory : "./", - defs->filename); - output_cpp_line_info = 0; - } - - fprintf (defs->output, "%s\n", line); - } - } - } - - /* Close the production file. */ - if (defs->output) - fclose (defs->output); - - /* The file has been processed. Write the accumulated builtins to - the builtins.c file, and write the extern definitions to the - builtext.h file. */ - write_builtins (defs, structfile, externfile); - - free (buffer); - free_defs (defs); -} - -#define free_safely(x) if (x) free (x) - -static void -free_builtin (builtin) - BUILTIN_DESC *builtin; -{ - register int i; - - free_safely (builtin->name); - free_safely (builtin->function); - free_safely (builtin->shortdoc); - free_safely (builtin->docname); - - if (builtin->longdoc) - array_free (builtin->longdoc); - - if (builtin->dependencies) - { - for (i = 0; builtin->dependencies->array[i]; i++) - free (builtin->dependencies->array[i]); - array_free (builtin->dependencies); - } -} - -/* Free all of the memory allocated to a DEF_FILE. */ -void -free_defs (defs) - DEF_FILE *defs; -{ - register int i; - register BUILTIN_DESC *builtin; - - if (defs->production) - free (defs->production); - - if (defs->lines) - array_free (defs->lines); - - if (defs->builtins) - { - for (i = 0; builtin = (BUILTIN_DESC *)defs->builtins->array[i]; i++) - { - free_builtin (builtin); - free (builtin); - } - array_free (defs->builtins); - } - free (defs); -} - -/* **************************************************************** */ -/* */ -/* The Handler Functions Themselves */ -/* */ -/* **************************************************************** */ - -/* Strip surrounding whitespace from STRING, and - return a pointer to the start of it. */ -char * -strip_whitespace (string) - char *string; -{ - while (whitespace (*string)) - string++; - - remove_trailing_whitespace (string); - return (string); -} - -/* Remove only the trailing whitespace from STRING. */ -void -remove_trailing_whitespace (string) - char *string; -{ - register int i; - - i = strlen (string) - 1; - - while (i > 0 && whitespace (string[i])) - i--; - - string[++i] = '\0'; -} - -/* Ensure that there is a argument in STRING and return it. - FOR_WHOM is the name of the directive which needs the argument. - DEFS is the DEF_FILE in which the directive is found. - If there is no argument, produce an error. */ -char * -get_arg (for_whom, defs, string) - char *for_whom, *string; - DEF_FILE *defs; -{ - char *new; - - new = strip_whitespace (string); - - if (!*new) - line_error (defs, "%s requires an argument", for_whom); - - return (savestring (new)); -} - -/* Error if not building a builtin. */ -void -must_be_building (directive, defs) - char *directive; - DEF_FILE *defs; -{ - if (!building_builtin) - line_error (defs, "%s must be inside of a $BUILTIN block", directive); -} - -/* Return the current builtin. */ -BUILTIN_DESC * -current_builtin (directive, defs) - char *directive; - DEF_FILE *defs; -{ - must_be_building (directive, defs); - if (defs->builtins) - return ((BUILTIN_DESC *)defs->builtins->array[defs->builtins->sindex - 1]); - else - return ((BUILTIN_DESC *)NULL); -} - -/* Add LINE to the long documentation for the current builtin. - Ignore blank lines until the first non-blank line has been seen. */ -void -add_documentation (defs, line) - DEF_FILE *defs; - char *line; -{ - register BUILTIN_DESC *builtin; - - builtin = current_builtin ("(implied LONGDOC)", defs); - - remove_trailing_whitespace (line); - - if (!*line && !builtin->longdoc) - return; - - if (!builtin->longdoc) - builtin->longdoc = array_create (sizeof (char *)); - - array_add (line, builtin->longdoc); -} - -/* How to handle the $BUILTIN directive. */ -int -builtin_handler (self, defs, arg) - char *self; - DEF_FILE *defs; - char *arg; -{ - BUILTIN_DESC *new; - char *name; - - /* If we are already building a builtin, we cannot start a new one. */ - if (building_builtin) - { - line_error (defs, "%s found before $END", self); - return (-1); - } - - output_cpp_line_info++; - - /* Get the name of this builtin, and stick it in the array. */ - name = get_arg (self, defs, arg); - - /* If this is the first builtin, create the array to hold them. */ - if (!defs->builtins) - defs->builtins = array_create (sizeof (BUILTIN_DESC *)); - - new = (BUILTIN_DESC *)xmalloc (sizeof (BUILTIN_DESC)); - new->name = name; - new->function = (char *)NULL; - new->shortdoc = (char *)NULL; - new->docname = (char *)NULL; - new->longdoc = (ARRAY *)NULL; - new->dependencies = (ARRAY *)NULL; - new->flags = 0; - - if (is_special_builtin (name)) - new->flags |= BUILTIN_FLAG_SPECIAL; - if (is_assignment_builtin (name)) - new->flags |= BUILTIN_FLAG_ASSIGNMENT; - if (is_posix_builtin (name)) - new->flags |= BUILTIN_FLAG_POSIX_BUILTIN; - - array_add ((char *)new, defs->builtins); - building_builtin = 1; - - return (0); -} - -/* How to handle the $FUNCTION directive. */ -int -function_handler (self, defs, arg) - char *self; - DEF_FILE *defs; - char *arg; -{ - register BUILTIN_DESC *builtin; - - builtin = current_builtin (self, defs); - - if (builtin == 0) - { - line_error (defs, "syntax error: no current builtin for $FUNCTION directive"); - exit (1); - } - if (builtin->function) - line_error (defs, "%s already has a function (%s)", - builtin->name, builtin->function); - else - builtin->function = get_arg (self, defs, arg); - - return (0); -} - -/* How to handle the $DOCNAME directive. */ -int -docname_handler (self, defs, arg) - char *self; - DEF_FILE *defs; - char *arg; -{ - register BUILTIN_DESC *builtin; - - builtin = current_builtin (self, defs); - - if (builtin->docname) - line_error (defs, "%s already had a docname (%s)", - builtin->name, builtin->docname); - else - builtin->docname = get_arg (self, defs, arg); - - return (0); -} - -/* How to handle the $SHORT_DOC directive. */ -int -short_doc_handler (self, defs, arg) - char *self; - DEF_FILE *defs; - char *arg; -{ - register BUILTIN_DESC *builtin; - - builtin = current_builtin (self, defs); - - if (builtin->shortdoc) - line_error (defs, "%s already has short documentation (%s)", - builtin->name, builtin->shortdoc); - else - builtin->shortdoc = get_arg (self, defs, arg); - - return (0); -} - -/* How to handle the $COMMENT directive. */ -int -comment_handler (self, defs, arg) - char *self; - DEF_FILE *defs; - char *arg; -{ - return (0); -} - -/* How to handle the $DEPENDS_ON directive. */ -int -depends_on_handler (self, defs, arg) - char *self; - DEF_FILE *defs; - char *arg; -{ - register BUILTIN_DESC *builtin; - char *dependent; - - builtin = current_builtin (self, defs); - dependent = get_arg (self, defs, arg); - - if (!builtin->dependencies) - builtin->dependencies = array_create (sizeof (char *)); - - array_add (dependent, builtin->dependencies); - - return (0); -} - -/* How to handle the $PRODUCES directive. */ -int -produces_handler (self, defs, arg) - char *self; - DEF_FILE *defs; - char *arg; -{ - /* If just hacking documentation, don't change any of the production - files. */ - if (only_documentation) - return (0); - - output_cpp_line_info++; - - if (defs->production) - line_error (defs, "%s already has a %s definition", defs->filename, self); - else - { - defs->production = get_arg (self, defs, arg); - - if (inhibit_production) - return (0); - - defs->output = fopen (defs->production, "w"); - - if (!defs->output) - file_error (defs->production); - - fprintf (defs->output, "/* %s, created from %s. */\n", - defs->production, defs->filename); - } - return (0); -} - -/* How to handle the $END directive. */ -int -end_handler (self, defs, arg) - char *self; - DEF_FILE *defs; - char *arg; -{ - must_be_building (self, defs); - building_builtin = 0; - return (0); -} - -/* **************************************************************** */ -/* */ -/* Error Handling Functions */ -/* */ -/* **************************************************************** */ - -/* Produce an error for DEFS with FORMAT and ARGS. */ -void -line_error (defs, format, arg1, arg2) - DEF_FILE *defs; - char *format, *arg1, *arg2; -{ - if (defs->filename[0] != '/') - fprintf (stderr, "%s", error_directory ? error_directory : "./"); - fprintf (stderr, "%s:%d:", defs->filename, defs->line_number + 1); - fprintf (stderr, format, arg1, arg2); - fprintf (stderr, "\n"); - fflush (stderr); -} - -/* Print error message for FILENAME. */ -void -file_error (filename) - char *filename; -{ - perror (filename); - exit (2); -} - -/* **************************************************************** */ -/* */ -/* xmalloc and xrealloc () */ -/* */ -/* **************************************************************** */ - -static void memory_error_and_abort (); - -static char * -xmalloc (bytes) - int bytes; -{ - char *temp = (char *)malloc (bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static char * -xrealloc (pointer, bytes) - char *pointer; - int bytes; -{ - char *temp; - - if (!pointer) - temp = (char *)malloc (bytes); - else - temp = (char *)realloc (pointer, bytes); - - if (!temp) - memory_error_and_abort (); - - return (temp); -} - -static void -memory_error_and_abort () -{ - fprintf (stderr, "mkbuiltins: out of virtual memory\n"); - abort (); -} - -/* **************************************************************** */ -/* */ -/* Creating the Struct and Extern Files */ -/* */ -/* **************************************************************** */ - -/* Return a pointer to a newly allocated builtin which is - an exact copy of BUILTIN. */ -BUILTIN_DESC * -copy_builtin (builtin) - BUILTIN_DESC *builtin; -{ - BUILTIN_DESC *new; - - new = (BUILTIN_DESC *)xmalloc (sizeof (BUILTIN_DESC)); - - new->name = savestring (builtin->name); - new->shortdoc = savestring (builtin->shortdoc); - new->longdoc = copy_string_array (builtin->longdoc); - new->dependencies = copy_string_array (builtin->dependencies); - - new->function = - builtin->function ? savestring (builtin->function) : (char *)NULL; - new->docname = - builtin->docname ? savestring (builtin->docname) : (char *)NULL; - - return (new); -} - -/* How to save away a builtin. */ -void -save_builtin (builtin) - BUILTIN_DESC *builtin; -{ - BUILTIN_DESC *newbuiltin; - - newbuiltin = copy_builtin (builtin); - - /* If this is the first builtin to be saved, create the array - to hold it. */ - if (!saved_builtins) - saved_builtins = array_create (sizeof (BUILTIN_DESC *)); - - array_add ((char *)newbuiltin, saved_builtins); -} - -/* Flags that mean something to write_documentation (). */ -#define STRING_ARRAY 0x01 -#define TEXINFO 0x02 -#define PLAINTEXT 0x04 -#define HELPFILE 0x08 - -char *structfile_header[] = { - "/* builtins.c -- the built in shell commands. */", - "", - "/* This file is manufactured by ./mkbuiltins, and should not be", - " edited by hand. See the source to mkbuiltins for details. */", - "", - "/* Copyright (C) 1987-2007 Free Software Foundation, Inc.", - "", - " This file is part of GNU Bash, the Bourne Again SHell.", - "", - " Bash is free software; you can 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. */", - "", - "/* The list of shell builtins. Each element is name, function, flags,", - " long-doc, short-doc. The long-doc field contains a pointer to an array", - " of help lines. The function takes a WORD_LIST *; the first word in the", - " list is the first arg to the command. The list has already had word", - " expansion performed.", - "", - " Functions which need to look at only the simple commands (e.g.", - " the enable_builtin ()), should ignore entries where", - " (array[i].function == (sh_builtin_func_t *)NULL). Such entries are for", - " the list of shell reserved control structures, like `if' and `while'.", - " The end of the list is denoted with a NULL name field. */", - "", - "#include \"../builtins.h\"", - (char *)NULL - }; - -char *structfile_footer[] = { - " { (char *)0x0, (sh_builtin_func_t *)0x0, 0, (char **)0x0, (char *)0x0 }", - "};", - "", - "struct builtin *shell_builtins = static_shell_builtins;", - "struct builtin *current_builtin;", - "", - "int num_shell_builtins =", - "\tsizeof (static_shell_builtins) / sizeof (struct builtin) - 1;", - (char *)NULL -}; - -/* Write out any neccessary opening information for - STRUCTFILE and EXTERNFILE. */ -void -write_file_headers (structfile, externfile) - FILE *structfile, *externfile; -{ - register int i; - - if (structfile) - { - for (i = 0; structfile_header[i]; i++) - fprintf (structfile, "%s\n", structfile_header[i]); - - fprintf (structfile, "#include \"%s\"\n", - extern_filename ? extern_filename : "builtext.h"); - - fprintf (structfile, "#include \"bashintl.h\"\n"); - - fprintf (structfile, "\nstruct builtin static_shell_builtins[] = {\n"); - } - - if (externfile) - fprintf (externfile, - "/* %s - The list of builtins found in libbuiltins.a. */\n", - extern_filename ? extern_filename : "builtext.h"); -} - -/* Write out any necessary closing information for - STRUCTFILE and EXTERNFILE. */ -void -write_file_footers (structfile, externfile) - FILE *structfile, *externfile; -{ - register int i; - - /* Write out the footers. */ - if (structfile) - { - for (i = 0; structfile_footer[i]; i++) - fprintf (structfile, "%s\n", structfile_footer[i]); - } -} - -/* Write out the information accumulated in DEFS to - STRUCTFILE and EXTERNFILE. */ -void -write_builtins (defs, structfile, externfile) - DEF_FILE *defs; - FILE *structfile, *externfile; -{ - register int i; - - /* Write out the information. */ - if (defs->builtins) - { - register BUILTIN_DESC *builtin; - - for (i = 0; i < defs->builtins->sindex; i++) - { - builtin = (BUILTIN_DESC *)defs->builtins->array[i]; - - /* Write out any #ifdefs that may be there. */ - if (!only_documentation) - { - if (builtin->dependencies) - { - write_ifdefs (externfile, builtin->dependencies->array); - write_ifdefs (structfile, builtin->dependencies->array); - } - - /* Write the extern definition. */ - if (externfile) - { - if (builtin->function) - fprintf (externfile, "extern int %s __P((WORD_LIST *));\n", - builtin->function); - - fprintf (externfile, "extern char * const %s_doc[];\n", - document_name (builtin)); - } - - /* Write the structure definition. */ - if (structfile) - { - fprintf (structfile, " { \"%s\", ", builtin->name); - - if (builtin->function) - fprintf (structfile, "%s, ", builtin->function); - else - fprintf (structfile, "(sh_builtin_func_t *)0x0, "); - - fprintf (structfile, "%s%s%s%s, %s_doc,\n", - "BUILTIN_ENABLED | STATIC_BUILTIN", - (builtin->flags & BUILTIN_FLAG_SPECIAL) ? " | SPECIAL_BUILTIN" : "", - (builtin->flags & BUILTIN_FLAG_ASSIGNMENT) ? " | ASSIGNMENT_BUILTIN" : "", - (builtin->flags & BUILTIN_FLAG_POSIX_BUILTIN) ? " | POSIX_BUILTIN" : "", - document_name (builtin)); - - fprintf - (structfile, " N_(\"%s\"), (char *)NULL },\n", - builtin->shortdoc ? builtin->shortdoc : builtin->name); - - } - - if (structfile || separate_helpfiles) - /* Save away this builtin for later writing of the - long documentation strings. */ - save_builtin (builtin); - - /* Write out the matching #endif, if neccessary. */ - if (builtin->dependencies) - { - if (externfile) - write_endifs (externfile, builtin->dependencies->array); - - if (structfile) - write_endifs (structfile, builtin->dependencies->array); - } - } - - if (documentation_file) - { - fprintf (documentation_file, "@item %s\n", builtin->name); - write_documentation - (documentation_file, builtin->longdoc->array, 0, TEXINFO); - } - } - } -} - -/* Write out the long documentation strings in BUILTINS to STREAM. */ -void -write_longdocs (stream, builtins) - FILE *stream; - ARRAY *builtins; -{ - register int i; - register BUILTIN_DESC *builtin; - char *dname; - char *sarray[2]; - - for (i = 0; i < builtins->sindex; i++) - { - builtin = (BUILTIN_DESC *)builtins->array[i]; - - if (builtin->dependencies) - write_ifdefs (stream, builtin->dependencies->array); - - /* Write the long documentation strings. */ - dname = document_name (builtin); - fprintf (stream, "char * const %s_doc[] =", dname); - - if (separate_helpfiles) - { - int l = strlen (helpfile_directory) + strlen (dname) + 1; - sarray[0] = (char *)xmalloc (l + 1); - sprintf (sarray[0], "%s/%s", helpfile_directory, dname); - sarray[1] = (char *)NULL; - write_documentation (stream, sarray, 0, STRING_ARRAY|HELPFILE); - free (sarray[0]); - } - else - write_documentation (stream, builtin->longdoc->array, 0, STRING_ARRAY); - - if (builtin->dependencies) - write_endifs (stream, builtin->dependencies->array); - - } -} - -/* Write an #ifdef string saying what needs to be defined (or not defined) - in order to allow compilation of the code that will follow. - STREAM is the stream to write the information to, - DEFINES is a null terminated array of define names. - If a define is preceded by an `!', then the sense of the test is - reversed. */ -void -write_ifdefs (stream, defines) - FILE *stream; - char **defines; -{ - register int i; - - if (!stream) - return; - - fprintf (stream, "#if "); - - for (i = 0; defines[i]; i++) - { - char *def = defines[i]; - - if (*def == '!') - fprintf (stream, "!defined (%s)", def + 1); - else - fprintf (stream, "defined (%s)", def); - - if (defines[i + 1]) - fprintf (stream, " && "); - } - fprintf (stream, "\n"); -} - -/* Write an #endif string saying what defines controlled the compilation - of the immediately preceding code. - STREAM is the stream to write the information to. - DEFINES is a null terminated array of define names. */ -void -write_endifs (stream, defines) - FILE *stream; - char **defines; -{ - register int i; - - if (!stream) - return; - - fprintf (stream, "#endif /* "); - - for (i = 0; defines[i]; i++) - { - fprintf (stream, "%s", defines[i]); - - if (defines[i + 1]) - fprintf (stream, " && "); - } - - fprintf (stream, " */\n"); -} - -/* Write DOCUMENTATION to STREAM, perhaps surrounding it with double-quotes - and quoting special characters in the string. Handle special things for - internationalization (gettext) and the single-string vs. multiple-strings - issues. */ -void -write_documentation (stream, documentation, indentation, flags) - FILE *stream; - char **documentation; - int indentation, flags; -{ - register int i, j; - register char *line; - int string_array, texinfo, base_indent, last_cpp, filename_p; - - if (stream == 0) - return; - - string_array = flags & STRING_ARRAY; - filename_p = flags & HELPFILE; - - if (string_array) - { - fprintf (stream, " {\n#if defined (HELP_BUILTIN)\n"); /* } */ - if (single_longdoc_strings) - { - if (filename_p == 0) - { - if (documentation && documentation[0] && documentation[0][0]) - fprintf (stream, "N_(\""); - else - fprintf (stream, "N_(\" "); /* the empty string translates specially. */ - } - else - fprintf (stream, "\""); - } - } - - base_indent = (string_array && single_longdoc_strings && filename_p == 0) ? BASE_INDENT : 0; - - for (i = last_cpp = 0, texinfo = (flags & TEXINFO); line = documentation[i]; i++) - { - /* Allow #ifdef's to be written out verbatim, but don't put them into - separate help files. */ - if (*line == '#') - { - if (string_array && filename_p == 0 && single_longdoc_strings == 0) - fprintf (stream, "%s\n", line); - last_cpp = 1; - continue; - } - else - last_cpp = 0; - - /* prefix with N_( for gettext */ - if (string_array && single_longdoc_strings == 0) - { - if (filename_p == 0) - { - if (line[0]) - fprintf (stream, " N_(\""); - else - fprintf (stream, " N_(\" "); /* the empty string translates specially. */ - } - else - fprintf (stream, " \""); - } - - if (indentation) - for (j = 0; j < indentation; j++) - fprintf (stream, " "); - - /* Don't indent the first line, because of how the help builtin works. */ - if (i == 0) - indentation += base_indent; - - if (string_array) - { - for (j = 0; line[j]; j++) - { - switch (line[j]) - { - case '\\': - case '"': - fprintf (stream, "\\%c", line[j]); - break; - - default: - fprintf (stream, "%c", line[j]); - } - } - - /* closing right paren for gettext */ - if (single_longdoc_strings == 0) - { - if (filename_p == 0) - fprintf (stream, "\"),\n"); - else - fprintf (stream, "\",\n"); - } - else if (documentation[i+1]) - /* don't add extra newline after last line */ - fprintf (stream, "\\n\\\n"); - } - else if (texinfo) - { - for (j = 0; line[j]; j++) - { - switch (line[j]) - { - case '@': - case '{': - case '}': - fprintf (stream, "@%c", line[j]); - break; - - default: - fprintf (stream, "%c", line[j]); - } - } - fprintf (stream, "\n"); - } - else - fprintf (stream, "%s\n", line); - } - - /* closing right paren for gettext */ - if (string_array && single_longdoc_strings) - { - if (filename_p == 0) - fprintf (stream, "\"),\n"); - else - fprintf (stream, "\",\n"); - } - - if (string_array) - fprintf (stream, "#endif /* HELP_BUILTIN */\n (char *)NULL\n};\n"); -} - -int -write_helpfiles (builtins) - ARRAY *builtins; -{ - char *helpfile, *bname; - FILE *helpfp; - int i, hdlen; - BUILTIN_DESC *builtin; - - i = mkdir ("helpfiles", 0777); - if (i < 0 && errno != EEXIST) - { - fprintf (stderr, "write_helpfiles: helpfiles: cannot create directory\n"); - return -1; - } - - hdlen = strlen ("helpfiles/"); - for (i = 0; i < builtins->sindex; i++) - { - builtin = (BUILTIN_DESC *)builtins->array[i]; - - bname = document_name (builtin); - helpfile = (char *)xmalloc (hdlen + strlen (bname) + 1); - sprintf (helpfile, "helpfiles/%s", bname); - - helpfp = fopen (helpfile, "w"); - if (helpfp == 0) - { - fprintf (stderr, "write_helpfiles: cannot open %s\n", helpfile); - free (helpfile); - continue; - } - - write_documentation (helpfp, builtin->longdoc->array, 4, PLAINTEXT); - - fflush (helpfp); - fclose (helpfp); - free (helpfile); - } - return 0; -} - -static int -_find_in_table (name, name_table) - char *name, *name_table[]; -{ - register int i; - - for (i = 0; name_table[i]; i++) - if (strcmp (name, name_table[i]) == 0) - return 1; - return 0; -} - -static int -is_special_builtin (name) - char *name; -{ - return (_find_in_table (name, special_builtins)); -} - -static int -is_assignment_builtin (name) - char *name; -{ - return (_find_in_table (name, assignment_builtins)); -} - -static int -is_posix_builtin (name) - char *name; -{ - return (_find_in_table (name, posix_builtins)); -} - -#if !defined (HAVE_RENAME) -static int -rename (from, to) - char *from, *to; -{ - unlink (to); - if (link (from, to) < 0) - return (-1); - unlink (from); - return (0); -} -#endif /* !HAVE_RENAME */ diff --git a/builtins/printf.def.save1 b/builtins/printf.def.save1 deleted file mode 100644 index 2b564cf0c..000000000 --- a/builtins/printf.def.save1 +++ /dev/null @@ -1,1057 +0,0 @@ -This file is printf.def, from which is created printf.c. -It implements the builtin "printf" in Bash. - -Copyright (C) 1997-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA - -$PRODUCES printf.c - -$BUILTIN printf -$FUNCTION printf_builtin -$SHORT_DOC printf [-v var] format [arguments] -Formats and prints ARGUMENTS under control of the FORMAT. - -Options: - -v var assign the output to shell variable VAR rather than - display it on the standard output - -FORMAT is a character string which contains three types of objects: plain -characters, which are simply copied to standard output; character escape -sequences, which are converted and copied to the standard output; and -format specifications, each of which causes printing of the next successive -argument. - -In addition to the standard format specifications described in printf(1) -and printf(3), printf interprets: - - %b expand backslash escape sequences in the corresponding argument - %q quote the argument in a way that can be reused as shell input -$END - -#include - -#include "../bashtypes.h" - -#include -#if defined (HAVE_LIMITS_H) -# include -#else - /* Assume 32-bit ints. */ -# define INT_MAX 2147483647 -# define INT_MIN (-2147483647-1) -#endif - -#if defined (PREFER_STDARG) -# include -#else -# include -#endif - -#include -#include - -#ifdef HAVE_INTTYPES_H -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "shmbutil.h" -#include "stdc.h" -#include "bashgetopt.h" -#include "common.h" - -#if defined (PRI_MACROS_BROKEN) -# undef PRIdMAX -#endif - -#if !defined (PRIdMAX) -# if HAVE_LONG_LONG -# define PRIdMAX "lld" -# else -# define PRIdMAX "ld" -# endif -#endif - -#if !defined (errno) -extern int errno; -#endif - -#define PC(c) \ - do { \ - char b[2]; \ - tw++; \ - b[0] = c; b[1] = '\0'; \ - if (vflag) \ - vbadd (b, 1); \ - else \ - putchar (c); \ - } while (0) - -#define PF(f, func) \ - do { \ - char *b = 0; \ - int nw; \ - clearerr (stdout); \ - if (have_fieldwidth && have_precision) \ - nw = asprintf(&b, f, fieldwidth, precision, func); \ - else if (have_fieldwidth) \ - nw = asprintf(&b, f, fieldwidth, func); \ - else if (have_precision) \ - nw = asprintf(&b, f, precision, func); \ - else \ - nw = asprintf(&b, f, func); \ - tw += nw; \ - if (b) \ - { \ - if (vflag) \ - (void)vbadd (b, nw); \ - else \ - (void)fputs (b, stdout); \ - if (ferror (stdout)) \ - { \ - sh_wrerror (); \ - clearerr (stdout); \ - return (EXECUTION_FAILURE); \ - } \ - free (b); \ - } \ - } while (0) - -/* We free the buffer used by mklong() if it's `too big'. */ -#define PRETURN(value) \ - do \ - { \ - if (vflag) \ - { \ - bind_variable (vname, vbuf, 0); \ - stupidly_hack_special_variables (vname); \ - } \ - if (conv_bufsize > 4096 ) \ - { \ - free (conv_buf); \ - conv_bufsize = 0; \ - conv_buf = 0; \ - } \ - if (vbsize > 4096) \ - { \ - free (vbuf); \ - vbsize = 0; \ - vbuf = 0; \ - } \ - else if (vbuf) \ - vbuf[0] = 0; \ - fflush (stdout); \ - if (ferror (stdout)) \ - { \ - clearerr (stdout); \ - return (EXECUTION_FAILURE); \ - } \ - return (value); \ - } \ - while (0) - -#define SKIP1 "#'-+ 0" -#define LENMODS "hjlLtz" - -#ifndef HAVE_ASPRINTF -extern int asprintf __P((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3))); -#endif - -#ifndef HAVE_VSNPRINTF -extern int vsnprintf __P((char *, size_t, const char *, ...)) __attribute__((__format__ (printf, 3, 4))); -#endif - -static void printf_erange __P((char *)); -static int printstr __P((char *, char *, int, int, int)); -static int tescape __P((char *, char *, int *)); -static char *bexpand __P((char *, int, int *, int *)); -static char *vbadd __P((char *, int)); -static char *mklong __P((char *, char *, size_t)); -static int getchr __P((void)); -static char *getstr __P((void)); -static int getint __P((void)); -static intmax_t getintmax __P((void)); -static uintmax_t getuintmax __P((void)); - -#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN) -typedef long double floatmax_t; -# define FLOATMAX_CONV "L" -# define strtofltmax strtold -#else -typedef double floatmax_t; -# define FLOATMAX_CONV "" -# define strtofltmax strtod -#endif -static floatmax_t getfloatmax __P((void)); - -static intmax_t asciicode __P((void)); - -static WORD_LIST *garglist; -static int retval; -static int conversion_error; - -/* printf -v var support */ -static int vflag = 0; -static char *vbuf, *vname; -static size_t vbsize; -static int vblen; - -static intmax_t tw; - -static char *conv_buf; -static size_t conv_bufsize; - -int -printf_builtin (list) - WORD_LIST *list; -{ - int ch, fieldwidth, precision; - int have_fieldwidth, have_precision; - char convch, thisch, nextch, *format, *modstart, *fmt, *start; - - conversion_error = 0; - retval = EXECUTION_SUCCESS; - - vflag = 0; - - reset_internal_getopt (); - while ((ch = internal_getopt (list, "v:")) != -1) - { - switch (ch) - { - case 'v': - if (legal_identifier (vname = list_optarg)) - { - vflag = 1; - vblen = 0; - if (vbuf) - vbuf[0] = 0; - } - else - { - sh_invalidid (vname); - return (EX_USAGE); - } - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; /* skip over possible `--' */ - - if (list == 0) - { - builtin_usage (); - return (EX_USAGE); - } - - if (list->word->word == 0 || list->word->word[0] == '\0') - return (EXECUTION_SUCCESS); - - format = list->word->word; - tw = 0; - - garglist = list->next; - - /* If the format string is empty after preprocessing, return immediately. */ - if (format == 0 || *format == 0) - return (EXECUTION_SUCCESS); - - /* Basic algorithm is to scan the format string for conversion - specifications -- once one is found, find out if the field - width or precision is a '*'; if it is, gather up value. Note, - format strings are reused as necessary to use up the provided - arguments, arguments of zero/null string are provided to use - up the format string. */ - do - { - tw = 0; - /* find next format specification */ - for (fmt = format; *fmt; fmt++) - { - precision = fieldwidth = 0; - have_fieldwidth = have_precision = 0; - - if (*fmt == '\\') - { - fmt++; - /* A NULL third argument to tescape means to bypass the - special processing for arguments to %b. */ - fmt += tescape (fmt, &nextch, (int *)NULL); - PC (nextch); - fmt--; /* for loop will increment it for us again */ - continue; - } - - if (*fmt != '%') - { - PC (*fmt); - continue; - } - - /* ASSERT(*fmt == '%') */ - start = fmt++; - - if (*fmt == '%') /* %% prints a % */ - { - PC ('%'); - continue; - } - - /* found format specification, skip to field width */ - for (; *fmt && strchr(SKIP1, *fmt); ++fmt) - ; - - /* Skip optional field width. */ - if (*fmt == '*') - { - fmt++; - have_fieldwidth = 1; - fieldwidth = getint (); - } - else - while (DIGIT (*fmt)) - fmt++; - - /* Skip optional '.' and precision */ - if (*fmt == '.') - { - ++fmt; - if (*fmt == '*') - { - fmt++; - have_precision = 1; - precision = getint (); - } - else - { - /* Negative precisions are allowed but treated as if the - precision were missing; I would like to allow a leading - `+' in the precision number as an extension, but lots - of asprintf/fprintf implementations get this wrong. */ -#if 0 - if (*fmt == '-' || *fmt == '+') -#else - if (*fmt == '-') -#endif - fmt++; - while (DIGIT (*fmt)) - fmt++; - } - } - - /* skip possible format modifiers */ - modstart = fmt; - while (*fmt && strchr (LENMODS, *fmt)) - fmt++; - - if (*fmt == 0) - { - builtin_error (_("`%s': missing format character"), start); - PRETURN (EXECUTION_FAILURE); - } - - convch = *fmt; - thisch = modstart[0]; - nextch = modstart[1]; - modstart[0] = convch; - modstart[1] = '\0'; - - switch(convch) - { - case 'c': - { - char p; - - p = getchr (); - PF(start, p); - break; - } - - case 's': - { - char *p; - - p = getstr (); - PF(start, p); - break; - } - - case 'n': - { - char *var; - - var = getstr (); - if (var && *var) - { - if (legal_identifier (var)) - bind_var_to_int (var, tw); - else - { - sh_invalidid (var); - PRETURN (EXECUTION_FAILURE); - } - } - break; - } - - case 'b': /* expand escapes in argument */ - { - char *p, *xp; - int rlen, r; - - p = getstr (); - ch = rlen = r = 0; - xp = bexpand (p, strlen (p), &ch, &rlen); - - if (xp) - { - /* Have to use printstr because of possible NUL bytes - in XP -- printf does not handle that well. */ - r = printstr (start, xp, rlen, fieldwidth, precision); - if (r < 0) - { - sh_wrerror (); - clearerr (stdout); - retval = EXECUTION_FAILURE; - } - free (xp); - } - - if (ch || r < 0) - PRETURN (retval); - break; - } - - case 'q': /* print with shell quoting */ - { - char *p, *xp; - int r; - - r = 0; - p = getstr (); - if (p && *p == 0) /* XXX - getstr never returns null */ - xp = savestring ("''"); - else if (ansic_shouldquote (p)) - xp = ansic_quote (p, 0, (int *)0); - else - xp = sh_backslash_quote (p); - if (xp) - { - /* Use printstr to get fieldwidth and precision right. */ - r = printstr (start, xp, strlen (xp), fieldwidth, precision); - if (r < 0) - { - sh_wrerror (); - clearerr (stdout); - } - free (xp); - } - - if (r < 0) - PRETURN (EXECUTION_FAILURE); - break; - } - - case 'd': - case 'i': - { - char *f; - long p; - intmax_t pp; - - p = pp = getintmax (); - if (p != pp) - { - f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2); - PF (f, pp); - } - else - { - /* Optimize the common case where the integer fits - in "long". This also works around some long - long and/or intmax_t library bugs in the common - case, e.g. glibc 2.2 x86. */ - f = mklong (start, "l", 1); - PF (f, p); - } - break; - } - - case 'o': - case 'u': - case 'x': - case 'X': - { - char *f; - unsigned long p; - uintmax_t pp; - - p = pp = getuintmax (); - if (p != pp) - { - f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2); - PF (f, pp); - } - else - { - f = mklong (start, "l", 1); - PF (f, p); - } - break; - } - - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': -#if defined (HAVE_PRINTF_A_FORMAT) - case 'a': - case 'A': -#endif - { - char *f; - floatmax_t p; - - p = getfloatmax (); - f = mklong (start, FLOATMAX_CONV, sizeof(FLOATMAX_CONV) - 1); - PF (f, p); - break; - } - - /* We don't output unrecognized format characters; we print an - error message and return a failure exit status. */ - default: - builtin_error (_("`%c': invalid format character"), convch); - PRETURN (EXECUTION_FAILURE); - } - - modstart[0] = thisch; - modstart[1] = nextch; - } - - if (ferror (stdout)) - { - sh_wrerror (); - clearerr (stdout); - PRETURN (EXECUTION_FAILURE); - } - } - while (garglist && garglist != list->next); - - if (conversion_error) - retval = EXECUTION_FAILURE; - - PRETURN (retval); -} - -static void -printf_erange (s) - char *s; -{ - builtin_error (_("warning: %s: %s"), s, strerror(ERANGE)); -} - -/* We duplicate a lot of what printf(3) does here. */ -static int -printstr (fmt, string, len, fieldwidth, precision) - char *fmt; /* format */ - char *string; /* expanded string argument */ - int len; /* length of expanded string */ - int fieldwidth; /* argument for width of `*' */ - int precision; /* argument for precision of `*' */ -{ -#if 0 - char *s; -#endif - int padlen, nc, ljust, i; - int fw, pr; /* fieldwidth and precision */ - -#if 0 - if (string == 0 || *string == '\0') -#else - if (string == 0 || len == 0) -#endif - return; - -#if 0 - s = fmt; -#endif - if (*fmt == '%') - fmt++; - - ljust = fw = 0; - pr = -1; - - /* skip flags */ - while (strchr (SKIP1, *fmt)) - { - if (*fmt == '-') - ljust = 1; - fmt++; - } - - /* get fieldwidth, if present */ - if (*fmt == '*') - { - fmt++; - fw = fieldwidth; - if (fw < 0) - { - fw = -fw; - ljust = 1; - } - } - else if (DIGIT (*fmt)) - { - fw = *fmt++ - '0'; - while (DIGIT (*fmt)) - fw = (fw * 10) + (*fmt++ - '0'); - } - - /* get precision, if present */ - if (*fmt == '.') - { - fmt++; - if (*fmt == '*') - { - fmt++; - pr = precision; - } - else if (DIGIT (*fmt)) - { - pr = *fmt++ - '0'; - while (DIGIT (*fmt)) - pr = (pr * 10) + (*fmt++ - '0'); - } - } - -#if 0 - /* If we remove this, get rid of `s'. */ - if (*fmt != 'b' && *fmt != 'q') - { - internal_error ("format parsing problem: %s", s); - fw = pr = 0; - } -#endif - - /* chars from string to print */ - nc = (pr >= 0 && pr <= len) ? pr : len; - - padlen = fw - nc; - if (padlen < 0) - padlen = 0; - if (ljust) - padlen = -padlen; - - /* leading pad characters */ - for (; padlen > 0; padlen--) - PC (' '); - - /* output NC characters from STRING */ - for (i = 0; i < nc; i++) - PC (string[i]); - - /* output any necessary trailing padding */ - for (; padlen < 0; padlen++) - PC (' '); - - return (ferror (stdout) ? -1 : 0); -} - -/* Convert STRING by expanding the escape sequences specified by the - POSIX standard for printf's `%b' format string. If SAWC is non-null, - perform the processing appropriate for %b arguments. In particular, - recognize `\c' and use that as a string terminator. If we see \c, set - *SAWC to 1 before returning. LEN is the length of STRING. */ - -/* Translate a single backslash-escape sequence starting at ESTART (the - character after the backslash) and return the number of characters - consumed by the sequence. CP is the place to return the translated - value. *SAWC is set to 1 if the escape sequence was \c, since that means - to short-circuit the rest of the processing. If SAWC is null, we don't - do the \c short-circuiting, and \c is treated as an unrecognized escape - sequence; we also bypass the other processing specific to %b arguments. */ -static int -tescape (estart, cp, sawc) - char *estart; - char *cp; - int *sawc; -{ - register char *p; - int temp, c, evalue; - - p = estart; - - switch (c = *p++) - { -#if defined (__STDC__) - case 'a': *cp = '\a'; break; -#else - case 'a': *cp = '\007'; break; -#endif - - case 'b': *cp = '\b'; break; - - case 'e': - case 'E': *cp = '\033'; break; /* ESC -- non-ANSI */ - - case 'f': *cp = '\f'; break; - - case 'n': *cp = '\n'; break; - - case 'r': *cp = '\r'; break; - - case 't': *cp = '\t'; break; - - case 'v': *cp = '\v'; break; - - /* The octal escape sequences are `\0' followed by up to three octal - digits (if SAWC), or `\' followed by up to three octal digits (if - !SAWC). As an extension, we allow the latter form even if SAWC. */ - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - evalue = OCTVALUE (c); - for (temp = 2 + (!evalue && !!sawc); ISOCTAL (*p) && temp--; p++) - evalue = (evalue * 8) + OCTVALUE (*p); - *cp = evalue & 0xFF; - break; - - /* And, as another extension, we allow \xNNN, where each N is a - hex digit. */ - case 'x': -#if 0 - for (evalue = 0; ISXDIGIT ((unsigned char)*p); p++) -#else - for (temp = 2, evalue = 0; ISXDIGIT ((unsigned char)*p) && temp--; p++) -#endif - evalue = (evalue * 16) + HEXVALUE (*p); - if (p == estart + 1) - { - builtin_error (_("missing hex digit for \\x")); - *cp = '\\'; - return 0; - } - *cp = evalue & 0xFF; - break; - - case '\\': /* \\ -> \ */ - *cp = c; - break; - - /* SAWC == 0 means that \', \", and \? are recognized as escape - sequences, though the only processing performed is backslash - removal. */ - case '\'': case '"': case '?': - if (!sawc) - *cp = c; - else - { - *cp = '\\'; - return 0; - } - break; - - case 'c': - if (sawc) - { - *sawc = 1; - break; - } - /* other backslash escapes are passed through unaltered */ - default: - *cp = '\\'; - return 0; - } - return (p - estart); -} - -static char * -bexpand (string, len, sawc, lenp) - char *string; - int len, *sawc, *lenp; -{ - int temp; - char *ret, *r, *s, c; - -#if 0 - if (string == 0 || *string == '\0') -#else - if (string == 0 || len == 0) -#endif - { - if (sawc) - *sawc = 0; - if (lenp) - *lenp = 0; - return ((char *)NULL); - } - - ret = (char *)xmalloc (len + 1); - for (r = ret, s = string; s && *s; ) - { - c = *s++; - if (c != '\\' || *s == '\0') - { - *r++ = c; - continue; - } - temp = 0; - s += tescape (s, &c, &temp); - if (temp) - { - if (sawc) - *sawc = 1; - break; - } - - *r++ = c; - } - - *r = '\0'; - if (lenp) - *lenp = r - ret; - return ret; -} - -static char * -vbadd (buf, blen) - char *buf; - int blen; -{ - size_t nlen; - - nlen = vblen + blen + 1; - if (nlen >= vbsize) - { - vbsize = ((nlen + 63) >> 6) << 6; - vbuf = (char *)xrealloc (vbuf, vbsize); - } - - if (blen == 1) - vbuf[vblen++] = buf[0]; - else if (blen > 1) - { - FASTCOPY (buf, vbuf + vblen, blen); - vblen += blen; - } - vbuf[vblen] = '\0'; - -#ifdef DEBUG - if (strlen (vbuf) != vblen) - internal_error ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, (int)strlen (vbuf)); -#endif - - return vbuf; -} - -static char * -mklong (str, modifiers, mlen) - char *str; - char *modifiers; - size_t mlen; -{ - size_t len, slen; - - slen = strlen (str); - len = slen + mlen + 1; - - if (len > conv_bufsize) - { - conv_bufsize = (((len + 1023) >> 10) << 10); - conv_buf = (char *)xrealloc (conv_buf, conv_bufsize); - } - - FASTCOPY (str, conv_buf, slen - 1); - FASTCOPY (modifiers, conv_buf + slen - 1, mlen); - - conv_buf[len - 2] = str[slen - 1]; - conv_buf[len - 1] = '\0'; - return (conv_buf); -} - -static int -getchr () -{ - int ret; - - if (garglist == 0) - return ('\0'); - - ret = (int)garglist->word->word[0]; - garglist = garglist->next; - return ret; -} - -static char * -getstr () -{ - char *ret; - - if (garglist == 0) - return (""); - - ret = garglist->word->word; - garglist = garglist->next; - return ret; -} - -static int -getint () -{ - intmax_t ret; - - ret = getintmax (); - - if (ret > INT_MAX) - { - printf_erange (garglist->word->word); - ret = INT_MAX; - } - else if (ret < INT_MIN) - { - printf_erange (garglist->word->word); - ret = INT_MIN; - } - - return ((int)ret); -} - -static intmax_t -getintmax () -{ - intmax_t ret; - char *ep; - - if (garglist == 0) - return (0); - - if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') - return asciicode (); - - errno = 0; - ret = strtoimax (garglist->word->word, &ep, 0); - - if (*ep) - { - sh_invalidnum (garglist->word->word); - /* POSIX.2 says ``...a diagnostic message shall be written to standard - error, and the utility shall not exit with a zero exit status, but - shall continue processing any remaining operands and shall write the - value accumulated at the time the error was detected to standard - output.'' Yecch. */ - ret = 0; - conversion_error = 1; - } - else if (errno == ERANGE) - printf_erange (garglist->word->word); - - garglist = garglist->next; - return (ret); -} - -static uintmax_t -getuintmax () -{ - uintmax_t ret; - char *ep; - - if (garglist == 0) - return (0); - - if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') - return asciicode (); - - errno = 0; - ret = strtoumax (garglist->word->word, &ep, 0); - - if (*ep) - { - sh_invalidnum (garglist->word->word); - /* Same POSIX.2 conversion error requirements as getintmax(). */ - ret = 0; - conversion_error = 1; - } - else if (errno == ERANGE) - printf_erange (garglist->word->word); - - garglist = garglist->next; - return (ret); -} - -static floatmax_t -getfloatmax () -{ - floatmax_t ret; - char *ep; - - if (garglist == 0) - return (0); - - if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') - return asciicode (); - - errno = 0; - ret = strtofltmax (garglist->word->word, &ep); - - if (*ep) - { - sh_invalidnum (garglist->word->word); - /* Same thing about POSIX.2 conversion error requirements. */ - ret = 0; - conversion_error = 1; - } - else if (errno == ERANGE) - printf_erange (garglist->word->word); - - garglist = garglist->next; - return (ret); -} - -/* NO check is needed for garglist here. */ -static intmax_t -asciicode () -{ - register intmax_t ch; -#if defined (HANDLE_MULTIBYTE) - wchar_t wc; - size_t mblength, slen; -#endif - DECLARE_MBSTATE; - -#if defined (HANDLE_MULTIBYTE) - slen = strlen (garglist->word->word+1); - mblength = MBLEN (garglist->word->word+1, slen); - if (mblength > 1) - { - mblength = mbtowc (&wc, garglist->word->word+1, slen); - ch = wc; /* XXX */ - } - else -#endif - ch = (unsigned char)garglist->word->word[1]; - - garglist = garglist->next; - return (ch); -} diff --git a/builtins/printf.def~ b/builtins/printf.def~ deleted file mode 100644 index 7f07d156c..000000000 --- a/builtins/printf.def~ +++ /dev/null @@ -1,1091 +0,0 @@ -This file is printf.def, from which is created printf.c. -It implements the builtin "printf" in Bash. - -Copyright (C) 1997-2009 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Bash is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Bash. If not, see . - -$PRODUCES printf.c - -$BUILTIN printf -$FUNCTION printf_builtin -$SHORT_DOC printf [-v var] format [arguments] -Formats and prints ARGUMENTS under control of the FORMAT. - -Options: - -v var assign the output to shell variable VAR rather than - display it on the standard output - -FORMAT is a character string which contains three types of objects: plain -characters, which are simply copied to standard output; character escape -sequences, which are converted and copied to the standard output; and -format specifications, each of which causes printing of the next successive -argument. - -In addition to the standard format specifications described in printf(1) -and printf(3), printf interprets: - - %b expand backslash escape sequences in the corresponding argument - %q quote the argument in a way that can be reused as shell input - -Exit Status: -Returns success unless an invalid option is given or a write or assignment -error occurs. -$END - -#include - -#include "../bashtypes.h" - -#include -#if defined (HAVE_LIMITS_H) -# include -#else - /* Assume 32-bit ints. */ -# define INT_MAX 2147483647 -# define INT_MIN (-2147483647-1) -#endif - -#if defined (PREFER_STDARG) -# include -#else -# include -#endif - -#include -#include - -#ifdef HAVE_INTTYPES_H -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "shmbutil.h" -#include "stdc.h" -#include "bashgetopt.h" -#include "common.h" - -#if defined (PRI_MACROS_BROKEN) -# undef PRIdMAX -#endif - -#if !defined (PRIdMAX) -# if HAVE_LONG_LONG -# define PRIdMAX "lld" -# else -# define PRIdMAX "ld" -# endif -#endif - -#if !defined (errno) -extern int errno; -#endif - -#define PC(c) \ - do { \ - char b[2]; \ - tw++; \ - b[0] = c; b[1] = '\0'; \ - if (vflag) \ - vbadd (b, 1); \ - else \ - putchar (c); \ - } while (0) - -#define PF(f, func) \ - do { \ - int nw; \ - clearerr (stdout); \ - if (have_fieldwidth && have_precision) \ - nw = vflag ? vbprintf (f, fieldwidth, precision, func) : printf (f, fieldwidth, precision, func); \ - else if (have_fieldwidth) \ - nw = vflag ? vbprintf (f, fieldwidth, func) : printf (f, fieldwidth, func); \ - else if (have_precision) \ - nw = vflag ? vbprintf (f, precision, func) : printf (f, fieldwidth, func); \ - else \ - nw = vflag ? vbprintf (f, func) : printf (f, func); \ - tw += nw; \ - if (ferror (stdout)) \ - { \ - sh_wrerror (); \ - clearerr (stdout); \ - return (EXECUTION_FAILURE); \ - } \ - } while (0) - -/* We free the buffer used by mklong() if it's `too big'. */ -#define PRETURN(value) \ - do \ - { \ - if (vflag) \ - { \ - bind_variable (vname, vbuf, 0); \ - stupidly_hack_special_variables (vname); \ - } \ - if (conv_bufsize > 4096 ) \ - { \ - free (conv_buf); \ - conv_bufsize = 0; \ - conv_buf = 0; \ - } \ - if (vbsize > 4096) \ - { \ - free (vbuf); \ - vbsize = 0; \ - vbuf = 0; \ - } \ - else if (vbuf) \ - vbuf[0] = 0; \ - terminate_immediately--; \ - fflush (stdout); \ - if (ferror (stdout)) \ - { \ - clearerr (stdout); \ - return (EXECUTION_FAILURE); \ - } \ - return (value); \ - } \ - while (0) - -#define SKIP1 "#'-+ 0" -#define LENMODS "hjlLtz" - -#ifndef HAVE_ASPRINTF -extern int asprintf __P((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3))); -#endif - -#ifndef HAVE_VSNPRINTF -extern int vsnprintf __P((char *, size_t, const char *, ...)) __attribute__((__format__ (printf, 3, 4))); -#endif - -static void printf_erange __P((char *)); -static int printstr __P((char *, char *, int, int, int)); -static int tescape __P((char *, char *, int *)); -static char *bexpand __P((char *, int, int *, int *)); -static char *vbadd __P((char *, int)); -static int vbprintf __P((const char *, ...)) __attribute__((__format__ (printf, 1, 2))); -static char *mklong __P((char *, char *, size_t)); -static int getchr __P((void)); -static char *getstr __P((void)); -static int getint __P((void)); -static intmax_t getintmax __P((void)); -static uintmax_t getuintmax __P((void)); - -#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN) -typedef long double floatmax_t; -# define FLOATMAX_CONV "L" -# define strtofltmax strtold -#else -typedef double floatmax_t; -# define FLOATMAX_CONV "" -# define strtofltmax strtod -#endif -static floatmax_t getfloatmax __P((void)); - -static intmax_t asciicode __P((void)); - -static WORD_LIST *garglist; -static int retval; -static int conversion_error; - -/* printf -v var support */ -static int vflag = 0; -static char *vbuf, *vname; -static size_t vbsize; -static int vblen; - -static intmax_t tw; - -static char *conv_buf; -static size_t conv_bufsize; - -int -printf_builtin (list) - WORD_LIST *list; -{ - int ch, fieldwidth, precision; - int have_fieldwidth, have_precision; - char convch, thisch, nextch, *format, *modstart, *fmt, *start; - - conversion_error = 0; - retval = EXECUTION_SUCCESS; - - vflag = 0; - - reset_internal_getopt (); - while ((ch = internal_getopt (list, "v:")) != -1) - { - switch (ch) - { - case 'v': - if (legal_identifier (vname = list_optarg)) - { - vflag = 1; - vblen = 0; - if (vbuf) - vbuf[0] = 0; - } - else - { - sh_invalidid (vname); - return (EX_USAGE); - } - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; /* skip over possible `--' */ - - if (list == 0) - { - builtin_usage (); - return (EX_USAGE); - } - - if (list->word->word == 0 || list->word->word[0] == '\0') - return (EXECUTION_SUCCESS); - - format = list->word->word; - tw = 0; - - garglist = list->next; - - /* If the format string is empty after preprocessing, return immediately. */ - if (format == 0 || *format == 0) - return (EXECUTION_SUCCESS); - - terminate_immediately++; - - /* Basic algorithm is to scan the format string for conversion - specifications -- once one is found, find out if the field - width or precision is a '*'; if it is, gather up value. Note, - format strings are reused as necessary to use up the provided - arguments, arguments of zero/null string are provided to use - up the format string. */ - do - { - tw = 0; - /* find next format specification */ - for (fmt = format; *fmt; fmt++) - { - precision = fieldwidth = 0; - have_fieldwidth = have_precision = 0; - - if (*fmt == '\\') - { - fmt++; - /* A NULL third argument to tescape means to bypass the - special processing for arguments to %b. */ - fmt += tescape (fmt, &nextch, (int *)NULL); - PC (nextch); - fmt--; /* for loop will increment it for us again */ - continue; - } - - if (*fmt != '%') - { - PC (*fmt); - continue; - } - - /* ASSERT(*fmt == '%') */ - start = fmt++; - - if (*fmt == '%') /* %% prints a % */ - { - PC ('%'); - continue; - } - - /* found format specification, skip to field width */ - for (; *fmt && strchr(SKIP1, *fmt); ++fmt) - ; - - /* Skip optional field width. */ - if (*fmt == '*') - { - fmt++; - have_fieldwidth = 1; - fieldwidth = getint (); - } - else - while (DIGIT (*fmt)) - fmt++; - - /* Skip optional '.' and precision */ - if (*fmt == '.') - { - ++fmt; - if (*fmt == '*') - { - fmt++; - have_precision = 1; - precision = getint (); - } - else - { - /* Negative precisions are allowed but treated as if the - precision were missing; I would like to allow a leading - `+' in the precision number as an extension, but lots - of asprintf/fprintf implementations get this wrong. */ -#if 0 - if (*fmt == '-' || *fmt == '+') -#else - if (*fmt == '-') -#endif - fmt++; - while (DIGIT (*fmt)) - fmt++; - } - } - - /* skip possible format modifiers */ - modstart = fmt; - while (*fmt && strchr (LENMODS, *fmt)) - fmt++; - - if (*fmt == 0) - { - builtin_error (_("`%s': missing format character"), start); - PRETURN (EXECUTION_FAILURE); - } - - convch = *fmt; - thisch = modstart[0]; - nextch = modstart[1]; - modstart[0] = convch; - modstart[1] = '\0'; - - switch(convch) - { - case 'c': - { - char p; - - p = getchr (); - PF(start, p); - break; - } - - case 's': - { - char *p; - - p = getstr (); - PF(start, p); - break; - } - - case 'n': - { - char *var; - - var = getstr (); - if (var && *var) - { - if (legal_identifier (var)) - bind_var_to_int (var, tw); - else - { - sh_invalidid (var); - PRETURN (EXECUTION_FAILURE); - } - } - break; - } - - case 'b': /* expand escapes in argument */ - { - char *p, *xp; - int rlen, r; - - p = getstr (); - ch = rlen = r = 0; - xp = bexpand (p, strlen (p), &ch, &rlen); - - if (xp) - { - /* Have to use printstr because of possible NUL bytes - in XP -- printf does not handle that well. */ - r = printstr (start, xp, rlen, fieldwidth, precision); - if (r < 0) - { - sh_wrerror (); - clearerr (stdout); - retval = EXECUTION_FAILURE; - } - free (xp); - } - - if (ch || r < 0) - PRETURN (retval); - break; - } - - case 'q': /* print with shell quoting */ - { - char *p, *xp; - int r; - - r = 0; - p = getstr (); - if (p && *p == 0) /* XXX - getstr never returns null */ - xp = savestring ("''"); - else if (ansic_shouldquote (p)) - xp = ansic_quote (p, 0, (int *)0); - else - xp = sh_backslash_quote (p); - if (xp) - { - /* Use printstr to get fieldwidth and precision right. */ - r = printstr (start, xp, strlen (xp), fieldwidth, precision); - if (r < 0) - { - sh_wrerror (); - clearerr (stdout); - } - free (xp); - } - - if (r < 0) - PRETURN (EXECUTION_FAILURE); - break; - } - - case 'd': - case 'i': - { - char *f; - long p; - intmax_t pp; - - p = pp = getintmax (); - if (p != pp) - { - f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2); - PF (f, pp); - } - else - { - /* Optimize the common case where the integer fits - in "long". This also works around some long - long and/or intmax_t library bugs in the common - case, e.g. glibc 2.2 x86. */ - f = mklong (start, "l", 1); - PF (f, p); - } - break; - } - - case 'o': - case 'u': - case 'x': - case 'X': - { - char *f; - unsigned long p; - uintmax_t pp; - - p = pp = getuintmax (); - if (p != pp) - { - f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2); - PF (f, pp); - } - else - { - f = mklong (start, "l", 1); - PF (f, p); - } - break; - } - - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': -#if defined (HAVE_PRINTF_A_FORMAT) - case 'a': - case 'A': -#endif - { - char *f; - floatmax_t p; - - p = getfloatmax (); - f = mklong (start, FLOATMAX_CONV, sizeof(FLOATMAX_CONV) - 1); - PF (f, p); - break; - } - - /* We don't output unrecognized format characters; we print an - error message and return a failure exit status. */ - default: - builtin_error (_("`%c': invalid format character"), convch); - PRETURN (EXECUTION_FAILURE); - } - - modstart[0] = thisch; - modstart[1] = nextch; - } - - if (ferror (stdout)) - { - sh_wrerror (); - clearerr (stdout); - PRETURN (EXECUTION_FAILURE); - } - } - while (garglist && garglist != list->next); - - if (conversion_error) - retval = EXECUTION_FAILURE; - - PRETURN (retval); -} - -static void -printf_erange (s) - char *s; -{ - builtin_error (_("warning: %s: %s"), s, strerror(ERANGE)); -} - -/* We duplicate a lot of what printf(3) does here. */ -static int -printstr (fmt, string, len, fieldwidth, precision) - char *fmt; /* format */ - char *string; /* expanded string argument */ - int len; /* length of expanded string */ - int fieldwidth; /* argument for width of `*' */ - int precision; /* argument for precision of `*' */ -{ -#if 0 - char *s; -#endif - int padlen, nc, ljust, i; - int fw, pr; /* fieldwidth and precision */ - -#if 0 - if (string == 0 || *string == '\0') -#else - if (string == 0 || len == 0) -#endif - return 0; - -#if 0 - s = fmt; -#endif - if (*fmt == '%') - fmt++; - - ljust = fw = 0; - pr = -1; - - /* skip flags */ - while (strchr (SKIP1, *fmt)) - { - if (*fmt == '-') - ljust = 1; - fmt++; - } - - /* get fieldwidth, if present */ - if (*fmt == '*') - { - fmt++; - fw = fieldwidth; - if (fw < 0) - { - fw = -fw; - ljust = 1; - } - } - else if (DIGIT (*fmt)) - { - fw = *fmt++ - '0'; - while (DIGIT (*fmt)) - fw = (fw * 10) + (*fmt++ - '0'); - } - - /* get precision, if present */ - if (*fmt == '.') - { - fmt++; - if (*fmt == '*') - { - fmt++; - pr = precision; - } - else if (DIGIT (*fmt)) - { - pr = *fmt++ - '0'; - while (DIGIT (*fmt)) - pr = (pr * 10) + (*fmt++ - '0'); - } - } - -#if 0 - /* If we remove this, get rid of `s'. */ - if (*fmt != 'b' && *fmt != 'q') - { - internal_error ("format parsing problem: %s", s); - fw = pr = 0; - } -#endif - - /* chars from string to print */ - nc = (pr >= 0 && pr <= len) ? pr : len; - - padlen = fw - nc; - if (padlen < 0) - padlen = 0; - if (ljust) - padlen = -padlen; - - /* leading pad characters */ - for (; padlen > 0; padlen--) - PC (' '); - - /* output NC characters from STRING */ - for (i = 0; i < nc; i++) - PC (string[i]); - - /* output any necessary trailing padding */ - for (; padlen < 0; padlen++) - PC (' '); - - return (ferror (stdout) ? -1 : 0); -} - -/* Convert STRING by expanding the escape sequences specified by the - POSIX standard for printf's `%b' format string. If SAWC is non-null, - perform the processing appropriate for %b arguments. In particular, - recognize `\c' and use that as a string terminator. If we see \c, set - *SAWC to 1 before returning. LEN is the length of STRING. */ - -/* Translate a single backslash-escape sequence starting at ESTART (the - character after the backslash) and return the number of characters - consumed by the sequence. CP is the place to return the translated - value. *SAWC is set to 1 if the escape sequence was \c, since that means - to short-circuit the rest of the processing. If SAWC is null, we don't - do the \c short-circuiting, and \c is treated as an unrecognized escape - sequence; we also bypass the other processing specific to %b arguments. */ -static int -tescape (estart, cp, sawc) - char *estart; - char *cp; - int *sawc; -{ - register char *p; - int temp, c, evalue; - - p = estart; - - switch (c = *p++) - { -#if defined (__STDC__) - case 'a': *cp = '\a'; break; -#else - case 'a': *cp = '\007'; break; -#endif - - case 'b': *cp = '\b'; break; - - case 'e': - case 'E': *cp = '\033'; break; /* ESC -- non-ANSI */ - - case 'f': *cp = '\f'; break; - - case 'n': *cp = '\n'; break; - - case 'r': *cp = '\r'; break; - - case 't': *cp = '\t'; break; - - case 'v': *cp = '\v'; break; - - /* The octal escape sequences are `\0' followed by up to three octal - digits (if SAWC), or `\' followed by up to three octal digits (if - !SAWC). As an extension, we allow the latter form even if SAWC. */ - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - evalue = OCTVALUE (c); - for (temp = 2 + (!evalue && !!sawc); ISOCTAL (*p) && temp--; p++) - evalue = (evalue * 8) + OCTVALUE (*p); - *cp = evalue & 0xFF; - break; - - /* And, as another extension, we allow \xNNN, where each N is a - hex digit. */ - case 'x': -#if 0 - for (evalue = 0; ISXDIGIT ((unsigned char)*p); p++) -#else - for (temp = 2, evalue = 0; ISXDIGIT ((unsigned char)*p) && temp--; p++) -#endif - evalue = (evalue * 16) + HEXVALUE (*p); - if (p == estart + 1) - { - builtin_error (_("missing hex digit for \\x")); - *cp = '\\'; - return 0; - } - *cp = evalue & 0xFF; - break; - - case '\\': /* \\ -> \ */ - *cp = c; - break; - - /* SAWC == 0 means that \', \", and \? are recognized as escape - sequences, though the only processing performed is backslash - removal. */ - case '\'': case '"': case '?': - if (!sawc) - *cp = c; - else - { - *cp = '\\'; - return 0; - } - break; - - case 'c': - if (sawc) - { - *sawc = 1; - break; - } - /* other backslash escapes are passed through unaltered */ - default: - *cp = '\\'; - return 0; - } - return (p - estart); -} - -static char * -bexpand (string, len, sawc, lenp) - char *string; - int len, *sawc, *lenp; -{ - int temp; - char *ret, *r, *s, c; - -#if 0 - if (string == 0 || *string == '\0') -#else - if (string == 0 || len == 0) -#endif - { - if (sawc) - *sawc = 0; - if (lenp) - *lenp = 0; - return ((char *)NULL); - } - - ret = (char *)xmalloc (len + 1); - for (r = ret, s = string; s && *s; ) - { - c = *s++; - if (c != '\\' || *s == '\0') - { - *r++ = c; - continue; - } - temp = 0; - s += tescape (s, &c, &temp); - if (temp) - { - if (sawc) - *sawc = 1; - break; - } - - *r++ = c; - } - - *r = '\0'; - if (lenp) - *lenp = r - ret; - return ret; -} - -static char * -vbadd (buf, blen) - char *buf; - int blen; -{ - size_t nlen; - - nlen = vblen + blen + 1; - if (nlen >= vbsize) - { - vbsize = ((nlen + 63) >> 6) << 6; - vbuf = (char *)xrealloc (vbuf, vbsize); - } - - if (blen == 1) - vbuf[vblen++] = buf[0]; - else if (blen > 1) - { - FASTCOPY (buf, vbuf + vblen, blen); - vblen += blen; - } - vbuf[vblen] = '\0'; - -#ifdef DEBUG - if (strlen (vbuf) != vblen) - internal_error ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, (int)strlen (vbuf)); -#endif - - return vbuf; -} - -static int -#if defined (PREFER_STDARG) -vbprintf (const char *format, ...) -#else -vbprintf (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - size_t nlen; - int blen; - - SH_VA_START (args, format); - blen = vsnprintf (vbuf + vblen, vbsize - vblen, format, args); - - nlen = vblen + blen + 1; - if (nlen >= vbsize) - { - vbsize = ((nlen + 63) >> 6) << 6; - vbuf = (char *)xrealloc (vbuf, vbsize); - blen = vsnprintf (vbuf + vblen, vbsize - vblen, format, args); - } - - va_end (args); - vblen += blen; - vbuf[vblen] = '\0'; - -#ifdef DEBUG - if (strlen (vbuf) != vblen) - internal_error ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, (int)strlen (vbuf)); -#endif - - return (blen); -} - -static char * -mklong (str, modifiers, mlen) - char *str; - char *modifiers; - size_t mlen; -{ - size_t len, slen; - - slen = strlen (str); - len = slen + mlen + 1; - - if (len > conv_bufsize) - { - conv_bufsize = (((len + 1023) >> 10) << 10); - conv_buf = (char *)xrealloc (conv_buf, conv_bufsize); - } - - FASTCOPY (str, conv_buf, slen - 1); - FASTCOPY (modifiers, conv_buf + slen - 1, mlen); - - conv_buf[len - 2] = str[slen - 1]; - conv_buf[len - 1] = '\0'; - return (conv_buf); -} - -static int -getchr () -{ - int ret; - - if (garglist == 0) - return ('\0'); - - ret = (int)garglist->word->word[0]; - garglist = garglist->next; - return ret; -} - -static char * -getstr () -{ - char *ret; - - if (garglist == 0) - return (""); - - ret = garglist->word->word; - garglist = garglist->next; - return ret; -} - -static int -getint () -{ - intmax_t ret; - - ret = getintmax (); - - if (ret > INT_MAX) - { - printf_erange (garglist->word->word); - ret = INT_MAX; - } - else if (ret < INT_MIN) - { - printf_erange (garglist->word->word); - ret = INT_MIN; - } - - return ((int)ret); -} - -static intmax_t -getintmax () -{ - intmax_t ret; - char *ep; - - if (garglist == 0) - return (0); - - if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') - return asciicode (); - - errno = 0; - ret = strtoimax (garglist->word->word, &ep, 0); - - if (*ep) - { - sh_invalidnum (garglist->word->word); - /* POSIX.2 says ``...a diagnostic message shall be written to standard - error, and the utility shall not exit with a zero exit status, but - shall continue processing any remaining operands and shall write the - value accumulated at the time the error was detected to standard - output.'' Yecch. */ - ret = 0; - conversion_error = 1; - } - else if (errno == ERANGE) - printf_erange (garglist->word->word); - - garglist = garglist->next; - return (ret); -} - -static uintmax_t -getuintmax () -{ - uintmax_t ret; - char *ep; - - if (garglist == 0) - return (0); - - if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') - return asciicode (); - - errno = 0; - ret = strtoumax (garglist->word->word, &ep, 0); - - if (*ep) - { - sh_invalidnum (garglist->word->word); - /* Same POSIX.2 conversion error requirements as getintmax(). */ - ret = 0; - conversion_error = 1; - } - else if (errno == ERANGE) - printf_erange (garglist->word->word); - - garglist = garglist->next; - return (ret); -} - -static floatmax_t -getfloatmax () -{ - floatmax_t ret; - char *ep; - - if (garglist == 0) - return (0); - - if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') - return asciicode (); - - errno = 0; - ret = strtofltmax (garglist->word->word, &ep); - - if (*ep) - { - sh_invalidnum (garglist->word->word); - /* Same thing about POSIX.2 conversion error requirements. */ - ret = 0; - conversion_error = 1; - } - else if (errno == ERANGE) - printf_erange (garglist->word->word); - - garglist = garglist->next; - return (ret); -} - -/* NO check is needed for garglist here. */ -static intmax_t -asciicode () -{ - register intmax_t ch; -#if defined (HANDLE_MULTIBYTE) - wchar_t wc; - size_t mblength, slen; -#endif - DECLARE_MBSTATE; - -#if defined (HANDLE_MULTIBYTE) - slen = strlen (garglist->word->word+1); - mblength = MBLEN (garglist->word->word+1, slen); - if (mblength > 1) - { - mblength = mbtowc (&wc, garglist->word->word+1, slen); - ch = wc; /* XXX */ - } - else -#endif - ch = (unsigned char)garglist->word->word[1]; - - garglist = garglist->next; - return (ch); -} diff --git a/builtins/pushd.def~ b/builtins/pushd.def~ deleted file mode 100644 index dd603f3f1..000000000 --- a/builtins/pushd.def~ +++ /dev/null @@ -1,768 +0,0 @@ -This file is pushd.def, from which is created pushd.c. It implements the -builtins "pushd", "popd", and "dirs" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 pushd.c - -$BUILTIN pushd -$FUNCTION pushd_builtin -$DEPENDS_ON PUSHD_AND_POPD -$SHORT_DOC pushd [-n] [+N | -N | dir] -Add directories to stack. - -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. - -Options: - -n Suppresses the normal change of directory when adding - directories to the stack, so only the stack is manipulated. - -Arguments: - +N Rotates the stack so that the Nth directory (counting - from the left of the list shown by `dirs', starting with - zero) is at the top. - - -N Rotates the stack so that the Nth directory (counting - from the right of the list shown by `dirs', starting with - zero) is at the top. - - dir Adds DIR to the directory stack at the top, making it the - new current working directory. - -The `dirs' builtin displays the directory stack. -$END - -$BUILTIN popd -$FUNCTION popd_builtin -$DEPENDS_ON PUSHD_AND_POPD -$SHORT_DOC popd [-n] [+N | -N] -Remove directories from stack. - -Removes entries from the directory stack. With no arguments, removes -the top directory from the stack, and changes to the new top directory. - -Options: - -n Suppresses the normal change of directory when removing - directories from the stack, so only the stack is manipulated. - -Arguments: - +N Removes the Nth entry counting from the left of the list - shown by `dirs', starting with zero. For example: `popd +0' - removes the first directory, `popd +1' the second. - - -N Removes the Nth entry counting from the right of the list - shown by `dirs', starting with zero. For example: `popd -0' - removes the last directory, `popd -1' the next to last. - -The `dirs' builtin displays the directory stack. -$END - -$BUILTIN dirs -$FUNCTION dirs_builtin -$DEPENDS_ON PUSHD_AND_POPD -$SHORT_DOC dirs [-clpv] [+N] [-N] -Display directory stack. - -Display the list of currently remembered directories. Directories -find their way onto the list with the `pushd' command; you can get -back up through the list with the `popd' command. - -Options: - -c clear the directory stack by deleting all of the elements - -l do not print tilde-prefixed versions of directories relative - to your home directory - -p print the directory stack with one entry per line - -v print the directory stack with one entry per line prefixed - with its position in the stack - -Arguments: - +N Displays the Nth entry counting from the left of the list shown by - dirs when invoked without options, starting with zero. - - -N Displays the Nth entry counting from the right of the list shown by - dirs when invoked without options, starting with zero. -$END - -#include - -#if defined (PUSHD_AND_POPD) -#include -#ifndef _MINIX -# include -#endif - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include - -#include - -#include "../shell.h" -#include "maxpath.h" -#include "common.h" -#include "builtext.h" - -#ifdef LOADABLE_BUILTIN -# include "builtins.h" -#endif - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* The list of remembered directories. */ -static char **pushd_directory_list = (char **)NULL; - -/* Number of existing slots in this list. */ -static int directory_list_size; - -/* Offset to the end of the list. */ -static int directory_list_offset; - -static void pushd_error __P((int, char *)); -static void clear_directory_stack __P((void)); -static int cd_to_string __P((char *)); -static int change_to_temp __P((char *)); -static void add_dirstack_element __P((char *)); -static int get_dirstack_index __P((intmax_t, int, int *)); - -#define NOCD 0x01 -#define ROTATE 0x02 -#define LONGFORM 0x04 -#define CLEARSTAK 0x08 - -int -pushd_builtin (list) - WORD_LIST *list; -{ - WORD_LIST *orig_list; - char *temp, *current_directory, *top; - int j, flags, skipopt; - intmax_t num; - char direction; - - orig_list = list; - if (list && list->word && ISOPTION (list->word->word, '-')) - { - list = list->next; - skipopt = 1; - } - else - skipopt = 0; - - /* If there is no argument list then switch current and - top of list. */ - if (list == 0) - { - if (directory_list_offset == 0) - { - builtin_error (_("no other directory")); - return (EXECUTION_FAILURE); - } - - current_directory = get_working_directory ("pushd"); - if (current_directory == 0) - return (EXECUTION_FAILURE); - - j = directory_list_offset - 1; - temp = pushd_directory_list[j]; - pushd_directory_list[j] = current_directory; - j = change_to_temp (temp); - free (temp); - return j; - } - - for (flags = 0; skipopt == 0 && list; list = list->next) - { - if (ISOPTION (list->word->word, 'n')) - { - flags |= NOCD; - } - else if (ISOPTION (list->word->word, '-')) - { - list = list->next; - break; - } - else if (list->word->word[0] == '-' && list->word->word[1] == '\0') - /* Let `pushd -' work like it used to. */ - break; - else if (((direction = list->word->word[0]) == '+') || direction == '-') - { - if (legal_number (list->word->word + 1, &num) == 0) - { - sh_invalidnum (list->word->word); - builtin_usage (); - return (EXECUTION_FAILURE); - } - - if (direction == '-') - num = directory_list_offset - num; - - if (num > directory_list_offset || num < 0) - { - pushd_error (directory_list_offset, list->word->word); - return (EXECUTION_FAILURE); - } - flags |= ROTATE; - } - else if (*list->word->word == '-') - { - sh_invalidopt (list->word->word); - builtin_usage (); - return (EXECUTION_FAILURE); - } - else - break; - } - - if (flags & ROTATE) - { - /* Rotate the stack num times. Remember, the current - directory acts like it is part of the stack. */ - temp = get_working_directory ("pushd"); - - if (num == 0) - { - j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS; - free (temp); - return j; - } - - do - { - top = pushd_directory_list[directory_list_offset - 1]; - - for (j = directory_list_offset - 2; j > -1; j--) - pushd_directory_list[j + 1] = pushd_directory_list[j]; - - pushd_directory_list[j + 1] = temp; - - temp = top; - num--; - } - while (num); - - j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS; - free (temp); - return j; - } - - if (list == 0) - return (EXECUTION_SUCCESS); - - /* Change to the directory in list->word->word. Save the current - directory on the top of the stack. */ - current_directory = get_working_directory ("pushd"); - if (current_directory == 0) - return (EXECUTION_FAILURE); - - j = ((flags & NOCD) == 0) ? cd_builtin (skipopt ? orig_list : list) : EXECUTION_SUCCESS; - if (j == EXECUTION_SUCCESS) - { - add_dirstack_element ((flags & NOCD) ? savestring (list->word->word) : current_directory); - dirs_builtin ((WORD_LIST *)NULL); - if (flags & NOCD) - free (current_directory); - return (EXECUTION_SUCCESS); - } - else - { - free (current_directory); - return (EXECUTION_FAILURE); - } -} - -/* Pop the directory stack, and then change to the new top of the stack. - If LIST is non-null it should consist of a word +N or -N, which says - what element to delete from the stack. The default is the top one. */ -int -popd_builtin (list) - WORD_LIST *list; -{ - register int i; - intmax_t which; - int flags; - char direction; - char *which_word; - - which_word = (char *)NULL; - for (flags = 0, which = 0, direction = '+'; list; list = list->next) - { - if (ISOPTION (list->word->word, 'n')) - { - flags |= NOCD; - } - else if (ISOPTION (list->word->word, '-')) - { - list = list->next; - break; - } - else if (((direction = list->word->word[0]) == '+') || direction == '-') - { - if (legal_number (list->word->word + 1, &which) == 0) - { - sh_invalidnum (list->word->word); - builtin_usage (); - return (EXECUTION_FAILURE); - } - which_word = list->word->word; - } - else if (*list->word->word == '-') - { - sh_invalidopt (list->word->word); - builtin_usage (); - return (EXECUTION_FAILURE); - } - else - break; - } - - if (which > directory_list_offset || (directory_list_offset == 0 && which == 0)) - { - pushd_error (directory_list_offset, which_word ? which_word : ""); - return (EXECUTION_FAILURE); - } - - /* Handle case of no specification, or top of stack specification. */ - if ((direction == '+' && which == 0) || - (direction == '-' && which == directory_list_offset)) - { - i = ((flags & NOCD) == 0) ? cd_to_string (pushd_directory_list[directory_list_offset - 1]) - : EXECUTION_SUCCESS; - if (i != EXECUTION_SUCCESS) - return (i); - free (pushd_directory_list[--directory_list_offset]); - } - else - { - /* Since an offset other than the top directory was specified, - remove that directory from the list and shift the remainder - of the list into place. */ - i = (direction == '+') ? directory_list_offset - which : which; - free (pushd_directory_list[i]); - directory_list_offset--; - - /* Shift the remainder of the list into place. */ - for (; i < directory_list_offset; i++) - pushd_directory_list[i] = pushd_directory_list[i + 1]; - } - - dirs_builtin ((WORD_LIST *)NULL); - return (EXECUTION_SUCCESS); -} - -/* Print the current list of directories on the directory stack. */ -int -dirs_builtin (list) - WORD_LIST *list; -{ - int flags, desired_index, index_flag, vflag; - intmax_t i; - char *temp, *w; - - for (flags = vflag = index_flag = 0, desired_index = -1, w = ""; list; list = list->next) - { - if (ISOPTION (list->word->word, 'l')) - { - flags |= LONGFORM; - } - else if (ISOPTION (list->word->word, 'c')) - { - flags |= CLEARSTAK; - } - else if (ISOPTION (list->word->word, 'v')) - { - vflag |= 2; - } - else if (ISOPTION (list->word->word, 'p')) - { - vflag |= 1; - } - else if (ISOPTION (list->word->word, '-')) - { - list = list->next; - break; - } - else if (*list->word->word == '+' || *list->word->word == '-') - { - int sign; - if (legal_number (w = list->word->word + 1, &i) == 0) - { - sh_invalidnum (list->word->word); - builtin_usage (); - return (EXECUTION_FAILURE); - } - sign = (*list->word->word == '+') ? 1 : -1; - desired_index = get_dirstack_index (i, sign, &index_flag); - } - else - { - sh_invalidopt (list->word->word); - builtin_usage (); - return (EXECUTION_FAILURE); - } - } - - if (flags & CLEARSTAK) - { - clear_directory_stack (); - return (EXECUTION_SUCCESS); - } - - if (index_flag && (desired_index < 0 || desired_index > directory_list_offset)) - { - pushd_error (directory_list_offset, w); - return (EXECUTION_FAILURE); - } - -#define DIRSTACK_FORMAT(temp) \ - (flags & LONGFORM) ? temp : polite_directory_format (temp) - - /* The first directory printed is always the current working directory. */ - if (index_flag == 0 || (index_flag == 1 && desired_index == 0)) - { - temp = get_working_directory ("dirs"); - if (temp == 0) - temp = savestring (_("")); - if (vflag & 2) - printf ("%2d %s", 0, DIRSTACK_FORMAT (temp)); - else - printf ("%s", DIRSTACK_FORMAT (temp)); - free (temp); - if (index_flag) - { - putchar ('\n'); - return (sh_chkwrite (EXECUTION_SUCCESS)); - } - } - -#define DIRSTACK_ENTRY(i) \ - (flags & LONGFORM) ? pushd_directory_list[i] \ - : polite_directory_format (pushd_directory_list[i]) - - /* Now print the requested directory stack entries. */ - if (index_flag) - { - if (vflag & 2) - printf ("%2d %s", directory_list_offset - desired_index, - DIRSTACK_ENTRY (desired_index)); - else - printf ("%s", DIRSTACK_ENTRY (desired_index)); - } - else - for (i = directory_list_offset - 1; i >= 0; i--) - if (vflag >= 2) - printf ("\n%2d %s", directory_list_offset - (int)i, DIRSTACK_ENTRY (i)); - else - printf ("%s%s", (vflag & 1) ? "\n" : " ", DIRSTACK_ENTRY (i)); - - putchar ('\n'); - - return (sh_chkwrite (EXECUTION_SUCCESS)); -} - -static void -pushd_error (offset, arg) - int offset; - char *arg; -{ - if (offset == 0) - builtin_error (_("directory stack empty")); - else - sh_erange (arg, _("directory stack index")); -} - -static void -clear_directory_stack () -{ - register int i; - - for (i = 0; i < directory_list_offset; i++) - free (pushd_directory_list[i]); - directory_list_offset = 0; -} - -/* Switch to the directory in NAME. This uses the cd_builtin to do the work, - so if the result is EXECUTION_FAILURE then an error message has already - been printed. */ -static int -cd_to_string (name) - char *name; -{ - WORD_LIST *tlist; - WORD_LIST *dir; - int result; - - dir = make_word_list (make_word (name), NULL); - tlist = make_word_list (make_word ("--"), dir); - result = cd_builtin (tlist); - dispose_words (tlist); - return (result); -} - -static int -change_to_temp (temp) - char *temp; -{ - int tt; - - tt = temp ? cd_to_string (temp) : EXECUTION_FAILURE; - - if (tt == EXECUTION_SUCCESS) - dirs_builtin ((WORD_LIST *)NULL); - - return (tt); -} - -static void -add_dirstack_element (dir) - char *dir; -{ - if (directory_list_offset == directory_list_size) - pushd_directory_list = strvec_resize (pushd_directory_list, directory_list_size += 10); - pushd_directory_list[directory_list_offset++] = dir; -} - -static int -get_dirstack_index (ind, sign, indexp) - intmax_t ind; - int sign, *indexp; -{ - if (indexp) - *indexp = sign > 0 ? 1 : 2; - - /* dirs +0 prints the current working directory. */ - /* dirs -0 prints last element in directory stack */ - if (ind == 0 && sign > 0) - return 0; - else if (ind == directory_list_offset) - { - if (indexp) - *indexp = sign > 0 ? 2 : 1; - return 0; - } - else if (ind >= 0 && ind <= directory_list_offset) - return (sign > 0 ? directory_list_offset - ind : ind); - else - return -1; -} - -/* Used by the tilde expansion code. */ -char * -get_dirstack_from_string (string) - char *string; -{ - int ind, sign, index_flag; - intmax_t i; - - sign = 1; - if (*string == '-' || *string == '+') - { - sign = (*string == '-') ? -1 : 1; - string++; - } - if (legal_number (string, &i) == 0) - return ((char *)NULL); - - index_flag = 0; - ind = get_dirstack_index (i, sign, &index_flag); - if (index_flag && (ind < 0 || ind > directory_list_offset)) - return ((char *)NULL); - if (index_flag == 0 || (index_flag == 1 && ind == 0)) - return (get_string_value ("PWD")); - else - return (pushd_directory_list[ind]); -} - -#ifdef INCLUDE_UNUSED -char * -get_dirstack_element (ind, sign) - intmax_t ind; - int sign; -{ - int i; - - i = get_dirstack_index (ind, sign, (int *)NULL); - return (i < 0 || i > directory_list_offset) ? (char *)NULL - : pushd_directory_list[i]; -} -#endif - -void -set_dirstack_element (ind, sign, value) - intmax_t ind; - int sign; - char *value; -{ - int i; - - i = get_dirstack_index (ind, sign, (int *)NULL); - if (ind == 0 || i < 0 || i > directory_list_offset) - return; - free (pushd_directory_list[i]); - pushd_directory_list[i] = savestring (value); -} - -WORD_LIST * -get_directory_stack (flags) - int flags; -{ - register int i; - WORD_LIST *ret; - char *d, *t; - - for (ret = (WORD_LIST *)NULL, i = 0; i < directory_list_offset; i++) - { - d = (flags&1) ? polite_directory_format (pushd_directory_list[i]) - : pushd_directory_list[i]; - ret = make_word_list (make_word (d), ret); - } - /* Now the current directory. */ - d = get_working_directory ("dirstack"); - i = 0; /* sentinel to decide whether or not to free d */ - if (d == 0) - d = "."; - else - { - t = polite_directory_format (d); - /* polite_directory_format sometimes returns its argument unchanged. - If it does not, we can free d right away. If it does, we need to - mark d to be deleted later. */ - if (t != d) - { - free (d); - d = t; - } - else /* t == d, so d is what we want */ - i = 1; - } - ret = make_word_list (make_word (d), ret); - if (i) - free (d); - return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */ -} - -#ifdef LOADABLE_BUILTIN -char * const dirs_doc[] = { -N_("Display the list of currently remembered directories. Directories\n\ - find their way onto the list with the `pushd' command; you can get\n\ - back up through the list with the `popd' command.\n\ - \n\ - Options:\n\ - -c clear the directory stack by deleting all of the elements\n\ - -l do not print tilde-prefixed versions of directories relative\n\ - to your home directory\n\ - -p print the directory stack with one entry per line\n\ - -v print the directory stack with one entry per line prefixed\n\ - with its position in the stack\n\ - \n\ - Arguments:\n\ - +N Displays the Nth entry counting from the left of the list shown by\n\ - dirs when invoked without options, starting with zero.\n\ - \n\ - -N Displays the Nth entry counting from the right of the list shown by\n\ - dirs when invoked without options, starting with zero."), - (char *)NULL -}; - -char * const pushd_doc[] = { -N_("Adds a directory to the top of the directory stack, or rotates\n\ - the stack, making the new top of the stack the current working\n\ - directory. With no arguments, exchanges the top two directories.\n\ - \n\ - Options:\n\ - -n Suppresses the normal change of directory when adding\n\ - directories to the stack, so only the stack is manipulated.\n\ - \n\ - Arguments:\n\ - +N Rotates the stack so that the Nth directory (counting\n\ - from the left of the list shown by `dirs', starting with\n\ - zero) is at the top.\n\ - \n\ - -N Rotates the stack so that the Nth directory (counting\n\ - from the right of the list shown by `dirs', starting with\n\ - zero) is at the top.\n\ - \n\ - dir Adds DIR to the directory stack at the top, making it the\n\ - new current working directory.\n\ - \n\ - The `dirs' builtin displays the directory stack."), - (char *)NULL -}; - -char * const popd_doc[] = { -N_("Removes entries from the directory stack. With no arguments, removes\n\ - the top directory from the stack, and changes to the new top directory.\n\ - \n\ - Options:\n\ - -n Suppresses the normal change of directory when removing\n\ - directories from the stack, so only the stack is manipulated.\n\ - \n\ - Arguments:\n\ - +N Removes the Nth entry counting from the left of the list\n\ - shown by `dirs', starting with zero. For example: `popd +0'\n\ - removes the first directory, `popd +1' the second.\n\ - \n\ - -N Removes the Nth entry counting from the right of the list\n\ - shown by `dirs', starting with zero. For example: `popd -0'\n\ - removes the last directory, `popd -1' the next to last.\n\ - \n\ - The `dirs' builtin displays the directory stack."), - (char *)NULL -}; - -struct builtin pushd_struct = { - "pushd", - pushd_builtin, - BUILTIN_ENABLED, - pushd_doc, - "pushd [+N | -N] [-n] [dir]", - 0 -}; - -struct builtin popd_struct = { - "popd", - popd_builtin, - BUILTIN_ENABLED, - popd_doc, - "popd [+N | -N] [-n]", - 0 -}; - -struct builtin dirs_struct = { - "dirs", - dirs_builtin, - BUILTIN_ENABLED, - dirs_doc, - "dirs [-clpv] [+N] [-N]", - 0 -}; -#endif /* LOADABLE_BUILTIN */ - -#endif /* PUSHD_AND_POPD */ diff --git a/builtins/read.def.save1 b/builtins/read.def.save1 deleted file mode 100644 index 179ba17a6..000000000 --- a/builtins/read.def.save1 +++ /dev/null @@ -1,885 +0,0 @@ -This file is read.def, from which is created read.c. -It implements the builtin "read" in Bash. - -Copyright (C) 1987-2007 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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] [-a array] [-d delim] [-n nchars] [-p prompt] [-t timeout] [-u fd] [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 (BUFFERED_INPUT) -# include "input.h" -#endif - -#if !defined(errno) -extern int errno; -#endif - -struct ttsave -{ - int fd; - TTYSTRUCT *attrs; -}; - -#if defined (READLINE) -static void reset_attempted_completion_function __P((char *)); -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 *)); -#if defined (HANDLE_MULTIBYTE) -static int read_mbchar __P((int, char *, int, int, int)); -#endif -static void ttyrestore __P((struct ttsave *)); - -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, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2; - int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc, skip_ctlnul; - 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, *ps2, *tofree; - struct stat tsb; - SHELL_VAR *var; - TTYSTRUCT ttattrs; - struct ttsave termsave; -#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(print_ps2); - 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); - USE_VAR(ps2); - - 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 */ - nr = 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 = ""; - for (skip_ctlesc = skip_ctlnul = 0, e = ifs_chars; *e; e++) - skip_ctlesc |= *e == CTLESC, skip_ctlnul |= *e == CTLNUL; - - 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"); - -#if defined (BUFFERED_INPUT) - if (interactive == 0 && default_buffered_input >= 0 && fd_is_bash_input (fd)) - sync_buffered_stream (default_buffered_input); -#endif - - input_is_tty = isatty (fd); - if (input_is_tty == 0) -#ifndef __CYGWIN__ - input_is_pipe = (lseek (fd, 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); -#if defined (READLINE) - if (edit) - add_unwind_protect (reset_attempted_completion_function, (char *)NULL); -#endif - 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++; - terminate_immediately = 1; - - unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe; - -#if defined (__CYGWIN__) && defined (O_TEXT) - setmode (0, O_TEXT); -#endif - - ps2 = 0; - for (print_ps2 = 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 (print_ps2) - { - if (ps2 == 0) - ps2 = get_string_value ("PS2"); - fprintf (stderr, "%s", ps2 ? ps2 : ""); - fflush (stderr); - print_ps2 = 0; - } - - 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 + 4 >= size) /* XXX was i + 2; use i + 4 for multibyte/read_mbchar */ - { - 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) - { - pass_next = 0; - if (c == '\n') - { - i--; /* back up over the CTLESC */ - if (interactive && input_is_tty && raw == 0) - print_ps2 = 1; - } - else - goto add_char; - continue; - } - - /* This may cause problems if IFS contains CTLESC */ - if (c == '\\' && raw == 0) - { - pass_next++; - if (skip_ctlesc == 0) - { - saw_escape++; - input_string[i++] = CTLESC; - } - continue; - } - - if ((unsigned char)c == delim) - break; - - if ((skip_ctlesc == 0 && c == CTLESC) || (skip_ctlnul == 0 && c == CTLNUL)) - { - saw_escape++; - input_string[i++] = CTLESC; - } - -add_char: - input_string[i++] = c; - -#if defined (HANDLE_MULTIBYTE) - if (nchars > 0 && MB_CUR_MAX > 1) - { - input_string[i] = '\0'; /* for simplicity and debugging */ - i += read_mbchar (fd, input_string, i, c, unbuffered_read); - } -#endif - - nr++; - - if (nchars > 0 && nr >= nchars) - break; - } - input_string[i] = '\0'; - -#if 1 - if (retval < 0) - { - builtin_error (_("read error: %d: %s"), fd, strerror (errno)); - run_unwind_frame ("read_builtin"); - 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--; - terminate_immediately = 0; - 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) - { - xfree (input_string); - return EXECUTION_FAILURE; /* readonly or noassign */ - } - array_flush (array_cell (var)); - - alist = list_string (input_string, ifs_chars, 0); - if (alist) - { - if (saw_escape) - dequote_list (alist); - else - word_list_remove_quoted_nulls (alist); - assign_array_var_from_word_list (var, alist, 0); - 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, 0); - free (t); - } - else - var = bind_variable ("REPLY", input_string, 0); - 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); - } - -#if 0 - /* 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); -#else - /* Check whether or not the number of fields is exactly the same as the - number of variables. */ - tofree = NULL; - if (*input_string) - { - t1 = input_string; - t = get_word_from_string (&input_string, ifs_chars, &e); - if (*input_string == 0) - tofree = input_string = t; - else - input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape); - } -#endif - - 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); - FREE (tofree); - - 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, 0)); - else - return (assign_array_element (name, value, 0)); -#else /* !ARRAY_VARS */ - return bind_variable (name, value, 0); -#endif /* !ARRAY_VARS */ -} - -#if defined (HANDLE_MULTIBYTE) -static int -read_mbchar (fd, string, ind, ch, unbuffered) - int fd; - char *string; - int ind, ch, unbuffered; -{ - char mbchar[MB_LEN_MAX + 1]; - int i, n, r; - char c; - size_t ret; - mbstate_t ps, ps_back; - wchar_t wc; - - memset (&ps, '\0', sizeof (mbstate_t)); - memset (&ps_back, '\0', sizeof (mbstate_t)); - - mbchar[0] = ch; - i = 1; - for (n = 0; n <= MB_LEN_MAX; n++) - { - ps_back = ps; - ret = mbrtowc (&wc, mbchar, i, &ps); - if (ret == (size_t)-2) - { - ps = ps_back; - if (unbuffered) - r = zread (fd, &c, 1); - else - r = zreadc (fd, &c); - if (r < 0) - goto mbchar_return; - mbchar[i++] = c; - continue; - } - else if (ret == (size_t)-1 || ret == (size_t)0 || ret > (size_t)0) - break; - } - -mbchar_return: - if (i > 1) /* read a multibyte char */ - /* mbchar[0] is already string[ind-1] */ - for (r = 1; r < i; r++) - string[ind+r-1] = mbchar[r]; - return i - 1; -} -#endif - -static void -ttyrestore (ttp) - struct ttsave *ttp; -{ - ttsetattr (ttp->fd, ttp->attrs); -} - -#if defined (READLINE) -static rl_completion_func_t *old_attempted_completion_function = 0; - -static void -reset_attempted_completion_function (cp) - char *cp; -{ - if (rl_attempted_completion_function == 0 && old_attempted_completion_function) - rl_attempted_completion_function = old_attempted_completion_function; -} - -static char * -edit_line (p) - char *p; -{ - char *ret; - int len; - - if (bash_readline_initialized == 0) - 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; - old_attempted_completion_function = (rl_completion_func_t *)NULL; - - 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/read.def~ b/builtins/read.def~ deleted file mode 100644 index 0de0530a9..000000000 --- a/builtins/read.def~ +++ /dev/null @@ -1,968 +0,0 @@ -This file is read.def, from which is created read.c. -It implements the builtin "read" in Bash. - -Copyright (C) 1987-2009 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Bash is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Bash. If not, see . - -$PRODUCES read.c - -$BUILTIN read -$FUNCTION read_builtin -$SHORT_DOC read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-p prompt] [-t timeout] [-u fd] [name ...] -Read a line from the standard input and split it into fields. - -Reads a single line from the standard input, or from file descriptor FD -if the -u option is supplied. The line is split into fields as with word -splitting, and the first word is assigned to the first NAME, the second -word to the second NAME, and so on, with any 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. - -Options: - -a array assign the words read to sequential indices of the array - variable ARRAY, starting at zero - -d delim continue until the first character of DELIM is read, rather - than newline - -e use Readline to obtain the line in an interactive shell - -i text Use TEXT as the initial text for Readline - -n nchars return after reading NCHARS characters rather than waiting - for a newline - -p prompt output the string PROMPT without a trailing newline before - attempting to read - -r do not allow backslashes to escape any characters - -s do not echo input coming from a terminal - -t timeout time out and return failure if a complete line of input is - not read withint TIMEOUT seconds. The value of the TMOUT - variable is the default timeout. TIMEOUT may be a - fractional number. If TIMEOUT is 0, read returns success only - if input is available on the specified file descriptor. The - exit status is greater than 128 if the timeout is exceeded - -u fd read from file descriptor FD instead of the standard input - -Exit Status: -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 - -#include "bashansi.h" - -#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 (BUFFERED_INPUT) -# include "input.h" -#endif - -#if !defined(errno) -extern int errno; -#endif - -struct ttsave -{ - int fd; - TTYSTRUCT *attrs; -}; - -#if defined (READLINE) -static void reset_attempted_completion_function __P((char *)); -static int set_itext __P((void)); -static char *edit_line __P((char *, 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 *)); -#if defined (HANDLE_MULTIBYTE) -static int read_mbchar __P((int, char *, int, int, int)); -#endif -static void ttyrestore __P((struct ttsave *)); - -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); - falarm (0, 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, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2; - int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc, skip_ctlnul; - int raw, edit, nchars, silent, have_timeout, fd; - unsigned int tmsec, tmusec; - long ival, uval; - intmax_t intval; - char c; - char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname; - char *e, *t, *t1, *ps2, *tofree; - struct stat tsb; - SHELL_VAR *var; - TTYSTRUCT ttattrs, ttset; - struct ttsave termsave; -#if defined (ARRAY_VARS) - WORD_LIST *alist; -#endif -#if defined (READLINE) - char *rlbuf, *itext; - int rlind; -#endif - - USE_VAR(size); - USE_VAR(i); - USE_VAR(pass_next); - USE_VAR(print_ps2); - USE_VAR(saw_escape); - USE_VAR(input_is_pipe); -/* USE_VAR(raw); */ - USE_VAR(edit); - USE_VAR(tmsec); - USE_VAR(tmusec); - 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); - USE_VAR(itext); -#endif - USE_VAR(list); - USE_VAR(ps2); - - 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 = itext = (char *)0; - rlind = 0; -#endif - - tmsec = tmusec = 0; /* no timeout */ - nr = 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:i: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; - case 'i': -#if defined (READLINE) - itext = list_optarg; -#endif - break; -#if defined (ARRAY_VARS) - case 'a': - arrayname = list_optarg; - break; -#endif - case 't': - code = uconvert (list_optarg, &ival, &uval); - if (code == 0 || ival < 0 || uval < 0) - { - builtin_error (_("%s: invalid timeout specification"), list_optarg); - return (EXECUTION_FAILURE); - } - else - { - have_timeout = 1; - tmsec = ival; - tmusec = uval; - } - 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' tests whether input is available with select/FIONREAD, - and fails if those are unavailable */ - if (have_timeout && tmsec == 0 && tmusec == 0) -#if 0 - return (EXECUTION_FAILURE); -#else - return (input_avail (fd) ? EXECUTION_SUCCESS : EXECUTION_FAILURE); -#endif - - /* IF IFS is unset, we use the default of " \t\n". */ - ifs_chars = getifs (); - if (ifs_chars == 0) /* XXX - shouldn't happen */ - ifs_chars = ""; - for (skip_ctlesc = skip_ctlnul = 0, e = ifs_chars; *e; e++) - skip_ctlesc |= *e == CTLESC, skip_ctlnul |= *e == CTLNUL; - - input_string = (char *)xmalloc (size = 112); /* XXX was 128 */ - input_string[0] = '\0'; - - /* $TMOUT, if set, is the default timeout for read. */ - if (have_timeout == 0 && (e = get_string_value ("TMOUT"))) - { - code = uconvert (e, &ival, &uval); - if (code == 0 || ival < 0 || uval < 0) - tmsec = tmusec = 0; - else - { - tmsec = ival; - tmusec = uval; - } - } - - begin_unwind_frame ("read_builtin"); - -#if defined (BUFFERED_INPUT) - if (interactive == 0 && default_buffered_input >= 0 && fd_is_bash_input (fd)) - sync_buffered_stream (default_buffered_input); -#endif - - input_is_tty = isatty (fd); - if (input_is_tty == 0) -#ifndef __CYGWIN__ - input_is_pipe = (lseek (fd, 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; -#if defined (READLINE) - itext = (char *)NULL; -#endif - edit = silent = 0; - } - -#if defined (READLINE) - if (edit) - add_unwind_protect (xfree, rlbuf); -#endif - - pass_next = 0; /* Non-zero signifies last char was backslash. */ - saw_escape = 0; /* Non-zero signifies that we saw an escape char */ - - if (tmsec > 0 || tmusec > 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)) - tmsec = tmusec = 0; - } - - if (tmsec > 0 || tmusec > 0) - { - code = setjmp (alrmbuf); - if (code) - { -#if 0 - run_unwind_frame ("read_builtin"); - return (EXECUTION_FAILURE); -#else - input_string[i] = '\0'; /* make sure it's terminated */ - retval = 128+SIGALRM;; - goto assign_vars; -#endif - } - old_alrm = set_signal_handler (SIGALRM, sigalrm); - add_unwind_protect (reset_alarm, (char *)NULL); -#if defined (READLINE) - if (edit) - add_unwind_protect (reset_attempted_completion_function, (char *)NULL); -#endif - falarm (tmsec, tmusec); - } - - /* 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) - { -itrace("read_builtin: input_is_tty = %d", input_is_tty); - /* ttsave() */ - termsave.fd = fd; - ttgetattr (fd, &ttattrs); - termsave.attrs = &ttattrs; - - ttset = ttattrs; - i = silent ? ttfd_cbreak (fd, &ttset) : ttfd_onechar (fd, &ttset); - if (i < 0) - sh_ttyerror (1); - add_unwind_protect ((Function *)ttyrestore, (char *)&termsave); - } - } - else if (silent) /* turn off echo but leave term in canonical mode */ - { - /* ttsave (); */ - termsave.fd = fd; - ttgetattr (fd, &ttattrs); - termsave.attrs = &ttattrs; - - ttset = ttattrs; - i = ttfd_noecho (fd, &ttset); /* ttnoecho (); */ - if (i < 0) - sh_ttyerror (1); - - add_unwind_protect ((Function *)ttyrestore, (char *)&termsave); - } - - /* 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++; - terminate_immediately++; - - unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe; - - if (prompt && edit == 0) - { - fprintf (stderr, "%s", prompt); - fflush (stderr); - } - -#if defined (__CYGWIN__) && defined (O_TEXT) - setmode (0, O_TEXT); -#endif - - ps2 = 0; - for (print_ps2 = 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 : "", itext); - rlind = 0; - } - if (rlbuf == 0) - { - eof = 1; - break; - } - c = rlbuf[rlind++]; - } - else - { -#endif - - if (print_ps2) - { - if (ps2 == 0) - ps2 = get_string_value ("PS2"); - fprintf (stderr, "%s", ps2 ? ps2 : ""); - fflush (stderr); - print_ps2 = 0; - } - - 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 + 4 >= size) /* XXX was i + 2; use i + 4 for multibyte/read_mbchar */ - { - 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) - { - pass_next = 0; - if (c == '\n') - { - i--; /* back up over the CTLESC */ - if (interactive && input_is_tty && raw == 0) - print_ps2 = 1; - } - else - goto add_char; - continue; - } - - /* This may cause problems if IFS contains CTLESC */ - if (c == '\\' && raw == 0) - { - pass_next++; - if (skip_ctlesc == 0) - { - saw_escape++; - input_string[i++] = CTLESC; - } - continue; - } - - if ((unsigned char)c == delim) - break; - - if ((skip_ctlesc == 0 && c == CTLESC) || (skip_ctlnul == 0 && c == CTLNUL)) - { - saw_escape++; - input_string[i++] = CTLESC; - } - -add_char: - input_string[i++] = c; - -#if defined (HANDLE_MULTIBYTE) - if (nchars > 0 && MB_CUR_MAX > 1) - { - input_string[i] = '\0'; /* for simplicity and debugging */ - i += read_mbchar (fd, input_string, i, c, unbuffered_read); - } -#endif - - nr++; - - if (nchars > 0 && nr >= nchars) - break; - } - input_string[i] = '\0'; - -#if 1 - if (retval < 0) - { - builtin_error (_("read error: %d: %s"), fd, strerror (errno)); - run_unwind_frame ("read_builtin"); - return (EXECUTION_FAILURE); - } -#endif - - if (tmsec > 0 || tmusec > 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) - ttyrestore (&termsave); - } - else if (silent) - ttyrestore (&termsave); - - if (unbuffered_read == 0) - zsyncfd (fd); - - interrupt_immediately--; - terminate_immediately--; - discard_unwind_frame ("read_builtin"); - - retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS; - -assign_vars: - -#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) - { - xfree (input_string); - return EXECUTION_FAILURE; /* readonly or noassign */ - } - array_flush (array_cell (var)); - - alist = list_string (input_string, ifs_chars, 0); - if (alist) - { - if (saw_escape) - dequote_list (alist); - else - word_list_remove_quoted_nulls (alist); - assign_array_var_from_word_list (var, alist, 0); - 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, 0); - free (t); - } - else - var = bind_variable ("REPLY", input_string, 0); - 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); - } - -#if 0 - /* 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); -#else - /* Check whether or not the number of fields is exactly the same as the - number of variables. */ - tofree = NULL; - if (*input_string) - { - t1 = input_string; - t = get_word_from_string (&input_string, ifs_chars, &e); - if (*input_string == 0) - tofree = input_string = t; - else - input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape); - } -#endif - - 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); - FREE (tofree); - - 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, 0)); - else - return (assign_array_element (name, value, 0)); -#else /* !ARRAY_VARS */ - return bind_variable (name, value, 0); -#endif /* !ARRAY_VARS */ -} - -#if defined (HANDLE_MULTIBYTE) -static int -read_mbchar (fd, string, ind, ch, unbuffered) - int fd; - char *string; - int ind, ch, unbuffered; -{ - char mbchar[MB_LEN_MAX + 1]; - int i, n, r; - char c; - size_t ret; - mbstate_t ps, ps_back; - wchar_t wc; - - memset (&ps, '\0', sizeof (mbstate_t)); - memset (&ps_back, '\0', sizeof (mbstate_t)); - - mbchar[0] = ch; - i = 1; - for (n = 0; n <= MB_LEN_MAX; n++) - { - ps_back = ps; - ret = mbrtowc (&wc, mbchar, i, &ps); - if (ret == (size_t)-2) - { - ps = ps_back; - if (unbuffered) - r = zread (fd, &c, 1); - else - r = zreadc (fd, &c); - if (r < 0) - goto mbchar_return; - mbchar[i++] = c; - continue; - } - else if (ret == (size_t)-1 || ret == (size_t)0 || ret > (size_t)0) - break; - } - -mbchar_return: - if (i > 1) /* read a multibyte char */ - /* mbchar[0] is already string[ind-1] */ - for (r = 1; r < i; r++) - string[ind+r-1] = mbchar[r]; - return i - 1; -} -#endif - - -static void -ttyrestore (ttp) - struct ttsave *ttp; -{ - ttsetattr (ttp->fd, ttp->attrs); -} - -#if defined (READLINE) -static rl_completion_func_t *old_attempted_completion_function = 0; -static rl_hook_func_t *old_startup_hook; -static char *deftext; - -static void -reset_attempted_completion_function (cp) - char *cp; -{ - if (rl_attempted_completion_function == 0 && old_attempted_completion_function) - rl_attempted_completion_function = old_attempted_completion_function; -} - -static int -set_itext () -{ - int r1, r2; - - r1 = r2 = 0; - if (old_startup_hook) - r1 = (*old_startup_hook) (); - if (deftext) - { - r2 = rl_insert_text (deftext); - deftext = (char *)NULL; - rl_startup_hook = old_startup_hook; - old_startup_hook = (rl_hook_func_t *)NULL; - } - return (r1 || r2); -} - -static char * -edit_line (p, itext) - char *p; - char *itext; -{ - char *ret; - int len; - - if (bash_readline_initialized == 0) - initialize_readline (); - - old_attempted_completion_function = rl_attempted_completion_function; - rl_attempted_completion_function = (rl_completion_func_t *)NULL; - if (itext) - { - old_startup_hook = rl_startup_hook; - rl_startup_hook = set_itext; - deftext = itext; - } - ret = readline (p); - rl_attempted_completion_function = old_attempted_completion_function; - old_attempted_completion_function = (rl_completion_func_t *)NULL; - - 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/reserved.def~ b/builtins/reserved.def~ deleted file mode 100644 index b35e2dedc..000000000 --- a/builtins/reserved.def~ +++ /dev/null @@ -1,287 +0,0 @@ -This file is reserved.def, in which the shell reserved words are defined. -It has no direct C file production, but defines builtins for the Bash -builtin help command. - -Copyright (C) 1987-2009 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Bash is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Bash. If not, see . - -$BUILTIN for -$SHORT_DOC for NAME [in WORDS ... ] ; do COMMANDS; done -Execute commands for each member in a list. - -The `for' loop executes a sequence of commands for each member in a -list of items. If `in WORDS ...;' is not present, then `in "$@"' is -assumed. For each element in WORDS, NAME is set to that element, and -the COMMANDS are executed. - -Exit Status: -Returns the status of the last command executed. -$END - -$BUILTIN for (( -$DOCNAME arith_for -$SHORT_DOC for (( exp1; exp2; exp3 )); do COMMANDS; done -Arithmetic for loop. - -Equivalent to - (( EXP1 )) - while (( EXP2 )); do - COMMANDS - (( EXP3 )) - done -EXP1, EXP2, and EXP3 are arithmetic expressions. If any expression is -omitted, it behaves as if it evaluates to 1. - -Exit Status: -Returns the status of the last command executed. -$END - -$BUILTIN select -$SHORT_DOC select NAME [in WORDS ... ;] do COMMANDS; done -Select words from a list and execute commands. - -The WORDS are expanded, generating a list of words. The -set of expanded words is printed on the standard error, each -preceded by a number. If `in WORDS' is not present, `in "$@"' -is assumed. The PS3 prompt is then displayed and a line read -from the standard input. If the line consists of the number -corresponding to one of the displayed words, then NAME is set -to that word. If the line is empty, WORDS and the prompt are -redisplayed. If EOF is read, the command completes. Any other -value read causes NAME to be set to null. The line read is saved -in the variable REPLY. COMMANDS are executed after each selection -until a break command is executed. - -Exit Status: -Returns the status of the last command executed. -$END - -$BUILTIN time -$SHORT_DOC time [-p] pipeline -Report time consumed by pipeline's execution. - -Execute PIPELINE and print a summary of the real time, user CPU time, -and system CPU time spent executing PIPELINE when it terminates. - -Options: - -p print the timing summary in the portable Posix format - -The value of the TIMEFORMAT variable is used as the output format. - -Exit Status: -The return status is the return status of PIPELINE. -$END - -$BUILTIN case -$SHORT_DOC case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac -Execute commands based on pattern matching. - -Selectively execute COMMANDS based upon WORD matching PATTERN. The -`|' is used to separate multiple patterns. - -Exit Status: -Returns the status of the last command executed. -$END - -$BUILTIN if -$SHORT_DOC if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi -Execute commands based on conditional. - -The `if COMMANDS' list is executed. If its exit status is zero, then the -`then COMMANDS' list is executed. Otherwise, each `elif COMMANDS' list is -executed in turn, and if its exit status is zero, the corresponding -`then COMMANDS' list is executed and the if command completes. Otherwise, -the `else COMMANDS' list is executed, if present. The exit status of the -entire construct is the exit status of the last command executed, or zero -if no condition tested true. - -Exit Status: -Returns the status of the last command executed. -$END - -$BUILTIN while -$SHORT_DOC while COMMANDS; do COMMANDS; done -Execute commands as long as a test succeeds. - -Expand and execute COMMANDS as long as the final command in the -`while' COMMANDS has an exit status of zero. - -Exit Status: -Returns the status of the last command executed. -$END - -$BUILTIN until -$SHORT_DOC until COMMANDS; do COMMANDS; done -Execute commands as long as a test does not succeed. - -Expand and execute COMMANDS as long as the final command in the -`until' COMMANDS has an exit status which is not zero. - -Exit Status: -Returns the status of the last command executed. -$END - -$BUILTIN coproc -$SHORT_DOC coproc [NAME] command [redirections] -Create a coprocess named NAME. - -Execute COMMAND asynchronously, with the standard output and standard -input of the command connected via a pipe to file descriptors assigned -to indices 0 and 1 of an array variable NAME in the executing shell. -The default NAME is "COPROC". - -Exit Status: -Returns the exit status of COMMAND. - -$BUILTIN function -$SHORT_DOC function name { COMMANDS ; } or name () { COMMANDS ; } -Define shell function. - -Create a shell function named NAME. When invoked as a simple command, -NAME runs COMMANDs in the calling shell's context. When NAME is invoked, -the arguments are passed to the function as $1...$n, and the function's -name is in $FUNCNAME. - -Exit Status: -Returns success unless NAME is readonly. -$END - -$BUILTIN { ... } -$DOCNAME grouping_braces -$SHORT_DOC { COMMANDS ; } -Group commands as a unit. - -Run a set of commands in a group. This is one way to redirect an -entire set of commands. - -Exit Status: -Returns the status of the last command executed. -$END - -$BUILTIN % -$DOCNAME fg_percent -$SHORT_DOC job_spec [&] -Resume job in foreground. - -Equivalent to the JOB_SPEC argument to the `fg' command. Resume a -stopped or background job. JOB_SPEC can specify either a job name -or a job number. Following JOB_SPEC with a `&' places the job in -the background, as if the job specification had been supplied as an -argument to `bg'. - -Exit Status: -Returns the status of the resumed job. -$END - -$BUILTIN (( ... )) -$DOCNAME arith -$SHORT_DOC (( expression )) -Evaluate arithmetic expression. - -The EXPRESSION is evaluated according to the rules for arithmetic -evaluation. Equivalent to "let EXPRESSION". - -Exit Status: -Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise. -$END - -$BUILTIN [[ ... ]] -$DOCNAME conditional -$SHORT_DOC [[ expression ]] -Execute conditional command. - -Returns a status of 0 or 1 depending on the evaluation of the conditional -expression EXPRESSION. Expressions are composed of the same primaries used -by the `test' builtin, and may be combined using the following operators: - - ( EXPRESSION ) Returns the value of EXPRESSION - ! EXPRESSION True if EXPRESSION is false; else false - EXPR1 && EXPR2 True if both EXPR1 and EXPR2 are true; else false - EXPR1 || EXPR2 True if either EXPR1 or EXPR2 is true; else false - -When the `==' and `!=' operators are used, the string to the right of -the operator is used as a pattern and pattern matching is performed. -When the `=~' operator is used, the string to the right of the operator -is matched as a regular expression. - -The && and || operators do not evaluate EXPR2 if EXPR1 is sufficient to -determine the expression's value. - -Exit Status: -0 or 1 depending on value of EXPRESSION. -$END - -$BUILTIN variables -$DOCNAME variable_help -$SHORT_DOC variables - Names and meanings of some shell variables -Common shell variable names and usage. - -BASH_VERSION Version information for this Bash. -CDPATH A colon-separated list of directories to search - for directories given as arguments to `cd'. -GLOBIGNORE A colon-separated list of patterns describing filenames to - be ignored by pathname expansion. -#if defined (HISTORY) -HISTFILE The name of the file where your command history is stored. -HISTFILESIZE The maximum number of lines this file can contain. -HISTSIZE The maximum number of history lines that a running - shell can access. -#endif /* HISTORY */ -HOME The complete pathname to your login directory. -HOSTNAME The name of the current host. -HOSTTYPE The type of CPU this version of Bash is running under. -IGNOREEOF Controls the action of the shell on receipt of an EOF - character as the sole input. If set, then the value - of it is the number of EOF characters that can be seen - in a row on an empty line before the shell will exit - (default 10). When unset, EOF signifies the end of input. -MACHTYPE A string describing the current system Bash is running on. -MAILCHECK How often, in seconds, Bash checks for new mail. -MAILPATH A colon-separated list of filenames which Bash checks - for new mail. -OSTYPE The version of Unix this version of Bash is running on. -PATH A colon-separated list of directories to search when - looking for commands. -PROMPT_COMMAND A command to be executed before the printing of each - primary prompt. -PS1 The primary prompt string. -PS2 The secondary prompt string. -PWD The full pathname of the current directory. -SHELLOPTS A colon-separated list of enabled shell options. -TERM The name of the current terminal type. -TIMEFORMAT The output format for timing statistics displayed by the - `time' reserved word. -auto_resume Non-null means a command word appearing on a line by - itself is first looked for in the list of currently - stopped jobs. If found there, that job is foregrounded. - A value of `exact' means that the command word must - exactly match a command in the list of stopped jobs. A - value of `substring' means that the command word must - match a substring of the job. Any other value means that - the command must be a prefix of a stopped job. -#if defined (HISTORY) -# if defined (BANG_HISTORY) -histchars Characters controlling history expansion and quick - substitution. The first character is the history - substitution character, usually `!'. The second is - the `quick substitution' character, usually `^'. The - third is the `history comment' character, usually `#'. -# endif /* BANG_HISTORY */ -HISTIGNORE A colon-separated list of patterns used to decide which - commands should be saved on the history list. -#endif /* HISTORY */ -$END diff --git a/builtins/return.def~ b/builtins/return.def~ deleted file mode 100644 index 259c9222d..000000000 --- a/builtins/return.def~ +++ /dev/null @@ -1,69 +0,0 @@ -This file is return.def, from which is created return.c. -It implements the builtin "return" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 return.c - -$BUILTIN return - -$FUNCTION return_builtin -$SHORT_DOC return [n] -Return from a shell function. - -Causes a function or sourced script to exit with the return value -specified by N. If N is omitted, the return status is that of the -last command executed within the function or script. -$END - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashintl.h" - -#include "../shell.h" -#include "common.h" - -extern int last_command_exit_value; -extern int subshell_environment; -extern int return_catch_flag, return_catch_value; - -/* If we are executing a user-defined function then exit with the value - specified as an argument. if no argument is given, then the last - exit status is used. */ -int -return_builtin (list) - WORD_LIST *list; -{ - return_catch_value = get_exitstat (list); - - if (return_catch_flag) - longjmp (return_catch, 1); - else - { - builtin_error (_("can only `return' from a function or sourced script")); - return (EXECUTION_FAILURE); - } -} diff --git a/builtins/set.def~ b/builtins/set.def~ deleted file mode 100644 index 404e60538..000000000 --- a/builtins/set.def~ +++ /dev/null @@ -1,849 +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-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 set.c - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../flags.h" -#include "common.h" -#include "bashgetopt.h" - -#if defined (READLINE) -# include "../input.h" -# include "../bashline.h" -# include -#endif - -#if defined (HISTORY) -# include "../bashhist.h" -#endif - -extern int posixly_correct, ignoreeof, eof_encountered_limit; -#if defined (HISTORY) -extern int dont_save_function_defs; -#endif -#if defined (READLINE) -extern int no_line_editing; -#endif /* READLINE */ - -$BUILTIN set -$FUNCTION set_builtin -$SHORT_DOC set [--abefhkmnptuvxBCHP] [-o option-name] [arg ...] -Set or unset values of shell options and positional parameters. - -Change the value of shell attributes and positional parameters, or -display the names and values of shell variables. - -Options: - -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 Remember the location of commands as they are looked up. - -k All assignment arguments are placed in the environment for a - command, not just those that precede the command name. - -m Job control is enabled. - -n Read commands but do not execute them. - -o option-name - Set the variable corresponding to option-name: - allexport same as -a - braceexpand same as -B -#if defined (READLINE) - emacs use an emacs-style line editing interface -#endif /* READLINE */ - errexit same as -e - errtrace same as -E - functrace same as -T - hashall same as -h -#if defined (BANG_HISTORY) - histexpand same as -H -#endif /* BANG_HISTORY */ -#if defined (HISTORY) - history enable command history -#endif - ignoreeof the shell will not exit upon reading EOF - interactive-comments - allow comments to appear in interactive commands - keyword same as -k - monitor same as -m - noclobber same as -C - noexec same as -n - noglob same as -f - nolog currently accepted but ignored - notify same as -b - nounset same as -u - onecmd same as -t - physical same as -P - pipefail the return value of a pipeline is the status of - the last command to exit with a non-zero status, - or zero if no command exited with a non-zero status - posix change the behavior of bash where the default - operation differs from the Posix 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. -#if defined (BRACE_EXPANSION) - -B the shell will perform brace expansion -#endif /* BRACE_EXPANSION */ - -C If set, disallow existing regular files to be overwritten - by redirection of output. - -E If set, the ERR trap is inherited by shell functions. -#if defined (BANG_HISTORY) - -H Enable ! style history substitution. This flag is on - by default when the shell is interactive. -#endif /* BANG_HISTORY */ - -P If set, do not follow symbolic links when executing commands - such as cd which change the current directory. - -T If set, the DEBUG trap is inherited by shell functions. - - Assign any remaining arguments to the positional parameters. - The -x and -v options are turned off. - -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 - -typedef int setopt_set_func_t __P((int, char *)); -typedef int setopt_get_func_t __P((char *)); - -static void print_minus_o_option __P((char *, int, int)); -static void print_all_shell_variables __P((void)); - -static int set_ignoreeof __P((int, char *)); -static int set_posix_mode __P((int, char *)); - -#if defined (READLINE) -static int set_edit_mode __P((int, char *)); -static int get_edit_mode __P((char *)); -#endif - -#if defined (HISTORY) -static int bash_set_history __P((int, char *)); -#endif - -static const char * const on = "on"; -static const char * const off = "off"; - -/* A struct used to match long options for set -o to the corresponding - option letter or internal variable. The functions can be called to - dynamically generate values. */ -const struct { - char *name; - int letter; - int *variable; - setopt_set_func_t *set_func; - setopt_get_func_t *get_func; -} o_options[] = { - { "allexport", 'a', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, -#if defined (BRACE_EXPANSION) - { "braceexpand",'B', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, -#endif -#if defined (READLINE) - { "emacs", '\0', (int *)NULL, set_edit_mode, get_edit_mode }, -#endif - { "errexit", 'e', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - { "errtrace", 'E', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - { "functrace", 'T', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - { "hashall", 'h', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, -#if defined (BANG_HISTORY) - { "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, -#endif /* BANG_HISTORY */ -#if defined (HISTORY) - { "history", '\0', &enable_history_list, bash_set_history, (setopt_get_func_t *)NULL }, -#endif - { "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL }, - { "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - { "keyword", 'k', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - { "monitor", 'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - { "noclobber", 'C', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - { "noexec", 'n', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - { "noglob", 'f', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, -#if defined (HISTORY) - { "nolog", '\0', &dont_save_function_defs, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, -#endif -#if defined (JOB_CONTROL) - { "notify", 'b', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, -#endif /* JOB_CONTROL */ - { "nounset", 'u', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - { "onecmd", 't', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - { "physical", 'P', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - { "pipefail", '\0', &pipefail_opt, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - { "posix", '\0', &posixly_correct, set_posix_mode, (setopt_get_func_t *)NULL }, - { "privileged", 'p', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - { "verbose", 'v', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, -#if defined (READLINE) - { "vi", '\0', (int *)NULL, set_edit_mode, get_edit_mode }, -#endif - { "xtrace", 'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, - {(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, -}; - -#define N_O_OPTIONS (sizeof (o_options) / sizeof (o_options[0])) - -#define GET_BINARY_O_OPTION_VALUE(i, name) \ - ((o_options[i].get_func) ? (*o_options[i].get_func) (name) \ - : (*o_options[i].variable)) - -#define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \ - ((o_options[i].set_func) ? (*o_options[i].set_func) (onoff, name) \ - : (*o_options[i].variable = (onoff == FLAG_ON))) - -int -minus_o_option_value (name) - char *name; -{ - register int i; - int *on_or_off; - - for (i = 0; o_options[i].name; i++) - { - if (STREQ (name, o_options[i].name)) - { - if (o_options[i].letter) - { - on_or_off = find_flag (o_options[i].letter); - return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off); - } - else - return (GET_BINARY_O_OPTION_VALUE (i, name)); - } - } - - return (-1); -} - -#define MINUS_O_FORMAT "%-15s\t%s\n" - -static void -print_minus_o_option (name, value, pflag) - char *name; - int value, pflag; -{ - if (pflag == 0) - printf (MINUS_O_FORMAT, name, value ? on : off); - else - printf ("set %co %s\n", value ? '-' : '+', name); -} - -void -list_minus_o_opts (mode, reusable) - int mode, reusable; -{ - register int i; - int *on_or_off, value; - - for (i = 0; o_options[i].name; i++) - { - if (o_options[i].letter) - { - value = 0; - on_or_off = find_flag (o_options[i].letter); - if (on_or_off == FLAG_UNKNOWN) - on_or_off = &value; - if (mode == -1 || mode == *on_or_off) - print_minus_o_option (o_options[i].name, *on_or_off, reusable); - } - else - { - value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name); - if (mode == -1 || mode == value) - print_minus_o_option (o_options[i].name, value, reusable); - } - } -} - -char ** -get_minus_o_opts () -{ - char **ret; - int i; - - ret = strvec_create (N_O_OPTIONS + 1); - for (i = 0; o_options[i].name; i++) - ret[i] = o_options[i].name; - ret[i] = (char *)NULL; - return ret; -} - -static int -set_ignoreeof (on_or_off, option_name) - int on_or_off; - char *option_name; -{ - ignoreeof = on_or_off == FLAG_ON; - unbind_variable ("ignoreeof"); - if (ignoreeof) - bind_variable ("IGNOREEOF", "10", 0); - else - unbind_variable ("IGNOREEOF"); - sv_ignoreeof ("IGNOREEOF"); - return 0; -} - -static int -set_posix_mode (on_or_off, option_name) - int on_or_off; - char *option_name; -{ - posixly_correct = on_or_off == FLAG_ON; - if (posixly_correct == 0) - unbind_variable ("POSIXLY_CORRECT"); - else - bind_variable ("POSIXLY_CORRECT", "y", 0); - sv_strict_posix ("POSIXLY_CORRECT"); - return (0); -} - -#if defined (READLINE) -/* Magic. This code `knows' how readline handles rl_editing_mode. */ -static int -set_edit_mode (on_or_off, option_name) - int on_or_off; - char *option_name; -{ - int isemacs; - - if (on_or_off == FLAG_ON) - { - rl_variable_bind ("editing-mode", option_name); - - if (interactive) - with_input_from_stdin (); - no_line_editing = 0; - } - else - { - isemacs = rl_editing_mode == 1; - if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v')) - { - if (interactive) - with_input_from_stream (stdin, "stdin"); - no_line_editing = 1; - } - } - return 1-no_line_editing; -} - -static int -get_edit_mode (name) - char *name; -{ - return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1 - : no_line_editing == 0 && rl_editing_mode == 0); -} -#endif /* READLINE */ - -#if defined (HISTORY) -static int -bash_set_history (on_or_off, option_name) - int on_or_off; - char *option_name; -{ - if (on_or_off == FLAG_ON) - { - enable_history_list = 1; - bash_history_enable (); - if (history_lines_this_session == 0) - load_history (); - } - else - { - enable_history_list = 0; - bash_history_disable (); - } - return (1 - enable_history_list); -} -#endif - -int -set_minus_o_option (on_or_off, option_name) - int on_or_off; - char *option_name; -{ - register int i; - - for (i = 0; o_options[i].name; i++) - { - if (STREQ (option_name, o_options[i].name)) - { - if (o_options[i].letter == 0) - { - SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name); - return (EXECUTION_SUCCESS); - } - else - { - if (change_flag (o_options[i].letter, on_or_off) == FLAG_ERROR) - { - sh_invalidoptname (option_name); - return (EXECUTION_FAILURE); - } - else - return (EXECUTION_SUCCESS); - } - - } - } - - sh_invalidoptname (option_name); - return (EX_USAGE); -} - -static void -print_all_shell_variables () -{ - SHELL_VAR **vars; - - vars = all_shell_variables (); - if (vars) - { - print_var_list (vars); - free (vars); - } - - /* POSIX.2 does not allow function names and definitions to be output when - `set' is invoked without options (PASC Interp #202). */ - if (posixly_correct == 0) - { - vars = all_shell_functions (); - if (vars) - { - print_func_list (vars); - free (vars); - } - } -} - -void -set_shellopts () -{ - char *value; - char tflag[N_O_OPTIONS]; - int vsize, i, vptr, *ip, exported; - SHELL_VAR *v; - - for (vsize = i = 0; o_options[i].name; i++) - { - tflag[i] = 0; - if (o_options[i].letter) - { - ip = find_flag (o_options[i].letter); - if (ip && *ip) - { - vsize += strlen (o_options[i].name) + 1; - tflag[i] = 1; - } - } - else if (GET_BINARY_O_OPTION_VALUE (i, o_options[i].name)) - { - vsize += strlen (o_options[i].name) + 1; - tflag[i] = 1; - } - } - - value = (char *)xmalloc (vsize + 1); - - for (i = vptr = 0; o_options[i].name; i++) - { - if (tflag[i]) - { - strcpy (value + vptr, o_options[i].name); - vptr += strlen (o_options[i].name); - value[vptr++] = ':'; - } - } - - if (vptr) - vptr--; /* cut off trailing colon */ - value[vptr] = '\0'; - - v = find_variable ("SHELLOPTS"); - - /* Turn off the read-only attribute so we can bind the new value, and - note whether or not the variable was exported. */ - if (v) - { - VUNSETATTR (v, att_readonly); - exported = exported_p (v); - } - else - exported = 0; - - v = bind_variable ("SHELLOPTS", value, 0); - - /* Turn the read-only attribute back on, and turn off the export attribute - if it was set implicitly by mark_modified_vars and SHELLOPTS was not - exported before we bound the new value. */ - VSETATTR (v, att_readonly); - if (mark_modified_vars && exported == 0 && exported_p (v)) - VUNSETATTR (v, att_exported); - - free (value); -} - -void -parse_shellopts (value) - char *value; -{ - char *vname; - int vptr; - - vptr = 0; - while (vname = extract_colon_unit (value, &vptr)) - { - set_minus_o_option (FLAG_ON, vname); - free (vname); - } -} - -void -initialize_shell_options (no_shellopts) - int no_shellopts; -{ - char *temp; - SHELL_VAR *var; - - if (no_shellopts == 0) - { - var = find_variable ("SHELLOPTS"); - /* set up any shell options we may have inherited. */ - if (var && imported_p (var)) - { - temp = (array_p (var)) ? (char *)NULL : savestring (value_cell (var)); - if (temp) - { - parse_shellopts (temp); - free (temp); - } - } - } - - /* Set up the $SHELLOPTS variable. */ - set_shellopts (); -} - -/* Reset the values of the -o options that are not also shell flags. This is - called from execute_cmd.c:initialize_subshell() when setting up a subshell - to run an executable shell script without a leading `#!'. */ -void -reset_shell_options () -{ -#if defined (HISTORY) - remember_on_history = enable_history_list = 1; -#endif - ignoreeof = 0; -} - -/* Set some flags from the word values in the input list. If LIST is empty, - then print out the values of the variables instead. If LIST contains - non-flags, then set $1 - $9 to the successive words of LIST. */ -int -set_builtin (list) - WORD_LIST *list; -{ - int on_or_off, flag_name, force_assignment, opts_changed, rv, r; - register char *arg; - char s[3]; - - if (list == 0) - { - print_all_shell_variables (); - return (sh_chkwrite (EXECUTION_SUCCESS)); - } - - /* Check validity of flag arguments. */ - rv = EXECUTION_SUCCESS; - reset_internal_getopt (); - while ((flag_name = internal_getopt (list, optflags)) != -1) - { - switch (flag_name) - { - case '?': - builtin_usage (); - return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE); - default: - break; - } - } - - /* Do the set command. While the list consists of words starting with - '-' or '+' treat them as flags, otherwise, start assigning them to - $1 ... $n. */ - for (force_assignment = opts_changed = 0; list; ) - { - arg = list->word->word; - - /* If the argument is `--' or `-' then signal the end of the list - and remember the remaining arguments. */ - if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2]))) - { - list = list->next; - - /* `set --' unsets the positional parameters. */ - if (arg[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', '+'); - opts_changed = 1; - } - - break; - } - - if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+')) - { - while (flag_name = *++arg) - { - 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 == 0) - { - list_minus_o_opts (-1, (on_or_off == '+')); - rv = sh_chkwrite (rv); - continue; - } - - option_name = opt->word->word; - - if (option_name == 0 || *option_name == '\0' || - *option_name == '-' || *option_name == '+') - { - list_minus_o_opts (-1, (on_or_off == '+')); - continue; - } - list = list->next; /* Skip over option name. */ - - opts_changed = 1; - if ((r = set_minus_o_option (on_or_off, option_name)) != EXECUTION_SUCCESS) - { - set_shellopts (); - return (r); - } - } - else if (change_flag (flag_name, on_or_off) == FLAG_ERROR) - { - s[0] = on_or_off; - s[1] = flag_name; - s[2] = '\0'; - sh_invalidopt (s); - builtin_usage (); - set_shellopts (); - return (EXECUTION_FAILURE); - } - opts_changed = 1; - } - } - else - { - break; - } - list = list->next; - } - - /* Assigning $1 ... $n */ - if (list || force_assignment) - remember_args (list, 1); - /* Set up new value of $SHELLOPTS */ - if (opts_changed) - set_shellopts (); - return (rv); -} - -$BUILTIN unset -$FUNCTION unset_builtin -$SHORT_DOC unset [-f] [-v] [name ...] -Unset values and attributes of shell variables and functions. - -For each NAME, remove the corresponding variable or function. - -Options: - -f treat each NAME as a shell function - -v treat each NAME as a shell variable - -Without options, unset first tries to unset a variable, and if that fails, -tries to unset a function. - -Some variables cannot be unset; also see `readonly'. -$END - -#define NEXT_VARIABLE() any_failed++; list = list->next; continue; - -int -unset_builtin (list) - WORD_LIST *list; -{ - int unset_function, 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 (EX_USAGE); - } - } - - 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) - unset_array = 0; - if (!unset_function && valid_array_reference (name)) - { - t = strchr (name, '['); - *t++ = '\0'; - unset_array++; - } -#endif - - /* Bash allows functions with names which are not valid identifiers - to be created when not in posix mode, so check only when in posix - mode when unsetting a function. */ - if (((unset_function && posixly_correct) || !unset_function) && legal_identifier (name) == 0) - { - sh_invalidid (name); - NEXT_VARIABLE (); - } - - 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); - if (tem == -1) - any_failed++; - } - } - else -#endif /* ARRAY_VARS */ - tem = unset_function ? unbind_func (name) : unbind_variable (name); - - /* 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 = unbind_func (name); - - /* SUSv3, POSIX.1-2001 say: ``Unsetting a variable or function that - was not previously set shall not be considered an error.'' */ - - if (unset_function == 0) - stupidly_hack_special_variables (name); - - list = list->next; - } - - return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS); -} diff --git a/builtins/setattr.def~ b/builtins/setattr.def~ deleted file mode 100644 index b1f953b76..000000000 --- a/builtins/setattr.def~ +++ /dev/null @@ -1,506 +0,0 @@ -This file is setattr.def, from which is created setattr.c. -It implements the builtins "export" and "readonly", in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 setattr.c - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "common.h" -#include "bashgetopt.h" - -extern int posixly_correct; -extern int array_needs_making; -extern char *this_command_name; -extern sh_builtin_func_t *this_shell_builtin; - -#ifdef ARRAY_VARS -extern int declare_builtin __P((WORD_LIST *)); -#endif - -#define READONLY_OR_EXPORT \ - (this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin) - -$BUILTIN export -$FUNCTION export_builtin -$SHORT_DOC export [-fn] [name[=value] ...] or export -p -Set export attribute for shell variables. - -Marks each NAME for automatic export to the environment of subsequently -executed commands. If VALUE is supplied, assign VALUE before exporting. - -Options: - -f refer to shell functions - -n remove the export property from each NAME - -p display a list of all exported variables and functions - -An argument of `--' disables further option processing. - -Exit Status: -Returns success unless an invalid option is given or NAME is invalid. -$END - -/* For each variable name in LIST, make that variable appear in the - environment passed to simple commands. If there is no LIST, then - print all such variables. An argument of `-n' says to remove the - exported attribute from variables named in LIST. An argument of - -f indicates that the names present in LIST refer to functions. */ -int -export_builtin (list) - register WORD_LIST *list; -{ - return (set_or_show_attributes (list, att_exported, 0)); -} - -$BUILTIN readonly -$FUNCTION readonly_builtin -$SHORT_DOC readonly [-af] [name[=value] ...] or readonly -p -Mark shell variables as unchangeable. - -Mark each NAME as read-only; the values of these NAMEs may not be -changed by subsequent assignment. If VALUE is supplied, assign VALUE -before marking as read-only. - -Options: - -a refer to indexed array variables - -A refer to associative array variables - -f refer to shell functions - -p display a list of all readonly variables and functions - -An argument of `--' disables further option processing. - -Exit Status: -Returns success unless an invalid option is given or NAME is invalid. -$END - -/* For each variable name in LIST, make that variable readonly. Given an - empty LIST, print out all existing readonly variables. */ -int -readonly_builtin (list) - register WORD_LIST *list; -{ - return (set_or_show_attributes (list, att_readonly, 0)); -} - -#if defined (ARRAY_VARS) -# define ATTROPTS "aAfnp" -#else -# define ATTROPTS "fnp" -#endif - -/* For each variable name in LIST, make that variable have the specified - ATTRIBUTE. An arg of `-n' says to remove the attribute from the the - remaining names in LIST (doesn't work for readonly). */ -int -set_or_show_attributes (list, attribute, nodefs) - register WORD_LIST *list; - int attribute, nodefs; -{ - register SHELL_VAR *var; - int assign, undo, any_failed, assign_error, opt; - int functions_only, arrays_only, assoc_only; - int aflags; - char *name; -#if defined (ARRAY_VARS) - WORD_LIST *nlist, *tlist; - WORD_DESC *w; -#endif - - functions_only = arrays_only = assoc_only = 0; - undo = any_failed = assign_error = 0; - /* Read arguments from the front of the list. */ - reset_internal_getopt (); - while ((opt = internal_getopt (list, ATTROPTS)) != -1) - { - switch (opt) - { - case 'n': - undo = 1; - break; - case 'f': - functions_only = 1; - break; -#if defined (ARRAY_VARS) - case 'a': - arrays_only = 1; - break; - case 'A': - assoc_only = 1; - break; -#endif - case 'p': - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - if (list) - { - if (attribute & att_exported) - array_needs_making = 1; - - /* Cannot undo readonly status, silently disallowed. */ - if (undo && (attribute & att_readonly)) - attribute &= ~att_readonly; - - while (list) - { - name = list->word->word; - - if (functions_only) /* xxx -f name */ - { - var = find_function (name); - if (var == 0) - { - builtin_error (_("%s: not a function"), name); - any_failed++; - } - else - SETVARATTR (var, attribute, undo); - - list = list->next; - continue; - } - - /* xxx [-np] name[=value] */ - assign = assignment (name, 0); - - aflags = 0; - if (assign) - { - name[assign] = '\0'; - if (name[assign - 1] == '+') - { - aflags |= ASS_APPEND; - name[assign - 1] = '\0'; - } - } - - if (legal_identifier (name) == 0) - { - sh_invalidid (name); - if (assign) - assign_error++; - else - any_failed++; - list = list->next; - continue; - } - - if (assign) /* xxx [-np] name=value */ - { - name[assign] = '='; - if (aflags & ASS_APPEND) - name[assign - 1] = '+'; -#if defined (ARRAY_VARS) - /* Let's try something here. Turn readonly -a xxx=yyy into - declare -ra xxx=yyy and see what that gets us. */ - if (arrays_only || assoc_only) - { - tlist = list->next; - list->next = (WORD_LIST *)NULL; - w = arrays_only ? make_word ("-ra") : make_word ("-rA"); - nlist = make_word_list (w, list); - opt = declare_builtin (nlist); - if (opt != EXECUTION_SUCCESS) - assign_error++; - list->next = tlist; - dispose_word (w); - free (nlist); - } - else -#endif - /* This word has already been expanded once with command - and parameter expansion. Call do_assignment_no_expand (), - which does not do command or parameter substitution. If - the assignment is not performed correctly, flag an error. */ - if (do_assignment_no_expand (name) == 0) - assign_error++; - name[assign] = '\0'; - if (aflags & ASS_APPEND) - name[assign - 1] = '\0'; - } - - set_var_attribute (name, attribute, undo); - list = list->next; - } - } - else - { - SHELL_VAR **variable_list; - register int i; - - if ((attribute & att_function) || functions_only) - { - variable_list = all_shell_functions (); - if (attribute != att_function) - attribute &= ~att_function; /* so declare -xf works, for example */ - } - else - variable_list = all_shell_variables (); - -#if defined (ARRAY_VARS) - if (attribute & att_array) - { - arrays_only++; - if (attribute != att_array) - attribute &= ~att_array; - } - else if (attribute & att_assoc) - { - assoc_only++; - if (attribute != att_assoc) - attribute &= ~att_assoc; - } -#endif - - if (variable_list) - { - for (i = 0; var = variable_list[i]; i++) - { -#if defined (ARRAY_VARS) - if (arrays_only && array_p (var) == 0) - continue; - if (assoc_only && assoc_p (var) == 0) - continue; -#endif - if ((var->attributes & attribute)) - { - show_var_attributes (var, READONLY_OR_EXPORT, nodefs); - if (any_failed = sh_chkwrite (any_failed)) - break; - } - } - free (variable_list); - } - } - - return (assign_error ? EX_BADASSIGN - : ((any_failed == 0) ? EXECUTION_SUCCESS - : EXECUTION_FAILURE)); -} - -/* Show all variable variables (v == 1) or functions (v == 0) with - attributes. */ -int -show_all_var_attributes (v, nodefs) - int v, nodefs; -{ - SHELL_VAR **variable_list, *var; - int any_failed; - register int i; - - variable_list = v ? all_shell_variables () : all_shell_functions (); - if (variable_list == 0) - return (EXECUTION_SUCCESS); - - for (i = any_failed = 0; var = variable_list[i]; i++) - { - show_var_attributes (var, READONLY_OR_EXPORT, nodefs); - if (any_failed = sh_chkwrite (any_failed)) - break; - } - free (variable_list); - return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE); -} - -/* Show the attributes for shell variable VAR. If NODEFS is non-zero, - don't show function definitions along with the name. If PATTR is - non-zero, it indicates we're being called from `export' or `readonly'. - In POSIX mode, this prints the name of the calling builtin (`export' - or `readonly') instead of `declare', and doesn't print function defs - when called by `export' or `readonly'. */ -int -show_var_attributes (var, pattr, nodefs) - SHELL_VAR *var; - int pattr, nodefs; -{ - char flags[16], *x; - int i; - - i = 0; - - /* pattr == 0 means we are called from `declare'. */ - if (pattr == 0 || posixly_correct == 0) - { -#if defined (ARRAY_VARS) - if (array_p (var)) - flags[i++] = 'a'; - - if (assoc_p (var)) - flags[i++] = 'A'; -#endif - - if (function_p (var)) - flags[i++] = 'f'; - - if (integer_p (var)) - flags[i++] = 'i'; - - if (readonly_p (var)) - flags[i++] = 'r'; - - if (trace_p (var)) - flags[i++] = 't'; - - if (exported_p (var)) - flags[i++] = 'x'; - } - else - { -#if defined (ARRAY_VARS) - if (array_p (var)) - flags[i++] = 'a'; - - if (assoc_p (var)) - flags[i++] = 'A'; -#endif - - if (function_p (var)) - flags[i++] = 'f'; - } - - flags[i] = '\0'; - - /* If we're printing functions with definitions, print the function def - first, then the attributes, instead of printing output that can't be - reused as input to recreate the current state. */ - if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0)) - { - printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL)); - nodefs++; - if (pattr == 0 && i == 1 && flags[0] == 'f') - return 0; /* don't print `declare -f name' */ - } - - if (pattr == 0 || posixly_correct == 0) - printf ("declare -%s ", i ? flags : "-"); - else if (i) - printf ("%s -%s ", this_command_name, flags); - else - printf ("%s ", this_command_name); - -#if defined (ARRAY_VARS) - if (array_p (var)) - print_array_assignment (var, 1); - else if (assoc_p (var)) - print_assoc_assignment (var, 1); - else -#endif - /* force `readonly' and `export' to not print out function definitions - when in POSIX mode. */ - if (nodefs || (function_p (var) && pattr != 0 && posixly_correct)) - printf ("%s\n", var->name); - else if (function_p (var)) - printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL)); - else if (invisible_p (var)) - printf ("%s\n", var->name); - else - { - x = sh_double_quote (var_isset (var) ? value_cell (var) : ""); - printf ("%s=%s\n", var->name, x); - free (x); - } - return (0); -} - -int -show_name_attributes (name, nodefs) - char *name; - int nodefs; -{ - SHELL_VAR *var; - - var = find_variable_internal (name, 1); - - if (var && invisible_p (var) == 0) - { - show_var_attributes (var, READONLY_OR_EXPORT, nodefs); - return (0); - } - else - return (1); -} - -void -set_var_attribute (name, attribute, undo) - char *name; - int attribute, undo; -{ - SHELL_VAR *var, *tv; - char *tvalue; - - if (undo) - var = find_variable (name); - else - { - tv = find_tempenv_variable (name); - /* XXX -- need to handle case where tv is a temp variable in a - function-scope context, since function_env has been merged into - the local variables table. */ - if (tv && tempvar_p (tv)) - { - tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring (""); - - var = bind_variable (tv->name, tvalue, 0); - var->attributes |= tv->attributes & ~att_tempvar; - VSETATTR (tv, att_propagate); - if (var->context != 0) - VSETATTR (var, att_propagate); - SETVARATTR (tv, attribute, undo); /* XXX */ - - stupidly_hack_special_variables (tv->name); - - free (tvalue); - } - else - { - var = find_variable_internal (name, 0); - if (var == 0) - { - var = bind_variable (name, (char *)NULL, 0); - VSETATTR (var, att_invisible); - } - else if (var->context != 0) - VSETATTR (var, att_propagate); - } - } - - if (var) - SETVARATTR (var, attribute, undo); - - if (var && (exported_p (var) || (attribute & att_exported))) - array_needs_making++; /* XXX */ -} diff --git a/builtins/shift.def~ b/builtins/shift.def~ deleted file mode 100644 index af16d1a2a..000000000 --- a/builtins/shift.def~ +++ /dev/null @@ -1,98 +0,0 @@ -This file is shift.def, from which is created shift.c. -It implements the builtin "shift" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 shift.c - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "common.h" - -$BUILTIN shift -$FUNCTION shift_builtin -$SHORT_DOC shift [n] -Shift positional parameters. - -Rename the positional parameters $N+1,$N+2 ... to $1,$2 ... If N is -not given, it is assumed to be 1. -$END - -int print_shift_error; - -/* Shift the arguments ``left''. Shift DOLLAR_VARS down then take one - off of REST_OF_ARGS and place it into DOLLAR_VARS[9]. If LIST has - anything in it, it is a number which says where to start the - shifting. Return > 0 if `times' > $#, otherwise 0. */ -int -shift_builtin (list) - WORD_LIST *list; -{ - intmax_t times; - register int count; - WORD_LIST *temp; - - times = get_numeric_arg (list, 0); - - if (times == 0) - return (EXECUTION_SUCCESS); - else if (times < 0) - { - sh_erange (list ? list->word->word : NULL, _("shift count")); - return (EXECUTION_FAILURE); - } - else if (times > number_of_args ()) - { - if (print_shift_error) - sh_erange (list ? list->word->word : NULL, _("shift count")); - return (EXECUTION_FAILURE); - } - - while (times-- > 0) - { - if (dollar_vars[1]) - free (dollar_vars[1]); - - for (count = 1; count < 9; count++) - dollar_vars[count] = dollar_vars[count + 1]; - - if (rest_of_args) - { - temp = rest_of_args; - dollar_vars[9] = savestring (temp->word->word); - rest_of_args = rest_of_args->next; - temp->next = (WORD_LIST *)NULL; - dispose_words (temp); - } - else - dollar_vars[9] = (char *)NULL; - } - return (EXECUTION_SUCCESS); -} diff --git a/builtins/shopt.def~ b/builtins/shopt.def~ deleted file mode 100644 index 1fbb6c94b..000000000 --- a/builtins/shopt.def~ +++ /dev/null @@ -1,603 +0,0 @@ -This file is shopt.def, from which is created shopt.c. -It implements the Bash `shopt' builtin. - -Copyright (C) 1994-2009 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Bash is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Bash. If not, see . - -$PRODUCES shopt.c - -$BUILTIN shopt -$FUNCTION shopt_builtin -$SHORT_DOC shopt [-pqsu] [-o] [optname ...] -Set and unset shell options. - -Change the setting of each shell option OPTNAME. Without any option -arguments, list all shell options with an indication of whether or not each -is set. - -Options: - -o restrict OPTNAMEs to those defined for use with `set -o' - -p print each shell option with an indication of its status - -q suppress output - -s enable (set) each OPTNAME - -u disable (unset) each OPTNAME - -Exit Status: -Returns success if OPTNAME is enabled; fails if an invalid option is -given or OPTNAME is disabled. -$END - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include - -#include "version.h" - -#include "../bashintl.h" - -#include "../shell.h" -#include "../flags.h" -#include "common.h" -#include "bashgetopt.h" - -#if defined (HISTORY) -# include -# include "../bashhist.h" -#endif - -#define UNSETOPT 0 -#define SETOPT 1 - -#define OPTFMT "%-15s\t%s\n" - -/* When `extglob' is enabled, we don't want to history-expand !(...) */ -#define EXTGLOB_HIST_NOEXPAND " \t\n\r=(" /*)*/ -#define BASIC_HIST_NOEXPAND " \t\n\r=" - -extern int allow_null_glob_expansion, fail_glob_expansion, glob_dot_filenames; -extern int cdable_vars, mail_warning, source_uses_path; -extern int no_exit_on_failed_exec, print_shift_error; -extern int check_hashed_filenames, promptvars; -extern int cdspelling, expand_aliases; -extern int extended_quote; -extern int check_window_size; -extern int glob_ignore_case, match_ignore_case; -extern int hup_on_exit; -extern int xpg_echo; -extern int gnu_error_format; -extern int check_jobs_at_exit; -extern int autocd; -extern int glob_star; - -#if defined (EXTENDED_GLOB) -extern int extended_glob; -#endif - -#if defined (READLINE) -extern int hist_verify, history_reediting, perform_hostname_completion; -extern int no_empty_command_completion; -extern int force_fignore; -extern int dircomplete_spelling; - -extern int enable_hostname_completion __P((int)); -#endif - -#if defined (PROGRAMMABLE_COMPLETION) -extern int prog_completion_enabled; -#endif - -#if defined (RESTRICTED_SHELL) -extern char *shell_name; -#endif - -#if defined (DEBUGGER) -extern int debugging_mode; -#endif - -static void shopt_error __P((char *)); - -static int set_shellopts_after_change __P((int)); - -static int set_compatibility_level __P((int)); - -#if defined (EXTENDED_GLOB) -static int set_extglob __P((int)); -#endif - -#if defined (RESTRICTED_SHELL) -static int set_restricted_shell __P((int)); -#endif - -static int shopt_login_shell; -static int shopt_compat31; -static int shopt_compat32; - -typedef int shopt_set_func_t __P((int)); - -static struct { - char *name; - int *value; - shopt_set_func_t *set_func; -} shopt_vars[] = { - { "autocd", &autocd, (shopt_set_func_t *)NULL }, - { "cdable_vars", &cdable_vars, (shopt_set_func_t *)NULL }, - { "cdspell", &cdspelling, (shopt_set_func_t *)NULL }, - { "checkhash", &check_hashed_filenames, (shopt_set_func_t *)NULL }, -#if defined (JOB_CONTROL) - { "checkjobs", &check_jobs_at_exit, (shopt_set_func_t *)NULL }, -#endif - { "checkwinsize", &check_window_size, (shopt_set_func_t *)NULL }, -#if defined (HISTORY) - { "cmdhist", &command_oriented_history, (shopt_set_func_t *)NULL }, -#endif - { "compat31", &shopt_compat31, set_compatibility_level }, - { "compat32", &shopt_compat32, set_compatibility_level }, -#if defined (READLINE) - { "dirspell", &dircomplete_spelling, (shopt_set_func_t *)NULL }, -#endif - { "dotglob", &glob_dot_filenames, (shopt_set_func_t *)NULL }, - { "execfail", &no_exit_on_failed_exec, (shopt_set_func_t *)NULL }, - { "expand_aliases", &expand_aliases, (shopt_set_func_t *)NULL }, -#if defined (DEBUGGER) - { "extdebug", &debugging_mode, (shopt_set_func_t *)NULL }, -#endif -#if defined (EXTENDED_GLOB) - { "extglob", &extended_glob, (shopt_set_func_t *)NULL }, -#endif - { "extquote", &extended_quote, (shopt_set_func_t *)NULL }, - { "failglob", &fail_glob_expansion, (shopt_set_func_t *)NULL }, -#if defined (READLINE) - { "force_fignore", &force_fignore, (shopt_set_func_t *)NULL }, -#endif - { "globstar", &glob_star, (shopt_set_func_t *)NULL }, - { "gnu_errfmt", &gnu_error_format, (shopt_set_func_t *)NULL }, -#if defined (HISTORY) - { "histappend", &force_append_history, (shopt_set_func_t *)NULL }, -#endif -#if defined (READLINE) - { "histreedit", &history_reediting, (shopt_set_func_t *)NULL }, - { "histverify", &hist_verify, (shopt_set_func_t *)NULL }, - { "hostcomplete", &perform_hostname_completion, enable_hostname_completion }, -#endif - { "huponexit", &hup_on_exit, (shopt_set_func_t *)NULL }, - { "interactive_comments", &interactive_comments, set_shellopts_after_change }, -#if defined (HISTORY) - { "lithist", &literal_history, (shopt_set_func_t *)NULL }, -#endif - { "login_shell", &shopt_login_shell, set_login_shell }, - { "mailwarn", &mail_warning, (shopt_set_func_t *)NULL }, -#if defined (READLINE) - { "no_empty_cmd_completion", &no_empty_command_completion, (shopt_set_func_t *)NULL }, -#endif - { "nocaseglob", &glob_ignore_case, (shopt_set_func_t *)NULL }, - { "nocasematch", &match_ignore_case, (shopt_set_func_t *)NULL }, - { "nullglob", &allow_null_glob_expansion, (shopt_set_func_t *)NULL }, -#if defined (PROGRAMMABLE_COMPLETION) - { "progcomp", &prog_completion_enabled, (shopt_set_func_t *)NULL }, -#endif - { "promptvars", &promptvars, (shopt_set_func_t *)NULL }, -#if defined (RESTRICTED_SHELL) - { "restricted_shell", &restricted_shell, set_restricted_shell }, -#endif - { "shift_verbose", &print_shift_error, (shopt_set_func_t *)NULL }, - { "sourcepath", &source_uses_path, (shopt_set_func_t *)NULL }, - { "xpg_echo", &xpg_echo, (shopt_set_func_t *)NULL }, - { (char *)0, (int *)0, (shopt_set_func_t *)NULL } -}; - -static const char * const on = "on"; -static const char * const off = "off"; - -static int find_shopt __P((char *)); -static int toggle_shopts __P((int, WORD_LIST *, int)); -static void print_shopt __P((char *, int, int)); -static int list_shopts __P((WORD_LIST *, int)); -static int list_some_shopts __P((int, int)); -static int list_shopt_o_options __P((WORD_LIST *, int)); -static int list_some_o_options __P((int, int)); -static int set_shopt_o_options __P((int, WORD_LIST *, int)); - -#define SFLAG 0x01 -#define UFLAG 0x02 -#define QFLAG 0x04 -#define OFLAG 0x08 -#define PFLAG 0x10 - -int -shopt_builtin (list) - WORD_LIST *list; -{ - int opt, flags, rval; - - flags = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "psuoq")) != -1) - { - switch (opt) - { - case 's': - flags |= SFLAG; - break; - case 'u': - flags |= UFLAG; - break; - case 'q': - flags |= QFLAG; - break; - case 'o': - flags |= OFLAG; - break; - case 'p': - flags |= PFLAG; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - if ((flags & (SFLAG|UFLAG)) == (SFLAG|UFLAG)) - { - builtin_error (_("cannot set and unset shell options simultaneously")); - return (EXECUTION_FAILURE); - } - - rval = EXECUTION_SUCCESS; - if ((flags & OFLAG) && ((flags & (SFLAG|UFLAG)) == 0)) /* shopt -o */ - rval = list_shopt_o_options (list, flags); - else if (list && (flags & OFLAG)) /* shopt -so args */ - rval = set_shopt_o_options ((flags & SFLAG) ? FLAG_ON : FLAG_OFF, list, flags & QFLAG); - else if (flags & OFLAG) /* shopt -so */ - rval = list_some_o_options ((flags & SFLAG) ? 1 : 0, flags); - else if (list && (flags & (SFLAG|UFLAG))) /* shopt -su args */ - rval = toggle_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, list, flags & QFLAG); - else if ((flags & (SFLAG|UFLAG)) == 0) /* shopt [args] */ - rval = list_shopts (list, flags); - else /* shopt -su */ - rval = list_some_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, flags); - return (rval); -} - -/* Reset the options managed by `shopt' to the values they would have at - shell startup. */ -void -reset_shopt_options () -{ - allow_null_glob_expansion = glob_dot_filenames = 0; - cdable_vars = mail_warning = 0; - no_exit_on_failed_exec = print_shift_error = 0; - check_hashed_filenames = cdspelling = expand_aliases = check_window_size = 0; - - source_uses_path = promptvars = 1; - -#if defined (EXTENDED_GLOB) - extended_glob = 0; -#endif - -#if defined (HISTORY) - literal_history = force_append_history = 0; - command_oriented_history = 1; -#endif - -#if defined (READLINE) - hist_verify = history_reediting = 0; - perform_hostname_completion = 1; -#endif - - shopt_login_shell = login_shell; -} - -static int -find_shopt (name) - char *name; -{ - int i; - - for (i = 0; shopt_vars[i].name; i++) - if (STREQ (name, shopt_vars[i].name)) - return i; - return -1; -} - -static void -shopt_error (s) - char *s; -{ - builtin_error (_("%s: invalid shell option name"), s); -} - -static int -toggle_shopts (mode, list, quiet) - int mode; - WORD_LIST *list; - int quiet; -{ - WORD_LIST *l; - int ind, rval; - - for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next) - { - ind = find_shopt (l->word->word); - if (ind < 0) - { - shopt_error (l->word->word); - rval = EXECUTION_FAILURE; - } - else - { - *shopt_vars[ind].value = mode; /* 1 for set, 0 for unset */ - if (shopt_vars[ind].set_func) - (*shopt_vars[ind].set_func) (mode); - } - } - return (rval); -} - -static void -print_shopt (name, val, flags) - char *name; - int val, flags; -{ - if (flags & PFLAG) - printf ("shopt %s %s\n", val ? "-s" : "-u", name); - else - printf (OPTFMT, name, val ? on : off); -} - -/* List the values of all or any of the `shopt' options. Returns 0 if - all were listed or all variables queried were on; 1 otherwise. */ -static int -list_shopts (list, flags) - WORD_LIST *list; - int flags; -{ - WORD_LIST *l; - int i, val, rval; - - if (list == 0) - { - for (i = 0; shopt_vars[i].name; i++) - { - val = *shopt_vars[i].value; - if ((flags & QFLAG) == 0) - print_shopt (shopt_vars[i].name, val, flags); - } - return (sh_chkwrite (EXECUTION_SUCCESS)); - } - - for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next) - { - i = find_shopt (l->word->word); - if (i < 0) - { - shopt_error (l->word->word); - rval = EXECUTION_FAILURE; - continue; - } - val = *shopt_vars[i].value; - if (val == 0) - rval = EXECUTION_FAILURE; - if ((flags & QFLAG) == 0) - print_shopt (l->word->word, val, flags); - } - - return (sh_chkwrite (rval)); -} - -static int -list_some_shopts (mode, flags) - int mode, flags; -{ - int val, i; - - for (i = 0; shopt_vars[i].name; i++) - { - val = *shopt_vars[i].value; - if (((flags & QFLAG) == 0) && mode == val) - print_shopt (shopt_vars[i].name, val, flags); - } - return (sh_chkwrite (EXECUTION_SUCCESS)); -} - -static int -list_shopt_o_options (list, flags) - WORD_LIST *list; - int flags; -{ - WORD_LIST *l; - int val, rval; - - if (list == 0) - { - if ((flags & QFLAG) == 0) - list_minus_o_opts (-1, (flags & PFLAG)); - return (sh_chkwrite (EXECUTION_SUCCESS)); - } - - for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next) - { - val = minus_o_option_value (l->word->word); - if (val == -1) - { - sh_invalidoptname (l->word->word); - rval = EXECUTION_FAILURE; - continue; - } - if (val == 0) - rval = EXECUTION_FAILURE; - if ((flags & QFLAG) == 0) - { - if (flags & PFLAG) - printf ("set %co %s\n", val ? '-' : '+', l->word->word); - else - printf (OPTFMT, l->word->word, val ? on : off); - } - } - return (sh_chkwrite (rval)); -} - -static int -list_some_o_options (mode, flags) - int mode, flags; -{ - if ((flags & QFLAG) == 0) - list_minus_o_opts (mode, (flags & PFLAG)); - return (sh_chkwrite (EXECUTION_SUCCESS)); -} - -static int -set_shopt_o_options (mode, list, quiet) - int mode; - WORD_LIST *list; - int quiet; -{ - WORD_LIST *l; - int rval; - - for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next) - { - if (set_minus_o_option (mode, l->word->word) == EXECUTION_FAILURE) - rval = EXECUTION_FAILURE; - } - set_shellopts (); - return rval; -} - -/* If we set or unset interactive_comments with shopt, make sure the - change is reflected in $SHELLOPTS. */ -static int -set_shellopts_after_change (mode) - int mode; -{ - set_shellopts (); - return (0); -} - -static int -set_compatibility_level (mode) - int mode; -{ - /* Need to change logic here as we add more compatibility levels */ - if (shopt_compat31) - shell_compatibility_level = 31; - else if (shopt_compat32) - shell_compatibility_level = 32; - else - shell_compatibility_level = DEFAULT_COMPAT_LEVEL; - return 0; -} - -#if defined (EXTENDED_GLOB) -static int -set_extglob (mode) - int mode; -{ -# if defined (BANG_HISTORY) - history_no_expand_chars = extended_glob ? EXTGLOB_HIST_NOEXPAND : BASIC_HIST_NOEXPAND; -# endif - - return 0; -} -#endif - -#if defined (RESTRICTED_SHELL) -/* Don't allow the value of restricted_shell to be modified. */ - -static int -set_restricted_shell (mode) - int mode; -{ - static int save_restricted = -1; - - if (save_restricted == -1) - save_restricted = shell_is_restricted (shell_name); - - restricted_shell = save_restricted; - return (0); -} -#endif /* RESTRICTED_SHELL */ - -/* Not static so shell.c can call it to initialize shopt_login_shell */ -int -set_login_shell (mode) - int mode; -{ - shopt_login_shell = login_shell != 0; - return (0); -} - -char ** -get_shopt_options () -{ - char **ret; - int n, i; - - n = sizeof (shopt_vars) / sizeof (shopt_vars[0]); - ret = strvec_create (n + 1); - for (i = 0; shopt_vars[i].name; i++) - ret[i] = savestring (shopt_vars[i].name); - ret[i] = (char *)NULL; - return ret; -} - -/* - * External interface for other parts of the shell. NAME is a string option; - * MODE is 0 if we want to unset an option; 1 if we want to set an option. - * REUSABLE is 1 if we want to print output in a form that may be reused. - */ -int -shopt_setopt (name, mode) - char *name; - int mode; -{ - WORD_LIST *wl; - int r; - - wl = add_string_to_list (name, (WORD_LIST *)NULL); - r = toggle_shopts (mode, wl, 0); - dispose_words (wl); - return r; -} - -int -shopt_listopt (name, reusable) - char *name; - int reusable; -{ - int i; - - if (name == 0) - return (list_shopts ((WORD_LIST *)NULL, reusable ? PFLAG : 0)); - - i = find_shopt (name); - if (i < 0) - { - shopt_error (name); - return (EXECUTION_FAILURE); - } - - print_shopt (name, *shopt_vars[i].value, reusable ? PFLAG : 0); - return (sh_chkwrite (EXECUTION_SUCCESS)); -} diff --git a/builtins/source.def~ b/builtins/source.def~ deleted file mode 100644 index 9bdc1e1b5..000000000 --- a/builtins/source.def~ +++ /dev/null @@ -1,182 +0,0 @@ -This file is source.def, from which is created source.c. -It implements the builtins "." and "source" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 source.c - -$BUILTIN source -$FUNCTION source_builtin -$SHORT_DOC source filename [arguments] -Execute commands from a file in the current shell. - -Read and execute commands from FILENAME in the current shell. The -entries in $PATH are used to find the directory containing FILENAME. -If any ARGUMENTS are supplied, they become the positional parameters -when FILENAME is executed. -$END -$BUILTIN . -$DOCNAME dot -$FUNCTION source_builtin -$SHORT_DOC . filename [arguments] -Execute commands from a file in the current shell. - -Read and execute commands from FILENAME in the current shell. The -entries in $PATH are used to find the directory containing FILENAME. -If any ARGUMENTS are supplied, they become the positional parameters -when FILENAME is executed. -$END - -#include - -#include "../bashtypes.h" -#include "posixstat.h" -#include "filecntl.h" -#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../flags.h" -#include "../findcmd.h" -#include "common.h" -#include "bashgetopt.h" -#include "../trap.h" - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int posixly_correct; - -static void maybe_pop_dollar_vars __P((void)); - -/* If non-zero, `.' uses $PATH to look up the script to be sourced. */ -int source_uses_path = 1; - -/* If non-zero, `.' looks in the current directory if the filename argument - is not found in the $PATH. */ -int source_searches_cwd = 1; - -/* If this . script is supplied arguments, we save the dollar vars and - replace them with the script arguments for the duration of the script's - execution. If the script does not change the dollar vars, we restore - what we saved. If the dollar vars are changed in the script, and we are - not executing a shell function, we leave the new values alone and free - the saved values. */ -static void -maybe_pop_dollar_vars () -{ - if (variable_context == 0 && (dollar_vars_changed () & ARGS_SETBLTIN)) - dispose_saved_dollar_vars (); - else - pop_dollar_vars (); - if (debugging_mode) - pop_args (); /* restore BASH_ARGC and BASH_ARGV */ - set_dollar_vars_unchanged (); -} - -/* Read and execute commands from the file passed as argument. Guess what. - This cannot be done in a subshell, since things like variable assignments - take place in there. So, I open the file, place it into a large string, - close the file, and then execute the string. */ -int -source_builtin (list) - WORD_LIST *list; -{ - int result; - char *filename, *debug_trap; - - if (no_options (list)) - return (EX_USAGE); - list = loptend; - - if (list == 0) - { - builtin_error (_("filename argument required")); - builtin_usage (); - return (EX_USAGE); - } - -#if defined (RESTRICTED_SHELL) - if (restricted && strchr (list->word->word, '/')) - { - sh_restricted (list->word->word); - return (EXECUTION_FAILURE); - } -#endif - - filename = (char *)NULL; - /* XXX -- should this be absolute_pathname? */ - if (posixly_correct && strchr (list->word->word, '/')) - filename = savestring (list->word->word); - else if (absolute_pathname (list->word->word)) - filename = savestring (list->word->word); - else if (source_uses_path) - filename = find_path_file (list->word->word); - if (filename == 0) - { - if (source_searches_cwd == 0) - { - builtin_error (_("%s: file not found"), list->word->word); - return (EXECUTION_FAILURE); - } - else - filename = savestring (list->word->word); - } - - begin_unwind_frame ("source"); - add_unwind_protect ((Function *)xfree, filename); - - if (list->next) - { - push_dollar_vars (); - add_unwind_protect ((Function *)maybe_pop_dollar_vars, (char *)NULL); - remember_args (list->next, 1); - if (debugging_mode) - push_args (list->next); /* Update BASH_ARGV and BASH_ARGC */ - } - set_dollar_vars_unchanged (); - - /* Don't inherit the DEBUG trap unless function_trace_mode (overloaded) - is set. XXX - should sourced files inherit the RETURN trap? Functions - don't. */ - debug_trap = TRAP_STRING (DEBUG_TRAP); - if (debug_trap && function_trace_mode == 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); - } - - result = source_file (filename, (list && list->next)); - - run_unwind_frame ("source"); - - return (result); -} diff --git a/builtins/suspend.def~ b/builtins/suspend.def~ deleted file mode 100644 index 93fd51cea..000000000 --- a/builtins/suspend.def~ +++ /dev/null @@ -1,124 +0,0 @@ -This file is suspend.def, from which is created suspend.c. -It implements the builtin "suspend" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 suspend.c - -$BUILTIN suspend -$DEPENDS_ON JOB_CONTROL -$FUNCTION suspend_builtin -$SHORT_DOC suspend [-f] -Suspend shell execution. - -Suspend the execution of this shell until it receives a SIGCONT signal. - -Options: - -f force the suspend, even if the shell is a login shell -$END - -#include - -#if defined (JOB_CONTROL) -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashtypes.h" -#include -#include "../bashintl.h" -#include "../shell.h" -#include "../jobs.h" -#include "common.h" -#include "bashgetopt.h" - -static sighandler suspend_continue __P((int)); - -static SigHandler *old_cont; -#if 0 -static SigHandler *old_stop; -#endif - -/* Continue handler. */ -static sighandler -suspend_continue (sig) - int sig; -{ - set_signal_handler (SIGCONT, old_cont); -#if 0 - set_signal_handler (SIGSTOP, old_stop); -#endif - SIGRETURN (0); -} - -/* Suspending the shell. If -f is the arg, then do the suspend - no matter what. Otherwise, complain if a login shell. */ -int -suspend_builtin (list) - WORD_LIST *list; -{ - int opt, force; - - reset_internal_getopt (); - force = 0; - while ((opt = internal_getopt (list, "f")) != -1) - switch (opt) - { - case 'f': - force++; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - - list = loptend; - - if (job_control == 0) - { - sh_nojobs (_("cannot suspend")); - return (EXECUTION_FAILURE); - } - - if (force == 0) - { - no_args (list); - - if (login_shell) - { - builtin_error (_("cannot suspend a login shell")); - return (EXECUTION_FAILURE); - } - } - - /* XXX - should we put ourselves back into the original pgrp now? If so, - call end_job_control() here and do the right thing in suspend_continue - (that is, call restart_job_control()). */ - old_cont = (SigHandler *)set_signal_handler (SIGCONT, suspend_continue); -#if 0 - old_stop = (SigHandler *)set_signal_handler (SIGSTOP, SIG_DFL); -#endif - killpg (shell_pgrp, SIGSTOP); - return (EXECUTION_SUCCESS); -} - -#endif /* JOB_CONTROL */ diff --git a/builtins/test.def~ b/builtins/test.def~ deleted file mode 100644 index ff0b0d008..000000000 --- a/builtins/test.def~ +++ /dev/null @@ -1,151 +0,0 @@ -This file is test.def, from which is created test.c. -It implements the builtin "test" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 test.c - -$BUILTIN test -$FUNCTION test_builtin -$SHORT_DOC test [expr] -Evaluate conditional expression. - -Exits with a status of 0 (true) or 1 (false) depending on -the evaluation of EXPR. Expressions may be unary or binary. Unary -expressions are often used to examine the status of a file. There -are string operators as well, and numeric comparison operators. - -File operators: - - -a FILE True if file exists. - -b FILE True if file is block special. - -c FILE True if file is character special. - -d FILE True if file is a directory. - -e FILE True if file exists. - -f FILE True if file exists and is a regular file. - -g FILE True if file is set-group-id. - -h FILE True if file is a symbolic link. - -L FILE True if file is a symbolic link. - -k FILE True if file has its `sticky' bit set. - -p FILE True if file is a named pipe. - -r FILE True if file is readable by you. - -s FILE True if file exists and is not empty. - -S FILE True if file is a socket. - -t FD True if FD is opened on a terminal. - -u FILE True if the file is set-user-id. - -w FILE True if the file is writable by you. - -x FILE True if the file is executable by you. - -O FILE True if the file is effectively owned by you. - -G FILE True if the file is effectively owned by your group. - -N FILE True if the file has been modified since it was last read. - - FILE1 -nt FILE2 True if file1 is newer than file2 (according to - modification date). - - FILE1 -ot FILE2 True if file1 is older than file2. - - FILE1 -ef FILE2 True if file1 is a hard link to file2. - -String operators: - - -z STRING True if string is empty. - - -n STRING - STRING True if string is not empty. - - STRING1 = STRING2 - True if the strings are equal. - STRING1 != STRING2 - True if the strings are not equal. - STRING1 < STRING2 - True if STRING1 sorts before STRING2 lexicographically. - STRING1 > STRING2 - True if STRING1 sorts after STRING2 lexicographically. - -Other operators: - - -o OPTION True if the shell option OPTION is enabled. - ! EXPR True if expr is false. - EXPR1 -a EXPR2 True if both expr1 AND expr2 are true. - EXPR1 -o EXPR2 True if either expr1 OR expr2 is true. - - arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne, - -lt, -le, -gt, or -ge. - -Arithmetic binary operators return true if ARG1 is equal, not-equal, -less-than, less-than-or-equal, greater-than, or greater-than-or-equal -than ARG2. -$END - -$BUILTIN [ -$DOCNAME test_bracket -$FUNCTION test_builtin -$SHORT_DOC [ arg... ] -Evaluate conditional expression. - -This is a synonym for the "test" builtin, but the last argument must -be a literal `]', to match the opening `['. -$END - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../test.h" -#include "common.h" - -extern char *this_command_name; - -/* TEST/[ builtin. */ -int -test_builtin (list) - WORD_LIST *list; -{ - char **argv; - int argc, result; - - /* We let Matthew Bradburn and Kevin Braunsdorf's code do the - actual test command. So turn the list of args into an array - of strings, since that is what their code wants. */ - if (list == 0) - { - if (this_command_name[0] == '[' && !this_command_name[1]) - { - builtin_error (_("missing `]'")); - return (EX_BADUSAGE); - } - - return (EXECUTION_FAILURE); - } - - argv = make_builtin_argv (list, &argc); - result = test_command (argc, argv); - free ((char *)argv); - - return (result); -} diff --git a/builtins/times.def~ b/builtins/times.def~ deleted file mode 100644 index d08b5aeef..000000000 --- a/builtins/times.def~ +++ /dev/null @@ -1,117 +0,0 @@ -This file is times.def, from which is created times.c. -It implements the builtin "times" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 times.c - -$BUILTIN times -$FUNCTION times_builtin -$SHORT_DOC times -Display process times. - -Prints the accumulated user and system times for the shell and all of its -child processes. -$END - -#include - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include "../bashtypes.h" -#include "../shell.h" - -#include - -#if defined (HAVE_SYS_TIMES_H) -# include -#endif /* HAVE_SYS_TIMES_H */ - -#if defined (HAVE_SYS_RESOURCE_H) && !defined (RLIMTYPE) -# include -#endif - -#include "common.h" - -/* Print the totals for system and user time used. */ -int -times_builtin (list) - WORD_LIST *list; -{ -#if defined (HAVE_GETRUSAGE) && defined (HAVE_TIMEVAL) && defined (RUSAGE_SELF) - struct rusage self, kids; - - USE_VAR(list); - - if (no_options (list)) - return (EX_USAGE); - - getrusage (RUSAGE_SELF, &self); - getrusage (RUSAGE_CHILDREN, &kids); /* terminated child processes */ - - print_timeval (stdout, &self.ru_utime); - putchar (' '); - print_timeval (stdout, &self.ru_stime); - putchar ('\n'); - print_timeval (stdout, &kids.ru_utime); - putchar (' '); - print_timeval (stdout, &kids.ru_stime); - putchar ('\n'); - -#else -# if defined (HAVE_TIMES) - /* This uses the POSIX.1/XPG5 times(2) interface, which fills in a - `struct tms' with values of type clock_t. */ - struct tms t; - - USE_VAR(list); - - if (no_options (list)) - return (EX_USAGE); - - times (&t); - - print_clock_t (stdout, t.tms_utime); - putchar (' '); - print_clock_t (stdout, t.tms_stime); - putchar ('\n'); - print_clock_t (stdout, t.tms_cutime); - putchar (' '); - print_clock_t (stdout, t.tms_cstime); - putchar ('\n'); - -# else /* !HAVE_TIMES */ - - USE_VAR(list); - - if (no_options (list)) - return (EX_USAGE); - printf ("0.00 0.00\n0.00 0.00\n"); - -# endif /* HAVE_TIMES */ -#endif /* !HAVE_TIMES */ - - return (sh_chkwrite (EXECUTION_SUCCESS)); -} diff --git a/builtins/trap.def~ b/builtins/trap.def~ deleted file mode 100644 index e93267b19..000000000 --- a/builtins/trap.def~ +++ /dev/null @@ -1,278 +0,0 @@ -This file is trap.def, from which is created trap.c. -It implements the builtin "trap" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 ...] -Trap signals and other events. - -Defines and activates handlers to be run when the shell receives signals -or other conditions. - -ARG is a command to be read and executed when the shell receives the -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) ARG is executed on exit from the shell. If -a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command. - -If no arguments are supplied, trap prints the list of commands associated -with each signal. - -Options: - -l print a list of signal names and their corresponding numbers - -p display the trap commands associated with each SIGNAL_SPEC - -Each SIGNAL_SPEC is either a signal name in or a signal number. -Signal names are case insensitive and the SIG prefix is optional. A -signal may 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 (sh_chkwrite (display_signal_list ((WORD_LIST *)NULL, 1))); - else if (display || list == 0) - return (sh_chkwrite (display_traps (list))); - else - { - char *first_arg; - int operation, sig, first_signal; - - operation = SET; - first_arg = list->word->word; - first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt); - - /* Backwards compatibility. XXX - question about whether or not we - should throw an error if an all-digit argument doesn't correspond - to a valid signal number (e.g., if it's `50' on a system with only - 32 signals). */ - if (first_signal) - operation = REVERT; - /* 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. */ - else 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, termsig_sighandler); - 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/type.def~ b/builtins/type.def~ deleted file mode 100644 index 4cd30bcf6..000000000 --- a/builtins/type.def~ +++ /dev/null @@ -1,401 +0,0 @@ -This file is type.def, from which is created type.c. -It implements the builtin "type" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 type.c - -$BUILTIN type -$FUNCTION type_builtin -$SHORT_DOC type [-afptP] name [name ...] -Display information about command type. - -For each NAME, indicate how it would be interpreted if used as a -command name. - -Options: - -a display all locations containing an executable named NAME; - includes aliases, builtins, and functions, if and only if - the `-p' option is not also used - -f suppress shell function lookup - -P force a PATH search for each NAME, even if it is an alias, - builtin, or function, and returns the name of the disk file - that would be executed - -p returns either the name of the disk file that would be executed, - or nothing if `type -t NAME' would not return `file'. - -t output a single word which is one of `alias', `keyword', - `function', `builtin', `file' or `', if NAME is an alias, shell - reserved word, shell function, shell builtin, disk file, or not - found, respectively - -Arguments: - NAME Command name to be interpreted. -$END - -#include - -#include "../bashtypes.h" -#include "posixstat.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include "../bashansi.h" -#include "../bashintl.h" - -#include "../shell.h" -#include "../findcmd.h" -#include "../hashcmd.h" - -#if defined (ALIAS) -#include "../alias.h" -#endif /* ALIAS */ - -#include "common.h" -#include "bashgetopt.h" - -extern int find_reserved_word __P((char *)); - -extern char *this_command_name; -extern int expand_aliases, posixly_correct; - -/* For each word in LIST, find out what the shell is going to do with - it as a simple command. i.e., which file would this shell use to - execve, or if it is a builtin command, or an alias. Possible flag - arguments: - -t Returns the "type" of the object, one of - `alias', `keyword', `function', `builtin', - or `file'. - - -p Returns the pathname of the file if -type is - a file. - - -a Returns all occurrences of words, whether they - be a filename in the path, alias, function, - or builtin. - - -f Suppress shell function lookup, like `command'. - - -P Force a path search even in the presence of other - definitions. - - Order of evaluation: - alias - keyword - function - builtin - file - */ - -int -type_builtin (list) - WORD_LIST *list; -{ - int dflags, any_failed, opt; - WORD_LIST *this; - - if (list == 0) - return (EXECUTION_SUCCESS); - - dflags = CDESC_SHORTDESC; /* default */ - any_failed = 0; - - /* Handle the obsolescent `-type', `-path', and `-all' by prescanning - the arguments and converting those options to the form that - internal_getopt recognizes. Converts `--type', `--path', and `--all' - also. THIS SHOULD REALLY GO AWAY. */ - for (this = list; this && this->word->word[0] == '-'; this = this->next) - { - char *flag = &(this->word->word[1]); - - if (STREQ (flag, "type") || STREQ (flag, "-type")) - { - this->word->word[1] = 't'; - this->word->word[2] = '\0'; - } - else if (STREQ (flag, "path") || STREQ (flag, "-path")) - { - this->word->word[1] = 'p'; - this->word->word[2] = '\0'; - } - else if (STREQ (flag, "all") || STREQ (flag, "-all")) - { - this->word->word[1] = 'a'; - this->word->word[2] = '\0'; - } - } - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "afptP")) != -1) - { - switch (opt) - { - case 'a': - dflags |= CDESC_ALL; - break; - case 'f': - dflags |= CDESC_NOFUNCS; - break; - case 'p': - dflags |= CDESC_PATH_ONLY; - dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC); - break; - case 't': - dflags |= CDESC_TYPE; - dflags &= ~(CDESC_PATH_ONLY|CDESC_SHORTDESC); - break; - case 'P': /* shorthand for type -ap */ - dflags |= (CDESC_PATH_ONLY|CDESC_FORCE_PATH); - dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC); - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - while (list) - { - int found; - - found = describe_command (list->word->word, dflags); - - if (!found && (dflags & (CDESC_PATH_ONLY|CDESC_TYPE)) == 0) - sh_notfound (list->word->word); - - any_failed += found == 0; - list = list->next; - } - - opt = (any_failed == 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE; - return (sh_chkwrite (opt)); -} - -/* - * Describe COMMAND as required by the type and command builtins. - * - * Behavior is controlled by DFLAGS. Flag values are - * CDESC_ALL print all descriptions of a command - * CDESC_SHORTDESC print the description for type and command -V - * CDESC_REUSABLE print in a format that may be reused as input - * CDESC_TYPE print the type for type -t - * CDESC_PATH_ONLY print the path for type -p - * CDESC_FORCE_PATH force a path search for type -P - * CDESC_NOFUNCS skip function lookup for type -f - * CDESC_ABSPATH convert to absolute path, no ./ prefix - * - * CDESC_ALL says whether or not to look for all occurrences of COMMAND, or - * return after finding it once. - */ -int -describe_command (command, dflags) - char *command; - int dflags; -{ - int found, i, found_file, f, all; - char *full_path, *x; - SHELL_VAR *func; -#if defined (ALIAS) - alias_t *alias; -#endif - - all = (dflags & CDESC_ALL) != 0; - found = found_file = 0; - full_path = (char *)NULL; - -#if defined (ALIAS) - /* Command is an alias? */ - if (((dflags & CDESC_FORCE_PATH) == 0) && expand_aliases && (alias = find_alias (command))) - { - if (dflags & CDESC_TYPE) - puts ("alias"); - else if (dflags & CDESC_SHORTDESC) - printf (_("%s is aliased to `%s'\n"), command, alias->value); - else if (dflags & CDESC_REUSABLE) - { - x = sh_single_quote (alias->value); - printf ("alias %s=%s\n", command, x); - free (x); - } - - found = 1; - - if (all == 0) - return (1); - } -#endif /* ALIAS */ - - /* Command is a shell reserved word? */ - if (((dflags & CDESC_FORCE_PATH) == 0) && (i = find_reserved_word (command)) >= 0) - { - if (dflags & CDESC_TYPE) - puts ("keyword"); - else if (dflags & CDESC_SHORTDESC) - printf (_("%s is a shell keyword\n"), command); - else if (dflags & CDESC_REUSABLE) - printf ("%s\n", command); - - found = 1; - - if (all == 0) - return (1); - } - - /* Command is a function? */ - if (((dflags & (CDESC_FORCE_PATH|CDESC_NOFUNCS)) == 0) && (func = find_function (command))) - { - if (dflags & CDESC_TYPE) - puts ("function"); - else if (dflags & CDESC_SHORTDESC) - { - char *result; - - printf (_("%s is a function\n"), command); - - /* We're blowing away THE_PRINTED_COMMAND here... */ - - result = named_function_string (command, function_cell (func), FUNC_MULTILINE|FUNC_EXTERNAL); - printf ("%s\n", result); - } - else if (dflags & CDESC_REUSABLE) - printf ("%s\n", command); - - found = 1; - - if (all == 0) - return (1); - } - - /* Command is a builtin? */ - if (((dflags & CDESC_FORCE_PATH) == 0) && find_shell_builtin (command)) - { - if (dflags & CDESC_TYPE) - puts ("builtin"); - else if (dflags & CDESC_SHORTDESC) - printf (_("%s is a shell builtin\n"), command); - else if (dflags & CDESC_REUSABLE) - printf ("%s\n", command); - - found = 1; - - if (all == 0) - return (1); - } - - /* Command is a disk file? */ - /* If the command name given is already an absolute command, just - check to see if it is executable. */ - if (absolute_program (command)) - { - f = file_status (command); - if (f & FS_EXECABLE) - { - if (dflags & CDESC_TYPE) - puts ("file"); - else if (dflags & CDESC_SHORTDESC) - printf (_("%s is %s\n"), command, command); - else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY)) - printf ("%s\n", command); - - /* There's no use looking in the hash table or in $PATH, - because they're not consulted when an absolute program - name is supplied. */ - return (1); - } - } - - /* If the user isn't doing "-a", then we might care about - whether the file is present in our hash table. */ - if (all == 0 || (dflags & CDESC_FORCE_PATH)) - { - if (full_path = phash_search (command)) - { - if (dflags & CDESC_TYPE) - puts ("file"); - else if (dflags & CDESC_SHORTDESC) - printf (_("%s is hashed (%s)\n"), command, full_path); - else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY)) - printf ("%s\n", full_path); - - free (full_path); - return (1); - } - } - - /* Now search through $PATH. */ - while (1) - { - if (all == 0) - full_path = find_user_command (command); - else - full_path = - user_command_matches (command, FS_EXEC_ONLY, found_file); - /* XXX - should that be FS_EXEC_PREFERRED? */ - - if (!full_path) - break; - - /* If we found the command as itself by looking through $PATH, it - probably doesn't exist. Check whether or not the command is an - executable file. If it's not, don't report a match. This is - the default posix mode behavior */ - if (STREQ (full_path, command) || posixly_correct) - { - f = file_status (full_path); - if ((f & FS_EXECABLE) == 0) - { - free (full_path); - full_path = (char *)NULL; - if (all == 0) - break; - } - else if (ABSPATH (full_path)) - ; /* placeholder; don't need to do anything yet */ - else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY|CDESC_SHORTDESC)) - { - f = MP_DOCWD | ((dflags & CDESC_ABSPATH) ? MP_RMDOT : 0); - full_path = sh_makepath ((char *)NULL, full_path, f); - } - } - /* If we require a full path and don't have one, make one */ - else if ((dflags & CDESC_ABSPATH) && ABSPATH (full_path) == 0) - full_path = sh_makepath ((char *)NULL, full_path, MP_DOCWD|MP_RMDOT); - - found_file++; - found = 1; - - if (dflags & CDESC_TYPE) - puts ("file"); - else if (dflags & CDESC_SHORTDESC) - printf (_("%s is %s\n"), command, full_path); - else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY)) - printf ("%s\n", full_path); - - free (full_path); - full_path = (char *)NULL; - - if (all == 0) - break; - } - - return (found); -} diff --git a/builtins/ulimit.def~ b/builtins/ulimit.def~ deleted file mode 100644 index 9180da046..000000000 --- a/builtins/ulimit.def~ +++ /dev/null @@ -1,772 +0,0 @@ -This file is ulimit.def, from which is created ulimit.c. -It implements the builtin "ulimit" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Bash is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Bash. If not, see . - -$PRODUCES ulimit.c - -$BUILTIN ulimit -$FUNCTION ulimit_builtin -$DEPENDS_ON !_MINIX -$SHORT_DOC ulimit [-SHacdefilmnpqrstuvx] [limit] -Modify shell resource limits. - -Provides control over the resources available to the shell and processes -it creates, on systems that allow such control. - -Options: - -S use the `soft' resource limit - -H use the `hard' resource limit - -a all current limits are reported - -b the socket buffer size - -c the maximum size of core files created - -d the maximum size of a process's data segment - -e the maximum scheduling priority (`nice') - -f the maximum size of files written by the shell and its children - -i the maximum number of pending signals - -l the maximum size a process may lock into memory - -m the maximum resident set size - -n the maximum number of open file descriptors - -p the pipe buffer size - -q the maximum number of bytes in POSIX message queues - -r the maximum real-time scheduling priority - -s the maximum stack size - -t the maximum amount of cpu time in seconds - -u the maximum number of user processes - -v the size of virtual memory - -x the maximum number of file locks - -If LIMIT is given, it is the new value of the specified resource; the -special LIMIT values `soft', `hard', and `unlimited' stand for the -current soft limit, the current hard limit, and no limit, respectively. -Otherwise, the current value of the specified resource is printed. If -no option is given, then -f is assumed. - -Values are in 1024-byte increments, except for -t, which is in seconds, --p, which is in increments of 512 bytes, and -u, which is an unscaled -number of processes. - -Exit Status: -Returns success unless an invalid option is supplied or an error occurs. -$END - -#if !defined (_MINIX) - -#include - -#include "../bashtypes.h" -#ifndef _MINIX -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include - -#include "../bashintl.h" - -#include "../shell.h" -#include "common.h" -#include "bashgetopt.h" -#include "pipesize.h" - -#if !defined (errno) -extern int errno; -#endif - -/* For some reason, HPUX chose to make these definitions visible only if - _KERNEL is defined, so we define _KERNEL before including - and #undef it afterward. */ -#if defined (HAVE_RESOURCE) -# include -# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL) -# define _KERNEL -# endif -# include -# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL) -# undef _KERNEL -# endif -#elif defined (HAVE_SYS_TIMES_H) -# include -#endif - -#if defined (HAVE_LIMITS_H) -# include -#endif - -/* Check for the most basic symbols. If they aren't present, this - system's isn't very useful to us. */ -#if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT) -# undef HAVE_RESOURCE -#endif - -#if !defined (RLIMTYPE) -# define RLIMTYPE long -# define string_to_rlimtype(s) strtol(s, (char **)NULL, 10) -# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "") -#endif - -/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */ -#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE) -# define RLIMIT_NOFILE RLIMIT_OFILE -#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */ - -/* Some systems have these, some do not. */ -#ifdef RLIMIT_FSIZE -# define RLIMIT_FILESIZE RLIMIT_FSIZE -#else -# define RLIMIT_FILESIZE 256 -#endif - -#define RLIMIT_PIPESIZE 257 - -#ifdef RLIMIT_NOFILE -# define RLIMIT_OPENFILES RLIMIT_NOFILE -#else -# define RLIMIT_OPENFILES 258 -#endif - -#ifdef RLIMIT_VMEM -# define RLIMIT_VIRTMEM RLIMIT_VMEM -# define RLIMIT_VMBLKSZ 1024 -#else -# ifdef RLIMIT_AS -# define RLIMIT_VIRTMEM RLIMIT_AS -# define RLIMIT_VMBLKSZ 1024 -# else -# define RLIMIT_VIRTMEM 259 -# define RLIMIT_VMBLKSZ 1 -# endif -#endif - -#ifdef RLIMIT_NPROC -# define RLIMIT_MAXUPROC RLIMIT_NPROC -#else -# define RLIMIT_MAXUPROC 260 -#endif - -#if !defined (RLIM_INFINITY) -# define RLIM_INFINITY 0x7fffffff -#endif - -#if !defined (RLIM_SAVED_CUR) -# define RLIM_SAVED_CUR RLIM_INFINITY -#endif - -#if !defined (RLIM_SAVED_MAX) -# define RLIM_SAVED_MAX RLIM_INFINITY -#endif - -#define LIMIT_HARD 0x01 -#define LIMIT_SOFT 0x02 - -/* "Blocks" are defined as 512 bytes when in Posix mode and 1024 bytes - otherwise. */ -#define POSIXBLK -2 - -#define BLOCKSIZE(x) (((x) == POSIXBLK && posixly_correct) ? 512 : 1024) - -extern int posixly_correct; - -static int _findlim __P((int)); - -static int ulimit_internal __P((int, char *, int, int)); - -static int get_limit __P((int, RLIMTYPE *, RLIMTYPE *)); -static int set_limit __P((int, RLIMTYPE, int)); - -static void printone __P((int, RLIMTYPE, int)); -static void print_all_limits __P((int)); - -static int set_all_limits __P((int, RLIMTYPE)); - -static int filesize __P((RLIMTYPE *)); -static int pipesize __P((RLIMTYPE *)); -static int getmaxuprc __P((RLIMTYPE *)); -static int getmaxvm __P((RLIMTYPE *, RLIMTYPE *)); - -typedef struct { - int option; /* The ulimit option for this limit. */ - int parameter; /* Parameter to pass to get_limit (). */ - int block_factor; /* Blocking factor for specific limit. */ - const char * const description; /* Descriptive string to output. */ - const char * const units; /* scale */ -} RESOURCE_LIMITS; - -static RESOURCE_LIMITS limits[] = { -#ifdef RLIMIT_PTHREAD - { 'T', RLIMIT_PTHREAD, 1, "number of threads", (char *)NULL }, -#endif -#ifdef RLIMIT_SBSIZE - { 'b', RLIMIT_SBSIZE, 1, "socket buffer size", "bytes" }, -#endif -#ifdef RLIMIT_CORE - { 'c', RLIMIT_CORE, POSIXBLK, "core file size", "blocks" }, -#endif -#ifdef RLIMIT_DATA - { 'd', RLIMIT_DATA, 1024, "data seg size", "kbytes" }, -#endif -#ifdef RLIMIT_NICE - { 'e', RLIMIT_NICE, 1, "scheduling priority", (char *)NULL }, -#endif - { 'f', RLIMIT_FILESIZE, POSIXBLK, "file size", "blocks" }, -#ifdef RLIMIT_SIGPENDING - { 'i', RLIMIT_SIGPENDING, 1, "pending signals", (char *)NULL }, -#endif -#ifdef RLIMIT_MEMLOCK - { 'l', RLIMIT_MEMLOCK, 1024, "max locked memory", "kbytes" }, -#endif -#ifdef RLIMIT_RSS - { 'm', RLIMIT_RSS, 1024, "max memory size", "kbytes" }, -#endif /* RLIMIT_RSS */ - { 'n', RLIMIT_OPENFILES, 1, "open files", (char *)NULL}, - { 'p', RLIMIT_PIPESIZE, 512, "pipe size", "512 bytes" }, -#ifdef RLIMIT_MSGQUEUE - { 'q', RLIMIT_MSGQUEUE, 1, "POSIX message queues", "bytes" }, -#endif -#ifdef RLIMIT_RTPRIO - { 'r', RLIMIT_RTPRIO, 1, "real-time priority", (char *)NULL }, -#endif -#ifdef RLIMIT_STACK - { 's', RLIMIT_STACK, 1024, "stack size", "kbytes" }, -#endif -#ifdef RLIMIT_CPU - { 't', RLIMIT_CPU, 1, "cpu time", "seconds" }, -#endif /* RLIMIT_CPU */ - { 'u', RLIMIT_MAXUPROC, 1, "max user processes", (char *)NULL }, -#if defined (HAVE_RESOURCE) - { 'v', RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory", "kbytes" }, -#endif -#ifdef RLIMIT_SWAP - { 'w', RLIMIT_SWAP, 1024, "swap size", "kbytes" }, -#endif -#ifdef RLIMIT_LOCKS - { 'x', RLIMIT_LOCKS, 1, "file locks", (char *)NULL }, -#endif - { -1, -1, -1, (char *)NULL, (char *)NULL } -}; -#define NCMDS (sizeof(limits) / sizeof(limits[0])) - -typedef struct _cmd { - int cmd; - char *arg; -} ULCMD; - -static ULCMD *cmdlist; -static int ncmd; -static int cmdlistsz; - -#if !defined (HAVE_RESOURCE) && !defined (HAVE_ULIMIT) -long -ulimit (cmd, newlim) - int cmd; - long newlim; -{ - errno = EINVAL; - return -1; -} -#endif /* !HAVE_RESOURCE && !HAVE_ULIMIT */ - -static int -_findlim (opt) - int opt; -{ - register int i; - - for (i = 0; limits[i].option > 0; i++) - if (limits[i].option == opt) - return i; - return -1; -} - -static char optstring[4 + 2 * NCMDS]; - -/* Report or set limits associated with certain per-process resources. - See the help documentation in builtins.c for a full description. */ -int -ulimit_builtin (list) - register WORD_LIST *list; -{ - register char *s; - int c, limind, mode, opt, all_limits; - - mode = 0; - - all_limits = 0; - - /* Idea stolen from pdksh -- build option string the first time called. */ - if (optstring[0] == 0) - { - s = optstring; - *s++ = 'a'; *s++ = 'S'; *s++ = 'H'; - for (c = 0; limits[c].option > 0; c++) - { - *s++ = limits[c].option; - *s++ = ';'; - } - *s = '\0'; - } - - /* Initialize the command list. */ - if (cmdlistsz == 0) - cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD)); - ncmd = 0; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, optstring)) != -1) - { - switch (opt) - { - case 'a': - all_limits++; - break; - - /* -S and -H are modifiers, not real options. */ - case 'S': - mode |= LIMIT_SOFT; - break; - - case 'H': - mode |= LIMIT_HARD; - break; - - case '?': - builtin_usage (); - return (EX_USAGE); - - default: - if (ncmd >= cmdlistsz) - cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD)); - cmdlist[ncmd].cmd = opt; - cmdlist[ncmd++].arg = list_optarg; - break; - } - } - list = loptend; - - if (all_limits) - { -#ifdef NOTYET - if (list) /* setting */ - { - if (STREQ (list->word->word, "unlimited") == 0) - { - builtin_error (_("%s: invalid limit argument"), list->word->word); - return (EXECUTION_FAILURE); - } - return (set_all_limits (mode == 0 ? LIMIT_SOFT|LIMIT_HARD : mode, RLIM_INFINITY)); - } -#endif - print_all_limits (mode == 0 ? LIMIT_SOFT : mode); - return (sh_chkwrite (EXECUTION_SUCCESS)); - } - - /* default is `ulimit -f' */ - if (ncmd == 0) - { - cmdlist[ncmd].cmd = 'f'; - /* `ulimit something' is same as `ulimit -f something' */ - cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL; - if (list) - list = list->next; - } - - /* verify each command in the list. */ - for (c = 0; c < ncmd; c++) - { - limind = _findlim (cmdlist[c].cmd); - if (limind == -1) - { - builtin_error (_("`%c': bad command"), cmdlist[c].cmd); - return (EX_USAGE); - } - } - - for (c = 0; c < ncmd; c++) - if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE) - return (EXECUTION_FAILURE); - - return (EXECUTION_SUCCESS); -} - -static int -ulimit_internal (cmd, cmdarg, mode, multiple) - int cmd; - char *cmdarg; - int mode, multiple; -{ - int opt, limind, setting; - int block_factor; - RLIMTYPE soft_limit, hard_limit, real_limit, limit; - - setting = cmdarg != 0; - limind = _findlim (cmd); - if (mode == 0) - mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT; - opt = get_limit (limind, &soft_limit, &hard_limit); - if (opt < 0) - { - builtin_error (_("%s: cannot get limit: %s"), limits[limind].description, - strerror (errno)); - return (EXECUTION_FAILURE); - } - - if (setting == 0) /* print the value of the specified limit */ - { - printone (limind, (mode & LIMIT_SOFT) ? soft_limit : hard_limit, multiple); - return (EXECUTION_SUCCESS); - } - - /* Setting the limit. */ - if (STREQ (cmdarg, "hard")) - real_limit = hard_limit; - else if (STREQ (cmdarg, "soft")) - real_limit = soft_limit; - else if (STREQ (cmdarg, "unlimited")) - real_limit = RLIM_INFINITY; - else if (all_digits (cmdarg)) - { - limit = string_to_rlimtype (cmdarg); - block_factor = BLOCKSIZE(limits[limind].block_factor); - real_limit = limit * block_factor; - - if ((real_limit / block_factor) != limit) - { - sh_erange (cmdarg, _("limit")); - return (EXECUTION_FAILURE); - } - } - else - { - sh_invalidnum (cmdarg); - return (EXECUTION_FAILURE); - } - - if (set_limit (limind, real_limit, mode) < 0) - { - builtin_error (_("%s: cannot modify limit: %s"), limits[limind].description, - strerror (errno)); - return (EXECUTION_FAILURE); - } - - return (EXECUTION_SUCCESS); -} - -static int -get_limit (ind, softlim, hardlim) - int ind; - RLIMTYPE *softlim, *hardlim; -{ - RLIMTYPE value; -#if defined (HAVE_RESOURCE) - struct rlimit limit; -#endif - - if (limits[ind].parameter >= 256) - { - switch (limits[ind].parameter) - { - case RLIMIT_FILESIZE: - if (filesize (&value) < 0) - return -1; - break; - case RLIMIT_PIPESIZE: - if (pipesize (&value) < 0) - return -1; - break; - case RLIMIT_OPENFILES: - value = (RLIMTYPE)getdtablesize (); - break; - case RLIMIT_VIRTMEM: - return (getmaxvm (softlim, hardlim)); - case RLIMIT_MAXUPROC: - if (getmaxuprc (&value) < 0) - return -1; - break; - default: - errno = EINVAL; - return -1; - } - *softlim = *hardlim = value; - return (0); - } - else - { -#if defined (HAVE_RESOURCE) - if (getrlimit (limits[ind].parameter, &limit) < 0) - return -1; - *softlim = limit.rlim_cur; - *hardlim = limit.rlim_max; -# if defined (HPUX9) - if (limits[ind].parameter == RLIMIT_FILESIZE) - { - *softlim *= 512; - *hardlim *= 512; /* Ugh. */ - } - else -# endif /* HPUX9 */ - return 0; -#else - errno = EINVAL; - return -1; -#endif - } -} - -static int -set_limit (ind, newlim, mode) - int ind; - RLIMTYPE newlim; - int mode; -{ -#if defined (HAVE_RESOURCE) - struct rlimit limit; - RLIMTYPE val; -#endif - - if (limits[ind].parameter >= 256) - switch (limits[ind].parameter) - { - case RLIMIT_FILESIZE: -#if !defined (HAVE_RESOURCE) - return (ulimit (2, newlim / 512L)); -#else - errno = EINVAL; - return -1; -#endif - - case RLIMIT_OPENFILES: -#if defined (HAVE_SETDTABLESIZE) -# if defined (__CYGWIN__) - /* Grrr... Cygwin declares setdtablesize as void. */ - setdtablesize (newlim); - return 0; -# else - return (setdtablesize (newlim)); -# endif -#endif - case RLIMIT_PIPESIZE: - case RLIMIT_VIRTMEM: - case RLIMIT_MAXUPROC: - default: - errno = EINVAL; - return -1; - } - else - { -#if defined (HAVE_RESOURCE) - if (getrlimit (limits[ind].parameter, &limit) < 0) - return -1; -# if defined (HPUX9) - if (limits[ind].parameter == RLIMIT_FILESIZE) - newlim /= 512; /* Ugh. */ -# endif /* HPUX9 */ - val = (current_user.euid != 0 && newlim == RLIM_INFINITY && - (mode & LIMIT_HARD) == 0 && /* XXX -- test */ - (limit.rlim_cur <= limit.rlim_max)) - ? limit.rlim_max : newlim; - if (mode & LIMIT_SOFT) - limit.rlim_cur = val; - if (mode & LIMIT_HARD) - limit.rlim_max = val; - - return (setrlimit (limits[ind].parameter, &limit)); -#else - errno = EINVAL; - return -1; -#endif - } -} - -static int -getmaxvm (softlim, hardlim) - RLIMTYPE *softlim, *hardlim; -{ -#if defined (HAVE_RESOURCE) - struct rlimit datalim, stacklim; - - if (getrlimit (RLIMIT_DATA, &datalim) < 0) - return -1; - - if (getrlimit (RLIMIT_STACK, &stacklim) < 0) - return -1; - - /* Protect against overflow. */ - *softlim = (datalim.rlim_cur / 1024L) + (stacklim.rlim_cur / 1024L); - *hardlim = (datalim.rlim_max / 1024L) + (stacklim.rlim_max / 1024L); - return 0; -#else - errno = EINVAL; - return -1; -#endif /* HAVE_RESOURCE */ -} - -static int -filesize(valuep) - RLIMTYPE *valuep; -{ -#if !defined (HAVE_RESOURCE) - long result; - if ((result = ulimit (1, 0L)) < 0) - return -1; - else - *valuep = (RLIMTYPE) result * 512; - return 0; -#else - errno = EINVAL; - return -1; -#endif -} - -static int -pipesize (valuep) - RLIMTYPE *valuep; -{ -#if defined (PIPE_BUF) - /* This is defined on Posix systems. */ - *valuep = (RLIMTYPE) PIPE_BUF; - return 0; -#else -# if defined (_POSIX_PIPE_BUF) - *valuep = (RLIMTYPE) _POSIX_PIPE_BUF; - return 0; -# else -# if defined (PIPESIZE) - /* This is defined by running a program from the Makefile. */ - *valuep = (RLIMTYPE) PIPESIZE; - return 0; -# else - errno = EINVAL; - return -1; -# endif /* PIPESIZE */ -# endif /* _POSIX_PIPE_BUF */ -#endif /* PIPE_BUF */ -} - -static int -getmaxuprc (valuep) - RLIMTYPE *valuep; -{ - long maxchild; - - maxchild = getmaxchild (); - if (maxchild < 0) - { - errno = EINVAL; - return -1; - } - else - { - *valuep = (RLIMTYPE) maxchild; - return 0; - } -} - -static void -print_all_limits (mode) - int mode; -{ - register int i; - RLIMTYPE softlim, hardlim; - - if (mode == 0) - mode |= LIMIT_SOFT; - - for (i = 0; limits[i].option > 0; i++) - { - if (get_limit (i, &softlim, &hardlim) == 0) - printone (i, (mode & LIMIT_SOFT) ? softlim : hardlim, 1); - else if (errno != EINVAL) - builtin_error ("%s: cannot get limit: %s", limits[i].description, - strerror (errno)); - } -} - -static void -printone (limind, curlim, pdesc) - int limind; - RLIMTYPE curlim; - int pdesc; -{ - char unitstr[64]; - int factor; - - factor = BLOCKSIZE(limits[limind].block_factor); - if (pdesc) - { - if (limits[limind].units) - sprintf (unitstr, "(%s, -%c) ", limits[limind].units, limits[limind].option); - else - sprintf (unitstr, "(-%c) ", limits[limind].option); - - printf ("%-20s %16s", limits[limind].description, unitstr); - } - if (curlim == RLIM_INFINITY) - puts ("unlimited"); - else if (curlim == RLIM_SAVED_MAX) - puts ("hard"); - else if (curlim == RLIM_SAVED_CUR) - puts ("soft"); - else - print_rlimtype ((curlim / factor), 1); -} - -/* Set all limits to NEWLIM. NEWLIM currently must be RLIM_INFINITY, which - causes all limits to be set as high as possible depending on mode (like - csh `unlimit'). Returns -1 if NEWLIM is invalid, 0 if all limits - were set successfully, and 1 if at least one limit could not be set. - - To raise all soft limits to their corresponding hard limits, use - ulimit -S -a unlimited - To attempt to raise all hard limits to infinity (superuser-only), use - ulimit -H -a unlimited - To attempt to raise all soft and hard limits to infinity, use - ulimit -a unlimited -*/ - -static int -set_all_limits (mode, newlim) - int mode; - RLIMTYPE newlim; -{ - register int i; - int retval = 0; - - if (newlim != RLIM_INFINITY) - { - errno = EINVAL; - return -1; - } - - if (mode == 0) - mode = LIMIT_SOFT|LIMIT_HARD; - - for (retval = i = 0; limits[i].option > 0; i++) - if (set_limit (i, newlim, mode) < 0) - { - builtin_error (_("%s: cannot modify limit: %s"), limits[i].description, - strerror (errno)); - retval = 1; - } - return retval; -} - -#endif /* !_MINIX */ diff --git a/builtins/umask.def~ b/builtins/umask.def~ deleted file mode 100644 index c31f76a51..000000000 --- a/builtins/umask.def~ +++ /dev/null @@ -1,314 +0,0 @@ -This file is umask.def, from which is created umask.c. -It implements the builtin "umask" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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] -Display or set file mode mask. - -Sets the user file-creation mask to MODE. If MODE is omitted, prints -the current value of the mask. - -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). - -Options: - -p if MODE is omitted, output in a form that may be reused as input - -S makes the output symbolic; otherwise an octal number is output -$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); - } - - return (sh_chkwrite (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 '=': - if (who == 0) - who = S_IRWXU | S_IRWXG | S_IRWXO; - 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~ b/builtins/wait.def~ deleted file mode 100644 index e5734d20d..000000000 --- a/builtins/wait.def~ +++ /dev/null @@ -1,179 +0,0 @@ -This file is wait.def, from which is created wait.c. -It implements the builtin "wait" in Bash. - -Copyright (C) 1987-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 [id] -Wait for job completion and return exit status. - -Waits for the process identified by ID, which may be a process ID or a -job specification, and reports its termination status. If ID is not -given, waits for all currently active child processes, and the return -status is zero. If ID is a a job specification, waits for all processes -in the job's pipeline. -$END - -$BUILTIN wait -$FUNCTION wait_builtin -$DEPENDS_ON !JOB_CONTROL -$SHORT_DOC wait [pid] -Wait for process completion and return exit status. - -Waits for the specified process and reports its termination status. If -PID is not given, all currently active child processes are waited for, -and the return code is zero. PID must be a process ID. -$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 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 && *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 (INVALID_JOB (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/command.h~ b/command.h~ deleted file mode 100644 index dd52c39c0..000000000 --- a/command.h~ +++ /dev/null @@ -1,376 +0,0 @@ -/* command.h -- The structures used internally to represent commands, and - the extern declarations of the functions used to create them. */ - -/* Copyright (C) 1993-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#if !defined (_COMMAND_H_) -#define _COMMAND_H_ - -#include "stdc.h" - -/* Instructions describing what kind of thing to do for a redirection. */ -enum r_instruction { - r_output_direction, r_input_direction, r_inputa_direction, - r_appending_to, r_reading_until, r_reading_string, - r_duplicating_input, r_duplicating_output, r_deblank_reading_until, - r_close_this, r_err_and_out, r_input_output, r_output_force, - r_duplicating_input_word, r_duplicating_output_word, - r_move_input, r_move_output, r_move_input_word, r_move_output_word, - r_append_err_and_out -}; - -/* Redirection errors. */ -#define AMBIGUOUS_REDIRECT -1 -#define NOCLOBBER_REDIRECT -2 -#define RESTRICTED_REDIRECT -3 /* can only happen in restricted shells. */ -#define HEREDOC_REDIRECT -4 /* here-doc temp file can't be created */ - -#define CLOBBERING_REDIRECT(ri) \ - (ri == r_output_direction || ri == r_err_and_out) - -#define OUTPUT_REDIRECT(ri) \ - (ri == r_output_direction || ri == r_input_output || ri == r_err_and_out || ri == r_append_err_and_out) - -#define INPUT_REDIRECT(ri) \ - (ri == r_input_direction || ri == r_inputa_direction || ri == r_input_output) - -#define WRITE_REDIRECT(ri) \ - (ri == r_output_direction || \ - ri == r_input_output || \ - ri == r_err_and_out || \ - ri == r_appending_to || \ - ri == r_append_err_and_out || \ - ri == r_output_force) - -/* redirection needs translation */ -#define TRANSLATE_REDIRECT(ri) \ - (ri == r_duplicating_input_word || ri == r_duplicating_output_word || \ - ri == r_move_input_word || ri == r_move_output_word) - -/* Command Types: */ -enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select, - cm_connection, cm_function_def, cm_until, cm_group, - cm_arith, cm_cond, cm_arith_for, cm_subshell, cm_coproc }; - -/* Possible values for the `flags' field of a WORD_DESC. */ -#define W_HASDOLLAR 0x000001 /* Dollar sign present. */ -#define W_QUOTED 0x000002 /* Some form of quote character is present. */ -#define W_ASSIGNMENT 0x000004 /* This word is a variable assignment. */ -#define W_GLOBEXP 0x000008 /* This word is the result of a glob expansion. */ -#define W_NOSPLIT 0x000010 /* Do not perform word splitting on this word. */ -#define W_NOGLOB 0x000020 /* Do not perform globbing on this word. */ -#define W_NOSPLIT2 0x000040 /* Don't split word except for $@ expansion. */ -#define W_TILDEEXP 0x000080 /* Tilde expand this assignment word */ -#define W_DOLLARAT 0x000100 /* $@ and its special handling */ -#define W_DOLLARSTAR 0x000200 /* $* and its special handling */ -#define W_NOCOMSUB 0x000400 /* Don't perform command substitution on this word */ -#define W_ASSIGNRHS 0x000800 /* Word is rhs of an assignment statement */ -#define W_NOTILDE 0x001000 /* Don't perform tilde expansion on this word */ -#define W_ITILDE 0x002000 /* Internal flag for word expansion */ -#define W_NOEXPAND 0x004000 /* Don't expand at all -- do quote removal */ -#define W_COMPASSIGN 0x008000 /* Compound assignment */ -#define W_ASSNBLTIN 0x010000 /* word is a builtin command that takes assignments */ -#define W_ASSIGNARG 0x020000 /* word is assignment argument to command */ -#define W_HASQUOTEDNULL 0x040000 /* word contains a quoted null character */ -#define W_DQUOTE 0x080000 /* word should be treated as if double-quoted */ -#define W_NOPROCSUB 0x100000 /* don't perform process substitution */ -#define W_HASCTLESC 0x200000 /* word contains literal CTLESC characters */ -#define W_ASSIGNASSOC 0x400000 /* word looks like associative array assignment */ - -/* Possible values for subshell_environment */ -#define SUBSHELL_ASYNC 0x01 /* subshell caused by `command &' */ -#define SUBSHELL_PAREN 0x02 /* subshell caused by ( ... ) */ -#define SUBSHELL_COMSUB 0x04 /* subshell caused by `command` or $(command) */ -#define SUBSHELL_FORK 0x08 /* subshell caused by executing a disk command */ -#define SUBSHELL_PIPE 0x10 /* subshell from a pipeline element */ -#define SUBSHELL_PROCSUB 0x20 /* subshell caused by <(command) or >(command) */ -#define SUBSHELL_COPROC 0x40 /* subshell from a coproc pipeline */ - -/* A structure which represents a word. */ -typedef struct word_desc { - char *word; /* Zero terminated string. */ - int flags; /* Flags associated with this word. */ -} WORD_DESC; - -/* A linked list of words. */ -typedef struct word_list { - struct word_list *next; - WORD_DESC *word; -} WORD_LIST; - - -/* **************************************************************** */ -/* */ -/* Shell Command Structs */ -/* */ -/* **************************************************************** */ - -/* What a redirection descriptor looks like. If the redirection instruction - is ri_duplicating_input or ri_duplicating_output, use DEST, otherwise - use the file in FILENAME. Out-of-range descriptors are identified by a - negative DEST. */ - -typedef union { - int dest; /* Place to redirect REDIRECTOR to, or ... */ - WORD_DESC *filename; /* filename to redirect to. */ -} REDIRECTEE; - -/* Structure describing a redirection. If REDIRECTOR is negative, the parser - (or translator in redir.c) encountered an out-of-range file descriptor. */ -typedef struct redirect { - struct redirect *next; /* Next element, or NULL. */ - int redirector; /* Descriptor to be redirected. */ - int flags; /* Flag value for `open'. */ - enum r_instruction instruction; /* What to do with the information. */ - REDIRECTEE redirectee; /* File descriptor or filename */ - char *here_doc_eof; /* The word that appeared in <flags. */ -#define CMD_WANT_SUBSHELL 0x01 /* User wants a subshell: ( command ) */ -#define CMD_FORCE_SUBSHELL 0x02 /* Shell needs to force a subshell. */ -#define CMD_INVERT_RETURN 0x04 /* Invert the exit value. */ -#define CMD_IGNORE_RETURN 0x08 /* Ignore the exit value. For set -e. */ -#define CMD_NO_FUNCTIONS 0x10 /* Ignore functions during command lookup. */ -#define CMD_INHIBIT_EXPANSION 0x20 /* Do not expand the command words. */ -#define CMD_NO_FORK 0x40 /* Don't fork; just call execve */ -#define CMD_TIME_PIPELINE 0x80 /* Time a pipeline */ -#define CMD_TIME_POSIX 0x100 /* time -p; use POSIX.2 time output spec. */ -#define CMD_AMPERSAND 0x200 /* command & */ -#define CMD_STDIN_REDIR 0x400 /* async command needs implicit " - -/* Undefine this if you don't want the ksh-compatible behavior of reprinting - the select menu after a valid choice is made only if REPLY is set to NULL - in the body of the select command. The menu is always reprinted if the - reply to the select query is an empty line. */ -#define KSH_COMPATIBLE_SELECT - -/* System-wide .bashrc file for interactive shells. */ -/* #define SYS_BASHRC "/etc/bash.bashrc" */ - -/* System-wide .bash_logout for login shells. */ -/* #define SYS_BASH_LOGOUT "/etc/bash.bash_logout" */ - -/* Define this to make non-interactive shells begun with argv[0][0] == '-' - run the startup files when not in posix mode. */ -/* #define NON_INTERACTIVE_LOGIN_SHELLS */ - -/* Define this if you want bash to try to check whether it's being run by - sshd and source the .bashrc if so (like the rshd behavior). */ -/* #define SSH_SOURCE_BASHRC */ diff --git a/config.h.in~ b/config.h.in~ deleted file mode 100644 index 9ecfab03d..000000000 --- a/config.h.in~ +++ /dev/null @@ -1,1081 +0,0 @@ -/* config.h -- Configuration file for bash. */ - -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#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 COPROCESS_SUPPORT if you want support for ksh-like coprocesses and - the `coproc' reserved word */ -#define COPROCESS_SUPPORT - -/* 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 STRICT_POSIX if you want bash to be strictly posix.2 conformant by - default (except for echo; that is controlled separately). */ -#undef STRICT_POSIX - -/* 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 - -/* Define for case-modifying variable attributes; variables modified on - assignment */ -#undef CASEMOD_ATTRS - -/* Define for case-modifying word expansions */ -#undef CASEMOD_EXPANSIONS - -#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 - -#undef volatile - -/* 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 to `int' if doesn't define. */ -#undef sig_atomic_t - -#undef HAVE_MBSTATE_T - -/* Define if you have quad_t in . */ -#undef HAVE_QUAD_T - -/* Define if you have wchar_t in . */ -#undef HAVE_WCHAR_T - -/* Define if you have wctype_t in . */ -#undef HAVE_WCTYPE_T - -/* Define if you have wint_t in . */ -#undef HAVE_WINT_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 -#undef HAVE_DECL_TZNAME - -/* Characteristics of some of the system structures. */ - -#undef HAVE_STRUCT_DIRENT_D_INO - -#undef HAVE_STRUCT_DIRENT_D_FILENO - -#undef HAVE_STRUCT_DIRENT_D_NAMLEN - -#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 PRI_MACROS_BROKEN - -#undef STRTOLD_BROKEN - -/* Define if WCONTINUED is defined in system headers, but rejected by waitpid */ -#undef WCONTINUED_BROKEN - -/* 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 eaccess function. */ -#undef HAVE_EACCESS - -/* Define if you have the fcntl function. */ -#undef HAVE_FCNTL - -/* Define if you have the fdprintf function. */ -#undef HAVE_FDPRINTF - -/* Define if you have the fpurge/__fpurge function. */ -#undef HAVE_FPURGE -#undef HAVE___FPURGE -#undef HAVE_DECL_FPURGE - -/* 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 getpwent function. */ -#undef HAVE_GETPWENT - -/* Define if you have the getpwnam function. */ -#undef HAVE_GETPWNAM - -/* Define if you have the getpwuid function. */ -#undef HAVE_GETPWUID - -/* 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 isinf function in libc */ -#undef HAVE_ISINF_IN_LIBC - -/* Define if you have the isnan function in libc */ -#undef HAVE_ISNAN_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 iswctype function. */ -#undef HAVE_ISWCTYPE - -/* Define if you have the iswlower function. */ -#undef HAVE_ISWLOWER - -/* Define if you have the iswupper function. */ -#undef HAVE_ISWUPPER - -/* Define if you have the isxdigit function. */ -#undef HAVE_ISXDIGIT - -/* Define if you have the kill function. */ -#undef HAVE_KILL - -/* 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 mbscmp function. */ -#undef HAVE_MBSCMP - -/* 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 raise function. */ -#undef HAVE_RAISE - -/* 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 setitimer function. */ -#undef HAVE_SETITIMER - -/* 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 setregid function. */ -#undef HAVE_SETREGID -#undef HAVE_DECL_SETREGID - -/* 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 strnlen function. */ -#undef HAVE_STRNLEN - -/* 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 towlower function. */ -#undef HAVE_TOWLOWER - -/* Define if you have the towupper function. */ -#undef HAVE_TOWUPPER - -/* 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 wcrtomb function. */ -#undef HAVE_WCRTOMB - -/* Define if you have the wcscoll function. */ -#undef HAVE_WCSCOLL - -/* Define if you have the wcsdup function. */ -#undef HAVE_WCSDUP - -/* Define if you have the wctype function. */ -#undef HAVE_WCTYPE - -/* 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_PWD_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 you have the `localeconv' function. */ -#undef HAVE_LOCALECONV - -/* 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.save1 b/configure.in.save1 deleted file mode 100644 index 9ef2200df..000000000 --- a/configure.in.save1 +++ /dev/null @@ -1,1111 +0,0 @@ -dnl -dnl Configure script for bash-3.2 -dnl -dnl report bugs to chet@po.cwru.edu -dnl -dnl Process this file with autoconf to produce a configure script. - -# Copyright (C) 1987-2006 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.2, version 3.192])dnl - -define(bashvers, 3.2) -define(relstatus, maint) - -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*|maint*) 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, QNX 6.x -*-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}/share/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_strict_posix=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 -opt_single_longdoc_strings=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(single-help-strings, AC_HELP_STRING([--enable-single-help-strings], [store help documentation as a single string to ease translation]), opt_single_longdoc_strings=$enableval) -AC_ARG_ENABLE(strict-posix-default, AC_HELP_STRING([--enable-strict-posix-default], [configure bash to be posix-conformant by default]), opt_strict_posix=$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_strict_posix = yes; then -AC_DEFINE(STRICT_POSIX) -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 -HELPSTRINGS= -if test "$opt_single_longdoc_strings" != "yes"; then - HELPSTRINGS='-S' -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) -AC_SUBST(HELPSTRINGS) - -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 - -AC_SYS_LARGEFILE - -dnl BEGIN changes for cross-building (currently cygwin, minGW, and -dnl (obsolete) BeOS) - -SIGNAMES_O= -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. - -CROSS_COMPILE= -if test "x$cross_compiling" = "xyes"; then - case "${host}" in - *-cygwin*) - cross_cache=${srcdir}/cross-build/cygwin32.cache - ;; - *-mingw*) - cross_cache=${srcdir}/cross-build/cygwin32.cache - ;; - i[[3456]]86-*-beos*) - cross_cache=${srcdir}/cross-build/x86-beos.cache - ;; - *) 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 - SIGNAMES_O='signames.o' - CROSS_COMPILE='-DCROSS_COMPILING' - AC_SUBST(CROSS_COMPILE) -fi -AC_SUBST(SIGNAMES_H) -AC_SUBST(SIGNAMES_O) - -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 - -if test "X$cross_compiling" = "Xno"; then - CPPFLAGS_FOR_BUILD=${CPPFLAGS_FOR_BUILD-"$CPPFLAGS"} - LDFLAGS_FOR_BUILD=${LDFLAGS_FOR_BUILD-'$(LDFLAGS)'} -else - CPPFLAGS_FOR_BUILD=${CPPFLAGS_FOR_BUILD-""} - LDFLAGS_FOR_BUILD=${LDFLAGS_FOR_BUILD-""} -fi - -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 - -TILDE_LIB=-ltilde -if test $opt_readline = yes; then - AC_DEFINE(READLINE) - 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= - READLINE_LIB=-lreadline - # section for OS versions that don't allow unresolved symbols - # to be compiled into dynamic libraries. - case "$host_os" in - cygwin*) TILDE_LIB= ;; - esac - else - RL_LIBDIR='$(dot)/$(LIBSUBDIR)/readline' - READLINE_DEP='$(READLINE_LIBRARY)' - # section for OS versions that ship an older/broken version of - # readline as a standard dynamic library and don't allow a - # static version specified as -llibname to override the - # dynamic version - case "${host_os}" in - darwin8*) READLINE_LIB='${READLINE_LIBRARY}' ;; - *) READLINE_LIB=-lreadline ;; - esac - 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 - if test "$opt_with_installed_readline" != "no"; then - HIST_LIBDIR=$RL_LIBDIR - HISTORY_DEP= - HISTORY_LIB=-lhistory - 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)' - # section for OS versions that ship an older version of - # readline as a standard dynamic library and don't allow a - # static version specified as -llibname to override the - # dynamic version - case "${host_os}" in - darwin8*) HISTORY_LIB='${HISTORY_LIBRARY}' ;; - *) HISTORY_LIB=-lhistory ;; - esac - 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) -AC_SUBST(TILDE_LIB) - -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 this is similar to the expanded AC_PROG_RANLIB -if test x$SIZE = x; then - if test x$ac_tool_prefix = x; then - SIZE=size - else - SIZE=${ac_tool_prefix}size - save_IFS=$IFS ; IFS=: - size_found=0 - for dir in $PATH; do - if test -x $dir/$SIZE ; then - size_found=1 - break - fi - done - if test $size_found -eq 0; then - SIZE=: - fi - IFS=$save_IFS - fi -fi -AC_SUBST(SIZE) - -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 pwd.h grp.h strings.h regex.h) -AC_CHECK_HEADERS(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 sys/ptem.h requires definitions from sys/stream.h on systems where it -dnl exists -AC_CHECK_HEADER(sys/ptem.h, , ,[[ -#if HAVE_SYS_STREAM_H -# include -#endif -]]) - -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)) -AC_CHECK_FUNC(isnan, AC_DEFINE(HAVE_ISNAN_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 eaccess fcntl getdtablesize getgroups gethostname \ - getpagesize getpeername getrlimit getrusage gettimeofday \ - kill killpg lstat readlink sbrk select setdtablesize \ - tcgetpgrp uname ulimit waitpid) -AC_REPLACE_FUNCS(rename) - -dnl checks for c library functions -AC_CHECK_FUNCS(bcopy bzero confstr fnmatch \ - getaddrinfo gethostbyname getservbyname getservent inet_aton \ - memmove pathconf putenv raise regcomp regexec \ - setenv setlinebuf setlocale setvbuf siginterrupt strchr \ - sysconf tcgetattr times ttyname tzset unsetenv) - -AC_CHECK_FUNCS(vsnprintf snprintf vasprintf asprintf) -AC_CHECK_FUNCS(isascii isblank isgraph isprint isspace isxdigit) -AC_CHECK_FUNCS(getpwent getpwnam getpwuid) -AC_REPLACE_FUNCS(getcwd memset strcasecmp strerror strftime strnlen strpbrk 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([setregid]) -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]) - -dnl 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 - -BASH_CHECK_WCONTINUED - -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 - case "`uname -r`" in - 2.[[456789]]*|3*) AC_DEFINE(PGRP_PIPE) ;; - esac ;; -*qnx6*) LOCAL_CFLAGS="-Dqnx -Dqnx6" LOCAL_LIBS="-lncurses" ;; -*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 -D_POSIX_SOURCE" ;; -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 -dragonfly*) 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` -case "$BUILD_DIR" in -*\ *) BUILD_DIR=`echo "$BUILD_DIR" | sed 's: :\\\\ :g'` ;; -*) ;; -esac - -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/configure.in~ b/configure.in~ deleted file mode 100644 index caf5628a8..000000000 --- a/configure.in~ +++ /dev/null @@ -1,1145 +0,0 @@ -dnl -dnl Configure script for bash-4.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-2009 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 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -AC_REVISION([for Bash 4.0, version 4.012])dnl - -define(bashvers, 4.0) -define(relstatus, release) - -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*|maint*) 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, QNX 6.x -*-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='${datadir}/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_strict_posix=no -opt_cond_command=yes -opt_cond_regexp=yes -opt_coproc=yes -opt_arith_for_command=yes -opt_net_redirs=yes -opt_progcomp=yes -opt_separate_help=no -opt_multibyte=yes -opt_debugger=yes -opt_single_longdoc_strings=yes -opt_casemod_attrs=yes -opt_casemod_expansions=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 opt_coproc=no - opt_casemod_attrs=no opt_casemod_expansions=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(casemod-attributes, AC_HELP_STRING([--enable-casemod-attributes], [include case-modifying variable attributes]), opt_casemod_attrs=$enableval) -AC_ARG_ENABLE(casemod-expansions, AC_HELP_STRING([--enable-casemod-expansions], [include case-modifying word expansions]), opt_casemod_expansions=$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 extended regular expression matching in conditional commands]), opt_cond_regexp=$enableval) -AC_ARG_ENABLE(coprocesses, AC_HELP_STRING([--enable-coprocesses], [enable coprocess support and the coproc reserved word]), opt_coproc=$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(single-help-strings, AC_HELP_STRING([--enable-single-help-strings], [store help documentation as a single string to ease translation]), opt_single_longdoc_strings=$enableval) -AC_ARG_ENABLE(strict-posix-default, AC_HELP_STRING([--enable-strict-posix-default], [configure bash to be posix-conformant by default]), opt_strict_posix=$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_strict_posix = yes; then -AC_DEFINE(STRICT_POSIX) -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_coproc = yes; then -AC_DEFINE(COPROCESS_SUPPORT) -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_casemod_attrs = yes; then -AC_DEFINE(CASEMOD_ATTRS) -fi -if test $opt_casemod_expansions = yes; then -AC_DEFINE(CASEMOD_EXPANSIONS) -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 -HELPSTRINGS= -if test "$opt_single_longdoc_strings" != "yes"; then - HELPSTRINGS='-S' -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) -AC_SUBST(HELPSTRINGS) - -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 - -AC_SYS_LARGEFILE - -dnl BEGIN changes for cross-building (currently cygwin, minGW, and -dnl (obsolete) BeOS) - -SIGNAMES_O= -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. - -CROSS_COMPILE= -if test "x$cross_compiling" = "xyes"; then - case "${host}" in - *-cygwin*) - cross_cache=${srcdir}/cross-build/cygwin32.cache - ;; - *-mingw*) - cross_cache=${srcdir}/cross-build/cygwin32.cache - ;; - i[[3456]]86-*-beos*) - cross_cache=${srcdir}/cross-build/x86-beos.cache - ;; - *) 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 - SIGNAMES_O='signames.o' - CROSS_COMPILE='-DCROSS_COMPILING' - AC_SUBST(CROSS_COMPILE) -fi -AC_SUBST(SIGNAMES_H) -AC_SUBST(SIGNAMES_O) - -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 - -if test "X$cross_compiling" = "Xno"; then - CPPFLAGS_FOR_BUILD=${CPPFLAGS_FOR_BUILD-"$CPPFLAGS"} - LDFLAGS_FOR_BUILD=${LDFLAGS_FOR_BUILD-'$(LDFLAGS)'} -else - CPPFLAGS_FOR_BUILD=${CPPFLAGS_FOR_BUILD-""} - LDFLAGS_FOR_BUILD=${LDFLAGS_FOR_BUILD-""} -fi - -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 - -TILDE_LIB=-ltilde -if test $opt_readline = yes; then - AC_DEFINE(READLINE) - 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= - READLINE_LIB=-lreadline - # section for OS versions that don't allow unresolved symbols - # to be compiled into dynamic libraries. - case "$host_os" in - cygwin*) TILDE_LIB= ;; - esac - else - RL_LIBDIR='$(dot)/$(LIBSUBDIR)/readline' - READLINE_DEP='$(READLINE_LIBRARY)' - # section for OS versions that ship an older/broken version of - # readline as a standard dynamic library and don't allow a - # static version specified as -llibname to override the - # dynamic version - case "${host_os}" in - darwin[[89]]*) READLINE_LIB='${READLINE_LIBRARY}' ;; - *) READLINE_LIB=-lreadline ;; - esac - 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 - if test "$opt_with_installed_readline" != "no"; then - HIST_LIBDIR=$RL_LIBDIR - HISTORY_DEP= - HISTORY_LIB=-lhistory - 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)' - # section for OS versions that ship an older version of - # readline as a standard dynamic library and don't allow a - # static version specified as -llibname to override the - # dynamic version - case "${host_os}" in - darwin[[89]]*) HISTORY_LIB='${HISTORY_LIBRARY}' ;; - *) HISTORY_LIB=-lhistory ;; - esac - 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) -AC_SUBST(TILDE_LIB) - -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 this is similar to the expanded AC_PROG_RANLIB -if test x$SIZE = x; then - if test x$ac_tool_prefix = x; then - SIZE=size - else - SIZE=${ac_tool_prefix}size - save_IFS=$IFS ; IFS=: - size_found=0 - for dir in $PATH; do - if test -x $dir/$SIZE ; then - size_found=1 - break - fi - done - if test $size_found -eq 0; then - SIZE=: - fi - IFS=$save_IFS - fi -fi -AC_SUBST(SIZE) - -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 -AC_C_VOLATILE -AC_C_RESTRICT - -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 pwd.h grp.h strings.h regex.h) -AC_CHECK_HEADERS(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 sys/ptem.h requires definitions from sys/stream.h on systems where it -dnl exists -AC_CHECK_HEADER(sys/ptem.h, , ,[[ -#if HAVE_SYS_STREAM_H -# include -#endif -]]) - -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)) -AC_CHECK_FUNC(isnan, AC_DEFINE(HAVE_ISNAN_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 eaccess fcntl getdtablesize getgroups gethostname \ - getpagesize getpeername getrlimit getrusage gettimeofday \ - kill killpg lstat readlink sbrk select setdtablesize \ - setitimer tcgetpgrp uname ulimit waitpid) -AC_REPLACE_FUNCS(rename) - -dnl checks for c library functions -AC_CHECK_FUNCS(bcopy bzero confstr fnmatch \ - getaddrinfo gethostbyname getservbyname getservent inet_aton \ - memmove pathconf putenv raise regcomp regexec \ - setenv setlinebuf setlocale setvbuf siginterrupt strchr \ - sysconf tcgetattr times ttyname tzset unsetenv) - -AC_CHECK_FUNCS(vsnprintf snprintf vasprintf asprintf) -AC_CHECK_FUNCS(isascii isblank isgraph isprint isspace isxdigit) -AC_CHECK_FUNCS(getpwent getpwnam getpwuid) -AC_REPLACE_FUNCS(getcwd memset strcasecmp strerror strftime strnlen strpbrk strstr) -AC_REPLACE_FUNCS(strtod strtol strtoul strtoll strtoull strtoimax strtoumax) -AC_REPLACE_FUNCS(fdprintf) - -AC_CHECK_DECLS([confstr]) -AC_CHECK_DECLS([printf]) -AC_CHECK_DECLS([sbrk]) -AC_CHECK_DECLS([setregid]) -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]) - -dnl 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 HAVE_DECL_SYS_SIGLIST -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 -BASH_TYPE_SIG_ATOMIC_T - -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_FPURGE -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 - -BASH_CHECK_WCONTINUED - -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 or ld 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 -DSOLARIS" ;; -solaris2.8*) LOCAL_CFLAGS=-DSOLARIS LOCAL_LDFLAGS='-z interpose' ;; -solaris2.9*) LOCAL_CFLAGS=-DSOLARIS LOCAL_LDFLAGS='-z interpose' ;; -solaris2.10*) LOCAL_CFLAGS=-DSOLARIS LOCAL_LDFLAGS='-z interpose' ;; -solaris2*) LOCAL_CFLAGS=-DSOLARIS ;; -lynxos*) LOCAL_CFLAGS=-DRECYCLES_PIDS ;; -linux*) LOCAL_LDFLAGS=-rdynamic # allow dynamic loading - case "`uname -r`" in - 2.[[456789]]*|3*) AC_DEFINE(PGRP_PIPE) ;; - esac ;; -*qnx6*) LOCAL_CFLAGS="-Dqnx -Dqnx6" LOCAL_LIBS="-lncurses" ;; -*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 -D_POSIX_SOURCE" ;; -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 -dragonfly*) 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` -case "$BUILD_DIR" in -*\ *) BUILD_DIR=`echo "$BUILD_DIR" | sed 's: :\\\\ :g'` ;; -*) ;; -esac - -if test -z "$localedir"; then - localedir='${datarootdir}/locale' -fi -if test -z "$datarootdir"; then - datarootdir='${prefix}/share' -fi - -AC_SUBST(PROFILE_FLAGS) - -AC_SUBST(incdir) -AC_SUBST(BUILD_DIR) - -# Some versions of autoconf don't substitute these automatically -AC_SUBST(datarootdir) -AC_SUBST(localedir) - -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], -[ -# Makefile uses this timestamp file to record whether config.h is up to date. -echo timestamp > stamp-h -]) diff --git a/copy_cmd.c~ b/copy_cmd.c~ deleted file mode 100644 index 0adf0229e..000000000 --- a/copy_cmd.c~ +++ /dev/null @@ -1,424 +0,0 @@ -/* copy_command.c -- copy a COMMAND structure. This is needed - primarily for making function definitions, but I'm not sure - that anyone else will need it. */ - -/* Copyright (C) 1987,1991 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 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 - -#include "shell.h" - -static PATTERN_LIST *copy_case_clause __P((PATTERN_LIST *)); -static PATTERN_LIST *copy_case_clauses __P((PATTERN_LIST *)); -static FOR_COM *copy_for_command __P((FOR_COM *)); -#if defined (ARITH_FOR_COMMAND) -static ARITH_FOR_COM *copy_arith_for_command __P((ARITH_FOR_COM *)); -#endif -static GROUP_COM *copy_group_command __P((GROUP_COM *)); -static SUBSHELL_COM *copy_subshell_command __P((SUBSHELL_COM *)); -static CASE_COM *copy_case_command __P((CASE_COM *)); -static WHILE_COM *copy_while_command __P((WHILE_COM *)); -static IF_COM *copy_if_command __P((IF_COM *)); -#if defined (DPAREN_ARITHMETIC) -static ARITH_COM *copy_arith_command __P((ARITH_COM *)); -#endif -#if defined (COND_COMMAND) -static COND_COM *copy_cond_command __P((COND_COM *)); -#endif -static SIMPLE_COM *copy_simple_command __P((SIMPLE_COM *)); - -WORD_DESC * -copy_word (w) - WORD_DESC *w; -{ - WORD_DESC *new_word; - - new_word = make_bare_word (w->word); - new_word->flags = w->flags; - return (new_word); -} - -/* Copy the chain of words in LIST. Return a pointer to - the new chain. */ -WORD_LIST * -copy_word_list (list) - WORD_LIST *list; -{ - WORD_LIST *new_list; - - for (new_list = (WORD_LIST *)NULL; list; list = list->next) - new_list = make_word_list (copy_word (list->word), new_list); - - return (REVERSE_LIST (new_list, WORD_LIST *)); -} - -static PATTERN_LIST * -copy_case_clause (clause) - PATTERN_LIST *clause; -{ - PATTERN_LIST *new_clause; - - new_clause = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST)); - new_clause->patterns = copy_word_list (clause->patterns); - new_clause->action = copy_command (clause->action); - new_clause->flags = clause->flags; - return (new_clause); -} - -static PATTERN_LIST * -copy_case_clauses (clauses) - PATTERN_LIST *clauses; -{ - PATTERN_LIST *new_list, *new_clause; - - for (new_list = (PATTERN_LIST *)NULL; clauses; clauses = clauses->next) - { - new_clause = copy_case_clause (clauses); - new_clause->next = new_list; - new_list = new_clause; - } - return (REVERSE_LIST (new_list, PATTERN_LIST *)); -} - -/* Copy a single redirect. */ -REDIRECT * -copy_redirect (redirect) - REDIRECT *redirect; -{ - REDIRECT *new_redirect; - - new_redirect = (REDIRECT *)xmalloc (sizeof (REDIRECT)); - FASTCOPY ((char *)redirect, (char *)new_redirect, (sizeof (REDIRECT))); - switch (redirect->instruction) - { - case r_reading_until: - case r_deblank_reading_until: - new_redirect->here_doc_eof = savestring (redirect->here_doc_eof); - /*FALLTHROUGH*/ - case r_reading_string: - case r_appending_to: - case r_output_direction: - case r_input_direction: - case r_inputa_direction: - case r_err_and_out: - case r_append_err_and_out: - case r_input_output: - case r_output_force: - case r_duplicating_input_word: - case r_duplicating_output_word: - case r_move_input_word: - case r_move_output_word: - new_redirect->redirectee.filename = copy_word (redirect->redirectee.filename); - break; - case r_duplicating_input: - case r_duplicating_output: - case r_move_input: - case r_move_output: - case r_close_this: - break; - } - return (new_redirect); -} - -REDIRECT * -copy_redirects (list) - REDIRECT *list; -{ - REDIRECT *new_list, *temp; - - for (new_list = (REDIRECT *)NULL; list; list = list->next) - { - temp = copy_redirect (list); - temp->next = new_list; - new_list = temp; - } - return (REVERSE_LIST (new_list, REDIRECT *)); -} - -static FOR_COM * -copy_for_command (com) - FOR_COM *com; -{ - FOR_COM *new_for; - - new_for = (FOR_COM *)xmalloc (sizeof (FOR_COM)); - new_for->flags = com->flags; - new_for->line = com->line; - new_for->name = copy_word (com->name); - new_for->map_list = copy_word_list (com->map_list); - new_for->action = copy_command (com->action); - return (new_for); -} - -#if defined (ARITH_FOR_COMMAND) -static ARITH_FOR_COM * -copy_arith_for_command (com) - ARITH_FOR_COM *com; -{ - ARITH_FOR_COM *new_arith_for; - - new_arith_for = (ARITH_FOR_COM *)xmalloc (sizeof (ARITH_FOR_COM)); - new_arith_for->flags = com->flags; - new_arith_for->line = com->line; - new_arith_for->init = copy_word_list (com->init); - new_arith_for->test = copy_word_list (com->test); - new_arith_for->step = copy_word_list (com->step); - new_arith_for->action = copy_command (com->action); - return (new_arith_for); -} -#endif /* ARITH_FOR_COMMAND */ - -static GROUP_COM * -copy_group_command (com) - GROUP_COM *com; -{ - GROUP_COM *new_group; - - new_group = (GROUP_COM *)xmalloc (sizeof (GROUP_COM)); - new_group->command = copy_command (com->command); - return (new_group); -} - -static SUBSHELL_COM * -copy_subshell_command (com) - SUBSHELL_COM *com; -{ - SUBSHELL_COM *new_subshell; - - new_subshell = (SUBSHELL_COM *)xmalloc (sizeof (SUBSHELL_COM)); - new_subshell->command = copy_command (com->command); - new_subshell->flags = com->flags; - return (new_subshell); -} - -static CASE_COM * -copy_case_command (com) - CASE_COM *com; -{ - CASE_COM *new_case; - - new_case = (CASE_COM *)xmalloc (sizeof (CASE_COM)); - new_case->flags = com->flags; - new_case->line = com->line; - new_case->word = copy_word (com->word); - new_case->clauses = copy_case_clauses (com->clauses); - return (new_case); -} - -static WHILE_COM * -copy_while_command (com) - WHILE_COM *com; -{ - WHILE_COM *new_while; - - new_while = (WHILE_COM *)xmalloc (sizeof (WHILE_COM)); - new_while->flags = com->flags; - new_while->test = copy_command (com->test); - new_while->action = copy_command (com->action); - return (new_while); -} - -static IF_COM * -copy_if_command (com) - IF_COM *com; -{ - IF_COM *new_if; - - new_if = (IF_COM *)xmalloc (sizeof (IF_COM)); - new_if->flags = com->flags; - new_if->test = copy_command (com->test); - new_if->true_case = copy_command (com->true_case); - new_if->false_case = com->false_case ? copy_command (com->false_case) : com->false_case; - return (new_if); -} - -#if defined (DPAREN_ARITHMETIC) -static ARITH_COM * -copy_arith_command (com) - ARITH_COM *com; -{ - ARITH_COM *new_arith; - - new_arith = (ARITH_COM *)xmalloc (sizeof (ARITH_COM)); - new_arith->flags = com->flags; - new_arith->exp = copy_word_list (com->exp); - new_arith->line = com->line; - - return (new_arith); -} -#endif - -#if defined (COND_COMMAND) -static COND_COM * -copy_cond_command (com) - COND_COM *com; -{ - COND_COM *new_cond; - - new_cond = (COND_COM *)xmalloc (sizeof (COND_COM)); - new_cond->flags = com->flags; - new_cond->line = com->line; - new_cond->type = com->type; - new_cond->op = com->op ? copy_word (com->op) : com->op; - new_cond->left = com->left ? copy_cond_command (com->left) : (COND_COM *)NULL; - new_cond->right = com->right ? copy_cond_command (com->right) : (COND_COM *)NULL; - - return (new_cond); -} -#endif - -static SIMPLE_COM * -copy_simple_command (com) - SIMPLE_COM *com; -{ - SIMPLE_COM *new_simple; - - new_simple = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM)); - new_simple->flags = com->flags; - new_simple->words = copy_word_list (com->words); - new_simple->redirects = com->redirects ? copy_redirects (com->redirects) : (REDIRECT *)NULL; - new_simple->line = com->line; - return (new_simple); -} - -FUNCTION_DEF * -copy_function_def_contents (old, new_def) - FUNCTION_DEF *old, *new_def; -{ - new_def->name = copy_word (old->name); - new_def->command = old->command ? copy_command (old->command) : old->command; - new_def->flags = old->flags; - new_def->line = old->line; - new_def->source_file = old->source_file ? savestring (old->source_file) : old->source_file; - return (new_def); -} - -FUNCTION_DEF * -copy_function_def (com) - FUNCTION_DEF *com; -{ - FUNCTION_DEF *new_def; - - new_def = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF)); - new_def = copy_function_def_contents (com, new_def); - return (new_def); -} - -/* Copy the command structure in COMMAND. Return a pointer to the - copy. Don't you forget to dispose_command () on this pointer - later! */ -COMMAND * -copy_command (command) - COMMAND *command; -{ - COMMAND *new_command; - - if (command == NULL) - return (command); - - new_command = (COMMAND *)xmalloc (sizeof (COMMAND)); - FASTCOPY ((char *)command, (char *)new_command, sizeof (COMMAND)); - new_command->flags = command->flags; - new_command->line = command->line; - - if (command->redirects) - new_command->redirects = copy_redirects (command->redirects); - - switch (command->type) - { - case cm_for: - new_command->value.For = copy_for_command (command->value.For); - break; - -#if defined (ARITH_FOR_COMMAND) - case cm_arith_for: - new_command->value.ArithFor = copy_arith_for_command (command->value.ArithFor); - break; -#endif - -#if defined (SELECT_COMMAND) - case cm_select: - new_command->value.Select = - (SELECT_COM *)copy_for_command ((FOR_COM *)command->value.Select); - break; -#endif - - case cm_group: - new_command->value.Group = copy_group_command (command->value.Group); - break; - - case cm_subshell: - new_command->value.Subshell = copy_subshell_command (command->value.Subshell); - break; - - case cm_case: - new_command->value.Case = copy_case_command (command->value.Case); - break; - - case cm_until: - case cm_while: - new_command->value.While = copy_while_command (command->value.While); - break; - - case cm_if: - new_command->value.If = copy_if_command (command->value.If); - break; - -#if defined (DPAREN_ARITHMETIC) - case cm_arith: - new_command->value.Arith = copy_arith_command (command->value.Arith); - break; -#endif - -#if defined (COND_COMMAND) - case cm_cond: - new_command->value.Cond = copy_cond_command (command->value.Cond); - break; -#endif - - case cm_simple: - new_command->value.Simple = copy_simple_command (command->value.Simple); - break; - - case cm_connection: - { - CONNECTION *new_connection; - - new_connection = (CONNECTION *)xmalloc (sizeof (CONNECTION)); - new_connection->connector = command->value.Connection->connector; - new_connection->first = copy_command (command->value.Connection->first); - new_connection->second = copy_command (command->value.Connection->second); - new_command->value.Connection = new_connection; - break; - } - - case cm_function_def: - new_command->value.Function_def = copy_function_def (command->value.Function_def); - break; - } - return (new_command); -} diff --git a/cross-build/cygwin32.cache.old b/cross-build/cygwin32.cache.old deleted file mode 100644 index 640390fbf..000000000 --- a/cross-build/cygwin32.cache.old +++ /dev/null @@ -1,42 +0,0 @@ -# This file is a shell script that caches the results of configure -# tests for CYGWIN32 so they don't need to be done when cross-compiling. - -# AC_FUNC_GETPGRP should also define GETPGRP_VOID -ac_cv_func_getpgrp_void=${ac_cv_func_getpgrp_void='yes'} -# AC_FUNC_SETVBUF_REVERSED should not define anything else -ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed='no'} -# on CYGWIN32, system calls do not restart -ac_cv_sys_restartable_syscalls=${ac_cv_sys_restartable_syscalls='no'} -bash_cv_sys_restartable_syscalls=${bash_cv_sys_restartable_syscalls='no'} - -# these may be necessary, but they are currently commented out -#ac_cv_c_bigendian=${ac_cv_c_bigendian='no'} -ac_cv_sizeof_char_p=${ac_cv_sizeof_char_p='4'} -ac_cv_sizeof_int=${ac_cv_sizeof_int='4'} -ac_cv_sizeof_long=${ac_cv_sizeof_long='4'} -ac_cv_sizeof_double=${ac_cv_sizeof_double='8'} - -bash_cv_dup2_broken=${bash_cv_dup2_broken='no'} -bash_cv_pgrp_pipe=${bash_cv_pgrp_pipe='no'} -bash_cv_type_rlimit=${bash_cv_type_rlimit='long'} -bash_cv_decl_under_sys_siglist=${bash_cv_decl_under_sys_siglist='no'} -bash_cv_under_sys_siglist=${bash_cv_under_sys_siglist='no'} -bash_cv_sys_siglist=${bash_cv_sys_siglist='no'} -bash_cv_opendir_not_robust=${bash_cv_opendir_not_robust='no'} -bash_cv_getenv_redef=${bash_cv_getenv_redef='yes'} -bash_cv_printf_declared=${bash_cv_printf_declared='yes'} -bash_cv_ulimit_maxfds=${bash_cv_ulimit_maxfds='no'} -bash_cv_getcwd_calls_popen=${bash_cv_getcwd_calls_popen='no'} -bash_cv_must_reinstall_sighandlers=${bash_cv_must_reinstall_sighandlers='no'} -bash_cv_job_control_missing=${bash_cv_job_control_missing='present'} -bash_cv_sys_named_pipes=${bash_cv_sys_named_pipes='missing'} -bash_cv_func_sigsetjmp=${bash_cv_func_sigsetjmp='missing'} -bash_cv_mail_dir=${bash_cv_mail_dir='unknown'} -bash_cv_func_strcoll_broken=${bash_cv_func_strcoll_broken='no'} - -bash_cv_type_int32_t=${bash_cv_type_int32_t='int'} -bash_cv_type_u_int32_t=${bash_cv_type_u_int32_t='int'} - -ac_cv_type_bits64_t=${ac_cv_type_bits64_t='no'} - -# end of cross-build/cygwin32.cache diff --git a/ddd1~ b/ddd1~ deleted file mode 100644 index 708a2f547..000000000 --- a/ddd1~ +++ /dev/null @@ -1,1197 +0,0 @@ -*** ../bash-3.2-patched/doc/bash.1 2006-09-28 10:26:05.000000000 -0400 ---- doc/bash.1 2008-04-25 12:32:49.000000000 -0400 -*************** -*** 1,16 **** -! \" - .\" MAN PAGE COMMENTS to - .\" - .\" Chet Ramey -- .\" Information Network Services - .\" Case Western Reserve University - .\" chet@po.cwru.edu - .\" -! .\" Last Change: Thu Sep 28 10:25:59 EDT 2006 - .\" - .\" bash_builtins, strip all but Built-Ins section - .if \n(zZ=1 .ig zZ - .if \n(zY=1 .ig zY -! .TH BASH 1 "2006 September 28" "GNU Bash-3.2" - .\" - .\" There's some problem with having a `@' ---- 1,15 ---- -! .\" - .\" MAN PAGE COMMENTS to - .\" - .\" Chet Ramey - .\" Case Western Reserve University - .\" chet@po.cwru.edu - .\" -! .\" Last Change: Fri Apr 25 12:26:57 EDT 2008 - .\" - .\" bash_builtins, strip all but Built-Ins section - .if \n(zZ=1 .ig zZ - .if \n(zY=1 .ig zY -! .TH BASH 1 "2008 April 25" "GNU Bash-4.0" - .\" - .\" There's some problem with having a `@' -*************** -*** 52,57 **** - [file] - .SH COPYRIGHT -! .if n Bash is Copyright (C) 1989-2005 by the Free Software Foundation, Inc. -! .if t Bash is Copyright \(co 1989-2005 by the Free Software Foundation, Inc. - .SH DESCRIPTION - .B Bash ---- 51,56 ---- - [file] - .SH COPYRIGHT -! .if n Bash is Copyright (C) 1989-2008 by the Free Software Foundation, Inc. -! .if t Bash is Copyright \(co 1989-2008 by the Free Software Foundation, Inc. - .SH DESCRIPTION - .B Bash -*************** -*** 411,419 **** - .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. ---- 410,419 ---- - .PP - .B Bash -! attempts to determine when it is being run with its standard input -! connected to a a network connection, as if by the remote shell -! daemon, usually \fIrshd\fP, or the secure shell daemon \fIsshd\fP. - If - .B bash -! determines it is being run in this fashion, 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. -*************** -*** 579,583 **** - .B ; - and -! .BR &, - which have equal precedence. - .PP ---- 579,583 ---- - .B ; - and -! .BR & , - which have equal precedence. - .PP -*************** -*** 595,603 **** - 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 ---- 595,601 ---- - exit status of the last command executed. - .PP -! AND and OR lists are sequences of one of more pipelines separated by the -! \fB&&\fP and \fB\(bv\(bv\fP control operators, respectively. -! AND and OR lists are executed with left associativity. - An AND list has the form - .RS -*************** -*** 621,625 **** - 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. ---- 619,624 ---- - 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. -*************** -*** 647,651 **** - \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)) ---- 646,651 ---- - \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 or another -! shell metacharacter. - .TP - ((\fIexpression\fP)) -*************** -*** 697,700 **** ---- 697,702 ---- - is enabled, the match is performed without regard to the case - of alphabetic characters. -+ Any part of the pattern may be quoted to force it to be matched as a -+ string. - Substrings matched by parenthesized subexpressions within the regular - expression are saved in the array variable \fBBASH_REMATCH\fP. -*************** -*** 943,947 **** - of all characters within the quotes, with the exception of - .BR $ , -! .BR ` , - .BR \e , - and, when history expansion is enabled, ---- 945,949 ---- - of all characters within the quotes, with the exception of - .BR $ , -! .BR \` , - .BR \e , - and, when history expansion is enabled, -*************** -*** 950,959 **** - .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 , ---- 952,961 ---- - .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 , -*************** -*** 1186,1190 **** - .TP - .B ? -! Expands to the status of the most recently executed foreground - pipeline. - .TP ---- 1188,1192 ---- - .TP - .B ? -! Expands to the exit status of the most recently executed foreground - pipeline. - .TP -*************** -*** 1246,1252 **** - .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 ---- 1248,1259 ---- - .BR bash . - .TP -+ .B BASHPID -+ Expands to the process id of the current \fBbash\fP process. -+ This differs from \fB$$\fP under certain circumstances, such as subshells -+ that do not require \fBbash\fP to be re-initialized. -+ .TP - .B BASH_ARGC - An array variable whose values are the number of parameters in each -! frame of the current \fBbash\fP execution call stack. - The number of - parameters to the current subroutine (shell function or script executed -*************** -*** 1262,1266 **** - .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 ---- 1269,1273 ---- - .TP - .B BASH_ARGV -! An array variable containing all of the parameters in the current \fBbash\fP - 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 -*************** -*** 1286,1290 **** - corresponding to each member of \fBFUNCNAME\fP. - \fB${BASH_LINENO[\fP\fI$i\fP\fB]}\fP is the line number in the source -! file where \fB${FUNCNAME[\fP\fI$ifP\fB]}\fP was called. - The corresponding source file name is \fB${BASH_SOURCE[\fP\fI$i\fP\fB]}\fB. - Use \fBLINENO\fP to obtain the current line number. ---- 1293,1299 ---- - corresponding to each member of \fBFUNCNAME\fP. - \fB${BASH_LINENO[\fP\fI$i\fP\fB]}\fP is the line number in the source -! file where \fB${FUNCNAME[\fP\fI$i\fP\fB]}\fP was called -! (or \fB${BASH_LINENO[\fP\fI$i-1\fP\fB]}\fP if referenced within another -! shell function). - The corresponding source file name is \fB${BASH_SOURCE[\fP\fI$i\fP\fB]}\fB. - Use \fBLINENO\fP to obtain the current line number. -*************** -*** 1347,1350 **** ---- 1356,1363 ---- - below). - .TP -+ .B COMP_KEY -+ The key (or final key of a key sequence) used to invoke the current -+ completion function. -+ .TP - .B COMP_LINE - The current command line. -*************** -*** 1364,1367 **** ---- 1377,1394 ---- - below). - .TP -+ .B COMP_TYPE -+ Set to an integer value corresponding to the type of completion attempted -+ that caused a completion function to be called: -+ \fITAB\fP, for normal completion, -+ \fI?\fP, for listing completions after successive tabs, -+ \fI!\fP, for listing alternatives on partial word completion, -+ \fI@\fP, to list completions if the word is not unmodified, -+ or -+ \fI%\fP, for menu completion. -+ 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 -*************** -*** 1411,1415 **** - 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 ---- 1438,1444 ---- - The element with index 0 is the name of any currently-executing - shell function. -! The bottom-most element is -! .if t \f(CW"main"\fP. -! .if n "main". - This variable exists only when a shell function is executing. - Assignments to -*************** -*** 1728,1731 **** ---- 1757,1762 ---- - If this variable is set, time stamps are written to the history file so - they may be preserved across shell sessions. -+ This uses the history comment character to distinguish timestamps from -+ other history lines. - .TP - .B HOME -*************** -*** 2431,2435 **** - one space to avoid being confused with the :- expansion. - Substring indexing is zero-based unless the positional parameters -! are used, in which case the indexing starts at 1. - .TP - ${\fB!\fP\fIprefix\fP\fB*\fP} ---- 2462,2468 ---- - one space to avoid being confused with the :- expansion. - Substring indexing is zero-based unless the positional parameters -! are used, in which case the indexing starts at 1 by default. -! If \fIoffset\fP is 0, and the positional parameters are used, \fB$0\fP is -! prefixed to the list. - .TP - ${\fB!\fP\fIprefix\fP\fB*\fP} -*************** -*** 2443,2446 **** ---- 2476,2481 ---- - .B IFS - special variable. -+ When \fI@\fP is used and the expansion appears within double quotes, each -+ variable name expands to a separate word. - .TP - ${\fB!\fP\fIname\fP[\fI@\fP]} -*************** -*** 2540,2544 **** - \fIParameter\fP is expanded and the longest match of \fIpattern\fP - against its value is replaced with \fIstring\fP. -! If \Ipattern\fP begins with \fB/\fP, all matches of \fIpattern\fP are - replaced with \fIstring\fP. Normally only the first match is replaced. - If \fIpattern\fP begins with \fB#\fP, it must match at the beginning ---- 2575,2579 ---- - \fIParameter\fP is expanded and the longest match of \fIpattern\fP - against its value is replaced with \fIstring\fP. -! If \fIpattern\fP begins with \fB/\fP, all matches of \fIpattern\fP are - replaced with \fIstring\fP. Normally only the first match is replaced. - If \fIpattern\fP begins with \fB#\fP, it must match at the beginning -*************** -*** 2575,2579 **** - or - .RS -! \fB`\fP\fIcommand\fP\fB`\fP - .RE - .PP ---- 2610,2614 ---- - or - .RS -! \fB\`\fP\fIcommand\fP\fB\`\fP - .RE - .PP -*************** -*** 2590,2594 **** - backslash retains its literal meaning except when followed by - .BR $ , -! .BR ` , - or - .BR \e . ---- 2625,2629 ---- - backslash retains its literal meaning except when followed by - .BR $ , -! .BR \` , - or - .BR \e . -*************** -*** 2669,2676 **** - .BR , - the default, then - any sequence of - .SM - .B IFS -! characters serves to delimit words. If - .SM - .B IFS ---- 2704,2719 ---- - .BR , - the default, then -+ sequences of -+ .BR , -+ .BR , -+ and -+ .B -+ at the beginning and end of the results of the previous -+ expansions are ignored, and - any sequence of - .SM - .B IFS -! characters not at the beginning or end serves to delimit words. -! If - .SM - .B IFS -*************** -*** 3160,3164 **** - .BR $ , - and -! .BR ` . - .PP - If the redirection operator is ---- 3203,3207 ---- - .BR $ , - and -! .BR \` . - .PP - If the redirection operator is -*************** -*** 3274,3278 **** - 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. ---- 3317,3321 ---- - 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. -*************** -*** 3749,3753 **** - .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 ---- 3792,3801 ---- - .B PATH - is performed only if the command is not found in the hash table. -! If the search is unsuccessful, the shell searches for a defined shell -! function named \fBcommand_not_found_handle\fP. -! If that function exists, it is invoked with the original command and -! the original command's arguments as its arguments, and the function's -! exit status becomes the exit status of the shell. -! If that function is not defined, the shell prints an error - message and returns an exit status of 127. - .PP -*************** -*** 3907,3910 **** ---- 3955,3967 ---- - command in its environment. - .SH "EXIT STATUS" -+ .PP -+ The exit status of an executed command is the value returned by the -+ \fIwaitpid\fP system call or equivalent function. Exit statuses -+ fall between 0 and 255, though, as explained below, the shell may -+ use values above 125 specially. Exit statuses from shell builtins and -+ compound commands are also limited to this range. Under certain -+ circumstances, the shell will use special values to indicate specific -+ failure modes. -+ .PP - For the shell's purposes, a command which exits with a - zero exit status has succeeded. An exit status of zero -*************** -*** 4173,4181 **** - 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 ---- 4230,4242 ---- - If an attempt to exit - .B bash -! is made while jobs are stopped (or, if the \fBcheckjobs\fP shell option has -! been enabled using the \fBshopt\fP builtin, running), the shell prints a -! warning message, and, if the \fBcheckjobs\fP option is enabled, lists the -! jobs and their statuses. -! 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 any stopped - jobs are terminated. - .SH PROMPTING -*************** -*** 4656,4659 **** ---- 4717,4724 ---- - or \fBnext-history\fP. - .TP -+ .B history\-size (0) -+ Set the maximum number of history entries saved in the history list. If -+ set to zero, the number of entries in the history list is not limited. -+ .TP - .B horizontal\-scroll\-mode (Off) - When set to \fBOn\fP, makes readline use a single line for display, -*************** -*** 5454,5461 **** - 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. ---- 5519,5530 ---- - When the command or function is invoked, the - .SM -! .BR COMP_LINE , -! .SM -! .BR COMP_POINT , -! .SM -! .BR COMP_KEY , - and - .SM -! .B COMP_TYPE - variables are assigned values as described above under - \fBShell Variables\fP. -*************** -*** 5567,5570 **** ---- 5636,5646 ---- - .SM - .BR HISTFILESIZE . -+ When the history file is read, -+ lines beginning with the history comment character followed immediately -+ by a digit are interpreted as timestamps for the preceding history line. -+ These timestamps are optionally displayed depending on the value of the -+ .SM -+ .B HISTTIMEFORMAT -+ variable. - When an interactive shell exits, the last - .SM -*************** -*** 5587,5591 **** - .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 ---- 5663,5676 ---- - .B HISTFILE - is unset, or if the history file is unwritable, the history is -! not saved. -! If the -! .SM -! .HISTTIMEFORMAT -! variable is set, time stamps are written to the history file, marked -! with the history comment character, so -! they may be preserved across shell sessions. -! This uses the history comment character to distinguish timestamps from -! other history lines. -! After saving the history, the history file is truncated - to contain no more than - .SM -*************** -*** 5721,5724 **** ---- 5806,5812 ---- - above under - .BR "Shell Variables" ). -+ The shell uses -+ the history comment character to mark history timestamps when -+ writing the history file. - .SS Event Designators - .PP -*************** -*** 5980,5985 **** - 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 ---- 6068,6074 ---- - had been started with - .BR & . -! If -! .I jobspec -! is not present, the shell's notion of the \fIcurrent job\fP is used. - .B bg - .I jobspec -*************** -*** 6039,6049 **** - 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 ---- 6128,6131 ---- -*************** -*** 6054,6057 **** ---- 6136,6146 ---- - they output. - .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 \-f \fIfilename\fP - Read key bindings from \fIfilename\fP. -*************** -*** 6104,6107 **** ---- 6193,6210 ---- - is not a shell builtin command. - .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 - \fBcd\fP [\fB\-L|-P\fP] [\fIdir\fP] - Change the current directory to \fIdir\fP. The variable -*************** -*** 6149,6166 **** - 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 ---- 6252,6255 ---- -*************** -*** 6226,6235 **** - 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. ---- 6315,6324 ---- - matches were generated. - .TP -! \fBcomplete\fP [\fB\-abcdefgjksuv\fP] [\fB\-o\fP \fIcomp-option\fP] [\fB\-E\fP] [\fB\-A\fP \fIaction\fP] [\fB\-G\fP \fIglobpat\fP] [\fB\-W\fP \fIwordlist\fP] [\fB\-F\fP \fIfunction\fP] [\fB\-C\fP \fIcommand\fP] - .br -! [\fB\-X\fP \fIfilterpat\fP] [\fB\-P\fP \fIprefix\fP] [\fB\-S\fP \fIsuffix\fP] \fIname\fP [\fIname ...\fP] - .PD 0 - .TP -! \fBcomplete\fP \fB\-pr\fP [\fB\-E\fP] [\fIname\fP ...] - .PD - Specify how arguments to each \fIname\fP should be completed. -*************** -*** 6240,6243 **** ---- 6329,6335 ---- - each \fIname\fP, or, if no \fIname\fPs are supplied, all - completion specifications. -+ The \fB\-E\fP option indicates that the remaining options and actions should -+ apply to ``empty'' command completion; that is, completion attempted on a -+ blank line. - .sp 1 - The process of applying these completion specifications when word completion -*************** -*** 6415,6418 **** ---- 6507,6523 ---- - .RE - .TP -+ \fBcompopt\fP [\fB\-o\fP \fIoption\fP] [\fB+o\fP \fIoption\fP] [\fIname\fP] -+ Modify completion options for each \fIname\fP according to the -+ \fIoption\fPs, or for the -+ currently-execution completion if no \fIname\fPs are supplied. -+ If no \fIoption\fPs are given, display the completion options for each -+ \fIname\fP or the current completion. -+ The possible values of \fIoption\fP are those valid for the \fBcomplete\fP -+ builtin described above. -+ .PP -+ The return value is true unless an invalid option is supplied, an attempt -+ is made to modify the options for a \fIname\fP for which no completion -+ specification exists, or an output error occurs. -+ .TP - \fBcontinue\fP [\fIn\fP] - Resume the next iteration of the enclosing -*************** -*** 6448,6452 **** - When - .B \-p -! is used, additional options are ignored. - The - .B \-F ---- 6553,6565 ---- - When - .B \-p -! is used with \fIname\fP arguments, additional options are ignored. -! When -! .B \-p -! is supplied without \fIname\fP arguments, it will display the attributes -! and values of all variables having the attributes specified by the -! additional options. -! If no other options are supplied with \fB\-p\fP, \fBdeclare\fP will display -! the attributes and values of all shell variables. The \fB\-f\fP option -! will restrict the display to shell functions. - The - .B \-F -*************** -*** 6494,6499 **** - .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 ---- 6607,6615 ---- - .PP - Using `+' instead of `\-' -! turns off the attribute instead, -! with the exceptions that \fB+a\fP -! may not be used to destroy an array variable and \fB+r\fB will not -! remove the readonly attribute. -! When used in a function, - makes each - \fIname\fP local, as with the -*************** -*** 6516,6520 **** - .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 ---- 6632,6636 ---- - .RE - .TP -! .B dirs [+\fIn\fP] [\-\fIn\fP] [\fB\-cplv\fP] - Without options, displays the list of currently remembered directories. - The default display is on a single line with directory names separated -*************** -*** 6564,6567 **** ---- 6680,6687 ---- - .I jobspec - is removed from the table of active jobs. -+ If -+ .I jobspec -+ is not present, and neither \fB\-a\fB nor \fB\-r\fP is supplied, -+ the shell's notion of the \fIcurrent job\fP is used. - If the \fB\-h\fP option is given, each - .I jobspec -*************** -*** 6651,6655 **** - .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 ---- 6771,6775 ---- - .RE - .TP -! \fBenable\fP [\fB\-a\fP] [\fB\-dnps\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 -*************** -*** 6712,6716 **** - .B \-l - option is supplied, -! the shell places a dash at the beginning of the zeroth arg passed to - .IR command . - This is what ---- 6832,6836 ---- - .B \-l - option is supplied, -! the shell places a dash at the beginning of the zeroth argument passed to - .IR command . - This is what -*************** -*** 6783,6787 **** - that is not a function. - .TP -! \fBfc\fP [\fB\-e\fP \fIename\fP] [\fB\-nlr\fP] [\fIfirst\fP] [\fIlast\fP] - .PD 0 - .TP ---- 6903,6907 ---- - that is not a function. - .TP -! \fBfc\fP [\fB\-e\fP \fIename\fP] [\fB\-lnr\fP] [\fIfirst\fP] [\fIlast\fP] - .PD 0 - .TP -*************** -*** 7028,7032 **** - 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 ---- 7148,7152 ---- - is not found or an invalid option is supplied. - .TP -! \fBhelp\fP [\fB\-dms\fP] [\fIpattern\fP] - Display helpful information about builtin commands. If - .I pattern -*************** -*** 7037,7042 **** - 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 . ---- 7157,7173 ---- - otherwise help for all the builtins and shell control structures - is printed. -! .RS -! .PD 0 -! .TP -! .B \-d -! Display a short description of each \fIpattern\fP -! .TP -! .B \ -m -! Display the description of each \fIpattern\fP in a manpage-like format -! .TP -! .B \-s -! Display only a short usage synopsis for each \fIpattern\fP -! .PD -! .RE - The return status is 0 unless no command matches - .IR pattern . -*************** -*** 7117,7121 **** - .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 ---- 7248,7256 ---- - .PP - If the \fBHISTTIMEFORMAT\fP is set, the time stamp information -! associated with each history entry is written to the history file, -! marked with the history comment character. -! When the history file is read, lines beginning with the history -! comment character followed immediately by a digit are interpreted -! as timestamps for the previous history line. - The return value is 0 unless an invalid option is encountered, an - error occurs while reading or writing the history file, an invalid -*************** -*** 7260,7263 **** ---- 7395,7458 ---- - Exit a login shell. - .TP -+ \fBmapfile\fP [\fB\-n\fP \fIcount\fP] [\fB\-O\fP \fIorigin\fP] [\fB\-s\fP \fIcou -+ nt\fP] [\fB\-t\fP] [\fB\-u\fP \fIfd\fP] [\fB\-C\fP \fIcallback\fP] [\fB\-c\fP \f -+ Iquantum\fP] [\fIarray\fP] -+ Read lines from the standard input into array variable -+ .IR array , -+ or from file descriptor -+ .IR fd -+ if the -+ .B \-u -+ option is supplied. -+ The variable \fBMAPFILE\fP is the default \fIarray\fP. -+ Options, if supplied, have the following meanings: -+ .RS -+ .PD 0 -+ .TP -+ .B \-n -+ Copy at most -+ .I count -+ lines. If \fIcount\fP is 0, all lines are copied. -+ .TP -+ .B \-O -+ Begin assigning to -+ .I array -+ at index -+ .IR origin . -+ The default index is 0. -+ .TP -+ .B \-s -+ Discard the first \fIcount\fP lines read. -+ .TP -+ .B \-t -+ Remove a trailing line from each line read. -+ .TP -+ .B \-u -+ Read lines from file descriptor \fIfd\fP instead of the standard input. -+ .TP -+ .B \-C -+ Evaluate -+ .I callback -+ each time \fIquantum\fP lines are read. The \fB\-c\fP option specifies -+ .IR quantum . -+ .TP -+ .B \-c -+ Specify the number of lines read between each call to -+ .IR callback . -+ .PD -+ .PP -+ If -+ .B \-C -+ is specified without -+ .BR \-c , -+ the default quantum is 5000. -+ .PP -+ If not supplied with an explicit origin, \fBmapfile\fP will clear \fIarray\fP -+ before assigning to it. -+ .PP -+ \fBmapfile\fP returns successfully unless an invalid option or option -+ argument is supplied, or \fIarray\fP is invalid or unassignable. -+ .RE -+ .TP - \fBpopd\fP [\-\fBn\fP] [+\fIn\fP] [\-\fIn\fP] - Removes entries from the directory stack. With no arguments, -*************** -*** 7269,7272 **** ---- 7464,7471 ---- - .PD 0 - .TP -+ .B \-n -+ Suppresses the normal change of directory when removing directories -+ from the stack, so that only the stack is manipulated. -+ .TP - \fB+\fP\fIn\fP - Removes the \fIn\fPth entry counting from the left of the list -*************** -*** 7292,7299 **** - .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 ---- 7491,7494 ---- -*************** -*** 7334,7341 **** - 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 ---- 7529,7536 ---- - non-zero on failure. - .TP -! \fBpushd\fP [\fB\-n\fP] [+\fIn\fP] [\-\fIn\fP] - .PD 0 - .TP -! \fBpushd\fP [\fB\-n\fP] [\fIdir\fP] - .PD - Adds a directory to the top of the directory stack, or rotates -*************** -*** 7347,7350 **** ---- 7542,7549 ---- - .PD 0 - .TP -+ .B \-n -+ Suppresses the normal change of directory when adding directories -+ to the stack, so that only the stack is manipulated. -+ .TP - \fB+\fP\fIn\fP - Rotates the stack so that the \fIn\fPth directory -*************** -*** 7360,7367 **** - 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 ---- 7559,7562 ---- -*************** -*** 7404,7408 **** - 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 ---- 7599,7603 ---- - invalid option is supplied. - .TP -! \fBread\fP [\fB\-ers\fP] [\fB\-a\fP \fIaname\fP] [\fB\-d\fP \fIdelim\fP] [\fb\-\fP \fItext\fP] [\fB\-n\fP \fInchars\fP] [\fB\-p\fP \fIprompt\fP] [\fB\-t\fP \fItimeout\fP] [\fB\-u\fP \fIfd\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 -*************** -*** 7448,7451 **** ---- 7643,7652 ---- - above) is used to obtain the line. - .TP -+ .B \-i \fItext\fP -+ If -+ .B readline -+ is being used to read the line, \fItext\fP is placed into the editing -+ buffer before editing begins. -+ .TP - .B \-n \fInchars\fP - \fBread\fP returns after reading \fInchars\fP characters rather than -*************** -*** 7540,7544 **** - 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 ---- 7741,7749 ---- - before execution resumes after the function or script. - .TP -! \fBset\fP [\fB\-\-abefhkmnptuvxBCEHPT\fP] [\fB\-o\fP \fIoption\fP] [\fIarg\fP ...] -! .PD 0 -! .TP -! \fBset\fP [\fB+abefhkmnptuvxBCEHPT\fP] [\fB+o\fP \fIoption\fP] [\fIarg\fP ...] -! .PD - Without options, the name and value of each shell variable are displayed - in a format that can be reused as input -*************** -*** 7579,7590 **** - 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 ---- 7784,7800 ---- - keyword, - part of the test in an -! .B if -! statement, part of a command executed in a - .B && - or - .B \(bv\(bv -! list, -! any command in a pipeline but the last, -! or if the command's return value is - being inverted via - .BR ! . -+ Failing simple commands that are part of shell functions or command lists -+ enclosed in braces or parentheses satisfying the above conditions do not -+ cause the shell to exit. - A trap on \fBERR\fP, if set, is executed before the shell exits. - .TP 8 -*************** -*** 7940,7943 **** ---- 8150,8158 ---- - .PD 0 - .TP 8 -+ .B autocd -+ If set, a command name that is the name of a directory is executed as if -+ it were the argument to the \fBcd\fP command. -+ This option is only used by interactive shells. -+ .TP 8 - .B cdable_vars - If set, an argument to the -*************** -*** 7962,7965 **** ---- 8177,8187 ---- - longer exists, a normal path search is performed. - .TP 8 -+ .B checkjobs -+ If set, \fBbash\fP lists the status of any stopped and running jobs before -+ exiting an interactive shell. If any jobs are running, this causes -+ the exit to be deferred until a second exit is attempted without an -+ intervening command (see \fBJOB CONTROL\fP above). The shell always -+ postpones exiting if any jobs are stopped. -+ .TP 8 - .B checkwinsize - If set, \fBbash\fP checks the window size after each command -*************** -*** 7978,7981 **** ---- 8200,8209 ---- - easy re-editing of multi-line commands. - .TP 8 -+ .B compat31 -+ If set, -+ .B bash -+ changes its behavior to that of version 3.1 with respect to quoted -+ arguments to the conditional command's =~ operator. -+ .TP 8 - .B dotglob - If set, -*************** -*** 8224,8227 **** ---- 8452,8456 ---- - Expressions may be combined using the following operators, listed - in decreasing order of precedence. -+ The evaluation depends on the number of arguments; see below. - .RS - .PD 0 -*************** -*** 8281,8284 **** ---- 8510,8515 ---- - the result of the expression is the result of the binary test using - the first and third arguments as operands. -+ The \fB\-a\fP and \fB\-o\fP operators are considered binary operators -+ when there are three arguments. - If the first argument is \fB!\fP, the value is the negation of - the two-argument test using the second and third arguments. -*************** -*** 8287,8292 **** - 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 ---- 8518,8521 ---- -*************** -*** 8388,8392 **** - part of the test in an - .I if -! statement, part of a - .B && - or ---- 8617,8621 ---- - part of the test in an - .I if -! statement, part of a command executed in a - .B && - or -*************** -*** 8487,8499 **** - 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\-SHacdefilmnpqrstuvx\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. ---- 8716,8729 ---- - option suppresses shell function lookup, as with the \fBcommand\fP builtin. - .B type -! returns true if all of the arguments are found, false if -! any are not found. - .TP -! \fBulimit\fP [\fB\-HSTabcdefilmnpqrstuvx\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 by a non-root user 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. -*************** -*** 8520,8523 **** ---- 8750,8756 ---- - All current limits are reported - .TP -+ .B \-b -+ The maximum socket buffer size -+ .TP - .B \-c - The maximum size of core files created -*************** -*** 8568,8571 **** ---- 8801,8807 ---- - .B \-x - The maximum number of file locks -+ .TP -+ .B \-T -+ The maximum number of threads - .PD - .PP -*************** -*** 8583,8587 **** - which is in units of 512-byte blocks, - and -! .B \-n - and - .BR \-u , ---- 8819,8825 ---- - which is in units of 512-byte blocks, - and -! .BR \-T , -! .BR \-b , -! .BR \-n , - and - .BR \-u , diff --git a/dispose_cmd.c~ b/dispose_cmd.c~ deleted file mode 100644 index 36c195f9f..000000000 --- a/dispose_cmd.c~ +++ /dev/null @@ -1,330 +0,0 @@ -/* dispose_command.c -- dispose of a COMMAND structure. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 "shell.h" - -extern sh_obj_cache_t wdcache, wlcache; - -/* Dispose of the command structure passed. */ -void -dispose_command (command) - COMMAND *command; -{ - if (command == 0) - return; - - if (command->redirects) - dispose_redirects (command->redirects); - - switch (command->type) - { - case cm_for: -#if defined (SELECT_COMMAND) - case cm_select: -#endif - { - register FOR_COM *c; -#if defined (SELECT_COMMAND) - if (command->type == cm_select) - c = (FOR_COM *)command->value.Select; - else -#endif - c = command->value.For; - dispose_word (c->name); - dispose_words (c->map_list); - dispose_command (c->action); - free (c); - break; - } - -#if defined (ARITH_FOR_COMMAND) - case cm_arith_for: - { - register ARITH_FOR_COM *c; - - c = command->value.ArithFor; - dispose_words (c->init); - dispose_words (c->test); - dispose_words (c->step); - dispose_command (c->action); - free (c); - break; - } -#endif /* ARITH_FOR_COMMAND */ - - case cm_group: - { - dispose_command (command->value.Group->command); - free (command->value.Group); - break; - } - - case cm_subshell: - { - dispose_command (command->value.Subshell->command); - free (command->value.Subshell); - break; - } - - case cm_case: - { - register CASE_COM *c; - PATTERN_LIST *t, *p; - - c = command->value.Case; - dispose_word (c->word); - - for (p = c->clauses; p; ) - { - dispose_words (p->patterns); - dispose_command (p->action); - t = p; - p = p->next; - free (t); - } - free (c); - break; - } - - case cm_until: - case cm_while: - { - register WHILE_COM *c; - - c = command->value.While; - dispose_command (c->test); - dispose_command (c->action); - free (c); - break; - } - - case cm_if: - { - register IF_COM *c; - - c = command->value.If; - dispose_command (c->test); - dispose_command (c->true_case); - dispose_command (c->false_case); - free (c); - break; - } - - case cm_simple: - { - register SIMPLE_COM *c; - - c = command->value.Simple; - dispose_words (c->words); - dispose_redirects (c->redirects); - free (c); - break; - } - - case cm_connection: - { - register CONNECTION *c; - - c = command->value.Connection; - dispose_command (c->first); - dispose_command (c->second); - free (c); - break; - } - -#if defined (DPAREN_ARITHMETIC) - case cm_arith: - { - register ARITH_COM *c; - - c = command->value.Arith; - dispose_words (c->exp); - free (c); - break; - } -#endif /* DPAREN_ARITHMETIC */ - -#if defined (COND_COMMAND) - case cm_cond: - { - register COND_COM *c; - - c = command->value.Cond; - dispose_cond_node (c); - break; - } -#endif /* COND_COMMAND */ - - case cm_function_def: - { - register FUNCTION_DEF *c; - - c = command->value.Function_def; - dispose_function_def (c); - break; - } - - default: - command_error ("dispose_command", CMDERR_BADTYPE, command->type, 0); - break; - } - free (command); -} - -#if defined (COND_COMMAND) -/* How to free a node in a conditional command. */ -void -dispose_cond_node (cond) - COND_COM *cond; -{ - if (cond) - { - if (cond->left) - dispose_cond_node (cond->left); - if (cond->right) - dispose_cond_node (cond->right); - if (cond->op) - dispose_word (cond->op); - free (cond); - } -} -#endif /* COND_COMMAND */ - -void -dispose_function_def_contents (c) - FUNCTION_DEF *c; -{ - dispose_word (c->name); - dispose_command (c->command); - FREE (c->source_file); -} - -void -dispose_function_def (c) - FUNCTION_DEF *c; -{ - dispose_function_def_contents (c); - free (c); -} - -/* How to free a WORD_DESC. */ -void -dispose_word (w) - WORD_DESC *w; -{ - FREE (w->word); - ocache_free (wdcache, WORD_DESC, w); -} - -/* Free a WORD_DESC, but not the word contained within. */ -void -dispose_word_desc (w) - WORD_DESC *w; -{ - w->word = 0; - ocache_free (wdcache, WORD_DESC, w); -} - -/* How to get rid of a linked list of words. A WORD_LIST. */ -void -dispose_words (list) - WORD_LIST *list; -{ - WORD_LIST *t; - - while (list) - { - t = list; - list = list->next; - dispose_word (t->word); -#if 0 - free (t); -#else - ocache_free (wlcache, WORD_LIST, t); -#endif - } -} - -#ifdef INCLUDE_UNUSED -/* How to dispose of an array of pointers to char. This is identical to - free_array in stringlib.c. */ -void -dispose_word_array (array) - char **array; -{ - register int count; - - if (array == 0) - return; - - for (count = 0; array[count]; count++) - free (array[count]); - - free (array); -} -#endif - -/* How to dispose of an list of redirections. A REDIRECT. */ -void -dispose_redirects (list) - REDIRECT *list; -{ - register REDIRECT *t; - - while (list) - { - t = list; - list = list->next; - switch (t->instruction) - { - case r_reading_until: - case r_deblank_reading_until: - free (t->here_doc_eof); - /*FALLTHROUGH*/ - case r_reading_string: - case r_output_direction: - case r_input_direction: - case r_inputa_direction: - case r_appending_to: - case r_err_and_out: - case r_append_err_and_out: - case r_input_output: - case r_output_force: - case r_duplicating_input_word: - case r_duplicating_output_word: - case r_move_input_word: - case r_move_output_word: - dispose_word (t->redirectee.filename); - /* FALLTHROUGH */ - default: - break; - } - free (t); - } -} diff --git a/doc/FAQ-4.0~ b/doc/FAQ-4.0~ deleted file mode 100644 index 856804f05..000000000 --- a/doc/FAQ-4.0~ +++ /dev/null @@ -1,2062 +0,0 @@ -This is the Bash FAQ, version 4.01, for Bash version 4.0. - -This document contains a set of frequently-asked questions concerning -Bash, the GNU Bourne-Again Shell. Bash is a freely-available command -interpreter with advanced features for both interactive use and shell -programming. - -Another good source of basic information about shells is the collection -of FAQ articles periodically posted to comp.unix.shell. - -Questions and comments concerning this document should be sent to -chet.ramey@case.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 4.0? -B2) Are there any user-visible incompatibilities between bash-4.0, - bash-3.2, and bash-2.05b? - -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? -E13) Why does filename completion misbehave if a colon appears in the filename? -E14) Why does quoting the pattern argument to the regular expression matching - conditional operator (=~) cause matching to stop working? - -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 4.0, first made available on XXX YYYYY, 2008. - -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 4.0: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-4.0.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-4.0.tar.gz - -Formatted versions of the documentation are available with the URLs: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-doc-4.0.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-doc-4.0.tar.gz - -Any patches for the current version are available with the URL: - -ftp://ftp.cwru.edu/pub/bash/bash-4.0-patches/ - -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 (now part of Red Hat) as part -of their CYGWIN project. For more information about the project, see -http://www.cygwin.com/. - -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 -ports of bash-2.05b and bash-3.2 to the CYGWIN environment, and both -are available as part of their current release. - -Bash-2.05b and later versions should require no local Cygnus changes to -build and run under CYGWIN. - -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 began to work with bash-2.05, but I don't know the current status. - -Bash-3.0 compiles and runs with no modifications under Microsoft's Services -for Unix (SFU), once known as Interix. I do not anticipate any problems -with building bash-4.0, but will gladly accept any patches that are needed. - -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 2004 Edition) 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 4.0? - -Bash-4.0 is the fourth major release of bash. There are numerous new features, -some experimental. Depending on community reception, the experimental -features will evolve. - -Bash-4.0 contains the following new features (see the manual page for -complete descriptions and the CHANGES and NEWS files in the bash-4.0 -distribution): - -o When using substring expansion on the positional parameters, a starting - index of 0 now causes $0 to be prefixed to the list. - -o There is a new variable, $BASHPID, which always returns the process id of - the current shell. - -o There is a new `autocd' option that, when enabled, causes bash to attempt - to `cd' to a directory name that is supplied as the first word of a - simple command. - -o There is a new `checkjobs' option that causes the shell to check for and - report any running or stopped jobs at exit. - -o The programmable completion code exports a new COMP_TYPE variable, set to - a character describing the type of completion being attempted. - -o The programmable completion code exports a new COMP_KEY variable, set to - the character that caused the completion to be invoked (e.g., TAB). - -o The programmable completion code now uses the same set of characters as - readline when breaking the command line into a list of words. - -o The block multiplier for the ulimit -c and -f options is now 512 when in - Posix mode, as Posix specifies. - -o Changed the behavior of the read builtin to save any partial input received - in the specified variable when the read builtin times out. This also - results in variables specified as arguments to read to be set to the empty - string when there is no input available. When the read builtin times out, - it returns an exit status greater than 128. - -o The shell now has the notion of a `compatibility level', controlled by - new variables settable by `shopt'. Setting this variable currently - restores the bash-3.1 behavior when processing quoted strings on the rhs - of the `=~' operator to the `[[' command. - -o The `ulimit' builtin now has new -b (socket buffer size) and -T (number - of threads) options. - -o There is a new `compopt' builtin that allows completion functions to modify - completion options for existing completions or the completion currently - being executed. - -o The `read' builtin has a new -i option which inserts text into the reply - buffer when using readline. - -o A new `-E' option to the complete builtin allows control of the default - behavior for completion on an empty line. - -o There is now limited support for completing command name words containing - globbing characters. - -o The `help' builtin now has a new -d option, to display a short description, - and a -m option, to print help information in a man page-like format. - -o There is a new `mapfile' builtin to populate an array with lines from a - given file. - -o If a command is not found, the shell attempts to execute a shell function - named `command_not_found_handle', supplying the command words as the - function arguments. - -o There is a new shell option: `globstar'. When enabled, the globbing code - treats `**' specially -- it matches all directories (and files within - them, when appropriate) recursively. - -o There is a new shell option: `dirspell'. When enabled, the filename - completion code performs spelling correction on directory names during - completion. - -o The `-t' option to the `read' builtin now supports fractional timeout - values. - -o Brace expansion now allows zero-padding of expanded numeric values and - will add the proper number of zeroes to make sure all values contain the - same number of digits. - -o There is a new bash-specific bindable readline function: `dabbrev-expand'. - It uses menu completion on a set of words taken from the history list. - -o The command assigned to a key sequence with `bind -x' now sets two new - variables in the environment of the executed command: READLINE_LINE_BUFFER - and READLINE_POINT. The command can change the current readline line - and cursor position by modifying READLINE_LINE_BUFFER and READLINE_POINT, - respectively. - -o There is a new >>& redirection operator, which appends the standard output - and standard error to the named file. - -o The parser now understands `|&' as a synonym for `2>&1 |', which redirects - the standard error for a command through a pipe. - -o The new `;&' case statement action list terminator causes execution to - continue with the action associated with the next pattern in the - statement rather than terminating the command. - -o The new `;;&' case statement action list terminator causes the shell to - test the next set of patterns after completing execution of the current - action, rather than terminating the command. - -o The shell understands a new variable: PROMPT_DIRTRIM. When set to an - integer value greater than zero, prompt expansion of \w and \W will - retain only that number of trailing pathname components and replace - the intervening characters with `...'. - -o There are new case-modifying word expansions: uppercase (^[^]) and - lowercase (,[,]). They can work on either the first character or - array element, or globally. They accept an optional shell pattern - that determines which characters to modify. There is an optionally- - configured feature to include capitalization operators. - -o The shell provides associative array variables, with the appropriate - support to create, delete, assign values to, and expand them. - -o The `declare' builtin now has new -l (convert value to lowercase upon - assignment) and -u (convert value to uppercase upon assignment) options. - There is an optionally-configurable -c option to capitalize a value at - assignment. - -o There is a new `coproc' reserved word that specifies a coprocess: an - asynchronous command run with two pipes connected to the creating shell. - Coprocs can be named. The input and output file descriptors and the - PID of the coprocess are available to the calling shell in variables - with coproc-specific names. - -o A value of 0 for the -t option to `read' now returns success if there is - input available to be read from the specified file descriptor. - -o CDPATH and GLOBIGNORE are ignored when the shell is running in privileged - mode. - -o New bindable readline functions shell-forward-word and shell-backward-word, - which move forward and backward words delimited by shell metacharacters - and honor shell quoting. - -o New bindable readline functions shell-backward-kill-word and shell-kill-word - which kill words backward and forward, but use the same word boundaries - as shell-forward-word and shell-backward-word. - -A short feature history dating from Bash-2.0: - -Bash-3.2 contained the following new features: - -o Bash-3.2 now checks shell scripts for NUL characters rather than non-printing - characters when deciding whether or not a script is a binary file. - -o Quoting the string argument to the [[ command's =~ (regexp) operator now - forces string matching, as with the other pattern-matching operators. - -Bash-3.1 contained the following new features: - -o Bash-3.1 may now be configured and built in a mode that enforces strict - POSIX compliance. - -o The `+=' assignment operator, which appends to the value of a string or - array variable, has been implemented. - -o It is now possible to ignore case when matching in contexts other than - filename generation using the new `nocasematch' shell option. - -Bash-3.0 contained the following new features: - -o Features to support the bash debugger have been implemented, and there - is a new `extdebug' option to turn the non-default options on - -o HISTCONTROL is now a colon-separated list of options and has been - extended with a new `erasedups' option that will result in only one - copy of a command being kept in the history list - -o Brace expansion has been extended with a new {x..y} form, producing - sequences of digits or characters - -o Timestamps are now kept with history entries, with an option to save - and restore them from the history file; there is a new HISTTIMEFORMAT - variable describing how to display the timestamps when listing history - entries - -o The `[[' command can now perform extended regular expression (egrep-like) - matching, with matched subexpressions placed in the BASH_REMATCH array - variable - -o A new `pipefail' option causes a pipeline to return a failure status if - any command in it fails - -o The `jobs', `kill', and `wait' builtins now accept job control notation - in their arguments even if job control is not enabled - -o The `gettext' package and libintl have been integrated, and the shell - messages may be translated into other languages - -Bash-2.05b introduced the following new features: - -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 - -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/-i, - readonly -a/-f/name=value, trap -l, set +o, - set -b/-m/-o option/-h/-p/-B/-C/-H/-P, - unset -f/-v, ulimit -i/-m/-p/-q/-u/-x, - 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, compopt, mapfile - 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 and strict posix conformance - redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr, - /dev/tcp/host/port, /dev/udp/host/port - debugger support, including `caller' builtin and new variables - RETURN trap - the `+=' assignment operator - autocd shell option and behavior - command-not-found hook with command_not_found_handle shell function - globstar shell option and `**' globbing behavior - |& synonym for `2>&1 |' - ;& and ;;& case action list terminators - case-modifying word expansions and variable attributes - associative arrays - coprocesses using the `coproc' reserved word and variables - -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, BASHPID, 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_DIRTRIM - 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 -i/-q/-u/-x, umask -S, alias -p, - shopt, disown, printf, complete, compgen, compopt, mapfile - `!' 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' - debugger support, including the `caller' builtin - RETURN trap - Timestamps in history entries - {x..y} brace expansion - The `+=' assignment operator - autocd shell option and behavior - command-not-found hook with command_not_found_handle shell function - globstar shell option and `**' globbing behavior - |& synonym for `2>&1 |' - ;& and ;;& case action list terminators - case-modifying word expansions and variable attributes - associative arrays - coprocesses using the `coproc' reserved word and variables - -Things ksh88 has or uses that bash does not: - tracked aliases (alias -t) - variables: ERRNO, FPATH, EDITOR, VISUAL - co-processes (bash uses different syntax) - 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, newgrp, print, - read -p/-s/var?prompt, set -A/-o gmacs/ - -o bgnice/-o markdirs/-o trackall/-o viraw/-s, - typeset -H/-L/-R/-Z/-A/-ft/-fu/-fx/-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? - -This list is current through ksh93t (11/04/2008) - -New things in ksh-93 not in bash-4.0: - 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 - 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 (match all instead of any) - exit statuses between 0 and 255 - FPATH and PATH mixing - lexical scoping for local variables in `ksh' functions - no scoping for local variables in `POSIX' functions - $'' \C[.collating-element.] escape sequence - -C/-I invocation options - print -f (bash uses printf) - `fc' has been renamed to `hist' - `.' can execute shell functions - getopts -a - printf %B, %H, %P, %R, %T, %Z modifiers, output base for %d, `=' flag - read -N (read -n differs, too)/-v - set -o showme/-o multiline (bash default) - `sleep' and `getconf' builtins (bash has loadable versions) - typeset -n and `nameref' variables - typeset -C/-S/-T/-X/-h/-s - experimental `type' definitions (a la typedef) using typeset - negative subscripts for indexed array variables - array expansions ${array[sub1..sub2]} and ${!array[sub1..sub2]} - associative array assignments using `;' as element separator - negative offsets in ${param:offset:length} - command substitution $(n<#) expands to current byte offset for fd N - new '${ ' form of command substitution, executed in current shell - new >;/<#pat/<##pat/<#/># redirections - redirection operators preceded with {varname} to store fd number in varname - brace expansion printf-like formats - -New things in ksh-93 present in bash-4.0: - associative arrays - [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 - changes to kill builtin - echo -e - exec -c/-a - read -A (bash uses read -a) - read -t/-d - trap -p - brace expansion and set -B - `.' restores the positional parameters when it completes - set -o notify/-C - set -o pipefail - set -G (-o globstar) and ** - POSIX.2 `test' - umask -S - unalias -a - command and arithmetic substitution performed on PS1, PS4, and ENV - command name completion, TAB displaying possible completions - ENV processed only for interactive shells - The `+=' assignment operator - the `;&' case statement "fallthrough" pattern list terminator - csh-style history expansion and set -H - -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. Many Linux distributions -use GNU `which', which is a C program that can understand shell -aliases. - -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. - -As of bash-3.1, bash does not report SIGPIPE errors by default. You -can build a version of bash that will report such errors. - -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, even a builtin or shell function, -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 updated POSIX standard has 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. - -E13) Why does filename completion misbehave if a colon appears in the filename? - -Filename completion (and word completion in general) may appear to behave -improperly if there is a colon in the word to be completed. - -The colon is special to readline's word completion code: it is one of the -characters that breaks words for the completer. Readline uses these characters -in sort of the same way that bash uses $IFS: they break or separate the words -the completion code hands to the application-specific or default word -completion functions. The original intent was to make it easy to edit -colon-separated lists (such as $PATH in bash) in various applications using -readline for input. - -This is complicated by the fact that some versions of the popular -`bash-completion' programmable completion package have problems with the -default completion behavior in the presence of colons. - -The current set of completion word break characters is available in bash as -the value of the COMP_WORDBREAKS variable. Removing `:' from that value is -enough to make the colon not special to completion: - -COMP_WORDBREAKS=${COMP_WORDBREAKS//:} - -You can also quote the colon with a backslash to achieve the same result -temporarily. - -E14) Why does quoting the pattern argument to the regular expression matching - conditional operator (=~) cause regexp matching to stop working? - -In versions of bash prior to bash-3.2, the effect of quoting the regular -expression argument to the [[ command's =~ operator was not specified. -The practical effect was that double-quoting the pattern argument required -backslashes to quote special pattern characters, which interfered with the -backslash processing performed by double-quoted word expansion and was -inconsistent with how the == shell pattern matching operator treated -quoted characters. - -In bash-3.2, the shell was changed to internally quote characters in single- -and double-quoted string arguments to the =~ operator, which suppresses the -special meaning of the characters special to regular expression processing -(`.', `[', `\', `(', `), `*', `+', `?', `{', `|', `^', and `$') and forces -them to be matched literally. This is consistent with how the `==' pattern -matching operator treats quoted portions of its pattern argument. - -Since the treatment of quoted string arguments was changed, several issues -have arisen, chief among them the problem of white space in pattern arguments -and the differing treatment of quoted strings between bash-3.1 and bash-3.2. -Both problems may be solved by using a shell variable to hold the pattern. -Since word splitting is not performed when expanding shell variables in all -operands of the [[ command, this allows users to quote patterns as they wish -when assigning the variable, then expand the values to a single string that -may contain whitespace. The first problem may be solved by using backslashes -or any other quoting mechanism to escape the white space in the patterns. - -Bash-4.0 introduces the concept of a `compatibility level', controlled by -several options to the `shopt' builtin. If the `compat31' option is enabled, -bash reverts to the bash-3.1 behavior with respect to quoting the rhs of -the =~ operator. - -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 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. - -The script examples/scripts.noah/meta.bash encapsulates the bind -commands in a shell function. - -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. It's a variant of - - echo .[!.]* ..?* * - -(The ..?* catches files with names of three or more characters beginning -with `..') - -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 -of the third edition, published in March, 2005, is 0-596-00965-8. Look for -it in fine bookstores near you. This edition of the book has been updated -to cover bash-3.0. - -The GNU Bash Reference Manual has been published as a printed book by -Network Theory Ltd (Paperback, ISBN: 0-9541617-7-7, Nov. 2006). It covers -bash-3.2 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. - -Arnold Robbins and Nelson Beebe have written ``Classic Shell Scripting'', -published by O'Reilly. The first edition, with ISBN number 0-596-00595-4, -was published in May, 2005. - -Chris F. A. Johnson, a frequent contributor to comp.unix.shell and -gnu.bash.bug, has written ``Shell Scripting Recipes: A Problem-Solution -Approach,'' a new book on shell scripting, concentrating on features of -the POSIX standard helpful to shell script writers. The first edition from -Apress, with ISBN number 1-59059-471-1, was published in May, 2005. - -H3) What's coming in future versions? - -These are features I hope to include in a future version of bash. - -Rocky Bernstein's bash debugger (support is included with bash-3.0) -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 -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 `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 2009. Never make predictions. - -This document is Copyright 1995-2009 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.new b/doc/FAQ.new deleted file mode 100644 index d130b2320..000000000 --- a/doc/FAQ.new +++ /dev/null @@ -1,1841 +0,0 @@ -This is the Bash FAQ, version 3.34, for Bash version 3.2. - -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 3.2? -B2) Are there any user-visible incompatibilities between bash-3.2 and - bash-2.05b? - -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? -E13) Why does filename completion misbehave if a colon appears in the filename? - -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 3.2, first made available on XX October, 2006. - -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 3.1: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-3.2.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-3.2.tar.gz - -Formatted versions of the documentation are available with the URLs: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-doc-3.2.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-doc-3.2.tar.gz - -Any patches for the current version are available with the URL: - -ftp://ftp.cwru.edu/pub/bash/bash-3.2-patches/ - -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 (now part of Red Hat) as part -of their CYGWIN project. For more information about the project, see -http://www.cygwin.com/. - -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 -ports of bash-2.05b and bash-3.0 to the CYGWIN environment, and both -are available as part of their current release. Bash-3.1 is currently -being tested and should be available soon. - -Bash-2.05b and later versions should require no local Cygnus changes to -build and run under CYGWIN. - -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 began to work with bash-2.05, but I don't know the current status. - -Bash-3.0 compiles and runs with no modifications under Microsoft's Services -for Unix (SFU), once known as Interix. I do not anticipate any problems -with building bash-3.1 or bash-3.2. - -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 2004 Edition) 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 3.1? - -Bash-3.2 is the second maintenance release of the third major release of -bash. It contains the following significant new features (see the manual -page for complete descriptions and the CHANGES and NEWS files in the -bash-3.2 distribution). - -o Bash-3.2 now checks shell scripts for NUL characters rather than non-printing - characters when deciding whether or not a script is a binary file. - -o Quoting the string argument to the [[ command's =~ (regexp) operator now - forces string matching, as with the other pattern-matching operators. - -A short feature history dating from Bash-2.0: - -Bash-3.1 contained the following new features: - -o Bash-3.1 may now be configured and built in a mode that enforces strict - POSIX compliance. - -o The `+=' assignment operator, which appends to the value of a string or - array variable, has been implemented. - -o It is now possible to ignore case when matching in contexts other than - filename generation using the new `nocasematch' shell option. - -Bash-3.0 contained the following new features: - -o Features to support the bash debugger have been implemented, and there - is a new `extdebug' option to turn the non-default options on - -o HISTCONTROL is now a colon-separated list of options and has been - extended with a new `erasedups' option that will result in only one - copy of a command being kept in the history list - -o Brace expansion has been extended with a new {x..y} form, producing - sequences of digits or characters - -o Timestamps are now kept with history entries, with an option to save - and restore them from the history file; there is a new HISTTIMEFORMAT - variable describing how to display the timestamps when listing history - entries - -o The `[[' command can now perform extended regular expression (egrep-like) - matching, with matched subexpressions placed in the BASH_REMATCH array - variable - -o A new `pipefail' option causes a pipeline to return a failure status if - any command in it fails - -o The `jobs', `kill', and `wait' builtins now accept job control notation - in their arguments even if job control is not enabled - -o The `gettext' package and libintl have been integrated, and the shell - messages may be translated into other languages - -Bash-2.05b introduced the following new features: - -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 - -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 -i/-m/-p/-q/-u/-x, - 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 and strict posix conformance - redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr, - /dev/tcp/host/port, /dev/udp/host/port - debugger support, including `caller' builtin and new variables - RETURN trap - the `+=' assignment operator - - -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 -i/-q/-u/-x, 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' - debugger support, including the `caller' builtin - RETURN trap - Timestamps in history entries - {x..y} brace expansion - The `+=' assignment operator - -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, newgrp, print, - read -p/-s/var?prompt, set -A/-o gmacs/ - -o bgnice/-o markdirs/-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-3.0: - 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 - FPATH and PATH mixing - getopts -a - -I invocation option - 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-3.0: - [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 - set -o pipefail - The `+=' assignment operator - -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. - -As of bash-3.1, bash does not report SIGPIPE errors by default. You -can build a version of bash that will report such errors. - -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, even a builtin or shell function, -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 updated POSIX standard has 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. - -E13) Why does filename completion misbehave if a colon appears in the filename? - -Filename completion (and word completion in general) may appear to behave -improperly if there is a colon in the word to be completed. - -The colon is special to readline's word completion code: it is one of the -characters that breaks words for the completer. Readline uses these characters -in sort of the same way that bash uses $IFS: they break or separate the words -the completion code hands to the application-specific or default word -completion functions. The original intent was to make it easy to edit -colon-separated lists (such as $PATH in bash) in various applications using -readline for input. - -This is complicated by the fact that some versions of the popular -`bash-completion' programmable completion package have problems with the -default completion behavior in the presence of colons. - -The current set of completion word break characters is available in bash as -the value of the COMP_WORDBREAKS variable. Removing `:' from that value is -enough to make the colon not special to completion: - -COMP_WORDBREAKS=${COMP_WORDBREAKS//:} - -You can also quote the colon with a backslash to achieve the same result -temporarily. - -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 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. - -The script examples/scripts.noah/meta.bash encapsulates the bind -commands in a shell function. - -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 -of the third edition, published in March, 2005, is 0-596-00965-8. Look for -it in fine bookstores near you. This edition of the book has been updated -to cover bash-3.0. - -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. - -Arnold Robbins and Nelson Beebe have written ``Classic Shell Scripting'', -published by O'Reilly. The first edition, with ISBN number 0-596-00595-4, -was published in May, 2005. - -Chris F. A. Johnson, a frequent contributor to comp.unix.shell and -gnu.bash.bug, has written ``Shell Scripting Recipes: A Problem-Solution -Approach,'' a new book on shell scripting, concentrating on features of -the POSIX standard helpful to shell script writers. The first edition from -Apress, with ISBN number 1-59059-471-1, was published in May, 2005. - -H3) What's coming in future versions? - -These are features I hope to include in a future version of bash. - -Rocky Bernstein's bash debugger (support is included with bash-3.0) -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 -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 `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 2006. Never make predictions. - -This document is Copyright 1995-2005 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/FAQ~ b/doc/FAQ~ deleted file mode 100644 index f941839ac..000000000 --- a/doc/FAQ~ +++ /dev/null @@ -1,2062 +0,0 @@ -This is the Bash FAQ, version 4.01, for Bash version 4.0. - -This document contains a set of frequently-asked questions concerning -Bash, the GNU Bourne-Again Shell. Bash is a freely-available command -interpreter with advanced features for both interactive use and shell -programming. - -Another good source of basic information about shells is the collection -of FAQ articles periodically posted to comp.unix.shell. - -Questions and comments concerning this document should be sent to -chet.ramey@case.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 4.0? -B2) Are there any user-visible incompatibilities between bash-4.0, - bash-3.2, and bash-2.05b? - -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? -E13) Why does filename completion misbehave if a colon appears in the filename? -E14) Why does quoting the pattern argument to the regular expression matching - conditional operator (=~) cause matching to stop working? - -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 4.0, first made available on XXX YYYYY, 2008. - -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 4.0: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-4.0.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-4.0.tar.gz - -Formatted versions of the documentation are available with the URLs: - -ftp://ftp.gnu.org/pub/gnu/bash/bash-doc-4.0.tar.gz -ftp://ftp.cwru.edu/pub/bash/bash-doc-4.0.tar.gz - -Any patches for the current version are available with the URL: - -ftp://ftp.cwru.edu/pub/bash/bash-4.0-patches/ - -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 (now part of Red Hat) as part -of their CYGWIN project. For more information about the project, see -http://www.cygwin.com/. - -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 -ports of bash-2.05b and bash-3.2 to the CYGWIN environment, and both -are available as part of their current release. - -Bash-2.05b and later versions should require no local Cygnus changes to -build and run under CYGWIN. - -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 began to work with bash-2.05, but I don't know the current status. - -Bash-3.0 compiles and runs with no modifications under Microsoft's Services -for Unix (SFU), once known as Interix. I do not anticipate any problems -with building bash-4.0, but will gladly accept any patches that are needed. - -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 2004 Edition) 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 4.0? - -Bash-4.0 is the fourth major release of bash. There are numerous new features, -some experimental. Depending on community reception, the experimental -features will evolve. - -Bash-4.0 contains the following new features (see the manual page for -complete descriptions and the CHANGES and NEWS files in the bash-4.0 -distribution): - -o When using substring expansion on the positional parameters, a starting - index of 0 now causes $0 to be prefixed to the list. - -o There is a new variable, $BASHPID, which always returns the process id of - the current shell. - -o There is a new `autocd' option that, when enabled, causes bash to attempt - to `cd' to a directory name that is supplied as the first word of a - simple command. - -o There is a new `checkjobs' option that causes the shell to check for and - report any running or stopped jobs at exit. - -o The programmable completion code exports a new COMP_TYPE variable, set to - a character describing the type of completion being attempted. - -o The programmable completion code exports a new COMP_KEY variable, set to - the character that caused the completion to be invoked (e.g., TAB). - -o The programmable completion code now uses the same set of characters as - readline when breaking the command line into a list of words. - -o The block multiplier for the ulimit -c and -f options is now 512 when in - Posix mode, as Posix specifies. - -o Changed the behavior of the read builtin to save any partial input received - in the specified variable when the read builtin times out. This also - results in variables specified as arguments to read to be set to the empty - string when there is no input available. When the read builtin times out, - it returns an exit status greater than 128. - -o The shell now has the notion of a `compatibility level', controlled by - new variables settable by `shopt'. Setting this variable currently - restores the bash-3.1 behavior when processing quoted strings on the rhs - of the `=~' operator to the `[[' command. - -o The `ulimit' builtin now has new -b (socket buffer size) and -T (number - of threads) options. - -o There is a new `compopt' builtin that allows completion functions to modify - completion options for existing completions or the completion currently - being executed. - -o The `read' builtin has a new -i option which inserts text into the reply - buffer when using readline. - -o A new `-E' option to the complete builtin allows control of the default - behavior for completion on an empty line. - -o There is now limited support for completing command name words containing - globbing characters. - -o The `help' builtin now has a new -d option, to display a short description, - and a -m option, to print help information in a man page-like format. - -o There is a new `mapfile' builtin to populate an array with lines from a - given file. - -o If a command is not found, the shell attempts to execute a shell function - named `command_not_found_handle', supplying the command words as the - function arguments. - -o There is a new shell option: `globstar'. When enabled, the globbing code - treats `**' specially -- it matches all directories (and files within - them, when appropriate) recursively. - -o There is a new shell option: `dirspell'. When enabled, the filename - completion code performs spelling correction on directory names during - completion. - -o The `-t' option to the `read' builtin now supports fractional timeout - values. - -o Brace expansion now allows zero-padding of expanded numeric values and - will add the proper number of zeroes to make sure all values contain the - same number of digits. - -o There is a new bash-specific bindable readline function: `dabbrev-expand'. - It uses menu completion on a set of words taken from the history list. - -o The command assigned to a key sequence with `bind -x' now sets two new - variables in the environment of the executed command: READLINE_LINE_BUFFER - and READLINE_POINT. The command can change the current readline line - and cursor position by modifying READLINE_LINE_BUFFER and READLINE_POINT, - respectively. - -o There is a new >>& redirection operator, which appends the standard output - and standard error to the named file. - -o The parser now understands `|&' as a synonym for `2>&1 |', which redirects - the standard error for a command through a pipe. - -o The new `;&' case statement action list terminator causes execution to - continue with the action associated with the next pattern in the - statement rather than terminating the command. - -o The new `;;&' case statement action list terminator causes the shell to - test the next set of patterns after completing execution of the current - action, rather than terminating the command. - -o The shell understands a new variable: PROMPT_DIRTRIM. When set to an - integer value greater than zero, prompt expansion of \w and \W will - retain only that number of trailing pathname components and replace - the intervening characters with `...'. - -o There are new case-modifying word expansions: uppercase (^[^]) and - lowercase (,[,]). They can work on either the first character or - array element, or globally. They accept an optional shell pattern - that determines which characters to modify. There is an optionally- - configured feature to include capitalization operators. - -o The shell provides associative array variables, with the appropriate - support to create, delete, assign values to, and expand them. - -o The `declare' builtin now has new -l (convert value to lowercase upon - assignment) and -u (convert value to uppercase upon assignment) options. - There is an optionally-configurable -c option to capitalize a value at - assignment. - -o There is a new `coproc' reserved word that specifies a coprocess: an - asynchronous command run with two pipes connected to the creating shell. - Coprocs can be named. The input and output file descriptors and the - PID of the coprocess are available to the calling shell in variables - with coproc-specific names. - -o A value of 0 for the -t option to `read' now returns success if there is - input available to be read from the specified file descriptor. - -o CDPATH and GLOBIGNORE are ignored when the shell is running in privileged - mode. - -o New bindable readline functions shell-forward-word and shell-backward-word, - which move forward and backward words delimited by shell metacharacters - and honor shell quoting. - -o New bindable readline functions shell-backward-kill-word and shell-kill-word - which kill words backward and forward, but use the same word boundaries - as shell-forward-word and shell-backward-word. - -A short feature history dating from Bash-2.0: - -Bash-3.2 contained the following new features: - -o Bash-3.2 now checks shell scripts for NUL characters rather than non-printing - characters when deciding whether or not a script is a binary file. - -o Quoting the string argument to the [[ command's =~ (regexp) operator now - forces string matching, as with the other pattern-matching operators. - -Bash-3.1 contained the following new features: - -o Bash-3.1 may now be configured and built in a mode that enforces strict - POSIX compliance. - -o The `+=' assignment operator, which appends to the value of a string or - array variable, has been implemented. - -o It is now possible to ignore case when matching in contexts other than - filename generation using the new `nocasematch' shell option. - -Bash-3.0 contained the following new features: - -o Features to support the bash debugger have been implemented, and there - is a new `extdebug' option to turn the non-default options on - -o HISTCONTROL is now a colon-separated list of options and has been - extended with a new `erasedups' option that will result in only one - copy of a command being kept in the history list - -o Brace expansion has been extended with a new {x..y} form, producing - sequences of digits or characters - -o Timestamps are now kept with history entries, with an option to save - and restore them from the history file; there is a new HISTTIMEFORMAT - variable describing how to display the timestamps when listing history - entries - -o The `[[' command can now perform extended regular expression (egrep-like) - matching, with matched subexpressions placed in the BASH_REMATCH array - variable - -o A new `pipefail' option causes a pipeline to return a failure status if - any command in it fails - -o The `jobs', `kill', and `wait' builtins now accept job control notation - in their arguments even if job control is not enabled - -o The `gettext' package and libintl have been integrated, and the shell - messages may be translated into other languages - -Bash-2.05b introduced the following new features: - -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 - -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/-i, - readonly -a/-f/name=value, trap -l, set +o, - set -b/-m/-o option/-h/-p/-B/-C/-H/-P, - unset -f/-v, ulimit -i/-m/-p/-q/-u/-x, - 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, compopt, mapfile - 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 and strict posix conformance - redirection to /dev/fd/N, /dev/stdin, /dev/stdout, /dev/stderr, - /dev/tcp/host/port, /dev/udp/host/port - debugger support, including `caller' builtin and new variables - RETURN trap - the `+=' assignment operator - autocd shell option and behavior - command-not-found hook with command_not_found_handle shell function - globstar shell option and `**' globbing behavior - |& synonym for `2>&1 |' - ;& and ;;& case action list terminators - case-modifying word expansions and variable attributes - associative arrays - coprocesses using the `coproc' reserved word and variables - -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, BASHPID, 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_DIRTRIM - 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 -i/-q/-u/-x, umask -S, alias -p, - shopt, disown, printf, complete, compgen, compopt, mapfile - `!' 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' - debugger support, including the `caller' builtin - RETURN trap - Timestamps in history entries - {x..y} brace expansion - The `+=' assignment operator - autocd shell option and behavior - command-not-found hook with command_not_found_handle shell function - globstar shell option and `**' globbing behavior - |& synonym for `2>&1 |' - ;& and ;;& case action list terminators - case-modifying word expansions and variable attributes - associative arrays - coprocesses using the `coproc' reserved word and variables - -Things ksh88 has or uses that bash does not: - tracked aliases (alias -t) - variables: ERRNO, FPATH, EDITOR, VISUAL - co-processes (bash uses different syntax) - 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, newgrp, print, - read -p/-s/var?prompt, set -A/-o gmacs/ - -o bgnice/-o markdirs/-o trackall/-o viraw/-s, - typeset -H/-L/-R/-Z/-A/-ft/-fu/-fx/-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? - -This list is current through ksh93t (11/04/2008) - -New things in ksh-93 not in bash-4.0: - 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 - 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 (match all instead of any) - exit statuses between 0 and 255 - FPATH and PATH mixing - lexical scoping for local variables in `ksh' functions - no scoping for local variables in `POSIX' functions - $'' \C[.collating-element.] escape sequence - -C/-I invocation options - print -f (bash uses printf) - `fc' has been renamed to `hist' - `.' can execute shell functions - getopts -a - printf %B, %H, %P, %R, %T, %Z modifiers, output base for %d, `=' flag - read -N (read -n differs, too)/-v - set -o showme/-o multiline (bash default) - `sleep' and `getconf' builtins (bash has loadable versions) - typeset -n and `nameref' variables - typeset -C/-S/-T/-X/-h/-s - experimental `type' definitions (a la typedef) using typeset - negative subscripts for indexed array variables - array expansions ${array[sub1..sub2]} and ${!array[sub1..sub2]} - associative array assignments using `;' as element separator - command substitution $(n<#) expands to current byte offset for fd N - new '${ ' form of command substitution, executed in current shell - new >;/<#pat/<##pat/<#/># redirections - redirection operators preceded with {varname} to store fd number in varname - brace expansion printf-like formats - -New things in ksh-93 present in bash-4.0: - associative arrays - [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' - new $'...' and $"..." quoting - FIGNORE (but bash uses GLOBIGNORE), HISTCMD - brace expansion and set -B - changes to kill builtin - `command', `builtin', `disown' builtins - echo -e - exec -c/-a - read -A (bash uses read -a) - read -t/-d - trap -p - `.' restores the positional parameters when it completes - set -o notify/-C - set -o pipefail - set -G (-o globstar) and ** - POSIX.2 `test' - umask -S - unalias -a - command and arithmetic substitution performed on PS1, PS4, and ENV - command name completion, TAB displaying possible completions - ENV processed only for interactive shells - The `+=' assignment operator - the `;&' case statement "fallthrough" pattern list terminator - csh-style history expansion and set -H - negative offsets in ${param:offset:length} - -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. Many Linux distributions -use GNU `which', which is a C program that can understand shell -aliases. - -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. - -As of bash-3.1, bash does not report SIGPIPE errors by default. You -can build a version of bash that will report such errors. - -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, even a builtin or shell function, -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 updated POSIX standard has 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. - -E13) Why does filename completion misbehave if a colon appears in the filename? - -Filename completion (and word completion in general) may appear to behave -improperly if there is a colon in the word to be completed. - -The colon is special to readline's word completion code: it is one of the -characters that breaks words for the completer. Readline uses these characters -in sort of the same way that bash uses $IFS: they break or separate the words -the completion code hands to the application-specific or default word -completion functions. The original intent was to make it easy to edit -colon-separated lists (such as $PATH in bash) in various applications using -readline for input. - -This is complicated by the fact that some versions of the popular -`bash-completion' programmable completion package have problems with the -default completion behavior in the presence of colons. - -The current set of completion word break characters is available in bash as -the value of the COMP_WORDBREAKS variable. Removing `:' from that value is -enough to make the colon not special to completion: - -COMP_WORDBREAKS=${COMP_WORDBREAKS//:} - -You can also quote the colon with a backslash to achieve the same result -temporarily. - -E14) Why does quoting the pattern argument to the regular expression matching - conditional operator (=~) cause regexp matching to stop working? - -In versions of bash prior to bash-3.2, the effect of quoting the regular -expression argument to the [[ command's =~ operator was not specified. -The practical effect was that double-quoting the pattern argument required -backslashes to quote special pattern characters, which interfered with the -backslash processing performed by double-quoted word expansion and was -inconsistent with how the == shell pattern matching operator treated -quoted characters. - -In bash-3.2, the shell was changed to internally quote characters in single- -and double-quoted string arguments to the =~ operator, which suppresses the -special meaning of the characters special to regular expression processing -(`.', `[', `\', `(', `), `*', `+', `?', `{', `|', `^', and `$') and forces -them to be matched literally. This is consistent with how the `==' pattern -matching operator treats quoted portions of its pattern argument. - -Since the treatment of quoted string arguments was changed, several issues -have arisen, chief among them the problem of white space in pattern arguments -and the differing treatment of quoted strings between bash-3.1 and bash-3.2. -Both problems may be solved by using a shell variable to hold the pattern. -Since word splitting is not performed when expanding shell variables in all -operands of the [[ command, this allows users to quote patterns as they wish -when assigning the variable, then expand the values to a single string that -may contain whitespace. The first problem may be solved by using backslashes -or any other quoting mechanism to escape the white space in the patterns. - -Bash-4.0 introduces the concept of a `compatibility level', controlled by -several options to the `shopt' builtin. If the `compat31' option is enabled, -bash reverts to the bash-3.1 behavior with respect to quoting the rhs of -the =~ operator. - -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 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. - -The script examples/scripts.noah/meta.bash encapsulates the bind -commands in a shell function. - -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. It's a variant of - - echo .[!.]* ..?* * - -(The ..?* catches files with names of three or more characters beginning -with `..') - -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 -of the third edition, published in March, 2005, is 0-596-00965-8. Look for -it in fine bookstores near you. This edition of the book has been updated -to cover bash-3.0. - -The GNU Bash Reference Manual has been published as a printed book by -Network Theory Ltd (Paperback, ISBN: 0-9541617-7-7, Nov. 2006). It covers -bash-3.2 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. - -Arnold Robbins and Nelson Beebe have written ``Classic Shell Scripting'', -published by O'Reilly. The first edition, with ISBN number 0-596-00595-4, -was published in May, 2005. - -Chris F. A. Johnson, a frequent contributor to comp.unix.shell and -gnu.bash.bug, has written ``Shell Scripting Recipes: A Problem-Solution -Approach,'' a new book on shell scripting, concentrating on features of -the POSIX standard helpful to shell script writers. The first edition from -Apress, with ISBN number 1-59059-471-1, was published in May, 2005. - -H3) What's coming in future versions? - -These are features I hope to include in a future version of bash. - -Rocky Bernstein's bash debugger (support is included with bash-3.0) -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 -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 `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 2009. Never make predictions. - -This document is Copyright 1995-2009 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/Makefile.in~ b/doc/Makefile.in~ deleted file mode 100644 index bb44bc458..000000000 --- a/doc/Makefile.in~ +++ /dev/null @@ -1,304 +0,0 @@ -# This Makefile is for the Bash/documentation directory -*- text -*-. -# -# Copyright (C) 2003-2008 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 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -PACKAGE = @PACKAGE_NAME@ -VERSION = @PACKAGE_VERSION@ - -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_VERSION = @PACKAGE_VERSION@ - -# -SHELL = @MAKE_SHELL@ -RM = rm -f - -topdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = .:@srcdir@ - -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -datarootdir = @datarootdir@ - -infodir = @infodir@ - -# set this to a directory name to have the HTML files installed -htmldir = @htmldir@ - -# Support an alternate destination root directory for package building -DESTDIR = - -mandir = @mandir@ -manpfx = man - -man1ext = .1 -man1dir = $(mandir)/$(manpfx)1 -man3ext = .3 -man3dir = $(mandir)/$(manpfx)3 - -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -BUILD_DIR = @BUILD_DIR@ - -SUPPORT_SRCDIR = $(topdir)/support - -# bad style -RL_LIBDIR = $(topdir)/lib/readline - -# unused -TEXINDEX = texindex -TEX = tex - -MAKEINFO = makeinfo -TEXI2DVI = ${SUPPORT_SRCDIR}/texi2dvi -TEXI2HTML = ${SUPPORT_SRCDIR}/texi2html -MAN2HTML = ${BUILD_DIR}/support/man2html -HTMLPOST = ${srcdir}/htmlpost.sh -INFOPOST = ${srcdir}/infopost.sh -QUIETPS = #set this to -q to shut up dvips -PAPERSIZE = letter # change to a4 for A4-size paper -PSDPI = 600 # could be 300 if you like -DVIPS = dvips -D ${PSDPI} $(QUIETPS) -t ${PAPERSIZE} -o $@ # tricky - -TEXINPUTDIR = $(RL_LIBDIR)/doc -SET_TEXINPUTS = TEXINPUTS=.:$(TEXINPUTDIR):$$TEXINPUTS - -# These tools might not be available; they're not required -DVIPDF = dvipdfm -o $@ -p ${PAPERSIZE} -PSPDF = gs -sPAPERSIZE=${PAPERSIZE} -sDEVICE=pdfwrite -dNOPAUSE -dBATCH -sOutputFile=$@ - -MKDIRS = ${SUPPORT_SRCDIR}/mkdirs - -# This should be a program that converts troff to an ascii-readable format -NROFF = groff -Tascii - -# This should be a program that converts troff to postscript -GROFF = groff - -HSUSER = $(RL_LIBDIR)/doc/hsuser.texi -RLUSER = $(RL_LIBDIR)/doc/rluser.texi - -BASHREF_FILES = $(srcdir)/bashref.texi $(srcdir)/version.texi - -.SUFFIXES: .0 .1 .3 .ms .ps .txt .dvi .html .pdf - -.1.ps: - $(RM) $@ - -${GROFF} -man $< > $@ - -.1.0: - $(RM) $@ - -${NROFF} -man $< > $@ - -.1.html: - $(RM) $@ - -${MAN2HTML} $< | ${HTMLPOST} > $@ - -.ms.ps: - $(RM) $@ - -${GROFF} -ms $< > $@ - -.ms.txt: - $(RM) $@ - -${NROFF} -ms $< > $@ - -.3.ps: - $(RM) $@ - -${GROFF} -man $< > $@ - -.3.0: - $(RM) $@ - -${NROFF} -man $< > $@ - -.3.html: - $(RM) $@ - -${MAN2HTML} $< > $@ - -.ps.pdf: - $(RM) $@ - -${PSPDF} $< - -.dvi.pdf: - $(RM) $@ - -${DVIPDF} $< - -.dvi.ps: - ${RM} $@ - -${DVIPS} $< - -all: ps info dvi text html -nodvi: ps info text html -everything: all pdf - -PSFILES = bash.ps bashbug.ps article.ps builtins.ps rbash.ps -DVIFILES = bashref.dvi bashref.ps -INFOFILES = bashref.info -MAN0FILES = bash.0 bashbug.0 builtins.0 rbash.0 -HTMLFILES = bashref.html bash.html -PDFFILES = bash.pdf bashref.pdf article.pdf rose94.pdf - -ps: ${PSFILES} -dvi: ${DVIFILES} -info: ${INFOFILES} -text: ${MAN0FILES} -html: ${HTMLFILES} -pdf: ${PDFFILES} - -bashref.dvi: $(BASHREF_FILES) $(HSUSER) $(RLUSER) - ${SET_TEXINPUTS} $(TEXI2DVI) $(srcdir)/bashref.texi - -bashref.info: $(BASHREF_FILES) $(HSUSER) $(RLUSER) - $(MAKEINFO) --no-split -I$(TEXINPUTDIR) $(srcdir)/bashref.texi - -bashref.html: $(BASHREF_FILES) $(HSUSER) $(RLUSER) - $(TEXI2HTML) -menu -monolithic -I $(TEXINPUTDIR) $(srcdir)/bashref.texi - -bash.info: bashref.info - ${SHELL} ${INFOPOST} < $(srcdir)/bashref.info > $@ ; \ - -bash.txt: bash.1 -bash.ps: bash.1 -bash.html: bash.1 $(MAN2HTML) -bashbug.ps: bashbug.1 -builtins.ps: builtins.1 bash.1 -rbash.ps: rbash.1 bash.1 -bash.0: bash.1 -bashbug.0: bashbug.1 -builtins.0: builtins.1 bash.1 -rbash.0: rbash.1 bash.1 -article.ps: article.ms - -bashref.ps: bashref.dvi - -article.pdf: article.ps -bashref.pdf: bashref.dvi -bash.pdf: bash.ps -rose94.pdf: rose94.ps - -$(MAN2HTML): ${topdir}/support/man2html.c - -( cd ${BUILD_DIR}/support ; ${MAKE} ${MFLAGS} man2html) - -clean: - $(RM) *.aux *.bak *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps \ - *.pgs *.bt *.bts *.rw *.rws *.fns *.kys *.tps *.vrs *.o - ${RM} core *.core - -mostlyclean: clean - $(RM) Makefile - -distclean: clean maybe-clean - $(RM) Makefile - -maintainer-clean: clean - ${RM} ${PSFILES} ${DVIFILES} ${INFOFILES} ${MAN0FILES} ${HTMLFILES} - ${RM} ${CREATED_FAQ} - $(RM) Makefile - -maybe-clean: - -if test "X$(topdir)" != "X$(BUILD_DIR)"; then \ - $(RM) ${PSFILES} ${DVIFILES} ${INFOFILES} ${MAN0FILES} ${HTMLFILES}; \ - fi - -installdirs: - -$(SHELL) $(SUPPORT_SRCDIR)/mkinstalldirs $(DESTDIR)$(man1dir) - -$(SHELL) $(SUPPORT_SRCDIR)/mkinstalldirs $(DESTDIR)$(infodir) - -if test -n "$(htmldir)" ; then \ - $(SHELL) $(SUPPORT_SRCDIR)/mkinstalldirs $(DESTDIR)$(htmldir) ; \ - fi - -install: info installdirs bash.info - -$(INSTALL_DATA) $(srcdir)/bash.1 $(DESTDIR)$(man1dir)/bash${man1ext} - -$(INSTALL_DATA) $(srcdir)/bashbug.1 $(DESTDIR)$(man1dir)/bashbug${man1ext} -# uncomment the next lines to install the builtins man page -# sed 's:bash\.1:man1/&:' $(srcdir)/builtins.1 > $${TMPDIR:-/var/tmp}/builtins.1 -# -$(INSTALL_DATA) $${TMPDIR:-/var/tmp}/builtins.1 $(DESTDIR)$(man1dir)/bash_builtins${man1ext} -# -$(RM) $${TMPDIR:-/var/tmp}/builtins.1 - -if test -f bash.info; then d=.; else d=$(srcdir); fi; \ - $(INSTALL_DATA) $$d/bash.info $(DESTDIR)$(infodir)/bash.info -# run install-info if it is present to update the info directory - if $(SHELL) -c 'install-info --version' >/dev/null 2>&1; then \ - install-info --dir-file=$(DESTDIR)$(infodir)/dir $(DESTDIR)$(infodir)/bash.info; \ - else true; fi -# if htmldir is set, install the html files into that directory - -if test -n "${htmldir}" ; then \ - $(INSTALL_DATA) $(srcdir)/bash.html $(DESTDIR)$(htmldir) ; \ - $(INSTALL_DATA) $(srcdir)/bashref.html $(DESTDIR)$(htmldir) ; \ - fi - -install_builtins: installdirs - sed 's:bash\.1:man1/&:' $(srcdir)/builtins.1 > $${TMPDIR:-/var/tmp}/builtins.1 - -$(INSTALL_DATA) $${TMPDIR:-/var/tmp}/builtins.1 $(DESTDIR)$(man1dir)/bash_builtins${man1ext} - -$(RM) $${TMPDIR:-/var/tmp}/builtins.1 - -install_everything: install install_builtins - -uninstall: - -$(RM) $(DESTDIR)$(man1dir)/bash${man1ext} $(DESTDIR)$(man1dir)/bashbug${man1ext} - -$(RM) $(DESTDIR)$(man1dir)/bash_builtins${man1ext} - $(RM) $(DESTDIR)$(infodir)/bash.info - -if test -n "$(htmldir)" ; then \ - $(RM) $(DESTDIR)$(htmldir)/bash.html ; \ - $(RM) $(DESTDIR)$(htmldir)/bashref.html ; \ - fi - -# for use by chet -CREATED_FAQ = faq.news faq.news2 faq.mail faq.version - -faq: ${CREATED_FAQ} - -faq.version: FAQ.version FAQ - sh mkfaqvers FAQ.version > $@ - -faq.headers.mail: FAQ.headers.mail FAQ - sh mkfaqvers FAQ.headers.mail > $@ - -faq.headers.news: FAQ.headers.news FAQ - sh mkfaqvers FAQ.headers.news > $@ - -faq.headers.news2: FAQ.headers.news2 FAQ - sh mkfaqvers FAQ.headers.news2 > $@ - -faq.news: FAQ faq.headers.news faq.version - $(RM) $@ - cat faq.headers.news faq.version FAQ > $@ - -faq.news2: FAQ faq.headers.news2 faq.version - $(RM) $@ - cat faq.headers.news2 faq.version FAQ > $@ - -faq.mail: FAQ faq.headers.mail faq.version - $(RM) $@ - cat faq.headers.mail faq.version FAQ > $@ - -inst: bashref.texi - $(SHELL) ./mkinstall - cmp -s INSTALL ../INSTALL || mv INSTALL ../INSTALL - $(RM) INSTALL - -posix: bashref.texi - $(SHELL) ./mkposix - cmp -s POSIX ../POSIX || mv POSIX ../POSIX - $(RM) POSIX - -rbash: bashref.texi - $(SH) ./mkrbash - cmp -s RBASH ../RBASH || mv RBASH ../RBASH - $(RM) RBASH - -xdist: pdf inst posix rbash 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 3b1e37513..000000000 --- a/doc/bash.1~ +++ /dev/null @@ -1,9403 +0,0 @@ -.\" -.\" MAN PAGE COMMENTS to -.\" -.\" Chet Ramey -.\" Case Western Reserve University -.\" chet@po.cwru.edu -.\" -.\" Last Change: Sat Feb 7 20:50:40 EST 2009 -.\" -.\" bash_builtins, strip all but Built-Ins section -.if \n(zZ=1 .ig zZ -.if \n(zY=1 .ig zY -.TH BASH 1 "2009 February 7" "GNU Bash-4.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-2009 by the Free Software Foundation, Inc. -.if t Bash is Copyright \(co 1989-2009 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 -Shell and Utilities portion of the IEEE POSIX specification -(IEEE Standard 1003.1). -.B Bash -can be configured to be POSIX-conformant by default. -.SH OPTIONS -In addition to the single-character shell options documented in the -description of the \fBset\fR builtin command, \fBbash\fR -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 output. -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 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 error 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 with its standard input -connected to a a network connection, as if by the remote shell -daemon, usually \fIrshd\fP, or the secure shell daemon \fIsshd\fP. -If -.B bash -determines it is being run in this fashion, 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 -.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 -one of the control operators -.B | -or \fB|&\fP. -The format for a pipeline is: -.RS -.PP -[\fBtime\fP [\fB\-p\fP]] [ ! ] \fIcommand\fP [ [\fB|\fP\(bv\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). -If \fB|&\fP is used, the standard error of \fIcommand\fP is connected to -\fIcommand2\fP's standard input through the pipe; it is shorthand for -\fB2>&1 |\fP. -This implicit redirection of the standard error is performed after any -redirections specified by the command. -.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 -AND and OR lists are sequences of one of more pipelines separated by the -\fB&&\fP and \fB\(bv\(bv\fP control operators, respectively. -AND and OR lists are executed with left associativity. -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 or another -shell metacharacter. -.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. -If the shell option -.B nocasematch -is enabled, the match is performed without regard to the case -of alphabetic characters. -The return value is 0 if the string matches (\fB==\fP) or does not match -(\fB!=\fP) the pattern, and 1 otherwise. -Any part of the pattern may be quoted to force it to be matched as a -string. -.if t .sp 0.5 -.if n .sp 1 -An additional binary operator, \fB=~\fP, is available, with the same -precedence as \fB==\fP and \fB!=\fP. -When it is used, the string to the right of the operator is considered -an extended regular expression and matched accordingly (as in \fIregex\fP(3)). -The return value is 0 if the string matches -the pattern, and 1 otherwise. -If the regular expression is syntactically incorrect, the conditional -expression's return value is 2. -If the shell option -.B nocasematch -is enabled, the match is performed without regard to the case -of alphabetic characters. -Any part of the pattern may be quoted to force it to be matched as a -string. -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). -The \fIword\fP is expanded using tilde -expansion, parameter and variable expansion, arithmetic substitution, -command substitution, process substitution and quote removal. -Each \fIpattern\fP examined is expanded using tilde -expansion, parameter and variable expansion, arithmetic substitution, -command substitution, and process substitution. -If the shell option -.B nocasematch -is enabled, the match is performed without regard to the case -of alphabetic characters. -When a match is found, the corresponding \fIlist\fP is executed. -If the \fB;;\fP operator is used, no subsequent matches are attempted after -the first pattern match. -Using \fB;&\fP in place of \fB;;\fP causes execution to continue with -the \fIlist\fP associated with the next set of patterns. -Using \fB;;&\fP in place of \fB;;\fP causes the shell to test the next -pattern list in the statement, if any, and execute any associated \fIlist\fP -on a successful match. -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 Coprocesses -.PP -A \fIcoprocess\fP is a shell command preceded by the \fBcoproc\fP reserved -word. -A coprocess is executed asynchronously in a subshell, as if the command -had been terminated with the \fB&\fP control operator, with a two-way pipe -established between the executing shell and the coprocess. -.PP -The format for a coprocess is: -.RS -.PP -\fBcoproc\fP [\fINAME\fP] \fIcommand\fP [\fIredirections\fP] -.RE -.PP -This creates a coprocess named \fINAME\fP. -If \fINAME\fP is not supplied, the default name is \fICOPROC\fP. -\fINAME\fP must not be supplied if \fIcommand\fP is a \fIsimple -command\fP (see above); otherwise, it is interpreted as the first word -of the simple command. -When the coproc is executed, the shell creates an array variable (see -.B Arrays -below) named \fINAME\fP in the context of the executing shell. -The standard output of -.I command -is connected via a pipe to a file descriptor in the executing shell, -and that file descriptor is assigned to \fINAME\fP[0]. -The standard input of -.I command -is connected via a pipe to a file descriptor in the executing shell, -and that file descriptor is assigned to \fINAME\fP[1]. -This pipe is established before any redirections specified by the -command (see -.SM -.B REDIRECTION -below). -The file descriptors can be utilized as arguments to shell commands -and redirections using standard word expansions. -The process id of the shell spawned to execute the coprocess is -available as the value of the variable \fINAME\fP_PID. -The \fBwait\fP -builtin command may be used to wait for the coprocess to terminate. -.PP -The return status of a coprocess is the exit status of \fIcommand\fP. -.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 -(see -.SM -.B HISTORY EXPANSION -below), 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 \` , -.BR \e , -and, when history expansion is enabled, -.BR ! . -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. -If enabled, history expansion will be performed unless an -.B ! -appearing in double quotes is escaped using a backslash. -The backslash preceding the -.B ! -is not removed. -.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\(aq\fIstring\fP\(aq are treated specially. The -word expands to \fIstring\fP, with backslash-escaped characters replaced -as specified by the ANSI C standard. Backslash escape sequences, if -present, are decoded as follows: -.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\(aq -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. -.PP -In the context where an assignment statement is assigning a value -to a shell variable or array index, the += operator can be used to -append to or add to the variable's previous value. -When += is applied to a variable for which the integer attribute has been -set, \fIvalue\fP is evaluated as an arithmetic expression and added to the -variable's current value, which is also evaluated. -When += is applied to an array variable using compound assignment (see -.B Arrays -below), the -variable's value is not unset (as it is when using =), and new values are -appended to the array beginning at one greater than the array's maximum index -(for indexed arrays) or added as additional key\-value pairs in an -associative array. -When applied to a string-valued variable, \fIvalue\fP is expanded and -appended to the variable's value. -.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" ... -If the double-quoted expansion occurs within a word, the expansion of -the first parameter is joined with the beginning part of the original -word, and the expansion of the last parameter is joined with the last -part of the original word. -When there are no positional parameters, "\fB$@\fP" and -.B $@ -expand to nothing (i.e., they are removed). -.TP -.B # -Expands to the number of positional parameters in decimal. -.TP -.B ? -Expands to the exit 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 pathname used to invoke the -shell or shell script being executed as passed in the environment -or argument list. -Subsequently, expands to the last argument to the previous command, -after expansion. -Also set to the full pathname used to invoke each command executed -and placed in the environment exported to that command. -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 BASHPID -Expands to the process id of the current \fBbash\fP process. -This differs from \fB$$\fP under certain circumstances, such as subshells -that do not require \fBbash\fP to be re-initialized. -.TP -.B BASH_ALIASES -An associative array variable whose members correspond to the internal -list of aliases as maintained by the \fBalias\fP builtin -Elements added to this array appear in the alias list; unsetting array -elements cause aliases to be removed from the alias list. -.TP -.B BASH_ARGC -An array variable whose values are the number of parameters in each -frame of the current \fBbash\fP 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. -The shell sets \fBBASH_ARGC\fP only when in extended debugging mode -(see the description of the -.B extdebug -option to the -.B shopt -builtin below) -.TP -.B BASH_ARGV -An array variable containing all of the parameters in the current \fBbash\fP -execution call stack. The final parameter of the last subroutine call -is at the top of the stack; the first parameter of the initial call is -at the bottom. When a subroutine is executed, the parameters supplied -are pushed onto \fBBASH_ARGV\fP. -The shell sets \fBBASH_ARGV\fP only when in extended debugging mode -(see the description of the -.B extdebug -option to the -.B shopt -builtin below) -.TP -.B BASH_CMDS -An associative array variable whose members correspond to the internal -hash table of commands as maintained by the \fBhash\fP builtin. -Elements added to this array appear in the hash table; unsetting array -elements cause commands to be removed from the hash table. -.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 \fBFUNCNAME\fP. -\fB${BASH_LINENO[\fP\fI$i\fP\fB]}\fP is the line number in the source -file where \fB${FUNCNAME[\fP\fI$i\fP\fB]}\fP was called -(or \fB${BASH_LINENO[\fP\fI$i-1\fP\fB]}\fP if referenced within another -shell function). -The corresponding source file name is \fB${BASH_SOURCE[\fP\fI$i\fP\fB]}\fP. -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_KEY -The key (or final key of a key sequence) used to invoke the current -completion function. -.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_TYPE -Set to an integer value corresponding to the type of completion attempted -that caused a completion function to be called: -\fITAB\fP, for normal completion, -\fI?\fP, for listing completions after successive tabs, -\fI!\fP, for listing alternatives on partial word completion, -\fI@\fP, to list completions if the word is not unmodified, -or -\fI%\fP, for menu completion. -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 \fBreadline\fP 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. -The line is split into words as \fBreadline\fP would split it, using -\fBCOMP_WORDBREAKS\fP as described above. -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 -.if t \f(CW"main"\fP. -.if n "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, by removing the oldest entries, -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. -This uses the history comment character to distinguish timestamps from -other history lines. -.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=\(aq/var/mail/bfox?"You have mail":~/shell\-mail?"$_ has mail!"\(aq -.PP -.B Bash -supplies a default value for this variable, but the location of the user -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 PROMPT_DIRTRIM -If set to a number greater than zero, the value is used as the number of -trailing directory components to retain when expanding the \fB\ew\fB and -\fB\eW\fP prompt string escapes (see -.SM -.B PROMPTING -below). Characters removed are replaced with an ellipsis. -.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$\(aq\enreal\et%3lR\enuser\et%3lU\ensys\t%3lS\(aq\fP. -If the value is null, no timing information is displayed. -A trailing newline is added when the format string is displayed. -.TP -.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 TMPDIR -If set, \fBBash\fP uses its value as the name of a directory in which -\fBBash\fP creates temporary files for the shell's use. -.TP -.B auto_resume -This variable controls how the shell interacts with the user and -job control. If this variable is set, single word simple -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 \fB%\fP\fIstring\fP 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 indexed and associative array variables. -Any variable may be used as an indexed 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. -Indexed arrays are referenced using integers (including arithmetic -expressions) and are zero-based; associative arrays are referenced -using arbitrary strings. -.PP -An indexed 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 indexed 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. -.PP -Associative arrays are created using -.BR "declare \-A \fIname\fP" . -.PP -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. -Indexed array assignments do not require the bracket and subscript. -When assigning to indexed arrays, 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. -.PP -When assigning to an associative array, the subscript is required. -.PP -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. -If the double-quoted expansion occurs within a word, the expansion of -the first parameter is joined with the beginning part of the original -word, and the expansion of the last parameter is joined with the last -part of the original word. -This is analogous to the expansion -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 the array with a subscript of 0. -.PP -The -.B unset -builtin is used to destroy arrays. \fBunset\fP \fIname\fP[\fIsubscript\fP] -destroys the array element at index \fIsubscript\fP. -Care must be taken to avoid unwanted side effects caused by filename -generation. -\fBunset\fP \fIname\fP, where \fIname\fP is an array, or -\fBunset\fP \fIname\fP[\fIsubscript\fP], where -\fIsubscript\fP is \fB*\fP or \fB@\fP, removes the entire array. -.PP -The -.BR declare , -.BR local , -and -.B readonly -builtins each accept a -.B \-a -option to specify an indexed array and a -.B \-A -option to specify an associative 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\fIincr\fP\fB]}\fP, -where \fIx\fP and \fIy\fP are either integers or single characters, -and \fIincr\fP, an optional increment, is an integer. -When integers are supplied, the expression expands to each number between -\fIx\fP and \fIy\fP, inclusive. -Supplied integers may be prefixed with \fI0\fP to force each term to have the -same width. When either \fIx\fP or \fPy\fP begins with a zero, the shell -attempts to force all generated terms to contain the same number of digits, -zero-padding where necessary. -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. -When the increment is supplied, it is used as the difference between -each term. The default increment is 1 or -1 as appropriate. -.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 the first -.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 parameter -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. -.PP -When not performing substring expansion, using the forms documented below, -\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 indexed array name subscripted by @ or *, -the result is the \fIlength\fP -members of the array beginning with ${\fIparameter\fP[\fIoffset\fP]}. -A negative \fIoffset\fP is taken relative to one greater than the maximum -index of the specified array. -Substring expansion applied to an associative array produces undefined -results. -Note that a negative offset must be separated from the colon by at least -one space to avoid being confused with the :- expansion. -Substring indexing is zero-based unless the positional parameters -are used, in which case the indexing starts at 1 by default. -If \fIoffset\fP is 0, and the positional parameters are used, \fB$0\fP is -prefixed to the list. -.TP -${\fB!\fP\fIprefix\fP\fB*\fP} -.PD 0 -.TP -${\fB!\fP\fIprefix\fP\fB@\fP} -.PD -\fBNames matching prefix.\fP -Expands to the names of variables whose names begin with \fIprefix\fP, -separated by the first character of the -.SM -.B IFS -special variable. -When \fI@\fP is used and the expansion appears within double quotes, each -variable name expands to a separate word. -.TP -${\fB!\fP\fIname\fP[\fI@\fP]} -.PD 0 -.TP -${\fB!\fP\fIname\fP[\fI*\fP]} -.PD -\fBList of array keys.\fP -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} -\fBParameter length.\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 -\fBRemove matching prefix pattern.\fP -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 -\fBRemove matching suffix pattern.\fP -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} -\fBPattern substitution.\fP -The \fIpattern\fP is expanded to produce a pattern just as in -pathname expansion. -\fIParameter\fP is expanded and the longest match of \fIpattern\fP -against its value is replaced with \fIstring\fP. -If \fIpattern\fP begins with \fB/\fP, all matches of \fIpattern\fP are -replaced with \fIstring\fP. Normally only the first match is replaced. -If \fIpattern\fP begins with \fB#\fP, it must match at the beginning -of the expanded value of \fIparameter\fP. -If \fIpattern\fP begins with \fB%\fP, it must match at the end -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. -.TP -${\fIparameter\fP\fB^\fP\fIpattern\fP} -.PD 0 -.TP -${\fIparameter\fP\fB^^\fP\fIpattern\fP} -.TP -${\fIparameter\fP\fB,\fP\fIpattern\fP} -.TP -${\fIparameter\fP\fB,,\fP\fIpattern\fP} -.PD -\fBCase modification.\fP -This expansion modifies the case of alphabetic characters in \fIparameter\fP. -The \fIpattern\fP is expanded to produce a pattern just as in -pathname expansion. -The \fB^\fP operator converts lowercase letters matching \fIpattern\fP -to uppercase; the \fB,\fP operator converts matching uppercase letters -to lowercase. -The \fB^^\fP and \fB,,\fP expansions convert each matched character in the -expanded value; the \fB^\fP and \fB,\fP expansions match and convert only -the first character in the expanded value.. -If \fIpattern\fP is omitted, it is treated like a \fB?\fP, which matches -every character. -If -.I parameter -is -.B @ -or -.BR * , -the case modification 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 case modification 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 -sequences of -.BR , -.BR , -and -.B -at the beginning and end of the results of the previous -expansions are ignored, and -any sequence of -.SM -.B IFS -characters not at the beginning or end 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\(aq\^\(aq\fP\^) are retained. -Unquoted implicit null arguments, resulting from the expansion of -parameters that have no values, are removed. -If a parameter with no value is expanded within double quotes, a -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 not enabled, 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. -When the \fBglobstar\fP shell option is enabled, and \fB*\fP is used in -a filename expansion context, two adjacent \fB*\fPs used as a single -pattern will match all files and zero or more directories and -subdirectories. -If followed by a \fB/\fP, two adjacent \fB*\fPs will match only directories -and subdirectories. -.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 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 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 \(aq , -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 from the 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. -.PP -Redirections using file descriptors greater than 9 should be used with -care, as they may conflict with file descriptors the shell uses -internally. -.SS Redirecting Input -.PP -Redirection of input causes the file whose name results from -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 -This construct 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 -.IR word . -.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 -.PP -.SS Appending Standard Output and Standard Error -.PP -This construct allows both the -standard output (file descriptor 1) and -the standard error output (file descriptor 2) -to be appended to the file whose name is the -expansion of -.IR word . -.PP -The format for appending standard output and standard error is: -.RS -.PP -\fB&>>\fP\fIword\fP -.RE -.PP -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 delimiter -(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 -and -.B RETURN -traps (see the description of the -.B trap -builtin under -.SM -.B SHELL BUILTIN COMMANDS -below) are not inherited unless the function has been given the -\fBtrace\fP attribute (see the description of the -.SM -.B declare -builtin below) or the -\fB\-o functrace\fP shell option has been enabled with -the \fBset\fP builtin -(in which case all functions inherit the \fBDEBUG\fP and \fBRETURN\fP traps). -.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. -A function definition may be deleted using the \fB\-f\fP option to -the -.B unset -builtin. -Note that shell functions and variables with the same name may result -in multiple identically-named entries in the environment passed to the -shell's children. -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 interchangeably 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. -.PP -Unless otherwise specified, primaries that operate on files follow symbolic -links and operate on the target of the link, rather than the link itself. -.sp 1 -.PD 0 -.TP -.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 searches for a defined shell -function named \fBcommand_not_found_handle\fP. -If that function exists, it is invoked with the original command and -the original command's arguments as its arguments, and the function's -exit status becomes the exit status of the shell. -If that function is not defined, 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 -Subshells spawned to execute command substitutions inherit the value of -the \fB\-e\fP option from the parent shell. When not in posix mode, -Bash clears the \fB\-e\fP option in such subshells. -.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" -.PP -The exit status of an executed command is the value returned by the -\fIwaitpid\fP system call or equivalent function. Exit statuses -fall between 0 and 255, though, as explained below, the shell may -use values above 125 specially. Exit statuses from shell builtins and -compound commands are also limited to this range. Under certain -circumstances, the shell will use special values to indicate specific -failure modes. -.PP -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 \fBbash\fP is waiting for a command to complete and receives a signal -for which a trap has been set, the trap will not be executed until -the command completes. -When \fBbash\fP 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 specification (\fIjobspec\fP). 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 %\- . -If there is only a single job, \fB%+\fP and \fB%\-\fP can both be used -to refer to that job. -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 \- . -A single % (with no accompanying job specification) also refers to the -current job. -.PP -Simply naming a job can be used to bring it into the -foreground: -.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 (or, if the \fBcheckjobs\fP shell option has -been enabled using the \fBshopt\fP builtin, running), the shell prints a -warning message, and, if the \fBcheckjobs\fP option is enabled, lists the -jobs and their statuses. -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 any 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 + patch level (e.g., 2.00.0) -.TP -.B \ew -the current working directory, with \fB$HOME\fP abbreviated with a tilde -(uses the \fB$PROMPT_DIRTRIM\fP variable) -.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. -Line editing is also used when using the \fB\-e\fP option to the -\fBread\fP builtin. -By default, the line editing commands are similar to those of emacs. -A vi-style line editing interface is also available. -Line editing can be enabled at any time using the -.B \-o emacs -or -.B \-o vi -options to the -.B set -builtin (see -.SM -.B SHELL BUILTIN COMMANDS -below). -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. -.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\(aq -literal \(aq -.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 \(aq. -.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 -.B Off -(without regard to case). -Unrecognized variable names are ignored. -When a variable value is read, empty or null values, "on" (case-insensitive), -and "1" are equivalent to \fBOn\fP. All other values are equivalent to -\fBOff\fP. -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 bind\-tty\-special\-chars (On) -If set to \fBOn\fP, readline attempts to bind the control characters -treated specially by the kernel's terminal driver to their readline -equivalents. -.TP -.B comment\-begin (``#'') -The string that is inserted when the readline -.B insert\-comment -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\-prefix\-display\-length (0) -The length in characters of the common prefix of a list of possible -completions that is displayed without modification. When set to a -value greater than zero, common prefixes longer than this value are -replaced with an ellipsis when displaying possible completions. -.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 (Off) -If set to \fBon\fP, the history code attempts to place point at the -same location on each history line retrieved with \fBprevious-history\fP -or \fBnext-history\fP. -.TP -.B history\-size (0) -Set the maximum number of history entries saved in the history list. If -set to zero, the number of entries in the history list is not limited. -.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 revert\-all\-at\-newline (Off) -If set to \fBon\fP, readline will undo all changes to history lines -before returning when \fBaccept\-line\fP is executed. By default, -history lines may be modified and retain individual undo lists across -calls to \fBreadline\fP. -.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 shell\-forward\-word -Move forward to the end of the next word. -Words are delimited by non-quoted shell metacharacters. -.TP -.B shell\-backward\-word -Move back to the start of the current or previous word. -Words are delimited by non-quoted shell metacharacters. -.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. -Once the argument \fIn\fP is computed, the argument is extracted -as if the "!\fIn\fP" history expansion had been specified. -.TP -.B -yank\-last\-arg (M\-.\^, M\-_\^) -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. -The history expansion facilities are used to extract the last argument, -as if the "!$" history expansion had been specified. -.TP -.B shell\-expand\-line (M\-C\-e) -Expand the line as the shell does. This -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 $VISUAL , -.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 shell\-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 \fBshell\-forward\-word\fP. -.TP -.B shell\-backward\-kill\-word (M\-Rubout) -Kill the word behind point. -Word boundaries are the same as those used by \fBshell\-backward\-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 dabbrev\-expand -Attempt menu 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 output. 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, and arithmetic 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 -.BR COMP_LINE , -.SM -.BR COMP_POINT , -.SM -.BR COMP_KEY , -and -.SM -.B COMP_TYPE -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 the history file is read, -lines beginning with the history comment character followed immediately -by a digit are interpreted as timestamps for the preceding history line. -These timestamps are optionally displayed depending on the value of the -.SM -.B HISTTIMEFORMAT -variable. -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. -If the -.SM -.HISTTIMEFORMAT -variable is set, time stamps are written to the history file, marked -with the history comment character, so -they may be preserved across shell sessions. -This uses the history comment character to distinguish timestamps from -other history lines. -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" ). -The shell uses -the history comment character to mark history timestamps when -writing the history file. -.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. -For example, the \fB:\fP, \fBtrue\fP, \fBfalse\fP, and \fBtest\fP builtins -do not accept 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 each suspended job \fIjobspec\fP in the background, as if it -had been started with -.BR & . -If -.I jobspec -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, any specified \fIjobspec\fP was not found -or was 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 \-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 \-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 \-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. -When \fIshell\-command\fP is executed, the shell sets the -.B READLINE_LINE -variable to the contents of the \fBreadline\fP line buffer and the -.B READLINE_POINT -variable to the current location of the insertion point. -If the executed command changes the value of -.B READLINE_LINE -or -.BR READLINE_POINT , -those new values will be reflected in the editing state. -.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 \fIn\fP is not greater than or equal to 1. -.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 -\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 -\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 -\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\-E\fP] [\fB\-A\fP \fIaction\fP] [\fB\-G\fP \fIglobpat\fP] [\fB\-W\fP \fIwordlist\fP] [\fB\-F\fP \fIfunction\fP] [\fB\-C\fP \fIcommand\fP] -.br -[\fB\-X\fP \fIfilterpat\fP] [\fB\-P\fP \fIprefix\fP] [\fB\-S\fP \fIsuffix\fP] \fIname\fP [\fIname ...\fP] -.PD 0 -.TP -\fBcomplete\fP \fB\-pr\fP [\fB\-E\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. -The \fB\-E\fP option indicates that the remaining options and actions should -apply to ``empty'' command completion; that is, completion attempted on a -blank line. -.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, -quoting special characters, 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. -.TP 8 -.B plusdirs -After any matches defined by the compspec are generated, -directory name completion is attempted and any -matches are added to the results of the other actions. -.RE -.TP 8 -\fB\-A\fP \fIaction\fP -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 -\fBcompopt\fP [\fB\-o\fP \fIoption\fP] [\fB+o\fP \fIoption\fP] [\fIname\fP] -Modify completion options for each \fIname\fP according to the -\fIoption\fPs, or for the -currently-execution completion if no \fIname\fPs are supplied. -If no \fIoption\fPs are given, display the completion options for each -\fIname\fP or the current completion. -The possible values of \fIoption\fP are those valid for the \fBcomplete\fP -builtin described above. -.PP -The return value is true unless an invalid option is supplied, an attempt -is made to modify the options for a \fIname\fP for which no completion -specification exists, or an output error occurs. -.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 \fIn\fP is not greater than or equal to 1. -.TP -\fBdeclare\fP [\fB\-aAfFilrtux\fP] [\fB\-p\fP] [\fIname\fP[=\fIvalue\fP] ...] -.PD 0 -.TP -\fBtypeset\fP [\fB\-aAfFilrtux\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 with \fIname\fP arguments, additional options are ignored. -When -.B \-p -is supplied without \fIname\fP arguments, it will display the attributes -and values of all variables having the attributes specified by the -additional options. -If no other options are supplied with \fB\-p\fP, \fBdeclare\fP will display -the attributes and values of all shell variables. The \fB\-f\fP option -will restrict the display to shell functions. -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 indexed array variable (see -.B Arrays -above). -.TP -.B \-A -Each \fIname\fP is an associative 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 \-l -When the variable is assigned a value, all upper-case characters are -converted to lower-case. -The upper-case attribute is disabled. -.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 and \fBRETURN\fP traps from -the calling shell. -The trace attribute has no special meaning for variables. -.TP -.B \-u -When the variable is assigned a value, all lower-case characters are -converted to upper-case. -The lower-case attribute is disabled. -.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 exceptions that \fB+a\fP -may not be used to destroy an array variable and \fB+r\fB will not -remove the readonly attribute. -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 [+\fIn\fP] [\-\fIn\fP] [\fB\-cplv\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 -.I jobspec -is not present, and neither \fB\-a\fB nor \fB\-r\fP is supplied, -the shell's notion of the \fIcurrent job\fP is used. -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 \fB\-\-\fP 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 further output -.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 \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\-a\fP] [\fB\-dnps\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 argument 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\-lnr\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\-dms\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. -.RS -.PD 0 -.TP -.B \-d -Display a short description of each \fIpattern\fP -.TP -.B \ -m -Display the description of each \fIpattern\fP in a manpage-like format -.TP -.B \-s -Display only a short usage synopsis for each \fIpattern\fP -.PD -.RE -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, -marked with the history comment character. -When the history file is read, lines beginning with the history -comment character followed immediately by a digit are interpreted -as timestamps for the previous history line. -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 -\fBmapfile\fP [\fB\-n\fP \fIcount\fP] [\fB\-O\fP \fIorigin\fP] [\fB\-s\fP \fIcount\fP] [\fB\-t\fP] [\fB\-u\fP \fIfd\fP] [\fB\-C\fP \fIcallback\fP] [\fB\-c\fP \fIquantum\fP] [\fIarray\fP] -.PD 0 -.TP -\fBreadarray\fP [\fB\-n\fP \fIcount\fP] [\fB\-O\fP \fIorigin\fP] [\fB\-s\fP \fIcount\fP] [\fB\-t\fP] [\fB\-u\fP \fIfd\fP] [\fB\-C\fP \fIcallback\fP] [\fB\-c\fP \fIquantum\fP] [\fIarray\fP] -.PD -Read lines from the standard input into array variable -.IR array , -or from file descriptor -.IR fd -if the -.B \-u -option is supplied. -The variable \fBMAPFILE\fP is the default \fIarray\fP. -Options, if supplied, have the following meanings: -.RS -.PD 0 -.TP -.B \-n -Copy at most -.I count -lines. If \fIcount\fP is 0, all lines are copied. -.TP -.B \-O -Begin assigning to -.I array -at index -.IR origin . -The default index is 0. -.TP -.B \-s -Discard the first \fIcount\fP lines read. -.TP -.B \-t -Remove a trailing line from each line read. -.TP -.B \-u -Read lines from file descriptor \fIfd\fP instead of the standard input. -.TP -.B \-C -Evaluate -.I callback -each time \fIquantum\fP lines are read. The \fB\-c\fP option specifies -.IR quantum . -.TP -.B \-c -Specify the number of lines read between each call to -.IR callback . -.PD -.PP -If -.B \-C -is specified without -.BR \-c , -the default quantum is 5000. -When \fIcallback\fP is evaluated, it is supplied the index of the next -array element to be assigned as an additional argument. -\fIcallback\fP is evaluated after the line is read but before the -array element is assigned. -.PP -If not supplied with an explicit origin, \fBmapfile\fP will clear \fIarray\fP -before assigning to it. -.PP -\fBmapfile\fP returns successfully unless an invalid option or option -argument is supplied, or \fIarray\fP is invalid or unassignable. -.RE -.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 -.B \-n -Suppresses the normal change of directory when removing directories -from the stack, so that only the stack is manipulated. -.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. -.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 [\fB\-v\fP \fIvar\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\(aq\fP, \fB\e"\fP, and \fB\e?\fP are not removed, and octal escapes -beginning with \fB\e0\fP may contain up to four digits), -and \fB%q\fP causes \fBprintf\fP to output the corresponding -\fIargument\fP in a format that can be reused as shell input. -.sp 1 -The \fB\-v\fP option causes the output to be assigned to the variable -\fIvar\fP rather than being printed to the standard output. -.sp 1 -The \fIformat\fP is reused as necessary to consume all of the \fIarguments\fP. -If the \fIformat\fP requires more \fIarguments\fP than are supplied, the -extra format specifications behave as if a zero value or null string, as -appropriate, had been supplied. The return value is zero on success, -non-zero on failure. -.TP -\fBpushd\fP [\fB\-n\fP] [+\fIn\fP] [\-\fIn\fP] -.PD 0 -.TP -\fBpushd\fP [\fB\-n\fP] [\fIdir\fP] -.PD -Adds a directory to the top of the directory stack, or rotates -the stack, making the new top of the stack the current working -directory. With no arguments, exchanges the top two directories -and returns 0, unless the directory stack is empty. -Arguments, if supplied, have the following meanings: -.RS -.PD 0 -.TP -.B \-n -Suppresses the normal change of directory when adding directories -to the stack, so that only the stack is manipulated. -.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 -.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\-a\fP \fIaname\fP] [\fB\-d\fP \fIdelim\fP] [\fB\-i\fP \fItext\fP] [\fB\-n\fP \fInchars\fP] [\fB\-p\fP \fIprompt\fP] [\fB\-t\fP \fItimeout\fP] [\fB\-u\fP \fIfd\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. -Readline uses the current (or default, if line editing was not previously -active) editing settings. -.TP -.B \-i \fItext\fP -If -.B readline -is being used to read the line, \fItext\fP is placed into the editing -buffer before editing begins. -.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. -\fItimeout\fP may be a decimal number with a fractional portion following -the decimal point. -This option is only effective if \fBread\fP is reading input from a -terminal, pipe, or other special file; it has no effect when reading -from regular files. -If \fItimeout\fP is 0, \fBread\fP returns success if input is available on -the specified file descriptor, failure otherwise. -The exit status is greater than 128 if the timeout is exceeded. -.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 (in which case the return code is greater than 128), or an -invalid file descriptor is supplied as the argument to \fB\-u\fP. -.RE -.TP -\fBreadonly\fP [\fB\-aApf\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 indexed arrays; the -.B \-A -option restricts the variables to associative 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\-\-abefhkmnptuvxBCEHPT\fP] [\fB\-o\fP \fIoption\fP] [\fIarg\fP ...] -.PD 0 -.TP -\fBset\fP [\fB+abefhkmnptuvxBCEHPT\fP] [\fB+o\fP \fIoption\fP] [\fIarg\fP ...] -.PD -Without options, the name and value of each shell variable are displayed -in a format that can be reused as input -for setting or resetting the currently-set variables. -Read-only variables cannot be reset. -In \fIposix mode\fP, only shell variables are listed. -The output is sorted according to the current locale. -When options are specified, they set or unset shell attributes. -Any arguments remaining after option processing 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 \fIpipeline\fP (which may consist of a single -\fIsimple command\fP), a \fIsubshell\fP command enclosed in parentheses, -or one of the commands executed as part of a command list enclosed -by braces (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 -.B if -statement, part of any command executed in a -.B && -or -.B \(bv\(bv -list except the command following the final \fB&&\fP or \fB\(bv\(bv\fP, -any command in a pipeline but the last, -or if the command's return value is -being inverted with -.BR ! . -A trap on \fBERR\fP, if set, is executed before the shell exits. -This option applies to the shell environment and each subshell environment -separately (see -.B "COMMAND EXECUTION ENVIRONMENT" -above), and may cause -subshells to exit before executing all the commands in the subshell. -.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. -This also affects the editing interface used for \fBread \-e\fP. -.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 . -.TP 8 -.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 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. -This also affects the editing interface used for \fBread \-e\fP. -.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 -.BR SHELLOPTS , -.BR CDPATH , -and -.B GLOBIGNORE -variables, if they appear in the environment, are 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 traps on \fBDEBUG\fP and \fBRETURN\fP are inherited by shell -functions, command substitutions, and commands executed in a -subshell environment. -The \fBDEBUG\fP and \fBRETURN\fP traps are normally not inherited -in such cases. -.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 autocd -If set, a command name that is the name of a directory is executed as if -it were the argument to the \fBcd\fP command. -This option is only used by interactive shells. -.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 checkjobs -If set, \fBbash\fP lists the status of any stopped and running jobs before -exiting an interactive shell. If any jobs are running, this causes -the exit to be deferred until a second exit is attempted without an -intervening command (see \fBJOB CONTROL\fP above). The shell always -postpones exiting if any jobs are stopped. -.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 compat31 -If set, -.B bash -changes its behavior to that of version 3.1 with respect to quoted -arguments to the conditional command's =~ operator. -.TP 8 -.B dirspell -If set, -.B bash -attempts spelling correction on directory names during word completion -if the directory name initially supplied does not exist. -.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. -.TP -.B 4. -\fBBASH_ARGC\fP and \fBBASH_ARGV\fP are updated as described in their -descriptions above. -.TP -.B 5. -Function tracing is enabled: command substitution, shell functions, and -subshells invoked with \fB(\fP \fIcommand\fP \fB)\fP inherit the -\fBDEBUG\fP and \fBRETURN\fP traps. -.TP -.B 6. -Error tracing is enabled: command substitution, shell functions, and -subshells invoked with \fB(\fP \fIcommand\fP \fB)\fP inherit the -\fBERROR\fP trap. -.RE -.TP 8 -.B extglob -If set, the extended pattern matching features described above under -\fBPathname Expansion\fP are enabled. -.TP 8 -.B extquote -If set, \fB$\fP\(aq\fIstring\fP\(aq and \fB$\fP"\fIstring\fP" quoting is -performed within \fB${\fP\fIparameter\fP\fB}\fP expansions -enclosed in double quotes. This option is enabled by default. -.TP 8 -.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 globstar -If set, the pattern \fB**\fP used in a filename expansion context will -match a files and zero or more directories and subdirectories. -If the pattern is followed by a \fB/\fP, only directories and -subdirectories match. -.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 nocasematch -If set, -.B bash -matches patterns in a case\-insensitive fashion when performing matching -while executing \fBcase\fP or \fB[[\fP conditional commands. -.TP 8 -.B nullglob -If set, -.B bash -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. A login shell cannot be suspended; the -.B \-f -option can be used to override this and force the suspension. -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" . -\fBtest\fP does not accept any options, nor does it accept and ignore -an argument of \fB\-\-\fP as signifying the end of options. -.if t .sp 0.5 -.if n .sp 1 -Expressions may be combined using the following operators, listed -in decreasing order of precedence. -The evaluation depends on the number of arguments; see below. -.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. -The \fB\-a\fP and \fB\-o\fP operators are considered binary operators -when there are three arguments. -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. -.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 \fBextdebug\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 command executed in 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 that are not being ignored 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 all of the arguments are found, false if -any are not found. -.TP -\fBulimit\fP [\fB\-HSTabcdefilmnpqrstuvx\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 by a non-root user 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 \-b -The maximum socket buffer size -.TP -.B \-c -The maximum size of core files created -.TP -.B \-d -The maximum size of a process's data segment -.TP -.B \-e -The maximum scheduling priority ("nice") -.TP -.B \-f -The maximum size of files written by the shell and its children -.TP -.B \-i -The maximum number of pending signals -.TP -.B \-l -The maximum size that may be locked into memory -.TP -.B \-m -The maximum resident set size (many systems do not honor this limit) -.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 \-q -The maximum number of bytes in POSIX message queues -.TP -.B \-r -The maximum real-time scheduling priority -.TP -.B \-s -The maximum stack size -.TP -.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 -.TP -.B \-x -The maximum number of file locks -.TP -.B \-T -The maximum number of threads -.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 -.BR \-T , -.BR \-b , -.BR \-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 specified, 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 each specified process and return its termination status. -Each -.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.ramey@case.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 -Array variables may not (yet) be exported. -.PP -There may be only one active coprocess at a time. -.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.save b/doc/bashref.texi.save deleted file mode 100644 index 093c94d96..000000000 --- a/doc/bashref.texi.save +++ /dev/null @@ -1,7490 +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-2005 Free Software Foundation, Inc. - -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -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.2 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:: What job control is and how Bash allows you - to use it. -* Using History Interactively:: Command History Expansion -* 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 portion of the @sc{ieee} @sc{posix} -specification (@sc{ieee} Standard 1003.1). -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 utilities 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 primarily concerned with the Shell and Utilities portion of the -@sc{posix} 1003.1 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 identifier 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} 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 -(@pxref{History Interaction}), 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{`}, @samp{\}, -and, when history expansion is enabled, @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. -If enabled, history expansion will be performed unless an @samp{!} -appearing in double quotes is escaped using a backslash. -The backslash preceding the @samp{!} is not removed. - -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{The Shopt Builtin}), -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}. -If the shell option @code{nocasematch} -(see the description of @code{shopt} in @ref{The Shopt Builtin}) -is enabled, the match is performed without regard to the case -of alphabetic characters. -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 specified. -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}. -If the shell option @code{nocasematch} -(see the description of @code{shopt} in @ref{The Shopt Builtin}) -is enabled, the match is performed without regard to the case -of alphabetic characters. -The return value is 0 if the string matches (@samp{==}) or does not -match (@samp{!=})the pattern, 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{nocasematch} -(see the description of @code{shopt} in @ref{The Shopt Builtin}) -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. - -A function definition may be deleted using the @option{-f} option to the -@code{unset} builtin (@pxref{Bourne Shell Builtins}). - -The exit status of a function definition is zero unless a syntax error -occurs or a readonly function with the same name already exists. -When executed, the exit status of a function is the exit status of the -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} and @env{RETURN} traps -are 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 @env{DEBUG} and @env{RETURN} traps). -@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. - -In the context where an assignment statement is assigning a value -to a shell variable or array index (@pxref{Arrays}), the @samp{+=} -operator can be used to -append to or add to the variable's previous value. -When @samp{+=} is applied to a variable for which the integer attribute -has been set, @var{value} is evaluated as an arithmetic expression and -added to the variable's current value, which is also evaluated. -When @samp{+=} is applied to an array variable using compound assignment -(@pxref{Arrays}), the -variable's value is not unset (as it is when using @samp{=}), and new -values are appended to the array beginning at one greater than the array's -maximum index. -When applied to a string-valued variable, @var{value} is expanded and -appended to the variable's value. - -@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{}}. -If the double-quoted expansion occurs within a word, the expansion of -the first parameter is joined with the beginning part of the original -word, and the expansion of the last parameter is joined with the last -part of the original word. -When there are no positional parameters, @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 pathname used to invoke the -shell or shell script being executed as passed in the environment -or argument list. -Subsequently, expands to the last argument to the previous command, -after expansion. -Also set to the full pathname used to invoke each command executed -and placed in the environment exported to that command. -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 seqeunce 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 the first @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}]@}}. -A negative @var{offset} is taken relative to one greater than the maximum -index of the specified array. -Note that a negative offset must be separated from the colon by at least -one space to avoid being confused with the @samp{:-} expansion. -Substring indexing is zero-based unless the positional parameters -are used, in which case the indexing starts at 1 by default. -If @var{offset} is 0, and the positional parameters are used, @code{$@@} is -prefixed to the list. - -@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. -When @samp{@@} is used and the expansion appears within double quotes, each -variable name expands to a separate word. - -@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}@} - -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}. -If @var{pattern} begins with @samp{/}, all matches of @var{pattern} are -replaced with @var{string}. Normally only the first match is replaced. -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 sequences of -@code{ }, @code{}, and @code{} -at the beginning and end of the results of the previous -expansions are ignored, and any sequence of @env{IFS} -characters not at the beginning or end 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{The Shopt Builtin}, -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} 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 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. - -Redirections using file descriptors greater than 9 should be used with -care, as they may conflict with file descriptors the shell uses -internally. - -@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} (@pxref{The Shopt Builtin}) - -@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{The Shopt Builtin}), 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. -* Modifying Shell Behavior:: Builtins to modify shell attributes and - optional behavior. -* Special Builtins:: Builtin commands classified specially by - POSIX. -@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 describes the builtins which Bash inherits from -the Bourne Shell, as well as the builtin commands which are unique -to or have been extended in Bash. - -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. -For example, the @code{:}, @code{true}, @code{false}, and @code{test} -builtins do not accept 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} 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 argument 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}. -Parameters represented by the numbers @code{$#} to @code{$#}-@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}. -@code{test} does not accept any options, nor does it accept and ignore -an argument of @option{--} as signifying the end of options. - -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{The Shopt Builtin}) 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 that are not being ignored 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} 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 -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{The Shopt Builtin}), 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} and @code{RETURN} traps 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, -with the exceptions that @samp{+a} -may not be used to destroy an array variable and @samp{+r} will not -remove the readonly attribute. -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} does not interpret @option{--} to mean the end of options. - -@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 \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 [-a] [-dnps] [-f @var{filename}] [@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} [-v @var{var}] @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 @option{-v} option causes the output to be assigned to the variable -@var{var} rather than being printed to the standard output. - -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 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 [-acdefilmnpqrstuvxSH] [@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 -e -The maximum scheduling priority ("nice"). - -@item -f -The maximum size of files written by the shell and its children. - -@item -i -The maximum number of pending signals. - -@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 -q -The maximum number of bytes in POSIX message queues. - -@item -r -The maximum real-time scheduling priority. - -@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. - -@item -x -The maximum number of file locks. - -@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 Modifying Shell Behavior -@section Modifying Shell Behavior - -@menu -* The Set Builtin:: Change the values of shell attributes and - positional parameters. -* The Shopt Builtin:: Modify shell optional behavior. -@end menu - -@node The Set Builtin -@subsection The Set Builtin - -This builtin is so complicated that it deserves its own section. @code{set} -allows you to change the values of shell options and set the positional -parameters, or to display the names and values of shell variables. - -@table @code -@item set -@btindex set -@example -set [--abefhkmnptuvxBCEHPT] [-o @var{option}] [@var{argument} @dots{}] -set [+abefhkmnptuvxBCEHPT] [+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 -for setting or resetting the currently-set variables. -Read-only variables cannot be reset. -In @sc{posix} mode, only shell variables are listed. - -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, -any command in a pipeline but the last, -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} 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, @code{for} commands, @code{case} -commands, @code{select} commands, and arithmetic @code{for} commands -and their arguments or associated word lists after they are -expanded and before they are executed. The value of the @env{PS4} -variable is expanded and the resultant value is printed before -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} and @code{RETURN} are inherited by -shell functions, command substitutions, and commands executed -in a subshell environment. -The @code{DEBUG} and @code{RETURN} traps are 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 The Shopt Builtin -@subsection The Shopt Builtin - -This builtin allows you to change additional shell optional behavior. - -@table @code - -@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 autocd -If set, a command name that is the name of a directory is executed as if -it were the argument to the @code{cd} command. -This option is only used by interactive shells. - -@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 checkjobs -If set, Bash lists the status of any stopped and running jobs before -exiting an interactive shell. If any jobs are running, this causes -the exit to be deferred until a second exit is attempted without an -intervening command (@pxref{Job Control}). -The shell always postpones exiting if any jobs are stopped. - -@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. - -@item -@code{BASH_ARGC} and @code{BASH_ARGV} are updated as described in their -descriptions (@pxref{Bash Variables}). - -@item -Function tracing is enabled: command substitution, shell functions, and -subshells invoked with @code{( @var{command} )} inherit the -@code{DEBUG} and @code{RETURN} traps. - -@item -Error tracing is enabled: command substitution, shell functions, and -subshells invoked with @code{( @var{command} )} inherit the -@code{ERROR} trap. -@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 nocasematch -If set, Bash matches patterns in a case-insensitive fashion when -performing matching while executing @code{case} or @code{[[} -conditional commands. - -@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. - -@end table - -@node Special Builtins -@section Special Builtins -@cindex special builtin - -For historical reasons, the @sc{posix} 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 BASHPID -Expands to the process id of the current Bash process. -This differs from @code{$$} under certain circumstances, such as subshells -that do not require Bash to be re-initialized. - -@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}. -The shell sets @code{BASH_ARGC} only when in extended debugging mode -(see @ref{The Shopt Builtin} -for a description of the @code{extdebug} option to the @code{shopt} -builtin). - -@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}. -The shell sets @code{BASH_ARGV} only when in extended debugging mode -(see @ref{The Shopt Builtin} -for a description of the @code{extdebug} option to the @code{shopt} -builtin). - -@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]@}} was called. -The corresponding source file name is @code{$@{BASH_SOURCE[$i]@}}. -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_TYPE -Set to an integer value corresponding to the type of completion attempted -that caused a completion function to be called: -@var{TAB}, for normal completion, -@samp{?}, for listing completions after successive tabs, -@samp{!}, for listing alternatives on partial word completion, -@samp{@@}, to list completions if the word is not unmodified, -or -@samp{%}, for menu completion. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMP_KEY -The key (or final key of a key sequence) used to invoke the current -completion function. - -@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. -The words are split on shell metacharacters as the shell parser would -separate them. -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 @code{"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, by removing the oldest entries, -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 interactive 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 TMPDIR -If set, Bash uses its value as the name of a directory in which -Bash creates temporary files for the shell's use. - -@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{The Shopt Builtin} -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 output -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 successfully. - -@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} 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 output. -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{The Shopt Builtin}). -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 describes 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 specifying the @option{-c} option, and -whose input and error 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{huponexit} 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{The Shopt Builtin}). - -@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. - -Unless otherwise specified, primaries that operate on files follow symbolic -links and operate on the target of the link, rather than the link itself. - -@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 interchangeably 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{The Shopt Builtin}). - -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. -If the double-quoted expansion occurs within a word, the expansion of -the first parameter is joined with the beginning part of the original -word, and the expansion of the last parameter is joined with the last -part of the original word. -This is analogous to the -expansion 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}. -Care must be taken to avoid unwanted side effects caused by filename -generation. -@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 [-n] [@var{+N} | @var{-N} | @var{dir} ] -@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 -n -Suppresses the normal change of directory when adding directories -to the stack, so that only the stack is manipulated. -@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 @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} 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 -The @code{bg} builtin uses the required format to describe each job placed -in the background, which does not include an indication of whether the job -is the current or previous job. - -@item -Reserved words appearing in a context where reserved words are recognized -do not undergo alias expansion. - -@item -The @sc{posix} @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} 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} special builtins are found before shell functions -during command lookup. - -@item -If a @sc{posix} special builtin returns an error status, a -non-interactive shell exits. The fatal errors are those listed in -the POSIX standard, and include things like passing incorrect options, -redirection errors, variable assignment errors for assignments preceding -the command name, and so on. - -@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} 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}. - -@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, unless that argument consists solely of digits and -is a valid signal number. 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. - -@item -When the @code{pwd} builtin is supplied the @option{-P} option, it resets -@code{$PWD} to a pathname containing no symlinks. - -@item -The @code{pwd} builtin verifies that the value it prints is the same as the -current directory, even if it is not asked to check the file system with the -@option{-P} option. - -@item -When listing the history, the @code{fc} builtin does not include an -indication of whether or not a history entry has been modified. - -@item -The default editor used by @code{fc} is @code{ed}. - -@item -The @code{type} and @code{command} builtins will not report a non-executable -file as having been found, though the shell will attempt to execute such a -file if it is the only so-named file found in @code{$PATH}. - -@item -The @code{vi} editing mode will invoke the @code{vi} editor directly when -the @samp{v} command is run, instead of checking @code{$FCEDIT} and -@code{$EDITOR}. - -@item -When the @code{xpg_echo} option is enabled, Bash does not attempt to interpret -any arguments to @code{echo} as options. Each argument is displayed, after -escape characters are converted. - -@end enumerate - -There is other @sc{posix} behavior that Bash does not implement by -default even when in @sc{posix} mode. -Specifically: - -@enumerate - -@item -The @code{fc} builtin checks @code{$EDITOR} as a program to edit history -entries if @code{FCEDIT} is unset, rather than defaulting directly to -@code{ed}. @code{fc} uses @code{ed} if @code{EDITOR} is unset. - -@item -As noted above, Bash requires the @code{xpg_echo} option to be enabled for -the @code{echo} builtin to be fully conformant. - -@end enumerate - -Bash can be configured to be @sc{posix}-conformant by default, by specifying -the @option{--enable-strict-posix-default} to @code{configure} when building -(@pxref{Optional Features}). - -@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. -A single @samp{%} (with no accompanying job specification) also refers -to the current job. -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, (or running, if -the @code{checkjobs} option is enabled -- see @ref{The Shopt Builtin}), the -shell prints a warning message, and if the @code{checkjobs} option is -enabled, lists the jobs and their statuses. -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 any stopped jobs are terminated. - -@node Job Control Builtins -@section Job Control Builtins - -@table @code - -@item bg -@btindex bg -@example -bg [@var{jobspec} @dots{}] -@end example -Resume each 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, any -@var{jobspec} was not found or 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 each 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 the directory @file{lib/malloc}. This is not the same -@code{malloc} that appears in @sc{gnu} libc, but an older version -originally 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 5.0 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-debugger -Include support for the bash debugger (distributed separately). - -@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-progcomp -Enable the programmable completion facilities -(@pxref{Programmable Completion}). -If Readline is not enabled, this option has no effect. - -@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-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-separate-helpfiles -Use external files for the documentation displayed by the @code{help} builtin -instead of storing the text internally. - -@item --enable-single-help-strings -Store the text displayed by the @code{help} builtin as a single string for -each help topic. This aids in translating the text to different languages. -You may need to disable this if your compiler cannot handle very long string -literals. - -@item --enable-strict-posix-default -Make Bash @sc{posix}-conformant by default (@pxref{Bash POSIX Mode}). - -@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 3. -@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} 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 (the -last version of the historical Bourne shell) 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. -The Bash @samp{-o pipefail} option to @code{set} will cause a pipeline to -return a failure status if any command 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}), including -optional regular expression matching. - -@item -Bash provides optional case-insensitive matching for the @code{case} and -@code{[[} 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 supports the @samp{+=} assignment operator, which appends to the value -of the variable named on the left hand side. - -@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} 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 includes the @samp{<<<} redirection operator, allowing a string to -be used as the standard input to a command. - -@item -Bash implements the @samp{[n]<&@var{word}} and @samp{[n]>&@var{word}} -redirection operators, which move one file descriptor to another. - -@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{The Shopt Builtin}), 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 unless the -function has been given the @code{trace} attribute or the -@code{functrace} option has been enabled using the @code{shopt} builtin. - -@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 -Bash includes a number of features to support a separate debugger for -shell scripts. - -@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} special builtins fails, and -only for certain failures, as enumerated in the @sc{posix} 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.save1 b/doc/bashref.texi.save1 deleted file mode 100644 index 3424599dc..000000000 --- a/doc/bashref.texi.save1 +++ /dev/null @@ -1,7445 +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-2005 Free Software Foundation, Inc. - -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -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.2 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:: What job control is and how Bash allows you - to use it. -* Using History Interactively:: Command History Expansion -* 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 portion of the @sc{ieee} @sc{posix} -specification (@sc{ieee} Standard 1003.1). -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 utilities 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 primarily concerned with the Shell and Utilities portion of the -@sc{posix} 1003.1 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 identifier 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} 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 -(@pxref{History Interaction}), 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{`}, @samp{\}, -and, when history expansion is enabled, @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. -If enabled, history expansion will be performed unless an @samp{!} -appearing in double quotes is escaped using a backslash. -The backslash preceding the @samp{!} is not removed. - -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{The Shopt Builtin}), -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}. -If the shell option @code{nocasematch} -(see the description of @code{shopt} in @ref{The Shopt Builtin}) -is enabled, the match is performed without regard to the case -of alphabetic characters. -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 specified. -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}. -If the shell option @code{nocasematch} -(see the description of @code{shopt} in @ref{The Shopt Builtin}) -is enabled, the match is performed without regard to the case -of alphabetic characters. -The return value is 0 if the string matches (@samp{==}) or does not -match (@samp{!=})the pattern, 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{nocasematch} -(see the description of @code{shopt} in @ref{The Shopt Builtin}) -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. - -A function definition may be deleted using the @option{-f} option to the -@code{unset} builtin (@pxref{Bourne Shell Builtins}). - -The exit status of a function definition is zero unless a syntax error -occurs or a readonly function with the same name already exists. -When executed, the exit status of a function is the exit status of the -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} and @env{RETURN} traps -are 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 @env{DEBUG} and @env{RETURN} traps). -@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. - -In the context where an assignment statement is assigning a value -to a shell variable or array index (@pxref{Arrays}), the @samp{+=} -operator can be used to -append to or add to the variable's previous value. -When @samp{+=} is applied to a variable for which the integer attribute -has been set, @var{value} is evaluated as an arithmetic expression and -added to the variable's current value, which is also evaluated. -When @samp{+=} is applied to an array variable using compound assignment -(@pxref{Arrays}), the -variable's value is not unset (as it is when using @samp{=}), and new -values are appended to the array beginning at one greater than the array's -maximum index. -When applied to a string-valued variable, @var{value} is expanded and -appended to the variable's value. - -@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{}}. -If the double-quoted expansion occurs within a word, the expansion of -the first parameter is joined with the beginning part of the original -word, and the expansion of the last parameter is joined with the last -part of the original word. -When there are no positional parameters, @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 pathname used to invoke the -shell or shell script being executed as passed in the environment -or argument list. -Subsequently, expands to the last argument to the previous command, -after expansion. -Also set to the full pathname used to invoke each command executed -and placed in the environment exported to that command. -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 seqeunce 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 the first @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}]@}}. -A negative @var{offset} is taken relative to one greater than the maximum -index of the specified array. -Note that a negative offset must be separated from the colon by at least -one space to avoid being confused with the @samp{:-} expansion. -Substring indexing is zero-based unless the positional parameters -are used, in which case the indexing starts at 1 by default. -If @var{offset} is 0, and the positional parameters are used, @code{$@@} is -prefixed to the list. - -@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. -When @samp{@@} is used and the expansion appears within double quotes, each -variable name expands to a separate word. - -@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}@} - -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}. -If @var{pattern} begins with @samp{/}, all matches of @var{pattern} are -replaced with @var{string}. Normally only the first match is replaced. -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 sequences of -@code{ }, @code{}, and @code{} -at the beginning and end of the results of the previous -expansions are ignored, and any sequence of @env{IFS} -characters not at the beginning or end 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{The Shopt Builtin}, -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} 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 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. - -Redirections using file descriptors greater than 9 should be used with -care, as they may conflict with file descriptors the shell uses -internally. - -@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} (@pxref{The Shopt Builtin}) - -@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{The Shopt Builtin}), 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:: Change the values of shell attributes and - positional parameters. -* The Shopt Builtin:: Modify shell optional behavior. -* Special Builtins:: Builtin commands classified specially by - POSIX. -@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 describes the builtins which Bash inherits from -the Bourne Shell, as well as the builtin commands which are unique -to or have been extended in Bash. - -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. -For example, the @code{:}, @code{true}, @code{false}, and @code{test} -builtins do not accept 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} 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 argument 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}. -@code{test} does not accept any options, nor does it accept and ignore -an argument of @option{--} as signifying the end of options. - -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{The Shopt Builtin}) 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 that are not being ignored 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} 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 -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{The Shopt Builtin}), 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} and @code{RETURN} traps 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, -with the exceptions that @samp{+a} -may not be used to destroy an array variable and @samp{+r} will not -remove the readonly attribute. -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} does not interpret @option{--} to mean the end of options. - -@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 \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 [-a] [-dnps] [-f @var{filename}] [@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} [-v @var{var}] @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 @option{-v} option causes the output to be assigned to the variable -@var{var} rather than being printed to the standard output. - -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 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 [-acdefilmnpqrstuvxSH] [@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 -e -The maximum scheduling priority ("nice"). - -@item -f -The maximum size of files written by the shell and its children. - -@item -i -The maximum number of pending signals. - -@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 -q -The maximum number of bytes in POSIX message queues. - -@item -r -The maximum real-time scheduling priority. - -@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. - -@item -x -The maximum number of file locks. - -@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. @code{set} -allows you to change the values of shell options and set the positional -parameters, or to display the names and values of shell variables. - -@table @code -@item set -@btindex set -@example -set [--abefhkmnptuvxBCEHPT] [-o @var{option}] [@var{argument} @dots{}] -set [+abefhkmnptuvxBCEHPT] [+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 -for setting or resetting the currently-set variables. -Read-only variables cannot be reset. -In @sc{posix} mode, only shell variables are listed. - -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, -any command in a pipeline but the last, -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} 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, @code{for} commands, @code{case} -commands, @code{select} commands, and arithmetic @code{for} commands -and their arguments or associated word lists after they are -expanded and before they are executed. The value of the @env{PS4} -variable is expanded and the resultant value is printed before -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} and @code{RETURN} are inherited by -shell functions, command substitutions, and commands executed -in a subshell environment. -The @code{DEBUG} and @code{RETURN} traps are 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 The Shopt Builtin -@section The Shopt Builtin - -This builtin allows you to change additional shell optional behavior. - -@table @code - -@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. - -@item -@code{BASH_ARGC} and @code{BASH_ARGV} are updated as described in their -descriptions (@pxref{Bash Variables}). - -@item -Function tracing is enabled: command substitution, shell functions, and -subshells invoked with @code{( @var{command} )} inherit the -@code{DEBUG} and @code{RETURN} traps. - -@item -Error tracing is enabled: command substitution, shell functions, and -subshells invoked with @code{( @var{command} )} inherit the -@code{ERROR} trap. -@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 nocasematch -If set, Bash matches patterns in a case-insensitive fashion when -performing matching while executing @code{case} or @code{[[} -conditional commands. - -@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. - -@end table - -@node Special Builtins -@section Special Builtins -@cindex special builtin - -For historical reasons, the @sc{posix} 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}. -The shell sets @code{BASH_ARGC} only when in extended debugging mode -(see @ref{The Shopt Builtin} -for a description of the @code{extdebug} option to the @code{shopt} -builtin). - -@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}. -The shell sets @code{BASH_ARGV} only when in extended debugging mode -(see @ref{The Shopt Builtin} -for a description of the @code{extdebug} option to the @code{shopt} -builtin). - -@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]@}} was called. -The corresponding source file name is @code{$@{BASH_SOURCE[$i]@}}. -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. -The words are split on shell metacharacters as the shell parser would -separate them. -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 @code{"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, by removing the oldest entries, -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 interactive 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 TMPDIR -If set, Bash uses its value as the name of a directory in which -Bash creates temporary files for the shell's use. - -@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{The Shopt Builtin} -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 output -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 successfully. - -@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} 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 output. -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{The Shopt Builtin}). -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 describes 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 specifying the @option{-c} option, and -whose input and error 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{huponexit} 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{The Shopt Builtin}). - -@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. - -Unless otherwise specified, primaries that operate on files follow symbolic -links and operate on the target of the link, rather than the link itself. - -@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 interchangeably 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{The Shopt Builtin}). - -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. -If the double-quoted expansion occurs within a word, the expansion of -the first parameter is joined with the beginning part of the original -word, and the expansion of the last parameter is joined with the last -part of the original word. -This is analogous to the -expansion 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}. -Care must be taken to avoid unwanted side effects caused by filename -generation. -@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 [-n] [@var{+N} | @var{-N} | @var{dir} ] -@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 -n -Suppresses the normal change of directory when adding directories -to the stack, so that only the stack is manipulated. -@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 @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} 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 -The @code{bg} builtin uses the required format to describe each job placed -in the background, which does not include an indication of whether the job -is the current or previous job. - -@item -Reserved words appearing in a context where reserved words are recognized -do not undergo alias expansion. - -@item -The @sc{posix} @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} 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} special builtins are found before shell functions -during command lookup. - -@item -If a @sc{posix} special builtin returns an error status, a -non-interactive shell exits. The fatal errors are those listed in -the POSIX standard, and include things like passing incorrect options, -redirection errors, variable assignment errors for assignments preceding -the command name, and so on. - -@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} 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}. - -@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, unless that argument consists solely of digits and -is a valid signal number. 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. - -@item -When the @code{pwd} builtin is supplied the @option{-P} option, it resets -@code{$PWD} to a pathname containing no symlinks. - -@item -The @code{pwd} builtin verifies that the value it prints is the same as the -current directory, even if it is not asked to check the file system with the -@option{-P} option. - -@item -When listing the history, the @code{fc} builtin does not include an -indication of whether or not a history entry has been modified. - -@item -The default editor used by @code{fc} is @code{ed}. - -@item -The @code{type} and @code{command} builtins will not report a non-executable -file as having been found, though the shell will attempt to execute such a -file if it is the only so-named file found in @code{$PATH}. - -@item -The @code{vi} editing mode will invoke the @code{vi} editor directly when -the @samp{v} command is run, instead of checking @code{$FCEDIT} and -@code{$EDITOR}. - -@item -When the @code{xpg_echo} option is enabled, Bash does not attempt to interpret -any arguments to @code{echo} as options. Each argument is displayed, after -escape characters are converted. - -@end enumerate - -There is other @sc{posix} behavior that Bash does not implement by -default even when in @sc{posix} mode. -Specifically: - -@enumerate - -@item -The @code{fc} builtin checks @code{$EDITOR} as a program to edit history -entries if @code{FCEDIT} is unset, rather than defaulting directly to -@code{ed}. @code{fc} uses @code{ed} if @code{EDITOR} is unset. - -@item -As noted above, Bash requires the @code{xpg_echo} option to be enabled for -the @code{echo} builtin to be fully conformant. - -@end enumerate - -Bash can be configured to be @sc{posix}-conformant by default, by specifying -the @option{--enable-strict-posix-default} to @code{configure} when building -(@pxref{Optional Features}). - -@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. -A single @samp{%} (with no accompanying job specification) also refers -to the current job. -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} @dots{}] -@end example -Resume each 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, any -@var{jobspec} was not found or 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 each 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 the directory @file{lib/malloc}. This is not the same -@code{malloc} that appears in @sc{gnu} libc, but an older version -originally 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 5.0 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-debugger -Include support for the bash debugger (distributed separately). - -@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-progcomp -Enable the programmable completion facilities -(@pxref{Programmable Completion}). -If Readline is not enabled, this option has no effect. - -@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-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-separate-helpfiles -Use external files for the documentation displayed by the @code{help} builtin -instead of storing the text internally. - -@item --enable-single-help-strings -Store the text displayed by the @code{help} builtin as a single string for -each help topic. This aids in translating the text to different languages. -You may need to disable this if your compiler cannot handle very long string -literals. - -@item --enable-strict-posix-default -Make Bash @sc{posix}-conformant by default (@pxref{Bash POSIX Mode}). - -@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 3. -@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} 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 (the -last version of the historical Bourne shell) 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. -The Bash @samp{-o pipefail} option to @code{set} will cause a pipeline to -return a failure status if any command 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}), including -optional regular expression matching. - -@item -Bash provides optional case-insensitive matching for the @code{case} and -@code{[[} 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 supports the @samp{+=} assignment operator, which appends to the value -of the variable named on the left hand side. - -@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} 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 includes the @samp{<<<} redirection operator, allowing a string to -be used as the standard input to a command. - -@item -Bash implements the @samp{[n]<&@var{word}} and @samp{[n]>&@var{word}} -redirection operators, which move one file descriptor to another. - -@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{The Shopt Builtin}), 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 unless the -function has been given the @code{trace} attribute or the -@code{functrace} option has been enabled using the @code{shopt} builtin. - -@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 -Bash includes a number of features to support a separate debugger for -shell scripts. - -@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} special builtins fails, and -only for certain failures, as enumerated in the @sc{posix} 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 4f1709a09..000000000 --- a/doc/bashref.texi~ +++ /dev/null @@ -1,7851 +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--2009 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.2 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 are free to copy and modify -this GNU manual. Buying copies from GNU Press supports the FSF in -developing GNU and promoting software freedom.'' - -@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:: What job control is and how Bash allows you - to use it. -* Command Line Editing:: Chapter describing the command line - editing features. -* Using History Interactively:: Command History Expansion -* 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. -* GNU Free Documentation License:: Copying and sharing this documentation. -* Indexes:: Various indexes for 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 portion of the @sc{ieee} @sc{posix} -specification (@sc{ieee} Standard 1003.1). -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 utilities 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 primarily concerned with the Shell and Utilities portion of the -@sc{posix} 1003.1 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{token} that performs a control function. It is a @code{newline} -or one of the following: -@samp{||}, @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. -Operators contain at least one unquoted @code{metacharacter}. - -@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 identifier 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} 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 sequence of characters treated as a unit by the shell. -Words may not include unquoted @code{metacharacters}. -@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 -(@pxref{History Interaction}), 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{`}, @samp{\}, -and, when history expansion is enabled, @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. -If enabled, history expansion will be performed unless an @samp{!} -appearing in double quotes is escaped using a backslash. -The backslash preceding the @samp{!} is not removed. - -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{The Shopt Builtin}), -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. -* Coprocesses:: Two-way communication between 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 one of -the control operators @samp{|} or @samp{|&}. - -@rwindex time -@rwindex ! -@cindex command timing -The format for a pipeline is -@example -[@code{time} [@code{-p}]] [@code{!}] @var{command1} [ [@code{|} or @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. This -connection is performed before any redirections specified by the -command. - -If @samp{|&} is used, the standard error of @var{command1} is connected to -@var{command2}'s standard input through the pipe; it is shorthand for -@code{2>&1 |}. This implicit redirection of the standard error is -performed after any redirections specified by the command. - -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. - -@sc{and} and @sc{or} lists are sequences of one or more pipelines -separated by the control operators @samp{&&} and @samp{||}, -respectively. @sc{and} and @sc{or} lists are executed with left -associativity. - -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}. -If the shell option @code{nocasematch} -(see the description of @code{shopt} in @ref{The Shopt Builtin}) -is enabled, the match is performed without regard to the case -of alphabetic characters. -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{;;}, @samp{,&}, or @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{;;}, @samp{;&}, or @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 - -If the @samp{;;} operator is used, no subsequent matches are attempted after -the first pattern match. -Using @samp{;&} in place of @samp{;;} causes execution to continue with -the @var{command-list} associated with the next clause, if any. -Using @samp{;;&} in place of @samp{;;} causes the shell to test the patterns -in the next clause, if any, and execute any associated @var{command-list} -on a successful match. - -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 specified. -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}. -If the shell option @code{nocasematch} -(see the description of @code{shopt} in @ref{The Shopt Builtin}) -is enabled, the match is performed without regard to the case -of alphabetic characters. -The return value is 0 if the string matches (@samp{==}) or does not -match (@samp{!=})the pattern, 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{nocasematch} -(see the description of @code{shopt} in @ref{The Shopt Builtin}) -is enabled, the match is performed without regard to the case -of alphabetic characters. -Any part of the pattern may be quoted to force it to be matched as a -string. -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 or other shell metacharacters. -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 Coprocesses -@subsection Coprocesses -@cindex coprocess - -A @code{coprocess} is a shell command preceded by the @code{coproc} -reserved word. -A coprocess is executed asynchronously in a subshell, as if the command -had been terminated with the @samp{&} control operator, with a two-way pipe -established between the executing shell and the coprocess. - -The format for a coprocess is: -@example -@code{coproc} [@var{NAME}] @var{command} [@var{redirections}] -@end example - -@noindent -This creates a coprocess named @var{NAME}. -If @var{NAME} is not supplied, the default name is @var{COPROC}. -@var{NAME} must not be supplied if @var{command} is a simple -command (@pxref{Simple Commands}); otherwise, it is interpreted as -the first word of the simple command. - -When the coproc is executed, the shell creates an array variable -(@pxref{Arrays}) -named @var{NAME} in the context of the executing shell. -The standard output of @var{command} -is connected via a pipe to a file descriptor in the executing shell, -and that file descriptor is assigned to @var{NAME}[0]. -The standard input of @var{command} -is connected via a pipe to a file descriptor in the executing shell, -and that file descriptor is assigned to @var{NAME}[1]. -This pipe is established before any redirections specified by the -command (@pxref{Redirections}). -The file descriptors can be utilized as arguments to shell commands -and redirections using standard word expansions. - -The process id of the shell spawned to execute the coprocess is -available as the value of the variable @var{NAME}_PID. -The @code{wait} -builtin command may be used to wait for the coprocess to terminate. - -The return status of a coprocess is the exit status of @var{command}. - -@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. - -A function definition may be deleted using the @option{-f} option to the -@code{unset} builtin (@pxref{Bourne Shell Builtins}). - -The exit status of a function definition is zero unless a syntax error -occurs or a readonly function with the same name already exists. -When executed, the exit status of a function is the exit status of the -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 from the command list -by whitespace or another shell metacharacter. -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} and @env{RETURN} traps -are 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 @env{DEBUG} and @env{RETURN} traps). -@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. - -In the context where an assignment statement is assigning a value -to a shell variable or array index (@pxref{Arrays}), the @samp{+=} -operator can be used to -append to or add to the variable's previous value. -When @samp{+=} is applied to a variable for which the integer attribute -has been set, @var{value} is evaluated as an arithmetic expression and -added to the variable's current value, which is also evaluated. -When @samp{+=} is applied to an array variable using compound assignment -(@pxref{Arrays}), the -variable's value is not unset (as it is when using @samp{=}), and new -values are appended to the array beginning at one greater than the array's -maximum index (for indexed arrays), or added as additional key-value pairs -in an associative array. -When applied to a string-valued variable, @var{value} is expanded and -appended to the variable's value. - -@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{}}. -If the double-quoted expansion occurs within a word, the expansion of -the first parameter is joined with the beginning part of the original -word, and the expansion of the last parameter is joined with the last -part of the original word. -When there are no positional parameters, @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 pathname used to invoke the -shell or shell script being executed as passed in the environment -or argument list. -Subsequently, expands to the last argument to the previous command, -after expansion. -Also set to the full pathname used to invoke each command executed -and placed in the environment exported to that command. -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 seqeunce 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}[@var{incr}]@}}, -where @var{x} and @var{y} are either integers or single characters, -and @var{incr}, an optional increment, is an integer. -When integers are supplied, the expression expands to each number between -@var{x} and @var{y}, inclusive. -Supplied integers may be prefixed with @samp{0} to force each term to have the -same width. When either @var{x} or @var{y} begins with a zero, the shell -attempts to force all generated terms to contain the same number of digits, -zero-padding where necessary. -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. -When the increment is supplied, it is used as the difference between -each term. The default increment is 1 or -1 as appropriate. - -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 the first @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, using the form described -below, 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 @var{parameter}'s existence and that its 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 indexed array name subscripted -by @samp{@@} or @samp{*}, the result is the @var{length} -members of the array beginning with @code{$@{@var{parameter}[@var{offset}]@}}. -A negative @var{offset} is taken relative to one greater than the maximum -index of the specified array. -Substring expansion applied to an associative array produces undefined -results. - -Note that a negative offset must be separated from the colon by at least -one space to avoid being confused with the @samp{:-} expansion. -Substring indexing is zero-based unless the positional parameters -are used, in which case the indexing starts at 1 by default. -If @var{offset} is 0, and the positional parameters are used, @code{$@@} is -prefixed to the list. - -@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. -When @samp{@@} is used and the expansion appears within double quotes, each -variable name expands to a separate word. - -@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}@} - -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}. -If @var{pattern} begins with @samp{/}, all matches of @var{pattern} are -replaced with @var{string}. Normally only the first match is replaced. -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. - -@item $@{@var{parameter}^@var{pattern}@} -@itemx $@{@var{parameter}^^@var{pattern}@} -@itemx $@{@var{parameter},@var{pattern}@} -@itemx $@{@var{parameter},,@var{pattern}@} -This expansion modifies the case of alphabetic characters in @var{parameter}. -The @var{pattern} is expanded to produce a pattern just as in -pathname expansion. -The @samp{^} operator converts lowercase letters matching @var{pattern} -to uppercase; the @samp{,} operator converts matching uppercase letters -to lowercase. -The @samp{^^} and @samp{,,} expansions convert each matched character in the -expanded value; the @samp{^} and @samp{,} expansions match and convert only -the first character in the expanded value. -If @var{pattern} is omitted, it is treated like a @samp{?}, which matches -every character. -If @var{parameter} is @samp{@@} or @samp{*}, -the case modification 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 case modification 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 sequences of -@code{ }, @code{}, and @code{} -at the beginning and end of the results of the previous -expansions are ignored, and any sequence of @env{IFS} -characters not at the beginning or end 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{The Shopt Builtin}, -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. -When the @code{globstar} shell option is enabled, and @samp{*} is used in -a filename expansion context, two adjacent @samp{*}s used as a single -pattern will match all files and zero or more directories and -subdirectories. -If followed by a @samp{/}, two adjacent @samp{*}s will match only -directories and subdirectories. -@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} 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 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 made a copy of the 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. - -Redirections using file descriptors greater than 9 should be used with -care, as they may conflict with file descriptors the shell uses -internally. - -@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 -This construct 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}. - -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 Appending Standard Output and Standard Error -This construct allows both the -standard output (file descriptor 1) and -the standard error output (file descriptor 2) -to be appended to the file whose name is the -expansion of @var{word}. - -The format for appending standard output and standard error is: -@example -&>>@var{word} -@end example -@noindent -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 searches for a defined shell -function named @code{command_not_found_handle}. -If that function exists, it is invoked with the original command and -the original command's arguments as its arguments, and the function's -exit status becomes the exit status of the shell. -If that function is not defined, 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} (@pxref{The Shopt Builtin}) - -@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. - -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. - -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 - -The exit status of an executed command is the value returned by the -@var{waitpid} system call or equivalent function. Exit statuses -fall between 0 and 255, though, as explained below, the shell may -use values above 125 specially. Exit statuses from shell builtins and -compound commands are also limited to this range. Under certain -circumstances, the shell will use special values to indicate specific -failure modes. - -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{The Shopt Builtin}), 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. -* Modifying Shell Behavior:: Builtins to modify shell attributes and - optional behavior. -* Special Builtins:: Builtin commands classified specially by - POSIX. -@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 describes the builtins which Bash inherits from -the Bourne Shell, as well as the builtin commands which are unique -to or have been extended in Bash. - -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. -For example, the @code{:}, @code{true}, @code{false}, and @code{test} -builtins do not accept 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} 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 argument 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 [-aApf] [@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 indexed -array variable; the @option{-A} option means each @var{name} refers -to an associative 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}. -Parameters represented by the numbers @code{$#} to @code{$#}-@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}. -@code{test} does not accept any options, nor does it accept and ignore -an argument of @option{--} as signifying the end of options. - -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. -The evaluation depends on the number of arguments; see below. - -@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. -The @samp{-a} and @samp{-o} operators are considered binary operators -when there are three arguments. -If the first argument is @samp{!}, the value is the negation of -the two-argument test using the second and third arguments. -If the 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. - -@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{The Shopt Builtin}) 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 command executed in 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 that are not being ignored 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} 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 -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. -When @var{shell-command} is executed, the shell sets the -@code{READLINE_LINE} variable to the contents of the Readline line -buffer and the @code{READLINE_POINT} variable to the current location -of the insertion point. -If the executed command changes the value of @code{READLINE_LINE} or -@code{READLINE_POINT}, those new values will be reflected in the -editing state. -@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 [-aAfFilrtux] [-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 with @var{name} arguments, additional options -are ignored. - -When @option{-p} is supplied without @var{name} arguments, @code{declare} -will display the attributes and values of all variables having the -attributes specified by the additional options. -If no other options are supplied with @option{-p}, @code{declare} will -display the attributes and values of all shell variables. The @option{-f} -option will restrict the display to shell functions. - -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{The Shopt Builtin}), 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 indexed array variable (@pxref{Arrays}). - -@item -A -Each @var{name} is an associative 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 -l -When the variable is assigned a value, all upper-case characters are -converted to lower-case. -The upper-case attribute is disabled. - -@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} and @code{RETURN} traps from -the calling shell. -The trace attribute has no special meaning for variables. - -@item -u -When the variable is assigned a value, all lower-case characters are -converted to upper-case. -The lower-case attribute is disabled. - -@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, -with the exceptions that @samp{+a} -may not be used to destroy an array variable and @samp{+r} will not -remove the readonly attribute. -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} does not interpret @option{--} to mean the end of options. - -@code{echo} interprets the following escape sequences: -@table @code -@item \a -alert (bell) -@item \b -backspace -@item \c -suppress further output -@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 \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 [-a] [-dnps] [-f @var{filename}] [@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 [-dms] [@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. - -Options, if supplied, have the following meanings: - -@table @code -@item -d -Display a short description of each @var{pattern} -@item -m -Display the description of each @var{pattern} in a manpage-like format -@item -s -Display only a short usage synopsis for each @var{pattern} -@end table - -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 mapfile -@btindex mapfile -@example -mapfile [-n @var{count}] [-O @var{origin}] [-s @var{count}] [-t] [-u @var{fd}] [ --C @var{callback}] [-c @var{quantum}] [@var{array}] -@end example -Read lines from the standard input into array variable @var{array}, -or from file descriptor @var{fd} -if the @option{-u} option is supplied. -The variable @code{MAPFILE} is the default @var{array}. -Options, if supplied, have the following meanings: -@table @code - -@item -n -Copy at most @var{count} lines. If @var{count} is 0, all lines are copied. -@item -O -Begin assigning to @var{array} at index @var{origin}. -The default index is 0. -@item -s -Discard the first @var{count} lines read. -@item -t -Remove a trailing line from each line read. -@item -u -Read lines from file descriptor @var{fd} instead of the standard input. -@item -C -Evaluate @var{callback} each time @var{quantum}P lines are read. -The @option{-c} option specifies @var{quantum}. -@item -c -Specify the number of lines read between each call to @var{callback}. -@end table - -If @option{-C} is specified without @option{-c}, -the default quantum is 5000. -When @var{callback} is evaluated, it is supplied the index of the next -array element to be assigned as an additional argument. -@var{callback} is evaluated after the line is read but before the -array element is assigned. - -If not supplied with an explicit origin, @code{mapfile} will clear @var{array} -before assigning to it. - -@code{mapfile} returns successfully unless an invalid option or option -argument is supplied, or @var{array} is invalid or unassignable. - -@item printf -@btindex printf -@example -printf [-v @var{var}] @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 @option{-v} option causes the output to be assigned to the variable -@var{var} rather than being printed to the standard output. - -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}] [-i @var{text}] [-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 (in which case the return code is greater than 128), 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. -Readline uses the current (or default, if line editing was not previously -active) editing settings. - -@item -i @var{text} -If Readline is being used to read the line, @var{text} is placed into -the editing buffer before editing begins. - -@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. -@var{timeout} may be a decimal number with a fractional portion following -the decimal point. -This option is only effective if @code{read} is reading input from a -terminal, pipe, or other special file; it has no effect when reading -from regular files. -If @var{timeout} is 0, @code{read} returns success if input is available on -the specified file descriptor, failure otherwise. -The exit status is greater than 128 if the timeout is exceeded. - -@item -u @var{fd} -Read input from file descriptor @var{fd}. - -@end table - -@item readarray -@btindex readarray -@example -readarray [-n @var{count}] [-O @var{origin}] [-s @var{count}] [-t] [-u @var{fd}] [ --C @var{callback}] [-c @var{quantum}] [@var{array}] -@end example -Read lines from the standard input into array variable @var{array}, -or from file descriptor @var{fd} -if the @option{-u} option is supplied. - -A synonym for @code{mapfile}. - -@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 all of the @var{names} are found, non-zero -if any are not 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 [-abcdefilmnpqrstuvxHST] [@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 -b -The maximum socket buffer size. - -@item -c -The maximum size of core files created. - -@item -d -The maximum size of a process's data segment. - -@item -e -The maximum scheduling priority ("nice"). - -@item -f -The maximum size of files written by the shell and its children. - -@item -i -The maximum number of pending signals. - -@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 -q -The maximum number of bytes in POSIX message queues. - -@item -r -The maximum real-time scheduling priority. - -@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. - -@item -x -The maximum number of file locks. - -@item -T -The maximum number of threads. - -@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. -A hard limit cannot be increased by a non-root user once it is set; -a soft limit may be increased up to the value of the hard limit. -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 Modifying Shell Behavior -@section Modifying Shell Behavior - -@menu -* The Set Builtin:: Change the values of shell attributes and - positional parameters. -* The Shopt Builtin:: Modify shell optional behavior. -@end menu - -@node The Set Builtin -@subsection The Set Builtin - -This builtin is so complicated that it deserves its own section. @code{set} -allows you to change the values of shell options and set the positional -parameters, or to display the names and values of shell variables. - -@table @code -@item set -@btindex set -@example -set [--abefhkmnptuvxBCEHPT] [-o @var{option}] [@var{argument} @dots{}] -set [+abefhkmnptuvxBCEHPT] [+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 -for setting or resetting the currently-set variables. -Read-only variables cannot be reset. -In @sc{posix} mode, only shell variables are listed. - -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 pipeline (@pxref{Pipelines}), which may consist -of a single simple command (@pxref{Simple Commands}), -a subshell command enclosed in parentheses (@pxref{Grouping Commands}), -or one of the commands executed as part of a command list enclosed -by braces (@pxref{Grouping Commands}) -returns a non-zero status. -The shell does not exit if 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 any command executed in a @code{&&} or @code{||} list except -the command following the final @code{&&} or @code{||}, -any command in a pipeline but the last, -or if the command's return status is being inverted with @code{!}. -A trap on @code{ERR}, if set, is executed before the shell exits. - -This option applies to the shell environment and each subshell environment -separately (@pxref{Command Execution Environment}), and may cause -subshells to exit before executing all the commands in the subshell. - -@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}). -This also affects the editing interface used for @code{read -e}. - -@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} 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. -This also affects the editing interface used for @code{read -e}. - -@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}, @env{CDPATH} and @env{GLOBIGNORE} variables, -if they appear in the environment, are 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, @code{for} commands, @code{case} -commands, @code{select} commands, and arithmetic @code{for} commands -and their arguments or associated word lists after they are -expanded and before they are executed. The value of the @env{PS4} -variable is expanded and the resultant value is printed before -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} and @code{RETURN} are inherited by -shell functions, command substitutions, and commands executed -in a subshell environment. -The @code{DEBUG} and @code{RETURN} traps are 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 The Shopt Builtin -@subsection The Shopt Builtin - -This builtin allows you to change additional shell optional behavior. - -@table @code - -@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 autocd -If set, a command name that is the name of a directory is executed as if -it were the argument to the @code{cd} command. -This option is only used by interactive shells. - -@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 checkjobs -If set, Bash lists the status of any stopped and running jobs before -exiting an interactive shell. If any jobs are running, this causes -the exit to be deferred until a second exit is attempted without an -intervening command (@pxref{Job Control}). -The shell always postpones exiting if any jobs are stopped. - -@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 compat31 -If set, Bash -changes its behavior to that of version 3.1 with respect to quoted -arguments to the conditional command's =~ operator. - -@item dirspell -If set, Bash -attempts spelling correction on directory names during word completion -if the directory name initially supplied does not exist. - -@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. - -@item -@code{BASH_ARGC} and @code{BASH_ARGV} are updated as described in their -descriptions (@pxref{Bash Variables}). - -@item -Function tracing is enabled: command substitution, shell functions, and -subshells invoked with @code{( @var{command} )} inherit the -@code{DEBUG} and @code{RETURN} traps. - -@item -Error tracing is enabled: command substitution, shell functions, and -subshells invoked with @code{( @var{command} )} inherit the -@code{ERROR} trap. -@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 globstar -If set, the pattern @samp{**} used in a filename expansion context will -match a files and zero or more directories and subdirectories. -If the pattern is followed by a @samp{/}, only directories and -subdirectories match. - -@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 nocasematch -If set, Bash matches patterns in a case-insensitive fashion when -performing matching while executing @code{case} or @code{[[} -conditional commands. - -@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. - -@end table - -@node Special Builtins -@section Special Builtins -@cindex special builtin - -For historical reasons, the @sc{posix} 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 BASHPID -Expands to the process id of the current Bash process. -This differs from @code{$$} under certain circumstances, such as subshells -that do not require Bash to be re-initialized. - -@item BASH_ALIASES -An associative array variable whose members correspond to the internal -list of aliases as maintained by the @code{alias} builtin -(@pxref{Bourne Shell Builtins}). -Elements added to this array appear in the alias list; unsetting array -elements cause aliases to be removed from the alias list. - -@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}. -The shell sets @code{BASH_ARGC} only when in extended debugging mode -(see @ref{The Shopt Builtin} -for a description of the @code{extdebug} option to the @code{shopt} -builtin). - -@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}. -The shell sets @code{BASH_ARGV} only when in extended debugging mode -(see @ref{The Shopt Builtin} -for a description of the @code{extdebug} option to the @code{shopt} -builtin). - -@item BASH_CMDS -An associative array variable whose members correspond to the internal -hash table of commands as maintained by the @code{hash} builtin -(@pxref{Bourne Shell Builtins}). -Elements added to this array appear in the hash table; unsetting array -elements cause commands to be removed from the hash table. - -@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]@}} was called (or @code{$@{BASH_LINENO[$i-1]@}} if -referenced within another shell function). -The corresponding source file name is @code{$@{BASH_SOURCE[$i]@}}. -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_TYPE -Set to an integer value corresponding to the type of completion attempted -that caused a completion function to be called: -@var{TAB}, for normal completion, -@samp{?}, for listing completions after successive tabs, -@samp{!}, for listing alternatives on partial word completion, -@samp{@@}, to list completions if the word is not unmodified, -or -@samp{%}, for menu completion. -This variable is available only in shell functions and external -commands invoked by the -programmable completion facilities (@pxref{Programmable Completion}). - -@item COMP_KEY -The key (or final key of a key sequence) used to invoke the current -completion function. - -@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. -The line is split into words as Readline would split it, using -@code{COMP_WORDBREAKS} as described above. -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 @code{"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, by removing the oldest entries, -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. -This uses the history comment character to distinguish timestamps from -other history lines. - -@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 PROMPT_DIRTRIM -If set to a number greater than zero, the value is used as the number of -trailing directory components to retain when expanding the @code{\w} and -@code{\W} prompt string escapes (@pxref{Printing a Prompt}). -Characters removed are replaced with an ellipsis. - -@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 interactive 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 TMPDIR -If set, Bash uses its value as the name of a directory in which -Bash creates temporary files for the shell's use. - -@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{The Shopt Builtin} -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 output -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 successfully. - -@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} 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 output. -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{The Shopt Builtin}). -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 describes 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 with its standard input -connected to a a network connection, as if by the remote shell -daemon, usually @code{rshd}, or the secure shell daemon @code{sshd}. -If Bash determines it is being run in -this fashion, 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 specifying the @option{-c} option, and -whose input and error 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{huponexit} 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{The Shopt Builtin}). - -@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. - -Unless otherwise specified, primaries that operate on files follow symbolic -links and operate on the target of the link, rather than the link itself. - -@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 interchangeably 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{The Shopt Builtin}). - -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 indexed and associative array variables. -Any variable may be used as an indexed 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. -Indexed arrays are referenced using integers (including arithmetic -expressions (@pxref{Shell Arithmetic}) and are zero-based; -associative arrays use arbitrary strings. - -An indexed 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. - -Associative arrays are created using -@example -declare -A @var{name}. -@end example - -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}. -Indexed array assignments do not require the bracket and subscript. -When assigning to indexed arrays, 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. - -When assigning to an associative array, the subscript is required. - -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. -If the double-quoted expansion occurs within a word, the expansion of -the first parameter is joined with the beginning part of the original -word, and the expansion of the last parameter is joined with the last -part of the original word. -This is analogous to the -expansion 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 with a subscript of 0. - -The @code{unset} builtin is used to destroy arrays. -@code{unset} @var{name}[@var{subscript}] -destroys the array element at index @var{subscript}. -Care must be taken to avoid unwanted side effects caused by filename -generation. -@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 indexed -array and a @option{-A} option to specify an associative 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 [-n] [@var{+N} | @var{-N} | @var{dir} ] -@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 -n -Suppresses the normal change of directory when adding directories -to the stack, so that only the stack is manipulated. -@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 @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 -(uses the @env{$PROMPT_DIRTRIM} variable). -@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} 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 -The @code{bg} builtin uses the required format to describe each job placed -in the background, which does not include an indication of whether the job -is the current or previous job. - -@item -Reserved words appearing in a context where reserved words are recognized -do not undergo alias expansion. - -@item -The @sc{posix} @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} 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} special builtins are found before shell functions -during command lookup. - -@item -If a @sc{posix} special builtin returns an error status, a -non-interactive shell exits. The fatal errors are those listed in -the POSIX standard, and include things like passing incorrect options, -redirection errors, variable assignment errors for assignments preceding -the command name, and so on. - -@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} 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}. - -@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, unless that argument consists solely of digits and -is a valid signal number. 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. - -@item -When the @code{pwd} builtin is supplied the @option{-P} option, it resets -@code{$PWD} to a pathname containing no symlinks. - -@item -The @code{pwd} builtin verifies that the value it prints is the same as the -current directory, even if it is not asked to check the file system with the -@option{-P} option. - -@item -When listing the history, the @code{fc} builtin does not include an -indication of whether or not a history entry has been modified. - -@item -The default editor used by @code{fc} is @code{ed}. - -@item -The @code{type} and @code{command} builtins will not report a non-executable -file as having been found, though the shell will attempt to execute such a -file if it is the only so-named file found in @code{$PATH}. - -@item -The @code{vi} editing mode will invoke the @code{vi} editor directly when -the @samp{v} command is run, instead of checking @code{$VISUAL} and -@code{$EDITOR}. - -@item -When the @code{xpg_echo} option is enabled, Bash does not attempt to interpret -any arguments to @code{echo} as options. Each argument is displayed, after -escape characters are converted. - -@item -The @code{ulimit} builtin uses a block size of 512 bytes for the @option{-c} -and @option{-f} options. - -@end enumerate - -There is other @sc{posix} behavior that Bash does not implement by -default even when in @sc{posix} mode. -Specifically: - -@enumerate - -@item -The @code{fc} builtin checks @code{$EDITOR} as a program to edit history -entries if @code{FCEDIT} is unset, rather than defaulting directly to -@code{ed}. @code{fc} uses @code{ed} if @code{EDITOR} is unset. - -@item -As noted above, Bash requires the @code{xpg_echo} option to be enabled for -the @code{echo} builtin to be fully conformant. - -@end enumerate - -Bash can be configured to be @sc{posix}-conformant by default, by specifying -the @option{--enable-strict-posix-default} to @code{configure} when building -(@pxref{Optional Features}). - -@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 specification (@var{jobspec}). - -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. -A single @samp{%} (with no accompanying job specification) also refers -to the current job. -The previous job may be referenced using @samp{%-}. -If there is only a single job, @samp{%+} and @samp{%-} can both be used -to refer to that job. -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, (or running, if -the @code{checkjobs} option is enabled -- see @ref{The Shopt Builtin}), the -shell prints a warning message, and if the @code{checkjobs} option is -enabled, lists the jobs and their statuses. -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 any stopped jobs are terminated. - -@node Job Control Builtins -@section Job Control Builtins - -@table @code - -@item bg -@btindex bg -@example -bg [@var{jobspec} @dots{}] -@end example -Resume each 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, any -@var{jobspec} was not found or 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 each 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. -A login shell cannot be suspended; the @option{-f} -option can be used to override this and force the suspension. - -@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 the directory @file{lib/malloc}. This is not the same -@code{malloc} that appears in @sc{gnu} libc, but an older version -originally 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 5.0 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-casemod-attributes -Include support for case-modifying attributes in the @code{declare} builtin -and assignment statements. Variables with the @var{uppercase} attribute, -for example, will have their values converted to uppercase upon assignment. - -@item --enable-casemod-expansion -Include support for case-modifying word expansions. - -@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-coprocesses -Include support for coprocesses and the @code{coproc} reserved word -(@pxref{Pipelines}). - -@item --enable-debugger -Include support for the bash debugger (distributed separately). - -@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-progcomp -Enable the programmable completion facilities -(@pxref{Programmable Completion}). -If Readline is not enabled, this option has no effect. - -@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-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-separate-helpfiles -Use external files for the documentation displayed by the @code{help} builtin -instead of storing the text internally. - -@item --enable-single-help-strings -Store the text displayed by the @code{help} builtin as a single string for -each help topic. This aids in translating the text to different languages. -You may need to disable this if your compiler cannot handle very long string -literals. - -@item --enable-strict-posix-default -Make Bash @sc{posix}-conformant by default (@pxref{Bash POSIX Mode}). - -@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 3. -@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.ramey@case.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} 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 (the -last version of the historical Bourne shell) 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 builtin commands -@code{complete}, @code{compgen}, and @code{compopt}, 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. -The Bash @samp{-o pipefail} option to @code{set} will cause a pipeline to -return a failure status if any command 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}), including -optional regular expression matching. - -@item -Bash provides optional case-insensitive matching for the @code{case} and -@code{[[} 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 supports the @samp{+=} assignment operator, which appends to the value -of the variable named on the left hand side. - -@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} 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 includes the @samp{<<<} redirection operator, allowing a string to -be used as the standard input to a command. - -@item -Bash implements the @samp{[n]<&@var{word}} and @samp{[n]>&@var{word}} -redirection operators, which move one file descriptor to another. - -@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{The Shopt Builtin}), 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 unless the -function has been given the @code{trace} attribute or the -@code{functrace} option has been enabled using the @code{shopt} builtin. - -@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 -Bash includes a number of features to support a separate debugger for -shell scripts. - -@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} special builtins fails, and -only for certain failures, as enumerated in the @sc{posix} standard. - -@item -The SVR4.2 shell behaves differently when invoked as @code{jsh} -(it turns on job control). -@end itemize - -@node GNU Free Documentation License -@appendix GNU Free Documentation License - -@include fdl.texi - -@node Indexes -@appendix Indexes - -@menu -* 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 - -@node Builtin Index -@appendixsec Index of Shell Builtin Commands -@printindex bt - -@node Reserved Word Index -@appendixsec Index of Shell Reserved Words -@printindex rw - -@node Variable Index -@appendixsec Parameter and Variable Index -@printindex vr - -@node Function Index -@appendixsec Function Index -@printindex fn - -@node Concept Index -@appendixsec Concept Index -@printindex cp - -@bye diff --git a/doc/version.texi~ b/doc/version.texi~ deleted file mode 100644 index 5d269ba03..000000000 --- a/doc/version.texi~ +++ /dev/null @@ -1,10 +0,0 @@ -@ignore -Copyright (C) 1988-2009 Free Software Foundation, Inc. -@end ignore - -@set LASTCHANGE Sat Feb 7 20:51:06 EST 2009 - -@set EDITION 4.0 -@set VERSION 4.0 -@set UPDATED 7 February 2009 -@set UPDATED-MONTH February 2009 diff --git a/error.c~ b/error.c~ deleted file mode 100644 index ceedc2c93..000000000 --- a/error.c~ +++ /dev/null @@ -1,452 +0,0 @@ -/* error.c -- Functions for handling errors. */ -/* Copyright (C) 1993-2006 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#include "bashtypes.h" -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (PREFER_STDARG) -# include -#else -# include -#endif - -#include - -#include -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#include "bashansi.h" -#include "bashintl.h" - -#include "shell.h" -#include "flags.h" -#include "input.h" - -#if defined (HISTORY) -# include "bashhist.h" -#endif - -extern int executing_line_number __P((void)); - -extern char *shell_name; -#if defined (JOB_CONTROL) -extern pid_t shell_pgrp; -extern int give_terminal_to __P((pid_t, int)); -#endif /* JOB_CONTROL */ - -#if defined (ARRAY_VARS) -extern const char * const bash_badsub_errmsg; -#endif - -static void error_prolog __P((int)); - -/* The current maintainer of the shell. You change this in the - Makefile. */ -#if !defined (MAINTAINER) -#define MAINTAINER "bash-maintainers@gnu.org" -#endif - -const char * const the_current_maintainer = MAINTAINER; - -int gnu_error_format = 0; - -static void -error_prolog (print_lineno) - int print_lineno; -{ - char *ename; - int line; - - ename = get_name_for_error (); - line = (print_lineno && interactive_shell == 0) ? executing_line_number () : -1; - - if (line > 0) - fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), line); - else - fprintf (stderr, "%s: ", ename); -} - -/* Return the name of the shell or the shell script for error reporting. */ -char * -get_name_for_error () -{ - char *name; -#if defined (ARRAY_VARS) - SHELL_VAR *bash_source_v; - ARRAY *bash_source_a; -#endif - - name = (char *)NULL; - if (interactive_shell == 0) - { -#if defined (ARRAY_VARS) - bash_source_v = find_variable ("BASH_SOURCE"); - if (bash_source_v && array_p (bash_source_v) && - (bash_source_a = array_cell (bash_source_v))) - name = array_reference (bash_source_a, 0); - if (name == 0 || *name == '\0') /* XXX - was just name == 0 */ -#endif - name = dollar_vars[0]; - } - if (name == 0 && shell_name && *shell_name) - name = base_pathname (shell_name); - if (name == 0) -#if defined (PROGRAM) - name = PROGRAM; -#else - name = "bash"; -#endif - - return (name); -} - -/* Report an error having to do with FILENAME. This does not use - sys_error so the filename is not interpreted as a printf-style - format string. */ -void -file_error (filename) - const char *filename; -{ - report_error ("%s: %s", filename, strerror (errno)); -} - -void -#if defined (PREFER_STDARG) -programming_error (const char *format, ...) -#else -programming_error (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - char *h; - -#if defined (JOB_CONTROL) - give_terminal_to (shell_pgrp, 0); -#endif /* JOB_CONTROL */ - - SH_VA_START (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - va_end (args); - -#if defined (HISTORY) - if (remember_on_history) - { - h = last_history_line (); - fprintf (stderr, _("last command: %s\n"), h ? h : "(null)"); - } -#endif - -#if 0 - fprintf (stderr, "Report this to %s\n", the_current_maintainer); -#endif - - fprintf (stderr, _("Aborting...")); - fflush (stderr); - - abort (); -} - -/* Print an error message and, if `set -e' has been executed, exit the - shell. Used in this file by file_error and programming_error. Used - outside this file mostly to report substitution and expansion errors, - and for bad invocation options. */ -void -#if defined (PREFER_STDARG) -report_error (const char *format, ...) -#else -report_error (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - - error_prolog (1); - - SH_VA_START (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - - va_end (args); - if (exit_immediately_on_error) - exit_shell (1); -} - -void -#if defined (PREFER_STDARG) -fatal_error (const char *format, ...) -#else -fatal_error (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - - error_prolog (0); - - SH_VA_START (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - - va_end (args); - sh_exit (2); -} - -void -#if defined (PREFER_STDARG) -internal_error (const char *format, ...) -#else -internal_error (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - - error_prolog (1); - - SH_VA_START (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - - va_end (args); -} - -void -#if defined (PREFER_STDARG) -internal_warning (const char *format, ...) -#else -internal_warning (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - - fprintf (stderr, _("%s: warning: "), get_name_for_error ()); - - SH_VA_START (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - - va_end (args); -} - -void -#if defined (PREFER_STDARG) -sys_error (const char *format, ...) -#else -sys_error (format, va_alist) - const char *format; - va_dcl -#endif -{ - int e; - va_list args; - - e = errno; - error_prolog (0); - - SH_VA_START (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, ": %s\n", strerror (e)); - - va_end (args); -} - -/* An error from the parser takes the general form - - shell_name: input file name: line number: message - - The input file name and line number are omitted if the shell is - currently interactive. If the shell is not currently interactive, - the input file name is inserted only if it is different from the - shell name. */ -void -#if defined (PREFER_STDARG) -parser_error (int lineno, const char *format, ...) -#else -parser_error (lineno, format, va_alist) - int lineno; - const char *format; - va_dcl -#endif -{ - va_list args; - char *ename, *iname; - - ename = get_name_for_error (); - iname = yy_input_name (); - - if (interactive) - fprintf (stderr, "%s: ", ename); - else if (interactive_shell) - fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno); - else if (STREQ (ename, iname)) - fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), lineno); - else - fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno); - - SH_VA_START (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - - va_end (args); - - if (exit_immediately_on_error) - exit_shell (2); -} - -#ifdef DEBUG -void -#if defined (PREFER_STDARG) -itrace (const char *format, ...) -#else -itrace (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - - fprintf(stderr, "TRACE: pid %ld: ", (long)getpid()); - - SH_VA_START (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - - va_end (args); - - fflush(stderr); -} - -/* A trace function for silent debugging -- doesn't require a control - terminal. */ -void -#if defined (PREFER_STDARG) -trace (const char *format, ...) -#else -trace (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - static FILE *tracefp = (FILE *)NULL; - - if (tracefp == NULL) - tracefp = fopen("/tmp/bash-trace.log", "a+"); - - if (tracefp == NULL) - tracefp = stderr; - else - fcntl (fileno (tracefp), F_SETFD, 1); /* close-on-exec */ - - fprintf(tracefp, "TRACE: pid %ld: ", (long)getpid()); - - SH_VA_START (args, format); - - vfprintf (tracefp, format, args); - fprintf (tracefp, "\n"); - - va_end (args); - - fflush(tracefp); -} - -#endif /* DEBUG */ - -/* **************************************************************** */ -/* */ -/* Common error reporting */ -/* */ -/* **************************************************************** */ - - -static const char * const cmd_error_table[] = { - N_("unknown command error"), /* CMDERR_DEFAULT */ - N_("bad command type"), /* CMDERR_BADTYPE */ - N_("bad connector"), /* CMDERR_BADCONN */ - N_("bad jump"), /* CMDERR_BADJUMP */ - 0 -}; - -void -command_error (func, code, e, flags) - const char *func; - int code, e, flags; /* flags currently unused */ -{ - if (code > CMDERR_LAST) - code = CMDERR_DEFAULT; - - programming_error ("%s: %s: %d", func, _(cmd_error_table[code]), e); -} - -char * -command_errstr (code) - int code; -{ - if (code > CMDERR_LAST) - code = CMDERR_DEFAULT; - - return (_(cmd_error_table[code])); -} - -#ifdef ARRAY_VARS -void -err_badarraysub (s) - const char *s; -{ - report_error ("%s: %s", s, _(bash_badsub_errmsg)); -} -#endif - -void -err_unboundvar (s) - const char *s; -{ - report_error (_("%s: unbound variable"), s); -} - -void -err_readonly (s) - const char *s; -{ - report_error (_("%s: readonly variable"), s); -} diff --git a/eval.c~ b/eval.c~ deleted file mode 100644 index f77b76c87..000000000 --- a/eval.c~ +++ /dev/null @@ -1,280 +0,0 @@ -/* eval.c -- reading and evaluating commands. */ - -/* Copyright (C) 1996 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - Bash is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with Bash; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "bashansi.h" -#include - -#include "bashintl.h" - -#include "shell.h" -#include "flags.h" -#include "trap.h" - -#include "builtins/common.h" - -#include "input.h" -#include "execute_cmd.h" - -#if defined (HISTORY) -# include "bashhist.h" -#endif - -extern int EOF_reached; -extern int indirection_level; -extern int posixly_correct; -extern int subshell_environment, running_under_emacs; -extern int last_command_exit_value, stdin_redir; -extern int need_here_doc; -extern int current_command_number, current_command_line_count, line_number; -extern int expand_aliases; - -static void send_pwd_to_eterm __P((void)); -static sighandler alrm_catcher __P((int)); - -/* Read and execute commands until EOF is reached. This assumes that - the input source has already been initialized. */ -int -reader_loop () -{ - int our_indirection_level; - COMMAND * volatile current_command; - - current_command = (COMMAND *)NULL; - USE_VAR(current_command); - - our_indirection_level = ++indirection_level; - - while (EOF_Reached == 0) - { - int code; - - code = setjmp (top_level); - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - if (interactive_shell && signal_is_ignored (SIGINT) == 0) - set_signal_handler (SIGINT, sigint_sighandler); - - if (code != NOT_JUMPED) - { - indirection_level = our_indirection_level; - - switch (code) - { - /* Some kind of throw to top_level has occured. */ - case FORCE_EOF: - case ERREXIT: - case EXITPROG: - current_command = (COMMAND *)NULL; - if (exit_immediately_on_error) - variable_context = 0; /* not in a function */ - EOF_Reached = EOF; - goto exec_done; - - case DISCARD: - /* Make sure the exit status is reset to a non-zero value, but - leave existing non-zero values (e.g., > 128 on signal) - alone. */ - if (last_command_exit_value == 0) - last_command_exit_value = EXECUTION_FAILURE; - if (subshell_environment) - { - current_command = (COMMAND *)NULL; - EOF_Reached = EOF; - goto exec_done; - } - /* Obstack free command elements, etc. */ - if (current_command) - { - dispose_command (current_command); - current_command = (COMMAND *)NULL; - } - break; - - default: - command_error ("reader_loop", CMDERR_BADJUMP, code, 0); - } - } - - executing = 0; - if (temporary_env) - dispose_used_env_vars (); - -#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA) - /* Attempt to reclaim memory allocated with alloca (). */ - (void) alloca (0); -#endif - - if (read_command () == 0) - { - if (interactive_shell == 0 && read_but_dont_execute) - { - last_command_exit_value = EXECUTION_SUCCESS; - dispose_command (global_command); - global_command = (COMMAND *)NULL; - } - else if (current_command = global_command) - { - global_command = (COMMAND *)NULL; - current_command_number++; - - executing = 1; - stdin_redir = 0; - execute_command (current_command); - - exec_done: - QUIT; - - if (current_command) - { - dispose_command (current_command); - current_command = (COMMAND *)NULL; - } - } - } - else - { - /* Parse error, maybe discard rest of stream if not interactive. */ - if (interactive == 0) - EOF_Reached = EOF; - } - if (just_one_command) - EOF_Reached = EOF; - } - indirection_level--; - return (last_command_exit_value); -} - -static sighandler -alrm_catcher(i) - int i; -{ - printf (_("\007timed out waiting for input: auto-logout\n")); - fflush (stdout); - bash_logout (); /* run ~/.bash_logout if this is a login shell */ - jump_to_top_level (EXITPROG); - SIGRETURN (0); -} - -/* Send an escape sequence to emacs term mode to tell it the - current working directory. */ -static void -send_pwd_to_eterm () -{ - char *pwd; - - pwd = get_string_value ("PWD"); - if (pwd == 0) - pwd = get_working_directory ("eterm"); - fprintf (stderr, "\032/%s\n", pwd); -} - -/* Call the YACC-generated parser and return the status of the parse. - Input is read from the current input stream (bash_input). yyparse - leaves the parsed command in the global variable GLOBAL_COMMAND. - This is where PROMPT_COMMAND is executed. */ -int -parse_command () -{ - int r; - char *command_to_execute; - - need_here_doc = 0; - run_pending_traps (); - - /* Allow the execution of a random command just before the printing - of each primary prompt. If the shell variable PROMPT_COMMAND - is set then the value of it is the command to execute. */ - if (interactive && bash_input.type != st_string) - { - command_to_execute = get_string_value ("PROMPT_COMMAND"); - if (command_to_execute) - execute_variable_command (command_to_execute, "PROMPT_COMMAND"); - - if (running_under_emacs == 2) - send_pwd_to_eterm (); /* Yuck */ - } - - current_command_line_count = 0; - r = yyparse (); - - if (need_here_doc) - gather_here_documents (); - - return (r); -} - -/* Read and parse a command, returning the status of the parse. The command - is left in the globval variable GLOBAL_COMMAND for use by reader_loop. - This is where the shell timeout code is executed. */ -int -read_command () -{ - SHELL_VAR *tmout_var; - int tmout_len, result; - SigHandler *old_alrm; - - set_current_prompt_level (1); - global_command = (COMMAND *)NULL; - - /* Only do timeouts if interactive. */ - tmout_var = (SHELL_VAR *)NULL; - tmout_len = 0; - old_alrm = (SigHandler *)NULL; - - if (interactive) - { - tmout_var = find_variable ("TMOUT"); - - if (tmout_var && var_isset (tmout_var)) - { - tmout_len = atoi (value_cell (tmout_var)); - if (tmout_len > 0) - { - old_alrm = set_signal_handler (SIGALRM, alrm_catcher); - alarm (tmout_len); - } - } - } - - QUIT; - - current_command_line_count = 0; - result = parse_command (); - - if (interactive && tmout_var && (tmout_len > 0)) - { - alarm(0); - set_signal_handler (SIGALRM, old_alrm); - } - - return (result); -} diff --git a/examples/loadables/Makefile.in.save b/examples/loadables/Makefile.in.save deleted file mode 100644 index f6208f5cc..000000000 --- a/examples/loadables/Makefile.in.save +++ /dev/null @@ -1,238 +0,0 @@ -# -# Simple makefile for the sample loadable builtins -# -# Copyright (C) 1996 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. - -# Include some boilerplate Gnu makefile definitions. -prefix = @prefix@ - -exec_prefix = @exec_prefix@ -bindir = @bindir@ -libdir = @libdir@ -infodir = @infodir@ -includedir = @includedir@ - -topdir = @top_srcdir@ -BUILD_DIR = @BUILD_DIR@ -srcdir = @srcdir@ -VPATH = .:@srcdir@ - -@SET_MAKE@ -CC = @CC@ -RM = rm -f - -SHELL = @MAKE_SHELL@ - -host_os = @host_os@ -host_cpu = @host_cpu@ -host_vendor = @host_vendor@ - -CFLAGS = @CFLAGS@ -LOCAL_CFLAGS = @LOCAL_CFLAGS@ -DEFS = @DEFS@ -LOCAL_DEFS = @LOCAL_DEFS@ - -CPPFLAGS = @CPPFLAGS@ - -BASHINCDIR = ${topdir}/include - -LIBBUILD = ${BUILD_DIR}/lib - -INTL_LIBSRC = ${topdir}/lib/intl -INTL_BUILDDIR = ${LIBBUILD}/intl -INTL_INC = @INTL_INC@ -LIBINTL_H = @LIBINTL_H@ - -CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS) - -# -# These values are generated for configure by ${topdir}/support/shobj-conf. -# If your system is not supported by that script, but includes facilities for -# dynamic loading of shared objects, please update the script and send the -# changes to bash-maintainers@gnu.org. -# -SHOBJ_CC = @SHOBJ_CC@ -SHOBJ_CFLAGS = @SHOBJ_CFLAGS@ -SHOBJ_LD = @SHOBJ_LD@ -SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@ -SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@ -SHOBJ_LIBS = @SHOBJ_LIBS@ -SHOBJ_STATUS = @SHOBJ_STATUS@ - -INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \ - -I$(BASHINCDIR) -I$(BUILD_DIR) -I$(LIBBUILD) \ - -I$(BUILD_DIR)/builtins $(INTL_INC) - -.c.o: - $(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $< - - -ALLPROG = print truefalse sleep pushd finfo logname basename dirname \ - tty pathchk tee head mkdir rmdir printenv id whoami \ - uname sync push ln unlink cut realpath getconf strftime -OTHERPROG = necho hello cat - -all: $(SHOBJ_STATUS) - -supported: $(ALLPROG) -others: $(OTHERPROG) - -unsupported: - @echo "Your system (${host_os}) is not supported by the" - @echo "${topdir}/support/shobj-conf script." - @echo "If your operating system provides facilities for dynamic" - @echo "loading of shared objects using the dlopen(3) interface," - @echo "please update the script and re-run configure. - @echo "Please send the changes you made to bash-maintainers@gnu.org" - @echo "for inclusion in future bash releases." - -everything: supported others - -print: print.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ print.o $(SHOBJ_LIBS) - -necho: necho.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ necho.o $(SHOBJ_LIBS) - -getconf: getconf.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ getconf.o $(SHOBJ_LIBS) - -hello: hello.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ hello.o $(SHOBJ_LIBS) - -truefalse: truefalse.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ truefalse.o $(SHOBJ_LIBS) - -sleep: sleep.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sleep.o $(SHOBJ_LIBS) - -finfo: finfo.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ finfo.o $(SHOBJ_LIBS) - -cat: cat.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS) - -logname: logname.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS) - -basename: basename.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ basename.o $(SHOBJ_LIBS) - -dirname: dirname.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dirname.o $(SHOBJ_LIBS) - -tty: tty.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tty.o $(SHOBJ_LIBS) - -pathchk: pathchk.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pathchk.o $(SHOBJ_LIBS) - -tee: tee.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tee.o $(SHOBJ_LIBS) - -mkdir: mkdir.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkdir.o $(SHOBJ_LIBS) - -rmdir: rmdir.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rmdir.o $(SHOBJ_LIBS) - -head: head.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ head.o $(SHOBJ_LIBS) - -printenv: printenv.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ printenv.o $(SHOBJ_LIBS) - -id: id.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ id.o $(SHOBJ_LIBS) - -whoami: whoami.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ whoami.o $(SHOBJ_LIBS) - -uname: uname.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ uname.o $(SHOBJ_LIBS) - -sync: sync.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sync.o $(SHOBJ_LIBS) - -push: push.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ push.o $(SHOBJ_LIBS) - -ln: ln.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ ln.o $(SHOBJ_LIBS) - -unlink: unlink.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ unlink.o $(SHOBJ_LIBS) - -cut: cut.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cut.o $(SHOBJ_LIBS) - -realpath: realpath.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ realpath.o $(SHOBJ_LIBS) - -strftime: strftime.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ strftime.o $(SHOBJ_LIBS) - -# pushd is a special case. We use the same source that the builtin version -# uses, with special compilation options. -# -pushd.c: ${topdir}/builtins/pushd.def - $(RM) $@ - ${BUILD_DIR}/builtins/mkbuiltins -D ${topdir}/builtins ${topdir}/builtins/pushd.def - -pushd.o: pushd.c - $(RM) $@ - $(SHOBJ_CC) -DHAVE_CONFIG_H -DPUSHD_AND_POPD -DLOADABLE_BUILTIN $(SHOBJ_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(INC) -c -o $@ $< - -pushd: pushd.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pushd.o $(SHOBJ_LIBS) - -clean: - $(RM) $(ALLPROG) $(OTHERPROG) *.o - -( cd perl && ${MAKE} ${MFLAGS} $@ ) - -mostlyclean: clean - -( cd perl && ${MAKE} ${MFLAGS} $@ ) - -distclean maintainer-clean: clean - $(RM) Makefile pushd.c - -( cd perl && ${MAKE} ${MFLAGS} $@ ) - -print.o: print.c -truefalse.o: truefalse.c -sleep.o: sleep.c -finfo.o: finfo.c -logname.o: logname.c -basename.o: basename.c -dirname.o: dirname.c -tty.o: tty.c -pathchk.o: pathchk.c -tee.o: tee.c -head.o: head.c -rmdir.o: rmdir.c -necho.o: necho.c -getconf.o: getconf.c -hello.o: hello.c -cat.o: cat.c -printenv.o: printenv.c -id.o: id.c -whoami.o: whoami.c -uname.o: uname.c -sync.o: sync.c -push.o: push.c -mkdir.o: mkdir.c -realpath.o: realpath.c -strftime.o: strftime.c diff --git a/examples/loadables/Makefile.in~ b/examples/loadables/Makefile.in~ deleted file mode 100644 index 8092d20df..000000000 --- a/examples/loadables/Makefile.in~ +++ /dev/null @@ -1,244 +0,0 @@ -# -# Simple makefile for the sample loadable builtins -# -# Copyright (C) 1996 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. - -# Include some boilerplate Gnu makefile definitions. -prefix = @prefix@ - -exec_prefix = @exec_prefix@ -bindir = @bindir@ -libdir = @libdir@ -infodir = @infodir@ -includedir = @includedir@ - -datarootdir = @datarootdir@ - -topdir = @top_srcdir@ -BUILD_DIR = @BUILD_DIR@ -srcdir = @srcdir@ -VPATH = .:@srcdir@ - -@SET_MAKE@ -CC = @CC@ -RM = rm -f - -SHELL = @MAKE_SHELL@ - -host_os = @host_os@ -host_cpu = @host_cpu@ -host_vendor = @host_vendor@ - -CFLAGS = @CFLAGS@ -LOCAL_CFLAGS = @LOCAL_CFLAGS@ -DEFS = @DEFS@ -LOCAL_DEFS = @LOCAL_DEFS@ - -CPPFLAGS = @CPPFLAGS@ - -BASHINCDIR = ${topdir}/include - -LIBBUILD = ${BUILD_DIR}/lib - -INTL_LIBSRC = ${topdir}/lib/intl -INTL_BUILDDIR = ${LIBBUILD}/intl -INTL_INC = @INTL_INC@ -LIBINTL_H = @LIBINTL_H@ - -CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS) - -# -# These values are generated for configure by ${topdir}/support/shobj-conf. -# If your system is not supported by that script, but includes facilities for -# dynamic loading of shared objects, please update the script and send the -# changes to bash-maintainers@gnu.org. -# -SHOBJ_CC = @SHOBJ_CC@ -SHOBJ_CFLAGS = @SHOBJ_CFLAGS@ -SHOBJ_LD = @SHOBJ_LD@ -SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@ -SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@ -SHOBJ_LIBS = @SHOBJ_LIBS@ -SHOBJ_STATUS = @SHOBJ_STATUS@ - -INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \ - -I$(BASHINCDIR) -I$(BUILD_DIR) -I$(LIBBUILD) \ - -I$(BUILD_DIR)/builtins $(INTL_INC) - -.c.o: - $(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $< - - -ALLPROG = print truefalse sleep pushd finfo logname basename dirname \ - tty pathchk tee head mkdir rmdir printenv id whoami \ - uname sync push ln unlink cut realpath getconf strftime mypid -OTHERPROG = necho hello cat - -all: $(SHOBJ_STATUS) - -supported: $(ALLPROG) -others: $(OTHERPROG) - -unsupported: - @echo "Your system (${host_os}) is not supported by the" - @echo "${topdir}/support/shobj-conf script." - @echo "If your operating system provides facilities for dynamic" - @echo "loading of shared objects using the dlopen(3) interface," - @echo "please update the script and re-run configure. - @echo "Please send the changes you made to bash-maintainers@gnu.org" - @echo "for inclusion in future bash releases." - -everything: supported others - -print: print.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ print.o $(SHOBJ_LIBS) - -necho: necho.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ necho.o $(SHOBJ_LIBS) - -getconf: getconf.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ getconf.o $(SHOBJ_LIBS) - -hello: hello.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ hello.o $(SHOBJ_LIBS) - -truefalse: truefalse.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ truefalse.o $(SHOBJ_LIBS) - -sleep: sleep.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sleep.o $(SHOBJ_LIBS) - -finfo: finfo.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ finfo.o $(SHOBJ_LIBS) - -cat: cat.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS) - -logname: logname.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS) - -basename: basename.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ basename.o $(SHOBJ_LIBS) - -dirname: dirname.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dirname.o $(SHOBJ_LIBS) - -tty: tty.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tty.o $(SHOBJ_LIBS) - -pathchk: pathchk.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pathchk.o $(SHOBJ_LIBS) - -tee: tee.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tee.o $(SHOBJ_LIBS) - -mkdir: mkdir.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkdir.o $(SHOBJ_LIBS) - -rmdir: rmdir.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rmdir.o $(SHOBJ_LIBS) - -head: head.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ head.o $(SHOBJ_LIBS) - -printenv: printenv.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ printenv.o $(SHOBJ_LIBS) - -id: id.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ id.o $(SHOBJ_LIBS) - -whoami: whoami.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ whoami.o $(SHOBJ_LIBS) - -uname: uname.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ uname.o $(SHOBJ_LIBS) - -sync: sync.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sync.o $(SHOBJ_LIBS) - -push: push.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ push.o $(SHOBJ_LIBS) - -ln: ln.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ ln.o $(SHOBJ_LIBS) - -unlink: unlink.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ unlink.o $(SHOBJ_LIBS) - -cut: cut.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cut.o $(SHOBJ_LIBS) - -realpath: realpath.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ realpath.o $(SHOBJ_LIBS) - -strftime: strftime.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ strftime.o $(SHOBJ_LIBS) - -mypid: mypid.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mypid.o $(SHOBJ_LIBS) - -# pushd is a special case. We use the same source that the builtin version -# uses, with special compilation options. -# -pushd.c: ${topdir}/builtins/pushd.def - $(RM) $@ - ${BUILD_DIR}/builtins/mkbuiltins -D ${topdir}/builtins ${topdir}/builtins/pushd.def - -pushd.o: pushd.c - $(RM) $@ - $(SHOBJ_CC) -DHAVE_CONFIG_H -DPUSHD_AND_POPD -DLOADABLE_BUILTIN $(SHOBJ_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(INC) -c -o $@ $< - -pushd: pushd.o - $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pushd.o $(SHOBJ_LIBS) - -clean: - $(RM) $(ALLPROG) $(OTHERPROG) *.o - -( cd perl && ${MAKE} ${MFLAGS} $@ ) - -mostlyclean: clean - -( cd perl && ${MAKE} ${MFLAGS} $@ ) - -distclean maintainer-clean: clean - $(RM) Makefile pushd.c - -( cd perl && ${MAKE} ${MFLAGS} $@ ) - -print.o: print.c -truefalse.o: truefalse.c -sleep.o: sleep.c -finfo.o: finfo.c -logname.o: logname.c -basename.o: basename.c -dirname.o: dirname.c -tty.o: tty.c -pathchk.o: pathchk.c -tee.o: tee.c -head.o: head.c -rmdir.o: rmdir.c -necho.o: necho.c -getconf.o: getconf.c -hello.o: hello.c -cat.o: cat.c -printenv.o: printenv.c -id.o: id.c -whoami.o: whoami.c -uname.o: uname.c -sync.o: sync.c -push.o: push.c -mkdir.o: mkdir.c -realpath.o: realpath.c -strftime.o: strftime.c -mypid.o: mypid.c diff --git a/examples/loadables/basename.c~ b/examples/loadables/basename.c~ deleted file mode 100644 index bec68a751..000000000 --- a/examples/loadables/basename.c~ +++ /dev/null @@ -1,109 +0,0 @@ -/* basename - return nondirectory portion of pathname */ - -/* See Makefile for compilation details. */ - -#include "config.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include "builtins.h" -#include "shell.h" -#include "common.h" - -basename_builtin (list) - WORD_LIST *list; -{ - int slen, sufflen, off; - char *string, *suffix, *fn; - - if (list == 0) - { - builtin_usage (); - return (EX_USAGE); - } - - if (no_options (list)) - return (EX_USAGE); - - string = list->word->word; - suffix = (char *)NULL; - if (list->next) - { - list = list->next; - suffix = list->word->word; - } - - if (list->next) - { - builtin_usage (); - return (EX_USAGE); - } - - slen = strlen (string); - - /* Strip trailing slashes */ - while (slen > 0 && string[slen - 1] == '/') - slen--; - - /* (2) If string consists entirely of slash characters, string shall be - set to a single slash character. In this case, skip steps (3) - through (5). */ - if (slen == 0) - { - fputs ("/\n", stdout); - return (EXECUTION_SUCCESS); - } - - /* (3) If there are any trailing slash characters in string, they - shall be removed. */ - string[slen] = '\0'; - - /* (4) If there are any slash characters remaining in string, the prefix - of string up to an including the last slash character in string - shall be removed. */ - while (--slen >= 0) - if (string[slen] == '/') - break; - - fn = string + slen + 1; - - /* (5) If the suffix operand is present, is not identical to the - characters remaining in string, and is identical to a suffix - of the characters remaining in string, the suffix suffix - shall be removed from string. Otherwise, string shall not be - modified by this step. */ - if (suffix) - { - sufflen = strlen (suffix); - slen = strlen (fn); - if (sufflen < slen) - { - off = slen - sufflen; - if (strcmp (fn + off, suffix) == 0) - fn[off] = '\0'; - } - } - printf ("%s\n", fn); - return (EXECUTION_SUCCESS); -} - -char *basename_doc[] = { - "The STRING is converted to a filename corresponding to the last", - "pathname component in STRING. If the suffix string SUFFIX is", - "supplied, it is removed.", - (char *)NULL -}; - -/* The standard structure describing a builtin command. bash keeps an array - of these structures. */ -struct builtin basename_struct = { - "basename", /* builtin name */ - basename_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - basename_doc, /* array of long documentation strings. */ - "basename string [suffix]", /* usage synopsis */ - 0 /* reserved for internal use */ -}; diff --git a/examples/loadables/cat.c~ b/examples/loadables/cat.c~ deleted file mode 100644 index 9dd1d1a74..000000000 --- a/examples/loadables/cat.c~ +++ /dev/null @@ -1,100 +0,0 @@ -/* - * cat replacement - * - * no options - the way cat was intended - */ - -#include -#include - -#include "builtins.h" -#include "shell.h" - -#ifndef errno -extern int errno; -#endif - -extern char *strerror (); -extern char **make_builtin_argv (); - -static int -fcopy(fd) -int fd; -{ - char buf[1024], *s; - int n, w, e; - - while (n = read(fd, buf, sizeof (buf))) { - w = write(1, buf, n); - if (w != n) { - e = errno; - write(2, "cat: write error: ", 18); - s = strerror(e); - write(2, s, strlen(s)); - write(2, "\n", 1); - return 1; - } - } - return 0; -} - -cat_main (argc, argv) -int argc; -char **argv; -{ - int i, fd, r; - char *s; - - if (argc == 1) - return (fcopy(0)); - - for (i = r = 1; i < argc; i++) { - if (argv[i][0] == '-' && argv[i][1] == '\0') - fd = 0; - else { - fd = open(argv[i], O_RDONLY, 0666); - if (fd < 0) { - s = strerror(errno); - write(2, "cat: cannot open ", 17); - write(2, argv[i], strlen(argv[i])); - write(2, ": ", 2); - write(2, s, strlen(s)); - write(2, "\n", 1); - continue; - } - } - r = fcopy(fd); - if (fd != 0) - close(fd); - } - return (r); -} - -cat_builtin(list) -WORD_LIST *list; -{ - char **v; - int c, r; - - v = make_builtin_argv(list, &c); - r = cat_main(c, v); - free(v); - - return r; -} - -char *cat_doc[] = { - "Read each FILE and display it on the standard output. If any", - "FILE is `-' or if no FILE argument is given, the standard input", - "is read.", - (char *)0 -}; - -struct builtin cat_struct = { - "cat", - cat_builtin, - BUILTIN_ENABLED, - cat_doc, - "cat [-] [file ...]", - 0 -}; diff --git a/examples/loadables/cut.c~ b/examples/loadables/cut.c~ deleted file mode 100644 index f358cba3c..000000000 --- a/examples/loadables/cut.c~ +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -static const char copyright[] = -"@(#) Copyright (c) 1989, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static const char sccsid[] = "@(#)cut.c 8.3 (Berkeley) 5/4/95"; -#endif /* not lint */ - -#include - -#include -#include -#include - -#include "bashansi.h" - -#ifdef HAVE_LIMITS_H -# include -#endif - -#ifdef HAVE_UNISTD_H -# include -#endif - -#include "builtins.h" -#include "shell.h" -#include "bashgetopt.h" -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif - -#if !defined (_POSIX2_LINE_MAX) -# define _POSIX2_LINE_MAX 2048 -#endif - -static int cflag; -static char dchar; -static int dflag; -static int fflag; -static int sflag; - -static int autostart, autostop, maxval; -static char positions[_POSIX2_LINE_MAX + 1]; - -static int c_cut __P((FILE *, char *)); -static int f_cut __P((FILE *, char *)); -static int get_list __P((char *)); -static char *_cut_strsep __P((char **, const char *)); - -int -cut_builtin(list) - WORD_LIST *list; -{ - FILE *fp; - int (*fcn) __P((FILE *, char *)) = NULL; - int ch; - - fcn = NULL; - dchar = '\t'; /* default delimiter is \t */ - - /* Since we don't support multi-byte characters, the -c and -b - options are equivalent, and the -n option is meaningless. */ - reset_internal_getopt (); - while ((ch = internal_getopt (list, "b:c:d:f:sn")) != -1) - switch(ch) { - case 'b': - case 'c': - fcn = c_cut; - if (get_list(list_optarg) < 0) - return (EXECUTION_FAILURE); - cflag = 1; - break; - case 'd': - dchar = *list_optarg; - dflag = 1; - break; - case 'f': - fcn = f_cut; - if (get_list(list_optarg) < 0) - return (EXECUTION_FAILURE); - fflag = 1; - break; - case 's': - sflag = 1; - break; - case 'n': - break; - case '?': - default: - builtin_usage(); - return (EX_USAGE); - } - - list = loptend; - - if (fflag) { - if (cflag) { - builtin_usage(); - return (EX_USAGE); - } - } else if (!cflag || dflag || sflag) { - builtin_usage(); - return (EX_USAGE); - } - - if (list) { - while (list) { - fp = fopen(list->word->word, "r"); - if (fp == 0) { - builtin_error("%s", list->word->word); - return (EXECUTION_FAILURE); - } - ch = (*fcn)(fp, list->word->word); - (void)fclose(fp); - if (ch < 0) - return (EXECUTION_FAILURE); - list = list->next; - } - } else { - ch = (*fcn)(stdin, "stdin"); - if (ch < 0) - return (EXECUTION_FAILURE); - } - - return (EXECUTION_SUCCESS); -} - -static int -get_list(list) - char *list; -{ - int setautostart, start, stop; - char *pos; - char *p; - - /* - * set a byte in the positions array to indicate if a field or - * column is to be selected; use +1, it's 1-based, not 0-based. - * This parser is less restrictive than the Draft 9 POSIX spec. - * POSIX doesn't allow lists that aren't in increasing order or - * overlapping lists. We also handle "-3-5" although there's no - * real reason too. - */ - for (; (p = _cut_strsep(&list, ", \t")) != NULL;) { - setautostart = start = stop = 0; - if (*p == '-') { - ++p; - setautostart = 1; - } - if (isdigit((unsigned char)*p)) { - start = stop = strtol(p, &p, 10); - if (setautostart && start > autostart) - autostart = start; - } - if (*p == '-') { - if (isdigit((unsigned char)p[1])) - stop = strtol(p + 1, &p, 10); - if (*p == '-') { - ++p; - if (!autostop || autostop > stop) - autostop = stop; - } - } - if (*p) { - builtin_error("[-cf] list: illegal list value"); - return -1; - } - if (!stop || !start) { - builtin_error("[-cf] list: values may not include zero"); - return -1; - } - if (stop > _POSIX2_LINE_MAX) { - builtin_error("[-cf] list: %d too large (max %d)", - stop, _POSIX2_LINE_MAX); - return -1; - } - if (maxval < stop) - maxval = stop; - for (pos = positions + start; start++ <= stop; *pos++ = 1); - } - - /* overlapping ranges */ - if (autostop && maxval > autostop) - maxval = autostop; - - /* set autostart */ - if (autostart) - memset(positions + 1, '1', autostart); - - return 0; -} - -/* ARGSUSED */ -static int -c_cut(fp, fname) - FILE *fp; - char *fname; -{ - int ch, col; - char *pos; - - ch = 0; - for (;;) { - pos = positions + 1; - for (col = maxval; col; --col) { - if ((ch = getc(fp)) == EOF) - return; - if (ch == '\n') - break; - if (*pos++) - (void)putchar(ch); - } - if (ch != '\n') { - if (autostop) - while ((ch = getc(fp)) != EOF && ch != '\n') - (void)putchar(ch); - else - while ((ch = getc(fp)) != EOF && ch != '\n'); - } - (void)putchar('\n'); - } - return (0); -} - -static int -f_cut(fp, fname) - FILE *fp; - char *fname; -{ - int ch, field, isdelim; - char *pos, *p, sep; - int output; - char lbuf[_POSIX2_LINE_MAX + 1]; - - for (sep = dchar; fgets(lbuf, sizeof(lbuf), fp);) { - output = 0; - for (isdelim = 0, p = lbuf;; ++p) { - if (!(ch = *p)) { - builtin_error("%s: line too long.", fname); - return -1; - } - /* this should work if newline is delimiter */ - if (ch == sep) - isdelim = 1; - if (ch == '\n') { - if (!isdelim && !sflag) - (void)printf("%s", lbuf); - break; - } - } - if (!isdelim) - continue; - - pos = positions + 1; - for (field = maxval, p = lbuf; field; --field, ++pos) { - if (*pos) { - if (output++) - (void)putchar(sep); - while ((ch = *p++) != '\n' && ch != sep) - (void)putchar(ch); - } else { - while ((ch = *p++) != '\n' && ch != sep) - continue; - } - if (ch == '\n') - break; - } - if (ch != '\n') { - if (autostop) { - if (output) - (void)putchar(sep); - for (; (ch = *p) != '\n'; ++p) - (void)putchar(ch); - } else - for (; (ch = *p) != '\n'; ++p); - } - (void)putchar('\n'); - } - return (0); -} - -/* - * Get next token from string *stringp, where tokens are possibly-empty - * strings separated by characters from delim. - * - * Writes NULs into the string at *stringp to end tokens. - * delim need not remain constant from call to call. - * On return, *stringp points past the last NUL written (if there might - * be further tokens), or is NULL (if there are definitely no more tokens). - * - * If *stringp is NULL, strsep returns NULL. - */ -static char * -_cut_strsep(stringp, delim) - register char **stringp; - register const char *delim; -{ - register char *s; - register const char *spanp; - register int c, sc; - char *tok; - - if ((s = *stringp) == NULL) - return (NULL); - for (tok = s;;) { - c = *s++; - spanp = delim; - do { - if ((sc = *spanp++) == c) { - if (c == 0) - s = NULL; - else - s[-1] = 0; - *stringp = s; - return (tok); - } - } while (sc != 0); - } - /* NOTREACHED */ -} - -static char *cut_doc[] = { - "Select portions of each line (as specified by LIST) from each FILE", - "(by default, the standard input), and write them to the standard output.", - "Items specified by LIST are either column positions or fields delimited", - "by a special character. Column numbering starts at 1.", - (char *)0 -}; - -struct builtin cut_struct = { - "cut", - cut_builtin, - BUILTIN_ENABLED, - cut_doc, - "cut -b list [-n] [file ...] OR cut -c list [file ...] OR cut -f list [-s] [-d delim] [file ...]", - 0 -}; diff --git a/examples/loadables/dirname.c~ b/examples/loadables/dirname.c~ deleted file mode 100644 index 129ae7a99..000000000 --- a/examples/loadables/dirname.c~ +++ /dev/null @@ -1,96 +0,0 @@ -/* dirname - return directory portion of pathname */ - -/* See Makefile for compilation details. */ - -#include "config.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include "builtins.h" -#include "shell.h" -#include "common.h" - -dirname_builtin (list) - WORD_LIST *list; -{ - int slen; - char *string; - - if (list == 0 || list->next) - { - builtin_usage (); - return (EX_USAGE); - } - - if (no_options (list)) - return (EX_USAGE); - - string = list->word->word; - slen = strlen (string); - - /* Strip trailing slashes */ - while (slen > 0 && string[slen - 1] == '/') - slen--; - - /* (2) If string consists entirely of slash characters, string shall be - set to a single slash character. In this case, skip steps (3) - through (8). */ - if (slen == 0) - { - fputs ("/\n", stdout); - return (EXECUTION_SUCCESS); - } - - /* (3) If there are any trailing slash characters in string, they - shall be removed. */ - string[slen] = '\0'; - - /* (4) If there are no slash characters remaining in string, string - shall be set to a single period character. In this case, skip - steps (5) through (8). - - (5) If there are any trailing nonslash characters in string, - they shall be removed. */ - - while (--slen >= 0) - if (string[slen] == '/') - break; - - if (slen < 0) - { - fputs (".\n", stdout); - return (EXECUTION_SUCCESS); - } - - /* (7) If there are any trailing slash characters in string, they - shall be removed. */ - while (--slen >= 0) - if (string[slen] != '/') - break; - string[++slen] = '\0'; - - /* (8) If the remaining string is empty, string shall be set to a single - slash character. */ - printf ("%s\n", (slen == 0) ? "/" : string); - return (EXECUTION_SUCCESS); -} - -char *dirname_doc[] = { - "The STRING is converted to the name of the directory containing", - "the filename corresponding to the last pathname component in STRING.", - (char *)NULL -}; - -/* The standard structure describing a builtin command. bash keeps an array - of these structures. */ -struct builtin dirname_struct = { - "dirname", /* builtin name */ - dirname_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - dirname_doc, /* array of long documentation strings. */ - "dirname string", /* usage synopsis */ - 0 /* reserved for internal use */ -}; diff --git a/examples/loadables/finfo.c~ b/examples/loadables/finfo.c~ deleted file mode 100644 index 99d73e277..000000000 --- a/examples/loadables/finfo.c~ +++ /dev/null @@ -1,597 +0,0 @@ -/* - * finfo - print file info - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include "posixstat.h" -#include -#include -#include -#include -#include "posixtime.h" - -#include "bashansi.h" -#include "shell.h" -#include "builtins.h" -#include "common.h" - -#ifndef errno -extern int errno; -#endif - -extern char **make_builtin_argv (); - -static int printst(); -static int printsome(); -static int printfinfo(); -static int finfo_main(); - -extern int sh_optind; -extern char *sh_optarg; -extern char *this_command_name; - -static char *prog; -static int pmask; - -#define OPT_UID 0x00001 -#define OPT_GID 0x00002 -#define OPT_DEV 0x00004 -#define OPT_INO 0x00008 -#define OPT_PERM 0x00010 -#define OPT_LNKNAM 0x00020 -#define OPT_FID 0x00040 -#define OPT_NLINK 0x00080 -#define OPT_RDEV 0x00100 -#define OPT_SIZE 0x00200 -#define OPT_ATIME 0x00400 -#define OPT_MTIME 0x00800 -#define OPT_CTIME 0x01000 -#define OPT_BLKSIZE 0x02000 -#define OPT_BLKS 0x04000 -#define OPT_FTYPE 0x08000 -#define OPT_PMASK 0x10000 -#define OPT_OPERM 0x20000 - -#define OPT_ASCII 0x1000000 - -#define OPTIONS "acdgiflmnopsuACGMP:U" - -static int -octal(s) -char *s; -{ - int r; - - r = *s - '0'; - while (*++s >= '0' && *s <= '7') - r = (r * 8) + (*s - '0'); - return r; -} - -static int -finfo_main(argc, argv) -int argc; -char **argv; -{ - register int i; - int mode, flags, opt; - - sh_optind = 0; /* XXX */ - prog = base_pathname(argv[0]); - if (argc == 1) { - builtin_usage(); - return(1); - } - flags = 0; - while ((opt = sh_getopt(argc, argv, OPTIONS)) != EOF) { - switch(opt) { - case 'a': flags |= OPT_ATIME; break; - case 'A': flags |= OPT_ATIME|OPT_ASCII; break; - case 'c': flags |= OPT_CTIME; break; - case 'C': flags |= OPT_CTIME|OPT_ASCII; break; - case 'd': flags |= OPT_DEV; break; - case 'i': flags |= OPT_INO; break; - case 'f': flags |= OPT_FID; break; - case 'g': flags |= OPT_GID; break; - case 'G': flags |= OPT_GID|OPT_ASCII; break; - case 'l': flags |= OPT_LNKNAM; break; - case 'm': flags |= OPT_MTIME; break; - case 'M': flags |= OPT_MTIME|OPT_ASCII; break; - case 'n': flags |= OPT_NLINK; break; - case 'o': flags |= OPT_OPERM; break; - case 'p': flags |= OPT_PERM; break; - case 'P': flags |= OPT_PMASK; pmask = octal(sh_optarg); break; - case 's': flags |= OPT_SIZE; break; - case 'u': flags |= OPT_UID; break; - case 'U': flags |= OPT_UID|OPT_ASCII; break; - default: builtin_usage (); return(1); - } - } - - argc -= sh_optind; - argv += sh_optind; - - if (argc == 0) { - builtin_usage(); - return(1); - } - - for (i = 0; i < argc; i++) - opt = flags ? printsome (argv[i], flags) : printfinfo(argv[i]); - - return(opt); -} - -static struct stat * -getstat(f) -char *f; -{ - static struct stat st; - int fd, r; - intmax_t lfd; - - if (strncmp(f, "/dev/fd/", 8) == 0) { - if ((legal_number(f + 8, &lfd) == 0) || (int)lfd != lfd) { - builtin_error("%s: invalid fd", f + 8); - return ((struct stat *)0); - } - fd = lfd; - r = fstat(fd, &st); - } else -#ifdef HAVE_LSTAT - r = lstat(f, &st); -#else - r = stat(f, &st); -#endif - if (r < 0) { - builtin_error("%s: cannot stat: %s", f, strerror(errno)); - return ((struct stat *)0); - } - return (&st); -} - -static int -printfinfo(f) -char *f; -{ - struct stat *st; - - st = getstat(f); - return (st ? printst(st) : 1); -} - -static int -getperm(m) -int m; -{ - return (m & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID)); -} - -static int -perms(m) -int m; -{ - char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */ - int i; - - i = 0; - if (m & S_IRUSR) - ubits[i++] = 'r'; - if (m & S_IWUSR) - ubits[i++] = 'w'; - if (m & S_IXUSR) - ubits[i++] = 'x'; - ubits[i] = '\0'; - - i = 0; - if (m & S_IRGRP) - gbits[i++] = 'r'; - if (m & S_IWGRP) - gbits[i++] = 'w'; - if (m & S_IXGRP) - gbits[i++] = 'x'; - gbits[i] = '\0'; - - i = 0; - if (m & S_IROTH) - obits[i++] = 'r'; - if (m & S_IWOTH) - obits[i++] = 'w'; - if (m & S_IXOTH) - obits[i++] = 'x'; - obits[i] = '\0'; - - if (m & S_ISUID) - ubits[2] = (m & S_IXUSR) ? 's' : 'S'; - if (m & S_ISGID) - gbits[2] = (m & S_IXGRP) ? 's' : 'S'; - if (m & S_ISVTX) - obits[2] = (m & S_IXOTH) ? 't' : 'T'; - - printf ("u=%s,g=%s,o=%s", ubits, gbits, obits); -} - -static int -printmode(mode) -int mode; -{ - if (S_ISBLK(mode)) - printf("S_IFBLK "); - if (S_ISCHR(mode)) - printf("S_IFCHR "); - if (S_ISDIR(mode)) - printf("S_IFDIR "); - if (S_ISREG(mode)) - printf("S_IFREG "); - if (S_ISFIFO(mode)) - printf("S_IFIFO "); - if (S_ISLNK(mode)) - printf("S_IFLNK "); - if (S_ISSOCK(mode)) - printf("S_IFSOCK "); -#ifdef S_ISWHT - if (S_ISWHT(mode)) - printf("S_ISWHT "); -#endif - perms(getperm(mode)); - printf("\n"); -} - -static int -printst(st) -struct stat *st; -{ - struct passwd *pw; - struct group *gr; - char *owner; - int ma, mi, d; - - ma = major (st->st_rdev); - mi = minor (st->st_rdev); -#if defined (makedev) - d = makedev (ma, mi); -#else - d = st->st_rdev & 0xFF; -#endif - printf("Device (major/minor): %d (%d/%d)\n", d, ma, mi); - - printf("Inode: %d\n", (int) st->st_ino); - printf("Mode: (%o) ", (int) st->st_mode); - printmode((int) st->st_mode); - printf("Link count: %d\n", (int) st->st_nlink); - pw = getpwuid(st->st_uid); - owner = pw ? pw->pw_name : "unknown"; - printf("Uid of owner: %d (%s)\n", (int) st->st_uid, owner); - gr = getgrgid(st->st_gid); - owner = gr ? gr->gr_name : "unknown"; - printf("Gid of owner: %d (%s)\n", (int) st->st_gid, owner); - printf("Device type: %d\n", (int) st->st_rdev); - printf("File size: %ld\n", (long) st->st_size); - printf("File last access time: %s", ctime (&st->st_atime)); - printf("File last modify time: %s", ctime (&st->st_mtime)); - printf("File last status change time: %s", ctime (&st->st_ctime)); - fflush(stdout); - return(0); -} - -static int -printsome(f, flags) -char *f; -int flags; -{ - struct stat *st; - struct passwd *pw; - struct group *gr; - int p; - char *b; - - st = getstat(f); - if (st == NULL) - return (1); - - /* Print requested info */ - if (flags & OPT_ATIME) { - if (flags & OPT_ASCII) - printf("%s", ctime(&st->st_atime)); - else - printf("%ld\n", st->st_atime); - } else if (flags & OPT_MTIME) { - if (flags & OPT_ASCII) - printf("%s", ctime(&st->st_mtime)); - else - printf("%ld\n", st->st_mtime); - } else if (flags & OPT_CTIME) { - if (flags & OPT_ASCII) - printf("%s", ctime(&st->st_ctime)); - else - printf("%ld\n", st->st_ctime); - } else if (flags & OPT_DEV) - printf("%d\n", st->st_dev); - else if (flags & OPT_INO) - printf("%d\n", st->st_ino); - else if (flags & OPT_FID) - printf("%d:%ld\n", st->st_dev, st->st_ino); - else if (flags & OPT_NLINK) - printf("%d\n", st->st_nlink); - else if (flags & OPT_LNKNAM) { -#ifdef S_ISLNK - b = xmalloc(4096); - p = readlink(f, b, 4096); - if (p >= 0 && p < 4096) - b[p] = '\0'; - else { - p = errno; - strcpy(b, prog); - strcat(b, ": "); - strcat(b, strerror(p)); - } - printf("%s\n", b); - free(b); -#else - printf("%s\n", f); -#endif - } else if (flags & OPT_PERM) { - perms(st->st_mode); - printf("\n"); - } else if (flags & OPT_OPERM) - printf("%o\n", getperm(st->st_mode)); - else if (flags & OPT_PMASK) - printf("%o\n", getperm(st->st_mode) & pmask); - else if (flags & OPT_UID) { - pw = getpwuid(st->st_uid); - if (flags & OPT_ASCII) - printf("%s\n", pw ? pw->pw_name : "unknown"); - else - printf("%d\n", st->st_uid); - } else if (flags & OPT_GID) { - gr = getgrgid(st->st_gid); - if (flags & OPT_ASCII) - printf("%s\n", gr ? gr->gr_name : "unknown"); - else - printf("%d\n", st->st_gid); - } else if (flags & OPT_SIZE) - printf("%ld\n", st->st_size); - - return (0); -} - -#ifndef NOBUILTIN -int -finfo_builtin(list) - WORD_LIST *list; -{ - int c, r; - char **v; - WORD_LIST *l; - - v = make_builtin_argv (list, &c); - r = finfo_main (c, v); - free (v); - - return r; -} - -static char *finfo_doc[] = { - "Display information about each FILE. Only single operators should", - "be supplied. If no options are supplied, a summary of the info", - "available about each FILE is printed. If FILE is of the form", - "/dev/fd/XX, file descriptor XX is described. Operators, if supplied,", - "have the following meanings:", - "", - " -a last file access time", - " -A last file access time in ctime format", - " -c last file status change time", - " -C last file status change time in ctime format", - " -m last file modification time", - " -M last file modification time in ctime format", - " -d device", - " -i inode", - " -f composite file identifier (device:inode)", - " -g gid of owner", - " -G group name of owner", - " -l name of file pointed to by symlink", - " -n link count", - " -o permissions in octal", - " -p permissions in ascii", - " -P mask permissions ANDed with MASK (like with umask)", - " -s file size in bytes", - " -u uid of owner", - " -U user name of owner", - (char *)0 -}; - -struct builtin finfo_struct = { - "finfo", - finfo_builtin, - BUILTIN_ENABLED, - finfo_doc, - "finfo [-acdgiflmnopsuACGMPU] file [file...]", - 0 -}; -#endif - -#ifdef NOBUILTIN -#if defined (PREFER_STDARG) -# include -#else -# if defined (PREFER_VARARGS) -# include -# endif -#endif - -char *this_command_name; - -main(argc, argv) -int argc; -char **argv; -{ - this_command_name = argv[0]; - exit(finfo_main(argc, argv)); -} - -void -builtin_usage() -{ - fprintf(stderr, "%s: usage: %s [-%s] [file ...]\n", prog, OPTIONS); -} - -#ifndef HAVE_STRERROR -char * -strerror(e) -int e; -{ - static char ebuf[40]; - extern int sys_nerr; - extern char *sys_errlist[]; - - if (e < 0 || e > sys_nerr) { - sprintf(ebuf,"Unknown error code %d", e); - return (&ebuf[0]); - } - return (sys_errlist[e]); -} -#endif - -char * -xmalloc(s) -size_t s; -{ - char *ret; - extern char *malloc(); - - ret = malloc(s); - if (ret) - return (ret); - fprintf(stderr, "%s: cannot malloc %d bytes\n", prog, s); - exit(1); -} - -char * -base_pathname(p) -char *p; -{ - char *t; - - if (t = strrchr(p, '/')) - return(++t); - return(p); -} - -int -legal_number (string, result) - char *string; - long *result; -{ - int sign; - long value; - - sign = 1; - value = 0; - - if (result) - *result = 0; - - /* Skip leading whitespace characters. */ - while (whitespace (*string)) - string++; - - if (!*string) - return (0); - - /* We allow leading `-' or `+'. */ - if (*string == '-' || *string == '+') - { - if (!digit (string[1])) - return (0); - - if (*string == '-') - sign = -1; - - string++; - } - - while (digit (*string)) - { - if (result) - value = (value * 10) + digit_value (*string); - string++; - } - - /* Skip trailing whitespace, if any. */ - while (whitespace (*string)) - string++; - - /* Error if not at end of string. */ - if (*string) - return (0); - - if (result) - *result = value * sign; - - return (1); -} - -int sh_optind; -char *sh_optarg; -int sh_opterr; - -extern int optind; -extern char *optarg; - -int -sh_getopt(c, v, o) -int c; -char **v, *o; -{ - int r; - - r = getopt(c, v, o); - sh_optind = optind; - sh_optarg = optarg; - return r; -} - -#if defined (USE_VARARGS) -void -#if defined (PREFER_STDARG) -builtin_error (const char *format, ...) -#else -builtin_error (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - - if (this_command_name && *this_command_name) - fprintf (stderr, "%s: ", this_command_name); - -#if defined (PREFER_STDARG) - va_start (args, format); -#else - va_start (args); -#endif - - vfprintf (stderr, format, args); - va_end (args); - fprintf (stderr, "\n"); -} -#else -void -builtin_error (format, arg1, arg2, arg3, arg4, arg5) - char *format, *arg1, *arg2, *arg3, *arg4, *arg5; -{ - if (this_command_name && *this_command_name) - fprintf (stderr, "%s: ", this_command_name); - - fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); - fprintf (stderr, "\n"); - fflush (stderr); -} -#endif /* !USE_VARARGS */ - -#endif diff --git a/examples/loadables/getconf.c~ b/examples/loadables/getconf.c~ deleted file mode 100644 index 0bf20797d..000000000 --- a/examples/loadables/getconf.c~ +++ /dev/null @@ -1,1488 +0,0 @@ -/* - * ORIGINAL COPYRIGHT STATEMENT: - * - * Copyright (c) 1994 Winning Strategies, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Winning Strategies, Inc. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * POSIX.2 getconf utility - * - * Originally Written by: - * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc. - * - * Heavily modified for inclusion in bash by - * Chet Ramey - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef HAVE_SYS_PARAM_H -# include -#endif - -#include -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_LOCALE_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include - -#include "typemax.h" - -#include "bashansi.h" -#include "shell.h" -#include "builtins.h" -#include "stdc.h" -#include "common.h" -#include "bashgetopt.h" - -#include "getconf.h" - -#ifndef errno -extern int errno; -#endif - -struct conf_variable -{ - const char *name; - enum { SYSCONF, CONFSTR, PATHCONF, CONSTANT, LLCONST, G_UNDEF } type; - long value; -}; - -#ifndef HAVE_CONFSTR -static size_t confstr __P((int, char *, size_t)); -#endif - -#ifndef HAVE_SYSCONF -static long sysconf __P((int)); -#endif - -#ifndef HAVE_PATHCONF -static long pathconf __P((const char *, int)); -#endif - -/* Hack to `encode' values wider than long into a conf_variable */ -#define VAL_LLONG_MIN -1000 -#define VAL_LLONG_MAX -1001 -#define VAL_ULLONG_MAX -1002 - -static const struct conf_variable conf_table[] = -{ - /* POSIX.2 Configurable Variable Values */ - { "PATH", CONFSTR, _CS_PATH }, - { "CS_PATH", CONFSTR, _CS_PATH }, - - /* POSIX.1 Configurable Variable Values (only Solaris?) */ -#if defined (_CS_LFS_CFLAGS) - { "LFS_CFLAGS", CONFSTR, _CS_LFS_CFLAGS }, - { "LFS_LDFLAGS", CONFSTR, _CS_LFS_LDFLAGS }, - { "LFS_LIBS", CONFSTR, _CS_LFS_LIBS }, - { "LFS_LINTFLAGS", CONFSTR, _CS_LFS_LINTFLAGS }, -#endif -#if defined (_CS_LFS64_CFLAGS) - { "LFS64_CFLAGS", CONFSTR, _CS_LFS64_CFLAGS }, - { "LFS64_LDFLAGS", CONFSTR, _CS_LFS64_LDFLAGS }, - { "LFS64_LIBS", CONFSTR, _CS_LFS64_LIBS }, - { "LFS64_LINTFLAGS", CONFSTR, _CS_LFS64_LINTFLAGS }, -#endif - - /* Single UNIX Specification version 2 Configurable Variable Values. The - SYSCONF variables say whether or not the appropriate CONFSTR variables - are available. */ -#if defined (_SC_XBS5_ILP32_OFF32) - { "XBS5_ILP32_OFF32", SYSCONF, _SC_XBS5_ILP32_OFF32 }, - { "_XBS5_ILP32_OFF32", SYSCONF, _SC_XBS5_ILP32_OFF32 }, -#endif -#if defined (_CS_XBS5_ILP32_OFF32_CFLAGS) - { "XBS5_ILP32_OFF32_CFLAGS", CONFSTR, _CS_XBS5_ILP32_OFF32_CFLAGS }, - { "XBS5_ILP32_OFF32_LDFLAGS", CONFSTR, _CS_XBS5_ILP32_OFF32_LDFLAGS }, - { "XBS5_ILP32_OFF32_LIBS", CONFSTR, _CS_XBS5_ILP32_OFF32_LIBS }, - { "XBS5_ILP32_OFF32_LINTFLAGS", CONFSTR, _CS_XBS5_ILP32_OFF32_LINTFLAGS }, -#endif -#if defined (_SC_XBS5_ILP32_OFFBIG) - { "XBS5_ILP32_OFFBIG", SYSCONF, _SC_XBS5_ILP32_OFFBIG }, - { "_XBS5_ILP32_OFFBIG", SYSCONF, _SC_XBS5_ILP32_OFFBIG }, -#endif -#if defined (_CS_XBS5_ILP32_OFFBIG_CFLAGS) - { "XBS5_ILP32_OFFBIG_CFLAGS", CONFSTR, _CS_XBS5_ILP32_OFFBIG_CFLAGS }, - { "XBS5_ILP32_OFFBIG_LDFLAGS", CONFSTR, _CS_XBS5_ILP32_OFFBIG_LDFLAGS }, - { "XBS5_ILP32_OFFBIG_LIBS", CONFSTR, _CS_XBS5_ILP32_OFFBIG_LIBS }, - { "XBS5_ILP32_OFFBIG_LINTFLAGS", CONFSTR, _CS_XBS5_ILP32_OFFBIG_LINTFLAGS }, -#endif -#if defined (_SC_XBS5_LP64_OFF64) - { "XBS5_LP64_OFF64", SYSCONF, _SC_XBS5_LP64_OFF64 }, - { "_XBS5_LP64_OFF64", SYSCONF, _SC_XBS5_LP64_OFF64 }, -#endif -#if defined (_CS_XBS5_LP64_OFF64_CFLAGS) - { "XBS5_LP64_OFF64_CFLAGS", CONFSTR, _CS_XBS5_LP64_OFF64_CFLAGS }, - { "XBS5_LP64_OFF64_LDFLAGS", CONFSTR, _CS_XBS5_LP64_OFF64_LDFLAGS }, - { "XBS5_LP64_OFF64_LIBS", CONFSTR, _CS_XBS5_LP64_OFF64_LIBS }, - { "XBS5_LP64_OFF64_LINTFLAGS", CONFSTR, _CS_XBS5_LP64_OFF64_LINTFLAGS }, -#endif -#if defined (_SC_XBS5_LPBIG_OFFBIG) - { "XBS5_LPBIG_OFFBIG", SYSCONF, _SC_XBS5_LPBIG_OFFBIG }, - { "_XBS5_LPBIG_OFFBIG", SYSCONF, _SC_XBS5_LPBIG_OFFBIG }, -#endif -#if defined (_CS_XBS5_LPBIG_OFFBIG_CFLAGS) - { "XBS5_LPBIG_OFFBIG_CFLAGS", CONFSTR, _CS_XBS5_LPBIG_OFFBIG_CFLAGS }, - { "XBS5_LPBIG_OFFBIG_LDFLAGS", CONFSTR, _CS_XBS5_LPBIG_OFFBIG_LDFLAGS }, - { "XBS5_LPBIG_OFFBIG_LIBS", CONFSTR, _CS_XBS5_LPBIG_OFFBIG_LIBS }, - { "XBS5_LPBIG_OFFBIG_LINTFLAGS", CONFSTR, _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS }, -#endif - - /* Single UNIX Specification version 3 (POSIX.1-200x) Configurable Variable - Values. The SYSCONF variables say whether or not the appropriate CONFSTR - variables are available. */ - -#if defined (_SC_POSIX_V6_ILP32_OFF32) - { "_POSIX_V6_ILP32_OFF32", SYSCONF, _SC_POSIX_V6_ILP32_OFF32 }, -#endif -#if defined (_CS_POSIX_V6_ILP32_OFF32_CFLAGS) - { "POSIX_V6_ILP32_OFF32_CFLAGS", CONFSTR, _CS_POSIX_V6_ILP32_OFF32_CFLAGS }, - { "POSIX_V6_ILP32_OFF32_LDFLAGS", CONFSTR, _CS_POSIX_V6_ILP32_OFF32_LDFLAGS }, - { "POSIX_V6_ILP32_OFF32_LIBS", CONFSTR, _CS_POSIX_V6_ILP32_OFF32_LIBS }, -#endif -#if defined (_CS_POSIX_V6_ILP32_OFF32_LINTFLAGS) - { "POSIX_V6_ILP32_OFF32_LINTFLAGS", CONFSTR, _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS }, -#endif -#if defined (_SC_POSIX_V6_ILP32_OFFBIG) - { "_POSIX_V6_ILP32_OFFBIG", SYSCONF, _SC_POSIX_V6_ILP32_OFFBIG }, -#endif -#if defined (_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS) - { "POSIX_V6_ILP32_OFFBIG_CFLAGS", CONFSTR, _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS }, - { "POSIX_V6_ILP32_OFFBIG_LDFLAGS", CONFSTR, _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS }, - { "POSIX_V6_ILP32_OFFBIG_LIBS", CONFSTR, _CS_POSIX_V6_ILP32_OFFBIG_LIBS }, -#endif -#if defined (_CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS) - { "POSIX_V6_ILP32_OFFBIG_LINTFLAGS", CONFSTR, _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS }, -#endif -#if defined (_SC_POSIX_V6_LP64_OFF64) - { "_POSIX_V6_LP64_OFF64", SYSCONF, _SC_POSIX_V6_LP64_OFF64 }, -#endif -#if defined (_CS_POSIX_V6_LP64_OFF64_CFLAGS) - { "POSIX_V6_LP64_OFF64_CFLAGS", CONFSTR, _CS_POSIX_V6_LP64_OFF64_CFLAGS }, - { "POSIX_V6_LP64_OFF64_LDFLAGS", CONFSTR, _CS_POSIX_V6_LP64_OFF64_LDFLAGS }, - { "POSIX_V6_LP64_OFF64_LIBS", CONFSTR, _CS_POSIX_V6_LP64_OFF64_LIBS }, -#endif -#if defined (CS_POSIX_V6_LP64_OFF64_LINTFLAGS) - { "POSIX_V6_LP64_OFF64_LINTFLAGS", CONFSTR, _CS_POSIX_V6_LP64_OFF64_LINTFLAGS }, -#endif -#if defined (_SC_POSIX_V6_LPBIG_OFFBIG) - { "_POSIX_V6_LPBIG_OFFBIG", SYSCONF, _SC_POSIX_V6_LPBIG_OFFBIG }, -#endif -#if defined (_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS) - { "POSIX_V6_LPBIG_OFFBIG_CFLAGS", CONFSTR, _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS }, - { "POSIX_V6_LPBIG_OFFBIG_LDFLAGS", CONFSTR, _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS }, - { "POSIX_V6_LPBIG_OFFBIG_LIBS", CONFSTR, _CS_POSIX_V6_LPBIG_OFFBIG_LIBS }, -#endif -#if defined (_CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS) - { "POSIX_V6_LPBIG_OFFBIG_LINTFLAGS", CONFSTR, _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS }, -#endif - -#if defined (_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS) - { "POSIX_6_WIDTH_RESTRICTED_ENVS", CONFSTR, _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS }, -#endif - - /* POSIX.2 Utility Limit Minimum Values */ -#ifdef _POSIX2_BC_BASE_MAX - { "POSIX2_BC_BASE_MAX", CONSTANT, _POSIX2_BC_BASE_MAX }, -#else - { "POSIX2_BC_BASE_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_BC_DIM_MAX - { "POSIX2_BC_DIM_MAX", CONSTANT, _POSIX2_BC_DIM_MAX }, -#else - { "POSIX2_BC_DIM_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_BC_SCALE_MAX - { "POSIX2_BC_SCALE_MAX", CONSTANT, _POSIX2_BC_SCALE_MAX }, -#else - { "POSIX2_BC_SCALE_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_BC_STRING_MAX - { "POSIX2_BC_STRING_MAX", CONSTANT, _POSIX2_BC_STRING_MAX }, -#else - { "POSIX2_BC_STRING_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_CHARCLASS_NAME_MAX - { "POSIX2_CHARCLASS_NAME_MAX", CONSTANT, _POSIX2_CHARCLASS_NAME_MAX }, -#else - { "POSIX2_CHARCLASS_NAME_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_COLL_WEIGHTS_MAX - { "POSIX2_COLL_WEIGHTS_MAX", CONSTANT, _POSIX2_COLL_WEIGHTS_MAX }, -#else - { "POSIX2_COLL_WEIGHTS_MAX", G_UNDEF, -1 }, -#endif -#if defined (_POSIX2_EQUIV_CLASS_MAX) - { "POSIX2_EQUIV_CLASS_MAX", CONSTANT, _POSIX2_EQUIV_CLASS_MAX }, -#endif -#ifdef _POSIX2_EXPR_NEST_MAX - { "POSIX2_EXPR_NEST_MAX", CONSTANT, _POSIX2_EXPR_NEST_MAX }, -#else - { "POSIX2_EXPR_NEST_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_LINE_MAX - { "POSIX2_LINE_MAX", CONSTANT, _POSIX2_LINE_MAX }, -#else - { "POSIX2_LINE_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_RE_DUP_MAX - { "POSIX2_RE_DUP_MAX", CONSTANT, _POSIX2_RE_DUP_MAX }, -#else - { "POSIX2_RE_DUP_MAX", G_UNDEF, -1 }, -#endif -#if defined (_POSIX2_VERSION) - { "POSIX2_VERSION", CONSTANT, _POSIX2_VERSION }, -#else -# if !defined (_SC_2_VERSION) - { "POSIX2_VERSION", G_UNDEF, -1 }, -# endif -#endif - -#ifdef _POSIX2_BC_BASE_MAX - { "_POSIX2_BC_BASE_MAX", CONSTANT, _POSIX2_BC_BASE_MAX }, -#else - { "_POSIX2_BC_BASE_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_BC_DIM_MAX - { "_POSIX2_BC_DIM_MAX", CONSTANT, _POSIX2_BC_DIM_MAX }, -#else - { "_POSIX2_BC_DIM_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_BC_SCALE_MAX - { "_POSIX2_BC_SCALE_MAX", CONSTANT, _POSIX2_BC_SCALE_MAX }, -#else - { "_POSIX2_BC_SCALE_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_BC_STRING_MAX - { "_POSIX2_BC_STRING_MAX", CONSTANT, _POSIX2_BC_STRING_MAX }, -#else - { "_POSIX2_BC_STRING_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_CHARCLASS_NAME_MAX - { "_POSIX2_CHARCLASS_NAME_MAX", CONSTANT, _POSIX2_CHARCLASS_NAME_MAX }, -#else - { "_POSIX2_CHARCLASS_NAME_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_COLL_WEIGHTS_MAX - { "_POSIX2_COLL_WEIGHTS_MAX", CONSTANT, _POSIX2_COLL_WEIGHTS_MAX }, -#else - { "_POSIX2_COLL_WEIGHTS_MAX", G_UNDEF, -1 }, -#endif -#if defined (_POSIX2_EQUIV_CLASS_MAX) - { "POSIX2_EQUIV_CLASS_MAX", CONSTANT, _POSIX2_EQUIV_CLASS_MAX }, -#endif -#ifdef _POSIX2_EXPR_NEST_MAX - { "_POSIX2_EXPR_NEST_MAX", CONSTANT, _POSIX2_EXPR_NEST_MAX }, -#else - { "_POSIX2_EXPR_NEST_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_LINE_MAX - { "_POSIX2_LINE_MAX", CONSTANT, _POSIX2_LINE_MAX }, -#else - { "_POSIX2_LINE_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX2_RE_DUP_MAX - { "_POSIX2_RE_DUP_MAX", CONSTANT, _POSIX2_RE_DUP_MAX }, -#else - { "_POSIX2_RE_DUP_MAX", G_UNDEF, -1 }, -#endif - - /* X/OPEN Maxmimum Values */ -#ifdef _XOPEN_IOV_MAX - { "_XOPEN_IOV_MAX", CONSTANT, _XOPEN_IOV_MAX }, -#else - { "_XOPEN_IOV_MAX", G_UNDEF, -1 }, -#endif -#ifdef _XOPEN_NAME_MAX - { "_XOPEN_NAME_MAX", CONSTANT, _XOPEN_NAME_MAX }, -#else - { "_XOPEN_NAME_MAX", G_UNDEF, -1 }, -#endif -#ifdef _XOPEN_PATH_MAX - { "_XOPEN_PATH_MAX", CONSTANT, _XOPEN_PATH_MAX }, -#else - { "_XOPEN_PATH_MAX", G_UNDEF, -1 }, -#endif - - /* POSIX.1 Minimum Values */ -#ifdef _POSIX_AIO_LISTIO_MAX - { "_POSIX_AIO_LISTIO_MAX", CONSTANT, _POSIX_AIO_LISTIO_MAX }, -#else - { "_POSIX_AIO_LISTIO_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_AIO_MAX - { "_POSIX_AIO_MAX", CONSTANT, _POSIX_AIO_MAX }, -#else - { "_POSIX_AIO_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_ARG_MAX - { "_POSIX_ARG_MAX", CONSTANT, _POSIX_ARG_MAX }, -#else - { "_POSIX_ARG_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_CHILD_MAX - { "_POSIX_CHILD_MAX", CONSTANT, _POSIX_CHILD_MAX }, -#else - { "_POSIX_CHILD_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_DELAYTIMER_MAX - { "_POSIX_DELAYTIMER_MAX", CONSTANT, _POSIX_DELAYTIMER_MAX }, -#else - { "_POSIX_DELAYTIMER_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_HOST_NAME_MAX - { "_POSIX_HOST_NAME_MAX", CONSTANT, _POSIX_HOST_NAME_MAX }, -#else - { "_POSIX_HOST_NAME_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_LINK_MAX - { "_POSIX_LINK_MAX", CONSTANT, _POSIX_LINK_MAX }, -#else - { "_POSIX_LINK_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_LOGIN_NAME_MAX - { "_POSIX_LOGIN_NAME_MAX", CONSTANT, _POSIX_LOGIN_NAME_MAX }, -#else - { "_POSIX_LOGIN_NAME_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_MAX_CANON - { "_POSIX_MAX_CANON", CONSTANT, _POSIX_MAX_CANON }, -#else - { "_POSIX_MAX_CANON", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_MAX_INPUT - { "_POSIX_MAX_INPUT", CONSTANT, _POSIX_MAX_INPUT }, -#else - { "_POSIX_MAX_INPUT", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_MQ_OPEN_MAX - { "_POSIX_MQ_OPEN_MAX", CONSTANT, _POSIX_MQ_OPEN_MAX }, -#else - { "_POSIX_MQ_OPEN_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_MQ_PRIO_MAX - { "_POSIX_MQ_PRIO_MAX", CONSTANT, _POSIX_MQ_PRIO_MAX }, -#else - { "_POSIX_MQ_PRIO_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_NAME_MAX - { "_POSIX_NAME_MAX", CONSTANT, _POSIX_NAME_MAX }, -#else - { "_POSIX_NAME_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_NGROUPS_MAX - { "_POSIX_NGROUPS_MAX", CONSTANT, _POSIX_NGROUPS_MAX }, -#else - { "_POSIX_NGROUPS_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_OPEN_MAX - { "_POSIX_OPEN_MAX", CONSTANT, _POSIX_OPEN_MAX }, -#else - { "_POSIX_OPEN_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_PATH_MAX - { "_POSIX_PATH_MAX", CONSTANT, _POSIX_PATH_MAX }, -#else - { "_POSIX_PATH_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_PIPE_BUF - { "_POSIX_PIPE_BUF", CONSTANT, _POSIX_PIPE_BUF }, -#else - { "_POSIX_PIPE_BUF", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_RE_DUP_MAX - { "_POSIX_RE_DUP_MAX", CONSTANT, _POSIX_RE_DUP_MAX }, -#else - { "_POSIX_RE_DUP_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_RTSIG_MAX - { "_POSIX_RTSIG_MAX", CONSTANT, _POSIX_RTSIG_MAX }, -#else - { "_POSIX_RTSIG_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_SEM_NSEMS_MAX - { "_POSIX_SEM_NSEMS_MAX", CONSTANT, _POSIX_SEM_NSEMS_MAX }, -#else - { "_POSIX_SEM_NSEMS_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_SEM_VALUE_MAX - { "_POSIX_SEM_VALUE_MAX", CONSTANT, _POSIX_SEM_VALUE_MAX }, -#else - { "_POSIX_SEM_VALUE_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_SIGQUEUE_MAX - { "_POSIX_SIGQUEUE_MAX", CONSTANT, _POSIX_SIGQUEUE_MAX }, -#else - { "_POSIX_SIGQUEUE_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_SSIZE_MAX - { "_POSIX_SSIZE_MAX", CONSTANT, _POSIX_SSIZE_MAX }, -#else - { "_POSIX_SSIZE_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_SS_REPL_MAX - { "_POSIX_SS_REPL_MAX", CONSTANT, _POSIX_SS_REPL_MAX }, -#else - { "_POSIX_SS_REPL_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_STREAM_MAX - { "_POSIX_STREAM_MAX", CONSTANT, _POSIX_STREAM_MAX }, -#else - { "_POSIX_STREAM_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_SYMLINK_MAX - { "_POSIX_SYMLINK_MAX", CONSTANT, _POSIX_SYMLINK_MAX }, -#else - { "_POSIX_SYMLINK_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_SYMLOOP_MAX - { "_POSIX_SYMLOOP_MAX", CONSTANT, _POSIX_SYMLOOP_MAX }, -#else - { "_POSIX_SYMLOOP_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_THREAD_DESTRUCTOR_ITERATIONS - { "_POSIX_THREAD_DESTRUCTOR_ITERATIONS", CONSTANT, _POSIX_THREAD_DESTRUCTOR_ITERATIONS }, -#else - { "_POSIX_THREAD_DESTRUCTOR_ITERATIONS", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_THREAD_KEYS_MAX - { "_POSIX_THREAD_KEYS_MAX", CONSTANT, _POSIX_THREAD_KEYS_MAX }, -#else - { "_POSIX_THREAD_KEYS_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_THREAD_THREADS_MAX - { "_POSIX_THREAD_THREADS_MAX",CONSTANT, _POSIX_THREAD_THREADS_MAX }, -#else - { "_POSIX_THREAD_THREADS_MAX",G_UNDEF, -1 }, -#endif -#ifdef _POSIX_TIMER_MAX - { "_POSIX_TIMER_MAX", CONSTANT, _POSIX_TIMER_MAX }, -#else - { "_POSIX_TIMER_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_TRACE_EVENT_NAME_MAX - { "_POSIX_TRACE_EVENT_NAME_MAX", CONSTANT, _POSIX_TRACE_EVENT_NAME_MAX }, -#else - { "_POSIX_TRACE_EVENT_NAME_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_TRACE_NAME_MAX - { "_POSIX_TRACE_NAME_MAX", CONSTANT, _POSIX_TRACE_NAME_MAX }, -#else - { "_POSIX_TRACE_NAME_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_TRACE_SYS_MAX - { "_POSIX_TRACE_SYS_MAX", CONSTANT, _POSIX_TRACE_SYS_MAX }, -#else - { "_POSIX_TRACE_SYS_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_TRACE_USER_EVENT_MAX - { "_POSIX_TRACE_USER_EVENT_MAX", CONSTANT, _POSIX_TRACE_USER_EVENT_MAX }, -#else - { "_POSIX_TRACE_USER_EVENT_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_TTY_NAME_MAX - { "_POSIX_TTY_NAME_MAX", CONSTANT, _POSIX_TTY_NAME_MAX }, -#else - { "_POSIX_TTY_NAME_MAX", G_UNDEF, -1 }, -#endif -#ifdef _POSIX_TZNAME_MAX - { "_POSIX_TZNAME_MAX", CONSTANT, _POSIX_TZNAME_MAX }, -#else - { "_POSIX_TZNAME_MAX", G_UNDEF, -1 }, -#endif - - /* POSIX.1 Maximum Values */ -#ifdef _POSIX_CLOCKRES_MIN - { "_POSIX_CLOCKRES_MIN", CONSTANT, _POSIX_CLOCKRES_MIN }, -#else - { "_POSIX_CLOCKRES_MIN", G_UNDEF, -1 }, -#endif - - /* POSIX.1-2001/XPG6 (and later) Runtime Invariants from */ -#ifdef _SC_SS_REPL_MAX - { "SS_REPL_MAX", SYSCONF, _SC_SS_REPL_MAX }, -#endif -#ifdef _SC_TRACE_EVENT_NAME_MAX - { "TRACE_EVENT_NAME_MAX", SYSCONF, _SC_TRACE_EVENT_NAME_MAX }, -#endif -#ifdef _SC_TRACE_NAME_MAX - { "TRACE_NAME_MAX", SYSCONF, _SC_TRACE_NAME_MAX }, -#endif -#ifdef _SC_TRACE_SYS_MAX - { "TRACE_SYS_MAX", SYSCONF, _SC_TRACE_SYS_MAX }, -#endif -#ifdef _SC_TRACE_USER_EVENT_MAX - { "TRACE_USER_EVENT_MAX", SYSCONF, _SC_TRACE_USER_EVENT_MAX }, -#endif - - /* POSIX.2/XPG 4.2 (and later) Symbolic Utility Limits */ -#ifdef _SC_BC_BASE_MAX - { "BC_BASE_MAX", SYSCONF, _SC_BC_BASE_MAX }, -#endif -#ifdef _SC_BC_DIM_MAX - { "BC_DIM_MAX", SYSCONF, _SC_BC_DIM_MAX }, -#endif -#ifdef _SC_BC_SCALE_MAX - { "BC_SCALE_MAX", SYSCONF, _SC_BC_SCALE_MAX }, -#endif -#ifdef _SC_BC_STRING_MAX - { "BC_STRING_MAX", SYSCONF, _SC_BC_STRING_MAX }, -#endif -#ifdef CHARCLASS_NAME_MAX - { "CHARCLASS_NAME_MAX", CONSTANT, CHARCLASS_NAME_MAX }, -#endif -#ifdef _SC_COLL_WEIGHTS_MAX - { "COLL_WEIGHTS_MAX", SYSCONF, _SC_COLL_WEIGHTS_MAX }, -#endif -#ifdef _SC_EXPR_NEST_MAX - { "EXPR_NEST_MAX", SYSCONF, _SC_EXPR_NEST_MAX }, -#endif -#ifdef _SC_LINE_MAX - { "LINE_MAX", SYSCONF, _SC_LINE_MAX }, -#endif -# ifdef NL_ARGMAX - { "NL_ARGMAX", CONSTANT, NL_ARGMAX }, -#endif -#ifdef NL_LANGMAX - { "NL_LANGMAX", CONSTANT, NL_LANGMAX }, -#endif -#ifdef NL_MSGMAX - { "NL_MSGMAX", CONSTANT, NL_MSGMAX }, -#endif -#ifdef NL_NMAX - { "NL_NMAX", CONSTANT, NL_NMAX }, -#endif -#ifdef NL_SETMAX - { "NL_SETMAX", CONSTANT, NL_SETMAX }, -#endif -#ifdef NL_TEXTMAX - { "NL_TEXTMAX", CONSTANT, NL_TEXTMAX }, -#endif -#ifdef _SC_RAW_SOCKET - { "RAW_SOCKET", SYSCONF, _SC_RAW_SOCKET }, -#endif -#ifdef _SC_RE_DUP_MAX - { "RE_DUP_MAX", SYSCONF, _SC_RE_DUP_MAX }, -#endif - - /* POSIX.2 Optional Facility Configuration Values */ -#ifdef _SC_2_C_BIND - { "POSIX2_C_BIND", SYSCONF, _SC_2_C_BIND }, -#else - { "POSIX2_C_BIND", G_UNDEF, -1 }, -#endif -#ifdef _SC_2_C_DEV - { "POSIX2_C_DEV", SYSCONF, _SC_2_C_DEV }, -#else - { "POSIX2_C_DEV", G_UNDEF, -1 }, -#endif -#if defined (_SC_2_C_VERSION) - { "POSIX2_C_VERSION", SYSCONF, _SC_2_C_VERSION }, -#else - { "POSIX2_C_VERSION", G_UNDEF, -1 }, -#endif -#if defined (_SC_2_CHAR_TERM) - { "POSIX2_CHAR_TERM", SYSCONF, _SC_2_CHAR_TERM }, -#else - { "POSIX2_CHAR_TERM", G_UNDEF, -1 }, -#endif -#ifdef _SC_2_FORT_DEV - { "POSIX2_FORT_DEV", SYSCONF, _SC_2_FORT_DEV }, -#else - { "POSIX2_FORT_DEV", G_UNDEF, -1 }, -#endif -#ifdef _SC_2_FORT_RUN - { "POSIX2_FORT_RUN", SYSCONF, _SC_2_FORT_RUN }, -#else - { "POSIX2_FORT_RUN", G_UNDEF, -1 }, -#endif -#ifdef _SC_2_LOCALEDEF - { "POSIX2_LOCALEDEF", SYSCONF, _SC_2_LOCALEDEF }, -#else - { "POSIX2_LOCALEDEF", G_UNDEF, -1 }, -#endif -#ifdef _SC_2_SW_DEV - { "POSIX2_SW_DEV", SYSCONF, _SC_2_SW_DEV }, -#else - { "POSIX2_SW_DEV", G_UNDEF, -1 }, -#endif -#if defined (_SC2_UPE) - { "POSIX2_UPE", SYSCONF, _SC_2_UPE }, -#else - { "POSIX2_UPE", G_UNDEF, -1 }, -#endif -#if !defined (_POSIX2_VERSION) && defined (_SC_2_VERSION) - { "_POSIX2_VERSION", SYSCONF, _SC_2_VERSION }, -#else - { "_POSIX2_VERSION", G_UNDEF, -1 }, -#endif -#if defined (_SC_REGEX_VERSION) - { "REGEX_VERSION", SYSCONF, _SC_REGEX_VERSION }, - { "_REGEX_VERSION", SYSCONF, _SC_REGEX_VERSION }, -#else - { "REGEX_VERSION", G_UNDEF, -1 }, - { "_REGEX_VERSION", G_UNDEF, -1 }, -#endif - -#if defined (_SC_2_PBS) - { "_POSIX2_PBS", SYSCONF, _SC_2_PBS }, - { "_POSIX2_PBS_ACCOUNTING", SYSCONF, _SC_2_PBS_ACCOUNTING }, -# if defined (_SC_2_PBS_CHECKPOINT) - { "_POSIX2_PBS_CHECKPOINT", SYSCONF, _SC_2_PBS_CHECKPOINT }, -# endif - { "_POSIX2_PBS_LOCATE", SYSCONF, _SC_2_PBS_LOCATE }, - { "_POSIX2_PBS_MESSAGE", SYSCONF, _SC_2_PBS_MESSAGE }, - { "_POSIX2_PBS_TRACK", SYSCONF, _SC_2_PBS_TRACK }, -#endif - - /* POSIX.1 Configurable System Variables */ -#ifdef _SC_ARG_MAX - { "ARG_MAX", SYSCONF, _SC_ARG_MAX }, -#endif -#ifdef _SC_CHILD_MAX - { "CHILD_MAX", SYSCONF, _SC_CHILD_MAX }, -#endif -#ifdef _SC_CLK_TCK - { "CLK_TCK", SYSCONF, _SC_CLK_TCK }, -#endif -#ifdef _SC_DELAYTIMER_MAX - { "DELAYTIMER_MAX", SYSCONF, _SC_DELAYTIMER_MAX }, -#endif -#ifdef _SC_NGROUPS_MAX - { "NGROUPS_MAX", SYSCONF, _SC_NGROUPS_MAX }, -#endif -#ifdef NZERO - { "NZERO", CONSTANT, NZERO }, -#endif -#ifdef _SC_OPEN_MAX - { "OPEN_MAX", SYSCONF, _SC_OPEN_MAX }, -#endif -#ifdef PASS_MAX - { "PASS_MAX", CONSTANT, PASS_MAX }, -#endif -#ifdef _SC_STREAM_MAX - { "STREAM_MAX", SYSCONF, _SC_STREAM_MAX }, -#endif -#ifdef TMP_MAX - { "TMP_MAX", CONSTANT, TMP_MAX }, -#endif -#ifdef _SC_TZNAME_MAX - { "TZNAME_MAX", SYSCONF, _SC_TZNAME_MAX }, -#endif - - /* POSIX.1 Optional Facility Configuration Values */ -#if defined (_SC_ADVISORY_INFO) - { "_POSIX_ADVISORY_INFO", SYSCONF, _SC_ADVISORY_INFO }, -#endif -#if defined (_SC_ASYNCHRONOUS_IO) - { "_POSIX_ASYNCHRONOUS_IO", SYSCONF, _SC_ASYNCHRONOUS_IO }, -#endif -#if defined (_SC_BARRIERS) - { "_POSIX_BARRIERS", SYSCONF, _SC_BARRIERS }, -#endif -#if defined (_SC_BASE) - { "_POSIX_BASE", SYSCONF, _SC_BASE }, -#endif -#if defined (_SC_C_LANG_SUPPORT) - { "_POSIX_C_LANG_SUPPORT", SYSCONF, _SC_C_LANG_SUPPORT }, -#endif -#if defined (_SC_C_LANG_SUPPORT_R) - { "_POSIX_C_LANG_SUPPORT_R", SYSCONF, _SC_C_LANG_SUPPORT_R }, -#endif -#if defined (_SC_CLOCK_SELECTION) - { "_POSIX_CLOCK_SELECTION", SYSCONF, _SC_CLOCK_SELECTION }, -#endif -#if defined (_SC_CPUTIME) - { "_POSIX_CPUTIME", SYSCONF, _SC_CPUTIME }, -#endif -#if defined (_SC_DEVICE_IO) - { "_POSIX_DEVICE_IO", SYSCONF, _SC_DEVICE_IO }, -#endif -#if defined (_SC_DEVICE_SPECIFIC) - { "_POSIX_DEVICE_SPECIFIC", SYSCONF, _SC_DEVICE_SPECIFIC }, -#endif -#if defined (_SC_DEVICE_SPECIFIC_R) - { "_POSIX_DEVICE_SPECIFIC_R", SYSCONF, _SC_DEVICE_SPECIFIC_R }, -#endif -#if defined (_SC_FD_MGMT) - { "_POSIX_FD_MGMT", SYSCONF, _SC_FD_MGMT }, -#endif -#if defined (_SC_FIFO) - { "_POSIX_FIFO", SYSCONF, _SC_FIFO }, -#endif -#if defined (_SC_FILE_ATTRIBUTES) - { "_POSIX_FILE_ATTRIBUTES", SYSCONF, _SC_FILE_ATTRIBUTES }, -#endif -#if defined (_SC_FILE_LOCKING) - { "_POSIX_FILE_LOCKING", SYSCONF, _SC_FILE_LOCKING }, -#endif -#if defined (_SC_FILE_SYSTEM) - { "_POSIX_FILE_SYSTEM", SYSCONF, _SC_FILE_SYSTEM }, -#endif -#if defined (_SC_FSYNC) - { "_POSIX_FSYNC", SYSCONF, _SC_FSYNC }, -#endif -#if defined (_SC_IPV6) - { "_POSIX_IPV6", SYSCONF, _SC_IPV6 }, -#endif -#if defined (_SC_JOB_CONTROL) - { "_POSIX_JOB_CONTROL", SYSCONF, _SC_JOB_CONTROL }, -#endif -#if defined (_SC_MAPPED_FILES) - { "_POSIX_MAPPED_FILES", SYSCONF, _SC_MAPPED_FILES }, -#endif -#if defined (_SC_MEMLOCK) - { "_POSIX_MEMLOCK", SYSCONF, _SC_MEMLOCK }, -#endif -#if defined (_SC_MEMLOCK_RANGE) - { "_POSIX_MEMLOCK_RANGE", SYSCONF, _SC_MEMLOCK_RANGE }, -#endif -#if defined (_SC_MEMORY_PROTECTION) - { "_POSIX_MEMORY_PROTECTION", SYSCONF, _SC_MEMORY_PROTECTION }, -#endif -#if defined (_SC_MESSAGE_PASSING) - { "_POSIX_MESSAGE_PASSING", SYSCONF, _SC_MESSAGE_PASSING }, -#endif -#if defined (_SC_MONOTONIC_CLOCK) - { "_POSIX_MONOTONIC_CLOCK", SYSCONF, _SC_MONOTONIC_CLOCK }, -#endif -#if defined (_SC_MULTI_PROCESS) - { "_POSIX_MULTI_PROCESS", SYSCONF, _SC_MULTI_PROCESS }, -#endif -#if defined (_SC_NETWORKING) - { "_POSIX_NETWORKING", SYSCONF, _SC_NETWORKING }, -#endif -#if defined (_SC_PIPE) - { "_POSIX_PIPE", SYSCONF, _SC_PIPE }, -#endif -#if defined (SC_PRIORITIZED_IO) - { "_POSIX_PRIORITIZED_IO", SYSCONF, _SC_PRIORITIZED_IO }, -#endif -#if defined (_SC_PRIORITY_SCHEDULING) - { "_POSIX_PRIORITY_SCHEDULING", SYSCONF, _SC_PRIORITY_SCHEDULING }, -#endif -#if defined (_SC_READER_WRITER_LOCKS) - { "_POSIX_READER_WRITER_LOCKS", SYSCONF, _SC_READER_WRITER_LOCKS }, -#endif -#if defined (_SC_RAW_SOCKETS) - { "_POSIX_RAW_SOCKETS", SYSCONF, _SC_RAW_SOCKETS }, -#endif -#if defined (_SC_REALTIME_SIGNALS) - { "_POSIX_REALTIME_SIGNALS", SYSCONF, _SC_REALTIME_SIGNALS }, -#endif -#if defined (_SC_REGEXP) - { "_POSIX_REGEXP", SYSCONF, _SC_REGEXP }, -#endif -#if defined (_SC_SAVED_IDS) - { "_POSIX_SAVED_IDS", SYSCONF, _SC_SAVED_IDS }, -#endif -#if defined (_SC_SEMAPHORES) - { "_POSIX_SEMAPHORES", SYSCONF, _SC_SEMAPHORES }, -#endif -#if defined (_SC_SHARED_MEMORY_OBJECTS) - { "_POSIX_SHARED_MEMORY_OBJECTS", SYSCONF, _SC_SHARED_MEMORY_OBJECTS }, -#endif - { "_POSIX_SHELL", CONSTANT, 1 }, -#if defined (_SC_SIGNALS) - { "_POSIX_SIGNALS", SYSCONF, _SC_SIGNALS }, -#endif -#if defined (_SC_SINGLE_PROCESS) - { "_POSIX_SINGLE_PROCESS", SYSCONF, _SC_SINGLE_PROCESS }, -#endif -#if defined (_SC_SPAWN) - { "_POSIX_SPAWN", SYSCONF, _SC_SPAWN }, -#endif -#if defined (_SC_SPIN_LOCKS) - { "_POSIX_SPIN_LOCKS", SYSCONF, _SC_SPIN_LOCKS }, -#endif -#if defined (_SC_SPORADIC_SERVER) - { "_POSIX_SPORADIC_SERVER", SYSCONF, _SC_SPORADIC_SERVER }, -#endif -#if defined (_SC_SYMLOOP_MAX) - { "_POSIX_SYMLOOP_MAX", SYSCONF, _SC_SYMLOOP_MAX }, -#endif -#if defined (_SC_SYNCHRONIZED_IO) - { "_POSIX_SYNCHRONIZED_IO", SYSCONF, _SC_SYNCHRONIZED_IO }, -#endif -#if defined (_SC_SYSTEM_DATABASE) - { "_POSIX_SYSTEM_DATABASE", SYSCONF, _SC_SYSTEM_DATABASE }, -#endif -#if defined (_SC_SYSTEM_DATABASE_R) - { "_POSIX_SYSTEM_DATABASE_R", SYSCONF, _SC_SYSTEM_DATABASE_R }, -#endif -#if defined (_SC_THREAD_ATTR_STACKADDR) - { "_POSIX_THREAD_ATTR_STACKADDR", SYSCONF, _SC_THREAD_ATTR_STACKADDR }, -#endif -#if defined (_SC_THREAD_ATTR_STACKSIZE) - { "_POSIX_THREAD_ATTR_STACKSIZE", SYSCONF, _SC_THREAD_ATTR_STACKSIZE }, -#endif -#if defined (_SC_THREAD_CPUTIME) - { "_POSIX_THREAD_CPUTIME", SYSCONF, _SC_THREAD_CPUTIME }, -#endif -#if defined (_SC_THREAD_PRIO_INHERIT) - { "_POSIX_THREAD_PRIO_INHERIT", SYSCONF, _SC_THREAD_PRIO_INHERIT }, -#endif -#if defined (_SC_THREAD_PRIO_PROTECT) - { "_POSIX_THREAD_PRIO_PROTECT", SYSCONF, _SC_THREAD_PRIO_PROTECT }, -#endif -#if defined (_SC_THREAD_PRIORITY_SCHEDULING) - { "_POSIX_THREAD_PRIORITY_SCHEDULING", SYSCONF, _SC_THREAD_PRIORITY_SCHEDULING }, -#endif -#if defined (_SC_THREAD_PROCESS_SHARED) - { "_POSIX_THREAD_PROCESS_SHARED", SYSCONF, _SC_THREAD_PROCESS_SHARED }, -#endif -#if defined (_SC_THREAD_SAFE_FUNCTIONS) - { "_POSIX_THREAD_SAFE_FUNCTIONS", SYSCONF, _SC_THREAD_SAFE_FUNCTIONS }, -#endif -#if defined (_SC_THREAD_SPORADIC_SERVER) - { "_POSIX_THREAD_SPORADIC_SERVER", SYSCONF, _SC_THREAD_SPORADIC_SERVER }, -#endif -#if defined (_SC_THREADS) - { "_POSIX_THREADS", SYSCONF, _SC_THREADS }, -#endif -#if defined (_SC_TIMEOUTS) - { "_POSIX_TIMEOUTS", SYSCONF, _SC_TIMEOUTS }, -#endif -#if defined (_SC_TIMERS) - { "_POSIX_TIMERS", SYSCONF, _SC_TIMERS }, -#endif -#if defined (_SC_TRACE) - { "_POSIX_TRACE", SYSCONF, _SC_TRACE }, -#endif -#if defined (_SC_TRACE) - { "_POSIX_TRACE_EVENT_FILTER",SYSCONF, _SC_TRACE_EVENT_FILTER }, -#endif -#if defined (_SC_TRACE) - { "_POSIX_TRACE_INHERIT", SYSCONF, _SC_TRACE_INHERIT }, -#endif -#if defined (_SC_TRACE) - { "_POSIX_TRACE_LOG", SYSCONF, _SC_TRACE_LOG }, -#endif -#if defined (_SC_TYPED_MEMORY_OBJECTS) - { "_POSIX_TYPED_MEMORY_OBJECTS", SYSCONF, _SC_TYPED_MEMORY_OBJECTS }, -#endif -#if defined (_SC_VERSION) - { "_POSIX_VERSION", SYSCONF, _SC_VERSION }, -#endif - - /* XPG 4.2 Configurable System Variables. */ -#if defined (_SC_ATEXIT_MAX) - { "ATEXIT_MAX", SYSCONF, _SC_ATEXIT_MAX }, -#endif -#if defined (_SC_GETGR_R_SIZE_MAX) - { "GETGR_R_SIZE_MAX", SYSCONF, _SC_GETGR_R_SIZE_MAX }, -#endif -#if defined (_SC_GETPW_R_SIZE_MAX) - { "GETPW_R_SIZE_MAX", SYSCONF, _SC_GETPW_R_SIZE_MAX }, -#endif -#if defined (_SC_HOST_NAME_MAX) - { "HOST_NAME_MAX", SYSCONF, _SC_HOST_NAME_MAX }, -#endif -#if defined (_SC_IOV_MAX) - { "IOV_MAX", SYSCONF, _SC_IOV_MAX }, -#endif -#if defined (_SC_LOGIN_NAME_MAX) - { "LOGIN_NAME_MAX", SYSCONF, _SC_LOGIN_NAME_MAX }, -#endif -#if defined (_SC_LOGNAME_MAX) - { "LOGNAME_MAX", SYSCONF, _SC_LOGNAME_MAX }, -#endif -#if defined (_SC_PAGESIZE) - { "PAGESIZE", SYSCONF, _SC_PAGESIZE }, -#endif -#if defined (_SC_PAGE_SIZE) - { "PAGE_SIZE", SYSCONF, _SC_PAGE_SIZE }, -#endif -#if defined (_SC_SYMLOOP_MAX) - { "SYMLOOP_MAX", SYSCONF, _SC_SYMLOOP_MAX }, -#endif -#if defined (_SC_TTY_NAME_MAX) - { "TTY_NAME_MAX", SYSCONF, _SC_TTY_NAME_MAX }, -#endif -#if defined (_SC_USER_GROUPS) - { "_POSIX_USER_GROUPS", SYSCONF, _SC_USER_GROUPS }, -#endif -#if defined (_SC_USER_GROUPS_R) - { "_POSIX_USER_GROUPS_R", SYSCONF, _SC_USER_GROUPS_R }, -#endif - -#if defined (_SC_AIO_LISTIO_MAX) - { "AIO_LISTIO_MAX", SYSCONF, _SC_AIO_LISTIO_MAX }, -#endif -#if defined (_SC_AIO_MAX) - { "AIO_MAX", SYSCONF, _SC_AIO_MAX }, -#endif -#if defined (_SC_AIO_PRIO_DELTA_MAX) - { "AIO_PRIO_DELTA_MAX", SYSCONF, _SC_AIO_PRIO_DELTA_MAX }, -#endif -#if defined (_SC_MQ_OPEN_MAX) - { "MQ_OPEN_MAX", SYSCONF, _SC_MQ_OPEN_MAX }, -#endif -#if defined (_SC_MQ_PRIO_MAX) - { "MQ_PRIO_MAX", SYSCONF, _SC_MQ_PRIO_MAX }, -#endif -#if defined (_SC_RTSIG_MAX) - { "RTSIG_MAX", SYSCONF, _SC_RTSIG_MAX }, -#endif -#if defined (_SC_SEM_NSEMS_MAX) - { "SEM_NSEMS_MAX", SYSCONF, _SC_SEM_NSEMS_MAX }, -#endif -#if defined (_SC_SEM_VALUE_MAX) - { "SEM_VALUE_MAX", SYSCONF, _SC_SEM_VALUE_MAX }, -#endif -#if defined (_SC_SIGQUEUE_MAX) - { "SIGQUEUE_MAX", SYSCONF, _SC_SIGQUEUE_MAX }, -#endif -#if defined (_SC_TIMER_MAX) - { "TIMER_MAX", SYSCONF, _SC_TIMER_MAX }, -#endif - -#if defined (_SC_THREAD_DESTRUCTOR_ITERATIONS) - { "PTHREAD_DESTRUCTOR_ITERATIONS", SYSCONF, _SC_THREAD_DESTRUCTOR_ITERATIONS }, -#endif -#if defined (_SC_THREAD_KEYS_MAX) - { "PTHREAD_KEYS_MAX", SYSCONF, _SC_THREAD_KEYS_MAX }, -#endif -#if defined (_SC_THREAD_STACK_MIN) - { "PTHREAD_STACK_MIN", SYSCONF, _SC_THREAD_STACK_MIN }, -#endif -#if defined (_SC_THREAD_THREADS_MAX) - { "PTHREAD_THREADS_MAX", SYSCONF, _SC_THREAD_THREADS_MAX }, -#endif - - /* XPG 4.2 (and later) Optional Facility Configuration Values */ -#if defined (_SC_XOPEN_CRYPT) - { "_XOPEN_CRYPT", SYSCONF, _SC_XOPEN_CRYPT }, -#endif -#if defined (_SC_XOPEN_ENH_I18N) - { "_XOPEN_ENH_I18N", SYSCONF, _SC_XOPEN_ENH_I18N }, -#endif -#if defined (_SC_XOPEN_LEGACY) - { "_XOPEN_LEGACY", SYSCONF, _SC_XOPEN_LEGACY }, -#endif /* _SC_XOPEN_LEGACY */ -#if defined (_SC_XOPEN_REALTIME) - { "_XOPEN_REALTIME", SYSCONF, _SC_XOPEN_REALTIME }, -#endif -#if defined (_SC_XOPEN_REALTIME_THREADS) - { "_XOPEN_REALTIME_THREADS", SYSCONF, _SC_XOPEN_REALTIME_THREADS }, -#endif -#if defined (_SC_XOPEN_SHM) - { "_XOPEN_SHM", SYSCONF, _SC_XOPEN_SHM }, -#endif -#if defined (_SC_XOPEN_STREAMS) - { "_XOPEN_STREAMS", SYSCONF, _SC_XOPEN_STREAMS }, -#endif -#if defined (_SC_XOPEN_UNIX) - { "_XOPEN_UNIX", SYSCONF, _SC_XOPEN_UNIX }, -#endif -#if defined (_SC_XOPEN_VERSION) - { "_XOPEN_VERSION", SYSCONF, _SC_XOPEN_VERSION }, -#endif -#if defined (_SC_XOPEN_XCU_VERSION) - { "_XOPEN_XCU_VERSION", SYSCONF, _SC_XOPEN_XCU_VERSION }, -#endif -#if defined (_SC_XOPEN_XPG2) - { "_XOPEN_XPG2", SYSCONF, _SC_XOPEN_XPG2 }, -#endif -#if defined (_SC_XOPEN_XPG3) - { "_XOPEN_XPG3", SYSCONF, _SC_XOPEN_XPG3 }, -#endif -#if defined (_SC_XOPEN_XPG4) - { "_XOPEN_XPG4", SYSCONF, _SC_XOPEN_XPG4 }, -#endif -#if defined (_SC_XOPEN_XPG5) - { "_XOPEN_XPG5", SYSCONF, _SC_XOPEN_XPG5 }, -#endif - - /* POSIX.1 Configurable Pathname Values */ -#ifdef _PC_LINK_MAX - { "LINK_MAX", PATHCONF, _PC_LINK_MAX }, -#endif -#ifdef _PC_MAX_CANON - { "MAX_CANON", PATHCONF, _PC_MAX_CANON }, -#endif -#ifdef _PC_MAX_INPUT - { "MAX_INPUT", PATHCONF, _PC_MAX_INPUT }, -#endif -#ifdef _PC_NAME_MAX - { "NAME_MAX", PATHCONF, _PC_NAME_MAX }, -#endif -#ifdef _PC_PATH_MAX - { "PATH_MAX", PATHCONF, _PC_PATH_MAX }, -#endif -#ifdef _PC_PIPE_BUF - { "PIPE_BUF", PATHCONF, _PC_PIPE_BUF }, -#endif -#ifdef _PC_SYMLINK_MAX - { "SYMLINK_MAX", PATHCONF, _PC_SYMLINK_MAX }, -#endif -#ifdef _PC_CHOWN_RESTRICTED - { "_POSIX_CHOWN_RESTRICTED", PATHCONF, _PC_CHOWN_RESTRICTED }, -#endif -#ifdef _PC_NO_TRUNC - { "_POSIX_NO_TRUNC", PATHCONF, _PC_NO_TRUNC }, -#endif -#ifdef _PC_VDISABLE - { "_POSIX_VDISABLE", PATHCONF, _PC_VDISABLE }, -#endif - - /* XPG 4.2 Configurable Pathname Values */ -#if defined (_PC_FILESIZEBITS) - { "FILESIZEBITS", PATHCONF, _PC_FILESIZEBITS }, -#endif -#if defined (_PC_ASYNC_IO) - { "_POSIX_ASYNC_IO", PATHCONF, _PC_ASYNC_IO }, -#endif -#if defined (_PC_PRIO_IO) - { "_POSIX_PRIO_IO", PATHCONF, _PC_PRIO_IO }, -#endif -#if defined (_PC_SYNC_IO) - { "_POSIX_SYNC_IO", PATHCONF, _PC_SYNC_IO }, -#endif - - /* POSIX.1-200x configurable pathname values */ -#if defined (_PC_ALLOC_SIZE_MIN) - { "POSIX_ALLOC_SIZE_MIN", PATHCONF, _PC_ALLOC_SIZE_MIN }, - { "POSIX_REC_INCR_XFER_SIZE", PATHCONF, _PC_REC_INCR_XFER_SIZE }, - { "POSIX_REC_MAX_XFER_SIZE", PATHCONF, _PC_REC_MAX_XFER_SIZE }, - { "POSIX_REC_MIN_XFER_SIZE", PATHCONF, _PC_REC_MIN_XFER_SIZE }, - { "POSIX_REC_XFER_ALIGN", PATHCONF, _PC_REC_XFER_ALIGN }, -#endif - - /* ANSI/ISO C, POSIX.1-200x, XPG 4.2 (and later) C language type limits. */ - { "CHAR_BIT", CONSTANT, CHAR_BIT }, - { "CHAR_MAX", CONSTANT, CHAR_MAX }, - { "CHAR_MIN", CONSTANT, CHAR_MIN }, - { "INT_BIT", CONSTANT, INT_BIT }, - { "INT_MAX", CONSTANT, INT_MAX }, - { "INT_MIN", CONSTANT, INT_MIN }, -#ifdef LLONG_MAX - { "LLONG_MAX", LLCONST, VAL_LLONG_MAX }, - { "LLONG_MIN", LLCONST, VAL_LLONG_MIN }, -#endif - { "LONG_BIT", CONSTANT, LONG_BIT }, - { "LONG_MAX", CONSTANT, LONG_MAX }, - { "LONG_MIN", CONSTANT, LONG_MIN }, -#ifdef MB_LEN_MAX - { "MB_LEN_MAX", CONSTANT, MB_LEN_MAX }, -#endif - { "SCHAR_MAX", CONSTANT, SCHAR_MAX }, - { "SCHAR_MIN", CONSTANT, SCHAR_MIN }, - { "SHRT_MAX", CONSTANT, SHRT_MAX }, - { "SHRT_MIN", CONSTANT, SHRT_MIN }, - { "SIZE_MAX", CONSTANT, SIZE_MAX }, - { "SSIZE_MAX", CONSTANT, SSIZE_MAX }, - { "UCHAR_MAX", CONSTANT, UCHAR_MAX }, - { "UINT_MAX", CONSTANT, UINT_MAX }, -#ifdef ULLONG_MAX - { "ULLONG_MAX", LLCONST, VAL_ULLONG_MAX }, -#endif - { "ULONG_MAX", CONSTANT, ULONG_MAX }, - { "USHRT_MAX", CONSTANT, USHRT_MAX }, - { "WORD_BIT", CONSTANT, WORD_BIT }, - - { NULL } -}; - -static int num_getconf_variables = sizeof(conf_table) / sizeof(struct conf_variable) - 1; - -extern char *this_command_name; -extern char **make_builtin_argv (); - -static void getconf_help (); -static int getconf_print (); -static int getconf_one (); -static int getconf_all (); - -int -getconf_builtin (list) - WORD_LIST *list; -{ - int c, r, opt, aflag; - char **v; - - aflag = 0; - reset_internal_getopt(); - while ((opt = internal_getopt (list, "ahv:")) != -1) { - switch (opt) { - case 'a': - aflag = 1; - break; - case 'h': - getconf_help(); - return(EXECUTION_SUCCESS); - case 'v': - break; /* ignored */ - default: - builtin_usage(); - return(EX_USAGE); - } - } - - list = loptend; - if ((aflag == 0 && list == 0) || (aflag && list) || list_length(list) > 2) { - builtin_usage(); - return(EX_USAGE); - } - - r = aflag ? getconf_all() : getconf_one(list); - - return r; -} - -static void -getconf_help() -{ - const struct conf_variable *cp; - register int i, column; - - builtin_usage(); - printf("Acceptable variable names are:\n"); - for (cp = conf_table; cp->name != NULL; cp++) { - if (cp->type == PATHCONF) - printf("%s pathname\n", cp->name); - else - printf("%s\n", cp->name); - } -} - -static int -getconf_print(cp, vpath, all) -struct conf_variable *cp; -char *vpath; -int all; -{ - long val; - char *sval; - size_t slen; - - switch (cp->type) { - case G_UNDEF: - printf("undefined\n"); - break; - -#ifdef LLONG_MAX - case LLCONST: - switch (cp->value) { - default: - case VAL_LLONG_MIN: - printf ("%lld\n", LLONG_MIN); - break; - case VAL_LLONG_MAX: - printf ("%lld\n", LLONG_MAX); - break; -# if (ULLONG_MAX != LLONG_MAX) - case VAL_ULLONG_MAX: - printf ("%llu\n", ULLONG_MAX); - break; -# endif - } - break; -#endif - case CONSTANT: - switch (cp->value) { - case UCHAR_MAX: - case USHRT_MAX: - case UINT_MAX: -#if (ULONG_MAX != UINT_MAX) - case ULONG_MAX: -#endif -#if (SIZE_MAX != UINT_MAX) && (SIZE_MAX != ULONG_MAX) - case SIZE_MAX: -#endif - - printf("%lu\n", cp->value); - break; - default: - printf("%ld\n", cp->value); - break; - } - break; - - case CONFSTR: - errno = 0; - slen = confstr (cp->value, (char *) 0, (size_t) 0); - if (slen == 0) { - if (errno != 0) { - if (all) - printf ("getconf: %s\n", strerror(errno)); - else - builtin_error ("%s", strerror(errno)); - } else - printf ("undefined\n"); - return (EXECUTION_FAILURE); - } - sval = xmalloc(slen); - - confstr(cp->value, sval, slen); - printf("%s\n", sval); - free(sval); - break; - - case SYSCONF: - errno = 0; - if ((val = sysconf(cp->value)) == -1) { - if (errno != 0) { - if (all) - printf("getconf: %s\n", strerror (errno)); - else - builtin_error ("%s", strerror (errno)); - return (EXECUTION_FAILURE); - } - - printf ("undefined\n"); - } else { - printf("%ld\n", val); - } - break; - - case PATHCONF: - errno = 0; - if ((val = pathconf(vpath, cp->value)) == -1) { - if (errno != 0) { - if (all) - printf("getconf: %s: %s\n", vpath, strerror (errno)); - else - builtin_error ("%s: %s", vpath, strerror (errno)); - return (EXECUTION_FAILURE); - } - - printf ("undefined\n"); - } else { - printf ("%ld\n", val); - } - break; - } - - return (ferror(stdout) ? EXECUTION_FAILURE : EXECUTION_SUCCESS); -} - -static int -getconf_all() -{ - const struct conf_variable *cp; - int ret; - - ret = EXECUTION_SUCCESS; - for (cp = conf_table; cp->name != NULL; cp++) { - printf("%-35s", cp->name); - if (getconf_print(cp, "/", 1) == EXECUTION_FAILURE) - ret = EXECUTION_FAILURE; - } - return ret; -} - -static int -getconf_one(list) - WORD_LIST *list; -{ - const struct conf_variable *cp; - char *vname, *vpath; - - vname = list->word->word; - vpath = (list->next && list->next->word) ? list->next->word->word - : (char *)NULL; - - for (cp = conf_table; cp->name != NULL; cp++) { - if (strcmp(vname, cp->name) == 0) - break; - } - if (cp->name == NULL) { - builtin_error ("%s: unknown variable", vname); - return (EXECUTION_FAILURE); - } - - if (cp->type == PATHCONF) { - if (list->next == 0) { - builtin_usage(); - return(EX_USAGE); - } - } else { - if (list->next) { - builtin_usage(); - return(EX_USAGE); - } - } - - return (getconf_print(cp, vpath, 0)); -} - -static char *getconf_doc[] = { - "getconf writes the current value of a configurable system limit or", - "option variable to the standard output.", - (char *)NULL -}; - -struct builtin getconf_struct = { - "getconf", - getconf_builtin, - BUILTIN_ENABLED, - getconf_doc, - "getconf -[ah] or getconf [-v spec] sysvar or getconf [-v spec] pathvar pathname", - 0 -}; - -#ifndef HAVE_CONFSTR -static size_t -confstr (name, buf, len) - int name; - char *buf; - size_t len; -{ - switch (name) - { - case _CS_PATH: - if (len > 0 && buf) - { - strncpy (buf, STANDARD_UTILS_PATH, len - 1); - buf[len - 1] = '\0'; - } - return (sizeof (STANDARD_UTILS_PATH) + 1); - default: - errno = EINVAL; - return 0; - } -} -#endif - -#ifndef HAVE_SYSCONF -extern long get_clk_tck __P((void)); - -static long -sysconf (name) - int name; -{ -# if defined (_POSIX_VERSION) - switch (name) - { - case _SC_ARG_MAX: - return _POSIX_ARG_MAX; - case _SC_CHILD_MAX: - return _POSIX_CHILD_MAX; - case _SC_CLK_TCK: - return get_clk_tck(); - case _SC_NGROUPS_MAX: - return _POSIX_NGROUPS_MAX; - case _SC_OPEN_MAX: - return _POSIX_OPEN_MAX; - case _SC_JOB_CONTROL: - return _POSIX_JOB_CONTROL; - case _SC_SAVED_IDS: - return _POSIX_SAVED_IDS; - case _SC_VERSION: - return _POSIX_VERSION; - case _SC_BC_BASE_MAX: - return _POSIX2_BC_BASE_MAX; - case _SC_BC_DIM_MAX: - return _POSIX2_BC_DIM_MAX; - case _SC_BC_SCALE_MAX: - return _POSIX2_BC_SCALE_MAX; - case _SC_BC_STRING_MAX: - return _POSIX2_BC_STRING_MAX; - case _SC_COLL_WEIGHTS_MAX: - return -1; - case _SC_EXPR_NEST_MAX: - return _POSIX2_EXPR_NEST_MAX; - case _SC_LINE_MAX: - return _POSIX2_LINE_MAX; - case _SC_RE_DUP_MAX: - return _POSIX2_RE_DUP_MAX; - case _SC_STREAM_MAX: - return _POSIX_STREAM_MAX; - case _SC_TZNAME_MAX: - return _POSIX_TZNAME_MAX; - default: - errno = EINVAL; - return -1; - } -#else - errno = EINVAL; - return -1; -#endif -} -#endif - -#ifndef HAVE_PATHCONF -static long -pathconf (path, name) - const char *path; - int name; -{ -#if defined (_POSIX_VERSION) - switch (name) - { - case _PC_LINK_MAX: - return _POSIX_LINK_MAX; - case _PC_MAX_CANON: - return _POSIX_MAX_CANON; - case _PC_MAX_INPUT: - return _POSIX_MAX_INPUT; - case _PC_NAME_MAX: - return _POSIX_NAME_MAX; - case _PC_PATH_MAX: - return _POSIX_PATH_MAX; - case _PC_PIPE_BUF: - return _POSIX_PIPE_BUF; - case _PC_CHOWN_RESTRICTED: -#ifdef _POSIX_CHOWN_RESTRICTED - return _POSIX_CHOWN_RESTRICTED; -#else - return -1; -#endif - case _PC_NO_TRUNC: -#ifdef _POSIX_NO_TRUNC - return _POSIX_NO_TRUNC; -#else - return -1; -#endif - case _PC_VDISABLE: -#ifdef _POSIX_VDISABLE - return _POSIX_VDISABLE; -#else - return -1; -#endif - default: - errno = EINVAL; - return -1; - } -#else - errno = EINVAL; - return -1; -#endif -} -#endif diff --git a/examples/loadables/head.c~ b/examples/loadables/head.c~ deleted file mode 100644 index 5dc5d70d0..000000000 --- a/examples/loadables/head.c~ +++ /dev/null @@ -1,144 +0,0 @@ -/* head - copy first part of files. */ - -/* See Makefile for compilation details. */ - -#include "config.h" - -#include "bashtypes.h" -#include "posixstat.h" -#include "filecntl.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" - -#include -#include -#include "chartypes.h" - -#include "builtins.h" -#include "shell.h" -#include "bashgetopt.h" -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif - -static void -munge_list (list) - WORD_LIST *list; -{ - WORD_LIST *l, *nl; - WORD_DESC *wd; - char *arg; - - for (l = list; l; l = l->next) - { - arg = l->word->word; - if (arg[0] != '-' || arg[1] == '-' || (DIGIT(arg[1]) == 0)) - return; - /* We have -[0-9]* */ - wd = make_bare_word (arg+1); - nl = make_word_list (wd, l->next); - l->word->word[1] = 'n'; - l->word->word[2] = '\0'; - l->next = nl; - l = nl; /* skip over new argument */ - } -} - -static int -file_head (fp, cnt) - FILE *fp; - int cnt; -{ - int ch; - - while (cnt--) - { - while ((ch = getc (fp)) != EOF) - { - if (putchar (ch) == EOF) - { - builtin_error ("write error: %s", strerror (errno)); - return EXECUTION_FAILURE; - } - if (ch == '\n') - break; - } - } -} - -head_builtin (list) - WORD_LIST *list; -{ - int nline, opt, rval; - WORD_LIST *l; - FILE *fp; - - char *t; - - munge_list (list); /* change -num into -n num */ - - reset_internal_getopt (); - nline = 10; - while ((opt = internal_getopt (list, "n:")) != -1) - { - switch (opt) - { - case 'n': - nline = atoi (list_optarg); - if (nline <= 0) - { - builtin_error ("bad line count: %s", list_optarg); - return (EX_USAGE); - } - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - if (list == 0) - return (file_head (stdin, nline)); - - for (rval = EXECUTION_SUCCESS, opt = 1, l = list; l; l = l->next) - { - fp = fopen (l->word->word, "r"); - if (fp == NULL) - { - builtin_error ("%s: %s", l->word->word, strerror (errno)); - continue; - } - if (list->next) /* more than one file */ - { - printf ("%s==> %s <==\n", opt ? "" : "\n", l->word->word); - opt = 0; - } - rval = file_head (fp, nline); - fclose (fp); - } - - return (rval); -} - -char *head_doc[] = { - "Copy the first N lines from the input files to the standard output.", - "N is supplied as an argument to the `-n' option. If N is not given,", - "the first ten lines are copied.", - (char *)NULL -}; - -struct builtin head_struct = { - "head", /* builtin name */ - head_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - head_doc, /* array of long documentation strings. */ - "head [-n num] [file ...]", /* usage synopsis; becomes short_doc */ - 0 /* reserved for internal use */ -}; diff --git a/examples/loadables/hello.c~ b/examples/loadables/hello.c~ deleted file mode 100644 index 1d68c6fc8..000000000 --- a/examples/loadables/hello.c~ +++ /dev/null @@ -1,61 +0,0 @@ -/* Sample builtin to be dynamically loaded with enable -f and create a new - builtin. */ - -/* See Makefile for compilation details. */ - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include - -#include "builtins.h" -#include "shell.h" -#include "bashgetopt.h" - -/* A builtin `xxx' is normally implemented with an `xxx_builtin' function. - If you're converting a command that uses the normal Unix argc/argv - calling convention, use argv = make_builtin_argv (list, &argc) and call - the original `main' something like `xxx_main'. Look at cat.c for an - example. - - Builtins should use internal_getopt to parse options. It is the same as - getopt(3), but it takes a WORD_LIST *. Look at print.c for an example - of its use. - - If the builtin takes no options, call no_options(list) before doing - anything else. If it returns a non-zero value, your builtin should - immediately return EX_USAGE. Look at logname.c for an example. - - A builtin command returns EXECUTION_SUCCESS for success and - EXECUTION_FAILURE to indicate failure. */ -int -hello_builtin (list) - WORD_LIST *list; -{ - printf("hello world\n"); - fflush (stdout); - return (EXECUTION_SUCCESS); -} - -/* An array of strings forming the `long' documentation for a builtin xxx, - which is printed by `help xxx'. It must end with a NULL. */ -char *hello_doc[] = { - "this is the long doc for the sample hello builtin", - (char *)NULL -}; - -/* The standard structure describing a builtin command. bash keeps an array - of these structures. The flags must include BUILTIN_ENABLED so the - builtin can be used. */ -struct builtin hello_struct = { - "hello", /* builtin name */ - hello_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - hello_doc, /* array of long documentation strings. */ - "hello", /* usage synopsis; becomes short_doc */ - 0 /* reserved for internal use */ -}; - diff --git a/examples/loadables/id.c~ b/examples/loadables/id.c~ deleted file mode 100644 index 945190d7c..000000000 --- a/examples/loadables/id.c~ +++ /dev/null @@ -1,308 +0,0 @@ -/* - * id - POSIX.2 user identity - * - * (INCOMPLETE -- supplementary groups for other users not yet done) - * - * usage: id [-Ggu] [-nr] [user] - * - * The default output format looks something like: - * uid=xxx(chet) gid=xx groups=aa(aname), bb(bname), cc(cname) - */ - -#include -#include -#include "bashtypes.h" -#include -#include -#include "bashansi.h" - -#ifdef HAVE_LIMITS_H -# include -#else -# include -#endif - -#if !defined (HAVE_GETPW_DECLS) -extern struct passwd *getpwuid (); -#endif -extern struct group *getgrgid (); - -#include "shell.h" -#include "builtins.h" -#include "stdc.h" -#include "common.h" -#include "bashgetopt.h" - -#define ID_ALLGROUPS 0x001 /* -G */ -#define ID_GIDONLY 0x002 /* -g */ -#define ID_USENAME 0x004 /* -n */ -#define ID_USEREAL 0x008 /* -r */ -#define ID_USERONLY 0x010 /* -u */ - -#define ID_FLAGSET(s) ((id_flags & (s)) != 0) - -static int id_flags; - -static uid_t ruid, euid; -static gid_t rgid, egid; - -static char *id_user; - -static int inituser (); - -static int id_pruser (); -static int id_prgrp (); -static int id_prgroups (); -static int id_prall (); - -int -id_builtin (list) - WORD_LIST *list; -{ - int opt; - char *user; - - id_flags = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "Ggnru")) != -1) - { - switch (opt) - { - case 'G': id_flags |= ID_ALLGROUPS; break; - case 'g': id_flags |= ID_GIDONLY; break; - case 'n': id_flags |= ID_USENAME; break; - case 'r': id_flags |= ID_USEREAL; break; - case 'u': id_flags |= ID_USERONLY; break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - user = list ? list->word->word : (char *)NULL; - - /* Check for some invalid option combinations */ - opt = ID_FLAGSET (ID_ALLGROUPS) + ID_FLAGSET (ID_GIDONLY) + ID_FLAGSET (ID_USERONLY); - if (opt > 1 || (opt == 0 && ((id_flags & (ID_USEREAL|ID_USENAME)) != 0))) - { - builtin_usage (); - return (EX_USAGE); - } - - if (list && list->next) - { - builtin_usage (); - return (EX_USAGE); - } - - if (inituser (user) < 0) - return (EXECUTION_FAILURE); - - opt = 0; - if (id_flags & ID_USERONLY) - opt += id_pruser ((id_flags & ID_USEREAL) ? ruid : euid); - else if (id_flags & ID_GIDONLY) - opt += id_prgrp ((id_flags & ID_USEREAL) ? rgid : egid); - else if (id_flags & ID_ALLGROUPS) - opt += id_prgroups (user); - else - opt += id_prall (user); - putchar ('\n'); - fflush (stdout); - - return (opt == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE); -} - -static int -inituser (uname) - char *uname; -{ - struct passwd *pwd; - - if (uname) - { - pwd = getpwnam (uname); - if (pwd == 0) - { - builtin_error ("%s: no such user", uname); - return -1; - } - ruid = euid = pwd->pw_uid; - rgid = egid = pwd->pw_gid; - } - else - { - ruid = current_user.uid; - euid = current_user.euid; - rgid = current_user.gid; - egid = current_user.egid; - } - return 0; -} - -/* Print the name or value of user ID UID. */ -static int -id_pruser (uid) - int uid; -{ - struct passwd *pwd = NULL; - int r; - - r = 0; - if (id_flags & ID_USENAME) - { - pwd = getpwuid (uid); - if (pwd == NULL) - r = 1; - } - if (pwd) - printf ("%s", pwd->pw_name); - else - printf ("%u", (unsigned) uid); - - return r; -} - -/* Print the name or value of group ID GID. */ - -static int -id_prgrp (gid) - int gid; -{ - struct group *grp = NULL; - int r; - - r = 0; - if (id_flags & ID_USENAME) - { - grp = getgrgid (gid); - if (grp == NULL) - r = 1; - } - - if (grp) - printf ("%s", grp->gr_name); - else - printf ("%u", (unsigned) gid); - - return r; -} - -static int -id_prgroups (uname) - char *uname; -{ - int *glist, ng, i, r; - - r = 0; - id_prgrp (rgid); - if (egid != rgid) - { - putchar (' '); - id_prgrp (egid); - } - - if (uname) - { - builtin_error ("supplementary groups for other users not yet implemented"); - glist = (int *)NULL; - ng = 0; - r = 1; - } - else - glist = get_group_array (&ng); - - for (i = 0; i < ng; i++) - if (glist[i] != rgid && glist[i] != egid) - { - putchar (' '); - id_prgrp (glist[i]); - } - - return r; -} - -static int -id_prall (uname) - char *uname; -{ - int r, i, ng, *glist; - struct passwd *pwd; - struct group *grp; - - r = 0; - printf ("uid=%u", (unsigned) ruid); - pwd = getpwuid (ruid); - if (pwd == NULL) - r = 1; - else - printf ("(%s)", pwd->pw_name); - - printf (" gid=%u", (unsigned) rgid); - grp = getgrgid (rgid); - if (grp == NULL) - r = 1; - else - printf ("(%s)", grp->gr_name); - - if (euid != ruid) - { - printf (" euid=%u", (unsigned) euid); - pwd = getpwuid (euid); - if (pwd == NULL) - r = 1; - else - printf ("(%s)", pwd->pw_name); - } - - if (egid != rgid) - { - printf (" egid=%u", (unsigned) egid); - grp = getgrgid (egid); - if (grp == NULL) - r = 1; - else - printf ("(%s)", grp->gr_name); - } - - if (uname) - { - builtin_error ("supplementary groups for other users not yet implemented"); - glist = (int *)NULL; - ng = 0; - r = 1; - } - else - glist = get_group_array (&ng); - - if (ng > 0) - printf (" groups="); - for (i = 0; i < ng; i++) - { - if (i > 0) - printf (", "); - printf ("%u", (unsigned) glist[i]); - grp = getgrgid (glist[i]); - if (grp == NULL) - r = 1; - else - printf ("(%s)", grp->gr_name); - } - - return r; -} - -char *id_doc[] = { - "return information about user identity", - (char *)NULL -}; - -struct builtin id_struct = { - "id", - id_builtin, - BUILTIN_ENABLED, - id_doc, - "id [user]\n\tid -G [-n] [user]\n\tid -g [-nr] [user]\n\tid -u [-nr] [user]", - 0 -}; diff --git a/examples/loadables/ln.c~ b/examples/loadables/ln.c~ deleted file mode 100644 index 80adf5fb3..000000000 --- a/examples/loadables/ln.c~ +++ /dev/null @@ -1,206 +0,0 @@ -/* ln - make links */ - -/* See Makefile for compilation details. */ - -#include "config.h" - -#include "bashtypes.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "posixstat.h" - -#include -#include - -#include "builtins.h" -#include "shell.h" -#include "bashgetopt.h" -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif - -typedef int unix_link_syscall_t __P((const char *, const char *)); - -#define LN_SYMLINK 0x01 -#define LN_UNLINK 0x02 - -static unix_link_syscall_t *linkfn; -static int dolink (); - -ln_builtin (list) - WORD_LIST *list; -{ - int rval, opt, flags; - WORD_LIST *l; - char *sdir; - struct stat sb; - - flags = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "fs")) != -1) - { - switch (opt) - { - case 'f': - flags |= LN_UNLINK; - break; - case 's': - flags |= LN_SYMLINK; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - if (list == 0) - { - builtin_usage (); - return (EX_USAGE); - } - - linkfn = (flags & LN_SYMLINK) ? symlink : link; - - if (list->next == 0) /* ln target, equivalent to ln target . */ - return (dolink (list->word->word, ".", flags)); - - if (list->next->next == 0) /* ln target source */ - return (dolink (list->word->word, list->next->word->word, flags)); - - /* ln target1 target2 ... directory */ - - /* find last argument: target directory, and make sure it's an existing - directory. */ - for (l = list; l->next; l = l->next) - ; - sdir = l->word->word; - - if (stat(sdir, &sb) < 0) - { - builtin_error ("%s", sdir); - return (EXECUTION_FAILURE); - } - - if (S_ISDIR (sb.st_mode) == 0) - { - builtin_usage (); - return (EX_USAGE); - } - - for (rval = EXECUTION_SUCCESS; list != l; list = list->next) - rval += dolink (list->word->word, sdir, flags); - - return rval; -} - -static char * -mkdirpath (dir, file) - char *dir, *file; -{ - int dlen, flen; - char *ret; - - dlen = strlen (dir); - flen = strlen (file); - - ret = xmalloc (2 + dlen + flen); - - strcpy (ret, dir); - if (ret[dlen - 1] != '/') - ret[dlen++] = '/'; - strcpy (ret + dlen, file); - return ret; -} - -#if defined (HAVE_LSTAT) -# define LSTAT lstat -#else -# define LSTAT stat -#endif - -static int -dolink (src, dst, flags) - char *src, *dst; - int flags; -{ - struct stat ssb, dsb; - int exists; - char *dst_path, *p; - - /* If we're not doing symlinks, the source must exist and not be a - directory. */ - if ((flags & LN_SYMLINK) == 0) - { - if (stat (src, &ssb) != 0) - { - builtin_error ("%s: %s", src, strerror (errno)); - return (EXECUTION_FAILURE); - } - if (S_ISDIR (ssb.st_mode)) - { - errno = EISDIR; - builtin_error ("%s: %s", src, strerror (errno)); - return (EXECUTION_FAILURE); - } - } - - /* If the destination is a directory, create the final filename by appending - the basename of the source to the destination. */ - dst_path = 0; - if ((stat (dst, &dsb) == 0) && S_ISDIR (dsb.st_mode)) - { - if ((p = strrchr (src, '/')) == 0) - p = src; - else - p++; - - dst_path = mkdirpath (dst, p); - dst = dst_path; - } - - exists = LSTAT (dst, &dsb) == 0; - - /* If -f was specified, and the destination exists, unlink it. */ - if ((flags & LN_UNLINK) && exists && unlink (dst) != 0) - { - builtin_error ("%s: cannot unlink: %s", dst, strerror (errno)); - FREE (dst_path); - return (EXECUTION_FAILURE); - } - - /* Perform the link. */ - if ((*linkfn) (src, dst) != 0) - { - builtin_error ("cannot link %s to %s: %s", dst, src, strerror (errno)); - FREE (dst_path); - return (EXECUTION_FAILURE); - } - - FREE (dst_path); - return (EXECUTION_SUCCESS); -} - -char *ln_doc[] = { - "Create a new directory entry with the same modes as the original", - "file. The -f option means to unlink any existing file, permitting", - "the link to occur. The -s option means to create a symbolic link.", - "By default, ln makes hard links.", - (char *)NULL -}; - -/* The standard structure describing a builtin command. bash keeps an array - of these structures. */ -struct builtin ln_struct = { - "ln", /* builtin name */ - ln_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - ln_doc, /* array of long documentation strings. */ - "ln [-fs] file1 [file2] OR ln [-fs] file ... directory", /* usage synopsis; becomes short_doc */ - 0 /* reserved for internal use */ -}; diff --git a/examples/loadables/logname.c~ b/examples/loadables/logname.c~ deleted file mode 100644 index 3baecb24f..000000000 --- a/examples/loadables/logname.c~ +++ /dev/null @@ -1,53 +0,0 @@ -/* logname - print login name of current user */ - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include - -#include "builtins.h" -#include "shell.h" -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif - -logname_builtin (list) - WORD_LIST *list; -{ - char *np; - - if (no_options (list)) - return (EX_USAGE); - - np = getlogin (); - if (np == 0) - { - builtin_error ("cannot find username: %s", strerror (errno)); - return (EXECUTION_FAILURE); - } - printf ("%s\n", np); - return (EXECUTION_SUCCESS); -} - -char *logname_doc[] = { - "write the current user's login name to the standard output", - "and exit. logname ignores the LOGNAME and USER variables.", - "logname ignores any non-option arguments.", - (char *)NULL -}; - -struct builtin logname_struct = { - "logname", - logname_builtin, - BUILTIN_ENABLED, - logname_doc, - "logname", - 0 -}; - diff --git a/examples/loadables/mkdir.c~ b/examples/loadables/mkdir.c~ deleted file mode 100644 index 6ccffdbe0..000000000 --- a/examples/loadables/mkdir.c~ +++ /dev/null @@ -1,217 +0,0 @@ -/* mkdir - make directories */ - -/* See Makefile for compilation details. */ - -#include - -#include "bashtypes.h" -#include "posixstat.h" -#include -#include -#include "bashansi.h" -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "builtins.h" -#include "shell.h" -#include "bashgetopt.h" -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif - -#define ISOCTAL(c) ((c) >= '0' && (c) <= '7') - -extern int parse_symbolic_mode (); - -static int make_path (); - -static int original_umask; - -int -mkdir_builtin (list) - WORD_LIST *list; -{ - int opt, pflag, omode, rval, octal, nmode, parent_mode, um; - char *mode; - WORD_LIST *l; - - reset_internal_getopt (); - pflag = 0; - mode = (char *)NULL; - while ((opt = internal_getopt(list, "m:p")) != -1) - switch (opt) - { - case 'p': - pflag = 1; - break; - case 'm': - mode = list_optarg; - break; - default: - builtin_usage(); - return (EX_USAGE); - } - list = loptend; - - if (list == 0) - { - builtin_usage (); - return (EX_USAGE); - } - - if (mode == NULL) - omode = S_IRWXU | S_IRWXG | S_IRWXO; /* a=rwx */ - else if (ISOCTAL (*mode)) /* octal number */ - { - omode = read_octal (mode); - if (omode < 0) - { - builtin_error ("invalid file mode: %s", mode); - return (EXECUTION_FAILURE); - } - octal = 1; - } - else if (mode) - { - /* initial bits are a=rwx; the mode argument modifies them */ - omode = parse_symbolic_mode (mode, S_IRWXU | S_IRWXG | S_IRWXO); - if (omode < 0) - { - builtin_error ("invalid file mode: %s", mode); - return (EXECUTION_FAILURE); - } - octal = 0; - } - - /* Make the new mode */ - original_umask = umask (0); - umask (original_umask); - - nmode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~original_umask; - parent_mode = nmode | (S_IWRITE|S_IEXEC); /* u+wx */ - - /* Adjust new mode based on mode argument */ - nmode &= omode; - - for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next) - { - if (pflag && make_path (l->word->word, nmode, parent_mode)) - { - rval = EXECUTION_FAILURE; - continue; - } - else if (pflag == 0 && mkdir (l->word->word, nmode) < 0) - { - builtin_error ("cannot create directory `%s': %s", l->word->word, strerror (errno)); - rval = EXECUTION_FAILURE; - } - } - return rval; -} - -/* Make all the directories leading up to PATH, then create PATH. Note that - this changes the process's umask; make sure that all paths leading to a - return reset it to ORIGINAL_UMASK */ -static int -make_path (path, nmode, parent_mode) - char *path; - int nmode, parent_mode; -{ - int oumask; - struct stat sb; - char *p, *npath; - - if (stat (path, &sb) == 0) - { - if (S_ISDIR (sb.st_mode) == 0) - { - builtin_error ("`%s': file exists but is not a directory", path); - return 1; - } - - if (chmod (path, nmode)) - { - builtin_error ("%s: %s", path, strerror (errno)); - return 1; - } - - return 0; - } - - oumask = umask (0); - npath = savestring (path); /* So we can write to it. */ - - /* Check whether or not we need to do anything with intermediate dirs. */ - - /* Skip leading slashes. */ - p = npath; - while (*p == '/') - p++; - - while (p = strchr (p, '/')) - { - *p = '\0'; - if (stat (npath, &sb) != 0) - { - if (mkdir (npath, parent_mode)) - { - builtin_error ("cannot create directory `%s': %s", npath, strerror (errno)); - umask (original_umask); - free (npath); - return 1; - } - } - else if (S_ISDIR (sb.st_mode) == 0) - { - builtin_error ("`%s': file exists but is not a directory", npath); - umask (original_umask); - free (npath); - return 1; - } - - *p++ = '/'; /* restore slash */ - while (*p == '/') - p++; - } - - /* Create the final directory component. */ - if (stat (npath, &sb) && mkdir (npath, nmode)) - { - builtin_error ("cannot create directory `%s': %s", npath, strerror (errno)); - umask (original_umask); - free (npath); - return 1; - } - - umask (original_umask); - free (npath); - return 0; -} - -char *mkdir_doc[] = { - "Make directories. Create the directories named as arguments, in", - "the order specified, using mode rwxrwxrwx as modified by the current", - "umask (see `help umask'). The -m option causes the file permission", - "bits of the final directory to be MODE. The MODE argument may be", - "an octal number or a symbolic mode like that used by chmod(1). If", - "a symbolic mode is used, the operations are interpreted relative to", - "an initial mode of \"a=rwx\". The -p option causes any required", - "intermediate directories in PATH to be created. The directories", - "are created with permssion bits of rwxrwxrwx as modified by the current", - "umask, plus write and search permissions for the owner. mkdir", - "returns 0 if the directories are created successfully, and non-zero", - "if an error occurs.", - (char *)NULL -}; - -struct builtin mkdir_struct = { - "mkdir", - mkdir_builtin, - BUILTIN_ENABLED, - mkdir_doc, - "mkdir [-p] [-m mode] directory [directory ...]", - 0 -}; diff --git a/examples/loadables/mypid.c~ b/examples/loadables/mypid.c~ deleted file mode 100644 index 03cad226e..000000000 --- a/examples/loadables/mypid.c~ +++ /dev/null @@ -1,73 +0,0 @@ -/* This module should be dynamically loaded with enable -f - * which would create a new builtin named mypid. You'll need - * the source code for GNU bash to recompile this module. - * - * Then, from within bash, enable -f ./mypid enable_mypid, where ./mypid - * is the binary obtained from running make. Hereafter, `${MYPID}' - * is a shell builtin variable. - */ - -#include -#include -#include - -#include "builtins.h" -#include "shell.h" - -#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \ - do \ - { SHELL_VAR *v = bind_variable (var, (val), 0); \ - v->dynamic_value = gfunc; \ - v->assign_func = afunc; \ - } \ - while (0) - -static SHELL_VAR * -assign_mypid ( - SHELL_VAR *self, - char *value, - arrayind_t unused ) -{ - return (self); -} - -static SHELL_VAR * -get_mypid (SHELL_VAR *var) -{ - int rv; - char *p; - - rv = getpid(); - p = itos (rv); - - FREE (value_cell (var)); - - VSETATTR (var, att_integer); - var_setvalue (var, p); - return (var); -} - -int -enable_mypid_builtin(WORD_LIST *list) -{ - INIT_DYNAMIC_VAR ("MYPID", (char *)NULL, get_mypid, assign_mypid); - - return 0; -} - -char const *enable_mypid_doc[] = { - "Enable $MYPID.", - "", - "Enables use of the ${MYPID} dynamic variable. ", - "It will yield the current pid of a subshell.", - (char *)0 -}; - -struct builtin enable_mypid_struct = { - "enable_mypid", - enable_mypid_builtin, - BUILTIN_ENABLED, - (char**)(void*)enable_mypid_doc, - "enable_mypid N", - 0 -}; diff --git a/examples/loadables/necho.c~ b/examples/loadables/necho.c~ deleted file mode 100644 index 521ee2c6d..000000000 --- a/examples/loadables/necho.c~ +++ /dev/null @@ -1,33 +0,0 @@ -/* necho - echo without options or argument interpretation */ - -/* Sample builtin to be dynamically loaded with enable -f and replace an - existing builtin. */ - -#include -#include "builtins.h" -#include "shell.h" - -necho_builtin (list) -WORD_LIST *list; -{ - print_word_list (list, " "); - printf("\n"); - fflush (stdout); - return (EXECUTION_SUCCESS); -} - -char *necho_doc[] = { - "Print the arguments to the standard ouput separated", - "by space characters and terminated with a newline.", - (char *)NULL -}; - -struct builtin necho_struct = { - "echo", - necho_builtin, - BUILTIN_ENABLED, - necho_doc, - "echo [args]", - 0 -}; - diff --git a/examples/loadables/pathchk.c~ b/examples/loadables/pathchk.c~ deleted file mode 100644 index 5b29c35af..000000000 --- a/examples/loadables/pathchk.c~ +++ /dev/null @@ -1,359 +0,0 @@ -/* pathchk - check pathnames for validity and portability */ - -/* Usage: pathchk [-p] path ... - - For each PATH, print a message if any of these conditions are false: - * all existing leading directories in PATH have search (execute) permission - * strlen (PATH) <= PATH_MAX - * strlen (each_directory_in_PATH) <= NAME_MAX - - Exit status: - 0 All PATH names passed all of the tests. - 1 An error occurred. - - Options: - -p Instead of performing length checks on the - underlying filesystem, test the length of the - pathname and its components against the POSIX.1 - minimum limits for portability, _POSIX_NAME_MAX - and _POSIX_PATH_MAX in 2.9.2. Also check that - the pathname contains no character not in the - portable filename character set. */ - -/* See Makefile for compilation details. */ - -#include - -#include -#include "posixstat.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (HAVE_LIMITS_H) -# include -#endif - -#include "bashansi.h" - -#include -#include - -#include "builtins.h" -#include "shell.h" -#include "stdc.h" -#include "bashgetopt.h" -#include "maxpath.h" -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif - -#if !defined (_POSIX_PATH_MAX) -# define _POSIX_PATH_MAX 255 -#endif -#if !defined (_POSIX_NAME_MAX) -# define _POSIX_NAME_MAX 14 -#endif - -/* How do we get PATH_MAX? */ -#if defined (_POSIX_VERSION) && !defined (PATH_MAX) -# define PATH_MAX_FOR(p) pathconf ((p), _PC_PATH_MAX) -#endif - -/* How do we get NAME_MAX? */ -#if defined (_POSIX_VERSION) && !defined (NAME_MAX) -# define NAME_MAX_FOR(p) pathconf ((p), _PC_NAME_MAX) -#endif - -#if !defined (PATH_MAX_FOR) -# define PATH_MAX_FOR(p) PATH_MAX -#endif - -#if !defined (NAME_MAX_FOR) -# define NAME_MAX_FOR(p) NAME_MAX -#endif - -extern char *strerror (); - -static int validate_path (); - -pathchk_builtin (list) - WORD_LIST *list; -{ - int retval, pflag, opt; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "p")) != -1) - { - switch (opt) - { - case 'p': - pflag = 1; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - if (list == 0) - { - builtin_usage (); - return (EX_USAGE); - } - - for (retval = 0; list; list = list->next) - retval |= validate_path (list->word->word, pflag); - - return (retval ? EXECUTION_FAILURE : EXECUTION_SUCCESS); -} - -char *pathchk_doc[] = { - "Check each pathname argument for validity (i.e., it may be used to", - "create or access a file without casuing syntax errors) and portability", - "(i.e., no filename truncation will result). If the `-p' option is", - "supplied, more extensive portability checks are performed.", - (char *)NULL -}; - -/* The standard structure describing a builtin command. bash keeps an array - of these structures. */ -struct builtin pathchk_struct = { - "pathchk", /* builtin name */ - pathchk_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - pathchk_doc, /* array of long documentation strings. */ - "pathchk [-p] pathname ...", /* usage synopsis */ - 0 /* reserved for internal use */ -}; - -/* The remainder of this file is stolen shamelessly from `pathchk.c' in - the sh-utils-1.12 distribution, by - - David MacKenzie - and Jim Meyering */ - -/* Each element is nonzero if the corresponding ASCII character is - in the POSIX portable character set, and zero if it is not. - In addition, the entry for `/' is nonzero to simplify checking. */ -static char const portable_chars[256] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, /* 32-47 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-63 */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 80-95 */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-127 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* If PATH contains only portable characters, return 1, else 0. */ - -static int -portable_chars_only (path) - const char *path; -{ - const char *p; - - for (p = path; *p; ++p) - if (portable_chars[(const unsigned char) *p] == 0) - { - builtin_error ("path `%s' contains nonportable character `%c'", path, *p); - return 0; - } - return 1; -} - -/* On some systems, stat can return EINTR. */ - -#ifndef EINTR -# define SAFE_STAT(name, buf) stat (name, buf) -#else -# define SAFE_STAT(name, buf) safe_stat (name, buf) -static inline int -safe_stat (name, buf) - const char *name; - struct stat *buf; -{ - int ret; - - do - ret = stat (name, buf); - while (ret < 0 && errno == EINTR); - - return ret; -} -#endif - -/* Return 1 if PATH is a usable leading directory, 0 if not, - 2 if it doesn't exist. */ - -static int -dir_ok (path) - const char *path; -{ - struct stat stats; - - if (SAFE_STAT (path, &stats)) - return 2; - - if (!S_ISDIR (stats.st_mode)) - { - builtin_error ("`%s' is not a directory", path); - return 0; - } - - /* Use access to test for search permission because - testing permission bits of st_mode can lose with new - access control mechanisms. Of course, access loses if you're - running setuid. */ - if (access (path, X_OK) != 0) - { - if (errno == EACCES) - builtin_error ("directory `%s' is not searchable", path); - else - builtin_error ("%s: %s", path, strerror (errno)); - return 0; - } - - return 1; -} - -static char * -xstrdup (s) - char *s; -{ - return (savestring (s)); -} - -/* Make sure that - strlen (PATH) <= PATH_MAX - && strlen (each-existing-directory-in-PATH) <= NAME_MAX - - If PORTABILITY is nonzero, compare against _POSIX_PATH_MAX and - _POSIX_NAME_MAX instead, and make sure that PATH contains no - characters not in the POSIX portable filename character set, which - consists of A-Z, a-z, 0-9, ., _, -. - - Make sure that all leading directories along PATH that exist have - `x' permission. - - Return 0 if all of these tests are successful, 1 if any fail. */ - -static int -validate_path (path, portability) - char *path; - int portability; -{ - int path_max; - int last_elem; /* Nonzero if checking last element of path. */ - int exists; /* 2 if the path element exists. */ - char *slash; - char *parent; /* Last existing leading directory so far. */ - - if (portability && !portable_chars_only (path)) - return 1; - - if (*path == '\0') - return 0; - -#ifdef lint - /* Suppress `used before initialized' warning. */ - exists = 0; -#endif - - /* Figure out the parent of the first element in PATH. */ - parent = xstrdup (*path == '/' ? "/" : "."); - - slash = path; - last_elem = 0; - while (1) - { - int name_max; - int length; /* Length of partial path being checked. */ - char *start; /* Start of path element being checked. */ - - /* Find the end of this element of the path. - Then chop off the rest of the path after this element. */ - while (*slash == '/') - slash++; - start = slash; - slash = strchr (slash, '/'); - if (slash != NULL) - *slash = '\0'; - else - { - last_elem = 1; - slash = strchr (start, '\0'); - } - - if (!last_elem) - { - exists = dir_ok (path); - if (dir_ok == 0) - { - free (parent); - return 1; - } - } - - length = slash - start; - /* Since we know that `parent' is a directory, it's ok to call - pathconf with it as the argument. (If `parent' isn't a directory - or doesn't exist, the behavior of pathconf is undefined.) - But if `parent' is a directory and is on a remote file system, - it's likely that pathconf can't give us a reasonable value - and will return -1. (NFS and tempfs are not POSIX . . .) - In that case, we have no choice but to assume the pessimal - POSIX minimums. */ - name_max = portability ? _POSIX_NAME_MAX : NAME_MAX_FOR (parent); - if (name_max < 0) - name_max = _POSIX_NAME_MAX; - if (length > name_max) - { - builtin_error ("name `%s' has length %d; exceeds limit of %d", - start, length, name_max); - free (parent); - return 1; - } - - if (last_elem) - break; - - if (exists == 1) - { - free (parent); - parent = xstrdup (path); - } - - *slash++ = '/'; - } - - /* `parent' is now the last existing leading directory in the whole path, - so it's ok to call pathconf with it as the argument. */ - path_max = portability ? _POSIX_PATH_MAX : PATH_MAX_FOR (parent); - if (path_max < 0) - path_max = _POSIX_PATH_MAX; - free (parent); - if (strlen (path) > path_max) - { - builtin_error ("path `%s' has length %d; exceeds limit of %d", - path, strlen (path), path_max); - return 1; - } - - return 0; -} diff --git a/examples/loadables/print.c~ b/examples/loadables/print.c~ deleted file mode 100644 index 02d3c92a7..000000000 --- a/examples/loadables/print.c~ +++ /dev/null @@ -1,171 +0,0 @@ -/* - * print -- loadable ksh-93 style print builtin - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "bashtypes.h" - -#include -#include -#include - -#include "bashansi.h" -#include "shell.h" -#include "builtins.h" -#include "stdc.h" -#include "bashgetopt.h" -#include "builtext.h" -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif - -int print_builtin (); -static int printargs (); - -static FILE *ofp; - -extern char *this_command_name; - -static char *print_doc[] = { - "Output the arguments. The -f option means to use the argument as a", - "format string as would be supplied to printf(1). The rest of the", - "options are as in ksh.", - (char *)NULL -}; - -struct builtin print_struct = { - "print", - print_builtin, - BUILTIN_ENABLED, - print_doc, - "print [-Rnprs] [-u unit] [-f format] [arguments]", - (char *)0 -}; - -#ifndef ISOPTION -#define ISOPTION(s, c) (s[0] == '-' && s[2] == '\0' && s[1] == c) -#endif - -int -print_builtin (list) - WORD_LIST *list; -{ - int c, r, nflag, raw, ofd, sflag; - intmax_t lfd; - char **v, *pfmt, *arg; - WORD_LIST *l; - - nflag = raw = sflag = 0; - ofd = 1; - pfmt = 0; - - reset_internal_getopt (); - while ((c = internal_getopt (list, "Rnprsu:f:")) != -1) - { - switch (c) - { - case 'R': - raw = 2; - loptend = lcurrent; - if (loptend && ISOPTION (loptend->word->word, 'n')) - { - loptend = loptend->next; - nflag = 1; - } - goto opt_end; - case 'r': - raw = 1; - break; - case 'n': - nflag = 1; - break; - case 's': - sflag = 1; - break; - case 'p': - break; /* NOP */ - case 'u': - if (all_digits (list_optarg) && legal_number (list_optarg, &lfd) && lfd == (int)lfd) - ofd = lfd; - else - { - for (l = list; l->next && l->next != lcurrent; l = l->next); - lcurrent = loptend = l; - goto opt_end; - } - break; - case 'f': - pfmt = list_optarg; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - -opt_end: - list = loptend; - - ofp = (ofd == 1) ? stdout : fdopen (dup (ofd), "w"); - - if (pfmt) - { - WORD_DESC *w; - WORD_LIST *nlist; - - w = make_word (pfmt); - nlist = make_word_list (w, list); - r = printf_builtin (nlist); - nlist->next = (WORD_LIST *)NULL; - dispose_words (nlist); - return (r); - } - - if (raw) - { - for (l = list; l; l = l->next) - { - fprintf (ofp, "%s", l->word->word); - if (l->next) - fprintf (ofp, " "); - } - if (nflag == 0) - fprintf (ofp, "\n"); - fflush (ofp); - return (0); - } - - r = printargs (list, ofp); - if (r && nflag == 0) - fprintf (ofp, "\n"); - if (ofd != 1) - fclose (ofp); - return 0; -} - -static int -printargs (list, ofp) - WORD_LIST *list; - FILE *ofp; -{ - WORD_LIST *l; - char *ostr; - int sawc; - - for (sawc = 0, l = list; l; l = l->next) - { - ostr = ansicstr (l->word->word, strlen (l->word->word), 0, &sawc, (int *)0); - fprintf (ofp, "%s", ostr); - free (ostr); - if (sawc) - return (0); - if (l->next) - fprintf (ofp, " "); - } - return (1); -} diff --git a/examples/loadables/printenv.c~ b/examples/loadables/printenv.c~ deleted file mode 100644 index 29a82dc09..000000000 --- a/examples/loadables/printenv.c~ +++ /dev/null @@ -1,72 +0,0 @@ -/* - * printenv -- minimal builtin clone of BSD printenv(1). - * - * usage: printenv [varname] - * - */ - -#include -#include - -#include "builtins.h" -#include "shell.h" -#include "bashgetopt.h" -#include "common.h" - -extern char **export_env; - -int -printenv_builtin (list) - WORD_LIST *list; -{ - register char **envp; - int opt; - SHELL_VAR *var; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "")) != -1) - { - switch (opt) - { - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - /* printenv */ - if (list == 0) - { - maybe_make_export_env (); /* this allows minimal code */ - for (envp = export_env; *envp; envp++) - printf ("%s\n", *envp); - return (EXECUTION_SUCCESS); - } - - /* printenv varname */ - var = find_variable (list->word->word); - if (var == 0 || (exported_p (var) == 0)) - return (EXECUTION_FAILURE); - - if (function_p (var)) - print_var_function (var); - else - print_var_value (var, 0); - - return (EXECUTION_SUCCESS); -} - -char *printenv_doc[] = { - "print values of environment variables", - (char *)NULL -}; - -struct builtin printenv_struct = { - "printenv", - printenv_builtin, - BUILTIN_ENABLED, - printenv_doc, - "printenv [varname]", - 0 -}; diff --git a/examples/loadables/push.c~ b/examples/loadables/push.c~ deleted file mode 100644 index fea4b0084..000000000 --- a/examples/loadables/push.c~ +++ /dev/null @@ -1,96 +0,0 @@ -/* - * push - anyone remember TOPS-20? - * - */ - -#include -#include -#include - -#include "builtins.h" -#include "shell.h" -#include "jobs.h" -#include "bashgetopt.h" -#include "common.h" - -#ifndef errno -extern int errno; -#endif - -extern int dollar_dollar_pid; -extern int last_command_exit_value; - -int -push_builtin (list) - WORD_LIST *list; -{ - pid_t pid; - int xstatus, opt; - - xstatus = EXECUTION_SUCCESS; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "")) != -1) - { - switch (opt) - { - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - pid = make_child (savestring ("push"), 0); - if (pid == -1) - { - builtin_error ("cannot fork: %s", strerror (errno)); - return (EXECUTION_FAILURE); - } - else if (pid == 0) - { - /* Shell variable adjustments: $SHLVL, $$, $PPID, $! */ - adjust_shell_level (1); - dollar_dollar_pid = getpid (); - set_ppid (); - - /* Clean up job control stuff. */ - stop_making_children (); - cleanup_the_pipeline (); - delete_all_jobs (0); - - last_asynchronous_pid = NO_PID; - - /* Make sure the job control code has the right values for - the shell's process group and tty process group, and that - the signals are set correctly for job control. */ - initialize_job_control (0); - initialize_job_signals (); - - /* And read commands until exit. */ - reader_loop (); - exit_shell (last_command_exit_value); - } - else - { - stop_pipeline (0, (COMMAND *)NULL); - xstatus = wait_for (pid); - return (xstatus); - } -} - -char *push_doc[] = { - "Create a child that is an exact duplicate of the running shell", - "and wait for it to exit. The $SHLVL, $!, $$, and $PPID variables", - "are adjusted in the child. The return value is the exit status", - "of the child.", - (char *)NULL -}; - -struct builtin push_struct = { - "push", - push_builtin, - BUILTIN_ENABLED, - push_doc, - "push", - 0 -}; diff --git a/examples/loadables/realpath.c~ b/examples/loadables/realpath.c~ deleted file mode 100644 index d94544025..000000000 --- a/examples/loadables/realpath.c~ +++ /dev/null @@ -1,120 +0,0 @@ -/* - * realpath -- canonicalize pathnames, resolving symlinks - * - * usage: realpath [-csv] pathname [pathname...] - * - * options: -c check whether or not each resolved path exists - * -s no output, exit status determines whether path is valid - * -v produce verbose output - * - * - * exit status: 0 if all pathnames resolved - * 1 if any of the pathname arguments could not be resolved - * - * - * Bash loadable builtin version - * - * Chet Ramey - * chet@po.cwru.edu - */ - -#include "config.h" - -#include -#include - -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include "bashansi.h" -#include -#include - -#include "builtins.h" -#include "shell.h" -#include "bashgetopt.h" -#include "common.h" - -#ifndef errno -extern int errno; -#endif - -extern char *sh_realpath(); - -realpath_builtin(list) -WORD_LIST *list; -{ - int opt, cflag, vflag, sflag, es; - char *r, realbuf[PATH_MAX], *p; - struct stat sb; - - if (list == 0) { - builtin_usage(); - return (EX_USAGE); - } - - vflag = cflag = sflag = 0; - reset_internal_getopt(); - while ((opt = internal_getopt (list, "csv")) != -1) { - switch (opt) { - case 'c': - cflag = 1; - break; - case 's': - sflag = 1; - break; - case 'v': - vflag = 1; - break; - default: - builtin_usage(); - } - } - - list = loptend; - - if (list == 0) - builtin_usage(); - - for (es = EXECUTION_SUCCESS; list; list = list->next) { - p = list->word->word; - r = sh_realpath(p, realbuf); - if (r == 0) { - es = EXECUTION_FAILURE; - if (sflag == 0) - builtin_error("%s: cannot resolve: %s", p, strerror(errno)); - continue; - } - if (cflag && (stat(realbuf, &sb) < 0)) { - es = EXECUTION_FAILURE; - if (sflag == 0) - builtin_error("%s: %s", p, strerror(errno)); - continue; - } - if (sflag == 0) { - if (vflag) - printf ("%s -> ", p); - printf("%s\n", realbuf); - } - } - return es; -} - -char *realpath_doc[] = { - "Display the canonicalized version of each PATHNAME argument, resolving", - "symbolic links. The -c option checks whether or not each resolved name", - "exists. The -s option produces no output; the exit status determines the", - "valididty of each PATHNAME. The -v option produces verbose output. The", - "exit status is 0 if each PATHNAME was resolved; non-zero otherwise.", - (char *)NULL -}; - -struct builtin realpath_struct = { - "realpath", /* builtin name */ - realpath_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - realpath_doc, /* array of long documentation strings */ - "realpath [-csv] pathname [pathname...]", /* usage synopsis */ - 0 /* reserved for internal use */ -}; diff --git a/examples/loadables/rmdir.c~ b/examples/loadables/rmdir.c~ deleted file mode 100644 index e52247c3b..000000000 --- a/examples/loadables/rmdir.c~ +++ /dev/null @@ -1,51 +0,0 @@ -/* rmdir - remove directory */ - -/* See Makefile for compilation details. */ - -#include "config.h" - -#include -#include -#include "builtins.h" -#include "shell.h" -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif - -rmdir_builtin (list) - WORD_LIST *list; -{ - int rval; - WORD_LIST *l; - - if (no_options (list)) - return (EX_USAGE); - - for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next) - if (rmdir (l->word->word) < 0) - { - builtin_error ("%s: %s", l->word->word, strerror (errno)); - rval = EXECUTION_FAILURE; - } - - return rval; -} - -char *rmdir_doc[] = { - "rmdir removes the directory entry specified by each argument,", - "provided the directory is empty.", - (char *)NULL -}; - -/* The standard structure describing a builtin command. bash keeps an array - of these structures. */ -struct builtin rmdir_struct = { - "rmdir", /* builtin name */ - rmdir_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - rmdir_doc, /* array of long documentation strings. */ - "rmdir directory ...", /* usage synopsis; becomes short_doc */ - 0 /* reserved for internal use */ -}; diff --git a/examples/loadables/sleep.c~ b/examples/loadables/sleep.c~ deleted file mode 100644 index 58c057f9f..000000000 --- a/examples/loadables/sleep.c~ +++ /dev/null @@ -1,126 +0,0 @@ -/* - * sleep -- sleep for fractions of a second - * - * usage: sleep seconds[.fraction] - */ -#include "config.h" - -#include "bashtypes.h" - -#if defined (TIME_WITH_SYS_TIME) -# include -# include -#else -# if defined (HAVE_SYS_TIME_H) -# include -# else -# include -# endif -#endif - -#if defined (HAVE_UNISTD_H) -#include -#endif - -#include -#include "chartypes.h" - -#include "shell.h" -#include "builtins.h" -#include "common.h" - -#define RETURN(x) \ - do { \ - if (sp) *sp = sec; \ - if (usp) *usp = usec; \ - return (x); \ - } while (0) - -/* - * An incredibly simplistic floating point converter. - */ -static int multiplier[7] = { 1, 100000, 10000, 1000, 100, 10, 1 }; - -static int -convert(s, sp, usp) -char *s; -long *sp, *usp; -{ - int n; - long sec, usec; - char *p; - - sec = usec = 0; - -#define DECIMAL '.' - - for (p = s; p && *p; p++) { - if (*p == DECIMAL) /* decimal point */ - break; - if (DIGIT(*p) == 0) - RETURN(0); - sec = (sec * 10) + (*p - '0'); - } - - if (*p == 0) - RETURN(1); - - if (*p == DECIMAL) - p++; - - /* Look for up to six digits past a decimal point. */ - for (n = 0; n < 6 && p[n]; n++) { - if (DIGIT(p[n]) == 0) - RETURN(0); - usec = (usec * 10) + (p[n] - '0'); - } - - /* Now convert to millionths */ - usec *= multiplier[n]; - - if (n == 6 && p[6] >= '5' && p[6] <= '9') - usec++; /* round up 1 */ - - RETURN(1); -} - -int -sleep_builtin (list) -WORD_LIST *list; -{ - long sec, usec; - - if (list == 0) { - builtin_usage(); - return(EX_USAGE); - } - - if (*list->word->word == '-' || list->next) { - builtin_usage (); - return (EX_USAGE); - } - - if (uconvert(list->word->word, &sec, &usec)) { - fsleep(sec, usec); - return(EXECUTION_SUCCESS); - } - - builtin_error("%s: bad sleep interval", list->word->word); - return (EXECUTION_FAILURE); -} - -static char *sleep_doc[] = { - "Suspend execution for specified period.", - "" - "sleep suspends execution for a minimum of SECONDS[.FRACTION] seconds.", - (char *)NULL -}; - -struct builtin sleep_struct = { - "sleep", - sleep_builtin, - BUILTIN_ENABLED, - sleep_doc, - "sleep seconds[.fraction]", - 0 -}; diff --git a/examples/loadables/sprintf.c~ b/examples/loadables/sprintf.c~ deleted file mode 100644 index a56a49b3c..000000000 --- a/examples/loadables/sprintf.c~ +++ /dev/null @@ -1,514 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if !defined(BUILTIN) && !defined(SHELL) -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1989, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ -#endif - -#ifndef lint -static char sccsid[] = "@(#)printf.c 8.1 (Berkeley) 7/20/93"; -#endif /* not lint */ - -#include - -#include -#include -#include - -#include "bashansi.h" -#include "shell.h" -#include "builtins.h" -#include "stdc.h" - -#if !defined (errno) -extern int errno; -#endif - -static char sbuf[1024]; -static int sblen; - -/* Gee, I wish sprintf could be reliably counted upon to return the - number of characters written :-( */ -#define PF(f, func) \ -do { \ - if (fieldwidth) \ - if (precision) \ - sprintf(sbuf, f, fieldwidth, precision, func); \ - else \ - sprintf(sbuf, f, fieldwidth, func); \ - else if (precision) \ - sprintf(sbuf, f, precision, func); \ - else \ - sprintf(sbuf, f, func); \ - spaddstr (sbuf, strlen (sbuf)); \ -} while (0) - -static int asciicode __P((void)); -static void escape __P((char *)); -static int getchr __P((void)); -static double getdouble __P((void)); -static int getint __P((int *)); -static int getlong __P((long *)); -static char *getstr __P((void)); -static char *mklong __P((char *, int)); -static void usage __P((void)); - -static char **gargv; - -static char *outstr; -static int outsize; -static int outind; - -int sprintf_builtin (); -static int sprintf_main (); -static void spaddstr (); - -extern char *this_command_name; -extern char *single_quote (); -extern char **make_builtin_argv (); - -static char *sprintf_doc[] = { - "sprintf formats and outputs its arguments, after the second, under control", - "of the format and assigns the result to the variable named by its first", - "argument. The format is a character string which contains three types", - "of objects: plain characters, which are simply copied to the output string,", - "character escape sequences which are converted and copied to the output", - "string, and format specifications, each of which causes printing of the", - "next successive argument. In addition to the standard sprintf(3) formats,", - "%b means to expand escapes in the corresponding argument, and %q means", - "to quote the argument in a way that can be reused as shell input. Each", - "one of the format specifications must not expand to more than 1024", - "characters, though there is no limit on the total size of the output", - "string.", - (char *)NULL -}; - -struct builtin sprintf_struct = { - "sprintf", - sprintf_builtin, - BUILTIN_ENABLED, - sprintf_doc, - "sprintf var format [arguments]", - (char *)0 -}; - -int -sprintf_builtin (list) - WORD_LIST *list; -{ - int c, r; - char **v, *varname; - WORD_LIST *l; - SHELL_VAR *var; - - if (list == 0) - { - builtin_usage (); - return (EXECUTION_FAILURE); - } - - varname = list->word->word; - list = list->next; - - if (legal_identifier (varname) == 0) - { - builtin_error ("%s: not a legal variable name", varname); - return (EXECUTION_FAILURE); - } - - outind = 0; - if (outstr == 0) - outstr = xmalloc (outsize = 64); - outstr[0] = '\0'; - - v = make_builtin_argv (list, &c); - r = sprintf_main (c, v); - free (v); - - var = bind_variable (varname, outstr, 0); - if (readonly_p (var)) - { - builtin_error ("%s: readonly variable", varname); - return (EXECUTION_FAILURE); - } - - return r; -} - -static void -spaddstr(str, len) - char *str; - int len; -{ - RESIZE_MALLOCED_BUFFER (outstr, outind, len, outsize, 64); - strcpy (outstr + outind, str); - outind += len; -} - -static int -sprintf_main(argc, argv) - int argc; - char *argv[]; -{ - extern int optind; - static char *skip1, *skip2; - int ch, end, fieldwidth, precision; - char convch, nextch, *format, *fmt, *start; - - while ((ch = getopt(argc, argv, "")) != EOF) - switch (ch) { - case '?': - default: - usage(); - return (1); - } - argc -= optind; - argv += optind; - - if (argc < 1) { - usage(); - return (1); - } - - /* - * Basic algorithm is to scan the format string for conversion - * specifications -- once one is found, find out if the field - * width or precision is a '*'; if it is, gather up value. Note, - * format strings are reused as necessary to use up the provided - * arguments, arguments of zero/null string are provided to use - * up the format string. - */ - skip1 = "#-+ 0"; - skip2 = "*0123456789"; - - escape(fmt = format = *argv); /* backslash interpretation */ - gargv = ++argv; - for (;;) { - end = 0; - /* find next format specification */ -next: for (start = fmt;; ++fmt) { - if (!*fmt) { - /* avoid infinite loop */ - if (end == 1) { - warnx("missing format character", - NULL, NULL); - return (1); - } - end = 1; - if (fmt > start) - (void)printf("%s", start); - if (!*gargv) - return (0); - fmt = format; - goto next; - } - /* %% prints a % */ - if (*fmt == '%') { - if (*++fmt != '%') - break; - *fmt++ = '\0'; - (void)printf("%s", start); - goto next; - } - } - - /* skip to field width */ - for (; strchr(skip1, *fmt); ++fmt); - if (*fmt == '*') { - if (getint(&fieldwidth)) - return (1); - } else - fieldwidth = 0; - - /* skip to possible '.', get following precision */ - for (; strchr(skip2, *fmt); ++fmt); - if (*fmt == '.') - ++fmt; - if (*fmt == '*') { - if (getint(&precision)) - return (1); - } else - precision = 0; - - /* skip to conversion char */ - for (; strchr(skip2, *fmt); ++fmt); - if (!*fmt) { - warnx("missing format character", NULL, NULL); - return (1); - } - - convch = *fmt; - nextch = *++fmt; - *fmt = '\0'; - switch(convch) { - case 'c': { - char p; - - p = getchr(); - PF(start, p); - break; - } - case 's': { - char *p; - - p = getstr(); - PF(start, p); - break; - } - case 'b': { /* expand escapes in argument */ - char *p; - - p = getstr(); - escape(p); - PF("%s", p); - break; - } - case 'q': { /* print with shell single quoting */ - char *p, *p2; - - p = getstr(); - p2 = single_quote(p); - PF("%s", p2); - free(p2); - break; - } - case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { - long p; - char *f; - - if ((f = mklong(start, convch)) == NULL) - return (1); - if (getlong(&p)) - return (1); - PF(f, p); - break; - } - case 'e': case 'E': case 'f': case 'g': case 'G': { - double p; - - p = getdouble(); - PF(start, p); - break; - } - default: - warnx("illegal format character", NULL, NULL); - return (1); - } - *fmt = nextch; - } - /* NOTREACHED */ -} - -static char * -mklong(str, ch) - char *str; - int ch; -{ - static char copy[64]; - int len; - - len = strlen(str) + 2; - memmove(copy, str, len - 3); - copy[len - 3] = 'l'; - copy[len - 2] = ch; - copy[len - 1] = '\0'; - return (copy); -} - -static void -escape(fmt) - register char *fmt; -{ - register char *store; - register int value, c; - - for (store = fmt; c = *fmt; ++fmt, ++store) { - if (c != '\\') { - *store = c; - continue; - } - switch (*++fmt) { - case '\0': /* EOS, user error */ - *store = '\\'; - *++store = '\0'; - return; - case '\\': /* backslash */ - case '\'': /* single quote */ - *store = *fmt; - break; - case 'a': /* bell/alert */ - *store = '\7'; - break; - case 'b': /* backspace */ - *store = '\b'; - break; - case 'c': - return; - case 'e': - case 'E': - *store = '\033'; - break; - case 'f': /* form-feed */ - *store = '\f'; - break; - case 'n': /* newline */ - *store = '\n'; - break; - case 'r': /* carriage-return */ - *store = '\r'; - break; - case 't': /* horizontal tab */ - *store = '\t'; - break; - case 'v': /* vertical tab */ - *store = '\13'; - break; - /* octal constant */ - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - for (c = 3, value = 0; - c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { - value <<= 3; - value += *fmt - '0'; - } - --fmt; - *store = value; - break; - default: - *store = *fmt; - break; - } - } - *store = '\0'; -} - -static int -getchr() -{ - if (!*gargv) - return ('\0'); - return ((int)**gargv++); -} - -static char * -getstr() -{ - if (!*gargv) - return (""); - return (*gargv++); -} - -static char *Number = "+-.0123456789"; -static int -getint(ip) - int *ip; -{ - long val; - - if (getlong(&val)) - return (1); - if (val > INT_MAX) { - warnx("%s: %s", *gargv, strerror(ERANGE)); - return (1); - } - *ip = val; - return (0); -} - -static int -getlong(lp) - long *lp; -{ - long val; - char *ep; - - if (!*gargv) { - *lp = 0; - return (0); - } - if (strchr(Number, **gargv)) { - errno = 0; - val = strtol(*gargv, &ep, 0); - if (*ep != '\0') { - warnx("%s: illegal number", *gargv, NULL); - return (1); - } - if (errno == ERANGE) - if (val == LONG_MAX) { - warnx("%s: %s", *gargv, strerror(ERANGE)); - return (1); - } - if (val == LONG_MIN) { - warnx("%s: %s", *gargv, strerror(ERANGE)); - return (1); - } - - *lp = val; - ++gargv; - return (0); - } - *lp = (long)asciicode(); - return (0); -} - -static double -getdouble() -{ - if (!*gargv) - return ((double)0); - if (strchr(Number, **gargv)) - return (atof(*gargv++)); - return ((double)asciicode()); -} - -static int -asciicode() -{ - register int ch; - - ch = **gargv; - if (ch == '\'' || ch == '"') - ch = (*gargv)[1]; - ++gargv; - return (ch); -} - -static void -usage() -{ - (void)fprintf(stderr, "usage: printf format [arg ...]\n"); -} diff --git a/examples/loadables/strftime.c~ b/examples/loadables/strftime.c~ deleted file mode 100644 index 92f489e38..000000000 --- a/examples/loadables/strftime.c~ +++ /dev/null @@ -1,105 +0,0 @@ -/* strftime - loadable builtin interface to strftime(3) */ - -/* See Makefile for compilation details. */ - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashtypes.h" -#include "posixtime.h" - -#include - -#include "builtins.h" -#include "shell.h" -#include "common.h" - -int -strftime_builtin (list) - WORD_LIST *list; -{ - char *format, *tbuf; - size_t tbsize, tsize; - time_t secs; - struct tm *t; - int n; - intmax_t i; - - if (list == 0) - { - builtin_usage (); - return (EX_USAGE); - } - - if (no_options (list)) - return (EX_USAGE); - - format = list->word->word; - if (format == 0 || *format == 0) - { - printf ("\n"); - return (EXECUTION_SUCCESS); - } - - list = list->next; - - if (list && list->word->word) - { - n = legal_number (list->word->word, &i); - if (n == 0 || i < 0 || i != (time_t)i) - { - sh_invalidnum (list->word->word); - return (EXECUTION_FAILURE); - } - else - secs = i; - } - else - secs = NOW; - - t = localtime (&secs); - - tbsize = strlen (format) * 4; - tbuf = 0; - - /* Now try to figure out how big the buffer should really be. strftime(3) - will return the number of bytes placed in the buffer unless it's greater - than MAXSIZE, in which case it returns 0. */ - for (n = 1; n < 4; n++) - { - tbuf = xrealloc (tbuf, tbsize * n); - tsize = strftime (tbuf, tbsize * n, format, t); - if (tsize) - break; - } - - printf ("%s\n", tbuf); - free (tbuf); - - return (EXECUTION_SUCCESS); -} - -/* An array of strings forming the `long' documentation for a builtin xxx, - which is printed by `help xxx'. It must end with a NULL. */ -char *strftime_doc[] = { - "Converts date and time format to a string and displays it on the", - "standard output. If the optional second argument is supplied, it", - "is used as the number of seconds since the epoch to use in the", - "conversion, otherwise the current time is used.", - (char *)NULL -}; - -/* The standard structure describing a builtin command. bash keeps an array - of these structures. The flags must include BUILTIN_ENABLED so the - builtin can be used. */ -struct builtin strftime_struct = { - "strftime", /* builtin name */ - strftime_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - strftime_doc, /* array of long documentation strings. */ - "strftime format [seconds]", /* usage synopsis; becomes short_doc */ - 0 /* reserved for internal use */ -}; diff --git a/examples/loadables/sync.c~ b/examples/loadables/sync.c~ deleted file mode 100644 index 44d4e095e..000000000 --- a/examples/loadables/sync.c~ +++ /dev/null @@ -1,32 +0,0 @@ -/* sync - sync the disks by forcing pending filesystem writes to complete */ - -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "builtins.h" -#include "shell.h" -#include "bashgetopt.h" - -sync_builtin (list) - WORD_LIST *list; -{ - sync(); - return (EXECUTION_SUCCESS); -} - -char *sync_doc[] = { - "force completion of pending disk writes", - (char *)NULL -}; - -struct builtin sync_struct = { - "sync", /* builtin name */ - sync_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - sync_doc, /* array of long documentation strings. */ - "sync", /* usage synopsis; becomes short_doc */ - 0 /* reserved for internal use */ -}; diff --git a/examples/loadables/tee.c~ b/examples/loadables/tee.c~ deleted file mode 100644 index 6e2ea355d..000000000 --- a/examples/loadables/tee.c~ +++ /dev/null @@ -1,158 +0,0 @@ -/* tee - duplicate standard input */ - -/* See Makefile for compilation details. */ - -#include "config.h" - -#include "bashtypes.h" -#include "posixstat.h" -#include "filecntl.h" - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" - -#include -#include - -#include "builtins.h" -#include "shell.h" -#include "bashgetopt.h" -#include "common.h" - -#if !defined (errno) -extern int errno; -#endif - -typedef struct flist { - struct flist *next; - int fd; - char *fname; -} FLIST; - -static FLIST *tee_flist; - -#define TEE_BUFSIZE 8192 - -extern int interrupt_immediately; - -extern char *strerror (); - -tee_builtin (list) - WORD_LIST *list; -{ - int opt, append, nointr, rval, fd, fflags; - int n, nr, nw; - FLIST *fl; - char *buf, *bp; - - char *t; - - reset_internal_getopt (); - append = nointr = 0; - tee_flist = (FLIST *)NULL; - while ((opt = internal_getopt (list, "ai")) != -1) - { - switch (opt) - { - case 'a': - append = 1; - break; - case 'i': - nointr = 1; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - if (nointr == 0) - interrupt_immediately++; - - buf = xmalloc (TEE_BUFSIZE); - - /* Initialize output file list. */ - fl = tee_flist = (FLIST *)xmalloc (sizeof(FLIST)); - tee_flist->fd = 1; - tee_flist->fname = "stdout"; - tee_flist->next = (FLIST *)NULL; - - /* Add file arguments to list of output files. */ - fflags = append ? O_WRONLY|O_CREAT|O_APPEND : O_WRONLY|O_CREAT|O_TRUNC; - for (rval = EXECUTION_SUCCESS; list; list = list->next) - { - fd = open (list->word->word, fflags, 0666); - if (fd < 0) - { - builtin_error ("%s: cannot open: %s", list->word->word, strerror (errno)); - rval = EXECUTION_FAILURE; - } - else - { - fl->next = (FLIST *)xmalloc (sizeof(FLIST)); - fl->next->fd = fd; - fl->next->fname = list->word->word; - fl = fl->next; - fl->next = (FLIST *)NULL; - } - } - - while ((nr = read(0, buf, TEE_BUFSIZE)) > 0) - for (fl = tee_flist; fl; fl = fl->next) - { - n = nr; - bp = buf; - do - { - if ((nw = write (fl->fd, bp, n)) == -1) - { - builtin_error ("%s: write error: %s", fl->fname, strerror (errno)); - rval = EXECUTION_FAILURE; - break; - } - bp += nw; - } - while (n -= nw); - } - if (nr < 0) - builtin_error ("read error: %s", strerror (errno)); - - /* Deallocate resources -- this is a builtin command. */ - tee_flist = tee_flist->next; /* skip bogus close of stdout */ - while (tee_flist) - { - fl = tee_flist; - if (close (fl->fd) < 0) - { - builtin_error ("%s: close_error: %s", fl->fname, strerror (errno)); - rval = EXECUTION_FAILURE; - } - tee_flist = tee_flist->next; - free (fl); - } - - return (rval); -} - -char *tee_doc[] = { - "Copy standard input to standard output, making a copy in each", - "filename argument. If the `-a' option is gived, the specified", - "files are appended to, otherwise they are overwritten. If the", - "`-i' option is supplied, tee ignores interrupts.", - (char *)NULL -}; - -struct builtin tee_struct = { - "tee", /* builtin name */ - tee_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - tee_doc, /* array of long documentation strings. */ - "tee [-ai] [file ...]", /* usage synopsis; becomes short_doc */ - 0 /* reserved for internal use */ -}; diff --git a/examples/loadables/template.c~ b/examples/loadables/template.c~ deleted file mode 100644 index 7bb3f9f35..000000000 --- a/examples/loadables/template.c~ +++ /dev/null @@ -1,56 +0,0 @@ -/* template - example template for loadable builtin */ - -/* See Makefile for compilation details. */ - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif -#include "bashansi.h" -#include -#include - -#include "builtins.h" -#include "shell.h" -#include "bashgetopt.h" - -#if !defined (errno) -extern int errno; -#endif - -extern char *strerror (); - -template_builtin (list) - WORD_LIST *list; -{ - int opt, rval; - - rval = EXECUTION_SUCCESS; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "")) != -1) - { - switch (opt) - { - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - return (rval); -} - -char *template_doc[] = { - (char *)NULL -}; - -struct builtin template_struct = { - "template", /* builtin name */ - template_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - template_doc, /* array of long documentation strings. */ - "template", /* usage synopsis; becomes short_doc */ - 0 /* reserved for internal use */ -}; diff --git a/examples/loadables/truefalse.c~ b/examples/loadables/truefalse.c~ deleted file mode 100644 index a6ae7aa8d..000000000 --- a/examples/loadables/truefalse.c~ +++ /dev/null @@ -1,47 +0,0 @@ -/* true and false builtins */ -#include - -#include "bashtypes.h" -#include "shell.h" -#include "builtins.h" -#include "common.h" - -true_builtin (list) - WORD_LIST *list; -{ - return EXECUTION_SUCCESS; -} - -false_builtin (list) - WORD_LIST *list; -{ - return EXECUTION_FAILURE; -} - -static char *true_doc[] = { - "Return a successful result.", - (char *)NULL -}; - -static char *false_doc[] = { - "Return an unsuccessful result.", - (char *)NULL -}; - -struct builtin true_struct = { - "true", - true_builtin, - BUILTIN_ENABLED, - true_doc, - "true", - 0 -}; - -struct builtin false_struct = { - "false", - false_builtin, - BUILTIN_ENABLED, - false_doc, - "false", - 0 -}; diff --git a/examples/loadables/tty.c~ b/examples/loadables/tty.c~ deleted file mode 100644 index 1ce7afebc..000000000 --- a/examples/loadables/tty.c~ +++ /dev/null @@ -1,60 +0,0 @@ -/* tty - return terminal name */ - -/* See Makefile for compilation details. */ - -#include "config.h" - -#include -#include "builtins.h" -#include "shell.h" -#include "bashgetopt.h" -#include "common.h" - -extern char *ttyname (); - -tty_builtin (list) - WORD_LIST *list; -{ - int opt, sflag; - char *t; - - reset_internal_getopt (); - sflag = 0; - while ((opt = internal_getopt (list, "s")) != -1) - { - switch (opt) - { - case 's': - sflag = 1; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - t = ttyname (0); - if (sflag == 0) - puts (t ? t : "not a tty"); - return (t ? EXECUTION_SUCCESS : EXECUTION_FAILURE); -} - -char *tty_doc[] = { - "tty writes the name of the terminal that is opened for standard", - "input to standard output. If the `-s' option is supplied, nothing", - "is written; the exit status determines whether or not the standard", - "input is connected to a tty.", - (char *)NULL -}; - -/* The standard structure describing a builtin command. bash keeps an array - of these structures. */ -struct builtin tty_struct = { - "tty", /* builtin name */ - tty_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - tty_doc, /* array of long documentation strings. */ - "tty [-s]", /* usage synopsis; becomes short_doc */ - 0 /* reserved for internal use */ -}; diff --git a/examples/loadables/uname.c~ b/examples/loadables/uname.c~ deleted file mode 100644 index 25ad497ef..000000000 --- a/examples/loadables/uname.c~ +++ /dev/null @@ -1,140 +0,0 @@ -/* - * uname - print system information - * - * usage: uname [-amnrsv] - * - */ - -#include -#include - -#include "bashtypes.h" - -#if defined (HAVE_UNAME) -# include -#else -struct utsname { - char sysname[32]; - char nodename[32]; - char release[32]; - char version[32]; - char machine[32]; -}; -#endif - -#include - -#include "builtins.h" -#include "shell.h" -#include "bashgetopt.h" -#include "common.h" - -#define FLAG_SYSNAME 0x01 /* -s */ -#define FLAG_NODENAME 0x02 /* -n */ -#define FLAG_RELEASE 0x04 /* -r */ -#define FLAG_VERSION 0x08 /* -v */ -#define FLAG_MACHINE 0x10 /* -m, -p */ - -#define FLAG_ALL 0x1f - -#ifndef errno -extern int errno; -#endif - -static void uprint(); - -static int uname_flags; - -uname_builtin (list) - WORD_LIST *list; -{ - int opt, r; - struct utsname uninfo; - - uname_flags = 0; - reset_internal_getopt (); - while ((opt = internal_getopt (list, "amnprsv")) != -1) - { - switch (opt) - { - case 'a': - uname_flags |= FLAG_ALL; - break; - case 'm': - case 'p': - uname_flags |= FLAG_MACHINE; - break; - case 'n': - uname_flags |= FLAG_NODENAME; - break; - case 'r': - uname_flags |= FLAG_RELEASE; - break; - case 's': - uname_flags |= FLAG_SYSNAME; - break; - case 'v': - uname_flags |= FLAG_VERSION; - break; - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - - if (list) - { - builtin_usage (); - return (EX_USAGE); - } - - if (uname_flags == 0) - uname_flags = FLAG_SYSNAME; - - /* Only ancient systems will not have uname(2). */ -#ifdef HAVE_UNAME - if (uname (&uninfo) < 0) - { - builtin_error ("cannot get system name: %s", strerror (errno)); - return (EXECUTION_FAILURE); - } -#else - builtin_error ("cannot get system information: uname(2) not available"); - return (EXECUTION_FAILURE); -#endif - - uprint (FLAG_SYSNAME, uninfo.sysname); - uprint (FLAG_NODENAME, uninfo.nodename); - uprint (FLAG_RELEASE, uninfo.release); - uprint (FLAG_VERSION, uninfo.version); - uprint (FLAG_MACHINE, uninfo.machine); - - return (EXECUTION_SUCCESS); -} - -static void -uprint (flag, info) - int flag; - char *info; -{ - if (uname_flags & flag) - { - uname_flags &= ~flag; - printf ("%s%c", info, uname_flags ? ' ' : '\n'); - } -} - -char *uname_doc[] = { - "display information about the system", - (char *)NULL -}; - -struct builtin uname_struct = { - "uname", - uname_builtin, - BUILTIN_ENABLED, - uname_doc, - "uname [-amnrsv]", - 0 -}; diff --git a/examples/loadables/unlink.c~ b/examples/loadables/unlink.c~ deleted file mode 100644 index 3b5aafba3..000000000 --- a/examples/loadables/unlink.c~ +++ /dev/null @@ -1,53 +0,0 @@ -/* unlink - remove a directory entry */ - -/* Should only be used to remove directories by a superuser prepared to let - fsck clean up the file system. */ - -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#include -#include - -#include "builtins.h" -#include "shell.h" -#include "common.h" - -#ifndef errno -extern int errno; -#endif - -unlink_builtin (list) - WORD_LIST *list; -{ - if (list == 0) - { - builtin_usage (); - return (EX_USAGE); - } - - if (unlink (list->word->word) != 0) - { - builtin_error ("%s: cannot unlink: %s", list->word->word, strerror (errno)); - return (EXECUTION_FAILURE); - } - - return (EXECUTION_SUCCESS); -} - -char *unlink_doc[] = { - "Remove a directory entry.", - (char *)NULL -}; - -struct builtin unlink_struct = { - "unlink", /* builtin name */ - unlink_builtin, /* function implementing the builtin */ - BUILTIN_ENABLED, /* initial flags for builtin */ - unlink_doc, /* array of long documentation strings. */ - "unlink name", /* usage synopsis; becomes short_doc */ - 0 /* reserved for internal use */ -}; diff --git a/examples/loadables/whoami.c~ b/examples/loadables/whoami.c~ deleted file mode 100644 index e89d872f9..000000000 --- a/examples/loadables/whoami.c~ +++ /dev/null @@ -1,53 +0,0 @@ -/* - * whoami - print out username of current user - */ - -#include -#include - -#include "builtins.h" -#include "shell.h" -#include "bashgetopt.h" -#include "common.h" - -whoami_builtin (list) - WORD_LIST *list; -{ - int opt; - - reset_internal_getopt (); - while ((opt = internal_getopt (list, "")) != -1) - { - switch (opt) - { - default: - builtin_usage (); - return (EX_USAGE); - } - } - list = loptend; - if (list) - { - builtin_usage (); - return (EX_USAGE); - } - - if (current_user.user_name == 0) - get_current_user_info (); - printf ("%s\n", current_user.user_name); - return (EXECUTION_SUCCESS); -} - -char *whoami_doc[] = { - "display name of current user", - (char *)NULL -}; - -struct builtin whoami_struct = { - "whoami", - whoami_builtin, - BUILTIN_ENABLED, - whoami_doc, - "whoami", - 0 -}; diff --git a/examples/loadables/xtitle.c~ b/examples/loadables/xtitle.c~ deleted file mode 100644 index 244c8fa91..000000000 --- a/examples/loadables/xtitle.c~ +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Originally from - * http://www.excessus.demon.co.uk/misc-hacks/index.html#xtitle - */ - -/* - * Made into a loadable builtin by chet@po.cwru.edu. - */ - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include -#include -#include -#include - -#include - -#ifdef BASH_BUILTIN -#include "shell.h" -#include "builtins.h" -#include "bashgetopt.h" -#endif - -#ifdef BASH_BUILTIN -int xtitle_builtin(WORD_LIST *list) -#else -int main(int argc, char *argv[]) -#endif -{ - int query = 0; - int fd; - int openned = 0; - -#ifdef BASH_BUILTIN - reset_internal_getopt(); -#endif - for (;;) { -#ifdef BASH_BUILTIN - int i; - i = internal_getopt(list, "q"); -#else - int i = getopt(argc, argv, "q"); -#endif - if (i < 0) - break; - switch (i) { - case 'q': - query = 1; - break; - default: -#ifdef BASH_BUILTIN - builtin_usage(); -#else - fprintf(stderr, "usage: xtitle [-q] [string]\n"); -#endif - return (1); - } - } - -#ifdef BASH_BUILTIN - if (!query && loptend == 0) { -#else - if (!query && optind == argc) { -#endif - fprintf(stderr, "xtitle: no string to set\n"); - return (1); - } - - { - char *t = getenv("TERM"); - if (!t || strncmp(t, "xterm", 5)) - return (0); - } - - if (isatty(0)) - fd = 0; - else { - fd = open("/dev/tty", O_RDWR); - if (fd < 0) { - fprintf(stderr, "xtitle: couldn't open terminal: %s", strerror(errno)); - return (1); - } - openned = 1; - } - - if (!query) { -#ifdef BASH_BUILTIN - WORD_LIST *l = loptend; - char sp = ' '; - write(fd, "\33]0;", 4); - while (l) { - write(fd, l->word->word, strlen(l->word->word)); - if (l->next) - write(fd, &sp, 1); - l = l->next; - } - write(fd, "\33\\", 2); -#else - int i; - char sp = ' '; - write(fd, "\33]0;", 4); - for (i = optind; i < argc; i++) { - write(fd, argv[i], strlen(argv[i])); - if (i < argc - 1) - write(fd, &sp, 1); - } - write(fd, "\33\\", 2); -#endif - } else { - struct termios o, n; - char hack; - int state = 0; - - tcgetattr(fd, &o); - n = o; - n.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP - |INLCR|IGNCR|ICRNL|IXON); - n.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); - n.c_cflag &= ~(CSIZE|PARENB); - n.c_cflag |= CS8; - tcsetattr(fd, TCSAFLUSH, &n); - write(fd, "\33[21t", 5); - - while (state != -1) { - if (read(fd, &hack, 1) < 1) - break; - switch (state) { - case 0: - if (hack == '\33') state = 1; - break; - case 1: - if (hack == ']') state = 2; else state = 0; - break; - case 2: - if (hack == 'l') state = 3; else state = 0; - break; - case 3: - if (hack == '\33') state = 4; else putchar(hack); - break; - case 4: - if (hack == '\\') { state = -1; putchar('\n'); } - else { putchar('\33'); putchar(hack); state = 3; } - break; - } - } - - tcsetattr(fd, TCSAFLUSH, &o); - } - - if (openned) - close(fd); - - return (0); -} - - -#ifdef BASH_BUILTIN - -static char *xtitle_doc[] = { - "Either set or read the title of the current xterm window. With the", - "-q option, writes the current xterm title to standard output. Without", - "the -q option, sets the xterm title to be the arguments given,", - "separated by space characters. [By Mark Wooding, mdw@nsict.org]", - 0 -}; - -struct builtin xtitle_struct = { - "xtitle", - xtitle_builtin, - BUILTIN_ENABLED, - xtitle_doc, - "xtitle [-q] [arguments]", - 0 -}; - -#endif 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 e10538464..000000000 --- a/execute_cmd.c~ +++ /dev/null @@ -1,4889 +0,0 @@ -/* execute_cmd.c -- Execute a COMMAND structure. */ - -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#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 expand_aliases; -extern int autocd; -extern int breaking, continuing, loop_level; -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 int tempenv_assign_error; -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)); -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 *)); -#if defined (COPROCESS_SUPPORT) -static int execute_coproc __P((COMMAND *, int, int, struct fd_bitmap *)); -#endif - -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 *)); - -/* 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; - -/* 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; - -/* When greater than zero, value is the `level' of builtins we are - currently executing (e.g. `eval echo a' would have it set to 2). */ -int executing_builtin = 0; - -/* Non-zero if we are executing a command list (a;b;c, etc.) */ -int executing_list = 0; - -/* Non-zero if failing commands in a command substitution should not exit the - shell even if -e is set. Used to pass the CMD_IGNORE_RETURN flag down to - commands run in command substitutions by parse_and_execute. */ -int comsub_ignore_return = 0; - -/* 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; - -/* If non-zero, matches in case and [[ ... ]] are case-insensitive */ -int match_ignore_case = 0; - -struct stat SB; /* used for debugging */ - -static int special_builtin_failed; - -static COMMAND *currently_executing_command; - -/* The line number that the currently executing function starts on. */ -static int function_line_number; - -/* 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; - -static int line_number_for_err_trap; - -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 */ - - QUIT; - return (result); -} - -/* Return 1 if TYPE is a shell control structure type. */ -static int -shell_control_structure (type) - enum command_type type; -{ - switch (type) - { -#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_for: - case cm_group: - case cm_function_def: - 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, user_subshell, invert, ignore_return, was_error_trap; - REDIRECT *my_undo_list, *exec_undo_list; - volatile int last_pid; - volatile int save_line_number; - -#if 0 - if (command == 0 || breaking || continuing || read_but_dont_execute) - return (EXECUTION_SUCCESS); -#else - if (breaking || continuing) - return (last_command_exit_value); - if (command == 0 || read_but_dont_execute) - return (EXECUTION_SUCCESS); -#endif - - QUIT; - 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 defined (COPROCESS_SUPPORT) - if (command->type == cm_coproc) - return (execute_coproc (command, pipe_in, pipe_out, fds_to_close)); -#endif - - user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0); - - 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) - { - was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; - invert = (command->flags & CMD_INVERT_RETURN) != 0; - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 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; - - - if (user_subshell && was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - run_error_trap (); - } - - if (user_subshell && ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) - { -fprintf(stderr, "user subshell errexit\n"); - last_command_exit_value = exec_result; - run_pending_traps (); - jump_to_top_level (ERREXIT); - } - - 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 (last_command_exit_value = 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. */ -#if defined (RECYCLES_PIDS) - last_made_pid = NO_PID; -#endif - 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_for_err_trap = 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_made_pid != last_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); - } - } - - /* 2009/02/13 -- pipeline failure is processed elsewhere. This handles - only the failure of a simple command. */ - if (was_error_trap && ignore_return == 0 && invert == 0 && pipe_in == NO_PIPE && pipe_out == NO_PIPE && 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 && pipe_in == NO_PIPE && pipe_out == NO_PIPE && 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; - -#if defined (DPAREN_ARITHMETIC) || defined (COND_COMMAND) - /* This is where we set PIPESTATUS from the exit status of the appropriate - compound commands (the ones that look enough like simple commands to - cause confusion). We might be able to optimize by not doing this if - subshell_environment != 0. */ - switch (command->type) - { -# if defined (DPAREN_ARITHMETIC) - case cm_arith: -# endif -# if defined (COND_COMMAND) - case cm_cond: -# endif - set_pipestatus_from_exit (exec_result); - break; - } -#endif - - 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 const 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 0 - /* clamp CPU usage at 100% */ - if (cpu > 10000) - cpu = 10000; -#endif - 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, user_coproc; - COMMAND *tcom; - - USE_VAR(user_subshell); - USE_VAR(user_coproc); - 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); - user_coproc = command->type == cm_coproc; - - 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. - XXX - asynchronous used to be set to 0 in this block, but that - means that setup_async_signals was never run. Now it's set to - 0 after subshell_environment is set appropriately and setup_async_signals - is run. - - 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; - } - - /* Subshells are neither login nor interactive. */ - login_shell = interactive = 0; - - if (user_subshell) - subshell_environment = SUBSHELL_PAREN; - else - { - subshell_environment = 0; /* XXX */ - if (asynchronous) - subshell_environment |= SUBSHELL_ASYNC; - if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) - subshell_environment |= SUBSHELL_PIPE; - if (user_coproc) - subshell_environment |= SUBSHELL_COPROC; - } - - reset_terminating_signals (); /* in sig.c */ - /* Cancel traps, in trap.c. */ - restore_original_signals (); - - /* Make sure restore_original_signals doesn't undo the work done by - make_child to ensure that asynchronous children are immune to SIGINT - and SIGQUIT. Turn off asynchronous to make sure more subshells are - not spawned. */ - if (asynchronous) - { - setup_async_signals (); - asynchronous = 0; - } - -#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 defined (COPROCESS_SUPPORT) - coproc_closeall (); -#endif - - /* 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; - } - - if (command->type == cm_subshell) - tcom = command->value.Subshell->command; - else if (user_coproc) - tcom = command->value.Coproc->command; - else - tcom = command; - - if (command->flags & CMD_TIME_PIPELINE) - tcom->flags |= CMD_TIME_PIPELINE; - if (command->flags & CMD_TIME_POSIX) - tcom->flags |= CMD_TIME_POSIX; - - /* 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 || user_coproc) && (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 */ -} - -#if defined (COPROCESS_SUPPORT) -#define COPROC_MAX 16 - -typedef struct cpelement - { - struct cpelement *next; - struct coproc *coproc; - } -cpelement_t; - -typedef struct cplist - { - struct cpelement *head; - struct cpelement *tail; - int ncoproc; - } -cplist_t; - -static struct cpelement *cpe_alloc __P((struct coproc *)); -static void cpe_dispose __P((struct cpelement *)); -static struct cpelement *cpl_add __P((struct coproc *)); -static struct cpelement *cpl_delete __P((pid_t)); -static void cpl_reap __P((void)); -static void cpl_flush __P((void)); -static struct cpelement *cpl_search __P((pid_t)); -static struct cpelement *cpl_searchbyname __P((char *)); -static void cpl_prune __P((void)); - -Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0 }; - -cplist_t coproc_list = {0, 0, 0}; - -/* Functions to manage the list of coprocs */ - -static struct cpelement * -cpe_alloc (cp) - Coproc *cp; -{ - struct cpelement *cpe; - - cpe = (struct cpelement *)xmalloc (sizeof (struct cpelement)); - cpe->coproc = cp; - cpe->next = (struct cpelement *)0; - return cpe; -} - -static void -cpe_dispose (cpe) - struct cpelement *cpe; -{ - free (cpe); -} - -static struct cpelement * -cpl_add (cp) - Coproc *cp; -{ - struct cpelement *cpe; - - cpe = cpe_alloc (cp); - - if (coproc_list.head == 0) - { - coproc_list.head = coproc_list.tail = cpe; - coproc_list.ncoproc = 0; /* just to make sure */ - } - else - { - coproc_list.tail->next = cpe; - coproc_list.tail = cpe; - } - coproc_list.ncoproc++; - - return cpe; -} - -static struct cpelement * -cpl_delete (pid) - pid_t pid; -{ - struct cpelement *prev, *p; - - for (prev = p = coproc_list.head; p; prev = p, p = p->next) - if (p->coproc->c_pid == pid) - { - prev->next = p->next; /* remove from list */ - break; - } - - if (p == 0) - return 0; /* not found */ - -#if defined (DEBUG) - itrace("cpl_delete: deleting %d", pid); -#endif - - /* Housekeeping in the border cases. */ - if (p == coproc_list.head) - coproc_list.head = coproc_list.head->next; - else if (p == coproc_list.tail) - coproc_list.tail = prev; - - coproc_list.ncoproc--; - if (coproc_list.ncoproc == 0) - coproc_list.head = coproc_list.tail = 0; - else if (coproc_list.ncoproc == 1) - coproc_list.tail = coproc_list.head; /* just to make sure */ - - return (p); -} - -static void -cpl_reap () -{ - struct cpelement *prev, *p; - - for (prev = p = coproc_list.head; p; prev = p, p = p->next) - if (p->coproc->c_flags & COPROC_DEAD) - { - prev->next = p->next; /* remove from list */ - - /* Housekeeping in the border cases. */ - if (p == coproc_list.head) - coproc_list.head = coproc_list.head->next; - else if (p == coproc_list.tail) - coproc_list.tail = prev; - - coproc_list.ncoproc--; - if (coproc_list.ncoproc == 0) - coproc_list.head = coproc_list.tail = 0; - else if (coproc_list.ncoproc == 1) - coproc_list.tail = coproc_list.head; /* just to make sure */ - -#if defined (DEBUG) - itrace("cpl_reap: deleting %d", p->coproc->c_pid); -#endif - - coproc_dispose (p->coproc); - cpe_dispose (p); - } -} - -/* Clear out the list of saved statuses */ -static void -cpl_flush () -{ - struct cpelement *cpe, *p; - - for (cpe = coproc_list.head; cpe; ) - { - p = cpe; - cpe = cpe->next; - - coproc_dispose (p->coproc); - cpe_dispose (p); - } - - coproc_list.head = coproc_list.tail = 0; - coproc_list.ncoproc = 0; -} - -/* Search for PID in the list of coprocs; return the cpelement struct if - found. If not found, return NULL. */ -static struct cpelement * -cpl_search (pid) - pid_t pid; -{ - struct cpelement *cp; - - for (cp = coproc_list.head ; cp; cp = cp->next) - if (cp->coproc->c_pid == pid) - return cp; - return (struct cpelement *)NULL; -} - -/* Search for the coproc named NAME in the list of coprocs; return the - cpelement struct if found. If not found, return NULL. */ -static struct cpelement * -cpl_searchbyname (name) - char *name; -{ - struct cpelement *cp; - - for (cp = coproc_list.head ; cp; cp = cp->next) - if (STREQ (cp->coproc->c_name, name)) - return cp; - return (struct cpelement *)NULL; -} - -#if 0 -static void -cpl_prune () -{ - struct cpelement *cp; - - while (coproc_list.head && coproc_list.ncoproc > COPROC_MAX) - { - cp = coproc_list.head; - coproc_list.head = coproc_list.head->next; - coproc_dispose (cp->coproc); - cpe_dispose (cp); - coproc_list.ncoproc--; - } -} -#endif - -/* These currently use a single global "shell coproc" but are written in a - way to not preclude additional coprocs later (using the list management - package above). */ - -struct coproc * -getcoprocbypid (pid) - pid_t pid; -{ - return (pid == sh_coproc.c_pid ? &sh_coproc : 0); -} - -struct coproc * -getcoprocbyname (name) - const char *name; -{ - return ((sh_coproc.c_name && STREQ (sh_coproc.c_name, name)) ? &sh_coproc : 0); -} - -void -coproc_init (cp) - struct coproc *cp; -{ - cp->c_name = 0; - cp->c_pid = NO_PID; - cp->c_rfd = cp->c_wfd = -1; - cp->c_rsave = cp->c_wsave = -1; - cp->c_flags = cp->c_status = 0; -} - -struct coproc * -coproc_alloc (name, pid) - char *name; - pid_t pid; -{ - struct coproc *cp; - - cp = &sh_coproc; /* XXX */ - coproc_init (cp); - - cp->c_name = savestring (name); - cp->c_pid = pid; - - return (cp); -} - -void -coproc_dispose (cp) - struct coproc *cp; -{ - if (cp == 0) - return; - - coproc_unsetvars (cp); - FREE (cp->c_name); - coproc_close (cp); - coproc_init (cp); -} - -/* Placeholder for now. */ -void -coproc_flush () -{ - coproc_dispose (&sh_coproc); -} - -void -coproc_close (cp) - struct coproc *cp; -{ - if (cp->c_rfd >= 0) - { - close (cp->c_rfd); - cp->c_rfd = -1; - } - if (cp->c_wfd >= 0) - { - close (cp->c_wfd); - cp->c_wfd = -1; - } - cp->c_rsave = cp->c_wsave = -1; -} - -void -coproc_closeall () -{ - coproc_close (&sh_coproc); -} - -void -coproc_reap () -{ - struct coproc *cp; - - cp = &sh_coproc; - if (cp && (cp->c_flags & COPROC_DEAD)) - coproc_dispose (cp); -} - -void -coproc_rclose (cp, fd) - struct coproc *cp; - int fd; -{ - if (cp->c_rfd >= 0 && cp->c_rfd == fd) - { - close (cp->c_rfd); - cp->c_rfd = -1; - } -} - -void -coproc_wclose (cp, fd) - struct coproc *cp; - int fd; -{ - if (cp->c_wfd >= 0 && cp->c_wfd == fd) - { - close (cp->c_wfd); - cp->c_wfd = -1; - } -} - -void -coproc_checkfd (cp, fd) - struct coproc *cp; - int fd; -{ - int update; - - update = 0; - if (cp->c_rfd >= 0 && cp->c_rfd == fd) - update = cp->c_rfd = -1; - if (cp->c_wfd >= 0 && cp->c_wfd == fd) - update = cp->c_wfd = -1; - if (update) - coproc_setvars (cp); -} - -void -coproc_fdchk (fd) - int fd; -{ - coproc_checkfd (&sh_coproc, fd); -} - -void -coproc_fdclose (cp, fd) - struct coproc *cp; - int fd; -{ - coproc_rclose (cp, fd); - coproc_wclose (cp, fd); - coproc_setvars (cp); -} - -void -coproc_fdsave (cp) - struct coproc *cp; -{ - cp->c_rsave = cp->c_rfd; - cp->c_wsave = cp->c_wfd; -} - -void -coproc_fdrestore (cp) - struct coproc *cp; -{ - cp->c_rfd = cp->c_rsave; - cp->c_wfd = cp->c_wsave; -} - -void -coproc_pidchk (pid, status) - pid_t pid; -{ - struct coproc *cp; - - cp = getcoprocbypid (pid); -#if 0 - if (cp) - itrace("coproc_pidchk: pid %d has died", pid); -#endif - if (cp) - { - cp->c_status = status; - cp->c_flags |= COPROC_DEAD; - cp->c_flags &= ~COPROC_RUNNING; -#if 0 - coproc_dispose (cp); -#endif - } -} - -void -coproc_setvars (cp) - struct coproc *cp; -{ - SHELL_VAR *v; - char *namevar, *t; - int l; -#if defined (ARRAY_VARS) - arrayind_t ind; -#endif - - if (cp->c_name == 0) - return; - - l = strlen (cp->c_name); - namevar = xmalloc (l + 16); - -#if defined (ARRAY_VARS) - v = find_variable (cp->c_name); - if (v == 0) - v = make_new_array_variable (cp->c_name); - if (array_p (v) == 0) - v = convert_var_to_array (v); - - t = itos (cp->c_rfd); - ind = 0; - v = bind_array_variable (cp->c_name, ind, t, 0); - free (t); - - t = itos (cp->c_wfd); - ind = 1; - bind_array_variable (cp->c_name, ind, t, 0); - free (t); -#else - sprintf (namevar, "%s_READ", cp->c_name); - t = itos (cp->c_rfd); - bind_variable (namevar, t, 0); - free (t); - sprintf (namevar, "%s_WRITE", cp->c_name); - t = itos (cp->c_wfd); - bind_variable (namevar, t, 0); - free (t); -#endif - - sprintf (namevar, "%s_PID", cp->c_name); - t = itos (cp->c_pid); - bind_variable (namevar, t, 0); - free (t); - - free (namevar); -} - -void -coproc_unsetvars (cp) - struct coproc *cp; -{ - int l; - char *namevar; - - if (cp->c_name == 0) - return; - - l = strlen (cp->c_name); - namevar = xmalloc (l + 16); - - sprintf (namevar, "%s_PID", cp->c_name); - unbind_variable (namevar); - -#if defined (ARRAY_VARS) - unbind_variable (cp->c_name); -#else - sprintf (namevar, "%s_READ", cp->c_name); - unbind_variable (namevar); - sprintf (namevar, "%s_WRITE", cp->c_name); - unbind_variable (namevar); -#endif - - free (namevar); -} - -static int -execute_coproc (command, pipe_in, pipe_out, fds_to_close) - COMMAND *command; - int pipe_in, pipe_out; - struct fd_bitmap *fds_to_close; -{ - int rpipe[2], wpipe[2]; - pid_t coproc_pid; - Coproc *cp; - char *tcmd; - - /* XXX -- will require changes to handle multiple coprocs */ - if (sh_coproc.c_pid != NO_PID) - { -#if 0 - internal_error ("execute_coproc: coproc [%d:%s] already exists", sh_coproc.c_pid, sh_coproc.c_name); - return (last_command_exit_value = EXECUTION_FAILURE); -#else - internal_warning ("execute_coproc: coproc [%d:%s] still exists", sh_coproc.c_pid, sh_coproc.c_name); -#endif - } - coproc_init (&sh_coproc); - - command_string_index = 0; - tcmd = make_command_string (command); - - sh_openpipe ((int *)&rpipe); /* 0 = parent read, 1 = child write */ - sh_openpipe ((int *)&wpipe); /* 0 = child read, 1 = parent write */ - - coproc_pid = make_child (savestring (tcmd), 1); - if (coproc_pid == 0) - { - close (rpipe[0]); - close (wpipe[1]); - - exit (execute_in_subshell (command, 1, wpipe[0], rpipe[1], fds_to_close)); - } - - close (rpipe[1]); - close (wpipe[0]); - - cp = coproc_alloc (command->value.Coproc->name, coproc_pid); - cp->c_rfd = rpipe[0]; - cp->c_wfd = wpipe[1]; - - SET_CLOSE_ON_EXEC (cp->c_rfd); - SET_CLOSE_ON_EXEC (cp->c_wfd); - - coproc_setvars (cp); - -#if 0 - itrace ("execute_coproc: [%d] %s", coproc_pid, the_printed_command); -#endif - - close_pipes (pipe_in, pipe_out); -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - unlink_fifo_list (); -#endif - stop_pipeline (1, (COMMAND *)NULL); - DESCRIBE_PID (coproc_pid); - run_pending_traps (); - - return (EXECUTION_SUCCESS); -} -#endif - -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 (); - UNBLOCK_CHILD (oset); -#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 - - QUIT; - 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, was_error_trap, invert; - - 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); - QUIT; - - 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; - } - executing_list++; - 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); - executing_list--; - break; - - case '|': - was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; - invert = (command->flags & CMD_INVERT_RETURN) != 0; - ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; - - exec_result = execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close); - - 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 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) - { - last_command_exit_value = exec_result; - run_pending_traps (); - jump_to_top_level (ERREXIT); - } - - 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. */ - - executing_list++; - 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); - } - executing_list--; - 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_BADUSAGE; - 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 and we're not running - a debug trap. */ -#if 0 - if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) -#else - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) -#endif - { - 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, 0); - 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), 0); - 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); - if (signal_in_progress (DEBUG_TRAP) == 0) - { - 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); - -#if 0 - if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) -#else - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) -#endif - { - 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, 0); - 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 0 - if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) -#else - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) -#endif - { - 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 - - 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) - { - 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|FNMATCH_IGNCASE) != FNM_NOMATCH; - free (pattern); - - dispose_words (es); - - if (match) - { - do - { - if (clauses->action && ignore_return) - clauses->action->flags |= CMD_IGNORE_RETURN; - retval = execute_command (clauses->action); - } - while ((clauses->flags & CASEPAT_FALLTHROUGH) && (clauses = clauses->next)); - if ((clauses->flags & CASEPAT_TESTNEXT) == 0) - EXIT_CASE (); - else - break; - } - - 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; - char *exp; - - 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); - - if (signal_in_progress (DEBUG_TRAP) == 0) - { - 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) - { - exp = new->next ? string_list (new) : new->word->word; - expresult = evalexp (exp, &expok); - line_number = save_line_number; - if (exp != new->word->word) - free (exp); - dispose_words (new); - } - else - { - 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 * const 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) - { - rmatch = 0; - 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, - (rmatch && shell_compatibility_level > 31) ? 2 : (patmatch ? 1 : 0)); - 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 */ - { - int oe; - oe = extended_glob; - extended_glob = 1; - result = binary_test (cond->op->word, arg1, arg2, TEST_PATMATCH|TEST_ARITHEXP) - ? EXECUTION_SUCCESS - : EXECUTION_FAILURE; - extended_glob = oe; - } - 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); - - if (signal_in_progress (DEBUG_TRAP) == 0) - { - 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, 0); - 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) - REDIRECT *redirects; - int pipe_in, pipe_out, async; -{ - 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); - -#if defined (COPROCESS_SUPPORT) - coproc_closeall (); -#endif - - subshell_environment = 0; - if (async) - subshell_environment |= SUBSHELL_ASYNC; - if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) - subshell_environment |= SUBSHELL_PIPE; - - 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 (last_command_subst_pid != NO_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; - int assoc; - - if (words == 0) - return; - - b = 0; - assoc = 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; - else if (b && (b->flags & ASSIGNMENT_BUILTIN)) - words->word->flags |= W_ASSNBLTIN; - } - w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG); -#if defined (ARRAY_VARS) - if (assoc) - w->word->flags |= W_ASSIGNASSOC; -#endif - } -#if defined (ARRAY_VARS) - /* Note that we saw an associative array option to a builtin that takes - assignment statements. This is a bit of a kludge. */ - else if (w->word->word[0] == '-' && strchr (w->word->word, 'A')) - { - if (b == 0) - { - b = builtin_address_internal (words->word->word, 0); - if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) - return; - else if (b && (b->flags & ASSIGNMENT_BUILTIN)) - words->word->flags |= W_ASSNBLTIN; - } - if (words->word->flags & W_ASSNBLTIN) - assoc = 1; - } -#endif -} - -/* Return 1 if the file found by searching $PATH for PATHNAME, defaulting - to PATHNAME, is a directory. Used by the autocd code below. */ -static int -is_dirname (pathname) - char *pathname; -{ - char *temp; - temp = search_for_command (pathname); - return (temp ? file_isdir (temp) : file_isdir (pathname)); -} - -/* 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_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 0 - if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))) -#else - if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0) -#endif - { - FREE (the_printed_command_except_trap); - the_printed_command_except_trap = the_printed_command ? savestring (the_printed_command) : (char *)0; - } - - /* 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; - - last_command_subst_pid = NO_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) - { - /* Do this now, because execute_disk_command will do it anyway in the - vast majority of cases. */ - maybe_make_export_env (); - - /* Don't let a DEBUG trap overwrite the command string to be saved with - the process/job associated with this child. */ - if (make_child (savestring (the_printed_command_except_trap), async) == 0) - { - already_forked = 1; - simple_command->flags |= CMD_NO_FORK; - - subshell_environment = SUBSHELL_FORK; - if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) - subshell_environment |= SUBSHELL_PIPE; - if (async) - subshell_environment |= SUBSHELL_ASYNC; - - /* 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; -#if defined (COPROCESS_SUPPORT) - coproc_closeall (); -#endif - - 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); - /* Pass the ignore return flag down to command substitutions */ - if (simple_command->flags & CMD_IGNORE_RETURN) /* XXX */ - comsub_ignore_return++; - words = expand_words (simple_command->words); - if (simple_command->flags & CMD_IGNORE_RETURN) - comsub_ignore_return--; - 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); - 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 */ - -run_builtin: - /* 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 (builtin) - unwind_protect_int (executing_builtin); /* modified in execute_builtin */ - 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 (autocd && interactive && words->word && is_dirname (words->word->word)) - { - words = make_word_list (make_word ("cd"), words); - xtrace_print_word_list (words, 0); - goto run_builtin; - } - - if (command_line == 0) - command_line = savestring (the_printed_command_except_trap); - -#if defined (PROCESS_SUBSTITUTION) - if ((subshell_environment & SUBSHELL_COMSUB) && (simple_command->flags & CMD_NO_FORK) && fifos_pending() > 0) - simple_command->flags &= ~CMD_NO_FORK; -#endif - - 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; - -#if 0 - /* XXX -- added 12/11 */ - terminate_immediately++; -#endif - - 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. This is also a problem (as - below) for the command and source/. builtins. */ - if (subshell == 0 && (flags & CMD_IGNORE_RETURN) && - (builtin == eval_builtin || builtin == command_builtin || builtin == source_builtin)) - { - 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 `unset', `source' and `eval' builtins. */ - - isbltinenv = (builtin == source_builtin || builtin == eval_builtin || builtin == unset_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, (flags & CMD_COMMAND_BUILTIN) ? 0 : "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); - } - - executing_builtin++; - 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"); - } - -#if 0 - /* XXX -- added 12/11 */ - terminate_immediately--; -#endif - - 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, *nfv, *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); - } - - /* Shell functions inherit the RETURN trap if function tracing is on - globally or on individually for this function. */ -#if 0 - if (return_trap && ((trace_p (var) == 0) && function_trace_mode == 0)) -#else - if (return_trap && (signal_in_progress (DEBUG_TRAP) || ((trace_p (var) == 0) && function_trace_mode == 0))) -#endif - { - 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 defined (JOB_CONTROL) - if (subshell) - stop_pipeline (async, (COMMAND *)NULL); -#endif - - fc = tc; - - return_catch_flag++; - return_val = setjmp (return_catch); - - if (return_val) - { - result = return_catch_value; - /* Run the RETURN trap in the function's context. */ - save_current = currently_executing_command; - run_return_trap (); - currently_executing_command = save_current; - } - 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); - - save_current = currently_executing_command; - run_return_trap (); - currently_executing_command = save_current; -#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) - /* These two variables cannot be unset, and cannot be affected by the - function. */ - array_pop (bash_source_a); - array_pop (bash_lineno_a); - - /* FUNCNAME can be unset, and so can potentially be changed by the - function. */ - GET_ARRAY_FROM_VAR ("FUNCNAME", nfv, funcname_a); - if (nfv == funcname_v) - array_pop (funcname_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, funcvalue; -#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; - - if (async) - subshell_environment |= SUBSHELL_ASYNC; - if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) - subshell_environment |= SUBSHELL_PIPE; - - 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); - - /* Give the return builtin a place to jump to when executed in a subshell - or pipeline */ - funcvalue = 0; - if (return_catch_flag && builtin == return_builtin) - funcvalue = setjmp (return_catch); - - if (result == EXITPROG) - exit (last_command_exit_value); - else if (result) - exit (EXECUTION_FAILURE); - else if (funcvalue) - exit (return_catch_value); - else - { - r = execute_builtin (builtin, words, flags, 1); - fflush (stdout); - if (r == EX_USAGE) - r = EX_BADUSAGE; - exit (r); - } - } - else - { - r = execute_function (var, words, flags, fds_to_close, async, 1); - fflush (stdout); - exit (r); - } -} - -/* 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. */ - fflush (stdout); - fpurge (stdout); - 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(). */ - -/* Name of a shell function to call when a command name is not found. */ -#ifndef NOTFOUND_HOOK -# define NOTFOUND_HOOK "command_not_found_handle" -#endif - -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; - SHELL_VAR *hookf; - WORD_LIST *wl; - - 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) - { - hookf = find_function (NOTFOUND_HOOK); - if (hookf == 0) - { - internal_error (_("%s: command not found"), pathname); - exit (EX_NOTFOUND); /* Posix.2 says the exit status is 127 */ - } - - wl = make_word_list (make_word (NOTFOUND_HOOK), words); - exit (execute_shell_function (hookf, wl)); - } - - /* 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 (); - init_job_stats (); -#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); - /* XXX -- are there other things we should be resetting here? */ - parse_and_execute_level = 0; /* nothing left to restore it */ - - /* We're no longer inside a shell function. */ - variable_context = return_catch_flag = 0; - - executing_list = 0; /* XXX */ - - /* 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; -{ - 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() */ - CHECK_TERMSIG; - 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 (file_isdir (command)) - internal_error (_("%s: is a directory"), command); - else if (executable_file (command) == 0) - { - errno = i; - file_error (command); - } - /* errors not involving the path argument to execve. */ - else if (i == E2BIG || i == ENOMEM) - { - 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; - int ilen; - - interp = getinterp (sample, sample_len, (int *)NULL); - ilen = strlen (interp); - errno = i; - if (interp[ilen - 1] == '\r') - { - interp = xrealloc (interp, ilen + 2); - interp[ilen - 1] = '^'; - interp[ilen] = 'M'; - interp[ilen + 1] = '\0'; - } - 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_BADUSAGE; - 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/execute_cmd.h~ b/execute_cmd.h~ deleted file mode 100644 index 29a026ac9..000000000 --- a/execute_cmd.h~ +++ /dev/null @@ -1,67 +0,0 @@ -/* execute_cmd.h - functions from execute_cmd.c. */ - -/* Copyright (C) 1993-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#if !defined (_EXECUTE_CMD_H_) -#define _EXECUTE_CMD_H_ - -#include "stdc.h" - -extern struct fd_bitmap *new_fd_bitmap __P((int)); -extern void dispose_fd_bitmap __P((struct fd_bitmap *)); -extern void close_fd_bitmap __P((struct fd_bitmap *)); -extern int executing_line_number __P((void)); -extern int execute_command __P((COMMAND *)); -extern int execute_command_internal __P((COMMAND *, int, int, int, struct fd_bitmap *)); -extern int shell_execve __P((char *, char **, char **)); -extern void setup_async_signals __P((void)); -extern void dispose_exec_redirects __P ((void)); - -extern int execute_shell_function __P((SHELL_VAR *, WORD_LIST *)); - -extern struct coproc *getcoprocbypid __P((pid_t)); -extern struct coproc *getcoprocbyname __P((const char *)); - -extern void coproc_init __P((struct coproc *)); -extern struct coproc *coproc_alloc __P((char *, pid_t)); -extern void coproc_dispose __P((struct coproc *)); -extern void coproc_flush __P((void)); -extern void coproc_close __P((struct coproc *)); -extern void coproc_closeall __P((void)); - -extern void coproc_rclose __P((struct coproc *, int)); -extern void coproc_wclose __P((struct coproc *, int)); -extern void coproc_fdclose __P((struct coproc *, int)); - -extern void coproc_checkfd __P((struct coproc *, int)); -extern void coproc_fdchk __P((int)); - -extern void coproc_pidchk __P((pid_t, int)); - -extern void coproc_fdsave __P((struct coproc *)); -extern void coproc_fdrestore __P((struct coproc *)); - -extern void coproc_setvars __P((struct coproc *)); -extern void coproc_unsetvars __P((struct coproc *)); - -#if defined (PROCESS_SUBSTITUTION) -extern void close_all_files __P((void)); -#endif - -#endif /* _EXECUTE_CMD_H_ */ diff --git a/expr.c~ b/expr.c~ deleted file mode 100644 index e5f5034e4..000000000 --- a/expr.c~ +++ /dev/null @@ -1,1355 +0,0 @@ -/* expr.c -- arithmetic expression evaluation. */ - -/* Copyright (C) 1990-2006 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - Bash is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with Bash; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -/* - 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 int _is_arithop __P((int)); -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((const 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 const char * const 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 */ - - noeval = 0; /* XXX */ -} - -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; - noeval = 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++; - } -#if 0 - val2 = explor (); -#else - val2 = expcond (); -#endif - 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 = exppower (); /* exponentiation is right-associative */ - 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 (); - top_level_cleanup (); - 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); -} - -static int -_is_multiop (c) - int c; -{ - switch (c) - { - case EQEQ: - case NEQ: - case LEQ: - case GEQ: - case LAND: - case LOR: - case LSH: - case RSH: - case OP_ASSIGN: - case COND: - case POWER: - case PREINC: - case PREDEC: - case POSTINC: - case POSTDEC: - return 1; - default: - return 0; - } -} - -static int -_is_arithop (c) - int c; -{ - switch (c) - { - case EQ: - case GT: - case LT: - case PLUS: - case MINUS: - case MUL: - case DIV: - case MOD: - case NOT: - case LPAR: - case RPAR: - case BAND: - case BOR: - case BXOR: - case BNOT: - return 1; /* operator tokens */ - case QUES: - case COL: - case COMMA: - return 1; /* questionable */ - default: - return 0; /* anything else is invalid */ - } -} - -/* 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, *xp; - 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++; - - if (c == '\0') - { - lasttok = curtok; - curtok = 0; - tp = cp; - return; - } - lasttp = tp = cp - 1; - - 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 == '-' || c == '+') && c1 == c && curtok == STR) - c = (c == '-') ? POSTDEC : POSTINC; - else if ((c == '-' || c == '+') && c1 == c) - { - /* Quickly scan forward to see if this is followed by optional - whitespace and an identifier. */ - xp = cp; - while (xp && *xp && cr_whitespace (*xp)) - xp++; - if (legal_variable_starter ((unsigned char)*xp)) - c = (c == '-') ? PREDEC : PREINC; - else - cp--; /* not preinc or predec, so unget the character */ - } - else if (c1 == EQ && member (c, "*/%+-&^|")) - { - assigntok = c; /* a OP= b */ - c = OP_ASSIGN; - } - else if (_is_arithop (c) == 0) - { - cp--; - /* use curtok, since it hasn't been copied to lasttok yet */ - if (curtok == 0 || _is_arithop (curtok) || _is_multiop (curtok)) - evalerror (_("syntax error: operand expected")); - else - evalerror (_("syntax error: invalid arithmetic operator")); - } - else - cp--; /* `unget' the character */ - - /* Should check here to make sure that the current character is one - of the recognized operators and flag an error if not. Could create - a character map the first time through and check it on subsequent - calls. */ - lasttok = curtok; - curtok = c; - } - tp = cp; -} - -static void -evalerror (msg) - const 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 69f831f98..000000000 --- a/externs.h~ +++ /dev/null @@ -1,448 +0,0 @@ -/* externs.h -- extern function declarations which do not appear in their - own header file. */ - -/* Copyright (C) 1993-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -/* 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. */ -#define FUNC_MULTILINE 0x01 -#define FUNC_EXTERNAL 0x02 - -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 char *xparse_dolparen __P((char *, char *, int *, int)); -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 void set_default_lang __P((void)); -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/casemod.c */ -extern char *sh_modcase __P((const char *, char *, int)); - -/* Defines for flags argument to sh_modcase. These need to agree with what's - in lib/sh/casemode.c */ -#define CASE_LOWER 0x01 -#define CASE_UPPER 0x02 -#define CASE_CAPITALIZE 0x04 -#define CASE_UNCAP 0x08 -#define CASE_TOGGLE 0x10 -#define CASE_TOGGLEALL 0x20 -#define CASE_UPFIRST 0x40 -#define CASE_LOWFIRST 0x80 - -/* 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/fdprintf.c */ -extern void fdprintf __P((int, const char *, ...)) __attribute__((__format__ (printf, 2, 3))); - -/* 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/fpurge.c */ -#if !HAVE_DECL_FPURGE - -#if HAVE_FPURGE -# define fpurge _bash_fpurge -#endif -extern int fpurge __P((FILE *stream)); - -#endif /* HAVE_DECL_FPURGE */ - - -/* 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/input_avail.c */ -extern int input_avail __P((int)); - -/* 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 -#define MP_IGNDOT 0x08 - -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/shaccess.c */ -extern int sh_eaccess __P((char *, int)); - -/* 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_mkdoublequoted __P((const char *, int, int)); -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 *)); -extern char *dirspell __P((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 (HAVE_STRERROR) && !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/strnlen.c */ -#if !defined (HAVE_STRNLEN) -extern size_t strnlen __P((const char *, size_t)); -#endif - -/* declarations for functions defined in lib/sh/strpbrk.c */ -#if !defined (HAVE_STRPBRK) -extern char *strpbrk __P((const char *, const char *)); -#endif - -/* 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/uconvert.c */ -extern int uconvert __P((char *, long *, long *)); - -/* declarations for functions defined in lib/sh/ufuncs.c */ -extern unsigned int falarm __P((unsigned int, unsigned int)); -extern unsigned int fsleep __P((unsigned int, unsigned int)); - -/* declarations for functions defined in lib/sh/winsize.c */ -extern void get_new_window_size __P((int, int *, int *)); - -/* 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/zcatfd.c */ -extern int zcatfd __P((int, int, char *)); - -/* declarations for functions defined in lib/sh/zgetline.c */ -extern ssize_t zgetline __P((int, char **, size_t *, int)); - -/* declarations for functions defined in lib/sh/zmapfd.c */ -extern int zmapfd __P((int, char **, char *)); - -/* declarations for functions defined in lib/sh/zread.c */ -extern ssize_t zread __P((int, char *, size_t)); -extern ssize_t zreadretry __P((int, char *, size_t)); -extern ssize_t zreadintr __P((int, char *, size_t)); -extern ssize_t zreadc __P((int, char *)); -extern ssize_t zreadcintr __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/findcmd.c~ b/findcmd.c~ deleted file mode 100644 index 4c5a12db5..000000000 --- a/findcmd.c~ +++ /dev/null @@ -1,602 +0,0 @@ -/* findcmd.c -- Functions to search for commands by name. */ - -/* Copyright (C) 1997 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ - -#include "config.h" - -#include -#include "chartypes.h" -#include "bashtypes.h" -#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "filecntl.h" -#include "posixstat.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" - -#include "memalloc.h" -#include "shell.h" -#include "flags.h" -#include "hashlib.h" -#include "pathexp.h" -#include "hashcmd.h" -#include "findcmd.h" /* matching prototypes and declarations */ - -extern int posixly_correct; - -/* Static functions defined and used in this file. */ -static char *_find_user_command_internal __P((const char *, int)); -static char *find_user_command_internal __P((const char *, int)); -static char *find_user_command_in_path __P((const char *, char *, int)); -static char *find_in_path_element __P((const char *, char *, int, int, struct stat *)); -static char *find_absolute_program __P((const char *, int)); - -static char *get_next_path_element __P((char *, int *)); - -/* The file name which we would try to execute, except that it isn't - possible to execute it. This is the first file that matches the - name that we are looking for while we are searching $PATH for a - suitable one to execute. If we cannot find a suitable executable - file, then we use this one. */ -static char *file_to_lose_on; - -/* Non-zero if we should stat every command found in the hash table to - make sure it still exists. */ -int check_hashed_filenames; - -/* DOT_FOUND_IN_SEARCH becomes non-zero when find_user_command () - encounters a `.' as the directory pathname while scanning the - list of possible pathnames; i.e., if `.' comes before the directory - containing the file of interest. */ -int dot_found_in_search = 0; - -/* Return some flags based on information about this file. - The EXISTS bit is non-zero if the file is found. - The EXECABLE bit is non-zero the file is executble. - Zero is returned if the file is not found. */ -int -file_status (name) - const char *name; -{ - struct stat finfo; - int r; - - /* Determine whether this file exists or not. */ - if (stat (name, &finfo) < 0) - return (0); - - /* If the file is a directory, then it is not "executable" in the - sense of the shell. */ - if (S_ISDIR (finfo.st_mode)) - return (FS_EXISTS|FS_DIRECTORY); - - r = FS_EXISTS; - -#if defined (AFS) - /* We have to use access(2) to determine access because AFS does not - support Unix file system semantics. This may produce wrong - answers for non-AFS files when ruid != euid. I hate AFS. */ - if (access (name, X_OK) == 0) - r |= FS_EXECABLE; - if (access (name, R_OK) == 0) - r |= FS_READABLE; - - return r; -#else /* !AFS */ - - /* Find out if the file is actually executable. By definition, the - only other criteria is that the file has an execute bit set that - we can use. The same with whether or not a file is readable. */ - - /* Root only requires execute permission for any of owner, group or - others to be able to exec a file, and can read any file. */ - if (current_user.euid == (uid_t)0) - { - r |= FS_READABLE; - if (finfo.st_mode & S_IXUGO) - r |= FS_EXECABLE; - return r; - } - - /* If we are the owner of the file, the owner bits apply. */ - if (current_user.euid == finfo.st_uid) - { - if (finfo.st_mode & S_IXUSR) - r |= FS_EXECABLE; - if (finfo.st_mode & S_IRUSR) - r |= FS_READABLE; - } - - /* If we are in the owning group, the group permissions apply. */ - else if (group_member (finfo.st_gid)) - { - if (finfo.st_mode & S_IXGRP) - r |= FS_EXECABLE; - if (finfo.st_mode & S_IRGRP) - r |= FS_READABLE; - } - - /* Else we check whether `others' have permission to execute the file */ - else - { - if (finfo.st_mode & S_IXOTH) - r |= FS_EXECABLE; - if (finfo.st_mode & S_IROTH) - r |= FS_READABLE; - } - - return r; -#endif /* !AFS */ -} - -/* Return non-zero if FILE exists and is executable. - Note that this function is the definition of what an - executable file is; do not change this unless YOU know - what an executable file is. */ -int -executable_file (file) - const char *file; -{ - int s; - - s = file_status (file); - return ((s & FS_EXECABLE) && ((s & FS_DIRECTORY) == 0)); -} - -int -is_directory (file) - const char *file; -{ - return (file_status (file) & FS_DIRECTORY); -} - -int -executable_or_directory (file) - const char *file; -{ - int s; - - s = file_status (file); - return ((s & FS_EXECABLE) || (s & FS_DIRECTORY)); -} - -/* Locate the executable file referenced by NAME, searching along - the contents of the shell PATH variable. Return a new string - which is the full pathname to the file, or NULL if the file - couldn't be found. If a file is found that isn't executable, - and that is the only match, then return that. */ -char * -find_user_command (name) - const char *name; -{ - return (find_user_command_internal (name, FS_EXEC_PREFERRED|FS_NODIRS)); -} - -/* Locate the file referenced by NAME, searching along the contents - of the shell PATH variable. Return a new string which is the full - pathname to the file, or NULL if the file couldn't be found. This - returns the first readable file found; designed to be used to look - for shell scripts or files to source. */ -char * -find_path_file (name) - const char *name; -{ - return (find_user_command_internal (name, FS_READABLE)); -} - -static char * -_find_user_command_internal (name, flags) - const char *name; - int flags; -{ - char *path_list, *cmd; - SHELL_VAR *var; - - /* Search for the value of PATH in both the temporary environments and - in the regular list of variables. */ - if (var = find_variable_internal ("PATH", 1)) /* XXX could be array? */ - path_list = value_cell (var); - else - path_list = (char *)NULL; - - if (path_list == 0 || *path_list == '\0') - return (savestring (name)); - - cmd = find_user_command_in_path (name, path_list, flags); - - return (cmd); -} - -static char * -find_user_command_internal (name, flags) - const char *name; - int flags; -{ -#ifdef __WIN32__ - char *res, *dotexe; - - dotexe = (char *)xmalloc (strlen (name) + 5); - strcpy (dotexe, name); - strcat (dotexe, ".exe"); - res = _find_user_command_internal (dotexe, flags); - free (dotexe); - if (res == 0) - res = _find_user_command_internal (name, flags); - return res; -#else - return (_find_user_command_internal (name, flags)); -#endif -} - -/* Return the next element from PATH_LIST, a colon separated list of - paths. PATH_INDEX_POINTER is the address of an index into PATH_LIST; - the index is modified by this function. - Return the next element of PATH_LIST or NULL if there are no more. */ -static char * -get_next_path_element (path_list, path_index_pointer) - char *path_list; - int *path_index_pointer; -{ - char *path; - - path = extract_colon_unit (path_list, path_index_pointer); - - if (path == 0) - return (path); - - if (*path == '\0') - { - free (path); - path = savestring ("."); - } - - return (path); -} - -/* Look for PATHNAME in $PATH. Returns either the hashed command - corresponding to PATHNAME or the first instance of PATHNAME found - in $PATH. Returns a newly-allocated string. */ -char * -search_for_command (pathname) - const char *pathname; -{ - char *hashed_file, *command; - int temp_path, st; - SHELL_VAR *path; - - hashed_file = command = (char *)NULL; - - /* If PATH is in the temporary environment for this command, don't use the - hash table to search for the full pathname. */ - path = find_variable_internal ("PATH", 1); - temp_path = path && tempvar_p (path); - if (temp_path == 0 && path) - path = (SHELL_VAR *)NULL; - - /* Don't waste time trying to find hashed data for a pathname - that is already completely specified or if we're using a command- - specific value for PATH. */ - if (path == 0 && absolute_program (pathname) == 0) - hashed_file = phash_search (pathname); - - /* If a command found in the hash table no longer exists, we need to - look for it in $PATH. Thank you Posix.2. This forces us to stat - every command found in the hash table. */ - - if (hashed_file && (posixly_correct || check_hashed_filenames)) - { - st = file_status (hashed_file); -#if 0 - if ((st ^ (FS_EXISTS | FS_EXECABLE)) != 0) -#else - if ((st & (FS_EXISTS|FS_EXECABLE)) != (FS_EXISTS|FS_EXECABLE)) -#endif - { - phash_remove (pathname); - free (hashed_file); - hashed_file = (char *)NULL; - } - } - - if (hashed_file) - command = hashed_file; - else if (absolute_program (pathname)) - /* A command containing a slash is not looked up in PATH or saved in - the hash table. */ - command = savestring (pathname); - else - { - /* If $PATH is in the temporary environment, we've already retrieved - it, so don't bother trying again. */ - if (temp_path) - { - command = find_user_command_in_path (pathname, value_cell (path), - FS_EXEC_PREFERRED|FS_NODIRS); - } - else - command = find_user_command (pathname); - if (command && hashing_enabled && temp_path == 0) - phash_insert ((char *)pathname, command, dot_found_in_search, 1); /* XXX fix const later */ - } - return (command); -} - -char * -user_command_matches (name, flags, state) - const char *name; - int flags, state; -{ - register int i; - int path_index, name_len; - char *path_list, *path_element, *match; - struct stat dotinfo; - static char **match_list = NULL; - static int match_list_size = 0; - static int match_index = 0; - - if (state == 0) - { - /* Create the list of matches. */ - if (match_list == 0) - { - match_list_size = 5; - match_list = strvec_create (match_list_size); - } - - /* Clear out the old match list. */ - for (i = 0; i < match_list_size; i++) - match_list[i] = 0; - - /* We haven't found any files yet. */ - match_index = 0; - - if (absolute_program (name)) - { - match_list[0] = find_absolute_program (name, flags); - match_list[1] = (char *)NULL; - path_list = (char *)NULL; - } - else - { - name_len = strlen (name); - file_to_lose_on = (char *)NULL; - dot_found_in_search = 0; - stat (".", &dotinfo); - path_list = get_string_value ("PATH"); - path_index = 0; - } - - while (path_list && path_list[path_index]) - { - path_element = get_next_path_element (path_list, &path_index); - - if (path_element == 0) - break; - - match = find_in_path_element (name, path_element, flags, name_len, &dotinfo); - - free (path_element); - - if (match == 0) - continue; - - if (match_index + 1 == match_list_size) - { - match_list_size += 10; - match_list = strvec_resize (match_list, (match_list_size + 1)); - } - - match_list[match_index++] = match; - match_list[match_index] = (char *)NULL; - FREE (file_to_lose_on); - file_to_lose_on = (char *)NULL; - } - - /* We haven't returned any strings yet. */ - match_index = 0; - } - - match = match_list[match_index]; - - if (match) - match_index++; - - return (match); -} - -static char * -find_absolute_program (name, flags) - const char *name; - int flags; -{ - int st; - - st = file_status (name); - - /* If the file doesn't exist, quit now. */ - if ((st & FS_EXISTS) == 0) - return ((char *)NULL); - - /* If we only care about whether the file exists or not, return - this filename. Otherwise, maybe we care about whether this - file is executable. If it is, and that is what we want, return it. */ - if ((flags & FS_EXISTS) || ((flags & FS_EXEC_ONLY) && (st & FS_EXECABLE))) - return (savestring (name)); - - return (NULL); -} - -static char * -find_in_path_element (name, path, flags, name_len, dotinfop) - const char *name; - char *path; - int flags, name_len; - struct stat *dotinfop; -{ - int status; - char *full_path, *xpath; - - xpath = (*path == '~') ? bash_tilde_expand (path, 0) : path; - - /* Remember the location of "." in the path, in all its forms - (as long as they begin with a `.', e.g. `./.') */ - if (dot_found_in_search == 0 && *xpath == '.') - dot_found_in_search = same_file (".", xpath, dotinfop, (struct stat *)NULL); - - full_path = sh_makepath (xpath, name, 0); - - status = file_status (full_path); - - if (xpath != path) - free (xpath); - - if ((status & FS_EXISTS) == 0) - { - free (full_path); - return ((char *)NULL); - } - - /* The file exists. If the caller simply wants the first file, here it is. */ - if (flags & FS_EXISTS) - return (full_path); - - /* If we have a readable file, and the caller wants a readable file, this - is it. */ - if ((flags & FS_READABLE) && (status & FS_READABLE)) - return (full_path); - - /* If the file is executable, then it satisfies the cases of - EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */ - if ((status & FS_EXECABLE) && (flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) && - (((flags & FS_NODIRS) == 0) || ((status & FS_DIRECTORY) == 0))) - { - FREE (file_to_lose_on); - file_to_lose_on = (char *)NULL; - return (full_path); - } - - /* The file is not executable, but it does exist. If we prefer - an executable, then remember this one if it is the first one - we have found. */ - if ((flags & FS_EXEC_PREFERRED) && file_to_lose_on == 0) - file_to_lose_on = savestring (full_path); - - /* If we want only executable files, or we don't want directories and - this file is a directory, or we want a readable file and this file - isn't readable, fail. */ - if ((flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) || - ((flags & FS_NODIRS) && (status & FS_DIRECTORY)) || - ((flags & FS_READABLE) && (status & FS_READABLE) == 0)) - { - free (full_path); - return ((char *)NULL); - } - else - return (full_path); -} - -/* This does the dirty work for find_user_command_internal () and - user_command_matches (). - NAME is the name of the file to search for. - PATH_LIST is a colon separated list of directories to search. - FLAGS contains bit fields which control the files which are eligible. - Some values are: - FS_EXEC_ONLY: The file must be an executable to be found. - FS_EXEC_PREFERRED: If we can't find an executable, then the - the first file matching NAME will do. - FS_EXISTS: The first file found will do. - FS_NODIRS: Don't find any directories. -*/ -static char * -find_user_command_in_path (name, path_list, flags) - const char *name; - char *path_list; - int flags; -{ - char *full_path, *path; - int path_index, name_len; - struct stat dotinfo; - - /* We haven't started looking, so we certainly haven't seen - a `.' as the directory path yet. */ - dot_found_in_search = 0; - - if (absolute_program (name)) - { - full_path = find_absolute_program (name, flags); - return (full_path); - } - - if (path_list == 0 || *path_list == '\0') - return (savestring (name)); /* XXX */ - - file_to_lose_on = (char *)NULL; - name_len = strlen (name); - stat (".", &dotinfo); - path_index = 0; - - while (path_list[path_index]) - { - /* Allow the user to interrupt out of a lengthy path search. */ - QUIT; - - path = get_next_path_element (path_list, &path_index); - if (path == 0) - break; - - /* Side effects: sets dot_found_in_search, possibly sets - file_to_lose_on. */ - full_path = find_in_path_element (name, path, flags, name_len, &dotinfo); - free (path); - - /* This should really be in find_in_path_element, but there isn't the - right combination of flags. */ - if (full_path && is_directory (full_path)) - { - free (full_path); - continue; - } - - if (full_path) - { - FREE (file_to_lose_on); - return (full_path); - } - } - - /* We didn't find exactly what the user was looking for. Return - the contents of FILE_TO_LOSE_ON which is NULL when the search - required an executable, or non-NULL if a file was found and the - search would accept a non-executable as a last resort. If the - caller specified FS_NODIRS, and file_to_lose_on is a directory, - return NULL. */ - if (file_to_lose_on && (flags & FS_NODIRS) && is_directory (file_to_lose_on)) - { - free (file_to_lose_on); - file_to_lose_on = (char *)NULL; - } - - return (file_to_lose_on); -} diff --git a/flags.c~ b/flags.c~ deleted file mode 100644 index 0c0868bcf..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_initialized; - -/* -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/flags.h~ b/flags.h~ deleted file mode 100644 index f16e60483..000000000 --- a/flags.h~ +++ /dev/null @@ -1,79 +0,0 @@ -/* flags.h -- a list of all the flags that the shell knows about. You add - a flag to this program by adding the name here, and in flags.c. */ - -/* Copyright (C) 1993 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#if !defined (_FLAGS_H_) -#define _FLAGS_H_ - -#include "stdc.h" - -/* Welcome to the world of Un*x, where everything is slightly backwards. */ -#define FLAG_ON '-' -#define FLAG_OFF '+' - -#define FLAG_ERROR -1 -#define FLAG_UNKNOWN (int *)0 - -/* The thing that we build the array of flags out of. */ -struct flags_alist { - char name; - int *value; -}; - -extern struct flags_alist shell_flags[]; -extern char optflags[]; - -extern int - mark_modified_vars, exit_immediately_on_error, disallow_filename_globbing, - place_keywords_in_env, read_but_dont_execute, - just_one_command, unbound_vars_is_error, echo_input_at_read, - echo_command_at_execute, no_invisible_vars, noclobber, - hashing_enabled, forced_interactive, privileged_mode, - asynchronous_notification, interactive_comments, no_symbolic_links, - function_trace_mode, error_trace_mode, pipefail_opt; - -#if 0 -extern int lexical_scoping; -#endif - -#if defined (BRACE_EXPANSION) -extern int brace_expansion; -#endif - -#if defined (BANG_HISTORY) -extern int history_expansion; -#endif /* BANG_HISTORY */ - -#if defined (RESTRICTED_SHELL) -extern int restricted; -extern int restricted_shell; -#endif /* RESTRICTED_SHELL */ - -extern int *find_flag __P((int)); -extern int change_flag __P((int, int)); -extern char *which_set_flags __P((void)); -extern void reset_shell_flags __P((void)); - -extern void initialize_flags __P((void)); - -/* A macro for efficiency. */ -#define change_flag_char(flag, on_or_off) change_flag (flag, on_or_off) - -#endif /* _FLAGS_H_ */ diff --git a/general.c~ b/general.c~ deleted file mode 100644 index b37d54438..000000000 --- a/general.c~ +++ /dev/null @@ -1,1125 +0,0 @@ -/* general.c -- Stuff that is used by all files. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#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 "test.h" - -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int expand_aliases; -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. */ -const char * const 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; - source_searches_cwd = 0; - } - - /* 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) - const 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) || shellxquote (*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 == 0 || 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); - if (string[newi] == '+' && string[newi+1] == '=') - return (newi + 1); - return ((string[newi] == '=') ? newi : 0); - } -#endif /* ARRAY_VARS */ - - /* Check for `+=' */ - if (c == '+' && string[indx+1] == '=') - return (indx + 1); - - /* 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 (c == '\0') - return (1); - } - - return (0); -} - -/* **************************************************************** */ -/* */ -/* Functions to manipulate pipes */ -/* */ -/* **************************************************************** */ - -int -sh_openpipe (pv) - int *pv; -{ - int r; - - if ((r = pipe (pv)) < 0) - return r; - - pv[0] = move_to_high_fd (pv[0], 1, 64); - pv[1] = move_to_high_fd (pv[1], 1, 64); - - return 0; -} - -int -sh_closepipe (pv) - int *pv; -{ - if (pv[0] >= 0) - close (pv[0]); - - if (pv[1] >= 0) - close (pv[1]); - - pv[0] = pv[1] = -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) && sh_eaccess (fn, W_OK) == 0); -} - -/* 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); -} - -/* **************************************************************** */ -/* */ -/* 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 the `basename' of the pathname in STRING (the stuff after the - last '/'). If STRING is `/', just return it. */ -char * -base_pathname (string) - char *string; -{ - char *p; - -#if 0 - if (absolute_pathname (string) == 0) - return (string); -#endif - - if (string[0] == '/' && string[1] == 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); -} - -/* Trim NAME. If NAME begins with `~/', skip over tilde prefix. Trim to - keep any tilde prefix and PROMPT_DIRTRIM trailing directory components - and replace the intervening characters with `...' */ -char * -trim_pathname (name, maxlen) - char *name; - int maxlen; -{ - int nlen, ndirs; - intmax_t nskip; - char *nbeg, *nend, *ntail, *v; - - if (name == 0 || (nlen = strlen (name)) == 0) - return name; - nend = name + nlen; - - v = get_string_value ("PROMPT_DIRTRIM"); - if (v == 0 || *v == 0) - return name; - if (legal_number (v, &nskip) == 0 || nskip <= 0) - return name; - - /* Skip over tilde prefix */ - nbeg = name; - if (name[0] == '~') - for (nbeg = name; *nbeg; nbeg++) - if (*nbeg == '/') - { - nbeg++; - break; - } - if (*nbeg == 0) - return name; - - for (ndirs = 0, ntail = nbeg; *ntail; ntail++) - if (*ntail == '/') - ndirs++; - if (ndirs <= nskip) - return name; - - for (ntail = (*nend == '/') ? nend : nend - 1; ntail > nbeg; ntail--) - { - if (*ntail == '/') - nskip--; - if (nskip == 0) - break; - } - if (ntail == nbeg) - return name; - - /* Now we want to return name[0..nbeg]+"..."+ntail, modifying name in place */ - nlen = ntail - nbeg; - if (nlen <= 3) - return name; - - *nbeg++ = '.'; - *nbeg++ = '.'; - *nbeg++ = '.'; - - nlen = nend - ntail; - memcpy (nbeg, ntail, nlen); - nbeg[nlen] = '\0'; - - 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_prefixes2; -static char **bash_tilde_suffixes; -static char **bash_tilde_suffixes2; - -/* 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; - - bash_tilde_prefixes2 = strvec_create (2); - bash_tilde_prefixes2[0] = ":~"; - bash_tilde_prefixes2[1] = (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; - - bash_tilde_suffixes2 = strvec_create (2); - bash_tilde_suffixes2[0] = ":"; - bash_tilde_suffixes2[1] = (char *)NULL; - } -} - -/* 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; -} - -/* Find the end of the tilde-prefix starting at S, and return the tilde - prefix in newly-allocated memory. Return the length of the string in - *LENP. FLAGS tells whether or not we're in an assignment context -- - if so, `:' delimits the end of the tilde prefix as well. */ -char * -bash_tilde_find_word (s, flags, lenp) - const char *s; - int flags, *lenp; -{ - const char *r; - char *ret; - int l; - - for (r = s; *r && *r != '/'; r++) - { - /* Short-circuit immediately if we see a quote character. Even though - POSIX says that `the first unquoted slash' (or `:') terminates the - tilde-prefix, in practice, any quoted portion of the tilde prefix - will cause it to not be expanded. */ - if (*r == '\\' || *r == '\'' || *r == '"') - { - ret = savestring (s); - if (lenp) - *lenp = 0; - return ret; - } - else if (flags && *r == ':') - break; - } - l = r - s; - ret = xmalloc (l + 1); - strncpy (ret, s, l); - ret[l] = '\0'; - if (lenp) - *lenp = l; - return ret; -} - -/* 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). If - ASSIGN_P is 2, we are expanding the rhs of an assignment statement, - so `=~' is not valid. */ -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 == 0 ? (char **)0 - : (assign_p == 2 ? bash_tilde_prefixes2 : bash_tilde_prefixes); - if (assign_p == 2) - tilde_additional_suffixes = bash_tilde_suffixes2; - - 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 5fc46cc69..000000000 --- a/general.h~ +++ /dev/null @@ -1,320 +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" -#include "chartypes.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_wassign_func_t __P((WORD_DESC *)); - -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 -#define FS_READABLE 0x40 - -/* 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] == ':') || ISDIRSEP((x)[0])) -# define RELPATH(x) (ABSPATH(x) == 0) -#endif /* __CYGWIN__ */ - -#define ROOTEDPATH(x) (ABSPATH(x)) - -#define DIRSEP '/' -#if !defined (__CYGWIN__) -# define ISDIRSEP(c) ((c) == '/') -#else -# define ISDIRSEP(c) ((c) == '/' || (c) == '\\') -#endif /* __CYGWIN__ */ -#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((const char *, intmax_t *)); -extern int legal_identifier __P((char *)); -extern int check_identifier __P((WORD_DESC *, int)); -extern int legal_alias_name __P((char *, 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 int absolute_pathname __P((const char *)); -extern int absolute_program __P((const char *)); - -extern char *make_absolute __P((char *, 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_find_word __P((const char *, int, int *)); -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/hashcmd.h~ b/hashcmd.h~ deleted file mode 100644 index 3d47c1c95..000000000 --- a/hashcmd.h~ +++ /dev/null @@ -1,43 +0,0 @@ -/* hashcmd.h - Common defines for hashing filenames. */ - -/* Copyright (C) 1993 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "stdc.h" -#include "hashlib.h" - -#define FILENAME_HASH_BUCKETS 64 /* must be power of two */ - -extern HASH_TABLE *hashed_filenames; - -typedef struct { - char *path; /* The full pathname of the file. */ - int flags; -} PATH_DATA; - -#define HASH_RELPATH 0x01 /* this filename is a relative pathname. */ -#define HASH_CHKDOT 0x02 /* check `.' since it was earlier in $PATH */ - -#define pathdata(x) ((PATH_DATA *)(x)->data) - -extern void phash_create __P((void)); -extern void phash_flush __P((void)); - -extern void phash_insert __P((char *, char *, int, int)); -extern int phash_remove __P((const char *)); -extern char *phash_search __P((const char *)); 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~ b/include/shmbutil.h~ deleted file mode 100644 index f5f8b9886..000000000 --- a/include/shmbutil.h~ +++ /dev/null @@ -1,445 +0,0 @@ -/* shmbutil.h -- utility functions for multibyte characters. */ - -/* Copyright (C) 2002-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 (_SH_MBUTIL_H_) -#define _SH_MBUTIL_H_ - -#include "stdc.h" - -/* Include config.h for HANDLE_MULTIBYTE */ -#include - -#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 size_t mbstrlen __P((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 - -#define MBSLEN(s) (((s) && (s)[0]) ? ((s)[1] ? mbstrlen (s) : 1) : 0) -#define MB_STRLEN(s) ((MB_CUR_MAX > 1) ? MBSLEN (s) : STRLEN (s)) - -#define MBLEN(s, n) ((MB_CUR_MAX > 1) ? mblen ((s), (n)) : 1) -#define MBRLEN(s, n, p) ((MB_CUR_MAX > 1) ? mbrlen ((s), (n), (p)) : 1) - -#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 - -#define MB_STRLEN(s) (STRLEN(s)) - -#define MBLEN(s, n) 1 -#define MBRLEN(s, n, p) 1 - -#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/shtty.h~ b/include/shtty.h~ deleted file mode 100644 index d3a0b0c98..000000000 --- a/include/shtty.h~ +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright (C) 1999 Free Software Foundation, Inc. */ - -/* This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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. */ - -/* - * shtty.h -- include the correct system-dependent files to manipulate the - * tty - */ - -#ifndef __SH_TTY_H_ -#define __SH_TTY_H_ - -#include "stdc.h" - -#if defined (_POSIX_VERSION) && defined (HAVE_TERMIOS_H) && defined (HAVE_TCGETATTR) && !defined (TERMIOS_MISSING) -# define TERMIOS_TTY_DRIVER -#else -# if defined (HAVE_TERMIO_H) -# define TERMIO_TTY_DRIVER -# else -# define NEW_TTY_DRIVER -# endif -#endif - -/* - * The _POSIX_SOURCE define is to avoid multiple symbol definitions - * between sys/ioctl.h and termios.h. Ditto for the test against SunOS4 - * and the undefining of several symbols. - */ - -#ifdef TERMIOS_TTY_DRIVER -# if (defined (SunOS4) || defined (SunOS5)) && !defined (_POSIX_SOURCE) -# define _POSIX_SOURCE -# endif -# if defined (SunOS4) -# undef ECHO -# undef NOFLSH -# undef TOSTOP -# endif /* SunOS4 */ -# include -# define TTYSTRUCT struct termios -#else -# ifdef TERMIO_TTY_DRIVER -# include -# define TTYSTRUCT struct termio -# else /* NEW_TTY_DRIVER */ -# include -# define TTYSTRUCT struct sgttyb -# endif -#endif - -/* Functions imported from lib/sh/shtty.c */ - -/* Get and set terminal attributes for the file descriptor passed as - an argument. */ -extern int ttgetattr __P((int, TTYSTRUCT *)); -extern int ttsetattr __P((int, TTYSTRUCT *)); - -/* Save and restore the terminal's attributes from static storage. */ -extern void ttsave __P((void)); -extern void ttrestore __P((void)); - -/* Return the attributes corresponding to the file descriptor (0 or 1) - passed as an argument. */ -extern TTYSTRUCT *ttattr __P((int)); - -/* These functions only operate on the passed TTYSTRUCT; they don't - actually change anything with the kernel's current tty settings. */ -extern int tt_setonechar __P((TTYSTRUCT *)); -extern int tt_setnoecho __P((TTYSTRUCT *)); -extern int tt_seteightbit __P((TTYSTRUCT *)); -extern int tt_setnocanon __P((TTYSTRUCT *)); -extern int tt_setcbreak __P((TTYSTRUCT *)); - -/* These functions are all generally mutually exclusive. If you call - more than one (bracketed with calls to ttsave and ttrestore, of - course), the right thing will happen, but more system calls will be - executed than absolutely necessary. You can do all of this yourself - with the other functions; these are only conveniences. */ - -/* These functions work with a given file descriptor and set terminal - attributes */ -extern int ttfd_onechar __P((int, TTYSTRUCT *)); -extern int ttfd_noecho __P((int, TTYSTRUCT *)); -extern int ttfd_eightbit __P((int, TTYSTRUCT *)); -extern int ttfd_nocanon __P((int, TTYSTRUCT *)); - -extern int ttcbreak __P((int, TTYSTRUCT *)); - -/* These functions work with fd 0 and the TTYSTRUCT saved with ttsave () */ -extern int ttonechar __P((void)); -extern int ttnoecho __P((void)); -extern int tteightbit __P((void)); -extern int ttnocanon __P((void)); - -extern int ttcbreak __P((void)); - -#endif diff --git a/include/typemax.h~ b/include/typemax.h~ deleted file mode 100644 index 42ae517dc..000000000 --- a/include/typemax.h~ +++ /dev/null @@ -1,80 +0,0 @@ -/* typemax.h -- encapsulate max values for long, long long, etc. */ - -/* Copyright (C) 2001 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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. */ - -/* - * NOTE: This should be included after config.h, limits.h, stdint.h, and - * inttypes.h - */ - -#ifndef _SH_TYPEMAX_H -#define _SH_TYPEMAX_H - -#ifndef CHAR_BIT -# define CHAR_BIT 8 -#endif - -/* Nonzero if the integer type T is signed. */ -#ifndef TYPE_SIGNED -# define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) -#endif - -#ifndef TYPE_MINIMUM -# define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ - ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) \ - : (t) 0)) -#endif - -#ifndef TYPE_MAXIMUM -# define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) -#endif - -#ifdef HAVE_LONG_LONG -# ifndef LLONG_MAX -# define LLONG_MAX TYPE_MAXIMUM(long long int) -# define LLONG_MIN TYPE_MINIMUM(long long int) -# endif -# ifndef ULLONG_MAX -# define ULLONG_MAX TYPE_MAXIMUM(unsigned long long int) -# endif -#endif - -#ifndef ULONG_MAX -# define ULONG_MAX ((unsigned long) ~(unsigned long) 0) -#endif - -#ifndef LONG_MAX -# define LONG_MAX ((long int) (ULONG_MAX >> 1)) -# define LONG_MIN ((long int) (-LONG_MAX - 1L)) -#endif - -#ifndef INT_MAX /* ouch */ -# define INT_MAX TYPE_MAXIMUM(int) -# define INT_MIN TYPE_MINIMUM(int) -# define UINT_MAX ((unsigned int) ~(unsigned int)0) -#endif - -/* workaround for gcc bug in versions < 2.7 */ -#if defined (HAVE_LONG_LONG) && __GNUC__ == 2 && __GNUC_MINOR__ < 7 -static const unsigned long long int maxquad = ULLONG_MAX; -# undef ULLONG_MAX -# define ULLONG_MAX maxquad -#endif - -#endif /* _SH_TYPEMAX_H */ diff --git a/jobs-patch~ b/jobs-patch~ deleted file mode 100644 index 5f2ac46d3..000000000 --- a/jobs-patch~ +++ /dev/null @@ -1,99 +0,0 @@ -*** ../bash-20070510/jobs.c Thu Mar 8 16:05:50 2007 ---- jobs.c Fri May 18 11:40:14 2007 -*************** -*** 784,792 **** - { - old = js.j_firstj++; - while (js.j_firstj != old) - { - if (js.j_firstj >= js.j_jobslots) - js.j_firstj = 0; -! if (jobs[js.j_firstj]) - break; - js.j_firstj++; ---- 784,794 ---- - { - old = js.j_firstj++; -+ if (old >= js.j_jobslots) -+ old = js.j_jobslots - 1; - while (js.j_firstj != old) - { - if (js.j_firstj >= js.j_jobslots) - js.j_firstj = 0; -! if (jobs[js.j_firstj] || js.j_firstj == old) /* needed if old == 0 */ - break; - js.j_firstj++; -*************** -*** 798,806 **** - { - old = js.j_lastj--; - while (js.j_lastj != old) - { - if (js.j_lastj < 0) - js.j_lastj = js.j_jobslots - 1; -! if (jobs[js.j_lastj]) - break; - js.j_lastj--; ---- 800,810 ---- - { - old = js.j_lastj--; -+ if (old < 0) -+ old = 0; - while (js.j_lastj != old) - { - if (js.j_lastj < 0) - js.j_lastj = js.j_jobslots - 1; -! if (jobs[js.j_lastj] || js.j_lastj == old) /* needed if old == js.j_jobslots */ - break; - js.j_lastj--; -*************** -*** 901,904 **** ---- 905,909 ---- - nlist = (js.j_jobslots == nsize) ? jobs : (JOB **) xmalloc (nsize * sizeof (JOB *)); - -+ js.c_reaped = js.j_ndead = 0; - for (i = j = 0; i < js.j_jobslots; i++) - if (jobs[i]) -*************** -*** 909,912 **** ---- 914,922 ---- - nprev = j; - nlist[j++] = jobs[i]; -+ if (jobs[i]->state == JDEAD) -+ { -+ js.j_ndead++; -+ js.c_reaped += processes_in_job (i); -+ } - } - -*************** -*** 914,918 **** - itrace ("realloc_jobs_list: resize jobs list from %d to %d", js.j_jobslots, nsize); - itrace ("realloc_jobs_list: j_lastj changed from %d to %d", js.j_lastj, (j > 0) ? j - 1 : 0); -! itrace ("realloc_jobs_list: j_njobs changed from %d to %d", js.j_njobs, (j > 0) ? j - 1 : 0); - #endif - ---- 924,929 ---- - itrace ("realloc_jobs_list: resize jobs list from %d to %d", js.j_jobslots, nsize); - itrace ("realloc_jobs_list: j_lastj changed from %d to %d", js.j_lastj, (j > 0) ? j - 1 : 0); -! itrace ("realloc_jobs_list: j_njobs changed from %d to %d", js.j_njobs, j); -! itrace ("realloc_jobs_list: js.j_ndead %d js.c_reaped %d", js.j_ndead, js.c_reaped); - #endif - -*************** -*** 964,968 **** - realloc_jobs_list (); - -! return (js.j_lastj ? js.j_lastj + 1 : 0); - } - ---- 975,983 ---- - realloc_jobs_list (); - -! #ifdef DEBUG -! itrace("compact_jobs_list: returning %d", (js.j_lastj || jobs[js.j_lastj]) ? js.j_lastj + 1 : 0); -! #endif -! -! return ((js.j_lastj || jobs[js.j_lastj]) ? js.j_lastj + 1 : 0); - } - diff --git a/jobs.c.diff b/jobs.c.diff deleted file mode 100644 index f1ea4e0cd..000000000 --- a/jobs.c.diff +++ /dev/null @@ -1,521 +0,0 @@ -*** ../bash-3.1/jobs.c Fri Nov 11 23:13:27 2005 ---- jobs.c Wed Feb 1 13:55:38 2006 -*************** -*** 4,8 **** - control. */ - -! /* Copyright (C) 1989-2005 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. ---- 4,8 ---- - control. */ - -! /* Copyright (C) 1989-2006 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. -*************** -*** 78,82 **** - - #define DEFAULT_CHILD_MAX 32 -! #define MAX_JOBS_IN_ARRAY 4096 /* testing */ - - /* Take care of system dependencies that must be handled when waiting for ---- 78,90 ---- - - #define DEFAULT_CHILD_MAX 32 -! #if !defined (DEBUG) -! #define MAX_JOBS_IN_ARRAY 4096 /* production */ -! #else -! #define MAX_JOBS_IN_ARRAY 128 /* testing */ -! #endif -! -! /* Flag values for second argument to delete_job */ -! #define DEL_WARNSTOPPED 1 /* warn about deleting stopped jobs */ -! #define DEL_NOBGPID 2 /* don't add pgrp leader to bgpids */ - - /* Take care of system dependencies that must be handled when waiting for -*************** -*** 308,311 **** ---- 316,323 ---- - static char retcode_name_buffer[64]; - -+ /* flags to detect pid wraparound */ -+ static pid_t first_pid = NO_PID; -+ static int pid_wrap = -1; -+ - #if !defined (_POSIX_VERSION) - -*************** -*** 329,337 **** - #endif /* !_POSIX_VERSION */ - -! /* Initialize the global job stats structure. */ - void - init_job_stats () - { - js = zerojs; - } - ---- 341,351 ---- - #endif /* !_POSIX_VERSION */ - -! /* Initialize the global job stats structure and other bookkeeping variables */ - void - init_job_stats () - { - js = zerojs; -+ first_pid = NO_PID; -+ pid_wrap = -1; - } - -*************** -*** 620,625 **** - * the parent gives it away. - * - */ -! if (job_control && newjob->pgrp) - give_terminal_to (newjob->pgrp, 0); - } ---- 634,642 ---- - * the parent gives it away. - * -+ * Don't give the terminal away if this shell is an asynchronous -+ * subshell. -+ * - */ -! if (job_control && newjob->pgrp && (subshell_environment&SUBSHELL_ASYNC) == 0) - give_terminal_to (newjob->pgrp, 0); - } -*************** -*** 806,810 **** - QUEUE_SIGCHLD(os); - -! /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { ---- 823,827 ---- - QUEUE_SIGCHLD(os); - -! /* XXX could use js.j_firstj and js.j_lastj here */ - for (i = 0; i < js.j_jobslots; i++) - { -*************** -*** 812,815 **** ---- 829,834 ---- - if (i < js.j_firstj && jobs[i]) - itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("cleanup_dead_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - -*************** -*** 838,841 **** ---- 857,884 ---- - } - -+ static void -+ delete_old_job (pid) -+ pid_t pid; -+ { -+ PROCESS *p; -+ int job; -+ -+ job = find_job (pid, 0, &p); -+ if (job != NO_JOB) -+ { -+ #ifdef DEBUG -+ itrace ("delete_old_job: found pid %d in job %d with state %d", pid, job, jobs[job]->state); -+ #endif -+ if (JOBSTATE (job) == JDEAD) -+ delete_job (job, DEL_NOBGPID); -+ else -+ { -+ internal_warning (_("forked pid %d appears in running job %d"), pid, job); -+ if (p) -+ p->pid = 0; -+ } -+ } -+ } -+ - /* Reallocate and compress the jobs list. This returns with a jobs array - whose size is a multiple of JOB_SLOTS and can hold the current number of -*************** -*** 845,851 **** - { - sigset_t set, oset; -! int nsize, i, j; - JOB **nlist; - - nsize = ((js.j_njobs + JOB_SLOTS - 1) / JOB_SLOTS); - nsize *= JOB_SLOTS; ---- 888,895 ---- - { - sigset_t set, oset; -! int nsize, i, j, ncur, nprev; - JOB **nlist; - -+ ncur = nprev = NO_JOB; - nsize = ((js.j_njobs + JOB_SLOTS - 1) / JOB_SLOTS); - nsize *= JOB_SLOTS; -*************** -*** 855,869 **** - - BLOCK_CHILD (set, oset); -! nlist = (JOB **) xmalloc (nsize * sizeof (JOB *)); - for (i = j = 0; i < js.j_jobslots; i++) - if (jobs[i]) -! nlist[j++] = jobs[i]; - - js.j_firstj = 0; -! js.j_lastj = (j > 0) ? j - 1: 0; - js.j_jobslots = nsize; - -! free (jobs); -! jobs = nlist; - - UNBLOCK_CHILD (oset); ---- 899,947 ---- - - BLOCK_CHILD (set, oset); -! nlist = (js.j_jobslots == nsize) ? jobs : (JOB **) xmalloc (nsize * sizeof (JOB *)); -! - for (i = j = 0; i < js.j_jobslots; i++) - if (jobs[i]) -! { -! if (i == js.j_current) -! ncur = j; -! if (i == js.j_previous) -! nprev = j; -! nlist[j++] = jobs[i]; -! } -! -! #if defined (DEBUG) -! itrace ("realloc_jobs_list: resize jobs list from %d to %d", js.j_jobslots, nsize); -! itrace ("realloc_jobs_list: j_lastj changed from %d to %d", js.j_lastj, (j > 0) ? j - 1 : 0); -! itrace ("realloc_jobs_list: j_njobs changed from %d to %d", js.j_njobs, (j > 0) ? j - 1 : 0); -! #endif - - js.j_firstj = 0; -! js.j_lastj = (j > 0) ? j - 1 : 0; -! js.j_njobs = j; - js.j_jobslots = nsize; - -! /* Zero out remaining slots in new jobs list */ -! for ( ; j < nsize; j++) -! nlist[j] = (JOB *)NULL; -! -! if (jobs != nlist) -! { -! free (jobs); -! jobs = nlist; -! } -! -! if (ncur != NO_JOB) -! js.j_current = ncur; -! if (nprev != NO_JOB) -! js.j_previous = nprev; -! -! /* Need to reset these */ -! if (js.j_current == NO_JOB || js.j_previous == NO_JOB || js.j_current > js.j_lastj || js.j_previous > js.j_lastj) -! reset_current (); -! -! #ifdef DEBUG -! itrace ("realloc_jobs_list: reset js.j_current (%d) and js.j_previous (%d)", js.j_current, js.j_previous); -! #endif - - UNBLOCK_CHILD (oset); -*************** -*** 874,878 **** - the foreground process (subshell_environment != 0). Returns the first - available slot in the compacted list. If that value is js.j_jobslots, then -! the list needs to be reallocated. The jobs array is in new memory if - this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */ - static int ---- 952,956 ---- - the foreground process (subshell_environment != 0). Returns the first - available slot in the compacted list. If that value is js.j_jobslots, then -! the list needs to be reallocated. The jobs array may be in new memory if - this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */ - static int -*************** -*** 892,897 **** - with SIGCHLD blocked. */ - void -! delete_job (job_index, warn_stopped) -! int job_index, warn_stopped; - { - register JOB *temp; ---- 970,975 ---- - with SIGCHLD blocked. */ - void -! delete_job (job_index, dflags) -! int job_index, dflags; - { - register JOB *temp; -*************** -*** 903,918 **** - 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 == js.j_current || job_index == js.j_previous) - reset_current (); - -! proc = find_last_proc (job_index, 0); -! /* Could do this just for J_ASYNC jobs, but we save all. */ -! bgp_add (proc->pid, process_exit_status (proc->status)); - - jobs[job_index] = (JOB *)NULL; -- - if (temp == js.j_lastmade) - js.j_lastmade = 0; ---- 981,1001 ---- - return; - -! if ((dflags & DEL_WARNSTOPPED) && subshell_environment == 0 && STOPPED (job_index)) - internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp); - temp = jobs[job_index]; -+ if (temp == 0) -+ return; - if (job_index == js.j_current || job_index == js.j_previous) - reset_current (); - -! if ((dflags & DEL_NOBGPID) == 0) -! { -! proc = find_last_proc (job_index, 0); -! /* Could do this just for J_ASYNC jobs, but we save all. */ -! if (proc) -! bgp_add (proc->pid, process_exit_status (proc->status)); -! } - - jobs[job_index] = (JOB *)NULL; - if (temp == js.j_lastmade) - js.j_lastmade = 0; -*************** -*** 1092,1095 **** ---- 1175,1180 ---- - if (i < js.j_firstj && jobs[i]) - itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("map_over_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - if (jobs[i]) -*************** -*** 1224,1228 **** - PROCESS *p; - -! /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { ---- 1309,1313 ---- - PROCESS *p; - -! /* XXX could use js.j_firstj here, and should check js.j_lastj */ - for (i = 0; i < js.j_jobslots; i++) - { -*************** -*** 1230,1233 **** ---- 1315,1320 ---- - if (i < js.j_firstj && jobs[i]) - itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("find_job: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - if (jobs[i]) -*************** -*** 1656,1660 **** - 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); - ---- 1743,1747 ---- - shell's process group (we could be in the middle of a - pipeline, for example). */ -! if (async_p == 0 && pipeline_pgrp != shell_pgrp && ((subshell_environment&SUBSHELL_ASYNC) == 0)) - give_terminal_to (pipeline_pgrp, 0); - -*************** -*** 1698,1701 **** ---- 1785,1795 ---- - as the proper pgrp if this is the first child. */ - -+ if (first_pid == NO_PID) -+ first_pid = pid; -+ else if (pid_wrap == -1 && pid < first_pid) -+ pid_wrap = 0; -+ else if (pid_wrap == 0 && pid >= first_pid) -+ pid_wrap = 1; -+ - if (job_control) - { -*************** -*** 1731,1734 **** ---- 1825,1831 ---- - #endif - -+ if (pid_wrap > 0) -+ delete_old_job (pid); -+ - #if !defined (RECYCLES_PIDS) - /* Only check for saved status if we've saved more than CHILD_MAX -*************** -*** 1915,1919 **** - - p = jobs[job]->pipe; -! while (p->next != jobs[job]->pipe) - p = p->next; - ---- 2012,2016 ---- - - p = jobs[job]->pipe; -! while (p && p->next != jobs[job]->pipe) - p = p->next; - -*************** -*** 1999,2003 **** - - /* find first running job; if none running in foreground, break */ -! /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { ---- 2096,2100 ---- - - /* find first running job; if none running in foreground, break */ -! /* XXX could use js.j_firstj and js.j_lastj here */ - for (i = 0; i < js.j_jobslots; i++) - { -*************** -*** 2005,2008 **** ---- 2102,2107 ---- - if (i < js.j_firstj && jobs[i]) - itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("wait_for_background_pids: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0) -*************** -*** 2199,2203 **** - wait_sigint_received = 0; - if (job_control == 0) -! old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); - - termination_state = last_command_exit_value; ---- 2298,2306 ---- - wait_sigint_received = 0; - if (job_control == 0) -! { -! old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); -! if (old_sigint_handler == SIG_IGN) -! set_signal_handler (SIGINT, old_sigint_handler); -! } - - termination_state = last_command_exit_value; -*************** -*** 2266,2269 **** ---- 2369,2373 ---- - child->running = PS_DONE; - child->status = 0; /* XXX -- can't find true status */ -+ js.c_living = 0; /* no living child processes */ - if (job != NO_JOB) - { -*************** -*** 2317,2321 **** - itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp); - #endif -- - give_terminal_to (shell_pgrp, 0); - } ---- 2421,2424 ---- -*************** -*** 2866,2869 **** ---- 2969,2973 ---- - if (sigchld || block == 0) - waitpid_flags |= WNOHANG; -+ CHECK_TERMSIG; - pid = WAITPID (-1, &status, waitpid_flags); - -*************** -*** 2892,2895 **** ---- 2996,3000 ---- - /* If waitpid returns 0, there are running children. If it returns -1, - the only other error POSIX says it can return is EINTR. */ -+ CHECK_TERMSIG; - if (pid <= 0) - continue; /* jumps right to the test */ -*************** -*** 2898,2902 **** - run the trap if a process is just being continued. */ - if (WIFCONTINUED(status) == 0) -! children_exited++; - - /* Locate our PROCESS for this pid. */ ---- 3003,3010 ---- - run the trap if a process is just being continued. */ - if (WIFCONTINUED(status) == 0) -! { -! children_exited++; -! js.c_living--; -! } - - /* Locate our PROCESS for this pid. */ -*************** -*** 3123,3127 **** - restore_sigint_handler (); - if (temp_handler == SIG_DFL) -! termination_unwind_protect (SIGINT); - else if (temp_handler != SIG_IGN) - (*temp_handler) (SIGINT); ---- 3231,3235 ---- - restore_sigint_handler (); - if (temp_handler == SIG_DFL) -! termsig_handler (SIGINT); - else if (temp_handler != SIG_IGN) - (*temp_handler) (SIGINT); -*************** -*** 3638,3644 **** - if (i < js.j_firstj && jobs[i]) - itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - #endif - if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) -! delete_job (i, 1); - } - if (running_only == 0) ---- 3746,3754 ---- - if (i < js.j_firstj && jobs[i]) - itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("delete_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) -! delete_job (i, DEL_WARNSTOPPED); - } - if (running_only == 0) -*************** -*** 3692,3695 **** ---- 3802,3807 ---- - if (i < js.j_firstj && jobs[i]) - itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("count_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - if (jobs[i] && DEADJOB(i) == 0) -*************** -*** 3765,3768 **** ---- 3877,3882 ---- - if (i < js.j_firstj && jobs[i]) - itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - if (jobs[i] && DEADJOB (i)) -*************** -*** 3816,3819 **** ---- 3930,3935 ---- - if (i < js.j_firstj && jobs[i]) - itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); -+ if (i > js.j_lastj && jobs[i]) -+ itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); - #endif - /* If marking this job as notified would drop us down below diff --git a/jobs.c~ b/jobs.c~ deleted file mode 100644 index c85ce8b1b..000000000 --- a/jobs.c~ +++ /dev/null @@ -1,4200 +0,0 @@ -/* jobs.c - functions that make children, remember them, and handle their termination. */ - -/* This file works with both POSIX and BSD systems. It implements job - control. */ - -/* Copyright (C) 1989-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#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 */ - -#include "bashansi.h" -#include "bashintl.h" -#include "shell.h" -#include "jobs.h" -#include "execute_cmd.h" -#include "flags.h" - -#include "builtins/builtext.h" -#include "builtins/common.h" - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#define DEFAULT_CHILD_MAX 32 -#if !defined (DEBUG) -#define MAX_JOBS_IN_ARRAY 4096 /* production */ -#else -#define MAX_JOBS_IN_ARRAY 128 /* testing */ -#endif - -/* Flag values for second argument to delete_job */ -#define DEL_WARNSTOPPED 1 /* warn about deleting stopped jobs */ -#define DEL_NOBGPID 2 /* don't add pgrp leader to bgpids */ - -/* Take care of system dependencies that must be handled when waiting for - children. The arguments to the WAITPID macro match those to the Posix.1 - waitpid() function. */ - -#if defined (ultrix) && defined (mips) && defined (_POSIX_VERSION) -# define WAITPID(pid, statusp, options) \ - wait3 ((union wait *)statusp, options, (struct rusage *)0) -#else -# if defined (_POSIX_VERSION) || defined (HAVE_WAITPID) -# define WAITPID(pid, statusp, options) \ - waitpid ((pid_t)pid, statusp, options) -# else -# if defined (HAVE_WAIT3) -# define WAITPID(pid, statusp, options) \ - wait3 (statusp, options, (struct rusage *)0) -# else -# define WAITPID(pid, statusp, options) \ - wait3 (statusp, options, (int *)0) -# endif /* HAVE_WAIT3 */ -# endif /* !_POSIX_VERSION && !HAVE_WAITPID*/ -#endif /* !(Ultrix && mips && _POSIX_VERSION) */ - -/* getpgrp () varies between systems. Even systems that claim to be - Posix.1 compatible lie sometimes (Ultrix, SunOS4, apollo). */ -#if defined (GETPGRP_VOID) -# define getpgid(p) getpgrp () -#else -# define getpgid(p) getpgrp (p) -#endif /* !GETPGRP_VOID */ - -/* If the system needs it, REINSTALL_SIGCHLD_HANDLER will reinstall the - handler for SIGCHLD. */ -#if defined (MUST_REINSTALL_SIGHANDLERS) -# define REINSTALL_SIGCHLD_HANDLER signal (SIGCHLD, sigchld_handler) -#else -# define REINSTALL_SIGCHLD_HANDLER -#endif /* !MUST_REINSTALL_SIGHANDLERS */ - -/* Some systems let waitpid(2) tell callers about stopped children. */ -#if !defined (WCONTINUED) || defined (WCONTINUED_BROKEN) -# undef WCONTINUED -# define WCONTINUED 0 -#endif -#if !defined (WIFCONTINUED) -# define WIFCONTINUED(s) (0) -#endif - -/* The number of additional slots to allocate when we run out. */ -#define JOB_SLOTS 8 - -typedef int sh_job_map_func_t __P((JOB *, int, int, int)); - -/* Variables used here but defined in other files. */ -extern int subshell_environment, line_number; -extern int posixly_correct, shell_level; -extern int last_command_exit_value, last_command_exit_signal; -extern int loop_level, breaking; -extern int executing_list; -extern int sourcelevel; -extern int running_trap; -extern sh_builtin_func_t *this_shell_builtin; -extern char *shell_name, *this_command_name; -extern sigset_t top_level_mask; -extern procenv_t wait_intr_buf; -extern int wait_signal_received; -extern WORD_LIST *subst_assign_varlist; - -static struct jobstats zerojs = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB, 0, 0 }; -struct jobstats js = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB, 0, 0 }; - -struct bgpids bgpids = { 0, 0, 0 }; - -/* The array of known jobs. */ -JOB **jobs = (JOB **)NULL; - -#if 0 -/* The number of slots currently allocated to JOBS. */ -int job_slots = 0; -#endif - -/* The controlling tty for this shell. */ -int shell_tty = -1; - -/* The shell's process group. */ -pid_t shell_pgrp = NO_PID; - -/* The terminal's process group. */ -pid_t terminal_pgrp = NO_PID; - -/* The process group of the shell's parent. */ -pid_t original_pgrp = NO_PID; - -/* The process group of the pipeline currently being made. */ -pid_t pipeline_pgrp = (pid_t)0; - -#if defined (PGRP_PIPE) -/* Pipes which each shell uses to communicate with the process group leader - until all of the processes in a pipeline have been started. Then the - process leader is allowed to continue. */ -int pgrp_pipe[2] = { -1, -1 }; -#endif - -#if 0 -/* The job which is current; i.e. the one that `%+' stands for. */ -int current_job = NO_JOB; - -/* The previous job; i.e. the one that `%-' stands for. */ -int previous_job = NO_JOB; -#endif - -/* Last child made by the shell. */ -pid_t last_made_pid = NO_PID; - -/* Pid of the last asynchronous child. */ -pid_t last_asynchronous_pid = NO_PID; - -/* The pipeline currently being built. */ -PROCESS *the_pipeline = (PROCESS *)NULL; - -/* If this is non-zero, do job control. */ -int job_control = 1; - -/* Call this when you start making children. */ -int already_making_children = 0; - -/* If this is non-zero, $LINES and $COLUMNS are reset after every process - exits from get_tty_state(). */ -int check_window_size; - -/* Functions local to this file. */ - -static sighandler wait_sigint_handler __P((int)); -static sighandler sigchld_handler __P((int)); -static sighandler sigcont_sighandler __P((int)); -static sighandler sigstop_sighandler __P((int)); - -static int waitchld __P((pid_t, int)); - -static PROCESS *find_pipeline __P((pid_t, int, int *)); -static PROCESS *find_process __P((pid_t, int, int *)); - -static char *current_working_directory __P((void)); -static char *job_working_directory __P((void)); -static char *j_strsignal __P((int)); -static char *printable_job_status __P((int, PROCESS *, int)); - -static PROCESS *find_last_proc __P((int, int)); -static pid_t find_last_pid __P((int, int)); - -static int set_new_line_discipline __P((int)); -static int map_over_jobs __P((sh_job_map_func_t *, int, int)); -static int job_last_stopped __P((int)); -static int job_last_running __P((int)); -static int most_recent_job_in_state __P((int, JOB_STATE)); -static int find_job __P((pid_t, int, PROCESS **)); -static int print_job __P((JOB *, int, int, int)); -static int process_exit_status __P((WAIT)); -static int process_exit_signal __P((WAIT)); -static int job_exit_status __P((int)); -static int job_exit_signal __P((int)); -static int set_job_status_and_cleanup __P((int)); - -static WAIT job_signal_status __P((int)); -static WAIT raw_job_exit_status __P((int)); - -static void notify_of_job_status __P((void)); -static void reset_job_indices __P((void)); -static void cleanup_dead_jobs __P((void)); -static int processes_in_job __P((int)); -static void realloc_jobs_list __P((void)); -static int compact_jobs_list __P((int)); -static int discard_pipeline __P((PROCESS *)); -static void add_process __P((char *, pid_t)); -static void print_pipeline __P((PROCESS *, int, int, FILE *)); -static void pretty_print_job __P((int, int, FILE *)); -static void set_current_job __P((int)); -static void reset_current __P((void)); -static void set_job_running __P((int)); -static void setjstatus __P((int)); -static int maybe_give_terminal_to __P((pid_t, pid_t, 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 *)); -#endif - -static struct pidstat *bgp_alloc __P((pid_t, int)); -static struct pidstat *bgp_add __P((pid_t, int)); -static int bgp_delete __P((pid_t)); -static void bgp_clear __P((void)); -static int bgp_search __P((pid_t)); -static void bgp_prune __P((void)); - -#if defined (ARRAY_VARS) -static int *pstatuses; /* list of pipeline statuses */ -static int statsize; -#endif - -/* Used to synchronize between wait_for and other functions and the SIGCHLD - signal handler. */ -static int sigchld; -static int queue_sigchld; - -#define QUEUE_SIGCHLD(os) (os) = sigchld, queue_sigchld++ - -#define UNQUEUE_SIGCHLD(os) \ - do { \ - queue_sigchld--; \ - if (queue_sigchld == 0 && os != sigchld) \ - waitchld (-1, 0); \ - } while (0) - -static SigHandler *old_tstp, *old_ttou, *old_ttin; -static SigHandler *old_cont = (SigHandler *)SIG_DFL; - -/* A place to temporarily save the current pipeline. */ -static PROCESS *saved_pipeline; -static int saved_already_making_children; - -/* Set this to non-zero whenever you don't want the jobs list to change at - all: no jobs deleted and no status change notifications. This is used, - for example, when executing SIGCHLD traps, which may run arbitrary - commands. */ -static int jobs_list_frozen; - -static char retcode_name_buffer[64]; - -/* flags to detect pid wraparound */ -static pid_t first_pid = NO_PID; -static int pid_wrap = -1; - -#if !defined (_POSIX_VERSION) - -/* These are definitions to map POSIX 1003.1 functions onto existing BSD - library functions and system calls. */ -#define setpgid(pid, pgrp) setpgrp (pid, pgrp) -#define tcsetpgrp(fd, pgrp) ioctl ((fd), TIOCSPGRP, &(pgrp)) - -pid_t -tcgetpgrp (fd) - int fd; -{ - pid_t pgrp; - - /* ioctl will handle setting errno correctly. */ - if (ioctl (fd, TIOCGPGRP, &pgrp) < 0) - return (-1); - return (pgrp); -} - -#endif /* !_POSIX_VERSION */ - -/* Initialize the global job stats structure and other bookkeeping variables */ -void -init_job_stats () -{ - js = zerojs; - first_pid = NO_PID; - pid_wrap = -1; -} - -/* Return the working directory for the current process. Unlike - job_working_directory, this does not call malloc (), nor do any - of the functions it calls. This is so that it can safely be called - from a signal handler. */ -static char * -current_working_directory () -{ - char *dir; - static char d[PATH_MAX]; - - dir = get_string_value ("PWD"); - - if (dir == 0 && the_current_working_directory && no_symbolic_links) - dir = the_current_working_directory; - - if (dir == 0) - { - dir = getcwd (d, sizeof(d)); - if (dir) - dir = d; - } - - return (dir == 0) ? "" : 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 () -{ - PROCESS *disposer; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - disposer = the_pipeline; - the_pipeline = (PROCESS *)NULL; - UNBLOCK_CHILD (oset); - - if (disposer) - discard_pipeline (disposer); -} - -void -save_pipeline (clear) - int clear; -{ - saved_pipeline = the_pipeline; - if (clear) - the_pipeline = (PROCESS *)NULL; - saved_already_making_children = already_making_children; -} - -void -restore_pipeline (discard) - int discard; -{ - PROCESS *old_pipeline; - - old_pipeline = the_pipeline; - the_pipeline = saved_pipeline; - already_making_children = saved_already_making_children; - if (discard) - discard_pipeline (old_pipeline); -} - -/* Start building a pipeline. */ -void -start_pipeline () -{ - if (the_pipeline) - { - cleanup_the_pipeline (); - pipeline_pgrp = 0; -#if defined (PGRP_PIPE) - sh_closepipe (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. */ - sh_closepipe (pgrp_pipe); -#endif - - cleanup_dead_jobs (); - - if (js.j_jobslots == 0) - { - js.j_jobslots = JOB_SLOTS; - jobs = (JOB **)xmalloc (js.j_jobslots * sizeof (JOB *)); - - /* Now blank out these new entries. */ - for (i = 0; i < js.j_jobslots; i++) - jobs[i] = (JOB *)NULL; - - js.j_firstj = js.j_lastj = js.j_njobs = 0; - } - - /* Scan from the last slot backward, looking for the next free one. */ - /* XXX - revisit this interactive assumption */ - /* XXX - this way for now */ - if (interactive) - { - for (i = js.j_jobslots; i; i--) - if (jobs[i - 1]) - break; - } - else - { -#if 0 - /* This wraps around, but makes it inconvenient to extend the array */ - for (i = js.j_lastj+1; i != js.j_lastj; i++) - { - if (i >= js.j_jobslots) - i = 0; - if (jobs[i] == 0) - break; - } - if (i == js.j_lastj) - i = js.j_jobslots; -#else - /* This doesn't wrap around yet. */ - for (i = js.j_lastj ? js.j_lastj + 1 : js.j_lastj; i < js.j_jobslots; i++) - if (jobs[i] == 0) - break; -#endif - } - - /* Do we need more room? */ - - /* First try compaction */ - if ((interactive_shell == 0 || subshell_environment) && i == js.j_jobslots && js.j_jobslots >= MAX_JOBS_IN_ARRAY) - i = compact_jobs_list (0); - - /* If we can't compact, reallocate */ - if (i == js.j_jobslots) - { - js.j_jobslots += JOB_SLOTS; - jobs = (JOB **)xrealloc (jobs, (js.j_jobslots * sizeof (JOB *))); - - for (j = i; j < js.j_jobslots; j++) - jobs[j] = (JOB *)NULL; - } - - /* Add the current pipeline to the job list. */ - if (the_pipeline) - { - register PROCESS *p; - int any_running, any_stopped, n; - - newjob = (JOB *)xmalloc (sizeof (JOB)); - - for (n = 1, p = the_pipeline; p->next != the_pipeline; n++, p = p->next) - ; - p->next = (PROCESS *)NULL; - newjob->pipe = REVERSE_LIST (the_pipeline, PROCESS *); - for (p = newjob->pipe; p->next; p = p->next) - ; - p->next = newjob->pipe; - - the_pipeline = (PROCESS *)NULL; - newjob->pgrp = pipeline_pgrp; - pipeline_pgrp = 0; - - newjob->flags = 0; - - /* Flag to see if in another pgrp. */ - if (job_control) - newjob->flags |= J_JOBCONTROL; - - /* Set the state of this pipeline. */ - p = newjob->pipe; - any_running = any_stopped = 0; - do - { - any_running |= PRUNNING (p); - any_stopped |= PSTOPPED (p); - p = p->next; - } - while (p != newjob->pipe); - - newjob->state = any_running ? JRUNNING : (any_stopped ? JSTOPPED : JDEAD); - newjob->wd = job_working_directory (); - newjob->deferred = deferred; - - newjob->j_cleanup = (sh_vptrfunc_t *)NULL; - newjob->cleanarg = (PTR_T) NULL; - - jobs[i] = newjob; - if (newjob->state == JDEAD && (newjob->flags & J_FOREGROUND)) - setjstatus (i); - if (newjob->state == JDEAD) - { - js.c_reaped += n; /* wouldn't have been done since this was not part of a job */ - js.j_ndead++; - } - js.c_injobs += n; - - js.j_lastj = i; - js.j_njobs++; - } - else - newjob = (JOB *)NULL; - - if (newjob) - js.j_lastmade = newjob; - - if (async) - { - if (newjob) - { - newjob->flags &= ~J_FOREGROUND; - newjob->flags |= J_ASYNC; - js.j_lastasync = newjob; - } - reset_current (); - } - else - { - if (newjob) - { - newjob->flags |= J_FOREGROUND; - /* - * !!!!! NOTE !!!!! (chet@ins.cwru.edu) - * - * The currently-accepted job control wisdom says to set the - * terminal's process group n+1 times in an n-step pipeline: - * once in the parent and once in each child. This is where - * the parent gives it away. - * - * Don't give the terminal away if this shell is an asynchronous - * subshell. - * - */ - if (job_control && newjob->pgrp && (subshell_environment&SUBSHELL_ASYNC) == 0) - maybe_give_terminal_to (shell_pgrp, newjob->pgrp, 0); - } - } - - stop_making_children (); - UNBLOCK_CHILD (oset); - return (js.j_current); -} - -/* Functions to manage the list of exited background pids whose status has - been saved. */ - -static struct pidstat * -bgp_alloc (pid, status) - pid_t pid; - int status; -{ - struct pidstat *ps; - - ps = (struct pidstat *)xmalloc (sizeof (struct pidstat)); - ps->pid = pid; - ps->status = status; - ps->next = (struct pidstat *)0; - return ps; -} - -static struct pidstat * -bgp_add (pid, status) - pid_t pid; - int status; -{ - struct pidstat *ps; - - ps = bgp_alloc (pid, status); - - if (bgpids.list == 0) - { - bgpids.list = bgpids.end = ps; - bgpids.npid = 0; /* just to make sure */ - } - else - { - bgpids.end->next = ps; - bgpids.end = ps; - } - bgpids.npid++; - - if (bgpids.npid > js.c_childmax) - bgp_prune (); - - return ps; -} - -static int -bgp_delete (pid) - pid_t pid; -{ - struct pidstat *prev, *p; - - for (prev = p = bgpids.list; p; prev = p, p = p->next) - if (p->pid == pid) - { - prev->next = p->next; /* remove from list */ - break; - } - - if (p == 0) - return 0; /* not found */ - -#if defined (DEBUG) - itrace("bgp_delete: deleting %d", pid); -#endif - - /* Housekeeping in the border cases. */ - if (p == bgpids.list) - bgpids.list = bgpids.list->next; - else if (p == bgpids.end) - bgpids.end = prev; - - bgpids.npid--; - if (bgpids.npid == 0) - bgpids.list = bgpids.end = 0; - else if (bgpids.npid == 1) - bgpids.end = bgpids.list; /* just to make sure */ - - free (p); - return 1; -} - -/* Clear out the list of saved statuses */ -static void -bgp_clear () -{ - struct pidstat *ps, *p; - - for (ps = bgpids.list; ps; ) - { - p = ps; - ps = ps->next; - free (p); - } - bgpids.list = bgpids.end = 0; - bgpids.npid = 0; -} - -/* Search for PID in the list of saved background pids; return its status if - found. If not found, return -1. */ -static int -bgp_search (pid) - pid_t pid; -{ - struct pidstat *ps; - - for (ps = bgpids.list ; ps; ps = ps->next) - if (ps->pid == pid) - return ps->status; - return -1; -} - -static void -bgp_prune () -{ - struct pidstat *ps; - - while (bgpids.npid > js.c_childmax) - { - ps = bgpids.list; - bgpids.list = bgpids.list->next; - free (ps); - bgpids.npid--; - } -} - -/* Reset the values of js.j_lastj and js.j_firstj after one or both have - been deleted. The caller should check whether js.j_njobs is 0 before - calling this. This wraps around, but the rest of the code does not. At - this point, it should not matter. */ -static void -reset_job_indices () -{ - int old; - - if (jobs[js.j_firstj] == 0) - { - old = js.j_firstj++; - if (old >= js.j_jobslots) - old = js.j_jobslots - 1; - while (js.j_firstj != old) - { - if (js.j_firstj >= js.j_jobslots) - js.j_firstj = 0; - if (jobs[js.j_firstj] || js.j_firstj == old) /* needed if old == 0 */ - break; - js.j_firstj++; - } - if (js.j_firstj == old) - js.j_firstj = js.j_lastj = js.j_njobs = 0; - } - if (jobs[js.j_lastj] == 0) - { - old = js.j_lastj--; - if (old < 0) - old = 0; - while (js.j_lastj != old) - { - if (js.j_lastj < 0) - js.j_lastj = js.j_jobslots - 1; - if (jobs[js.j_lastj] || js.j_lastj == old) /* needed if old == js.j_jobslots */ - break; - js.j_lastj--; - } - if (js.j_lastj == old) - js.j_firstj = js.j_lastj = js.j_njobs = 0; - } -} - -/* Delete all DEAD jobs that the user had received notification about. */ -static void -cleanup_dead_jobs () -{ - register int i; - int os; - - if (js.j_jobslots == 0 || jobs_list_frozen) - return; - - QUEUE_SIGCHLD(os); - - /* XXX could use js.j_firstj and js.j_lastj here */ - for (i = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("cleanup_dead_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - - if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i)) - delete_job (i, 0); - } - UNQUEUE_SIGCHLD(os); -} - -static int -processes_in_job (job) - int job; -{ - int nproc; - register PROCESS *p; - - nproc = 0; - p = jobs[job]->pipe; - do - { - p = p->next; - nproc++; - } - while (p != jobs[job]->pipe); - - return nproc; -} - -static void -delete_old_job (pid) - pid_t pid; -{ - PROCESS *p; - int job; - - job = find_job (pid, 0, &p); - if (job != NO_JOB) - { -#ifdef DEBUG - itrace ("delete_old_job: found pid %d in job %d with state %d", pid, job, jobs[job]->state); -#endif - if (JOBSTATE (job) == JDEAD) - delete_job (job, DEL_NOBGPID); - else - { - internal_warning (_("forked pid %d appears in running job %d"), pid, job); - if (p) - p->pid = 0; - } - } -} - -/* Reallocate and compress the jobs list. This returns with a jobs array - whose size is a multiple of JOB_SLOTS and can hold the current number of - jobs. Heuristics are used to minimize the number of new reallocs. */ -static void -realloc_jobs_list () -{ - sigset_t set, oset; - int nsize, i, j, ncur, nprev; - JOB **nlist; - - ncur = nprev = NO_JOB; - nsize = ((js.j_njobs + JOB_SLOTS - 1) / JOB_SLOTS); - nsize *= JOB_SLOTS; - i = js.j_njobs % JOB_SLOTS; - if (i == 0 || i > (JOB_SLOTS >> 1)) - nsize += JOB_SLOTS; - - BLOCK_CHILD (set, oset); - nlist = (js.j_jobslots == nsize) ? jobs : (JOB **) xmalloc (nsize * sizeof (JOB *)); - - js.c_reaped = js.j_ndead = 0; - for (i = j = 0; i < js.j_jobslots; i++) - if (jobs[i]) - { - if (i == js.j_current) - ncur = j; - if (i == js.j_previous) - nprev = j; - nlist[j++] = jobs[i]; - if (jobs[i]->state == JDEAD) - { - js.j_ndead++; - js.c_reaped += processes_in_job (i); - } - } - -#if defined (DEBUG) - itrace ("realloc_jobs_list: resize jobs list from %d to %d", js.j_jobslots, nsize); - itrace ("realloc_jobs_list: j_lastj changed from %d to %d", js.j_lastj, (j > 0) ? j - 1 : 0); - itrace ("realloc_jobs_list: j_njobs changed from %d to %d", js.j_njobs, j); - itrace ("realloc_jobs_list: js.j_ndead %d js.c_reaped %d", js.j_ndead, js.c_reaped); -#endif - - js.j_firstj = 0; - js.j_lastj = (j > 0) ? j - 1 : 0; - js.j_njobs = j; - js.j_jobslots = nsize; - - /* Zero out remaining slots in new jobs list */ - for ( ; j < nsize; j++) - nlist[j] = (JOB *)NULL; - - if (jobs != nlist) - { - free (jobs); - jobs = nlist; - } - - if (ncur != NO_JOB) - js.j_current = ncur; - if (nprev != NO_JOB) - js.j_previous = nprev; - - /* Need to reset these */ - if (js.j_current == NO_JOB || js.j_previous == NO_JOB || js.j_current > js.j_lastj || js.j_previous > js.j_lastj) - reset_current (); - -#ifdef DEBUG - itrace ("realloc_jobs_list: reset js.j_current (%d) and js.j_previous (%d)", js.j_current, js.j_previous); -#endif - - UNBLOCK_CHILD (oset); -} - -/* Compact the jobs list by removing dead jobs. Assumed that we have filled - the jobs array to some predefined maximum. Called when the shell is not - the foreground process (subshell_environment != 0). Returns the first - available slot in the compacted list. If that value is js.j_jobslots, then - the list needs to be reallocated. The jobs array may be in new memory if - this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */ -static int -compact_jobs_list (flags) - int flags; -{ - if (js.j_jobslots == 0 || jobs_list_frozen) - return js.j_jobslots; - - reap_dead_jobs (); - realloc_jobs_list (); - -#ifdef DEBUG - itrace("compact_jobs_list: returning %d", (js.j_lastj || jobs[js.j_lastj]) ? js.j_lastj + 1 : 0); -#endif - - return ((js.j_lastj || jobs[js.j_lastj]) ? js.j_lastj + 1 : 0); -} - -/* Delete the job at INDEX from the job list. Must be called - with SIGCHLD blocked. */ -void -delete_job (job_index, dflags) - int job_index, dflags; -{ - register JOB *temp; - PROCESS *proc; - int ndel; - - if (js.j_jobslots == 0 || jobs_list_frozen) - return; - - if ((dflags & DEL_WARNSTOPPED) && subshell_environment == 0 && STOPPED (job_index)) - internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp); - temp = jobs[job_index]; - if (temp == 0) - return; - - if ((dflags & DEL_NOBGPID) == 0) - { - proc = find_last_proc (job_index, 0); - /* Could do this just for J_ASYNC jobs, but we save all. */ - if (proc) - bgp_add (proc->pid, process_exit_status (proc->status)); - } - - jobs[job_index] = (JOB *)NULL; - if (temp == js.j_lastmade) - js.j_lastmade = 0; - else if (temp == js.j_lastasync) - js.j_lastasync = 0; - - free (temp->wd); - ndel = discard_pipeline (temp->pipe); - - js.c_injobs -= ndel; - if (temp->state == JDEAD) - { - js.c_reaped -= ndel; - js.j_ndead--; - if (js.c_reaped < 0) - { -#ifdef DEBUG - itrace("delete_job (%d pgrp %d): js.c_reaped (%d) < 0 ndel = %d js.j_ndead = %d", job_index, temp->pgrp, js.c_reaped, ndel, js.j_ndead); -#endif - js.c_reaped = 0; - } - } - - if (temp->deferred) - dispose_command (temp->deferred); - - free (temp); - - js.j_njobs--; - if (js.j_njobs == 0) - js.j_firstj = js.j_lastj = 0; - else if (jobs[js.j_firstj] == 0 || jobs[js.j_lastj] == 0) - reset_job_indices (); - - if (job_index == js.j_current || job_index == js.j_previous) - reset_current (); -} - -/* Must be called with SIGCHLD blocked. */ -void -nohup_job (job_index) - int job_index; -{ - register JOB *temp; - - if (js.j_jobslots == 0) - return; - - if (temp = jobs[job_index]) - temp->flags |= J_NOHUP; -} - -/* Get rid of the data structure associated with a process chain. */ -static int -discard_pipeline (chain) - register PROCESS *chain; -{ - register PROCESS *this, *next; - int n; - - this = chain; - n = 0; - do - { - next = this->next; - FREE (this->command); - free (this); - n++; - this = next; - } - while (this != chain); - - return n; -} - -/* Add this process to the chain being built in the_pipeline. - NAME is the command string that will be exec'ed later. - PID is the process id of the child. */ -static void -add_process (name, pid) - char *name; - pid_t pid; -{ - PROCESS *t, *p; - -#if defined (RECYCLES_PIDS) - int j; - p = find_process (pid, 0, &j); - if (p) - { -# ifdef DEBUG - if (j == NO_JOB) - internal_warning (_("add_process: process %5ld (%s) in the_pipeline"), (long)p->pid, p->command); -# endif - if (PALIVE (p)) - internal_warning (_("add_process: pid %5ld (%s) marked as still alive"), (long)p->pid, p->command); - p->running = PS_RECYCLED; /* mark as recycled */ - } -#endif - - t = (PROCESS *)xmalloc (sizeof (PROCESS)); - t->next = the_pipeline; - t->pid = pid; - WSTATUS (t->status) = 0; - t->running = PS_RUNNING; - t->command = name; - the_pipeline = t; - - if (t->next == 0) - t->next = t; - else - { - p = t->next; - while (p->next != t->next) - p = p->next; - p->next = t; - } -} - -#if 0 -/* Take the last job and make it the first job. Must be called with - SIGCHLD blocked. */ -int -rotate_the_pipeline () -{ - PROCESS *p; - - if (the_pipeline->next == the_pipeline) - return; - for (p = the_pipeline; p->next != the_pipeline; p = p->next) - ; - the_pipeline = p; -} - -/* Reverse the order of the processes in the_pipeline. Must be called with - SIGCHLD blocked. */ -int -reverse_the_pipeline () -{ - PROCESS *p, *n; - - if (the_pipeline->next == the_pipeline) - return; - - for (p = the_pipeline; p->next != the_pipeline; p = p->next) - ; - p->next = (PROCESS *)NULL; - - n = REVERSE_LIST (the_pipeline, PROCESS *); - - the_pipeline = n; - for (p = the_pipeline; p->next; p = p->next) - ; - p->next = the_pipeline; -} -#endif - -/* Map FUNC over the list of jobs. If FUNC returns non-zero, - then it is time to stop mapping, and that is the return value - for map_over_jobs. FUNC is called with a JOB, arg1, arg2, - and INDEX. */ -static int -map_over_jobs (func, arg1, arg2) - sh_job_map_func_t *func; - int arg1, arg2; -{ - register int i; - int result; - sigset_t set, oset; - - if (js.j_jobslots == 0) - return 0; - - BLOCK_CHILD (set, oset); - - /* XXX could use js.j_firstj here */ - for (i = result = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("map_over_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - if (jobs[i]) - { - result = (*func)(jobs[i], arg1, arg2, i); - if (result) - break; - } - } - - UNBLOCK_CHILD (oset); - - return (result); -} - -/* Cause all the jobs in the current pipeline to exit. */ -void -terminate_current_pipeline () -{ - if (pipeline_pgrp && pipeline_pgrp != shell_pgrp) - { - killpg (pipeline_pgrp, SIGTERM); - killpg (pipeline_pgrp, SIGCONT); - } -} - -/* Cause all stopped jobs to exit. */ -void -terminate_stopped_jobs () -{ - register int i; - - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { - if (jobs[i] && STOPPED (i)) - { - killpg (jobs[i]->pgrp, SIGTERM); - killpg (jobs[i]->pgrp, SIGCONT); - } - } -} - -/* Cause all jobs, running or stopped, to receive a hangup signal. If - a job is marked J_NOHUP, don't send the SIGHUP. */ -void -hangup_all_jobs () -{ - register int i; - - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { - if (jobs[i]) - { - if (jobs[i]->flags & J_NOHUP) - continue; - killpg (jobs[i]->pgrp, SIGHUP); - if (STOPPED (i)) - killpg (jobs[i]->pgrp, SIGCONT); - } - } -} - -void -kill_current_pipeline () -{ - stop_making_children (); - start_pipeline (); -} - -/* Return the pipeline that PID belongs to. Note that the pipeline - doesn't have to belong to a job. Must be called with SIGCHLD blocked. - If JOBP is non-null, return the index of the job containing PID. */ -static PROCESS * -find_pipeline (pid, alive_only, jobp) - pid_t pid; - int alive_only; - int *jobp; /* index into jobs list or NO_JOB */ -{ - int job; - PROCESS *p; - - /* See if this process is in the pipeline that we are building. */ - if (jobp) - *jobp = NO_JOB; - if (the_pipeline) - { - p = the_pipeline; - do - { - /* Return it if we found it. Don't ever return a recycled pid. */ - if (p->pid == pid && ((alive_only == 0 && PRECYCLED(p) == 0) || PALIVE(p))) - return (p); - - p = p->next; - } - while (p != the_pipeline); - } - - job = find_job (pid, alive_only, &p); - if (jobp) - *jobp = job; - return (job == NO_JOB) ? (PROCESS *)NULL : jobs[job]->pipe; -} - -/* Return the PROCESS * describing PID. If JOBP is non-null return the index - into the jobs array of the job containing PID. Must be called with - SIGCHLD blocked. */ -static PROCESS * -find_process (pid, alive_only, jobp) - pid_t pid; - int alive_only; - int *jobp; /* index into jobs list or NO_JOB */ -{ - PROCESS *p; - - p = find_pipeline (pid, alive_only, jobp); - while (p && p->pid != pid) - p = p->next; - return p; -} - -/* Return the job index that PID belongs to, or NO_JOB if it doesn't - belong to any job. Must be called with SIGCHLD blocked. */ -static int -find_job (pid, alive_only, procp) - pid_t pid; - int alive_only; - PROCESS **procp; -{ - register int i; - PROCESS *p; - - /* XXX could use js.j_firstj here, and should check js.j_lastj */ - for (i = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("find_job: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - if (jobs[i]) - { - p = jobs[i]->pipe; - - do - { - if (p->pid == pid && ((alive_only == 0 && PRECYCLED(p) == 0) || PALIVE(p))) - { - if (procp) - *procp = p; - return (i); - } - - p = p->next; - } - while (p != jobs[i]->pipe); - } - } - - return (NO_JOB); -} - -/* Find a job given a PID. If BLOCK is non-zero, block SIGCHLD as - required by find_job. */ -int -get_job_by_pid (pid, block) - pid_t pid; - int block; -{ - int job; - sigset_t set, oset; - - if (block) - BLOCK_CHILD (set, oset); - - job = find_job (pid, 0, NULL); - - if (block) - UNBLOCK_CHILD (oset); - - return job; -} - -/* Print descriptive information about the job with leader pid PID. */ -void -describe_pid (pid) - pid_t pid; -{ - int job; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - - job = find_job (pid, 0, NULL); - - if (job != NO_JOB) - fprintf (stderr, "[%d] %ld\n", job + 1, (long)pid); - else - programming_error (_("describe_pid: %ld: no such pid"), (long)pid); - - UNBLOCK_CHILD (oset); -} - -static char * -j_strsignal (s) - int s; -{ - char *x; - - x = strsignal (s); - if (x == 0) - { - x = retcode_name_buffer; - sprintf (x, _("Signal %d"), s); - } - return x; -} - -static char * -printable_job_status (j, p, format) - int j; - PROCESS *p; - int format; -{ - static char *temp; - int es; - - temp = _("Done"); - - if (STOPPED (j) && format == 0) - { - if (posixly_correct == 0 || p == 0 || (WIFSTOPPED (p->status) == 0)) - temp = _("Stopped"); - else - { - temp = retcode_name_buffer; - sprintf (temp, _("Stopped(%s)"), signal_name (WSTOPSIG (p->status))); - } - } - else if (RUNNING (j)) - temp = _("Running"); - else - { - if (WIFSTOPPED (p->status)) - temp = j_strsignal (WSTOPSIG (p->status)); - else if (WIFSIGNALED (p->status)) - temp = j_strsignal (WTERMSIG (p->status)); - else if (WIFEXITED (p->status)) - { - temp = retcode_name_buffer; - es = WEXITSTATUS (p->status); - if (es == 0) - strcpy (temp, _("Done")); - else if (posixly_correct) - sprintf (temp, _("Done(%d)"), es); - else - sprintf (temp, _("Exit %d"), es); - } - else - temp = _("Unknown status"); - } - - return temp; -} - -/* This is the way to print out information on a job if you - know the index. FORMAT is: - - JLIST_NORMAL) [1]+ Running emacs - JLIST_LONG ) [1]+ 2378 Running emacs - -1 ) [1]+ 2378 emacs - - JLIST_NORMAL) [1]+ Stopped ls | more - JLIST_LONG ) [1]+ 2369 Stopped ls - 2367 | more - JLIST_PID_ONLY) - Just list the pid of the process group leader (really - the process group). - JLIST_CHANGED_ONLY) - Use format JLIST_NORMAL, but list only jobs about which - the user has not been notified. */ - -/* Print status for pipeline P. If JOB_INDEX is >= 0, it is the index into - the JOBS array corresponding to this pipeline. FORMAT is as described - above. Must be called with SIGCHLD blocked. - - If you're printing a pipeline that's not in the jobs array, like the - current pipeline as it's being created, pass -1 for JOB_INDEX */ -static void -print_pipeline (p, job_index, format, stream) - PROCESS *p; - int job_index, format; - FILE *stream; -{ - PROCESS *first, *last, *show; - int es, name_padding; - char *temp; - - if (p == 0) - return; - - first = last = p; - while (last->next != first) - last = last->next; - - for (;;) - { - if (p != first) - fprintf (stream, format ? " " : " |"); - - if (format != JLIST_STANDARD) - fprintf (stream, "%5ld", (long)p->pid); - - fprintf (stream, " "); - - if (format > -1 && job_index >= 0) - { - show = format ? p : last; - temp = printable_job_status (job_index, show, format); - - if (p != first) - { - if (format) - { - if (show->running == first->running && - WSTATUS (show->status) == WSTATUS (first->status)) - temp = ""; - } - else - temp = (char *)NULL; - } - - if (temp) - { - fprintf (stream, "%s", temp); - - es = STRLEN (temp); - if (es == 0) - es = 2; /* strlen ("| ") */ - name_padding = LONGEST_SIGNAL_DESC - es; - - fprintf (stream, "%*s", name_padding, ""); - - if ((WIFSTOPPED (show->status) == 0) && - (WIFCONTINUED (show->status) == 0) && - WIFCORED (show->status)) - fprintf (stream, _("(core dumped) ")); - } - } - - if (p != first && format) - fprintf (stream, "| "); - - if (p->command) - fprintf (stream, "%s", p->command); - - if (p == last && job_index >= 0) - { - temp = current_working_directory (); - - if (RUNNING (job_index) && (IS_FOREGROUND (job_index) == 0)) - fprintf (stream, " &"); - - if (strcmp (temp, jobs[job_index]->wd) != 0) - fprintf (stream, - _(" (wd: %s)"), polite_directory_format (jobs[job_index]->wd)); - } - - if (format || (p == last)) - { - /* We need to add a CR only if this is an interactive shell, and - we're reporting the status of a completed job asynchronously. - We can't really check whether this particular job is being - reported asynchronously, so just add the CR if the shell is - currently interactive and asynchronous notification is enabled. */ - if (asynchronous_notification && interactive) - fprintf (stream, "\r\n"); - else - fprintf (stream, "\n"); - } - - if (p == last) - break; - p = p->next; - } - fflush (stream); -} - -/* Print information to STREAM about jobs[JOB_INDEX] according to FORMAT. - Must be called with SIGCHLD blocked or queued with queue_sigchld */ -static void -pretty_print_job (job_index, format, stream) - int job_index, format; - FILE *stream; -{ - register PROCESS *p; - - /* Format only pid information about the process group leader? */ - if (format == JLIST_PID_ONLY) - { - fprintf (stream, "%ld\n", (long)jobs[job_index]->pipe->pid); - return; - } - - if (format == JLIST_CHANGED_ONLY) - { - if (IS_NOTIFIED (job_index)) - return; - format = JLIST_STANDARD; - } - - if (format != JLIST_NONINTERACTIVE) - fprintf (stream, "[%d]%c ", job_index + 1, - (job_index == js.j_current) ? '+': - (job_index == js.j_previous) ? '-' : ' '); - - if (format == JLIST_NONINTERACTIVE) - format = JLIST_LONG; - - p = jobs[job_index]->pipe; - - print_pipeline (p, job_index, format, stream); - - /* We have printed information about this job. When the job's - status changes, waitchld () sets the notification flag to 0. */ - jobs[job_index]->flags |= J_NOTIFIED; -} - -static int -print_job (job, format, state, job_index) - JOB *job; - int format, state, job_index; -{ - if (state == -1 || (JOB_STATE)state == job->state) - pretty_print_job (job_index, format, stdout); - return (0); -} - -void -list_one_job (job, format, ignore, job_index) - JOB *job; - int format, ignore, job_index; -{ - pretty_print_job (job_index, format, stdout); -} - -void -list_stopped_jobs (format) - int format; -{ - cleanup_dead_jobs (); - map_over_jobs (print_job, format, (int)JSTOPPED); -} - -void -list_running_jobs (format) - int format; -{ - cleanup_dead_jobs (); - map_over_jobs (print_job, format, (int)JRUNNING); -} - -/* List jobs. If FORMAT is non-zero, then the long form of the information - is printed, else just a short version. */ -void -list_all_jobs (format) - int format; -{ - cleanup_dead_jobs (); - map_over_jobs (print_job, format, -1); -} - -/* Fork, handling errors. Returns the pid of the newly made child, or 0. - COMMAND is just for remembering the name of the command; we don't do - anything else with it. ASYNC_P says what to do with the tty. If - non-zero, then don't give it away. */ -pid_t -make_child (command, async_p) - char *command; - int async_p; -{ - int forksleep; - sigset_t set, oset; - pid_t pid; - - sigemptyset (&set); - sigaddset (&set, SIGCHLD); - sigaddset (&set, SIGINT); - sigemptyset (&oset); - sigprocmask (SIG_BLOCK, &set, &oset); - - making_children (); - - forksleep = 1; - -#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. Retry on EAGAIN. */ - while ((pid = fork ()) < 0 && errno == EAGAIN && forksleep < FORKSLEEP_MAX) - { - sys_error ("fork: retry"); - if (sleep (forksleep) != 0) - break; - forksleep <<= 1; - } - - if (pid < 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 && ((subshell_environment&SUBSHELL_ASYNC) == 0)) - 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 sh_closepipe is done in stop_pipeline. */ - sh_closepipe (pgrp_pipe); -#endif /* PGRP_PIPE */ - -#if 0 - /* Don't set last_asynchronous_pid in the child */ - if (async_p) - last_asynchronous_pid = mypid; /* XXX */ - else -#endif -#if defined (RECYCLES_PIDS) - if (last_asynchronous_pid == mypid) - /* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */ - last_asynchronous_pid = 1; -#endif - } - else - { - /* In the parent. Remember the pid of the child just created - as the proper pgrp if this is the first child. */ - - if (first_pid == NO_PID) - first_pid = pid; - else if (pid_wrap == -1 && pid < first_pid) - pid_wrap = 0; - else if (pid_wrap == 0 && pid >= first_pid) - pid_wrap = 1; - - if (job_control) - { - if (pipeline_pgrp == 0) - { - pipeline_pgrp = pid; - /* Don't twiddle terminal pgrps in the parent! This is the bug, - not the good thing of twiddling them in the child! */ - /* give_terminal_to (pipeline_pgrp, 0); */ - } - /* This is done on the recommendation of the Rationale section of - the POSIX 1003.1 standard, where it discusses job control and - shells. It is done to avoid possible race conditions. (Ref. - 1003.1 Rationale, section B.4.3.3, page 236). */ - setpgid (pid, pipeline_pgrp); - } - else - { - if (pipeline_pgrp == 0) - pipeline_pgrp = shell_pgrp; - } - - /* Place all processes into the jobs array regardless of the - state of job_control. */ - add_process (command, pid); - - if (async_p) - last_asynchronous_pid = pid; -#if defined (RECYCLES_PIDS) - else if (last_asynchronous_pid == pid) - /* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */ - last_asynchronous_pid = 1; -#endif - - if (pid_wrap > 0) - delete_old_job (pid); - -#if !defined (RECYCLES_PIDS) - /* Only check for saved status if we've saved more than CHILD_MAX - statuses, unless the system recycles pids. */ - if ((js.c_reaped + bgpids.npid) >= js.c_childmax) -#endif - bgp_delete (pid); /* new process, discard any saved status */ - - last_made_pid = pid; - - /* keep stats */ - js.c_totforked++; - js.c_living++; - - /* Unblock SIGINT and SIGCHLD unless creating a pipeline, in which case - SIGCHLD remains blocked until all commands in the pipeline have been - created. */ - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); - } - - return (pid); -} - -/* These two functions are called only in child processes. */ -void -ignore_tty_job_signals () -{ - set_signal_handler (SIGTSTP, SIG_IGN); - set_signal_handler (SIGTTIN, SIG_IGN); - set_signal_handler (SIGTTOU, SIG_IGN); -} - -void -default_tty_job_signals () -{ - set_signal_handler (SIGTSTP, SIG_DFL); - set_signal_handler (SIGTTIN, SIG_DFL); - set_signal_handler (SIGTTOU, SIG_DFL); -} - -/* When we end a job abnormally, or if we stop a job, we set the tty to the - state kept in here. When a job ends normally, we set the state in here - to the state of the tty. */ - -static TTYSTRUCT shell_tty_info; - -#if defined (NEW_TTY_DRIVER) -static struct tchars shell_tchars; -static struct ltchars shell_ltchars; -#endif /* NEW_TTY_DRIVER */ - -#if defined (NEW_TTY_DRIVER) && defined (DRAIN_OUTPUT) -/* Since the BSD tty driver does not allow us to change the tty modes - while simultaneously waiting for output to drain and preserving - typeahead, we have to drain the output ourselves before calling - ioctl. We cheat by finding the length of the output queue, and - using select to wait for an appropriate length of time. This is - a hack, and should be labeled as such (it's a hastily-adapted - mutation of a `usleep' implementation). It's only reason for - existing is the flaw in the BSD tty driver. */ - -static int ttspeeds[] = -{ - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, - 1800, 2400, 4800, 9600, 19200, 38400 -}; - -static void -draino (fd, ospeed) - int fd, ospeed; -{ - register int delay = ttspeeds[ospeed]; - int n; - - if (!delay) - return; - - while ((ioctl (fd, TIOCOUTQ, &n) == 0) && n) - { - if (n > (delay / 100)) - { - struct timeval tv; - - n *= 10; /* 2 bits more for conservativeness. */ - tv.tv_sec = n / delay; - tv.tv_usec = ((n % delay) * 1000000) / delay; - select (fd, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv); - } - else - break; - } -} -#endif /* NEW_TTY_DRIVER && DRAIN_OUTPUT */ - -/* Return the fd from which we are actually getting input. */ -#define input_tty() (shell_tty != -1) ? shell_tty : fileno (stderr) - -/* Fill the contents of shell_tty_info with the current tty info. */ -int -get_tty_state () -{ - int tty; - - tty = input_tty (); - if (tty != -1) - { -#if defined (NEW_TTY_DRIVER) - ioctl (tty, TIOCGETP, &shell_tty_info); - ioctl (tty, TIOCGETC, &shell_tchars); - ioctl (tty, TIOCGLTC, &shell_ltchars); -#endif /* NEW_TTY_DRIVER */ - -#if defined (TERMIO_TTY_DRIVER) - ioctl (tty, TCGETA, &shell_tty_info); -#endif /* TERMIO_TTY_DRIVER */ - -#if defined (TERMIOS_TTY_DRIVER) - if (tcgetattr (tty, &shell_tty_info) < 0) - { -#if 0 - /* Only print an error message if we're really interactive at - this time. */ - if (interactive) - sys_error ("[%ld: %d (%d)] tcgetattr", (long)getpid (), shell_level, tty); -#endif - return -1; - } -#endif /* TERMIOS_TTY_DRIVER */ - if (check_window_size) - get_new_window_size (0, (int *)0, (int *)0); - } - return 0; -} - -/* Make the current tty use the state in shell_tty_info. */ -int -set_tty_state () -{ - int tty; - - tty = input_tty (); - if (tty != -1) - { -#if defined (NEW_TTY_DRIVER) -# if defined (DRAIN_OUTPUT) - draino (tty, shell_tty_info.sg_ospeed); -# endif /* DRAIN_OUTPUT */ - ioctl (tty, TIOCSETN, &shell_tty_info); - ioctl (tty, TIOCSETC, &shell_tchars); - ioctl (tty, TIOCSLTC, &shell_ltchars); -#endif /* NEW_TTY_DRIVER */ - -#if defined (TERMIO_TTY_DRIVER) - ioctl (tty, TCSETAW, &shell_tty_info); -#endif /* TERMIO_TTY_DRIVER */ - -#if defined (TERMIOS_TTY_DRIVER) - if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0) - { - /* Only print an error message if we're really interactive at - this time. */ - if (interactive) - sys_error ("[%ld: %d (%d)] tcsetattr", (long)getpid (), shell_level, tty); - return -1; - } -#endif /* TERMIOS_TTY_DRIVER */ - } - return 0; -} - -/* Given an index into the jobs array JOB, return the PROCESS struct of the last - process in that job's pipeline. This is the one whose exit status - counts. Must be called with SIGCHLD blocked or queued. */ -static PROCESS * -find_last_proc (job, block) - int job; - int block; -{ - register PROCESS *p; - sigset_t set, oset; - - if (block) - BLOCK_CHILD (set, oset); - - p = jobs[job]->pipe; - while (p && p->next != jobs[job]->pipe) - p = p->next; - - if (block) - UNBLOCK_CHILD (oset); - - return (p); -} - -static pid_t -find_last_pid (job, block) - int job; - int block; -{ - PROCESS *p; - - p = find_last_proc (job, block); - /* Possible race condition here. */ - return p->pid; -} - -/* Wait for a particular child of the shell to finish executing. - This low-level function prints an error message if PID is not - a child of this shell. It returns -1 if it fails, or whatever - wait_for returns otherwise. If the child is not found in the - jobs table, it returns 127. */ -int -wait_for_single_pid (pid) - pid_t pid; -{ - register PROCESS *child; - sigset_t set, oset; - int r, job; - - BLOCK_CHILD (set, oset); - child = find_pipeline (pid, 0, (int *)NULL); - UNBLOCK_CHILD (oset); - - if (child == 0) - { - r = bgp_search (pid); - if (r >= 0) - return r; - } - - if (child == 0) - { - internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid); - return (127); - } - - r = wait_for (pid); - - /* POSIX.2: if we just waited for a job, we can remove it from the jobs - table. */ - BLOCK_CHILD (set, oset); - job = find_job (pid, 0, NULL); - if (job != NO_JOB && jobs[job] && DEADJOB (job)) - jobs[job]->flags |= J_NOTIFIED; - UNBLOCK_CHILD (oset); - - /* If running in posix mode, remove the job from the jobs table immediately */ - if (posixly_correct) - { - cleanup_dead_jobs (); - bgp_delete (pid); - } - - return r; -} - -/* Wait for all of the backgrounds of this shell to finish. */ -void -wait_for_background_pids () -{ - register int i, r, waited_for; - sigset_t set, oset; - pid_t pid; - - for (waited_for = 0;;) - { - BLOCK_CHILD (set, oset); - - /* find first running job; if none running in foreground, break */ - /* XXX could use js.j_firstj and js.j_lastj here */ - for (i = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("wait_for_background_pids: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0) - break; - } - if (i == js.j_jobslots) - { - UNBLOCK_CHILD (oset); - break; - } - - /* now wait for the last pid in that job. */ - pid = find_last_pid (i, 0); - UNBLOCK_CHILD (oset); - QUIT; - errno = 0; /* XXX */ - r = wait_for_single_pid (pid); - if (r == -1) - { - /* If we're mistaken about job state, compensate. */ - if (errno == ECHILD) - mark_all_jobs_as_dead (); - } - else - waited_for++; - } - - /* POSIX.2 says the shell can discard the statuses of all completed jobs if - `wait' is called with no arguments. */ - mark_dead_jobs_as_notified (1); - cleanup_dead_jobs (); - bgp_clear (); -} - -/* Make OLD_SIGINT_HANDLER the SIGINT signal handler. */ -#define INVALID_SIGNAL_HANDLER (SigHandler *)wait_for_background_pids -static SigHandler *old_sigint_handler = INVALID_SIGNAL_HANDLER; - -static void -restore_sigint_handler () -{ - if (old_sigint_handler != INVALID_SIGNAL_HANDLER) - { - set_signal_handler (SIGINT, old_sigint_handler); - old_sigint_handler = INVALID_SIGNAL_HANDLER; - } -} - -static int wait_sigint_received; - -/* Handle SIGINT while we are waiting for children in a script to exit. - The `wait' builtin should be interruptible, but all others should be - effectively ignored (i.e. not cause the shell to exit). */ -static sighandler -wait_sigint_handler (sig) - int sig; -{ - SigHandler *sigint_handler; - - if (interrupt_immediately || - (this_shell_builtin && this_shell_builtin == wait_builtin)) - { - last_command_exit_value = EXECUTION_FAILURE; - restore_sigint_handler (); - /* If we got a SIGINT while in `wait', and SIGINT is trapped, do - what POSIX.2 says (see builtins/wait.def for more info). */ - if (this_shell_builtin && this_shell_builtin == wait_builtin && - signal_is_trapped (SIGINT) && - ((sigint_handler = trap_to_sighandler (SIGINT)) == trap_handler)) - { - interrupt_immediately = 0; - trap_handler (SIGINT); /* set pending_traps[SIGINT] */ - wait_signal_received = SIGINT; - longjmp (wait_intr_buf, 1); - } - - ADDINTERRUPT; - QUIT; - } - - /* XXX - should this be interrupt_state? If it is, the shell will act - as if it got the SIGINT interrupt. */ - wait_sigint_received = 1; - - /* Otherwise effectively ignore the SIGINT and allow the running job to - be killed. */ - SIGRETURN (0); -} - -static int -process_exit_signal (status) - WAIT status; -{ - return (WIFSIGNALED (status) ? WTERMSIG (status) : 0); -} - -static int -process_exit_status (status) - WAIT status; -{ - if (WIFSIGNALED (status)) - return (128 + WTERMSIG (status)); - else if (WIFSTOPPED (status) == 0) - return (WEXITSTATUS (status)); - else - return (EXECUTION_SUCCESS); -} - -static WAIT -job_signal_status (job) - int job; -{ - register PROCESS *p; - WAIT s; - - p = jobs[job]->pipe; - do - { - s = p->status; - if (WIFSIGNALED(s) || WIFSTOPPED(s)) - break; - p = p->next; - } - while (p != jobs[job]->pipe); - - return s; -} - -/* 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; - WAIT ret; - - if (pipefail_opt) - { - fail = 0; - p = jobs[job]->pipe; - do - { - if (WSTATUS (p->status) != EXECUTION_SUCCESS) - fail = WSTATUS(p->status); - p = p->next; - } - while (p != jobs[job]->pipe); - WSTATUS (ret) = fail; - return ret; - } - - 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. In - fact, we want this set every time the waiting shell and the waited- - for process are in the same process group, including command - substitution. */ - - /* This is possibly a race condition -- should it go in stop_pipeline? */ - wait_sigint_received = 0; - if (job_control == 0 || (subshell_environment&SUBSHELL_COMSUB)) - { - old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); - if (old_sigint_handler == SIG_IGN) - set_signal_handler (SIGINT, old_sigint_handler); - } - - termination_state = last_command_exit_value; - - if (interactive && job_control == 0) - QUIT; - - /* If we say wait_for (), then we have a record of this child somewhere. - If it and none of its peers are running, don't call waitchld(). */ - - job = NO_JOB; - do - { - FIND_CHILD (pid, child); - - /* If this child is part of a job, then we are really waiting for the - job to finish. Otherwise, we are waiting for the child to finish. - We check for JDEAD in case the job state has been set by waitchld - after receipt of a SIGCHLD. */ - if (job == NO_JOB) - job = find_job (pid, 0, NULL); - - /* waitchld() takes care of setting the state of the job. If the job - has already exited before this is called, sigchld_handler will have - called waitchld and the state will be set to JDEAD. */ - - if (PRUNNING(child) || (job != NO_JOB && RUNNING (job))) - { -#if defined (WAITPID_BROKEN) /* SCOv4 */ - sigset_t suspend_set; - sigemptyset (&suspend_set); - sigsuspend (&suspend_set); -#else /* !WAITPID_BROKEN */ -# if defined (MUST_UNBLOCK_CHLD) - struct sigaction act, oact; - sigset_t nullset, chldset; - - sigemptyset (&nullset); - sigemptyset (&chldset); - sigprocmask (SIG_SETMASK, &nullset, &chldset); - act.sa_handler = SIG_DFL; - sigemptyset (&act.sa_mask); - sigemptyset (&oact.sa_mask); - act.sa_flags = 0; - sigaction (SIGCHLD, &act, &oact); -# endif - queue_sigchld = 1; - r = waitchld (pid, 1); -# if defined (MUST_UNBLOCK_CHLD) - sigaction (SIGCHLD, &oact, (struct sigaction *)NULL); - sigprocmask (SIG_SETMASK, &chldset, (sigset_t *)NULL); -# endif - queue_sigchld = 0; - if (r == -1 && errno == ECHILD && this_shell_builtin == wait_builtin) - { - termination_state = -1; - goto wait_for_return; - } - - /* If child is marked as running, but waitpid() returns -1/ECHILD, - there is something wrong. Somewhere, wait should have returned - that child's pid. Mark the child as not running and the job, - if it exists, as JDEAD. */ - if (r == -1 && errno == ECHILD) - { - child->running = PS_DONE; - WSTATUS (child->status) = 0; /* XXX -- can't find true status */ - js.c_living = 0; /* no living child processes */ - if (job != NO_JOB) - { - jobs[job]->state = JDEAD; - js.c_reaped++; - js.j_ndead++; - } - } -#endif /* WAITPID_BROKEN */ - } - - /* If the shell is interactive, and job control is disabled, see - if the foreground process has died due to SIGINT and jump out - of the wait loop if it has. waitchld has already restored the - old SIGINT signal handler. */ - if (interactive && job_control == 0) - QUIT; - } - while (PRUNNING (child) || (job != NO_JOB && RUNNING (job))); - - /* The exit state of the command is either the termination state of the - child, or the termination state of the job. If a job, the status - of the last child in the pipeline is the significant one. If the command - or job was terminated by a signal, note that value also. */ - termination_state = (job != NO_JOB) ? job_exit_status (job) - : process_exit_status (child->status); - last_command_exit_signal = (job != NO_JOB) ? job_exit_signal (job) - : process_exit_signal (child->status); - - /* XXX */ - if ((job != NO_JOB && JOBSTATE (job) == JSTOPPED) || WIFSTOPPED (child->status)) - termination_state = 128 + WSTOPSIG (child->status); - - if (job == NO_JOB || IS_JOBCONTROL (job)) - { - /* XXX - under what circumstances is a job not present in the jobs - table (job == NO_JOB)? - 1. command substitution - - In the case of command substitution, at least, it's probably not - the right thing to give the terminal to the shell's process group, - even though there is code in subst.c:command_substitute to work - around it. - - Things that don't: - $PROMPT_COMMAND execution - process substitution - */ -#if 0 -if (job == NO_JOB) - itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp); -#endif - give_terminal_to (shell_pgrp, 0); - } - - /* If the command did not exit cleanly, or the job is just - being stopped, then reset the tty state back to what it - was before this command. Reset the tty state and notify - the user of the job termination only if the shell is - interactive. Clean up any dead jobs in either case. */ - if (job != NO_JOB) - { - if (interactive_shell && subshell_environment == 0) - { - /* This used to use `child->status'. That's wrong, however, for - pipelines. `child' is the first process in the pipeline. It's - likely that the process we want to check for abnormal termination - or stopping is the last process in the pipeline, especially if - it's long-lived and the first process is short-lived. Since we - know we have a job here, we can check all the processes in this - job's pipeline and see if one of them stopped or terminated due - to a signal. We might want to change this later to just check - the last process in the pipeline. If no process exits due to a - signal, S is left as the status of the last job in the pipeline. */ - s = job_signal_status (job); - - if (WIFSIGNALED (s) || WIFSTOPPED (s)) - { - set_tty_state (); - - /* If the current job was stopped or killed by a signal, and - the user has requested it, get a possibly new window size */ - if (check_window_size && (job == js.j_current || IS_FOREGROUND (job))) - get_new_window_size (0, (int *)0, (int *)0); - } - else - get_tty_state (); - - /* If job control is enabled, the job was started with job - control, the job was the foreground job, and it was killed - by SIGINT, then print a newline to compensate for the kernel - printing the ^C without a trailing newline. */ - if (job_control && IS_JOBCONTROL (job) && IS_FOREGROUND (job) && - WIFSIGNALED (s) && WTERMSIG (s) == SIGINT) - { - /* If SIGINT is not trapped and the shell is in a for, while, - or until loop, act as if the shell received SIGINT as - well, so the loop can be broken. This doesn't call the - SIGINT signal handler; maybe it should. */ - if (signal_is_trapped (SIGINT) == 0 && (loop_level || (shell_compatibility_level > 32 && executing_list))) - ADDINTERRUPT; - else - { - putchar ('\n'); - fflush (stdout); - } - } - } - else if ((subshell_environment & SUBSHELL_COMSUB) && wait_sigint_received) - { - /* If waiting for a job in a subshell started to do command - substitution, simulate getting and being killed by the SIGINT to - pass the status back to our parent. */ - s = job_signal_status (job); - - if (WIFSIGNALED (s) && WTERMSIG (s) == SIGINT && signal_is_trapped (SIGINT) == 0) - { - UNBLOCK_CHILD (oset); - restore_sigint_handler (); - old_sigint_handler = set_signal_handler (SIGINT, SIG_DFL); - if (old_sigint_handler == SIG_IGN) - restore_sigint_handler (); - else - kill (getpid (), SIGINT); - } - } - - /* Moved here from set_job_status_and_cleanup, which is in the SIGCHLD - signal handler path */ - if (DEADJOB (job) && IS_FOREGROUND (job) /*&& subshell_environment == 0*/) - setjstatus (job); - - /* If this job is dead, notify the user of the status. If the shell - is interactive, this will display a message on the terminal. If - the shell is not interactive, make sure we turn on the notify bit - so we don't get an unwanted message about the job's termination, - and so delete_job really clears the slot in the jobs table. */ - notify_and_cleanup (); - } - -wait_for_return: - - UNBLOCK_CHILD (oset); - - /* Restore the original SIGINT signal handler before we return. */ - restore_sigint_handler (); - - return (termination_state); -} - -/* Wait for the last process in the pipeline for JOB. Returns whatever - wait_for returns: the last process's termination state or -1 if there - are no unwaited-for child processes or an error occurs. */ -int -wait_for_job (job) - int job; -{ - pid_t pid; - int r; - sigset_t set, oset; - - BLOCK_CHILD(set, oset); - if (JOBSTATE (job) == JSTOPPED) - internal_warning (_("wait_for_job: job %d is stopped"), job+1); - - pid = find_last_pid (job, 0); - UNBLOCK_CHILD(oset); - r = wait_for (pid); - - /* POSIX.2: we can remove the job from the jobs table if we just waited - for it. */ - BLOCK_CHILD (set, oset); - if (job != NO_JOB && jobs[job] && DEADJOB (job)) - jobs[job]->flags |= J_NOTIFIED; - UNBLOCK_CHILD (oset); - - return r; -} - -/* Print info about dead jobs, and then delete them from the list - of known jobs. This does not actually delete jobs when the - shell is not interactive, because the dead jobs are not marked - as notified. */ -void -notify_and_cleanup () -{ - if (jobs_list_frozen) - return; - - if (interactive || interactive_shell == 0 || sourcelevel) - notify_of_job_status (); - - cleanup_dead_jobs (); -} - -/* Make dead jobs disappear from the jobs array without notification. - This is used when the shell is not interactive. */ -void -reap_dead_jobs () -{ - mark_dead_jobs_as_notified (0); - cleanup_dead_jobs (); -} - -/* Return the next closest (chronologically) job to JOB which is in - STATE. STATE can be JSTOPPED, JRUNNING. NO_JOB is returned if - there is no next recent job. */ -static int -most_recent_job_in_state (job, state) - int job; - JOB_STATE state; -{ - register int i, result; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - - for (result = NO_JOB, i = job - 1; i >= 0; i--) - { - if (jobs[i] && (JOBSTATE (i) == state)) - { - result = i; - break; - } - } - - UNBLOCK_CHILD (oset); - - return (result); -} - -/* Return the newest *stopped* job older than JOB, or NO_JOB if not - found. */ -static int -job_last_stopped (job) - int job; -{ - return (most_recent_job_in_state (job, JSTOPPED)); -} - -/* Return the newest *running* job older than JOB, or NO_JOB if not - found. */ -static int -job_last_running (job) - int job; -{ - return (most_recent_job_in_state (job, JRUNNING)); -} - -/* Make JOB be the current job, and make previous be useful. Must be - called with SIGCHLD blocked. */ -static void -set_current_job (job) - int job; -{ - int candidate; - - if (js.j_current != job) - { - js.j_previous = js.j_current; - js.j_current = job; - } - - /* First choice for previous job is the old current job. */ - if (js.j_previous != js.j_current && - js.j_previous != NO_JOB && - jobs[js.j_previous] && - STOPPED (js.j_previous)) - return; - - /* Second choice: Newest stopped job that is older than - the current job. */ - candidate = NO_JOB; - if (STOPPED (js.j_current)) - { - candidate = job_last_stopped (js.j_current); - - if (candidate != NO_JOB) - { - js.j_previous = candidate; - return; - } - } - - /* If we get here, there is either only one stopped job, in which case it is - the current job and the previous job should be set to the newest running - job, or there are only running jobs and the previous job should be set to - the newest running job older than the current job. We decide on which - alternative to use based on whether or not JOBSTATE(js.j_current) is - JSTOPPED. */ - - candidate = RUNNING (js.j_current) ? job_last_running (js.j_current) - : job_last_running (js.j_jobslots); - - if (candidate != NO_JOB) - { - js.j_previous = candidate; - return; - } - - /* There is only a single job, and it is both `+' and `-'. */ - js.j_previous = js.j_current; -} - -/* Make current_job be something useful, if it isn't already. */ - -/* Here's the deal: The newest non-running job should be `+', and the - next-newest non-running job should be `-'. If there is only a single - stopped job, the js.j_previous is the newest non-running job. If there - are only running jobs, the newest running job is `+' and the - next-newest running job is `-'. Must be called with SIGCHLD blocked. */ - -static void -reset_current () -{ - int candidate; - - if (js.j_jobslots && js.j_current != NO_JOB && jobs[js.j_current] && STOPPED (js.j_current)) - candidate = js.j_current; - else - { - candidate = NO_JOB; - - /* First choice: the previous job. */ - if (js.j_previous != NO_JOB && jobs[js.j_previous] && STOPPED (js.j_previous)) - candidate = js.j_previous; - - /* Second choice: the most recently stopped job. */ - if (candidate == NO_JOB) - candidate = job_last_stopped (js.j_jobslots); - - /* Third choice: the newest running job. */ - if (candidate == NO_JOB) - candidate = job_last_running (js.j_jobslots); - } - - /* If we found a job to use, then use it. Otherwise, there - are no jobs period. */ - if (candidate != NO_JOB) - set_current_job (candidate); - else - js.j_current = js.j_previous = NO_JOB; -} - -/* Set up the job structures so we know the job and its processes are - all running. */ -static void -set_job_running (job) - int job; -{ - register PROCESS *p; - - /* Each member of the pipeline is now running. */ - p = jobs[job]->pipe; - - do - { - if (WIFSTOPPED (p->status)) - p->running = PS_RUNNING; /* XXX - could be PS_STOPPED */ - p = p->next; - } - while (p != jobs[job]->pipe); - - /* This means that the job is running. */ - JOBSTATE (job) = JRUNNING; -} - -/* Start a job. FOREGROUND if non-zero says to do that. Otherwise, - start the job in the background. JOB is a zero-based index into - JOBS. Returns -1 if it is unable to start a job, and the return - status of the job otherwise. */ -int -start_job (job, foreground) - int job, foreground; -{ - register PROCESS *p; - int already_running; - sigset_t set, oset; - char *wd, *s; - static TTYSTRUCT save_stty; - - BLOCK_CHILD (set, oset); - - if (DEADJOB (job)) - { - internal_error (_("%s: job has terminated"), this_command_name); - UNBLOCK_CHILD (oset); - return (-1); - } - - already_running = RUNNING (job); - - if (foreground == 0 && already_running) - { - internal_error (_("%s: job %d already in background"), this_command_name, job + 1); - UNBLOCK_CHILD (oset); - return (0); /* XPG6/SUSv3 says this is not an error */ - } - - wd = current_working_directory (); - - /* You don't know about the state of this job. Do you? */ - jobs[job]->flags &= ~J_NOTIFIED; - - if (foreground) - { - set_current_job (job); - jobs[job]->flags |= J_FOREGROUND; - } - - /* Tell the outside world what we're doing. */ - p = jobs[job]->pipe; - - if (foreground == 0) - { - /* POSIX.2 says `bg' doesn't give any indication about current or - previous job. */ - if (posixly_correct == 0) - s = (job == js.j_current) ? "+ ": ((job == js.j_previous) ? "- " : " "); - else - s = " "; - printf ("[%d]%s", job + 1, s); - } - - do - { - printf ("%s%s", - p->command ? p->command : "", - p->next != jobs[job]->pipe? " | " : ""); - p = p->next; - } - while (p != jobs[job]->pipe); - - if (foreground == 0) - printf (" &"); - - if (strcmp (wd, jobs[job]->wd) != 0) - printf (" (wd: %s)", polite_directory_format (jobs[job]->wd)); - - printf ("\n"); - - /* Run the job. */ - if (already_running == 0) - set_job_running (job); - - /* Save the tty settings before we start the job in the foreground. */ - if (foreground) - { - get_tty_state (); - save_stty = shell_tty_info; - /* Give the terminal to this job. */ - if (IS_JOBCONTROL (job)) - give_terminal_to (jobs[job]->pgrp, 0); - } - else - jobs[job]->flags &= ~J_FOREGROUND; - - /* If the job is already running, then don't bother jump-starting it. */ - if (already_running == 0) - { - jobs[job]->flags |= J_NOTIFIED; - killpg (jobs[job]->pgrp, SIGCONT); - } - - if (foreground) - { - pid_t pid; - int st; - - pid = find_last_pid (job, 0); - UNBLOCK_CHILD (oset); - st = wait_for (pid); - shell_tty_info = save_stty; - set_tty_state (); - return (st); - } - else - { - reset_current (); - UNBLOCK_CHILD (oset); - return (0); - } -} - -/* Give PID SIGNAL. This determines what job the pid belongs to (if any). - If PID does belong to a job, and the job is stopped, then CONTinue the - job after giving it SIGNAL. Returns -1 on failure. If GROUP is non-null, - then kill the process group associated with PID. */ -int -kill_pid (pid, sig, group) - pid_t pid; - int sig, group; -{ - register PROCESS *p; - int job, result, negative; - sigset_t set, oset; - - if (pid < -1) - { - pid = -pid; - group = negative = 1; - } - else - negative = 0; - - result = EXECUTION_SUCCESS; - if (group) - { - BLOCK_CHILD (set, oset); - p = find_pipeline (pid, 0, &job); - - if (job != NO_JOB) - { - jobs[job]->flags &= ~J_NOTIFIED; - - /* Kill process in backquotes or one started without job control? */ - - /* If we're passed a pid < -1, just call killpg and see what happens */ - if (negative && jobs[job]->pgrp == shell_pgrp) - result = killpg (pid, sig); - /* If we're killing using job control notification, for example, - without job control active, we have to do things ourselves. */ - else if (jobs[job]->pgrp == shell_pgrp) - { - p = jobs[job]->pipe; - do - { - if (PALIVE (p) == 0) - continue; /* avoid pid recycling problem */ - kill (p->pid, sig); - if (PEXITED (p) && (sig == SIGTERM || sig == SIGHUP)) - kill (p->pid, SIGCONT); - p = p->next; - } - while (p != jobs[job]->pipe); - } - else - { - result = killpg (jobs[job]->pgrp, sig); - if (p && STOPPED (job) && (sig == SIGTERM || sig == SIGHUP)) - killpg (jobs[job]->pgrp, SIGCONT); - /* If we're continuing a stopped job via kill rather than bg or - fg, emulate the `bg' behavior. */ - if (p && STOPPED (job) && (sig == SIGCONT)) - { - set_job_running (job); - jobs[job]->flags &= ~J_FOREGROUND; - jobs[job]->flags |= J_NOTIFIED; - } - } - } - else - result = killpg (pid, sig); - - UNBLOCK_CHILD (oset); - } - else - result = kill (pid, sig); - - return (result); -} - -/* sigchld_handler () flushes at least one of the children that we are - waiting for. It gets run when we have gotten a SIGCHLD signal. */ -static sighandler -sigchld_handler (sig) - int sig; -{ - int n, oerrno; - - oerrno = errno; - REINSTALL_SIGCHLD_HANDLER; - sigchld++; - n = 0; - if (queue_sigchld == 0) - n = waitchld (-1, 0); - errno = oerrno; - SIGRETURN (n); -} - -/* waitchld() reaps dead or stopped children. It's called by wait_for and - sigchld_handler, and runs until there aren't any children terminating any - more. - If BLOCK is 1, this is to be a blocking wait for a single child, although - an arriving SIGCHLD could cause the wait to be non-blocking. It returns - the number of children reaped, or -1 if there are no unwaited-for child - processes. */ -static int -waitchld (wpid, block) - pid_t wpid; - int block; -{ - WAIT status; - PROCESS *child; - pid_t pid; - int call_set_current, last_stopped_job, job, children_exited, waitpid_flags; - static int wcontinued = WCONTINUED; /* run-time fix for glibc problem */ - - call_set_current = children_exited = 0; - last_stopped_job = NO_JOB; - - do - { - /* We don't want to be notified about jobs stopping if job control - is not active. XXX - was interactive_shell instead of job_control */ - waitpid_flags = (job_control && subshell_environment == 0) - ? (WUNTRACED|wcontinued) - : 0; - if (sigchld || block == 0) - waitpid_flags |= WNOHANG; - CHECK_TERMSIG; - - pid = WAITPID (-1, &status, waitpid_flags); - - /* WCONTINUED may be rejected by waitpid as invalid even when defined */ - if (wcontinued && pid < 0 && errno == EINVAL) - { - wcontinued = 0; - continue; /* jump back to the test and retry without WCONTINUED */ - } - - /* The check for WNOHANG is to make sure we decrement sigchld only - if it was non-zero before we called waitpid. */ - if (sigchld > 0 && (waitpid_flags & WNOHANG)) - sigchld--; - - /* If waitpid returns -1 with errno == ECHILD, there are no more - unwaited-for child processes of this shell. */ - if (pid < 0 && errno == ECHILD) - { - if (children_exited == 0) - return -1; - else - break; - } - - /* If waitpid returns 0, there are running children. If it returns -1, - the only other error POSIX says it can return is EINTR. */ - CHECK_TERMSIG; - if (pid <= 0) - continue; /* jumps right to the test */ - - /* children_exited is used to run traps on SIGCHLD. We don't want to - run the trap if a process is just being continued. */ - if (WIFCONTINUED(status) == 0) - { - children_exited++; - js.c_living--; - } - - /* Locate our PROCESS for this pid. */ - child = find_process (pid, 1, &job); /* want living procs only */ - -#if defined (COPROCESS_SUPPORT) - coproc_pidchk (pid, status); -#endif - - /* 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) - { - if (WIFEXITED (status) || WIFSIGNALED (status)) - js.c_reaped++; - continue; - } - - /* Remember status, and whether or not the process is running. */ - child->status = status; - child->running = WIFCONTINUED(status) ? PS_RUNNING : PS_DONE; - - if (PEXITED (child)) - { - js.c_totreaped++; - if (job != NO_JOB) - js.c_reaped++; - } - - if (job == NO_JOB) - continue; - - call_set_current += set_job_status_and_cleanup (job); - - if (STOPPED (job)) - last_stopped_job = job; - else if (DEADJOB (job) && last_stopped_job == job) - last_stopped_job = NO_JOB; - } - while ((sigchld || block == 0) && pid > (pid_t)0); - - /* If a job was running and became stopped, then set the current - job. Otherwise, don't change a thing. */ - if (call_set_current) - { - if (last_stopped_job != NO_JOB) - set_current_job (last_stopped_job); - else - reset_current (); - } - - /* Call a SIGCHLD trap handler for each child that exits, if one is set. */ - if (job_control && signal_is_trapped (SIGCHLD) && children_exited && - trap_list[SIGCHLD] != (char *)IGNORE_SIG) - { - if (this_shell_builtin && this_shell_builtin == wait_builtin) - { - interrupt_immediately = 0; - trap_handler (SIGCHLD); /* set pending_traps[SIGCHLD] */ - wait_signal_received = SIGCHLD; - longjmp (wait_intr_buf, 1); - } - - run_sigchld_trap (children_exited); - } - - /* We have successfully recorded the useful information about this process - that has just changed state. If we notify asynchronously, and the job - that this process belongs to is no longer running, then notify the user - of that fact now. */ - if (asynchronous_notification && interactive) - notify_of_job_status (); - - return (children_exited); -} - -/* Set the status of JOB and perform any necessary cleanup if the job is - marked as JDEAD. - - Currently, the cleanup activity is restricted to handling any SIGINT - received while waiting for a foreground job to finish. */ -static int -set_job_status_and_cleanup (job) - int job; -{ - PROCESS *child; - int tstatus, job_state, any_stopped, any_tstped, call_set_current; - SigHandler *temp_handler; - - child = jobs[job]->pipe; - jobs[job]->flags &= ~J_NOTIFIED; - - call_set_current = 0; - - /* - * COMPUTE JOB STATUS - */ - - /* If all children are not running, but any of them is stopped, then - the job is stopped, not dead. */ - job_state = any_stopped = any_tstped = 0; - do - { - job_state |= PRUNNING (child); -#if 0 - if (PEXITED (child) && (WIFSTOPPED (child->status))) -#else - /* Only checking for WIFSTOPPED now, not for PS_DONE */ - if (PSTOPPED (child)) -#endif - { - any_stopped = 1; - any_tstped |= interactive && job_control && - (WSTOPSIG (child->status) == SIGTSTP); - } - child = child->next; - } - while (child != jobs[job]->pipe); - - /* If job_state != 0, the job is still running, so don't bother with - setting the process exit status and job state unless we're - transitioning from stopped to running. */ - if (job_state != 0 && JOBSTATE(job) != JSTOPPED) - return 0; - - /* - * SET JOB STATUS - */ - - /* The job is either stopped or dead. Set the state of the job accordingly. */ - if (any_stopped) - { - jobs[job]->state = JSTOPPED; - jobs[job]->flags &= ~J_FOREGROUND; - call_set_current++; - /* Suspending a job with SIGTSTP breaks all active loops. */ - if (any_tstped && loop_level) - breaking = loop_level; - } - else if (job_state != 0) /* was stopped, now running */ - { - jobs[job]->state = JRUNNING; - call_set_current++; - } - else - { - jobs[job]->state = JDEAD; - js.j_ndead++; - -#if 0 - if (IS_FOREGROUND (job)) - setjstatus (job); -#endif - - /* If this job has a cleanup function associated with it, call it - with `cleanarg' as the single argument, then set the function - pointer to NULL so it is not inadvertently called twice. The - cleanup function is responsible for deallocating cleanarg. */ - if (jobs[job]->j_cleanup) - { - (*jobs[job]->j_cleanup) (jobs[job]->cleanarg); - jobs[job]->j_cleanup = (sh_vptrfunc_t *)NULL; - } - } - - /* - * CLEANUP - * - * Currently, we just do special things if we got a SIGINT while waiting - * for a foreground job to complete - */ - - if (JOBSTATE (job) == JDEAD) - { - /* If we're running a shell script and we get a SIGINT with a - SIGINT trap handler, but the foreground job handles it and - does not exit due to SIGINT, run the trap handler but do not - otherwise act as if we got the interrupt. */ - if (wait_sigint_received && interactive_shell == 0 && - WIFSIGNALED (child->status) == 0 && IS_FOREGROUND (job) && - signal_is_trapped (SIGINT)) - { - int old_frozen; - wait_sigint_received = 0; - last_command_exit_value = process_exit_status (child->status); - - old_frozen = jobs_list_frozen; - jobs_list_frozen = 1; - tstatus = maybe_call_trap_handler (SIGINT); - jobs_list_frozen = old_frozen; - } - - /* If the foreground job is killed by SIGINT when job control is not - active, we need to perform some special handling. - - The check of wait_sigint_received is a way to determine if the - SIGINT came from the keyboard (in which case the shell has already - seen it, and wait_sigint_received is non-zero, because keyboard - signals are sent to process groups) or via kill(2) to the foreground - process by another process (or itself). If the shell did receive the - SIGINT, it needs to perform normal SIGINT processing. */ - else if (wait_sigint_received && (WTERMSIG (child->status) == SIGINT) && - IS_FOREGROUND (job) && IS_JOBCONTROL (job) == 0) - { - int old_frozen; - - wait_sigint_received = 0; - - /* If SIGINT is trapped, set the exit status so that the trap - handler can see it. */ - if (signal_is_trapped (SIGINT)) - last_command_exit_value = process_exit_status (child->status); - - /* If the signal is trapped, let the trap handler get it no matter - what and simply return if the trap handler returns. - maybe_call_trap_handler() may cause dead jobs to be removed from - the job table because of a call to execute_command. We work - around this by setting JOBS_LIST_FROZEN. */ - old_frozen = jobs_list_frozen; - jobs_list_frozen = 1; - tstatus = maybe_call_trap_handler (SIGINT); - jobs_list_frozen = old_frozen; - if (tstatus == 0 && old_sigint_handler != INVALID_SIGNAL_HANDLER) - { - /* wait_sigint_handler () has already seen SIGINT and - allowed the wait builtin to jump out. We need to - call the original SIGINT handler, if necessary. If - the original handler is SIG_DFL, we need to resend - the signal to ourselves. */ - - temp_handler = old_sigint_handler; - - /* Bogus. If we've reset the signal handler as the result - of a trap caught on SIGINT, then old_sigint_handler - will point to trap_handler, which now knows nothing about - SIGINT (if we reset the sighandler to the default). - In this case, we have to fix things up. What a crock. */ - if (temp_handler == trap_handler && signal_is_trapped (SIGINT) == 0) - temp_handler = trap_to_sighandler (SIGINT); - restore_sigint_handler (); - if (temp_handler == SIG_DFL) - termsig_handler (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 -} - -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; - - set_impossible_sigchld_trap (); - jobs_list_frozen = 1; - for (i = 0; i < nchild; i++) - { - interrupt_immediately = 1; - parse_and_execute (savestring (trap_command), "trap", SEVAL_NOHIST|SEVAL_RESETLINE); - } - - run_unwind_frame ("SIGCHLD trap"); -} - -/* Function to call when you want to notify people of changes - in job status. This prints out all jobs which are pending - notification to stderr, and marks those printed as already - notified, thus making them candidates for cleanup. */ -static void -notify_of_job_status () -{ - register int job, termsig; - char *dir; - sigset_t set, oset; - WAIT s; - - if (jobs == 0 || js.j_jobslots == 0) - return; - - if (old_ttou != 0) - { - sigemptyset (&set); - sigaddset (&set, SIGCHLD); - sigaddset (&set, SIGTTOU); - sigemptyset (&oset); - sigprocmask (SIG_BLOCK, &set, &oset); - } - else - queue_sigchld++; - - /* XXX could use js.j_firstj here */ - for (job = 0, dir = (char *)NULL; job < js.j_jobslots; job++) - { - if (jobs[job] && IS_NOTIFIED (job) == 0) - { - s = raw_job_exit_status (job); - termsig = WTERMSIG (s); - - /* POSIX.2 says we have to hang onto the statuses of at most the - last CHILD_MAX background processes if the shell is running a - script. If the shell is running a script, either from a file - or standard input, don't print anything unless the job was - killed by a signal. */ - if (startup_state == 0 && WIFSIGNALED (s) == 0 && - ((DEADJOB (job) && IS_FOREGROUND (job) == 0) || STOPPED (job))) - continue; - -#if 0 - /* If job control is disabled, don't print the status messages. - Mark dead jobs as notified so that they get cleaned up. If - startup_state == 2, we were started to run `-c command', so - don't print anything. */ - if ((job_control == 0 && interactive_shell) || startup_state == 2) -#else - /* If job control is disabled, don't print the status messages. - Mark dead jobs as notified so that they get cleaned up. If - startup_state == 2 and subshell_environment has the - SUBSHELL_COMSUB bit turned on, we were started to run a command - substitution, so don't print anything. */ - if ((job_control == 0 && interactive_shell) || - (startup_state == 2 && (subshell_environment & SUBSHELL_COMSUB))) -#endif - { - /* POSIX.2 compatibility: if the shell is not interactive, - hang onto the job corresponding to the last asynchronous - pid until the user has been notified of its status or does - a `wait'. */ - if (DEADJOB (job) && (interactive_shell || (find_last_pid (job, 0) != last_asynchronous_pid))) - jobs[job]->flags |= J_NOTIFIED; - continue; - } - - /* Print info on jobs that are running in the background, - and on foreground jobs that were killed by anything - except SIGINT (and possibly SIGPIPE). */ - switch (JOBSTATE (job)) - { - case JDEAD: - if (interactive_shell == 0 && termsig && WIFSIGNALED (s) && - termsig != SIGINT && -#if defined (DONT_REPORT_SIGPIPE) - termsig != SIGPIPE && -#endif - signal_is_trapped (termsig) == 0) - { - /* Don't print `0' for a line number. */ - fprintf (stderr, _("%s: line %d: "), get_name_for_error (), (line_number == 0) ? 1 : line_number); - pretty_print_job (job, JLIST_NONINTERACTIVE, stderr); - } - else if (IS_FOREGROUND (job)) - { -#if !defined (DONT_REPORT_SIGPIPE) - if (termsig && WIFSIGNALED (s) && termsig != SIGINT) -#else - if (termsig && WIFSIGNALED (s) && termsig != SIGINT && termsig != SIGPIPE) -#endif - { - fprintf (stderr, "%s", j_strsignal (termsig)); - - if (WIFCORED (s)) - fprintf (stderr, _(" (core dumped)")); - - fprintf (stderr, "\n"); - } - } - else if (job_control) /* XXX job control test added */ - { - if (dir == 0) - dir = current_working_directory (); - pretty_print_job (job, JLIST_STANDARD, stderr); - if (dir && strcmp (dir, jobs[job]->wd) != 0) - fprintf (stderr, - _("(wd now: %s)\n"), polite_directory_format (dir)); - } - - jobs[job]->flags |= J_NOTIFIED; - break; - - case JSTOPPED: - fprintf (stderr, "\n"); - if (dir == 0) - dir = current_working_directory (); - pretty_print_job (job, JLIST_STANDARD, stderr); - if (dir && (strcmp (dir, jobs[job]->wd) != 0)) - fprintf (stderr, - _("(wd now: %s)\n"), polite_directory_format (dir)); - jobs[job]->flags |= J_NOTIFIED; - break; - - case JRUNNING: - case JMIXED: - break; - - default: - programming_error ("notify_of_job_status"); - } - } - } - if (old_ttou != 0) - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); - else - queue_sigchld--; -} - -/* Initialize the job control mechanism, and set up the tty stuff. */ -int -initialize_job_control (force) - int force; -{ - pid_t t; - int t_errno; - - t_errno = -1; - 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 - { - shell_tty = -1; - - /* If forced_interactive is set, we skip the normal check that stderr - is attached to a tty, so we need to check here. If it's not, we - need to see whether we have a controlling tty by opening /dev/tty, - since trying to use job control tty pgrp manipulations on a non-tty - is going to fail. */ - if (forced_interactive && isatty (fileno (stderr)) == 0) - shell_tty = open ("/dev/tty", O_RDWR|O_NONBLOCK); - - /* 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. */ - if (shell_tty == -1) - 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; - } - - if (terminal_pgrp == -1) - t_errno = errno; - - /* 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) - { - t_errno = errno; - setpgid (0, original_pgrp); - shell_pgrp = original_pgrp; - job_control = 0; - } - } - - if (job_control && ((t = tcgetpgrp (shell_tty)) == -1 || t != shell_pgrp)) - { - if (t_errno != -1) - errno = t_errno; - sys_error (_("cannot set terminal process group (%d)"), t); - job_control = 0; - } - } - if (job_control == 0) - internal_error (_("no job control in this shell")); - } - - if (shell_tty != fileno (stderr)) - SET_CLOSE_ON_EXEC (shell_tty); - - set_signal_handler (SIGCHLD, sigchld_handler); - - change_flag ('m', job_control ? '-' : '+'); - - if (interactive) - get_tty_state (); - - if (js.c_childmax < 0) - js.c_childmax = getmaxchild (); - if (js.c_childmax < 0) - js.c_childmax = DEFAULT_CHILD_MAX; - - return job_control; -} - -#ifdef DEBUG -void -debug_print_pgrps () -{ - itrace("original_pgrp = %ld shell_pgrp = %ld terminal_pgrp = %ld", - (long)original_pgrp, (long)shell_pgrp, (long)terminal_pgrp); - itrace("tcgetpgrp(%d) -> %ld, getpgid(0) -> %ld", - shell_tty, (long)tcgetpgrp (shell_tty), (long)getpgid(0)); -} -#endif - -/* Set the line discipline to the best this system has to offer. - Return -1 if this is not possible. */ -static int -set_new_line_discipline (tty) - int tty; -{ -#if defined (NEW_TTY_DRIVER) - int ldisc; - - if (ioctl (tty, TIOCGETD, &ldisc) < 0) - return (-1); - - if (ldisc != NTTYDISC) - { - ldisc = NTTYDISC; - - if (ioctl (tty, TIOCSETD, &ldisc) < 0) - return (-1); - } - return (0); -#endif /* NEW_TTY_DRIVER */ - -#if defined (TERMIO_TTY_DRIVER) -# if defined (TERMIO_LDISC) && (NTTYDISC) - if (ioctl (tty, TCGETA, &shell_tty_info) < 0) - return (-1); - - if (shell_tty_info.c_line != NTTYDISC) - { - shell_tty_info.c_line = NTTYDISC; - if (ioctl (tty, TCSETAW, &shell_tty_info) < 0) - return (-1); - } -# endif /* TERMIO_LDISC && NTTYDISC */ - return (0); -#endif /* TERMIO_TTY_DRIVER */ - -#if defined (TERMIOS_TTY_DRIVER) -# if defined (TERMIOS_LDISC) && defined (NTTYDISC) - if (tcgetattr (tty, &shell_tty_info) < 0) - return (-1); - - if (shell_tty_info.c_line != NTTYDISC) - { - shell_tty_info.c_line = NTTYDISC; - if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0) - return (-1); - } -# endif /* TERMIOS_LDISC && NTTYDISC */ - return (0); -#endif /* TERMIOS_TTY_DRIVER */ - -#if !defined (NEW_TTY_DRIVER) && !defined (TERMIO_TTY_DRIVER) && !defined (TERMIOS_TTY_DRIVER) - return (-1); -#endif -} - -/* Setup this shell to handle C-C, etc. */ -void -initialize_job_signals () -{ - if (interactive) - { - set_signal_handler (SIGINT, sigint_sighandler); - set_signal_handler (SIGTSTP, SIG_IGN); - set_signal_handler (SIGTTOU, SIG_IGN); - set_signal_handler (SIGTTIN, SIG_IGN); - } - else if (job_control) - { - old_tstp = set_signal_handler (SIGTSTP, sigstop_sighandler); - old_ttin = set_signal_handler (SIGTTIN, sigstop_sighandler); - old_ttou = set_signal_handler (SIGTTOU, sigstop_sighandler); - } - /* Leave these things alone for non-interactive shells without job - control. */ -} - -/* Here we handle CONT signals. */ -static sighandler -sigcont_sighandler (sig) - int sig; -{ - initialize_job_signals (); - set_signal_handler (SIGCONT, old_cont); - kill (getpid (), SIGCONT); - - SIGRETURN (0); -} - -/* Here we handle stop signals while we are running not as a login shell. */ -static sighandler -sigstop_sighandler (sig) - int sig; -{ - set_signal_handler (SIGTSTP, old_tstp); - set_signal_handler (SIGTTOU, old_ttou); - set_signal_handler (SIGTTIN, old_ttin); - - old_cont = set_signal_handler (SIGCONT, sigcont_sighandler); - - give_terminal_to (shell_pgrp, 0); - - kill (getpid (), sig); - - SIGRETURN (0); -} - -/* Give the terminal to PGRP. */ -int -give_terminal_to (pgrp, force) - pid_t pgrp; - int force; -{ - sigset_t set, oset; - int r, e; - - 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; - e = errno; - } - else - terminal_pgrp = pgrp; - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); - } - - if (r == -1) - errno = e; - - return r; -} - -/* Give terminal to NPGRP iff it's currently owned by OPGRP. FLAGS are the - flags to pass to give_terminal_to(). */ -static int -maybe_give_terminal_to (opgrp, npgrp, flags) - pid_t opgrp, npgrp; - int flags; -{ - int tpgrp; - - tpgrp = tcgetpgrp (shell_tty); - if (tpgrp < 0 && errno == ENOTTY) - return -1; - if (tpgrp == npgrp) - { - terminal_pgrp = npgrp; - return 0; - } - else if (tpgrp != opgrp) - { -#if defined (DEBUG) - internal_warning ("maybe_give_terminal_to: terminal pgrp == %d shell pgrp = %d new pgrp = %d", tpgrp, opgrp, npgrp); -#endif - return -1; - } - else - return (give_terminal_to (npgrp, flags)); -} - -/* Clear out any jobs in the job array. This is intended to be used by - children of the shell, who should not have any job structures as baggage - when they start executing (forking subshells for parenthesized execution - and functions with pipes are the two that spring to mind). If RUNNING_ONLY - is nonzero, only running jobs are removed from the table. */ -void -delete_all_jobs (running_only) - int running_only; -{ - register int i; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - - /* XXX - need to set j_lastj, j_firstj appropriately if running_only != 0. */ - if (js.j_jobslots) - { - js.j_current = js.j_previous = NO_JOB; - - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("delete_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) - delete_job (i, DEL_WARNSTOPPED); - } - if (running_only == 0) - { - free ((char *)jobs); - js.j_jobslots = 0; - js.j_firstj = js.j_lastj = js.j_njobs = 0; - } - } - - if (running_only == 0) - bgp_clear (); - - UNBLOCK_CHILD (oset); -} - -/* Mark all jobs in the job array so that they don't get a SIGHUP when the - shell gets one. If RUNNING_ONLY is nonzero, mark only running jobs. */ -void -nohup_all_jobs (running_only) - int running_only; -{ - register int i; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); - - if (js.j_jobslots) - { - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) - nohup_job (i); - } - - UNBLOCK_CHILD (oset); -} - -int -count_all_jobs () -{ - int i, n; - sigset_t set, oset; - - /* This really counts all non-dead jobs. */ - BLOCK_CHILD (set, oset); - /* XXX could use js.j_firstj here */ - for (i = n = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("count_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - if (jobs[i] && DEADJOB(i) == 0) - n++; - } - UNBLOCK_CHILD (oset); - return n; -} - -static void -mark_all_jobs_as_dead () -{ - register int i; - sigset_t set, oset; - - if (js.j_jobslots == 0) - return; - - BLOCK_CHILD (set, oset); - - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - if (jobs[i]) - { - jobs[i]->state = JDEAD; - js.j_ndead++; - } - - UNBLOCK_CHILD (oset); -} - -/* Mark all dead jobs as notified, so delete_job () cleans them out - of the job table properly. POSIX.2 says we need to save the - status of the last CHILD_MAX jobs, so we count the number of dead - jobs and mark only enough as notified to save CHILD_MAX statuses. */ -static void -mark_dead_jobs_as_notified (force) - int force; -{ - register int i, ndead, ndeadproc; - sigset_t set, oset; - - if (js.j_jobslots == 0) - return; - - BLOCK_CHILD (set, oset); - - /* If FORCE is non-zero, we don't have to keep CHILD_MAX statuses - around; just run through the array. */ - if (force) - { - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { - if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid))) - jobs[i]->flags |= J_NOTIFIED; - } - UNBLOCK_CHILD (oset); - return; - } - - /* Mark enough dead jobs as notified to keep CHILD_MAX processes left in the - array with the corresponding not marked as notified. This is a better - way to avoid pid aliasing and reuse problems than keeping the POSIX- - mandated CHILD_MAX jobs around. delete_job() takes care of keeping the - bgpids list regulated. */ - - /* Count the number of dead jobs */ - /* XXX could use js.j_firstj here */ - for (i = ndead = ndeadproc = 0; i < js.j_jobslots; i++) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - if (jobs[i] && DEADJOB (i)) - { - ndead++; - ndeadproc += processes_in_job (i); - } - } - -#ifdef DEBUG - if (ndeadproc != js.c_reaped) - itrace("mark_dead_jobs_as_notified: ndeadproc (%d) != js.c_reaped (%d)", ndeadproc, js.c_reaped); - if (ndead != js.j_ndead) - itrace("mark_dead_jobs_as_notified: ndead (%d) != js.j_ndead (%d)", ndead, js.j_ndead); -#endif - - if (js.c_childmax < 0) - js.c_childmax = getmaxchild (); - if (js.c_childmax < 0) - js.c_childmax = DEFAULT_CHILD_MAX; - - /* Don't do anything if the number of dead processes is less than CHILD_MAX - and we're not forcing a cleanup. */ - if (ndeadproc <= js.c_childmax) - { - UNBLOCK_CHILD (oset); - return; - } - -#if 0 -itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", js.c_childmax, ndead, ndeadproc); -#endif - - /* Mark enough dead jobs as notified that we keep CHILD_MAX jobs in - the list. This isn't exactly right yet; changes need to be made - to stop_pipeline so we don't mark the newer jobs after we've - created CHILD_MAX slots in the jobs array. This needs to be - integrated with a way to keep the jobs array from growing without - bound. Maybe we wrap back around to 0 after we reach some max - limit, and there are sufficient job slots free (keep track of total - size of jobs array (js.j_jobslots) and running count of number of jobs - in jobs array. Then keep a job index corresponding to the `oldest job' - and start this loop there, wrapping around as necessary. In effect, - we turn the list into a circular buffer. */ - /* XXX could use js.j_firstj here */ - for (i = 0; i < js.j_jobslots; i++) - { - if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid))) - { -#if defined (DEBUG) - if (i < js.j_firstj && jobs[i]) - itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); - if (i > js.j_lastj && jobs[i]) - itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); -#endif - /* If marking this job as notified would drop us down below - child_max, don't mark it so we can keep at least child_max - statuses. XXX -- need to check what Posix actually says - about keeping statuses. */ - if ((ndeadproc -= processes_in_job (i)) <= js.c_childmax) - break; - jobs[i]->flags |= J_NOTIFIED; - } - } - - UNBLOCK_CHILD (oset); -} - -/* Here to allow other parts of the shell (like the trap stuff) to - unfreeze the jobs list. */ -void -unfreeze_jobs_list () -{ - jobs_list_frozen = 0; -} - -/* Allow or disallow job control to take place. Returns the old value - of job_control. */ -int -set_job_control (arg) - int arg; -{ - int old; - - old = job_control; - job_control = arg; - - /* If we're turning on job control, reset pipeline_pgrp so make_child will - put new child processes into the right pgrp */ - if (job_control != old && job_control) - pipeline_pgrp = 0; - - return (old); -} - -/* Turn off all traces of job control. This is run by children of the shell - which are going to do shellsy things, like wait (), etc. */ -void -without_job_control () -{ - stop_making_children (); - start_pipeline (); -#if defined (PGRP_PIPE) - sh_closepipe (pgrp_pipe); -#endif - delete_all_jobs (0); - set_job_control (0); -} - -/* If this shell is interactive, terminate all stopped jobs and - restore the original terminal process group. This is done - before the `exec' builtin calls shell_execve. */ -void -end_job_control () -{ - if (interactive_shell) /* XXX - should it be interactive? */ - { - terminate_stopped_jobs (); - - if (original_pgrp >= 0) - give_terminal_to (original_pgrp, 1); - } - - if (original_pgrp >= 0) - setpgid (0, original_pgrp); -} - -/* Restart job control by closing shell tty and reinitializing. This is - called after an exec fails in an interactive shell and we do not exit. */ -void -restart_job_control () -{ - if (shell_tty != -1) - close (shell_tty); - initialize_job_control (0); -} - -/* Set the handler to run when the shell receives a SIGCHLD signal. */ -void -set_sigchld_handler () -{ - set_signal_handler (SIGCHLD, sigchld_handler); -} - -#if defined (PGRP_PIPE) -/* Read from the read end of a pipe. This is how the process group leader - blocks until all of the processes in a pipeline have been made. */ -static void -pipe_read (pp) - int *pp; -{ - char ch; - - if (pp[1] >= 0) - { - close (pp[1]); - pp[1] = -1; - } - - if (pp[0] >= 0) - { - while (read (pp[0], &ch, 1) == -1 && errno == EINTR) - ; - } -} - -/* Functional interface closes our local-to-job-control pipes. */ -void -close_pgrp_pipe () -{ - sh_closepipe (pgrp_pipe); -} - -#endif /* PGRP_PIPE */ diff --git a/jobs.h~ b/jobs.h~ deleted file mode 100644 index c24f1d16a..000000000 --- a/jobs.h~ +++ /dev/null @@ -1,243 +0,0 @@ -/* jobs.h -- structures and definitions used by the jobs.c file. */ - -/* Copyright (C) 1993-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#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 - -/* The max time to sleep while retrying fork() on EAGAIN failure */ -#define FORKSLEEP_MAX 16 - -/* 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 -#define PS_RECYCLED 4 - -/* Each child of the shell is remembered in a STRUCT PROCESS. A circular - chain of such structures is a pipeline. */ -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; - -/* PALIVE really means `not exited' */ -#define PSTOPPED(p) (WIFSTOPPED((p)->status)) -#define PRUNNING(p) ((p)->running == PS_RUNNING) -#define PALIVE(p) (PRUNNING(p) || PSTOPPED(p)) - -#define PEXITED(p) ((p)->running == PS_DONE) -#if defined (RECYCLES_PIDS) -# define PRECYCLED(p) ((p)->running == PS_RECYCLED) -#else -# define PRECYCLED(p) (0) -#endif -#define PDEADPROC(p) (PEXITED(p) || PRECYCLED(p)) - -#define get_job_by_jid(ind) (jobs[(ind)]) - -/* A description of a pipeline's state. */ -typedef enum { JRUNNING = 1, JSTOPPED = 2, JDEAD = 4, JMIXED = 8 } JOB_STATE; -#define JOBSTATE(job) (jobs[(job)]->state) -#define J_JOBSTATE(j) ((j)->state) - -#define STOPPED(j) (jobs[(j)]->state == JSTOPPED) -#define RUNNING(j) (jobs[(j)]->state == JRUNNING) -#define DEADJOB(j) (jobs[(j)]->state == JDEAD) - -#define INVALID_JOB(j) ((j) < 0 || (j) >= js.j_jobslots || get_job_by_jid(j) == 0) - -/* 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 J_STATSAVED 0x10 /* A process in this job had had status saved via $! */ -#define J_ASYNC 0x20 /* Job was started asynchronously */ - -#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) -#define IS_ASYNC(j) ((jobs[j]->flags & J_ASYNC) != 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; - -struct jobstats { - /* limits */ - long c_childmax; - /* child process statistics */ - int c_living; /* running or stopped child processes */ - int c_reaped; /* exited child processes still in jobs list */ - int c_injobs; /* total number of child processes in jobs list */ - /* child process totals */ - int c_totforked; /* total number of children this shell has forked */ - int c_totreaped; /* total number of children this shell has reaped */ - /* job counters and indices */ - int j_jobslots; /* total size of jobs array */ - int j_lastj; /* last (newest) job allocated */ - int j_firstj; /* first (oldest) job allocated */ - int j_njobs; /* number of non-NULL jobs in jobs array */ - int j_ndead; /* number of JDEAD jobs in jobs array */ - /* */ - int j_current; /* current job */ - int j_previous; /* previous job */ - /* */ - JOB *j_lastmade; /* last job allocated by stop_pipeline */ - JOB *j_lastasync; /* last async job allocated by stop_pipeline */ -}; - -struct pidstat { - struct pidstat *next; - pid_t pid; - int status; -}; - -struct bgpids { - struct pidstat *list; - struct pidstat *end; - int npid; -}; - -#define NO_JOB -1 /* An impossible job array index. */ -#define DUP_JOB -2 /* A possible return value for get_job_spec (). */ -#define BAD_JOBSPEC -3 /* Bad syntax for 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 struct jobstats js; - -extern pid_t original_pgrp, shell_pgrp, pipeline_pgrp; -extern pid_t last_made_pid, last_asynchronous_pid; -extern int asynchronous_notification; - -extern JOB **jobs; - -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 run_sigchld_trap __P((int)); - -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)); - -extern void init_job_stats __P((void)); - -extern void close_pgrp_pipe __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 34d017265..000000000 --- a/lib/glob/glob.c~ +++ /dev/null @@ -1,1067 +0,0 @@ -/* glob.c -- file-name wildcard pattern matching for Bash. - - Copyright (C) 1985-2006 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 "shell.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 - -/* Don't try to alloca() more than this much memory for `struct globval' - in glob_vector() */ -#ifndef ALLOCA_MAX -# define ALLOCA_MAX 100000 -#endif - -struct globval - { - struct globval *next; - char *name; - }; - -extern void throw_to_top_level __P((void)); -extern int sh_eaccess __P((char *, int)); -extern char *sh_makepath __P((const char *, const 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; - -static struct globval finddirs_error_return; - -/* Some forward declarations. */ -static int skipname __P((char *, char *, int)); -#if HANDLE_MULTIBYTE -static int mbskipname __P((char *, char *, int)); -#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 ((unsigned char *)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 ((unsigned char *)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, flags) - char *pat; - char *dname; - int flags; -{ - /* 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, flags) - char *pat, *dname; - int flags; -{ - int ret; - wchar_t *pat_wc, *dn_wc; - size_t pat_n, dn_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'; - - /* 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'; - - /* Can't just free wpathname here; wcsrtombs changes it in many cases. */ - 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) (sh_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); -} - -/* Recursively scan SDIR for directories matching PAT (PAT is always `**'). - FLAGS is simply passed down to the recursive call to glob_vector. Returns - a list of matching directory names. EP, if non-null, is set to the last - element of the returned list. NP, if non-null, is set to the number of - directories in the returned list. These two variables exist for the - convenience of the caller (always glob_vector). */ -static struct globval * -finddirs (pat, sdir, flags, ep, np) - char *pat; - char *sdir; - int flags; - struct globval **ep; - int *np; -{ - char **r, *n; - int ndirs; - struct globval *ret, *e, *g; - -/*itrace("finddirs: pat = `%s' sdir = `%s' flags = 0x%x", pat, sdir, flags);*/ - e = ret = 0; - r = glob_vector (pat, sdir, flags); - if (r == 0 || r[0] == 0) - { - if (np) - *np = 0; - if (ep) - *ep = 0; - if (r) - free (r); - return (struct globval *)0; - } - for (ndirs = 0; r[ndirs] != 0; ndirs++) - { - g = (struct globval *) malloc (sizeof (struct globval)); - if (g == 0) - { - while (ret) /* free list built so far */ - { - g = ret->next; - free (ret); - ret = g; - } - - free (r); - if (np) - *np = 0; - if (ep) - *ep = 0; - return (&finddirs_error_return); - } - if (e == 0) - e = g; - - g->next = ret; - ret = g; - - g->name = r[ndirs]; - } - - free (r); - if (ep) - *ep = e; - if (np) - *np = ndirs; - - return ret; -} - - -/* 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; -{ - DIR *d; - register struct dirent *dp; - struct globval *lastlink, *e, *dirlist; - register struct globval *nextlink; - register char *nextname, *npat, *subdir; - unsigned int count; - int lose, skip, ndirs, isdir, sdlen, add_current; - register char **name_vector; - register unsigned int i; - int mflags; /* Flags passed to strmatch (). */ - int pflags; /* flags passed to sh_makepath () */ - int nalloca; - struct globval *firstmalloc, *tmplink; - - lastlink = 0; - count = lose = skip = add_current = 0; - - firstmalloc = 0; - nalloca = 0; - -/*itrace("glob_vector: pat = `%s' dir = `%s' flags = 0x%x", pat, dir, flags);*/ - /* 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; - - add_current = ((flags & (GX_ALLDIRS|GX_ADDCURDIR)) == (GX_ALLDIRS|GX_ADDCURDIR)); - - /* 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 || terminating_signal) - { - 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 0 - if (dp->d_name == 0 || *dp->d_name == 0) - continue; -#endif - -#if HANDLE_MULTIBYTE - if (MB_CUR_MAX > 1 && mbskipname (pat, dp->d_name, flags)) - continue; - else -#endif - if (skipname (pat, dp->d_name, flags)) - continue; - - /* If we're only interested in directories, don't bother with files */ - if (flags & (GX_MATCHDIRS|GX_ALLDIRS)) - { - pflags = (flags & GX_ALLDIRS) ? MP_RMDOT : 0; - if (flags & GX_NULLDIR) - pflags |= MP_IGNDOT; - subdir = sh_makepath (dir, dp->d_name, pflags); - isdir = glob_testdir (subdir); - if (isdir < 0 && (flags & GX_MATCHDIRS)) - { - free (subdir); - continue; - } - } - - if (flags & GX_ALLDIRS) - { - if (isdir == 0) - { - dirlist = finddirs (pat, subdir, (flags & ~GX_ADDCURDIR), &e, &ndirs); - if (dirlist == &finddirs_error_return) - { - free (subdir); - lose = 1; - break; - } - if (ndirs) /* add recursive directories to list */ - { - if (firstmalloc == 0) - firstmalloc = e; - e->next = lastlink; - lastlink = dirlist; - count += ndirs; - } - } - - nextlink = (struct globval *) malloc (sizeof (struct globval)); - if (firstmalloc == 0) - firstmalloc = nextlink; - sdlen = strlen (subdir); - nextname = (char *) malloc (sdlen + 1); - if (nextlink == 0 || nextname == 0) - { - free (subdir); - lose = 1; - break; - } - nextlink->next = lastlink; - lastlink = nextlink; - nextlink->name = nextname; - bcopy (subdir, nextname, sdlen + 1); - free (subdir); - ++count; - continue; - } - - if (strmatch (pat, dp->d_name, mflags) != FNM_NOMATCH) - { - if (nalloca < ALLOCA_MAX) - { - nextlink = (struct globval *) alloca (sizeof (struct globval)); - nalloca += sizeof (struct globval); - } - else - { - nextlink = (struct globval *) malloc (sizeof (struct globval)); - if (firstmalloc == 0) - firstmalloc = nextlink; - } - - nextname = (char *) malloc (D_NAMLEN (dp) + 1); - 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); - } - - /* compat: if GX_ALLDIRS, add the passed directory also */ - if (add_current) - { - sdlen = strlen (dir); - nextname = (char *)malloc (sdlen + 1); - nextlink = (struct globval *) malloc (sizeof (struct globval)); - if (nextlink == 0 || nextname == 0) - lose = 1; - else - { - nextlink->name = nextname; - nextlink->next = lastlink; - lastlink = nextlink; - if (flags & GX_NULLDIR) - nextname[0] = '\0'; - else - bcopy (dir, nextname, sdlen + 1); - ++count; - } - } - - if (lose == 0) - { - name_vector = (char **) malloc ((count + 1) * sizeof (char *)); - lose |= name_vector == NULL; - } - - /* Have we run out of memory? */ - if (lose) - { - tmplink = 0; - - /* Here free the strings we have got. */ - while (lastlink) - { - /* Since we build the list in reverse order, the first N entries - will be allocated with malloc, if firstmalloc is set, from - lastlink to firstmalloc. */ - if (firstmalloc) - { - if (lastlink == firstmalloc) - firstmalloc = 0; - tmplink = lastlink; - } - else - tmplink = 0; - free (lastlink->name); - lastlink = lastlink->next; - FREE (tmplink); - } - - QUIT; - - return ((char **)NULL); - } - - /* Copy the name pointers from the linked list into the vector. */ - for (tmplink = lastlink, i = 0; i < count; ++i) - { - name_vector[i] = tmplink->name; - tmplink = tmplink->next; - } - - name_vector[count] = NULL; - - /* If we allocated some of the struct globvals, free them now. */ - if (firstmalloc) - { - tmplink = 0; - while (lastlink) - { - tmplink = lastlink; - if (lastlink == firstmalloc) - lastlink = firstmalloc = 0; - else - lastlink = lastlink->next; - free (tmplink); - } - } - - 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, *dname; - unsigned int directory_len; - int free_dirname; /* flag */ - int dflags; - - 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; - - dflags = flags & ~GX_MARKDIRS; - if ((flags & GX_GLOBSTAR) && directory_name[0] == '*' && directory_name[1] == '*' && (directory_name[2] == '/' || directory_name[2] == '\0')) - dflags |= GX_ALLDIRS|GX_ADDCURDIR; - - if (directory_name[directory_len - 1] == '/') - directory_name[directory_len - 1] = '\0'; - - directories = glob_filename (directory_name, dflags); - - 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 filename. That way, `*h/' - returns only directories ending in `h', instead of all - files ending in `h' with a `/' appended. */ - dname = directories[i]; - dflags = flags & ~GX_MARKDIRS; - if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0') - dflags |= GX_ALLDIRS|GX_ADDCURDIR; - if (dname[0] == '\0' && filename[0]) - { - dflags |= GX_NULLDIR; - dname = "."; /* treat null directory name and non-null filename as current directory */ - } - temp_results = glob_vector (filename, dname, dflags); - - /* 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. */ - dflags = flags & ~GX_MARKDIRS; - if (directory_len == 0) - dflags |= GX_NULLDIR; - if ((flags & GX_GLOBSTAR) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0') - dflags |= GX_ALLDIRS|GX_ADDCURDIR; - temp_results = glob_vector (filename, - (directory_len == 0 ? "." : directory_name), - dflags); - - if (temp_results == NULL || temp_results == (char **)&glob_error_return) - { - if (free_dirname) - free (directory_name); - return (temp_results); - } - - result = glob_dir_to_array ((dflags & GX_ALLDIRS) ? "" : 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/glob.h~ b/lib/glob/glob.h~ deleted file mode 100644 index 95108a44d..000000000 --- a/lib/glob/glob.h~ +++ /dev/null @@ -1,35 +0,0 @@ -/* File-name wildcard pattern matching for GNU. - Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 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. */ - -#ifndef _GLOB_H_ -#define _GLOB_H_ - -#include "stdc.h" - -#define GX_MARKDIRS 0x01 /* mark directory names with trailing `/' */ -#define GX_NOCASE 0x02 /* ignore case */ -#define GX_MATCHDOT 0x04 /* match `.' literally */ - -extern int glob_pattern_p __P((const char *)); -extern char **glob_vector __P((char *, char *, int)); -extern char **glob_filename __P((char *, int)); - -extern char *glob_error_return; -extern int noglob_dot_filenames; -extern int glob_ignore_case; - -#endif /* _GLOB_H_ */ diff --git a/lib/glob/strmatch.c~ b/lib/glob/strmatch.c~ deleted file mode 100644 index 50878b85d..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 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#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 (HANDLE_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/xmbsrtowcs.c~ b/lib/glob/xmbsrtowcs.c~ deleted file mode 100644 index 036d2531e..000000000 --- a/lib/glob/xmbsrtowcs.c~ +++ /dev/null @@ -1,261 +0,0 @@ -/* xmbsrtowcs.c -- replacement function for mbsrtowcs */ - -/* Copyright (C) 2002-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 - -#include - -/* , and are included in "shmbutil.h". - If , , mbsrtowcs(), exist, HANDLE_MULTIBYTE - is defined as 1. */ -#include - -#if HANDLE_MULTIBYTE - -#ifndef FREE -# define FREE(x) if (x) free (x) -#endif -/* 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; - const char *mbs; - mbstate_t psbuf; - - /* It doesn't matter if malloc fails here, since mbsrtowcs should do - the right thing with a NULL first argument. */ - wsbuf = (wchar_t *) malloc ((n + 1) * sizeof(wchar_t)); - mbs = *src; - psbuf = *ps; - - wclength = mbsrtowcs (wsbuf, &mbs, n, &psbuf); - - if (wsbuf) - free (wsbuf); - 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) - { - if (destp) - *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 = NULL; - if (indicesp) - { - 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; - - if (indicesp) - { - 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; - if (indices) - 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; - - return (wcnum - 1); -} - -#endif /* HANDLE_MULTIBYTE */ diff --git a/lib/intl/Makefile.in.save b/lib/intl/Makefile.in.save deleted file mode 100644 index 8520ed2e3..000000000 --- a/lib/intl/Makefile.in.save +++ /dev/null @@ -1,465 +0,0 @@ -# Makefile for directory with message catalog handling library of GNU gettext -# Copyright (C) 1995-1998, 2000-2003 Free Software Foundation, Inc. -# -# This program 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, 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 -# Library General Public License for more details. -# -# You should have received a copy of the GNU Library 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. - -PACKAGE = @PACKAGE_NAME@ -VERSION = @PACKAGE_VERSION@ - -SHELL = /bin/sh - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -top_builddir = @BUILD_DIR@ -VPATH = $(srcdir) - -prefix = @prefix@ -exec_prefix = @exec_prefix@ -transform = @program_transform_name@ -libdir = @libdir@ -includedir = @includedir@ -datadir = @datadir@ -localedir = $(datadir)/locale -gettextsrcdir = $(datadir)/gettext/intl -aliaspath = $(localedir) -subdir = intl - -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -MKINSTALLDIRS = @MKINSTALLDIRS@ -mkinstalldirs = $(SHELL) $(MKINSTALLDIRS) - -l = @INTL_LIBTOOL_SUFFIX_PREFIX@ - -AR = ar -CC = @CC@ -LIBTOOL = @LIBTOOL@ -RANLIB = @RANLIB@ -YACC = @INTLBISON@ -y -d -YFLAGS = --name-prefix=__gettext - -LOCAL_DEFS = @LOCAL_DEFS@ - -DEFS = -DLOCALEDIR=\"$(localedir)\" -DLOCALE_ALIAS_PATH=\"$(aliaspath)\" \ --DLIBDIR=\"$(prefix)/libdata\" -DIN_LIBINTL \ --DENABLE_RELOCATABLE=1 -DIN_LIBRARY -DINSTALLDIR=\"$(libdir)\" -DNO_XMALLOC \ --Dset_relocation_prefix=libintl_set_relocation_prefix \ --Drelocate=libintl_relocate \ --DDEPENDS_ON_LIBICONV=1 @DEFS@ @LOCAL_DEFS@ -CPPFLAGS = @CPPFLAGS@ -CFLAGS = @CFLAGS@ -LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ - -COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) - -HEADERS = \ - gmo.h \ - gettextP.h \ - hash-string.h \ - loadinfo.h \ - plural-exp.h \ - eval-plural.h \ - localcharset.h \ - relocatable.h \ - os2compat.h \ - libgnuintl.h.in -SOURCES = \ - bindtextdom.c \ - dcgettext.c \ - dgettext.c \ - gettext.c \ - finddomain.c \ - loadmsgcat.c \ - localealias.c \ - textdomain.c \ - l10nflist.c \ - explodename.c \ - dcigettext.c \ - dcngettext.c \ - dngettext.c \ - ngettext.c \ - plural.y \ - plural-exp.c \ - localcharset.c \ - relocatable.c \ - localename.c \ - log.c \ - osdep.c \ - os2compat.c \ - intl-compat.c -OBJECTS = \ - bindtextdom.$lo \ - dcgettext.$lo \ - dgettext.$lo \ - gettext.$lo \ - finddomain.$lo \ - loadmsgcat.$lo \ - localealias.$lo \ - textdomain.$lo \ - l10nflist.$lo \ - explodename.$lo \ - dcigettext.$lo \ - dcngettext.$lo \ - dngettext.$lo \ - ngettext.$lo \ - plural.$lo \ - plural-exp.$lo \ - localcharset.$lo \ - relocatable.$lo \ - localename.$lo \ - log.$lo \ - osdep.$lo \ - intl-compat.$lo -DISTFILES.common = Makefile.in \ -config.charset locale.alias ref-add.sin ref-del.sin $(HEADERS) $(SOURCES) -DISTFILES.generated = plural.c -DISTFILES.normal = VERSION -DISTFILES.gettext = COPYING.LIB-2.0 COPYING.LIB-2.1 libintl.glibc \ -Makefile.vms libgnuintl.h.msvc-shared README.woe32 Makefile.msvc -DISTFILES.obsolete = xopen-msg.sed linux-msg.sed po2tbl.sed.in cat-compat.c \ -COPYING.LIB-2 gettext.h libgettext.h plural-eval.c libgnuintl.h - -all: all-@USE_INCLUDED_LIBINTL@ -all-yes: libintl.$la libintl.h charset.alias ref-add.sed ref-del.sed -all-no: all-no-@BUILD_INCLUDED_LIBINTL@ -all-no-yes: libgnuintl.$la -all-no-no: - -libintl.a libgnuintl.a: $(OBJECTS) - rm -f $@ - $(AR) cru $@ $(OBJECTS) - $(RANLIB) $@ - -libintl.la libgnuintl.la: $(OBJECTS) - $(LIBTOOL) --mode=link \ - $(CC) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ \ - $(OBJECTS) @LTLIBICONV@ $(LIBS) \ - -version-info $(LTV_CURRENT):$(LTV_REVISION):$(LTV_AGE) \ - -rpath $(libdir) \ - -no-undefined - -# Libtool's library version information for libintl. -# Before making a gettext release, the gettext maintainer must change this -# according to the libtool documentation, section "Library interface versions". -# Maintainers of other packages that include the intl directory must *not* -# change these values. -LTV_CURRENT=5 -LTV_REVISION=0 -LTV_AGE=3 - -.SUFFIXES: -.SUFFIXES: .c .y .o .lo .sin .sed - -.c.o: - $(COMPILE) $< - -.y.c: - $(YACC) $(YFLAGS) --output $@ $< - rm -f $*.h - -bindtextdom.lo: $(srcdir)/bindtextdom.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/bindtextdom.c -dcgettext.lo: $(srcdir)/dcgettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcgettext.c -dgettext.lo: $(srcdir)/dgettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dgettext.c -gettext.lo: $(srcdir)/gettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/gettext.c -finddomain.lo: $(srcdir)/finddomain.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/finddomain.c -loadmsgcat.lo: $(srcdir)/loadmsgcat.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/loadmsgcat.c -localealias.lo: $(srcdir)/localealias.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localealias.c -textdomain.lo: $(srcdir)/textdomain.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/textdomain.c -l10nflist.lo: $(srcdir)/l10nflist.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/l10nflist.c -explodename.lo: $(srcdir)/explodename.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/explodename.c -dcigettext.lo: $(srcdir)/dcigettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcigettext.c -dcngettext.lo: $(srcdir)/dcngettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcngettext.c -dngettext.lo: $(srcdir)/dngettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dngettext.c -ngettext.lo: $(srcdir)/ngettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/ngettext.c -plural.lo: $(srcdir)/plural.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/plural.c -plural-exp.lo: $(srcdir)/plural-exp.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/plural-exp.c -localcharset.lo: $(srcdir)/localcharset.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localcharset.c -relocatable.lo: $(srcdir)/relocatable.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/relocatable.c -localename.lo: $(srcdir)/localename.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localename.c -log.lo: $(srcdir)/log.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/log.c -osdep.lo: $(srcdir)/osdep.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/osdep.c -intl-compat.lo: $(srcdir)/intl-compat.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/intl-compat.c - -ref-add.sed: $(srcdir)/ref-add.sin - sed -e '/^#/d' -e 's/@''PACKAGE''@/@PACKAGE@/g' $(srcdir)/ref-add.sin > t-ref-add.sed - mv t-ref-add.sed ref-add.sed -ref-del.sed: $(srcdir)/ref-del.sin - sed -e '/^#/d' -e 's/@''PACKAGE''@/@PACKAGE@/g' $(srcdir)/ref-del.sin > t-ref-del.sed - mv t-ref-del.sed ref-del.sed - -INCLUDES = -I. -I$(srcdir) -I${top_builddir} -I${top_srcdir} - -libgnuintl.h: $(srcdir)/libgnuintl.h.in - cp $(srcdir)/libgnuintl.h.in libgnuintl.h - -libintl.h: libgnuintl.h - cp libgnuintl.h libintl.h - -charset.alias: $(srcdir)/config.charset - $(SHELL) $(srcdir)/config.charset '@host@' > t-$@ - mv t-$@ $@ - -check: all - -# We must not install the libintl.h/libintl.a files if we are on a -# system which has the GNU gettext() function in its C library or in a -# separate library. -# If you want to use the one which comes with this version of the -# package, you have to use `configure --with-included-gettext'. -install: install-exec install-data -install-exec: all - if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \ - && test '@USE_INCLUDED_LIBINTL@' = yes; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ - $(INSTALL_DATA) libintl.h $(DESTDIR)$(includedir)/libintl.h; \ - $(LIBTOOL) --mode=install \ - $(INSTALL_DATA) libintl.$la $(DESTDIR)$(libdir)/libintl.$la; \ - if test "@RELOCATABLE@" = yes; then \ - dependencies=`sed -n -e 's,^dependency_libs=\(.*\),\1,p' < $(DESTDIR)$(libdir)/libintl.la | sed -e "s,^',," -e "s,'\$$,,"`; \ - if test -n "$dependencies"; then \ - rm -f $(DESTDIR)$(libdir)/libintl.la; \ - fi; \ - fi; \ - else \ - : ; \ - fi - if test "$(PACKAGE)" = "gettext-tools" \ - && test '@USE_INCLUDED_LIBINTL@' = no; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir); \ - $(LIBTOOL) --mode=install \ - $(INSTALL_DATA) libgnuintl.$la $(DESTDIR)$(libdir)/libgnuintl.$la; \ - rm -f $(DESTDIR)$(libdir)/preloadable_libintl.so; \ - $(INSTALL_DATA) $(DESTDIR)$(libdir)/libgnuintl.so $(DESTDIR)$(libdir)/preloadable_libintl.so; \ - $(LIBTOOL) --mode=uninstall \ - rm -f $(DESTDIR)$(libdir)/libgnuintl.$la; \ - else \ - : ; \ - fi - if test '@USE_INCLUDED_LIBINTL@' = yes; then \ - $(mkinstalldirs) $(DESTDIR)$(localedir); \ - test -f $(DESTDIR)$(localedir)/locale.alias \ - && orig=$(DESTDIR)$(localedir)/locale.alias \ - || orig=$(srcdir)/locale.alias; \ - temp=$(DESTDIR)$(localedir)/t-locale.alias; \ - dest=$(DESTDIR)$(localedir)/locale.alias; \ - sed -f ref-add.sed $$orig > $$temp; \ - $(INSTALL_DATA) $$temp $$dest; \ - rm -f $$temp; \ - else \ - : ; \ - fi -install-data: all - if test "$(PACKAGE)" = "gettext-tools"; then \ - $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ - $(INSTALL_DATA) VERSION $(DESTDIR)$(gettextsrcdir)/VERSION; \ - $(INSTALL_DATA) ChangeLog.inst $(DESTDIR)$(gettextsrcdir)/ChangeLog; \ - dists="COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common)"; \ - for file in $$dists; do \ - $(INSTALL_DATA) $(srcdir)/$$file \ - $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - chmod a+x $(DESTDIR)$(gettextsrcdir)/config.charset; \ - dists="$(DISTFILES.generated)"; \ - for file in $$dists; do \ - if test -f $$file; then dir=.; else dir=$(srcdir); fi; \ - $(INSTALL_DATA) $$dir/$$file \ - $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - dists="$(DISTFILES.obsolete)"; \ - for file in $$dists; do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi - -install-strip: install - -installdirs: - if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \ - && test '@USE_INCLUDED_LIBINTL@' = yes; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ - else \ - : ; \ - fi - if test "$(PACKAGE)" = "gettext-tools" \ - && test '@USE_INCLUDED_LIBINTL@' = no; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir); \ - else \ - : ; \ - fi - if test '@USE_INCLUDED_LIBINTL@' = yes; then \ - test @GLIBC21@ != no || $(mkinstalldirs) $(DESTDIR)$(libdir); \ - $(mkinstalldirs) $(DESTDIR)$(localedir); \ - else \ - : ; \ - fi - if test "$(PACKAGE)" = "gettext-tools"; then \ - $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ - else \ - : ; \ - fi - -# Define this as empty until I found a useful application. -installcheck: - -uninstall: - if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \ - && test '@USE_INCLUDED_LIBINTL@' = yes; then \ - rm -f $(DESTDIR)$(includedir)/libintl.h; \ - $(LIBTOOL) --mode=uninstall \ - rm -f $(DESTDIR)$(libdir)/libintl.$la; \ - else \ - : ; \ - fi - if test "$(PACKAGE)" = "gettext-tools" \ - && test '@USE_INCLUDED_LIBINTL@' = no; then \ - rm -f $(DESTDIR)$(libdir)/preloadable_libintl.so; \ - else \ - : ; \ - fi - if test '@USE_INCLUDED_LIBINTL@' = yes; then \ - if test -f $(DESTDIR)$(prefix)/libdata/charset.alias; then \ - temp=$(DESTDIR)$(prefix)/libdata/t-charset.alias; \ - dest=$(DESTDIR)$(prefix)/libdata/charset.alias; \ - sed -f ref-del.sed $$dest > $$temp; \ - if grep '^# Packages using this file: $$' $$temp > /dev/null; then \ - rm -f $$dest; \ - else \ - $(INSTALL_DATA) $$temp $$dest; \ - fi; \ - rm -f $$temp; \ - fi; \ - if test -f $(DESTDIR)$(localedir)/locale.alias; then \ - temp=$(DESTDIR)$(localedir)/t-locale.alias; \ - dest=$(DESTDIR)$(localedir)/locale.alias; \ - sed -f ref-del.sed $$dest > $$temp; \ - if grep '^# Packages using this file: $$' $$temp > /dev/null; then \ - rm -f $$dest; \ - else \ - $(INSTALL_DATA) $$temp $$dest; \ - fi; \ - rm -f $$temp; \ - fi; \ - else \ - : ; \ - fi - if test "$(PACKAGE)" = "gettext-tools"; then \ - for file in VERSION ChangeLog COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common) $(DISTFILES.generated); do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi - -info dvi ps pdf html: - -$(OBJECTS): ${top_builddir}/config.h libgnuintl.h -bindtextdom.$lo dcgettext.$lo dcigettext.$lo dcngettext.$lo dgettext.$lo dngettext.$lo finddomain.$lo gettext.$lo intl-compat.$lo loadmsgcat.$lo localealias.$lo ngettext.$lo textdomain.$lo: $(srcdir)/gettextP.h $(srcdir)/gmo.h $(srcdir)/loadinfo.h -dcigettext.$lo loadmsgcat.$lo: $(srcdir)/hash-string.h -explodename.$lo l10nflist.$lo: $(srcdir)/loadinfo.h -dcigettext.$lo loadmsgcat.$lo plural.$lo plural-exp.$lo: $(srcdir)/plural-exp.h -dcigettext.$lo: $(srcdir)/eval-plural.h -localcharset.$lo: $(srcdir)/localcharset.h -localealias.$lo localcharset.$lo relocatable.$lo: $(srcdir)/relocatable.h - -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) - here=`pwd`; cd $(srcdir) && etags -o $$here/TAGS $(HEADERS) $(SOURCES) - -ctags: CTAGS - -CTAGS: $(HEADERS) $(SOURCES) - here=`pwd`; cd $(srcdir) && ctags -o $$here/CTAGS $(HEADERS) $(SOURCES) - -id: ID - -ID: $(HEADERS) $(SOURCES) - here=`pwd`; cd $(srcdir) && mkid -f$$here/ID $(HEADERS) $(SOURCES) - - -mostlyclean: - rm -f *.a *.la *.o *.obj *.lo core core.* - rm -f libgnuintl.h libintl.h charset.alias ref-add.sed ref-del.sed - rm -f -r .libs _libs - -clean: mostlyclean - -distclean: clean - rm -f Makefile ID TAGS - if test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; then \ - rm -f ChangeLog.inst $(DISTFILES.normal); \ - else \ - : ; \ - fi - -maintainer-clean: distclean - @echo "This command is intended for maintainers to use;" - @echo "it deletes files that may require special tools to rebuild." - - -# GNU gettext needs not contain the file `VERSION' but contains some -# other files which should not be distributed in other packages. -distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) -dist distdir: Makefile - if test "$(PACKAGE)" = "gettext-tools"; then \ - : ; \ - else \ - if test "$(PACKAGE)" = "gettext-runtime"; then \ - additional="$(DISTFILES.gettext)"; \ - else \ - additional="$(DISTFILES.normal)"; \ - fi; \ - $(MAKE) $(DISTFILES.common) $(DISTFILES.generated) $$additional; \ - for file in ChangeLog $(DISTFILES.common) $(DISTFILES.generated) $$additional; do \ - if test -f $$file; then dir=.; else dir=$(srcdir); fi; \ - cp -p $$dir/$$file $(distdir); \ - done; \ - fi - -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - cd $(top_builddir) && $(SHELL) ./config.status -# This would be more efficient, but doesn't work any more with autoconf-2.57, -# when AC_CONFIG_FILES([intl/Makefile:somedir/Makefile.in]) is used. -# cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status - -# Tell versions [3.59,3.63) of GNU make not to export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/lib/intl/Makefile.in~ b/lib/intl/Makefile.in~ deleted file mode 100644 index 6bcb034fe..000000000 --- a/lib/intl/Makefile.in~ +++ /dev/null @@ -1,468 +0,0 @@ -# Makefile for directory with message catalog handling library of GNU gettext -# Copyright (C) 1995-1998, 2000-2003 Free Software Foundation, Inc. -# -# This program 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, 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 -# Library General Public License for more details. -# -# You should have received a copy of the GNU Library 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. - -PACKAGE = @PACKAGE_NAME@ -VERSION = @PACKAGE_VERSION@ - -SHELL = /bin/sh - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -top_builddir = @BUILD_DIR@ -VPATH = $(srcdir) - -prefix = @prefix@ -exec_prefix = @exec_prefix@ -transform = @program_transform_name@ - -datarootdir = @datarootdir@ - -libdir = @libdir@ -includedir = @includedir@ -datadir = @datadir@ -localedir = $(datadir)/locale -gettextsrcdir = $(datadir)/gettext/intl -aliaspath = $(localedir) -subdir = intl - -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -MKINSTALLDIRS = @MKINSTALLDIRS@ -mkinstalldirs = $(SHELL) $(MKINSTALLDIRS) - -l = @INTL_LIBTOOL_SUFFIX_PREFIX@ - -AR = ar -CC = @CC@ -LIBTOOL = @LIBTOOL@ -RANLIB = @RANLIB@ -YACC = @INTLBISON@ -y -d -YFLAGS = --name-prefix=__gettext - -LOCAL_DEFS = @LOCAL_DEFS@ - -DEFS = -DLOCALEDIR=\"$(localedir)\" -DLOCALE_ALIAS_PATH=\"$(aliaspath)\" \ --DLIBDIR=\"$(prefix)/libdata\" -DIN_LIBINTL \ --DENABLE_RELOCATABLE=1 -DIN_LIBRARY -DINSTALLDIR=\"$(libdir)\" -DNO_XMALLOC \ --Dset_relocation_prefix=libintl_set_relocation_prefix \ --Drelocate=libintl_relocate \ --DDEPENDS_ON_LIBICONV=1 @DEFS@ ${LOCAL_DEFS} -CPPFLAGS = @CPPFLAGS@ -CFLAGS = @CFLAGS@ -LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ - -COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) - -HEADERS = \ - gmo.h \ - gettextP.h \ - hash-string.h \ - loadinfo.h \ - plural-exp.h \ - eval-plural.h \ - localcharset.h \ - relocatable.h \ - os2compat.h \ - libgnuintl.h.in -SOURCES = \ - bindtextdom.c \ - dcgettext.c \ - dgettext.c \ - gettext.c \ - finddomain.c \ - loadmsgcat.c \ - localealias.c \ - textdomain.c \ - l10nflist.c \ - explodename.c \ - dcigettext.c \ - dcngettext.c \ - dngettext.c \ - ngettext.c \ - plural.y \ - plural-exp.c \ - localcharset.c \ - relocatable.c \ - localename.c \ - log.c \ - osdep.c \ - os2compat.c \ - intl-compat.c -OBJECTS = \ - bindtextdom.$lo \ - dcgettext.$lo \ - dgettext.$lo \ - gettext.$lo \ - finddomain.$lo \ - loadmsgcat.$lo \ - localealias.$lo \ - textdomain.$lo \ - l10nflist.$lo \ - explodename.$lo \ - dcigettext.$lo \ - dcngettext.$lo \ - dngettext.$lo \ - ngettext.$lo \ - plural.$lo \ - plural-exp.$lo \ - localcharset.$lo \ - relocatable.$lo \ - localename.$lo \ - log.$lo \ - osdep.$lo \ - intl-compat.$lo -DISTFILES.common = Makefile.in \ -config.charset locale.alias ref-add.sin ref-del.sin $(HEADERS) $(SOURCES) -DISTFILES.generated = plural.c -DISTFILES.normal = VERSION -DISTFILES.gettext = COPYING.LIB-2.0 COPYING.LIB-2.1 libintl.glibc \ -Makefile.vms libgnuintl.h.msvc-shared README.woe32 Makefile.msvc -DISTFILES.obsolete = xopen-msg.sed linux-msg.sed po2tbl.sed.in cat-compat.c \ -COPYING.LIB-2 gettext.h libgettext.h plural-eval.c libgnuintl.h - -all: all-@USE_INCLUDED_LIBINTL@ -all-yes: libintl.$la libintl.h charset.alias ref-add.sed ref-del.sed -all-no: all-no-@BUILD_INCLUDED_LIBINTL@ -all-no-yes: libgnuintl.$la -all-no-no: - -libintl.a libgnuintl.a: $(OBJECTS) - rm -f $@ - $(AR) cru $@ $(OBJECTS) - $(RANLIB) $@ - -libintl.la libgnuintl.la: $(OBJECTS) - $(LIBTOOL) --mode=link \ - $(CC) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ \ - $(OBJECTS) @LTLIBICONV@ $(LIBS) \ - -version-info $(LTV_CURRENT):$(LTV_REVISION):$(LTV_AGE) \ - -rpath $(libdir) \ - -no-undefined - -# Libtool's library version information for libintl. -# Before making a gettext release, the gettext maintainer must change this -# according to the libtool documentation, section "Library interface versions". -# Maintainers of other packages that include the intl directory must *not* -# change these values. -LTV_CURRENT=5 -LTV_REVISION=0 -LTV_AGE=3 - -.SUFFIXES: -.SUFFIXES: .c .y .o .lo .sin .sed - -.c.o: - $(COMPILE) $< - -.y.c: - $(YACC) $(YFLAGS) --output $@ $< - rm -f $*.h - -bindtextdom.lo: $(srcdir)/bindtextdom.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/bindtextdom.c -dcgettext.lo: $(srcdir)/dcgettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcgettext.c -dgettext.lo: $(srcdir)/dgettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dgettext.c -gettext.lo: $(srcdir)/gettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/gettext.c -finddomain.lo: $(srcdir)/finddomain.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/finddomain.c -loadmsgcat.lo: $(srcdir)/loadmsgcat.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/loadmsgcat.c -localealias.lo: $(srcdir)/localealias.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localealias.c -textdomain.lo: $(srcdir)/textdomain.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/textdomain.c -l10nflist.lo: $(srcdir)/l10nflist.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/l10nflist.c -explodename.lo: $(srcdir)/explodename.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/explodename.c -dcigettext.lo: $(srcdir)/dcigettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcigettext.c -dcngettext.lo: $(srcdir)/dcngettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcngettext.c -dngettext.lo: $(srcdir)/dngettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dngettext.c -ngettext.lo: $(srcdir)/ngettext.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/ngettext.c -plural.lo: $(srcdir)/plural.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/plural.c -plural-exp.lo: $(srcdir)/plural-exp.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/plural-exp.c -localcharset.lo: $(srcdir)/localcharset.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localcharset.c -relocatable.lo: $(srcdir)/relocatable.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/relocatable.c -localename.lo: $(srcdir)/localename.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localename.c -log.lo: $(srcdir)/log.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/log.c -osdep.lo: $(srcdir)/osdep.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/osdep.c -intl-compat.lo: $(srcdir)/intl-compat.c - $(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/intl-compat.c - -ref-add.sed: $(srcdir)/ref-add.sin - sed -e '/^#/d' -e 's/@''PACKAGE''@/@PACKAGE@/g' $(srcdir)/ref-add.sin > t-ref-add.sed - mv t-ref-add.sed ref-add.sed -ref-del.sed: $(srcdir)/ref-del.sin - sed -e '/^#/d' -e 's/@''PACKAGE''@/@PACKAGE@/g' $(srcdir)/ref-del.sin > t-ref-del.sed - mv t-ref-del.sed ref-del.sed - -INCLUDES = -I. -I$(srcdir) -I${top_builddir} -I${top_srcdir} - -libgnuintl.h: $(srcdir)/libgnuintl.h.in - cp $(srcdir)/libgnuintl.h.in libgnuintl.h - -libintl.h: libgnuintl.h - cmp libgnuintl.h libintl.h || cp libgnuintl.h libintl.h - -charset.alias: $(srcdir)/config.charset - $(SHELL) $(srcdir)/config.charset '@host@' > t-$@ - mv t-$@ $@ - -check: all - -# We must not install the libintl.h/libintl.a files if we are on a -# system which has the GNU gettext() function in its C library or in a -# separate library. -# If you want to use the one which comes with this version of the -# package, you have to use `configure --with-included-gettext'. -install: install-exec install-data -install-exec: all - if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \ - && test '@USE_INCLUDED_LIBINTL@' = yes; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ - $(INSTALL_DATA) libintl.h $(DESTDIR)$(includedir)/libintl.h; \ - $(LIBTOOL) --mode=install \ - $(INSTALL_DATA) libintl.$la $(DESTDIR)$(libdir)/libintl.$la; \ - if test "@RELOCATABLE@" = yes; then \ - dependencies=`sed -n -e 's,^dependency_libs=\(.*\),\1,p' < $(DESTDIR)$(libdir)/libintl.la | sed -e "s,^',," -e "s,'\$$,,"`; \ - if test -n "$dependencies"; then \ - rm -f $(DESTDIR)$(libdir)/libintl.la; \ - fi; \ - fi; \ - else \ - : ; \ - fi - if test "$(PACKAGE)" = "gettext-tools" \ - && test '@USE_INCLUDED_LIBINTL@' = no; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir); \ - $(LIBTOOL) --mode=install \ - $(INSTALL_DATA) libgnuintl.$la $(DESTDIR)$(libdir)/libgnuintl.$la; \ - rm -f $(DESTDIR)$(libdir)/preloadable_libintl.so; \ - $(INSTALL_DATA) $(DESTDIR)$(libdir)/libgnuintl.so $(DESTDIR)$(libdir)/preloadable_libintl.so; \ - $(LIBTOOL) --mode=uninstall \ - rm -f $(DESTDIR)$(libdir)/libgnuintl.$la; \ - else \ - : ; \ - fi - if test '@USE_INCLUDED_LIBINTL@' = yes; then \ - $(mkinstalldirs) $(DESTDIR)$(localedir); \ - test -f $(DESTDIR)$(localedir)/locale.alias \ - && orig=$(DESTDIR)$(localedir)/locale.alias \ - || orig=$(srcdir)/locale.alias; \ - temp=$(DESTDIR)$(localedir)/t-locale.alias; \ - dest=$(DESTDIR)$(localedir)/locale.alias; \ - sed -f ref-add.sed $$orig > $$temp; \ - $(INSTALL_DATA) $$temp $$dest; \ - rm -f $$temp; \ - else \ - : ; \ - fi -install-data: all - if test "$(PACKAGE)" = "gettext-tools"; then \ - $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ - $(INSTALL_DATA) VERSION $(DESTDIR)$(gettextsrcdir)/VERSION; \ - $(INSTALL_DATA) ChangeLog.inst $(DESTDIR)$(gettextsrcdir)/ChangeLog; \ - dists="COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common)"; \ - for file in $$dists; do \ - $(INSTALL_DATA) $(srcdir)/$$file \ - $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - chmod a+x $(DESTDIR)$(gettextsrcdir)/config.charset; \ - dists="$(DISTFILES.generated)"; \ - for file in $$dists; do \ - if test -f $$file; then dir=.; else dir=$(srcdir); fi; \ - $(INSTALL_DATA) $$dir/$$file \ - $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - dists="$(DISTFILES.obsolete)"; \ - for file in $$dists; do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi - -install-strip: install - -installdirs: - if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \ - && test '@USE_INCLUDED_LIBINTL@' = yes; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \ - else \ - : ; \ - fi - if test "$(PACKAGE)" = "gettext-tools" \ - && test '@USE_INCLUDED_LIBINTL@' = no; then \ - $(mkinstalldirs) $(DESTDIR)$(libdir); \ - else \ - : ; \ - fi - if test '@USE_INCLUDED_LIBINTL@' = yes; then \ - test @GLIBC21@ != no || $(mkinstalldirs) $(DESTDIR)$(libdir); \ - $(mkinstalldirs) $(DESTDIR)$(localedir); \ - else \ - : ; \ - fi - if test "$(PACKAGE)" = "gettext-tools"; then \ - $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ - else \ - : ; \ - fi - -# Define this as empty until I found a useful application. -installcheck: - -uninstall: - if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \ - && test '@USE_INCLUDED_LIBINTL@' = yes; then \ - rm -f $(DESTDIR)$(includedir)/libintl.h; \ - $(LIBTOOL) --mode=uninstall \ - rm -f $(DESTDIR)$(libdir)/libintl.$la; \ - else \ - : ; \ - fi - if test "$(PACKAGE)" = "gettext-tools" \ - && test '@USE_INCLUDED_LIBINTL@' = no; then \ - rm -f $(DESTDIR)$(libdir)/preloadable_libintl.so; \ - else \ - : ; \ - fi - if test '@USE_INCLUDED_LIBINTL@' = yes; then \ - if test -f $(DESTDIR)$(prefix)/libdata/charset.alias; then \ - temp=$(DESTDIR)$(prefix)/libdata/t-charset.alias; \ - dest=$(DESTDIR)$(prefix)/libdata/charset.alias; \ - sed -f ref-del.sed $$dest > $$temp; \ - if grep '^# Packages using this file: $$' $$temp > /dev/null; then \ - rm -f $$dest; \ - else \ - $(INSTALL_DATA) $$temp $$dest; \ - fi; \ - rm -f $$temp; \ - fi; \ - if test -f $(DESTDIR)$(localedir)/locale.alias; then \ - temp=$(DESTDIR)$(localedir)/t-locale.alias; \ - dest=$(DESTDIR)$(localedir)/locale.alias; \ - sed -f ref-del.sed $$dest > $$temp; \ - if grep '^# Packages using this file: $$' $$temp > /dev/null; then \ - rm -f $$dest; \ - else \ - $(INSTALL_DATA) $$temp $$dest; \ - fi; \ - rm -f $$temp; \ - fi; \ - else \ - : ; \ - fi - if test "$(PACKAGE)" = "gettext-tools"; then \ - for file in VERSION ChangeLog COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common) $(DISTFILES.generated); do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi - -info dvi ps pdf html: - -$(OBJECTS): ${top_builddir}/config.h libgnuintl.h -bindtextdom.$lo dcgettext.$lo dcigettext.$lo dcngettext.$lo dgettext.$lo dngettext.$lo finddomain.$lo gettext.$lo intl-compat.$lo loadmsgcat.$lo localealias.$lo ngettext.$lo textdomain.$lo: $(srcdir)/gettextP.h $(srcdir)/gmo.h $(srcdir)/loadinfo.h -dcigettext.$lo loadmsgcat.$lo: $(srcdir)/hash-string.h -explodename.$lo l10nflist.$lo: $(srcdir)/loadinfo.h -dcigettext.$lo loadmsgcat.$lo plural.$lo plural-exp.$lo: $(srcdir)/plural-exp.h -dcigettext.$lo: $(srcdir)/eval-plural.h -localcharset.$lo: $(srcdir)/localcharset.h -localealias.$lo localcharset.$lo relocatable.$lo: $(srcdir)/relocatable.h - -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) - here=`pwd`; cd $(srcdir) && etags -o $$here/TAGS $(HEADERS) $(SOURCES) - -ctags: CTAGS - -CTAGS: $(HEADERS) $(SOURCES) - here=`pwd`; cd $(srcdir) && ctags -o $$here/CTAGS $(HEADERS) $(SOURCES) - -id: ID - -ID: $(HEADERS) $(SOURCES) - here=`pwd`; cd $(srcdir) && mkid -f$$here/ID $(HEADERS) $(SOURCES) - - -mostlyclean: - rm -f *.a *.la *.o *.obj *.lo core core.* - rm -f libgnuintl.h libintl.h charset.alias ref-add.sed ref-del.sed - rm -f -r .libs _libs - -clean: mostlyclean - -distclean: clean - rm -f Makefile ID TAGS - if test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; then \ - rm -f ChangeLog.inst $(DISTFILES.normal); \ - else \ - : ; \ - fi - -maintainer-clean: distclean - @echo "This command is intended for maintainers to use;" - @echo "it deletes files that may require special tools to rebuild." - - -# GNU gettext needs not contain the file `VERSION' but contains some -# other files which should not be distributed in other packages. -distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) -dist distdir: Makefile - if test "$(PACKAGE)" = "gettext-tools"; then \ - : ; \ - else \ - if test "$(PACKAGE)" = "gettext-runtime"; then \ - additional="$(DISTFILES.gettext)"; \ - else \ - additional="$(DISTFILES.normal)"; \ - fi; \ - $(MAKE) $(DISTFILES.common) $(DISTFILES.generated) $$additional; \ - for file in ChangeLog $(DISTFILES.common) $(DISTFILES.generated) $$additional; do \ - if test -f $$file; then dir=.; else dir=$(srcdir); fi; \ - cp -p $$dir/$$file $(distdir); \ - done; \ - fi - -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - cd $(top_builddir) && $(SHELL) ./config.status -# This would be more efficient, but doesn't work any more with autoconf-2.57, -# when AC_CONFIG_FILES([intl/Makefile:somedir/Makefile.in]) is used. -# cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status - -# Tell versions [3.59,3.63) of GNU make not to export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/lib/malloc/malloc.c~ b/lib/malloc/malloc.c~ deleted file mode 100644 index 7953d5597..000000000 --- a/lib/malloc/malloc.c~ +++ /dev/null @@ -1,1305 +0,0 @@ -/* malloc.c - dynamic memory allocation for bash. */ - -/* Copyright (C) 1985-2005 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 */ - -typedef union _malloc_guard { - char s[4]; - u_bits32_t i; -} mguard_t; - -/* 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 or free 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, 4294967295UL -}; - -/* 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((size_t, 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) - const char *s; - const char *file; - int 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. - BUSY[NU] must be set to 1. */ -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 || busy[nbuck]) - return; - - busy[nbuck] = 1; - 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) - { - busy[nbuck] = 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) - { - busy[nbuck] = 0; - xbotch ((PTR_T)0, 0, "bcoalesce: CHAIN(mp2) != mp1", (char *)NULL, 0); - } - -#ifdef MALLOC_DEBUG - if (CHAIN (mp1) != (union mhead *)((char *)mp1 + siz)) - { - busy[nbuck] = 0; - return; /* not adjacent */ - } -#endif - - /* Since they are adjacent, remove them from the free list */ - if (mp1 == nextf[nbuck]) - nextf[nbuck] = CHAIN (mp); - else - CHAIN (mp2) = CHAIN (mp); - busy[nbuck] = 0; - -#ifdef MALLOC_STATS - _mstats.tbcoalesce++; - _mstats.ncoalesce[nbuck]++; -#endif - - /* 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()). BUSY[NU] must be set to 1. */ -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. */ - - /* Remove the block from the chain of larger blocks. */ - busy[nbuck] = 1; - mp = nextf[nbuck]; - nextf[nbuck] = CHAIN (mp); - busy[nbuck] = 0; - -#ifdef MALLOC_STATS - _mstats.tbsplit++; - _mstats.nsplit[nbuck]++; -#endif - - /* Figure out how many blocks we'll get. */ - siz = binsize (nu); - nblks = binsize (nbuck) / siz; - - /* 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; -} - -/* Take the memory block MP and add it to a chain < NU. NU is the right bucket, - but is busy. This avoids memory orphaning. */ -static void -xsplit (mp, nu) - union mhead *mp; - int nu; -{ - union mhead *nh; - int nbuck, nblks, split_max; - unsigned long siz; - - nbuck = nu - 1; - while (nbuck >= SPLIT_MIN && busy[nbuck]) - nbuck--; - if (nbuck < SPLIT_MIN) - return; - -#ifdef MALLOC_STATS - _mstats.tbsplit++; - _mstats.nsplit[nu]++; -#endif - - /* Figure out how many blocks we'll get. */ - siz = binsize (nu); /* original block size */ - nblks = siz / binsize (nbuck); /* should be 2 most of the time */ - - /* And add it to nextf[nbuck] */ - siz = binsize (nbuck); /* XXX - resetting here */ - nh = mp; - while (1) - { - mp->mh_alloc = ISFREE; - mp->mh_index = nbuck; - if (--nblks <= 0) break; - CHAIN (mp) = (union mhead *)((char *)mp + siz); - mp = (union mhead *)((char *)mp + siz); - } - busy[nbuck] = 1; - CHAIN (mp) = nextf[nbuck]; - nextf[nbuck] = nh; - busy[nbuck] = 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 -} - -/* Ask system for more memory; add to NEXTF[NU]. BUSY[NU] must be set to 1. */ -static void -morecore (nu) - 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 within 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 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; - - if (nunits > 0) - { - 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, *z; - long nbytes; - mguard_t mg; - - /* 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 */ - mg.i = n; - z = mg.s; - m = (char *) (p + 1) + n; - *m++ = *z++, *m++ = *z++, *m++ = *z++, *m++ = *z++; - -#ifdef MEMSCRAMBLE - if (n) - 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, *z; - register int nunits; - register unsigned int nbytes; - int ubytes; /* caller-requested size */ - mguard_t mg; - - 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; - z = mg.s; - *z++ = *ap++, *z++ = *ap++, *z++ = *ap++, *z++ = *ap++; - if (mg.i != 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 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 - if (p->mh_nbytes) - MALLOC_MEMSET (mem, 0xcf, p->mh_nbytes); -#endif - - ASSERT (nunits < NBUCKETS); - - if (busy[nunits] == 1) - { - xsplit (p, nunits); /* split block and add to different chain */ - goto free_return; - } - - p->mh_alloc = ISFREE; - /* Protect against signal handlers calling malloc. */ - busy[nunits] = 1; - /* Put this block on the free list. */ - CHAIN (p) = nextf[nunits]; - nextf[nunits] = p; - busy[nunits] = 0; - -free_return: - ; /* Empty statement in case this is the end of the function */ - -#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, *z; - mguard_t mg; - -#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); - z = mg.s; - *z++ = *m++, *z++ = *m++, *z++ = *m++, *z++ = *m++; - if (mg.i != 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)) - { -#if 0 - m = (char *)mem + p->mh_nbytes; -#else - /* Compensate for increment above. */ - m -= 4; -#endif - *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0; - m = (char *)mem + (p->mh_nbytes = n); - - mg.i = n; - z = mg.s; - *m++ = *z++, *m++ = *z++, *m++ = *z++, *m++ = *z++; - - 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) - size_t 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) - size_t 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) - size_t 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/malloc/stats.c~ b/lib/malloc/stats.c~ deleted file mode 100644 index 3841511cf..000000000 --- a/lib/malloc/stats.c~ +++ /dev/null @@ -1,205 +0,0 @@ -/* stats.c - malloc statistics */ - -/* Copyright (C) 2001-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 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "imalloc.h" - -#ifdef MALLOC_STATS - -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include - -#include "mstats.h" - -extern int malloc_free_blocks __P((int)); - -extern struct _malstats _mstats; - -extern FILE *_imalloc_fopen __P((char *, char *, char *, char *, size_t)); - -struct bucket_stats -malloc_bucket_stats (size) - int size; -{ - struct bucket_stats v; - - v.nfree = 0; - - if (size < 0 || size >= NBUCKETS) - { - v.blocksize = 0; - v.nused = v.nmal = v.nmorecore = v.nlesscore = v.nsplit = 0; - return v; - } - - v.blocksize = 1 << (size + 3); - v.nused = _mstats.nmalloc[size]; - v.nmal = _mstats.tmalloc[size]; - v.nmorecore = _mstats.nmorecore[size]; - v.nlesscore = _mstats.nlesscore[size]; - v.nsplit = _mstats.nsplit[size]; - v.ncoalesce = _mstats.ncoalesce[size]; - - v.nfree = malloc_free_blocks (size); /* call back to malloc.c */ - - return v; -} - -/* Return a copy of _MSTATS, with two additional fields filled in: - BYTESFREE is the total number of bytes on free lists. BYTESUSED - is the total number of bytes in use. These two fields are fairly - expensive to compute, so we do it only when asked to. */ -struct _malstats -malloc_stats () -{ - struct _malstats result; - struct bucket_stats v; - register int i; - - result = _mstats; - result.bytesused = result.bytesfree = 0; - for (i = 0; i < NBUCKETS; i++) - { - v = malloc_bucket_stats (i); - result.bytesfree += v.nfree * v.blocksize; - result.bytesused += v.nused * v.blocksize; - } - return (result); -} - -static void -_print_malloc_stats (s, fp) - char *s; - FILE *fp; -{ - register int i; - unsigned long totused, totfree; - struct bucket_stats v; - - fprintf (fp, "Memory allocation statistics: %s\n size\tfree\tin use\ttotal\tmorecore lesscore split\tcoalesce\n", s ? s : ""); - for (i = totused = totfree = 0; i < NBUCKETS; i++) - { - v = malloc_bucket_stats (i); - if (v.nmal > 0) - fprintf (fp, "%8lu\t%4d\t%6d\t%5d\t%8d\t%d %5d %8d\n", (unsigned long)v.blocksize, v.nfree, v.nused, v.nmal, v.nmorecore, v.nlesscore, v.nsplit, v.ncoalesce); - totfree += v.nfree * v.blocksize; - totused += v.nused * v.blocksize; - } - fprintf (fp, "\nTotal bytes in use: %lu, total bytes free: %lu\n", - totused, totfree); - fprintf (fp, "\nTotal bytes requested by application: %lu\n", _mstats.bytesreq); - fprintf (fp, "Total mallocs: %d, total frees: %d, total reallocs: %d (%d copies)\n", - _mstats.nmal, _mstats.nfre, _mstats.nrealloc, _mstats.nrcopy); - fprintf (fp, "Total sbrks: %d, total bytes via sbrk: %d\n", - _mstats.nsbrk, _mstats.tsbrk); - fprintf (fp, "Total blocks split: %d, total block coalesces: %d\n", - _mstats.tbsplit, _mstats.tbcoalesce); -} - -void -print_malloc_stats (s) - char *s; -{ - _print_malloc_stats (s, stderr); -} - -void -fprint_malloc_stats (s, fp) - char *s; - FILE *fp; -{ - _print_malloc_stats (s, fp); -} - -#define TRACEROOT "/var/tmp/maltrace/stats." - -void -trace_malloc_stats (s, fn) - char *s, *fn; -{ - FILE *fp; - char defname[sizeof (TRACEROOT) + 64]; - static char mallbuf[1024]; - - fp = _imalloc_fopen (s, fn, TRACEROOT, defname, sizeof (defname)); - if (fp) - { - setvbuf (fp, mallbuf, _IOFBF, sizeof (mallbuf)); - _print_malloc_stats (s, fp); - fflush(fp); - fclose(fp); - } -} - -#endif /* MALLOC_STATS */ - -#if defined (MALLOC_STATS) || defined (MALLOC_TRACE) -FILE * -_imalloc_fopen (s, fn, def, defbuf, defsiz) - char *s; - char *fn; - char *def; - char *defbuf; - size_t defsiz; -{ - char fname[1024]; - long l; - FILE *fp; - - l = (long)getpid (); - if (fn == 0) - { - sprintf (defbuf, "%s%ld", def, l); - fp = fopen(defbuf, "w"); - } - else - { - char *p, *q, *r; - char pidbuf[32]; - int sp; - - sprintf (pidbuf, "%ld", l); - if ((strlen (pidbuf) + strlen (fn) + 2) >= sizeof (fname)) - return; - for (sp = 0, p = fname, q = fn; *q; ) - { - if (sp == 0 && *q == '%' && q[1] == 'p') - { - sp = 1; - for (r = pidbuf; *r; ) - *p++ = *r++; - q += 2; - } - else - *p++ = *q++; - } - *p = '\0'; - fp = fopen (fname, "w"); - } - - return fp; -} -#endif /* MALLOC_STATS || MALLOC_TRACE */ diff --git a/lib/malloc/watch.c~ b/lib/malloc/watch.c~ deleted file mode 100644 index 11ab744d4..000000000 --- a/lib/malloc/watch.c~ +++ /dev/null @@ -1,150 +0,0 @@ -/* watch.c - watchpoint functions for malloc */ - -/* Copyright (C) 2001-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. */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "imalloc.h" - -#ifdef MALLOC_WATCH -#include "watch.h" - -#define WATCH_MAX 32 - -int _malloc_nwatch; -static PTR_T _malloc_watch_list[WATCH_MAX]; - -static void -watch_warn (addr, file, line, type, data) - PTR_T addr; - const char *file; - int line, type; - unsigned long data; -{ - char *tag; - - if (type == W_ALLOC) - tag = _("allocated"); - else if (type == W_FREE) - tag = _("freed"); - else if (type == W_REALLOC) - tag = _("requesting resize"); - else if (type == W_RESIZED) - tag = _("just resized"); - else - tag = _("bug: unknown operation"); - - fprintf (stderr, _("malloc: watch alert: %p %s "), addr, tag); - if (data != (unsigned long)-1) - fprintf (stderr, "(size %lu) ", data); - fprintf (stderr, "from '%s:%d'\n", file ? file : "unknown", line); -} - -void -_malloc_ckwatch (addr, file, line, type, data) - PTR_T addr; - const char *file; - int line, type; - unsigned long data; -{ - register int i; - - for (i = _malloc_nwatch - 1; i >= 0; i--) - { - if (_malloc_watch_list[i] == addr) - { - watch_warn (addr, file, line, type, data); - return; - } - } -} -#endif /* MALLOC_WATCH */ - -PTR_T -malloc_watch (addr) - PTR_T addr; -{ - register int i; - PTR_T ret; - - if (addr == 0) - return addr; - ret = (PTR_T)0; - -#ifdef MALLOC_WATCH - for (i = _malloc_nwatch - 1; i >= 0; i--) - { - if (_malloc_watch_list[i] == addr) - break; - } - if (i < 0) - { - if (_malloc_nwatch == WATCH_MAX) /* full, take out first */ - { - ret = _malloc_watch_list[0]; - _malloc_nwatch--; - for (i = 0; i < _malloc_nwatch; i++) - _malloc_watch_list[i] = _malloc_watch_list[i+1]; - } - _malloc_watch_list[_malloc_nwatch++] = addr; - } -#endif - - return ret; -} - -/* Remove a watchpoint set on ADDR. If ADDR is NULL, remove all - watchpoints. Returns ADDR if everything went OK, NULL if ADDR was - not being watched. */ -PTR_T -malloc_unwatch (addr) - PTR_T addr; -{ -#ifdef MALLOC_WATCH - register int i; - - if (addr == 0) - { - for (i = 0; i < _malloc_nwatch; i++) - _malloc_watch_list[i] = (PTR_T)0; - _malloc_nwatch = 0; - return ((PTR_T)0); - } - else - { - for (i = 0; i < _malloc_nwatch; i++) - { - if (_malloc_watch_list[i] == addr) - break; - } - if (i == _malloc_nwatch) - return ((PTR_T)0); /* not found */ - /* shuffle everything from i+1 to end down 1 */ - _malloc_nwatch--; - for ( ; i < _malloc_nwatch; i++) - _malloc_watch_list[i] = _malloc_watch_list[i+1]; - return addr; - } -#else - return ((PTR_T)0); -#endif -} diff --git a/lib/readline/COPYING.old b/lib/readline/COPYING.old deleted file mode 100644 index 1bf152638..000000000 --- a/lib/readline/COPYING.old +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/lib/readline/Makefile.in~ b/lib/readline/Makefile.in~ deleted file mode 100644 index 98169e411..000000000 --- a/lib/readline/Makefile.in~ +++ /dev/null @@ -1,366 +0,0 @@ -## -*- text -*- ############################################################# -# # -# Makefile for the Bash versions of the GNU Readline and History Libraries. # -# # -############################################################################# - -# Copyright (C) 1994-2005 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. - -PACKAGE = @PACKAGE_NAME@ -VERSION = @PACKAGE_VERSION@ - -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_VERSION = @PACKAGE_VERSION@ - -srcdir = @srcdir@ -VPATH = .:@srcdir@ -topdir = @top_srcdir@ -BUILD_DIR = @BUILD_DIR@ - -INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_DATA = @INSTALL_DATA@ - -CC = @CC@ -RANLIB = @RANLIB@ -AR = @AR@ -ARFLAGS = @ARFLAGS@ -RM = rm -f -CP = cp -MV = mv - -SHELL = @MAKE_SHELL@ - -# Programs to make tags files. -ETAGS = etags -tw -CTAGS = ctags -tw - -CFLAGS = @CFLAGS@ -LOCAL_CFLAGS = @LOCAL_CFLAGS@ -CPPFLAGS = @CPPFLAGS@ -LDFLAGS = @LDFLAGS@ - -DEFS = @DEFS@ -LOCAL_DEFS = @LOCAL_DEFS@ - -INCLUDES = -I. -I$(BUILD_DIR) -I$(topdir) -I$(topdir)/lib - -CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(APP_CFLAGS) $(CPPFLAGS) ${INCLUDES} $(LOCAL_CFLAGS) $(CFLAGS) - -.c.o: - ${RM} $@ - $(CC) -c $(CCFLAGS) $< - -# The name of the main library target. -LIBRARY_NAME = libreadline.a - -# The C code source files for this library. -CSOURCES = $(srcdir)/readline.c $(srcdir)/funmap.c $(srcdir)/keymaps.c \ - $(srcdir)/vi_mode.c $(srcdir)/parens.c $(srcdir)/rltty.c \ - $(srcdir)/complete.c $(srcdir)/bind.c $(srcdir)/isearch.c \ - $(srcdir)/display.c $(srcdir)/signals.c $(srcdir)/emacs_keymap.c \ - $(srcdir)/vi_keymap.c $(srcdir)/util.c $(srcdir)/kill.c \ - $(srcdir)/undo.c $(srcdir)/macro.c $(srcdir)/input.c \ - $(srcdir)/callback.c $(srcdir)/terminal.c $(srcdir)/xmalloc.c \ - $(srcdir)/history.c $(srcdir)/histsearch.c $(srcdir)/histexpand.c \ - $(srcdir)/histfile.c $(srcdir)/nls.c $(srcdir)/search.c \ - $(srcdir)/shell.c $(srcdir)/tilde.c $(srcdir)/savestring.c \ - $(srcdir)/text.c $(srcdir)/misc.c $(srcdir)/compat.c \ - $(srcdir)/mbutil.c - -# The header files for this library. -HSOURCES = readline.h rldefs.h chardefs.h keymaps.h history.h histlib.h \ - posixstat.h posixdir.h posixjmp.h tilde.h rlconf.h rltty.h \ - ansi_stdlib.h rlstdc.h tcap.h xmalloc.h rlprivate.h rlshell.h \ - rltypedefs.h rlmbutil.h - -HISTOBJ = history.o histexpand.o histfile.o histsearch.o shell.o savestring.o \ - mbutil.o -TILDEOBJ = tilde.o -OBJECTS = readline.o vi_mode.o funmap.o keymaps.o parens.o search.o \ - rltty.o complete.o bind.o isearch.o display.o signals.o \ - util.o kill.o undo.o macro.o input.o callback.o terminal.o \ - text.o nls.o misc.o $(HISTOBJ) $(TILDEOBJ) xmalloc.o compat.o - -# The texinfo files which document this library. -DOCSOURCE = doc/rlman.texinfo doc/rltech.texinfo doc/rluser.texinfo -DOCOBJECT = doc/readline.dvi -DOCSUPPORT = doc/Makefile -DOCUMENTATION = $(DOCSOURCE) $(DOCOBJECT) $(DOCSUPPORT) - -SUPPORT = Makefile ChangeLog $(DOCSUPPORT) examples/[-a-z.]* - -SOURCES = $(CSOURCES) $(HSOURCES) $(DOCSOURCE) - -THINGS_TO_TAR = $(SOURCES) $(SUPPORT) - -INSTALLED_HEADERS = readline.h chardefs.h keymaps.h history.h tilde.h \ - rlstdc.h rlconf.h rltypedefs.h - -########################################################################## - -all: libreadline.a libhistory.a - -libreadline.a: $(OBJECTS) - $(RM) $@ - $(AR) $(ARFLAGS) $@ $(OBJECTS) - -test -n "$(RANLIB)" && $(RANLIB) $@ - -libhistory.a: $(HISTOBJ) xmalloc.o - $(RM) $@ - $(AR) $(ARFLAGS) $@ $(HISTOBJ) xmalloc.o - -test -n "$(RANLIB)" && $(RANLIB) $@ - -documentation: force - test -d doc || mkdir doc - -( cd doc && $(MAKE) $(MFLAGS) ) - -# Since tilde.c is shared between readline and bash, make sure we compile -# it with the right flags when it's built as part of readline -tilde.o: tilde.c - rm -f $@ - $(CC) $(CCFLAGS) -DREADLINE_LIBRARY -c $(srcdir)/tilde.c - -force: - -install: - @echo "This version of the readline library should not be installed." - -uninstall: - @echo "This version of the readline library should not be installed." - -TAGS: force - $(ETAGS) $(CSOURCES) $(HSOURCES) - -tags: force - $(CTAGS) $(CSOURCES) $(HSOURCES) - -clean: force - $(RM) $(OBJECTS) *.a - -( cd doc && $(MAKE) $(MFLAGS) $@ ) - -mostlyclean: clean - -( cd doc && $(MAKE) $(MFLAGS) $@ ) - -distclean maintainer-clean: clean - -( cd doc && $(MAKE) $(MFLAGS) $@ ) - $(RM) Makefile - $(RM) TAGS tags - -# Dependencies -bind.o: ansi_stdlib.h posixstat.h -bind.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -bind.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -bind.o: history.h rlstdc.h -callback.o: rlconf.h ansi_stdlib.h -callback.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -callback.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h -compat.o: rlstdc.h -complete.o: ansi_stdlib.h posixdir.h posixstat.h -complete.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -complete.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h -display.o: ansi_stdlib.h posixstat.h -display.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -display.o: tcap.h -display.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -display.o: history.h rlstdc.h -funmap.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -funmap.o: rlconf.h ansi_stdlib.h rlstdc.h -funmap.o: ${BUILD_DIR}/config.h -histexpand.o: ansi_stdlib.h -histexpand.o: history.h histlib.h rlstdc.h -histexpand.o: ${BUILD_DIR}/config.h -histfile.o: ansi_stdlib.h -histfile.o: history.h histlib.h rlstdc.h -histfile.o: ${BUILD_DIR}/config.h -history.o: ansi_stdlib.h -history.o: history.h histlib.h rlstdc.h -history.o: ${BUILD_DIR}/config.h -histsearch.o: ansi_stdlib.h -histsearch.o: history.h histlib.h rlstdc.h -histsearch.o: ${BUILD_DIR}/config.h -input.o: ansi_stdlib.h -input.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -input.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h -isearch.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -isearch.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -isearch.o: ansi_stdlib.h history.h rlstdc.h -keymaps.o: emacs_keymap.c vi_keymap.c -keymaps.o: keymaps.h rltypedefs.h chardefs.h rlconf.h ansi_stdlib.h -keymaps.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -keymaps.o: ${BUILD_DIR}/config.h rlstdc.h -kill.o: ansi_stdlib.h -kill.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -kill.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -kill.o: history.h rlstdc.h -macro.o: ansi_stdlib.h -macro.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -macro.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -macro.o: history.h rlstdc.h -mbutil.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h rlmbutil.h -mbutil.o: readline.h keymaps.h rltypedefs.h chardefs.h rlstdc.h -misc.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -misc.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -misc.o: history.h rlstdc.h ansi_stdlib.h -nls.o: ansi_stdlib.h -nls.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -nls.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -nls.o: history.h rlstdc.h -parens.o: rlconf.h -parens.o: ${BUILD_DIR}/config.h -parens.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h -readline.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -readline.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -readline.o: history.h rlstdc.h -readline.o: posixstat.h ansi_stdlib.h posixjmp.h -rltty.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -rltty.o: rltty.h -rltty.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h -search.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -search.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -search.o: ansi_stdlib.h history.h rlstdc.h -shell.o: ${BUILD_DIR}/config.h ansi_stdlib.h -signals.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -signals.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -signals.o: history.h rlstdc.h -terminal.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -terminal.o: tcap.h -terminal.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -terminal.o: history.h rlstdc.h -text.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -text.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -text.o: history.h rlstdc.h ansi_stdlib.h -rltty.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -tilde.o: ansi_stdlib.h -tilde.o: ${BUILD_DIR}/config.h -tilde.o: tilde.h -undo.o: ansi_stdlib.h -undo.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -undo.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -undo.o: history.h rlstdc.h xmalloc.h -util.o: posixjmp.h ansi_stdlib.h -util.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -util.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h -vi_mode.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h -vi_mode.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h -vi_mode.o: history.h ansi_stdlib.h rlstdc.h -xmalloc.o: ${BUILD_DIR}/config.h ansi_stdlib.h - -bind.o: rlshell.h -histfile.o: rlshell.h -nls.o: rlshell.h -readline.o: rlshell.h -shell.o: rlshell.h -terminal.o: rlshell.h -histexpand.o: rlshell.h - -bind.o: rlprivate.h -callback.o: rlprivate.h -complete.o: rlprivate.h -display.o: rlprivate.h -input.o: rlprivate.h -isearch.o: rlprivate.h -kill.o: rlprivate.h -macro.o: rlprivate.h -mbutil.o: rlprivate.h -misc.o: rlprivate.h -nls.o: rlprivate.h -parens.o: rlprivate.h -readline.o: rlprivate.h -rltty.o: rlprivate.h -search.o: rlprivate.h -signals.o: rlprivate.h -terminal.o: rlprivate.h -text.o: rlprivate.h -undo.o: rlprivate.h -util.o: rlprivate.h -vi_mode.o: rlprivate.h - -bind.o: xmalloc.h -complete.o: xmalloc.h -display.o: xmalloc.h -funmap.o: xmalloc.h -histexpand.o: xmalloc.h -histfile.o: xmalloc.h -history.o: xmalloc.h -input.o: xmalloc.h -isearch.o: xmalloc.h -keymaps.o: xmalloc.h -kill.o: xmalloc.h -macro.o: xmalloc.h -mbutil.o: xmalloc.h -misc.o: xmalloc.h -readline.o: xmalloc.h -savestring.o: xmalloc.h -search.o: xmalloc.h -shell.o: xmalloc.h -terminal.o: xmalloc.h -text.o: xmalloc.h -tilde.o: xmalloc.h -undo.o: xmalloc.h -util.o: xmalloc.h -vi_mode.o: xmalloc.h -xmalloc.o: xmalloc.h - -complete.o: rlmbutil.h -display.o: rlmbutil.h -histexpand.o: rlmbutil.h -input.o: rlmbutil.h -isearch.o: rlmbutil.h -mbutil.o: rlmbutil.h -misc.o: rlmbutil.h -readline.o: rlmbutil.h -search.o: rlmbutil.h -text.o: rlmbutil.h -vi_mode.o: rlmbutil.h - -# Rules for deficient makes, like SunOS and Solaris -bind.o: bind.c -callback.o: callback.c -compat.o: compat.c -complete.o: complete.c -display.o: display.c -funmap.o: funmap.c -input.o: input.c -isearch.o: isearch.c -keymaps.o: keymaps.c emacs_keymap.c vi_keymap.c -kill.o: kill.c -macro.o: macro.c -mbutil.o: mbutil.c -misc.o: misc.c -nls.o: nls.c -parens.o: parens.c -readline.o: readline.c -rltty.o: rltty.c -savestring.o: savestring.c -search.o: search.c -shell.o: shell.c -signals.o: signals.c -terminal.o: terminal.c -text.o: text.c -tilde.o: tilde.c -undo.o: undo.c -util.o: util.c -vi_mode.o: vi_mode.c -xmalloc.o: xmalloc.c - -histexpand.o: histexpand.c -histfile.o: histfile.c -history.o: history.c -histsearch.o: histsearch.c diff --git a/lib/readline/bind.c~ b/lib/readline/bind.c~ deleted file mode 100644 index f68b5fa85..000000000 --- a/lib/readline/bind.c~ +++ /dev/null @@ -1,2357 +0,0 @@ -/* bind.c -- key binding and startup file support for the readline library. */ - -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (__TANDEM) -# include -#endif - -#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 find_boolean_var PARAMS((const char *)); - -static char *_rl_get_string_variable_value PARAMS((const char *)); -static int substring_member_of_array PARAMS((const char *, const char * const *)); - -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)) - { - xfree (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 == 0 || *keyseq == 0) - { - if (type == ISMACR) - xfree (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)) - { - xfree (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) - { - xfree (keys); - return -1; - } - - if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii) - { - 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) - xfree ((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; - } - xfree (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++; /* seq[i] == '-' */ - /* XXX - obey convert-meta setting */ - if (_rl_convert_meta_chars_to_ascii && _rl_keymap[ESC].type == ISKMAP) - array[l++] = ESC; /* ESC is meta-prefix */ - else if (seq[i+1] == '\\' && seq[i+2] == 'C' && seq[i+3] == '-') - { - i += 4; - temp = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i])); - array[l++] = META (temp); - } - else - { - /* This doesn't yet handle things like \M-\a, which may - or may not have any reasonable meaning. You're - probably better off using straight octal or hex. */ - i++; - array[l++] = META (seq[i]); - } - } - 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 (c == ESC) - { - kseq[i++] = '\\'; - c = 'e'; - } - 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 (c == ESC) - { - *r++ = '\\'; - c = 'e'; - } - else if (CTRL_CHAR (c)) - { - *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 == 0) - 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) - { - map = FUNCTION_TO_KEYMAP (map, ESC); - ic = UNMETA (ic); - } - /* XXX - should we just return NULL here, since this obviously - doesn't match? */ - else - { - if (type) - *type = map[ESC].type; - - return (map[ESC].function); - } - } - - if (map[ic].type == ISKMAP) - { - /* If this is the last key in the key sequence, return the - map. */ - if (keyseq[i + 1] == '\0') - { - if (type) - *type = ISKMAP; - - return (map[ic].function); - } - else - map = FUNCTION_TO_KEYMAP (map, ic); - } - /* If we're not at the end of the key sequence, and the current key - is bound to something other than a keymap, then the entire key - sequence is not bound. */ - else if (map[ic].type != ISKMAP && keyseq[i+1]) - return ((rl_command_func_t *)NULL); - else /* map[ic].type != ISKMAP && keyseq[i+1] == 0 */ - { - 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) - { - xfree (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 - 4. /etc/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 == 0) - { - filename = DEFAULT_INPUTRC; - /* Try to read DEFAULT_INPUTRC; fall back to SYS_INPUTRC on failure */ - if (_rl_read_init_file (filename, 0) == 0) - return 0; - filename = SYS_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); - xfree (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++; - } - - xfree (buffer); - currently_reading_init_file = 0; - return (0); -} - -static void -_rl_init_file_error (msg) - const char *msg; -{ - if (currently_reading_init_file) - _rl_errmsg ("%s: line %d: %s\n", current_readline_init_file, - current_readline_init_lineno, msg); - else - _rl_errmsg ("%s", msg); -} - -/* **************************************************************** */ -/* */ -/* Parser Directives */ -/* */ -/* **************************************************************** */ - -typedef int _rl_parser_func_t PARAMS((char *)); - -/* Things that mean `Control'. */ -const char * const _rl_possible_control_prefixes[] = { - "Control-", "C-", "CTRL-", (const char *)NULL -}; - -const char * const _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); - xfree (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 const struct { - const char * const 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, *value, *e; - - var = string + i; - /* 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++; - - /* Strip trailing whitespace from values to boolean variables. Temp - fix until I get a real quoted-string parser here. */ - i = find_boolean_var (var); - if (i >= 0) - { - /* remove trailing whitespace */ - e = value + strlen (value) - 1; - while (e >= value && whitespace (*e)) - e--; - e++; /* skip back to whitespace or EOS */ - if (*e && e >= value) - *e = '\0'; - } - - 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, passc; - - delimiter = string[i++]; - 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)); - - xfree (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 const struct { - const char * const name; - int *value; - int flags; -} boolean_varlist [] = { - { "bind-tty-special-chars", &_rl_bind_stty_chars, 0 }, - { "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 }, - { "revert-all-at-newline", &_rl_revert_all_at_newline, 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_dispprefix PARAMS((const char *)); -static int sv_compquery PARAMS((const char *)); -static int sv_editmode PARAMS((const char *)); -static int sv_histsize PARAMS((const char *)); -static int sv_isrchterm PARAMS((const char *)); -static int sv_keymap PARAMS((const char *)); - -static const struct { - const char * const 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-prefix-display-length", V_INT, sv_dispprefix }, - { "completion-query-items", V_INT, sv_compquery }, - { "editing-mode", V_STRING, sv_editmode }, - { "history-size", V_INT, sv_histsize }, - { "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) - const char *value; -{ - return (value == 0 || *value == '\0' || - (_rl_stricmp (value, "on") == 0) || - (value[0] == '1' && value[1] == '\0')); -} - -char * -rl_variable_value (name) - const char *name; -{ - register int i; - - /* Check for simple variables first. */ - i = find_boolean_var (name); - if (i >= 0) - return (*boolean_varlist[i].value ? "on" : "off"); - - i = find_string_var (name); - if (i >= 0) - return (_rl_get_string_variable_value (string_varlist[i].name)); - - /* Unknown variable names return NULL. */ - return 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_dispprefix (value) - const char *value; -{ - int nval = 0; - - if (value && *value) - { - nval = atoi (value); - if (nval < 0) - nval = 0; - } - _rl_completion_prefix_display_length = nval; - return 0; -} - -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_histsize (value) - const char *value; -{ - int nval = 500; - - if (value && *value) - { - nval = atoi (value); - if (nval < 0) - return 1; - } - stifle_history (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'; - - xfree (v); - return 0; -} - -/* Return the character which matches NAME. - For example, `Space' returns ' '. */ - -typedef struct { - const char * const name; - int value; -} assoc_list; - -static const 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 const struct { - const char * const 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]); - - xfree (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 ESC is the meta prefix and we're converting chars - with the eighth bit set to ESC-prefixed sequences, then - we can use \M-. Otherwise we need to use the sequence - for ESC. */ - if (_rl_convert_meta_chars_to_ascii && map[ESC].type == ISKMAP) - sprintf (keyname, "\\M-"); - else - sprintf (keyname, "\\e"); - } - else if (CTRL_CHAR (key)) - sprintf (keyname, "\\C-%c", _rl_to_lower (UNCTRL (key))); - else if (key == RUBOUT) - sprintf (keyname, "\\C-?"); - else if (key == '\\' || key == '"') - { - keyname[0] = '\\'; - keyname[1] = (char) key; - keyname[2] = '\0'; - } - else - { - keyname[0] = (char) key; - keyname[1] = '\0'; - } - - strcat (keyname, seqs[i]); - xfree (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; - } - - xfree (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); - xfree (invokers[j]); - } - - xfree (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++) - xfree (invokers[j]); - - xfree (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 : ""); - xfree (keyname); - xfree (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); - xfree (keyname); - keyname = out; - } - } - - _rl_macro_dumper_internal (print_readably, FUNCTION_TO_KEYMAP (map, key), keyname); - xfree (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); -} - -static char * -_rl_get_string_variable_value (name) - const char *name; -{ - static char numbuf[32]; - char *ret; - - if (_rl_stricmp (name, "bell-style") == 0) - { - switch (_rl_bell_preference) - { - case NO_BELL: - return "none"; - case VISIBLE_BELL: - return "visible"; - case AUDIBLE_BELL: - default: - return "audible"; - } - } - else if (_rl_stricmp (name, "comment-begin") == 0) - return (_rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT); - else if (_rl_stricmp (name, "completion-prefix-display-length") == 0) - { - sprintf (numbuf, "%d", _rl_completion_prefix_display_length); - return (numbuf); - } - else if (_rl_stricmp (name, "completion-query-items") == 0) - { - sprintf (numbuf, "%d", rl_completion_query_items); - return (numbuf); - } - else if (_rl_stricmp (name, "editing-mode") == 0) - return (rl_get_keymap_name_from_edit_mode ()); - else if (_rl_stricmp (name, "history-size") == 0) - { - sprintf (numbuf, "%d", history_is_stifled() ? history_max_entries : 0); - return (numbuf); - } - else if (_rl_stricmp (name, "isearch-terminators") == 0) - { - if (_rl_isearch_terminators == 0) - return 0; - ret = _rl_untranslate_macro_value (_rl_isearch_terminators); - if (ret) - { - strncpy (numbuf, ret, sizeof (numbuf) - 1); - xfree (ret); - numbuf[sizeof(numbuf) - 1] = '\0'; - } - else - numbuf[0] = '\0'; - return numbuf; - } - else if (_rl_stricmp (name, "keymap") == 0) - { - ret = rl_get_keymap_name (_rl_keymap); - if (ret == 0) - ret = rl_get_keymap_name_from_edit_mode (); - return (ret ? ret : "none"); - } - else - return (0); -} - -void -rl_variable_dumper (print_readably) - int print_readably; -{ - int i; - char *v; - - 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"); - } - - for (i = 0; string_varlist[i].name; i++) - { - v = _rl_get_string_variable_value (string_varlist[i].name); - if (v == 0) /* _rl_isearch_terminators can be NULL */ - continue; - if (print_readably) - fprintf (rl_outstream, "set %s %s\n", string_varlist[i].name, v); - else - fprintf (rl_outstream, "%s is set to `%s'\n", string_varlist[i].name, v); - } -} - -/* 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) - const char *string; - const char * const *array; -{ - while (*array) - { - if (_rl_strindex (string, *array)) - return (1); - array++; - } - return (0); -} diff --git a/lib/readline/callback.c.save b/lib/readline/callback.c.save deleted file mode 100644 index 697066e03..000000000 --- a/lib/readline/callback.c.save +++ /dev/null @@ -1,261 +0,0 @@ -/* callback.c -- functions to use readline as an X `callback' mechanism. */ - -/* Copyright (C) 1987-2005 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include "rlconf.h" - -#if defined (READLINE_CALLBACKS) - -#include - -#ifdef HAVE_STDLIB_H -# include -#else -# include "ansi_stdlib.h" -#endif - -#include - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "readline.h" -#include "rlprivate.h" -#include "xmalloc.h" - -/* Private data for callback registration functions. See comments in - rl_callback_read_char for more details. */ -_rl_callback_func_t *_rl_callback_func = 0; -_rl_callback_generic_arg *_rl_callback_data = 0; - -/* **************************************************************** */ -/* */ -/* Callback Readline Functions */ -/* */ -/* **************************************************************** */ - -/* Allow using readline in situations where a program may have multiple - things to handle at once, and dispatches them via select(). Call - rl_callback_handler_install() with the prompt and a function to call - whenever a complete line of input is ready. The user must then - call rl_callback_read_char() every time some input is available, and - rl_callback_read_char() will call the user's function with the complete - text read in at each end of line. The terminal is kept prepped and - signals handled all the time, except during calls to the user's function. */ - -rl_vcpfunc_t *rl_linefunc; /* user callback function */ -static int in_handler; /* terminal_prepped and signals set? */ - -/* Make sure the terminal is set up, initialize readline, and prompt. */ -static void -_rl_callback_newline () -{ - rl_initialize (); - - if (in_handler == 0) - { - in_handler = 1; - - if (rl_prep_term_function) - (*rl_prep_term_function) (_rl_meta_flag); - -#if defined (HANDLE_SIGNALS) - rl_set_signals (); -#endif - } - - readline_internal_setup (); -} - -/* Install a readline handler, set up the terminal, and issue the prompt. */ -void -rl_callback_handler_install (prompt, linefunc) - const char *prompt; - rl_vcpfunc_t *linefunc; -{ - rl_set_prompt (prompt); - RL_SETSTATE (RL_STATE_CALLBACK); - rl_linefunc = linefunc; - _rl_callback_newline (); -} - -/* Read one character, and dispatch to the handler if it ends the line. */ -void -rl_callback_read_char () -{ - char *line; - int eof, jcode; - static procenv_t olevel; - - if (rl_linefunc == NULL) - { - fprintf (stderr, "readline: readline_callback_read_char() called with no handler!\r\n"); - abort (); - } - - memcpy ((void *)olevel, (void *)readline_top_level, sizeof (procenv_t)); - jcode = setjmp (readline_top_level); - if (jcode) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - memcpy ((void *)readline_top_level, (void *)olevel, sizeof (procenv_t)); - return; - } - - if (RL_ISSTATE (RL_STATE_ISEARCH)) - { - eof = _rl_isearch_callback (_rl_iscxt); - if (eof == 0 && (RL_ISSTATE (RL_STATE_ISEARCH) == 0) && RL_ISSTATE (RL_STATE_INPUTPENDING)) - rl_callback_read_char (); - - return; - } - else if (RL_ISSTATE (RL_STATE_NSEARCH)) - { - eof = _rl_nsearch_callback (_rl_nscxt); - return; - } - else if (RL_ISSTATE (RL_STATE_NUMERICARG)) - { - eof = _rl_arg_callback (_rl_argcxt); - if (eof == 0 && (RL_ISSTATE (RL_STATE_NUMERICARG) == 0) && RL_ISSTATE (RL_STATE_INPUTPENDING)) - rl_callback_read_char (); - /* XXX - this should handle _rl_last_command_was_kill better */ - else if (RL_ISSTATE (RL_STATE_NUMERICARG) == 0) - _rl_internal_char_cleanup (); - - return; - } - else if (RL_ISSTATE (RL_STATE_MULTIKEY)) - { - eof = _rl_dispatch_callback (_rl_kscxt); /* For now */ - while ((eof == -1 || eof == -2) && RL_ISSTATE (RL_STATE_MULTIKEY) && _rl_kscxt && (_rl_kscxt->flags & KSEQ_DISPATCHED)) - eof = _rl_dispatch_callback (_rl_kscxt); - if (RL_ISSTATE (RL_STATE_MULTIKEY) == 0) - { - _rl_internal_char_cleanup (); - _rl_want_redisplay = 1; - } - } - else if (_rl_callback_func) - { - /* This allows functions that simply need to read an additional character - (like quoted-insert) to register a function to be called when input is - available. _rl_callback_data is simply a pointer to a struct that has - the argument count originally passed to the registering function and - space for any additional parameters. */ - eof = (*_rl_callback_func) (_rl_callback_data); - /* If the function `deregisters' itself, make sure the data is cleaned - up. */ - if (_rl_callback_func == 0) - { - if (_rl_callback_data) - { - _rl_callback_data_dispose (_rl_callback_data); - _rl_callback_data = 0; - } - _rl_internal_char_cleanup (); - } - } - else - eof = readline_internal_char (); - - if (rl_done == 0 && _rl_want_redisplay) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - } - - /* We loop in case some function has pushed input back with rl_execute_next. */ - for (;;) - { - if (rl_done) - { - line = readline_internal_teardown (eof); - - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); -#if defined (HANDLE_SIGNALS) - rl_clear_signals (); -#endif - in_handler = 0; - (*rl_linefunc) (line); - - /* If the user did not clear out the line, do it for him. */ - if (rl_line_buffer[0]) - _rl_init_line_state (); - - /* Redisplay the prompt if readline_handler_{install,remove} - not called. */ - if (in_handler == 0 && rl_linefunc) - _rl_callback_newline (); - } - if (rl_pending_input || _rl_pushed_input_available () || RL_ISSTATE (RL_STATE_MACROINPUT)) - eof = readline_internal_char (); - else - break; - } -} - -/* Remove the handler, and make sure the terminal is in its normal state. */ -void -rl_callback_handler_remove () -{ - rl_linefunc = NULL; - RL_UNSETSTATE (RL_STATE_CALLBACK); - if (in_handler) - { - in_handler = 0; - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); -#if defined (HANDLE_SIGNALS) - rl_clear_signals (); -#endif - } -} - -_rl_callback_generic_arg * -_rl_callback_data_alloc (count) - int count; -{ - _rl_callback_generic_arg *arg; - - arg = (_rl_callback_generic_arg *)xmalloc (sizeof (_rl_callback_generic_arg)); - arg->count = count; - - arg->i1 = arg->i2 = 0; - - return arg; -} - -void _rl_callback_data_dispose (arg) - _rl_callback_generic_arg *arg; -{ - if (arg) - free (arg); -} - -#endif diff --git a/lib/readline/callback.c~ b/lib/readline/callback.c~ deleted file mode 100644 index 8c9b6d3a5..000000000 --- a/lib/readline/callback.c~ +++ /dev/null @@ -1,257 +0,0 @@ -/* callback.c -- functions to use readline as an X `callback' mechanism. */ - -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include "rlconf.h" - -#if defined (READLINE_CALLBACKS) - -#include - -#ifdef HAVE_STDLIB_H -# include -#else -# include "ansi_stdlib.h" -#endif - -#include - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "readline.h" -#include "rlprivate.h" -#include "xmalloc.h" - -/* Private data for callback registration functions. See comments in - rl_callback_read_char for more details. */ -_rl_callback_func_t *_rl_callback_func = 0; -_rl_callback_generic_arg *_rl_callback_data = 0; - -/* **************************************************************** */ -/* */ -/* Callback Readline Functions */ -/* */ -/* **************************************************************** */ - -/* Allow using readline in situations where a program may have multiple - things to handle at once, and dispatches them via select(). Call - rl_callback_handler_install() with the prompt and a function to call - whenever a complete line of input is ready. The user must then - call rl_callback_read_char() every time some input is available, and - rl_callback_read_char() will call the user's function with the complete - text read in at each end of line. The terminal is kept prepped and - signals handled all the time, except during calls to the user's function. */ - -rl_vcpfunc_t *rl_linefunc; /* user callback function */ -static int in_handler; /* terminal_prepped and signals set? */ - -/* Make sure the terminal is set up, initialize readline, and prompt. */ -static void -_rl_callback_newline () -{ - rl_initialize (); - - if (in_handler == 0) - { - in_handler = 1; - - if (rl_prep_term_function) - (*rl_prep_term_function) (_rl_meta_flag); - -#if defined (HANDLE_SIGNALS) - rl_set_signals (); -#endif - } - - readline_internal_setup (); -} - -/* Install a readline handler, set up the terminal, and issue the prompt. */ -void -rl_callback_handler_install (prompt, linefunc) - const char *prompt; - rl_vcpfunc_t *linefunc; -{ - rl_set_prompt (prompt); - RL_SETSTATE (RL_STATE_CALLBACK); - rl_linefunc = linefunc; - _rl_callback_newline (); -} - -/* Read one character, and dispatch to the handler if it ends the line. */ -void -rl_callback_read_char () -{ - char *line; - int eof, jcode; - static procenv_t olevel; - - if (rl_linefunc == NULL) - { - _rl_errmsg ("readline_callback_read_char() called with no handler!"); - abort (); - } - - memcpy ((void *)olevel, (void *)_rl_top_level, sizeof (procenv_t)); - jcode = setjmp (_rl_top_level); - if (jcode) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - memcpy ((void *)_rl_top_level, (void *)olevel, sizeof (procenv_t)); - return; - } - - do - { - if (RL_ISSTATE (RL_STATE_ISEARCH)) - { - eof = _rl_isearch_callback (_rl_iscxt); - if (eof == 0 && (RL_ISSTATE (RL_STATE_ISEARCH) == 0) && RL_ISSTATE (RL_STATE_INPUTPENDING)) - rl_callback_read_char (); - - return; - } - else if (RL_ISSTATE (RL_STATE_NSEARCH)) - { - eof = _rl_nsearch_callback (_rl_nscxt); - return; - } - else if (RL_ISSTATE (RL_STATE_NUMERICARG)) - { - eof = _rl_arg_callback (_rl_argcxt); - if (eof == 0 && (RL_ISSTATE (RL_STATE_NUMERICARG) == 0) && RL_ISSTATE (RL_STATE_INPUTPENDING)) - rl_callback_read_char (); - /* XXX - this should handle _rl_last_command_was_kill better */ - else if (RL_ISSTATE (RL_STATE_NUMERICARG) == 0) - _rl_internal_char_cleanup (); - - return; - } - else if (RL_ISSTATE (RL_STATE_MULTIKEY)) - { - eof = _rl_dispatch_callback (_rl_kscxt); /* For now */ - while ((eof == -1 || eof == -2) && RL_ISSTATE (RL_STATE_MULTIKEY) && _rl_kscxt && (_rl_kscxt->flags & KSEQ_DISPATCHED)) - eof = _rl_dispatch_callback (_rl_kscxt); - if (RL_ISSTATE (RL_STATE_MULTIKEY) == 0) - { - _rl_internal_char_cleanup (); - _rl_want_redisplay = 1; - } - } - else if (_rl_callback_func) - { - /* This allows functions that simply need to read an additional - character (like quoted-insert) to register a function to be - called when input is available. _rl_callback_data is simply a - pointer to a struct that has the argument count originally - passed to the registering function and space for any additional - parameters. */ - eof = (*_rl_callback_func) (_rl_callback_data); - /* If the function `deregisters' itself, make sure the data is - cleaned up. */ - if (_rl_callback_func == 0) - { - if (_rl_callback_data) - { - _rl_callback_data_dispose (_rl_callback_data); - _rl_callback_data = 0; - } - _rl_internal_char_cleanup (); - } - } - else - eof = readline_internal_char (); - - if (rl_done == 0 && _rl_want_redisplay) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - } - - if (rl_done) - { - line = readline_internal_teardown (eof); - - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); -#if defined (HANDLE_SIGNALS) - rl_clear_signals (); -#endif - in_handler = 0; - (*rl_linefunc) (line); - - /* If the user did not clear out the line, do it for him. */ - if (rl_line_buffer[0]) - _rl_init_line_state (); - - /* Redisplay the prompt if readline_handler_{install,remove} - not called. */ - if (in_handler == 0 && rl_linefunc) - _rl_callback_newline (); - } - } - while (rl_pending_input || _rl_pushed_input_available () || RL_ISSTATE (RL_STATE_MACROINPUT)); -} - -/* Remove the handler, and make sure the terminal is in its normal state. */ -void -rl_callback_handler_remove () -{ - rl_linefunc = NULL; - RL_UNSETSTATE (RL_STATE_CALLBACK); - if (in_handler) - { - in_handler = 0; - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); -#if defined (HANDLE_SIGNALS) - rl_clear_signals (); -#endif - } -} - -_rl_callback_generic_arg * -_rl_callback_data_alloc (count) - int count; -{ - _rl_callback_generic_arg *arg; - - arg = (_rl_callback_generic_arg *)xmalloc (sizeof (_rl_callback_generic_arg)); - arg->count = count; - - arg->i1 = arg->i2 = 0; - - return arg; -} - -void _rl_callback_data_dispose (arg) - _rl_callback_generic_arg *arg; -{ - xfree (arg); -} - -#endif diff --git a/lib/readline/complete.c~ b/lib/readline/complete.c~ deleted file mode 100644 index bd34a1242..000000000 --- a/lib/readline/complete.c~ +++ /dev/null @@ -1,2458 +0,0 @@ -/* complete.c -- filename completion for readline. */ - -/* Copyright (C) 1987-2008 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 */ - -#if defined (HAVE_PWD_H) -#include -#endif - -#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_GETPWENT) && (!defined (HAVE_GETPW_DECLS) || defined (_POSIX_SOURCE)) -extern struct passwd *getpwent PARAMS((void)); -#endif /* HAVE_GETPWENT && (!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 *, int)); -static int print_filename PARAMS((char *, char *, int)); - -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; - -/* Length in characters of a common prefix replaced with an ellipsis (`...') - when displaying completion matches. Matches whose printable portion has - more than this number of displaying characters in common will have the common - display prefix replaced with an ellipsis. */ -int _rl_completion_prefix_display_length = 0; - -/* 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 generator function for rl_menu_complete (). NULL means to use - *rl_completion_entry_function (see above). */ -rl_compentry_func_t *rl_menu_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. A negative value means - don't ask. */ -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; - -/* Set to the last key used to invoke one of the completion functions */ -int rl_completion_invoking_key; - -/* If non-zero, sort the completion matches. On by default. */ -int rl_sort_completion_matches = 1; - -/* Variables local to this file. */ - -/* Local variable states what happened during the last completion attempt. */ -static int completion_changed_buffer; - -/* The result of the query to the user about displaying completion matches */ -static int completion_y_or_n; - -/*************************************/ -/* */ -/* 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; -{ - rl_completion_invoking_key = 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; -{ - rl_completion_invoking_key = invoking_key; - return (rl_complete_internal ('?')); -} - -int -rl_insert_completions (ignore, invoking_key) - int ignore, invoking_key; -{ - rl_completion_invoking_key = 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 */ -/* */ -/************************************/ - -/* Reset readline state on a signal or other event. */ -void -_rl_reset_completion_state () -{ - rl_completion_found_quote = 0; - rl_completion_quote_character = 0; -} - -/* 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; - rl_completion_append_character = ' '; - - /* 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 || c < 0) - _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; - - /* Short-circuit a //server on cygwin, since that will always behave as - a directory. */ -#if __CYGWIN__ - if (filename[0] == '/' && filename[1] == '/' && strchr (filename+2, '/') == 0) - return '/'; -#endif - -#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[pos]) || string[pos] == 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; -} - -#define ELLIPSIS_LEN 3 - -static int -fnprint (to_print, prefix_bytes) - const char *to_print; - int prefix_bytes; -{ - int printed_len; - const char *s; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps; - const char *end; - size_t tlen; - int width, w; - wchar_t wc; - - end = to_print + strlen (to_print) + 1; - memset (&ps, 0, sizeof (mbstate_t)); -#endif - - printed_len = 0; - - /* Don't print only the ellipsis if the common prefix is one of the - possible completions */ - if (to_print[prefix_bytes] == '\0') - prefix_bytes = 0; - - if (prefix_bytes) - { - char ellipsis; - - ellipsis = (to_print[prefix_bytes] == '.') ? '_' : '.'; - for (w = 0; w < ELLIPSIS_LEN; w++) - putc (ellipsis, rl_outstream); - printed_len = ELLIPSIS_LEN; - } - - s = to_print + prefix_bytes; - 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 = mbrtowc (&wc, s, end - s, &ps); - if (MB_INVALIDCH (tlen)) - { - tlen = 1; - width = 1; - memset (&ps, 0, sizeof (mbstate_t)); - } - else if (MB_NULLWCH (tlen)) - break; - else - { - w = wcwidth (wc); - width = (w >= 0) ? w : 1; - } - fwrite (s, 1, tlen, rl_outstream); - s += tlen; - printed_len += width; -#else - putc (*s, rl_outstream); - s++; - printed_len++; -#endif - } - } - - 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, prefix_bytes) - char *to_print, *full_pathname; - int prefix_bytes; -{ - int printed_len, extension_char, slen, tlen; - char *s, c, *new_full_pathname, *dn; - - extension_char = 0; - printed_len = fnprint (to_print, prefix_bytes); - -#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 `/'. */ - if (full_pathname == 0 || *full_pathname == 0) - dn = "/"; - else if (full_pathname[0] != '/') - dn = full_pathname; - else if (full_pathname[1] == 0) - dn = "//"; /* restore trailing slash to `//' */ - else if (full_pathname[1] == '/' && full_pathname[2] == 0) - dn = "/"; /* don't turn /// into // */ - else - dn = full_pathname; - s = tilde_expand (dn); - 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); - if (s[slen - 1] == '/') - slen--; - else - new_full_pathname[slen] = '/'; - 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 (s)) - 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. */ - for (scan = pass_next = 0; scan < end; scan = MB_NEXTCHAR (rl_line_buffer, scan, 1, MB_FIND_ANY)) - { - 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. */ - while (rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_ANY)) - { - 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; - - 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); - } - } - - /* XXX -- filename dequoting moved into rl_filename_completion_function */ - - matches = rl_completion_matches (text, our_func); - 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 && rl_sort_completion_matches) - 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; - 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) ((char *)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, common_length, sind; - char *temp, *t; - - /* Find the length of the prefix common to all items: length as displayed - characters (common_length) and as a byte index into the matches (sind) */ - common_length = sind = 0; - if (_rl_completion_prefix_display_length > 0) - { - t = printable_part (matches[0]); - temp = strrchr (t, '/'); - common_length = temp ? fnwidth (temp) : fnwidth (t); - sind = temp ? strlen (temp) : strlen (t); - - if (common_length > _rl_completion_prefix_display_length && common_length > ELLIPSIS_LEN) - max -= common_length - ELLIPSIS_LEN; - else - common_length = sind = 0; - } - - /* 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 && rl_sort_completion_matches) - 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], sind); - - 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], sind); - /* 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], 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 (rl_completion_query_items > 0 && len >= rl_completion_query_items) - { - rl_crlf (); - fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len); - fflush (rl_outstream); - if ((completion_y_or_n = 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 /* && rl_completion_suppress_append == 0 */) - { - /* 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); - _rl_reset_completion_state (); - 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); - _rl_reset_completion_state (); - 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: - _rl_ttymsg ("bad value %d for what_to_do in rl_complete", what_to_do); - rl_ding (); - FREE (saved_line_buffer); - RL_UNSETSTATE(RL_STATE_COMPLETING); - _rl_reset_completion_state (); - 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); - _rl_reset_completion_state (); - 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 (); - } - -#if defined (HAVE_GETPWENT) - while (entry = getpwent ()) - { - /* Null usernames should result in all users as possible completions. */ - if (namelen == 0 || (STREQN (username, entry->pw_name, namelen))) - break; - } -#endif - - if (entry == 0) - { -#if defined (HAVE_GETPWENT) - endpwent (); -#endif - 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); - - /* The directory completion hook should perform any necessary - dequoting. */ - if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&dirname)) - { - free (users_dirname); - users_dirname = savestring (dirname); - } - else if (rl_completion_found_quote && rl_filename_dequoting_function) - { - /* delete single and double quotes */ - temp = (*rl_filename_dequoting_function) (users_dirname, rl_completion_quote_character); - free (users_dirname); - users_dirname = temp; - } - directory = opendir (dirname); - - /* Now dequote a non-null filename. */ - if (filename && *filename && rl_completion_found_quote && rl_filename_dequoting_function) - { - /* delete single and double quotes */ - temp = (*rl_filename_dequoting_function) (filename, rl_completion_quote_character); - free (filename); - filename = temp; - } - 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_old_menu_complete (count, invoking_key) - int count, invoking_key; -{ - 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; - - rl_completion_invoking_key = invoking_key; - - /* Only the completion entry function can change these. */ - set_completion_defaults ('%'); - - our_func = rl_menu_completion_entry_function; - if (our_func == 0) - 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. */ - - if (match_list_size > 1 && _rl_complete_show_all) - display_matches (matches); - } - - /* 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 += count; - if (match_list_index < 0) - match_list_index += match_list_size; - else - 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); -} - -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 nontrivial_lcd = 0; - static int full_completion = 0; /* set to 1 if menu completion should reinitialize on next call */ - 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 || full_completion) - { - /* 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; - - full_completion = 0; - - /* Only the completion entry function can change these. */ - set_completion_defaults ('%'); - - our_func = rl_menu_completion_entry_function; - if (our_func == 0) - 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); - - nontrivial_lcd = matches && strcmp (orig_text, matches[0]) != 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. */ - 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++) - ; - - if (match_list_size == 0) - { - rl_ding (); - FREE (matches); - matches = (char **)0; - match_list_index = 0; - completion_changed_buffer = 0; - return (0); - } - - /* matches[0] is lcd if match_list_size > 1, but the circular buffer - code below should take care of it. */ - if (*matches[0]) - { - insert_match (matches[0], orig_start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char); - orig_end = orig_start + strlen (matches[0]); - completion_changed_buffer = STREQ (orig_text, matches[0]) == 0; - } - - if (match_list_size > 1 && _rl_complete_show_all) - { - display_matches (matches); - /* If there are so many matches that the user has to be asked - whether or not he wants to see the matches, menu completion - is unwieldy. */ - if (rl_completion_query_items > 0 && match_list_size >= rl_completion_query_items) - { - rl_ding (); - FREE (matches); - matches = (char **)0; - full_completion = 1; - return (0); - } - } - else if (match_list_size <= 1) - { - append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd); - full_completion = 1; - return (0); - } - } - - /* 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 += count; - if (match_list_index < 0) - match_list_index += match_list_size; - else - match_list_index %= match_list_size; - - if (match_list_index == 0 && match_list_size > 1) - { - rl_ding (); - insert_match (matches[0], 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.new b/lib/readline/display.c.new deleted file mode 100644 index 1742f507f..000000000 --- a/lib/readline/display.c.new +++ /dev/null @@ -1,2619 +0,0 @@ -/* display.c -- readline redisplay facility. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#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__ */ - -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)); - -/* State of visible and invisible lines. */ -struct line_state - { - char *line; - int *lbreaks; - int lbsize; -#if defined (HANDLE_MULTIBYTE) - int *wrapped_line; - int wbsize; -#endif - }; - -/* The line display buffers. One is the line currently displayed on - the screen. The other is the line about to be displayed. */ -static struct line_state line_state_array[2]; -static struct line_state *line_state_visible = &line_state_array[0]; -static struct line_state *line_state_invisible = &line_state_array[1]; -static int line_structures_initialized = 0; - -/* Backwards-compatible names. */ -#define inv_lbreaks (line_state_invisible->lbreaks) -#define inv_lbsize (line_state_invisible->lbsize) -#define vis_lbreaks (line_state_visible->lbreaks) -#define vis_lbsize (line_state_visible->lbsize) - -#define visible_line (line_state_visible->line) -#define invisible_line (line_state_invisible->line) - -#if defined (HANDLE_MULTIBYTE) -static int _rl_col_width PARAMS((const char *, int, int)); -#else -# define _rl_col_width(l, s, e) (((e) <= (s)) ? 0 : (e) - (s)) -#endif - -/* 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. CUR - and NEW are either both buffer positions or absolute screen positions. */ -#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new))) - -/* _rl_last_c_pos is an absolute cursor position in multibyte locales and a - buffer index in others. This macro is used when deciding whether the - current cursor position is in the middle of a prompt string containing - invisible characters. XXX - might need to take `modmark' into account. */ -#define PROMPT_ENDING_INDEX \ - ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) ? prompt_physical_chars : prompt_last_invisible+1) - - -/* **************************************************************** */ -/* */ -/* 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; -int _rl_want_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. */ -/* NOTE: _rl_last_c_pos is used as a buffer index when not in a locale - supporting multibyte characters, and an absolute cursor position when - in such a locale. This is an artifact of the donated multibyte support. - Care must be taken when modifying its value. */ -int _rl_last_c_pos = 0; -int _rl_last_v_pos = 0; - -static int cpos_adjusted; -static int cpos_buffer_position; -static int prompt_multibyte_chars; - -/* 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; - -/* 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 local_prompt_len; -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; - -/* set to a non-zero value by rl_redisplay if we are marking modified history - lines and the current line is so marked. */ -static int modmark; - -/* Variables to save and restore prompt and display information. */ - -/* 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_prefix_length; -static int saved_local_length; -static int saved_invis_chars_first_line; -static int saved_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, *igstart; - int l, rl, last, ignoring, ninvis, invfl, invflset, 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 */ - invflset = 0; /* we only want to set invfl once */ - - igstart = 0; - 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 (ignoring == 0 && *p == RL_PROMPT_START_IGNORE) /* XXX - check ignoring? */ - { - ignoring = 1; - igstart = p; - continue; - } - else if (ignoring && *p == RL_PROMPT_END_IGNORE) - { - ignoring = 0; - if (p != (igstart + 1)) - 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 ends up being assigned to prompt_visible_length, - which is the number of characters in the buffer that - contribute to characters on the screen, which might - not be the same as the number of physical characters - on the screen in the presence of multibyte characters */ - rl += ind - pind; - physchars += _rl_col_width (pmt, pind, ind); - } - else - ninvis += ind - pind; - p--; /* compensate for later increment */ - } - else -#endif - { - *r++ = *p; - if (!ignoring) - { - rl++; /* visible length byte counter */ - physchars++; - } - else - ninvis++; /* invisible chars byte counter */ - } - - if (invflset == 0 && rl >= _rl_screenwidth) - { - invfl = ninvis; - invflset = 1; - } - } - } - - 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; - local_prompt_len = 0; - prompt_last_invisible = prompt_invis_chars_first_line = 0; - prompt_visible_length = prompt_physical_chars = 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; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - return (prompt_visible_length); - } - else - { - /* The prompt spans multiple lines. */ - t = ++p; - local_prompt = expand_prompt (p, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - 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, - (int *)NULL, - (int *)NULL); - *t = c; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - 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; - -#if defined (HANDLE_MULTIBYTE) - line_state_visible->wbsize = vis_lbsize; - line_state_visible->wrapped_line = (int *)xmalloc (line_state_visible->wbsize * sizeof (int)); - - line_state_invisible->wbsize = inv_lbsize; - line_state_invisible->wrapped_line = (int *)xmalloc (line_state_invisible->wbsize * sizeof (int)); -#endif - - inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int)); - vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int)); - inv_lbreaks[0] = vis_lbreaks[0] = 0; - } - - line_structures_initialized = 1; -} - -/* Basic redisplay algorithm. */ -void -rl_redisplay () -{ - register int in, out, c, linenum, cursor_linenum; - register char *line; - int inv_botlin, lb_botlin, lb_linenum, o_cpos; - int newlines, lpos, temp, n0, num, prompt_lines_estimate; - 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 (_rl_echoing_p == 0) - return; - - /* Block keyboard interrupts because this function manipulates global - data structures. */ - _rl_block_sigint (); - - if (!rl_display_prompt) - rl_display_prompt = ""; - - if (line_structures_initialized == 0) - { - init_line_structures (0); - rl_on_new_line (); - } - - /* Draw the line into the buffer. */ - cpos_buffer_position = -1; - - prompt_multibyte_chars = prompt_visible_length - prompt_physical_chars; - - 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) - { - if (local_prompt_prefix && forced_display) - _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix)); - - if (local_prompt_len > 0) - { - temp = local_prompt_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_prompt_len); - out += local_prompt_len; - } - line[out] = '\0'; - wrap_offset = local_prompt_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)); \ - } \ - inv_lbreaks[++newlines] = out; \ - if (newlines >= (line_state_invisible->wbsize - 1)) \ - { \ - line_state_invisible->wbsize *= 2; \ - line_state_invisible->wrapped_line = (int *)xrealloc (line_state_invisible->wrapped_line, line_state_invisible->wbsize * sizeof(int)); \ - } \ - line_state_invisible->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; - lpos = prompt_physical_chars + modmark; - -#if defined (HANDLE_MULTIBYTE) - memset (line_state_invisible->wrapped_line, 0, line_state_invisible->wbsize * sizeof (int)); - num = 0; -#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 (or, more generally, last) line. */ - - /* This is zero-based, used to set the newlines */ - prompt_lines_estimate = lpos / _rl_screenwidth; - - /* what if lpos is already >= _rl_screenwidth before we start drawing the - contents of the command line? */ - while (lpos >= _rl_screenwidth) - { - int z; - /* 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 */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0) - { - n0 = num; - temp = local_prompt_len; - while (num < temp) - { - z = _rl_col_width (local_prompt, n0, num); - if (z > _rl_screenwidth) - { - num = _rl_find_prev_mbchar (local_prompt, num, MB_FIND_ANY); - break; - } - else if (z == _rl_screenwidth) - break; - num++; - } - temp = num; - } - else -#endif /* !HANDLE_MULTIBYTE */ - temp = ((newlines + 1) * _rl_screenwidth); - - /* Now account for invisible characters in the current line. */ - /* XXX - this assumes that the invisible characters may be split, but only - between the first and the last lines. */ - temp += ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line - : ((newlines == prompt_lines_estimate) ? wrap_offset : prompt_invis_chars_first_line)) - : ((newlines == 0) ? wrap_offset : 0)); - - inv_lbreaks[++newlines] = temp; -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0) - lpos -= _rl_col_width (local_prompt, n0, num); - else -#endif - 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 (cpos_buffer_position), 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) - { - cpos_buffer_position = 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) - { - cpos_buffer_position = 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 (cpos_buffer_position < 0) - { - cpos_buffer_position = out; - lb_linenum = newlines; - } - - inv_botlin = lb_botlin = newlines; - CHECK_INV_LBREAKS (); - inv_lbreaks[newlines+1] = out; - cursor_linenum = lb_linenum; - - /* CPOS_BUFFER_POSITION == 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, tx; - - 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 INVIS_FIRST() (prompt_physical_chars > _rl_screenwidth ? prompt_invis_chars_first_line : wrap_offset) -#define WRAP_OFFSET(line, offset) ((line == 0) \ - ? (offset ? INVIS_FIRST() : 0) \ - : ((line == prompt_last_screen_line) ? wrap_offset-prompt_invis_chars_first_line : 0)) -#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++) - { - /* This can lead us astray if we execute a program that changes - the locale from a non-multibyte to a multibyte one. */ - o_cpos = _rl_last_c_pos; - cpos_adjusted = 0; - update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum, - VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin); - - /* update_line potentially changes _rl_last_c_pos, but doesn't - take invisible characters into account, since _rl_last_c_pos - is an absolute cursor position in a multibyte locale. See - if compensating here is the right thing, or if we have to - change update_line itself. There are several cases in which - update_line adjusts _rl_last_c_pos itself (so it can pass - _rl_move_cursor_relative accurate values); it communicates - this back by setting cpos_adjusted. If we assume that - _rl_last_c_pos is correct (an absolute cursor position) each - time update_line is called, then we can assume in our - calculations that o_cpos does not need to be adjusted by - wrap_offset. */ - if (linenum == 0 && (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > wrap_offset && - o_cpos < prompt_last_invisible) - _rl_last_c_pos -= prompt_invis_chars_first_line; /* XXX - was wrap_offset */ - else if (linenum == prompt_last_screen_line && prompt_physical_chars > _rl_screenwidth && - (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > (prompt_last_invisible - _rl_screenwidth - prompt_invis_chars_first_line)) - _rl_last_c_pos -= (wrap_offset-prompt_invis_chars_first_line); - - /* 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)) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - nleft = _rl_screenwidth - _rl_last_c_pos; - else - nleft = _rl_screenwidth + wrap_offset - _rl_last_c_pos; - if (nleft) - _rl_clear_to_eol (nleft); - } -#if 0 - /* This segment is intended to handle the case where the prompt - has invisible characters on the second line and the new line - to be displayed needs to clear the rest of the old characters - out (e.g., when printing the i-search prompt). In general, - the case of the new line being shorter than the old. - Incomplete */ - else if (linenum == prompt_last_screen_line && - prompt_physical_chars > _rl_screenwidth && - wrap_offset != prompt_invis_chars_first_line && - _rl_last_c_pos == out && -#endif - - - /* 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 ((MB_CUR_MAX == 1 || rl_byte_oriented) && 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 && -#if 0 - _rl_last_c_pos <= PROMPT_ENDING_INDEX && local_prompt) -#else - _rl_last_c_pos < PROMPT_ENDING_INDEX && local_prompt) -#endif - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - if (_rl_term_cr) - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - if (modmark) - _rl_output_some_chars ("*", 1); - - _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) - wrap_offset + modmark; - else - _rl_last_c_pos = nleft + modmark; - } - - /* 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 desired cursor position. */ - nleft = cpos_buffer_position - pos; - - /* NLEFT is now a number of characters in a buffer. When in a - multibyte locale, however, _rl_last_c_pos is an absolute cursor - position that doesn't take invisible characters in the prompt - into account. We use a fudge factor to compensate. */ - - /* 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) - { - /* TX == new physical cursor position in multibyte locale. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - tx = _rl_col_width (&visible_line[pos], 0, nleft) - visible_wrap_offset; - else - tx = nleft; - if (tx >= 0 && _rl_last_c_pos > tx) - { - _rl_backspace (_rl_last_c_pos - tx); /* XXX */ - _rl_last_c_pos = tx; - } - } - - /* We need to note that in a multibyte locale we are dealing with - _rl_last_c_pos as an absolute cursor position, but moving to a - point specified by a buffer position (NLEFT) that doesn't take - invisible characters into account. */ - 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 = cpos_buffer_position - 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 = cpos_buffer_position - (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 = cpos_buffer_position - (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 = ((cpos_buffer_position - 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 (cpos_buffer_position - lmargin, &invisible_line[lmargin]); - last_lmargin = lmargin; - } - } - fflush (rl_outstream); - - /* Swap visible and non-visible lines. */ - { - struct line_state *vtemp = line_state_visible; - - line_state_visible = line_state_invisible; - line_state_invisible = vtemp; - - 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; - } - - _rl_release_sigint (); -} - -/* 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, twidth, o_cpos; - int current_invis_chars; - int col_lendiff, col_temp; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps_new, ps_old; - int new_offset, old_offset; -#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. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - temp = _rl_last_c_pos; - else - temp = _rl_last_c_pos - WRAP_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 (current_line < line_state_visible->wbsize && line_state_visible->wrapped_line[current_line] > 0) - _rl_clear_to_eol (line_state_visible->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; - _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) /* adding at the end */ - { - 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 ((MB_CUR_MAX == 1 || rl_byte_oriented) && 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_len; - 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_ENDING_INDEX) - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - if (modmark) - _rl_output_some_chars ("*", 1); - _rl_output_some_chars (local_prompt, lendiff); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - /* We take wrap_offset into account here so we can pass correct - information to _rl_move_cursor_relative. */ - _rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff) - wrap_offset + modmark; - cpos_adjusted = 1; - } - else - _rl_last_c_pos = lendiff + modmark; - } - - o_cpos = _rl_last_c_pos; - - /* When this function returns, _rl_last_c_pos is correct, and an absolute - cursor postion in multibyte mode, but a buffer index when not in a - multibyte locale. */ - _rl_move_cursor_relative (od, old); -#if 1 -#if defined (HANDLE_MULTIBYTE) - /* We need to indicate that the cursor position is correct in the presence of - invisible characters in the prompt string. Let's see if setting this when - we make sure we're at the end of the drawn prompt string works. */ - if (current_line == 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0 && - (_rl_last_c_pos > 0 || o_cpos > 0) && - _rl_last_c_pos == prompt_physical_chars) - cpos_adjusted = 1; -#endif -#endif - - /* 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; - /* If col_lendiff is > 0, implying that the new string takes up more - screen real estate than the old, but lendiff is < 0, meaning that it - takes fewer bytes, we need to just output the characters starting - from the first difference. These will overwrite what is on the - display, so there's no reason to do a smart update. This can really - only happen in a multibyte environment. */ - if (lendiff < 0) - { - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += _rl_col_width (nfd, 0, temp); - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - return; - } - /* 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. */ - else 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 ((MB_CUR_MAX == 1 || rl_byte_oriented != 0) && *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 - { - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - 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); - /* 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. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - twidth = _rl_col_width (nfd+lendiff, 0, temp-col_lendiff); - else - twidth = temp - lendiff; - _rl_last_c_pos += twidth; - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - } - else - { - /* cannot insert chars, write to EOL */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - /* If we're in a multibyte locale and were before the last invisible - char in the current line (which implies we just output some invisible - characters) we need to adjust _rl_last_c_pos, since it represents - a physical character position. */ - if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - current_line == prompt_last_screen_line && wrap_offset && - wrap_offset != prompt_invis_chars_first_line && - ((nfd-new) < (prompt_last_invisible-(current_line*_rl_screenwidth)))) - { - _rl_last_c_pos -= wrap_offset - prompt_invis_chars_first_line; - cpos_adjusted = 1; - } - } - } - 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) - { - /* If nfd begins at the prompt, or before the invisible - characters in the prompt, we need to adjust _rl_last_c_pos - in a multibyte locale to account for the wrap offset and - set cpos_adjusted accordingly. */ - _rl_output_some_chars (nfd, temp); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - _rl_last_c_pos += _rl_col_width (nfd, 0, temp); - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - else - _rl_last_c_pos += temp; - } - } - /* Otherwise, print over the existing material. */ - else - { - if (temp > 0) - { - /* If nfd begins at the prompt, or before the invisible - characters in the prompt, we need to adjust _rl_last_c_pos - in a multibyte locale to account for the wrap offset and - set cpos_adjusted accordingly. */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; /* XXX */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - } - 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 0 - if (col_lendiff) -#else - /* If we've already printed over the entire width of the screen, - including the old material, then col_lendiff doesn't matter and - space_to_eol will insert too many spaces. XXX - maybe we should - adjust col_lendiff based on the difference between _rl_last_c_pos - and _rl_screenwidth */ - if (col_lendiff && (_rl_last_c_pos < _rl_screenwidth)) -#endif - { - 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. rl_expand_prompt must have already been called - (explicitly or implicitly). This still doesn't work exactly right. */ -int -rl_on_new_line_with_prompt () -{ - int prompt_size, i, l, real_screenwidth, newlines; - char *prompt_last_line, *lprompt; - - /* 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. */ - lprompt = local_prompt ? local_prompt : rl_prompt; - strcpy (visible_line, lprompt); - strcpy (invisible_line, lprompt); - - /* 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); /* XXX */ - 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 () -{ - register char *temp; - - if (visible_line) - { - 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. - (Well, when we don't have multibyte characters, _rl_last_c_pos is a - buffer index.) - 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; - int woff; /* number of invisible chars on current line */ - int cpos, dpos; /* current and desired cursor positions */ - - woff = WRAP_OFFSET (_rl_last_v_pos, wrap_offset); - cpos = _rl_last_c_pos; -#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. We need to account for invisible characters in this line, - as long as we are past them and they are counted by _rl_col_width. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - dpos = _rl_col_width (data, 0, new); - /* Use NEW when comparing against the last invisible character in the - prompt string, since they're both buffer indices and DPOS is a - desired display position. */ - if ((new > prompt_last_invisible) || /* XXX - don't use woff here */ - (prompt_physical_chars > _rl_screenwidth && - _rl_last_v_pos == prompt_last_screen_line && - wrap_offset != woff && - new > (prompt_last_invisible-(_rl_screenwidth*_rl_last_v_pos)-wrap_offset))) - /* XXX last comparison might need to be >= */ - { - dpos -= woff; - /* Since this will be assigned to _rl_last_c_pos at the end (more - precisely, _rl_last_c_pos == dpos when this function returns), - let the caller know. */ - cpos_adjusted = 1; - } - } - else -#endif - dpos = new; - - /* If we don't have to do anything, then return. */ - if (cpos == dpos) - return; - - /* It may be faster to output a CR, and then move forwards instead - of moving backwards. */ - /* i == current physical cursor position. */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - i = _rl_last_c_pos; - else -#endif - i = _rl_last_c_pos - woff; - if (dpos == 0 || CR_FASTER (dpos, _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__ */ - cpos = _rl_last_c_pos = 0; - } - - if (cpos < dpos) - { - /* 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. */ - - /* However, we need a handle on where the current display position is - in the buffer for the immediately preceding comment to be true. - In multibyte locales, we don't currently have that info available. - Without it, we don't know where the data we have to display begins - in the buffer and we have to go back to the beginning of the screen - line. In this case, we can use the terminal sequence to move forward - if it's available. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (_rl_term_forward_char) - { - for (i = cpos; i < dpos; i++) - tputs (_rl_term_forward_char, 1, _rl_output_character_function); - } - else - { - tputs (_rl_term_cr, 1, _rl_output_character_function); - for (i = 0; i < new; i++) - putc (data[i], rl_outstream); - } - } - else - for (i = cpos; i < new; i++) - putc (data[i], rl_outstream); - } - -#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. */ -#endif - else if (cpos > dpos) - _rl_backspace (cpos - dpos); - - _rl_last_c_pos = dpos; -} - -/* 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. */ -static int msg_saved_prompt = 0; - -#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); - - if (saved_local_prompt == 0) - { - rl_save_prompt (); - msg_saved_prompt = 1; - } - rl_display_prompt = msg_buf; - local_prompt = expand_prompt (msg_buf, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)NULL; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - (*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; - if (saved_local_prompt == 0) - { - rl_save_prompt (); - msg_saved_prompt = 1; - } - local_prompt = expand_prompt (msg_buf, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)NULL; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - (*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; - if (msg_saved_prompt) - { - rl_restore_prompt (); - msg_saved_prompt = 0; - } - (*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; -} - -void -rl_save_prompt () -{ - saved_local_prompt = local_prompt; - saved_local_prefix = local_prompt_prefix; - saved_prefix_length = prompt_prefix_length; - saved_local_length = local_prompt_len; - 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; - local_prompt_len = 0; - prompt_last_invisible = prompt_visible_length = prompt_prefix_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; - local_prompt_len = saved_local_length; - prompt_prefix_length = saved_prefix_length; - 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; - - /* can test saved_local_prompt to see if prompt info has been saved. */ - saved_local_prompt = saved_local_prefix = (char *)0; - saved_local_length = 0; - saved_last_invisible = saved_visible_length = saved_prefix_length = 0; - saved_invis_chars_first_line = saved_physical_chars = 0; -} - -char * -_rl_make_prompt_for_search (pchar) - int pchar; -{ - int len; - char *pmt, *p; - - rl_save_prompt (); - - /* We've saved the prompt, and can do anything with the various prompt - strings we need before they're restored. We want the unexpanded - portion of the prompt string after any final newline. */ - p = rl_prompt ? strrchr (rl_prompt, '\n') : 0; - if (p == 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 - { - p++; - len = strlen (p); - pmt = (char *)xmalloc (len + 2); - if (len) - strcpy (pmt, p); - pmt[len] = pchar; - pmt[len+1] = '\0'; - } - - /* will be overwritten by expand_prompt, called from rl_message */ - prompt_physical_chars = saved_physical_chars + 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; -{ -#if defined (__MSDOS__) || defined (__MINGW32__) - _rl_output_some_chars (string, count); -#else - /* DEBUGGING */ - if (MB_CUR_MAX == 1 || rl_byte_oriented) - if (count != col) - _rl_ttymsg ("debug: insert_some_chars: count (%d) != col (%d)", 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); - } -#endif /* __MSDOS__ || __MINGW32__ */ -} - -/* Delete COUNT characters from the display line. */ -static void -delete_chars (count) - int count; -{ - if (count > _rl_screenwidth) /* XXX */ - return; - -#if !defined (__MSDOS__) && !defined (__MINGW32__) - 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); - } -#endif /* !__MSDOS__ && !__MINGW32__ */ -} - -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]]; - cpos_buffer_position = -1; /* don't know where we are in buffer */ - _rl_move_cursor_relative (_rl_screenwidth - 1, last_line); /* XXX */ - _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; - - oldp = rl_display_prompt; - rl_save_prompt (); - - 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; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - - rl_forced_update_display (); - - rl_display_prompt = oldp; - rl_restore_prompt(); -} - -/* Redisplay the current line after a SIGWINCH is received. */ -void -_rl_redisplay_after_sigwinch () -{ - char *t; - - /* Clear the last line (assuming that the screen size change will result in - either more or fewer characters on that line only) 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) - { - _rl_move_vert (_rl_vis_botlin); - -#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 (_rl_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; - int tmp, point, width, max; - - if (end <= start) - return 0; - if (MB_CUR_MAX == 1 || rl_byte_oriented) -{ -_rl_ttymsg ("_rl_col_width: called with MB_CUR_MAX == 1"); - return (end - start); -} - - memset (&ps, 0, sizeof (mbstate_t)); - - 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/display.c.save b/lib/readline/display.c.save deleted file mode 100644 index d98e6ef26..000000000 --- a/lib/readline/display.c.save +++ /dev/null @@ -1,2610 +0,0 @@ -/* display.c -- readline redisplay facility. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#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__ */ - -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)); - -/* State of visible and invisible lines. */ -struct line_state - { - char *line; - int *lbreaks; - int lbsize; -#if defined (HANDLE_MULTIBYTE) - int *wrapped_line; - int wbsize; -#endif - }; - -/* The line display buffers. One is the line currently displayed on - the screen. The other is the line about to be displayed. */ -static struct line_state line_state_array[2]; -static struct line_state *line_state_visible = &line_state_array[0]; -static struct line_state *line_state_invisible = &line_state_array[1]; -static int line_structures_initialized = 0; - -/* Backwards-compatible names. */ -#define inv_lbreaks (line_state_invisible->lbreaks) -#define inv_lbsize (line_state_invisible->lbsize) -#define vis_lbreaks (line_state_visible->lbreaks) -#define vis_lbsize (line_state_visible->lbsize) - -#define visible_line (line_state_visible->line) -#define invisible_line (line_state_invisible->line) - -#if defined (HANDLE_MULTIBYTE) -static int _rl_col_width PARAMS((const char *, int, int)); -#else -# define _rl_col_width(l, s, e) (((e) <= (s)) ? 0 : (e) - (s)) -#endif - -/* 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. CUR - and NEW are either both buffer positions or absolute screen positions. */ -#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new))) - -/* _rl_last_c_pos is an absolute cursor position in multibyte locales and a - buffer index in others. This macro is used when deciding whether the - current cursor position is in the middle of a prompt string containing - invisible characters. XXX - might need to take `modmark' into account. */ -#define PROMPT_ENDING_INDEX \ - ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) ? prompt_physical_chars : prompt_last_invisible+1) - - -/* **************************************************************** */ -/* */ -/* 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; -int _rl_want_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. */ -/* NOTE: _rl_last_c_pos is used as a buffer index when not in a locale - supporting multibyte characters, and an absolute cursor position when - in such a locale. This is an artifact of the donated multibyte support. - Care must be taken when modifying its value. */ -int _rl_last_c_pos = 0; -int _rl_last_v_pos = 0; - -static int cpos_adjusted; -static int cpos_buffer_position; -static int prompt_multibyte_chars; - -/* 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; - -/* 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 local_prompt_len; -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; - -/* set to a non-zero value by rl_redisplay if we are marking modified history - lines and the current line is so marked. */ -static int modmark; - -/* Variables to save and restore prompt and display information. */ - -/* 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_prefix_length; -static int saved_local_length; -static int saved_invis_chars_first_line; -static int saved_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, *igstart; - int l, rl, last, ignoring, ninvis, invfl, invflset, 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 */ - invflset = 0; /* we only want to set invfl once */ - - igstart = 0; - 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 (ignoring == 0 && *p == RL_PROMPT_START_IGNORE) /* XXX - check ignoring? */ - { - ignoring = 1; - igstart = p; - continue; - } - else if (ignoring && *p == RL_PROMPT_END_IGNORE) - { - ignoring = 0; - if (p != (igstart + 1)) - 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 ends up being assigned to prompt_visible_length, - which is the number of characters in the buffer that - contribute to characters on the screen, which might - not be the same as the number of physical characters - on the screen in the presence of multibyte characters */ - rl += ind - pind; - physchars += _rl_col_width (pmt, pind, ind); - } - else - ninvis += ind - pind; - p--; /* compensate for later increment */ - } - else -#endif - { - *r++ = *p; - if (!ignoring) - { - rl++; /* visible length byte counter */ - physchars++; - } - else - ninvis++; /* invisible chars byte counter */ - } - - if (invflset == 0 && rl >= _rl_screenwidth) - { - invfl = ninvis; - invflset = 1; - } - } - } - - 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; - local_prompt_len = 0; - prompt_last_invisible = prompt_invis_chars_first_line = 0; - prompt_visible_length = prompt_physical_chars = 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; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - return (prompt_visible_length); - } - else - { - /* The prompt spans multiple lines. */ - t = ++p; - local_prompt = expand_prompt (p, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - 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, - (int *)NULL, - (int *)NULL); - *t = c; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - 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; - -#if defined (HANDLE_MULTIBYTE) - line_state_visible->wbsize = vis_lbsize; - line_state_visible->wrapped_line = (int *)xmalloc (line_state_visible->wbsize * sizeof (int)); - - line_state_invisible->wbsize = inv_lbsize; - line_state_invisible->wrapped_line = (int *)xmalloc (line_state_invisible->wbsize * sizeof (int)); -#endif - - inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int)); - vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int)); - inv_lbreaks[0] = vis_lbreaks[0] = 0; - } - - line_structures_initialized = 1; -} - -/* Basic redisplay algorithm. */ -void -rl_redisplay () -{ - register int in, out, c, linenum, cursor_linenum; - register char *line; - int inv_botlin, lb_botlin, lb_linenum, o_cpos; - int newlines, lpos, temp, n0, num, prompt_lines_estimate; - 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 (_rl_echoing_p == 0) - return; - - /* Block keyboard interrupts because this function manipulates global - data structures. */ - _rl_block_sigint (); - - if (!rl_display_prompt) - rl_display_prompt = ""; - - if (line_structures_initialized == 0) - { - init_line_structures (0); - rl_on_new_line (); - } - - /* Draw the line into the buffer. */ - cpos_buffer_position = -1; - - prompt_multibyte_chars = prompt_visible_length - prompt_physical_chars; - - 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) - { - if (local_prompt_prefix && forced_display) - _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix)); - - if (local_prompt_len > 0) - { - temp = local_prompt_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_prompt_len); - out += local_prompt_len; - } - line[out] = '\0'; - wrap_offset = local_prompt_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)); \ - } \ - inv_lbreaks[++newlines] = out; \ - if (newlines >= (line_state_invisible->wbsize - 1)) \ - { \ - line_state_invisible->wbsize *= 2; \ - line_state_invisible->wrapped_line = (int *)xrealloc (line_state_invisible->wrapped_line, line_state_invisible->wbsize * sizeof(int)); \ - } \ - line_state_invisible->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; - lpos = prompt_physical_chars + modmark; - -#if defined (HANDLE_MULTIBYTE) - memset (line_state_invisible->wrapped_line, 0, line_state_invisible->wbsize * sizeof (int)); - num = 0; -#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 (or, more generally, last) line. */ - - /* This is zero-based, used to set the newlines */ - prompt_lines_estimate = lpos / _rl_screenwidth; - - /* what if lpos is already >= _rl_screenwidth before we start drawing the - contents of the command line? */ - while (lpos >= _rl_screenwidth) - { - int z; - /* 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 */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0) - { - n0 = num; - temp = local_prompt_len; - while (num < temp) - { - z = _rl_col_width (local_prompt, n0, num); - if (z > _rl_screenwidth) - { - num = _rl_find_prev_mbchar (local_prompt, num, MB_FIND_ANY); - break; - } - else if (z == _rl_screenwidth) - break; - num++; - } - temp = num; - } - else -#endif /* !HANDLE_MULTIBYTE */ - temp = ((newlines + 1) * _rl_screenwidth); - - /* Now account for invisible characters in the current line. */ - /* XXX - this assumes that the invisible characters may be split, but only - between the first and the last lines. */ - temp += ((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; -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0) - lpos -= _rl_col_width (local_prompt, n0, num); - else -#endif - 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 (cpos_buffer_position), 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) - { - cpos_buffer_position = 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) - { - cpos_buffer_position = 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 (cpos_buffer_position < 0) - { - cpos_buffer_position = out; - lb_linenum = newlines; - } - - inv_botlin = lb_botlin = newlines; - CHECK_INV_LBREAKS (); - inv_lbreaks[newlines+1] = out; - cursor_linenum = lb_linenum; - - /* CPOS_BUFFER_POSITION == 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, tx; - - 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 INVIS_FIRST() (prompt_physical_chars > _rl_screenwidth ? prompt_invis_chars_first_line : wrap_offset) -#define WRAP_OFFSET(line, offset) ((line == 0) \ - ? (offset ? INVIS_FIRST() : 0) \ - : ((line == prompt_last_screen_line) ? wrap_offset-prompt_invis_chars_first_line : 0)) -#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++) - { - /* This can lead us astray if we execute a program that changes - the locale from a non-multibyte to a multibyte one. */ - o_cpos = _rl_last_c_pos; - cpos_adjusted = 0; - update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum, - VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin); - - /* update_line potentially changes _rl_last_c_pos, but doesn't - take invisible characters into account, since _rl_last_c_pos - is an absolute cursor position in a multibyte locale. See - if compensating here is the right thing, or if we have to - change update_line itself. There is one case in which - update_line adjusts _rl_last_c_pos itself (so it can pass - _rl_move_cursor_relative accurate values); it communicates - this back by setting cpos_adjusted. If we assume that - _rl_last_c_pos is correct (an absolute cursor position) each - time update_line is called, then we can assume in our - calculations that o_cpos does not need to be adjusted by - wrap_offset. */ - if (linenum == 0 && (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > wrap_offset && - o_cpos < prompt_last_invisible) - _rl_last_c_pos -= prompt_invis_chars_first_line; /* XXX - was wrap_offset */ - else if (linenum == prompt_last_screen_line && prompt_physical_chars > _rl_screenwidth && - (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > (prompt_last_invisible - _rl_screenwidth - prompt_invis_chars_first_line)) - _rl_last_c_pos -= (wrap_offset-prompt_invis_chars_first_line); - - /* 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)) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - nleft = _rl_screenwidth - _rl_last_c_pos; - else - nleft = _rl_screenwidth + wrap_offset - _rl_last_c_pos; - if (nleft) - _rl_clear_to_eol (nleft); - } -#if 0 - /* This segment is intended to handle the case where the prompt - has invisible characters on the second line and the new line - to be displayed needs to clear the rest of the old characters - out (e.g., when printing the i-search prompt). In general, - the case of the new line being shorter than the old. - Incomplete */ - else if (linenum == prompt_last_screen_line && - prompt_physical_chars > _rl_screenwidth && - wrap_offset != prompt_invis_chars_first_line && - _rl_last_c_pos == out && -#endif - - - /* 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 ((MB_CUR_MAX == 1 || rl_byte_oriented) && 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 && -#if 0 - _rl_last_c_pos <= PROMPT_ENDING_INDEX && local_prompt) -#else - _rl_last_c_pos < PROMPT_ENDING_INDEX && local_prompt) -#endif - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - if (_rl_term_cr) - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - if (modmark) - _rl_output_some_chars ("*", 1); - - _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) - wrap_offset + modmark; - else - _rl_last_c_pos = nleft + modmark; - } - - /* 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 desired cursor position. */ - nleft = cpos_buffer_position - pos; - - /* NLEFT is now a number of characters in a buffer. When in a - multibyte locale, however, _rl_last_c_pos is an absolute cursor - position that doesn't take invisible characters in the prompt - into account. We use a fudge factor to compensate. */ - - /* 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) - { - /* TX == new physical cursor position in multibyte locale. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - tx = _rl_col_width (&visible_line[pos], 0, nleft) - visible_wrap_offset; - else - tx = nleft; - if (tx >= 0 && _rl_last_c_pos > tx) - { - _rl_backspace (_rl_last_c_pos - tx); /* XXX */ - _rl_last_c_pos = tx; - } - } - - /* We need to note that in a multibyte locale we are dealing with - _rl_last_c_pos as an absolute cursor position, but moving to a - point specified by a buffer position (NLEFT) that doesn't take - invisible characters into account. */ - 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 = cpos_buffer_position - 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 = cpos_buffer_position - (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 = cpos_buffer_position - (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 = ((cpos_buffer_position - 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 (cpos_buffer_position - lmargin, &invisible_line[lmargin]); - last_lmargin = lmargin; - } - } - fflush (rl_outstream); - - /* Swap visible and non-visible lines. */ - { - struct line_state *vtemp = line_state_visible; - - line_state_visible = line_state_invisible; - line_state_invisible = vtemp; - - 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; - } - - _rl_release_sigint (); -} - -/* 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, twidth, o_cpos; - int current_invis_chars; - int col_lendiff, col_temp; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps_new, ps_old; - int new_offset, old_offset; -#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. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - temp = _rl_last_c_pos; - else - temp = _rl_last_c_pos - WRAP_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 (current_line < line_state_visible->wbsize && line_state_visible->wrapped_line[current_line] > 0) - _rl_clear_to_eol (line_state_visible->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; - _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) /* adding at the end */ - { - 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 ((MB_CUR_MAX == 1 || rl_byte_oriented) && 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_len; - 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_ENDING_INDEX) - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - if (modmark) - _rl_output_some_chars ("*", 1); - _rl_output_some_chars (local_prompt, lendiff); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - /* We take wrap_offset into account here so we can pass correct - information to _rl_move_cursor_relative. */ - _rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff) - wrap_offset + modmark; - cpos_adjusted = 1; - } - else - _rl_last_c_pos = lendiff + modmark; - } - - o_cpos = _rl_last_c_pos; - - /* When this function returns, _rl_last_c_pos is correct, and an absolute - cursor postion in multibyte mode, but a buffer index when not in a - multibyte locale. */ - _rl_move_cursor_relative (od, old); -#if 1 -#if defined (HANDLE_MULTIBYTE) - /* We need to indicate that the cursor position is correct in the presence of - invisible characters in the prompt string. Let's see if setting this when - we make sure we're at the end of the drawn prompt string works. */ - if (current_line == 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0 && - (_rl_last_c_pos > 0 || o_cpos > 0) && - _rl_last_c_pos == prompt_physical_chars) - cpos_adjusted = 1; -#endif -#endif - - /* 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; - /* If col_lendiff is > 0, implying that the new string takes up more - screen real estate than the old, but lendiff is < 0, meaning that it - takes fewer bytes, we need to just output the characters starting - from the first difference. These will overwrite what is on the - display, so there's no reason to do a smart update. This can really - only happen in a multibyte environment. */ - if (lendiff < 0) - { - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += _rl_col_width (nfd, 0, temp); - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - return; - } - /* 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. */ - else 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 ((MB_CUR_MAX == 1 || rl_byte_oriented != 0) && *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 - { - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - 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); - /* 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. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - twidth = _rl_col_width (nfd+lendiff, 0, temp-col_lendiff); - else - twidth = temp - lendiff; - _rl_last_c_pos += twidth; - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - } - else - { - /* cannot insert chars, write to EOL */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - /* If we're in a multibyte locale and were before the last invisible - char in the current line (which implies we just output some invisible - characters) we need to adjust _rl_last_c_pos, since it represents - a physical character position. */ - } - } - 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) - { - /* If nfd begins at the prompt, or before the invisible - characters in the prompt, we need to adjust _rl_last_c_pos - in a multibyte locale to account for the wrap offset and - set cpos_adjusted accordingly. */ - _rl_output_some_chars (nfd, temp); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - _rl_last_c_pos += _rl_col_width (nfd, 0, temp); - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - else - _rl_last_c_pos += temp; - } - } - /* Otherwise, print over the existing material. */ - else - { - if (temp > 0) - { - /* If nfd begins at the prompt, or before the invisible - characters in the prompt, we need to adjust _rl_last_c_pos - in a multibyte locale to account for the wrap offset and - set cpos_adjusted accordingly. */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; /* XXX */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - } - 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 0 - if (col_lendiff) -#else - /* If we've already printed over the entire width of the screen, - including the old material, then col_lendiff doesn't matter and - space_to_eol will insert too many spaces. XXX - maybe we should - adjust col_lendiff based on the difference between _rl_last_c_pos - and _rl_screenwidth */ - if (col_lendiff && (_rl_last_c_pos < _rl_screenwidth)) -#endif - { - 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. rl_expand_prompt must have already been called - (explicitly or implicitly). This still doesn't work exactly right. */ -int -rl_on_new_line_with_prompt () -{ - int prompt_size, i, l, real_screenwidth, newlines; - char *prompt_last_line, *lprompt; - - /* 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. */ - lprompt = local_prompt ? local_prompt : rl_prompt; - strcpy (visible_line, lprompt); - strcpy (invisible_line, lprompt); - - /* 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); /* XXX */ - 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 () -{ - register char *temp; - - if (visible_line) - { - 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. - (Well, when we don't have multibyte characters, _rl_last_c_pos is a - buffer index.) - 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; - int woff; /* number of invisible chars on current line */ - int cpos, dpos; /* current and desired cursor positions */ - - woff = WRAP_OFFSET (_rl_last_v_pos, wrap_offset); - cpos = _rl_last_c_pos; -#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. We need to account for invisible characters in this line, - as long as we are past them and they are counted by _rl_col_width. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - dpos = _rl_col_width (data, 0, new); - /* Use NEW when comparing against the last invisible character in the - prompt string, since they're both buffer indices and DPOS is a - desired display position. */ - if ((new > prompt_last_invisible) || /* XXX - don't use woff here */ - (prompt_physical_chars > _rl_screenwidth && - _rl_last_v_pos == prompt_last_screen_line && - wrap_offset != woff && - new > (prompt_last_invisible-_rl_screenwidth-wrap_offset))) - { - dpos -= woff; - /* Since this will be assigned to _rl_last_c_pos at the end (more - precisely, _rl_last_c_pos == dpos when this function returns), - let the caller know. */ - cpos_adjusted = 1; - } - } - else -#endif - dpos = new; - - /* If we don't have to do anything, then return. */ - if (cpos == dpos) - return; - - /* It may be faster to output a CR, and then move forwards instead - of moving backwards. */ - /* i == current physical cursor position. */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - i = _rl_last_c_pos; - else -#endif - i = _rl_last_c_pos - woff; - if (dpos == 0 || CR_FASTER (dpos, _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__ */ - cpos = _rl_last_c_pos = 0; - } - - if (cpos < dpos) - { - /* 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. */ - - /* However, we need a handle on where the current display position is - in the buffer for the immediately preceding comment to be true. - In multibyte locales, we don't currently have that info available. - Without it, we don't know where the data we have to display begins - in the buffer and we have to go back to the beginning of the screen - line. In this case, we can use the terminal sequence to move forward - if it's available. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (_rl_term_forward_char) - { - for (i = cpos; i < dpos; i++) - tputs (_rl_term_forward_char, 1, _rl_output_character_function); - } - else - { - tputs (_rl_term_cr, 1, _rl_output_character_function); - for (i = 0; i < new; i++) - putc (data[i], rl_outstream); - } - } - else - for (i = cpos; i < new; i++) - putc (data[i], rl_outstream); - } - -#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. */ -#endif - else if (cpos > dpos) - _rl_backspace (cpos - dpos); - - _rl_last_c_pos = dpos; -} - -/* 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. */ -static int msg_saved_prompt = 0; - -#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); - - if (saved_local_prompt == 0) - { - rl_save_prompt (); - msg_saved_prompt = 1; - } - rl_display_prompt = msg_buf; - local_prompt = expand_prompt (msg_buf, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)NULL; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - (*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; - if (saved_local_prompt == 0) - { - rl_save_prompt (); - msg_saved_prompt = 1; - } - local_prompt = expand_prompt (msg_buf, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)NULL; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - (*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; - if (msg_saved_prompt) - { - rl_restore_prompt (); - msg_saved_prompt = 0; - } - (*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; -} - -void -rl_save_prompt () -{ - saved_local_prompt = local_prompt; - saved_local_prefix = local_prompt_prefix; - saved_prefix_length = prompt_prefix_length; - saved_local_length = local_prompt_len; - 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; - local_prompt_len = 0; - prompt_last_invisible = prompt_visible_length = prompt_prefix_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; - local_prompt_len = saved_local_length; - prompt_prefix_length = saved_prefix_length; - 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; - - /* can test saved_local_prompt to see if prompt info has been saved. */ - saved_local_prompt = saved_local_prefix = (char *)0; - saved_local_length = 0; - saved_last_invisible = saved_visible_length = saved_prefix_length = 0; - saved_invis_chars_first_line = saved_physical_chars = 0; -} - -char * -_rl_make_prompt_for_search (pchar) - int pchar; -{ - int len; - char *pmt, *p; - - rl_save_prompt (); - - /* We've saved the prompt, and can do anything with the various prompt - strings we need before they're restored. We want the unexpanded - portion of the prompt string after any final newline. */ - p = rl_prompt ? strrchr (rl_prompt, '\n') : 0; - if (p == 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 - { - p++; - len = strlen (p); - pmt = (char *)xmalloc (len + 2); - if (len) - strcpy (pmt, p); - pmt[len] = pchar; - pmt[len+1] = '\0'; - } - - /* will be overwritten by expand_prompt, called from rl_message */ - prompt_physical_chars = saved_physical_chars + 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; -{ -#if defined (__MSDOS__) || defined (__MINGW32__) - _rl_output_some_chars (string, count); -#else - /* DEBUGGING */ - if (MB_CUR_MAX == 1 || rl_byte_oriented) - if (count != col) - _rl_ttymsg ("debug: insert_some_chars: count (%d) != col (%d)", 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); - } -#endif /* __MSDOS__ || __MINGW32__ */ -} - -/* Delete COUNT characters from the display line. */ -static void -delete_chars (count) - int count; -{ - if (count > _rl_screenwidth) /* XXX */ - return; - -#if !defined (__MSDOS__) && !defined (__MINGW32__) - 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); - } -#endif /* !__MSDOS__ && !__MINGW32__ */ -} - -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]]; - cpos_buffer_position = -1; /* don't know where we are in buffer */ - _rl_move_cursor_relative (_rl_screenwidth - 1, last_line); /* XXX */ - _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; - - oldp = rl_display_prompt; - rl_save_prompt (); - - 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; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - - rl_forced_update_display (); - - rl_display_prompt = oldp; - rl_restore_prompt(); -} - -/* Redisplay the current line after a SIGWINCH is received. */ -void -_rl_redisplay_after_sigwinch () -{ - char *t; - - /* Clear the last line (assuming that the screen size change will result in - either more or fewer characters on that line only) 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) - { - _rl_move_vert (_rl_vis_botlin); - -#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 (_rl_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; - int tmp, point, width, max; - - if (end <= start) - return 0; - if (MB_CUR_MAX == 1 || rl_byte_oriented) -{ -_rl_ttymsg ("_rl_col_width: called with MB_CUR_MAX == 1"); - return (end - start); -} - - memset (&ps, 0, sizeof (mbstate_t)); - - 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/display.c.save2 b/lib/readline/display.c.save2 deleted file mode 100644 index 3b816c8db..000000000 --- a/lib/readline/display.c.save2 +++ /dev/null @@ -1,2621 +0,0 @@ -/* display.c -- readline redisplay facility. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#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__ */ - -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)); - -/* State of visible and invisible lines. */ -struct line_state - { - char *line; - int *lbreaks; - int lbsize; -#if defined (HANDLE_MULTIBYTE) - int *wrapped_line; - int wbsize; -#endif - }; - -/* The line display buffers. One is the line currently displayed on - the screen. The other is the line about to be displayed. */ -static struct line_state line_state_array[2]; -static struct line_state *line_state_visible = &line_state_array[0]; -static struct line_state *line_state_invisible = &line_state_array[1]; -static int line_structures_initialized = 0; - -/* Backwards-compatible names. */ -#define inv_lbreaks (line_state_invisible->lbreaks) -#define inv_lbsize (line_state_invisible->lbsize) -#define vis_lbreaks (line_state_visible->lbreaks) -#define vis_lbsize (line_state_visible->lbsize) - -#define visible_line (line_state_visible->line) -#define invisible_line (line_state_invisible->line) - -#if defined (HANDLE_MULTIBYTE) -static int _rl_col_width PARAMS((const char *, int, int)); -#else -# define _rl_col_width(l, s, e) (((e) <= (s)) ? 0 : (e) - (s)) -#endif - -/* 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. CUR - and NEW are either both buffer positions or absolute screen positions. */ -#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new))) - -/* _rl_last_c_pos is an absolute cursor position in multibyte locales and a - buffer index in others. This macro is used when deciding whether the - current cursor position is in the middle of a prompt string containing - invisible characters. XXX - might need to take `modmark' into account. */ -#define PROMPT_ENDING_INDEX \ - ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) ? prompt_physical_chars : prompt_last_invisible+1) - - -/* **************************************************************** */ -/* */ -/* 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; -int _rl_want_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. */ -/* NOTE: _rl_last_c_pos is used as a buffer index when not in a locale - supporting multibyte characters, and an absolute cursor position when - in such a locale. This is an artifact of the donated multibyte support. - Care must be taken when modifying its value. */ -int _rl_last_c_pos = 0; -int _rl_last_v_pos = 0; - -static int cpos_adjusted; -static int cpos_buffer_position; -static int prompt_multibyte_chars; - -/* 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; - -/* 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 local_prompt_len; -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; - -/* set to a non-zero value by rl_redisplay if we are marking modified history - lines and the current line is so marked. */ -static int modmark; - -/* Variables to save and restore prompt and display information. */ - -/* 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_prefix_length; -static int saved_local_length; -static int saved_invis_chars_first_line; -static int saved_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, *igstart; - int l, rl, last, ignoring, ninvis, invfl, invflset, 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 */ - invflset = 0; /* we only want to set invfl once */ - - igstart = 0; - 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 (ignoring == 0 && *p == RL_PROMPT_START_IGNORE) /* XXX - check ignoring? */ - { - ignoring = 1; - igstart = p; - continue; - } - else if (ignoring && *p == RL_PROMPT_END_IGNORE) - { - ignoring = 0; - if (p != (igstart + 1)) - 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 ends up being assigned to prompt_visible_length, - which is the number of characters in the buffer that - contribute to characters on the screen, which might - not be the same as the number of physical characters - on the screen in the presence of multibyte characters */ - rl += ind - pind; - physchars += _rl_col_width (pmt, pind, ind); - } - else - ninvis += ind - pind; - p--; /* compensate for later increment */ - } - else -#endif - { - *r++ = *p; - if (!ignoring) - { - rl++; /* visible length byte counter */ - physchars++; - } - else - ninvis++; /* invisible chars byte counter */ - } - - if (invflset == 0 && rl >= _rl_screenwidth) - { - invfl = ninvis; - invflset = 1; - } - } - } - - 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; - local_prompt_len = 0; - prompt_last_invisible = prompt_invis_chars_first_line = 0; - prompt_visible_length = prompt_physical_chars = 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; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - return (prompt_visible_length); - } - else - { - /* The prompt spans multiple lines. */ - t = ++p; - local_prompt = expand_prompt (p, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - 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, - (int *)NULL, - (int *)NULL); - *t = c; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - 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; - -#if defined (HANDLE_MULTIBYTE) - line_state_visible->wbsize = vis_lbsize; - line_state_visible->wrapped_line = (int *)xmalloc (line_state_visible->wbsize * sizeof (int)); - - line_state_invisible->wbsize = inv_lbsize; - line_state_invisible->wrapped_line = (int *)xmalloc (line_state_invisible->wbsize * sizeof (int)); -#endif - - inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int)); - vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int)); - inv_lbreaks[0] = vis_lbreaks[0] = 0; - } - - line_structures_initialized = 1; -} - -/* Basic redisplay algorithm. */ -void -rl_redisplay () -{ - register int in, out, c, linenum, cursor_linenum; - register char *line; - int inv_botlin, lb_botlin, lb_linenum, o_cpos; - int newlines, lpos, temp, n0, num, prompt_lines_estimate; - 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 (_rl_echoing_p == 0) - return; - - /* Block keyboard interrupts because this function manipulates global - data structures. */ - _rl_block_sigint (); - - if (!rl_display_prompt) - rl_display_prompt = ""; - - if (line_structures_initialized == 0) - { - init_line_structures (0); - rl_on_new_line (); - } - - /* Draw the line into the buffer. */ - cpos_buffer_position = -1; - - prompt_multibyte_chars = prompt_visible_length - prompt_physical_chars; - - 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) - { - if (local_prompt_prefix && forced_display) - _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix)); - - if (local_prompt_len > 0) - { - temp = local_prompt_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_prompt_len); - out += local_prompt_len; - } - line[out] = '\0'; - wrap_offset = local_prompt_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)); \ - } \ - inv_lbreaks[++newlines] = out; \ - if (newlines >= (line_state_invisible->wbsize - 1)) \ - { \ - line_state_invisible->wbsize *= 2; \ - line_state_invisible->wrapped_line = (int *)xrealloc (line_state_invisible->wrapped_line, line_state_invisible->wbsize * sizeof(int)); \ - } \ - line_state_invisible->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; - lpos = prompt_physical_chars + modmark; - -#if defined (HANDLE_MULTIBYTE) - memset (line_state_invisible->wrapped_line, 0, line_state_invisible->wbsize * sizeof (int)); - num = 0; -#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 (or, more generally, last) line. */ - - /* This is zero-based, used to set the newlines */ - prompt_lines_estimate = lpos / _rl_screenwidth; - - /* what if lpos is already >= _rl_screenwidth before we start drawing the - contents of the command line? */ - while (lpos >= _rl_screenwidth) - { - int z; - /* 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 */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0) - { - n0 = num; - temp = local_prompt_len; - while (num < temp) - { - z = _rl_col_width (local_prompt, n0, num); - if (z > _rl_screenwidth) - { - num = _rl_find_prev_mbchar (local_prompt, num, MB_FIND_ANY); - break; - } - else if (z == _rl_screenwidth) - break; - num++; - } - temp = num; - } - else -#endif /* !HANDLE_MULTIBYTE */ - temp = ((newlines + 1) * _rl_screenwidth); - - /* Now account for invisible characters in the current line. */ - /* XXX - this assumes that the invisible characters may be split, but only - between the first and the last lines. */ - temp += ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line - : ((newlines == prompt_lines_estimate) ? wrap_offset : prompt_invis_chars_first_line)) - : ((newlines == 0) ? wrap_offset : 0)); - - inv_lbreaks[++newlines] = temp; -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0) - lpos -= _rl_col_width (local_prompt, n0, num); - else -#endif - 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 (cpos_buffer_position), 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) - { - cpos_buffer_position = 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) - { - cpos_buffer_position = 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 (cpos_buffer_position < 0) - { - cpos_buffer_position = out; - lb_linenum = newlines; - } - - inv_botlin = lb_botlin = newlines; - CHECK_INV_LBREAKS (); - inv_lbreaks[newlines+1] = out; - cursor_linenum = lb_linenum; - - /* CPOS_BUFFER_POSITION == 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, tx; - - 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 INVIS_FIRST() (prompt_physical_chars > _rl_screenwidth ? prompt_invis_chars_first_line : wrap_offset) -#define WRAP_OFFSET(line, offset) ((line == 0) \ - ? (offset ? INVIS_FIRST() : 0) \ - : ((line == prompt_last_screen_line) ? wrap_offset-prompt_invis_chars_first_line : 0)) -#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++) - { - /* This can lead us astray if we execute a program that changes - the locale from a non-multibyte to a multibyte one. */ - o_cpos = _rl_last_c_pos; - cpos_adjusted = 0; - update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum, - VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin); - - /* update_line potentially changes _rl_last_c_pos, but doesn't - take invisible characters into account, since _rl_last_c_pos - is an absolute cursor position in a multibyte locale. See - if compensating here is the right thing, or if we have to - change update_line itself. There are several cases in which - update_line adjusts _rl_last_c_pos itself (so it can pass - _rl_move_cursor_relative accurate values); it communicates - this back by setting cpos_adjusted. If we assume that - _rl_last_c_pos is correct (an absolute cursor position) each - time update_line is called, then we can assume in our - calculations that o_cpos does not need to be adjusted by - wrap_offset. */ - if (linenum == 0 && (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > wrap_offset && - o_cpos < prompt_last_invisible) - _rl_last_c_pos -= prompt_invis_chars_first_line; /* XXX - was wrap_offset */ - else if (linenum == prompt_last_screen_line && prompt_physical_chars > _rl_screenwidth && - (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > (prompt_last_invisible - _rl_screenwidth - prompt_invis_chars_first_line)) - _rl_last_c_pos -= (wrap_offset-prompt_invis_chars_first_line); - - /* 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)) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - nleft = _rl_screenwidth - _rl_last_c_pos; - else - nleft = _rl_screenwidth + wrap_offset - _rl_last_c_pos; - if (nleft) - _rl_clear_to_eol (nleft); - } -#if 0 - /* This segment is intended to handle the case where the prompt - has invisible characters on the second line and the new line - to be displayed needs to clear the rest of the old characters - out (e.g., when printing the i-search prompt). In general, - the case of the new line being shorter than the old. - Incomplete */ - else if (linenum == prompt_last_screen_line && - prompt_physical_chars > _rl_screenwidth && - wrap_offset != prompt_invis_chars_first_line && - _rl_last_c_pos == out && -#endif - - - /* 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 ((MB_CUR_MAX == 1 || rl_byte_oriented) && 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 && -#if 0 - _rl_last_c_pos <= PROMPT_ENDING_INDEX && local_prompt) -#else - _rl_last_c_pos < PROMPT_ENDING_INDEX && local_prompt) -#endif - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - if (_rl_term_cr) - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - if (modmark) - _rl_output_some_chars ("*", 1); - - _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) - wrap_offset + modmark; - else - _rl_last_c_pos = nleft + modmark; - } - - /* 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 desired cursor position. */ - nleft = cpos_buffer_position - pos; - - /* NLEFT is now a number of characters in a buffer. When in a - multibyte locale, however, _rl_last_c_pos is an absolute cursor - position that doesn't take invisible characters in the prompt - into account. We use a fudge factor to compensate. */ - - /* 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) - { - /* TX == new physical cursor position in multibyte locale. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - tx = _rl_col_width (&visible_line[pos], 0, nleft) - visible_wrap_offset; - else - tx = nleft; - if (tx >= 0 && _rl_last_c_pos > tx) - { - _rl_backspace (_rl_last_c_pos - tx); /* XXX */ - _rl_last_c_pos = tx; - } - } - - /* We need to note that in a multibyte locale we are dealing with - _rl_last_c_pos as an absolute cursor position, but moving to a - point specified by a buffer position (NLEFT) that doesn't take - invisible characters into account. */ - 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 = cpos_buffer_position - 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 = cpos_buffer_position - (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 = cpos_buffer_position - (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 = ((cpos_buffer_position - 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 (cpos_buffer_position - lmargin, &invisible_line[lmargin]); - last_lmargin = lmargin; - } - } - fflush (rl_outstream); - - /* Swap visible and non-visible lines. */ - { - struct line_state *vtemp = line_state_visible; - - line_state_visible = line_state_invisible; - line_state_invisible = vtemp; - - 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; - } - - _rl_release_sigint (); -} - -/* 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, twidth, o_cpos; - int current_invis_chars; - int col_lendiff, col_temp; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps_new, ps_old; - int new_offset, old_offset; -#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. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - temp = _rl_last_c_pos; - else - temp = _rl_last_c_pos - WRAP_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 (current_line < line_state_visible->wbsize && line_state_visible->wrapped_line[current_line] > 0) - _rl_clear_to_eol (line_state_visible->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; - _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) /* adding at the end */ - { - 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 ((MB_CUR_MAX == 1 || rl_byte_oriented) && 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_len; - 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_ENDING_INDEX) - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - if (modmark) - _rl_output_some_chars ("*", 1); - _rl_output_some_chars (local_prompt, lendiff); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - /* We take wrap_offset into account here so we can pass correct - information to _rl_move_cursor_relative. */ - _rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff) - wrap_offset + modmark; - cpos_adjusted = 1; - } - else - _rl_last_c_pos = lendiff + modmark; - } - - o_cpos = _rl_last_c_pos; - - /* When this function returns, _rl_last_c_pos is correct, and an absolute - cursor postion in multibyte mode, but a buffer index when not in a - multibyte locale. */ - _rl_move_cursor_relative (od, old); -#if 1 -#if defined (HANDLE_MULTIBYTE) - /* We need to indicate that the cursor position is correct in the presence of - invisible characters in the prompt string. Let's see if setting this when - we make sure we're at the end of the drawn prompt string works. */ - if (current_line == 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0 && - (_rl_last_c_pos > 0 || o_cpos > 0) && - _rl_last_c_pos == prompt_physical_chars) - cpos_adjusted = 1; -#endif -#endif - - /* 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; - /* If col_lendiff is > 0, implying that the new string takes up more - screen real estate than the old, but lendiff is < 0, meaning that it - takes fewer bytes, we need to just output the characters starting - from the first difference. These will overwrite what is on the - display, so there's no reason to do a smart update. This can really - only happen in a multibyte environment. */ - if (lendiff < 0) - { - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += _rl_col_width (nfd, 0, temp); - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - return; - } - /* 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. */ - else 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 == 0 || - _rl_last_c_pos > 0 || - lendiff <= prompt_visible_length || - current_invis_chars == 0)) - { - insert_some_chars (nfd, lendiff, col_lendiff); - _rl_last_c_pos += col_lendiff; - } - else if ((MB_CUR_MAX == 1 || rl_byte_oriented != 0) && *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 - { - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - 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); - /* 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. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - twidth = _rl_col_width (nfd+lendiff, 0, temp-col_lendiff); - else - twidth = temp - lendiff; - _rl_last_c_pos += twidth; - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - } - else - { - /* cannot insert chars, write to EOL */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - /* If we're in a multibyte locale and were before the last invisible - char in the current line (which implies we just output some invisible - characters) we need to adjust _rl_last_c_pos, since it represents - a physical character position. */ - if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - current_line == prompt_last_screen_line && wrap_offset && - wrap_offset != prompt_invis_chars_first_line && - ((nfd-new) < (prompt_last_invisible-(current_line*_rl_screenwidth)))) - { - _rl_last_c_pos -= wrap_offset - prompt_invis_chars_first_line; - cpos_adjusted = 1; - } - } - } - 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) - { - /* If nfd begins at the prompt, or before the invisible - characters in the prompt, we need to adjust _rl_last_c_pos - in a multibyte locale to account for the wrap offset and - set cpos_adjusted accordingly. */ - _rl_output_some_chars (nfd, temp); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - _rl_last_c_pos += _rl_col_width (nfd, 0, temp); - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - else - _rl_last_c_pos += temp; - } - } - /* Otherwise, print over the existing material. */ - else - { - if (temp > 0) - { - /* If nfd begins at the prompt, or before the invisible - characters in the prompt, we need to adjust _rl_last_c_pos - in a multibyte locale to account for the wrap offset and - set cpos_adjusted accordingly. */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; /* XXX */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - } - 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 0 - if (col_lendiff) -#else - /* If we've already printed over the entire width of the screen, - including the old material, then col_lendiff doesn't matter and - space_to_eol will insert too many spaces. XXX - maybe we should - adjust col_lendiff based on the difference between _rl_last_c_pos - and _rl_screenwidth */ - if (col_lendiff && (_rl_last_c_pos < _rl_screenwidth)) -#endif - { - 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. rl_expand_prompt must have already been called - (explicitly or implicitly). This still doesn't work exactly right. */ -int -rl_on_new_line_with_prompt () -{ - int prompt_size, i, l, real_screenwidth, newlines; - char *prompt_last_line, *lprompt; - - /* 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. */ - lprompt = local_prompt ? local_prompt : rl_prompt; - strcpy (visible_line, lprompt); - strcpy (invisible_line, lprompt); - - /* 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); /* XXX */ - 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 () -{ - register char *temp; - - if (visible_line) - { - 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. - (Well, when we don't have multibyte characters, _rl_last_c_pos is a - buffer index.) - 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; - int woff; /* number of invisible chars on current line */ - int cpos, dpos; /* current and desired cursor positions */ - - woff = WRAP_OFFSET (_rl_last_v_pos, wrap_offset); - cpos = _rl_last_c_pos; -#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. We need to account for invisible characters in this line, - as long as we are past them and they are counted by _rl_col_width. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - dpos = _rl_col_width (data, 0, new); - /* Use NEW when comparing against the last invisible character in the - prompt string, since they're both buffer indices and DPOS is a - desired display position. */ - if ((new > prompt_last_invisible) || /* XXX - don't use woff here */ - (prompt_physical_chars > _rl_screenwidth && - _rl_last_v_pos == prompt_last_screen_line && - wrap_offset != woff && - new > (prompt_last_invisible-(_rl_screenwidth*_rl_last_v_pos)-wrap_offset))) - /* XXX last comparison might need to be >= */ - { - dpos -= woff; - /* Since this will be assigned to _rl_last_c_pos at the end (more - precisely, _rl_last_c_pos == dpos when this function returns), - let the caller know. */ - cpos_adjusted = 1; - } - } - else -#endif - dpos = new; - - /* If we don't have to do anything, then return. */ - if (cpos == dpos) - return; - - /* It may be faster to output a CR, and then move forwards instead - of moving backwards. */ - /* i == current physical cursor position. */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - i = _rl_last_c_pos; - else -#endif - i = _rl_last_c_pos - woff; - if (dpos == 0 || CR_FASTER (dpos, _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__ */ - cpos = _rl_last_c_pos = 0; - } - - if (cpos < dpos) - { - /* 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. */ - - /* However, we need a handle on where the current display position is - in the buffer for the immediately preceding comment to be true. - In multibyte locales, we don't currently have that info available. - Without it, we don't know where the data we have to display begins - in the buffer and we have to go back to the beginning of the screen - line. In this case, we can use the terminal sequence to move forward - if it's available. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (_rl_term_forward_char) - { - for (i = cpos; i < dpos; i++) - tputs (_rl_term_forward_char, 1, _rl_output_character_function); - } - else - { - tputs (_rl_term_cr, 1, _rl_output_character_function); - for (i = 0; i < new; i++) - putc (data[i], rl_outstream); - } - } - else - for (i = cpos; i < new; i++) - putc (data[i], rl_outstream); - } - -#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. */ -#endif - else if (cpos > dpos) - _rl_backspace (cpos - dpos); - - _rl_last_c_pos = dpos; -} - -/* 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. */ -static int msg_saved_prompt = 0; - -#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); - - if (saved_local_prompt == 0) - { - rl_save_prompt (); - msg_saved_prompt = 1; - } - rl_display_prompt = msg_buf; - local_prompt = expand_prompt (msg_buf, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)NULL; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - (*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; - if (saved_local_prompt == 0) - { - rl_save_prompt (); - msg_saved_prompt = 1; - } - local_prompt = expand_prompt (msg_buf, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)NULL; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - (*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; - if (msg_saved_prompt) - { - rl_restore_prompt (); - msg_saved_prompt = 0; - } - (*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; -} - -void -rl_save_prompt () -{ - saved_local_prompt = local_prompt; - saved_local_prefix = local_prompt_prefix; - saved_prefix_length = prompt_prefix_length; - saved_local_length = local_prompt_len; - 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; - local_prompt_len = 0; - prompt_last_invisible = prompt_visible_length = prompt_prefix_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; - local_prompt_len = saved_local_length; - prompt_prefix_length = saved_prefix_length; - 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; - - /* can test saved_local_prompt to see if prompt info has been saved. */ - saved_local_prompt = saved_local_prefix = (char *)0; - saved_local_length = 0; - saved_last_invisible = saved_visible_length = saved_prefix_length = 0; - saved_invis_chars_first_line = saved_physical_chars = 0; -} - -char * -_rl_make_prompt_for_search (pchar) - int pchar; -{ - int len; - char *pmt, *p; - - rl_save_prompt (); - - /* We've saved the prompt, and can do anything with the various prompt - strings we need before they're restored. We want the unexpanded - portion of the prompt string after any final newline. */ - p = rl_prompt ? strrchr (rl_prompt, '\n') : 0; - if (p == 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 - { - p++; - len = strlen (p); - pmt = (char *)xmalloc (len + 2); - if (len) - strcpy (pmt, p); - pmt[len] = pchar; - pmt[len+1] = '\0'; - } - - /* will be overwritten by expand_prompt, called from rl_message */ - prompt_physical_chars = saved_physical_chars + 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; -{ -#if defined (__MSDOS__) || defined (__MINGW32__) - _rl_output_some_chars (string, count); -#else - /* DEBUGGING */ - if (MB_CUR_MAX == 1 || rl_byte_oriented) - if (count != col) - _rl_ttymsg ("debug: insert_some_chars: count (%d) != col (%d)", 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); - } -#endif /* __MSDOS__ || __MINGW32__ */ -} - -/* Delete COUNT characters from the display line. */ -static void -delete_chars (count) - int count; -{ - if (count > _rl_screenwidth) /* XXX */ - return; - -#if !defined (__MSDOS__) && !defined (__MINGW32__) - 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); - } -#endif /* !__MSDOS__ && !__MINGW32__ */ -} - -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]]; - cpos_buffer_position = -1; /* don't know where we are in buffer */ - _rl_move_cursor_relative (_rl_screenwidth - 1, last_line); /* XXX */ - _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; - - oldp = rl_display_prompt; - rl_save_prompt (); - - 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; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - - rl_forced_update_display (); - - rl_display_prompt = oldp; - rl_restore_prompt(); -} - -/* Redisplay the current line after a SIGWINCH is received. */ -void -_rl_redisplay_after_sigwinch () -{ - char *t; - - /* Clear the last line (assuming that the screen size change will result in - either more or fewer characters on that line only) 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) - { - _rl_move_vert (_rl_vis_botlin); - -#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 (_rl_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; - int tmp, point, width, max; - - if (end <= start) - return 0; - if (MB_CUR_MAX == 1 || rl_byte_oriented) -{ -_rl_ttymsg ("_rl_col_width: called with MB_CUR_MAX == 1"); - return (end - start); -} - - memset (&ps, 0, sizeof (mbstate_t)); - - 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/display.c.save3 b/lib/readline/display.c.save3 deleted file mode 100644 index f7c2a7db3..000000000 --- a/lib/readline/display.c.save3 +++ /dev/null @@ -1,2628 +0,0 @@ -/* display.c -- readline redisplay facility. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#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__ */ - -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)); - -/* State of visible and invisible lines. */ -struct line_state - { - char *line; - int *lbreaks; - int lbsize; -#if defined (HANDLE_MULTIBYTE) - int *wrapped_line; - int wbsize; -#endif - }; - -/* The line display buffers. One is the line currently displayed on - the screen. The other is the line about to be displayed. */ -static struct line_state line_state_array[2]; -static struct line_state *line_state_visible = &line_state_array[0]; -static struct line_state *line_state_invisible = &line_state_array[1]; -static int line_structures_initialized = 0; - -/* Backwards-compatible names. */ -#define inv_lbreaks (line_state_invisible->lbreaks) -#define inv_lbsize (line_state_invisible->lbsize) -#define vis_lbreaks (line_state_visible->lbreaks) -#define vis_lbsize (line_state_visible->lbsize) - -#define visible_line (line_state_visible->line) -#define invisible_line (line_state_invisible->line) - -#if defined (HANDLE_MULTIBYTE) -static int _rl_col_width PARAMS((const char *, int, int)); -#else -# define _rl_col_width(l, s, e) (((e) <= (s)) ? 0 : (e) - (s)) -#endif - -/* 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. CUR - and NEW are either both buffer positions or absolute screen positions. */ -#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new))) - -/* _rl_last_c_pos is an absolute cursor position in multibyte locales and a - buffer index in others. This macro is used when deciding whether the - current cursor position is in the middle of a prompt string containing - invisible characters. XXX - might need to take `modmark' into account. */ -#define PROMPT_ENDING_INDEX \ - ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) ? prompt_physical_chars : prompt_last_invisible+1) - - -/* **************************************************************** */ -/* */ -/* 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; -int _rl_want_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. */ -/* NOTE: _rl_last_c_pos is used as a buffer index when not in a locale - supporting multibyte characters, and an absolute cursor position when - in such a locale. This is an artifact of the donated multibyte support. - Care must be taken when modifying its value. */ -int _rl_last_c_pos = 0; -int _rl_last_v_pos = 0; - -static int cpos_adjusted; -static int cpos_buffer_position; -static int prompt_multibyte_chars; - -/* 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; - -/* 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 local_prompt_len; -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; - -/* set to a non-zero value by rl_redisplay if we are marking modified history - lines and the current line is so marked. */ -static int modmark; - -/* Variables to save and restore prompt and display information. */ - -/* 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_prefix_length; -static int saved_local_length; -static int saved_invis_chars_first_line; -static int saved_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, *igstart; - int l, rl, last, ignoring, ninvis, invfl, invflset, 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 */ - invflset = 0; /* we only want to set invfl once */ - - igstart = 0; - 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 (ignoring == 0 && *p == RL_PROMPT_START_IGNORE) /* XXX - check ignoring? */ - { - ignoring = 1; - igstart = p; - continue; - } - else if (ignoring && *p == RL_PROMPT_END_IGNORE) - { - ignoring = 0; - if (p != (igstart + 1)) - 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 ends up being assigned to prompt_visible_length, - which is the number of characters in the buffer that - contribute to characters on the screen, which might - not be the same as the number of physical characters - on the screen in the presence of multibyte characters */ - rl += ind - pind; - physchars += _rl_col_width (pmt, pind, ind); - } - else - ninvis += ind - pind; - p--; /* compensate for later increment */ - } - else -#endif - { - *r++ = *p; - if (!ignoring) - { - rl++; /* visible length byte counter */ - physchars++; - } - else - ninvis++; /* invisible chars byte counter */ - } - - if (invflset == 0 && rl >= _rl_screenwidth) - { - invfl = ninvis; - invflset = 1; - } - } - } - - 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; - local_prompt_len = 0; - prompt_last_invisible = prompt_invis_chars_first_line = 0; - prompt_visible_length = prompt_physical_chars = 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; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - return (prompt_visible_length); - } - else - { - /* The prompt spans multiple lines. */ - t = ++p; - local_prompt = expand_prompt (p, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - 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, - (int *)NULL, - (int *)NULL); - *t = c; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - 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; - -#if defined (HANDLE_MULTIBYTE) - line_state_visible->wbsize = vis_lbsize; - line_state_visible->wrapped_line = (int *)xmalloc (line_state_visible->wbsize * sizeof (int)); - - line_state_invisible->wbsize = inv_lbsize; - line_state_invisible->wrapped_line = (int *)xmalloc (line_state_invisible->wbsize * sizeof (int)); -#endif - - inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int)); - vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int)); - inv_lbreaks[0] = vis_lbreaks[0] = 0; - } - - line_structures_initialized = 1; -} - -/* Basic redisplay algorithm. */ -void -rl_redisplay () -{ - register int in, out, c, linenum, cursor_linenum; - register char *line; - int inv_botlin, lb_botlin, lb_linenum, o_cpos; - int newlines, lpos, temp, n0, num, prompt_lines_estimate; - 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 (_rl_echoing_p == 0) - return; - - /* Block keyboard interrupts because this function manipulates global - data structures. */ - _rl_block_sigint (); - - if (!rl_display_prompt) - rl_display_prompt = ""; - - if (line_structures_initialized == 0) - { - init_line_structures (0); - rl_on_new_line (); - } - - /* Draw the line into the buffer. */ - cpos_buffer_position = -1; - - prompt_multibyte_chars = prompt_visible_length - prompt_physical_chars; - - 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) - { - if (local_prompt_prefix && forced_display) - _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix)); - - if (local_prompt_len > 0) - { - temp = local_prompt_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_prompt_len); - out += local_prompt_len; - } - line[out] = '\0'; - wrap_offset = local_prompt_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)); \ - } \ - inv_lbreaks[++newlines] = out; \ - if (newlines >= (line_state_invisible->wbsize - 1)) \ - { \ - line_state_invisible->wbsize *= 2; \ - line_state_invisible->wrapped_line = (int *)xrealloc (line_state_invisible->wrapped_line, line_state_invisible->wbsize * sizeof(int)); \ - } \ - line_state_invisible->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; - lpos = prompt_physical_chars + modmark; - -#if defined (HANDLE_MULTIBYTE) - memset (line_state_invisible->wrapped_line, 0, line_state_invisible->wbsize * sizeof (int)); - num = 0; -#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 (or, more generally, last) line. */ - - /* This is zero-based, used to set the newlines */ - prompt_lines_estimate = lpos / _rl_screenwidth; - - /* what if lpos is already >= _rl_screenwidth before we start drawing the - contents of the command line? */ - while (lpos >= _rl_screenwidth) - { - int z; - /* 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 */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0) - { - n0 = num; - temp = local_prompt_len; - while (num < temp) - { - z = _rl_col_width (local_prompt, n0, num); - if (z > _rl_screenwidth) - { - num = _rl_find_prev_mbchar (local_prompt, num, MB_FIND_ANY); - break; - } - else if (z == _rl_screenwidth) - break; - num++; - } - temp = num; - } - else -#endif /* !HANDLE_MULTIBYTE */ - temp = ((newlines + 1) * _rl_screenwidth); - - /* Now account for invisible characters in the current line. */ - /* XXX - this assumes that the invisible characters may be split, but only - between the first and the last lines. */ - temp += ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line - : ((newlines == prompt_lines_estimate) ? wrap_offset : prompt_invis_chars_first_line)) - : ((newlines == 0) ? wrap_offset : 0)); - - inv_lbreaks[++newlines] = temp; -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0) - lpos -= _rl_col_width (local_prompt, n0, num); - else -#endif - 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 (cpos_buffer_position), 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) - { - cpos_buffer_position = 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) - { - cpos_buffer_position = 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 (cpos_buffer_position < 0) - { - cpos_buffer_position = out; - lb_linenum = newlines; - } - - inv_botlin = lb_botlin = newlines; - CHECK_INV_LBREAKS (); - inv_lbreaks[newlines+1] = out; - cursor_linenum = lb_linenum; - - /* CPOS_BUFFER_POSITION == 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, tx; - - 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 INVIS_FIRST() (prompt_physical_chars > _rl_screenwidth ? prompt_invis_chars_first_line : wrap_offset) -#define WRAP_OFFSET(line, offset) ((line == 0) \ - ? (offset ? INVIS_FIRST() : 0) \ - : ((line == prompt_last_screen_line) ? wrap_offset-prompt_invis_chars_first_line : 0)) -#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++) - { - /* This can lead us astray if we execute a program that changes - the locale from a non-multibyte to a multibyte one. */ - o_cpos = _rl_last_c_pos; - cpos_adjusted = 0; - update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum, - VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin); - - /* update_line potentially changes _rl_last_c_pos, but doesn't - take invisible characters into account, since _rl_last_c_pos - is an absolute cursor position in a multibyte locale. See - if compensating here is the right thing, or if we have to - change update_line itself. There are several cases in which - update_line adjusts _rl_last_c_pos itself (so it can pass - _rl_move_cursor_relative accurate values); it communicates - this back by setting cpos_adjusted. If we assume that - _rl_last_c_pos is correct (an absolute cursor position) each - time update_line is called, then we can assume in our - calculations that o_cpos does not need to be adjusted by - wrap_offset. */ - if (linenum == 0 && (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > wrap_offset && - o_cpos < prompt_last_invisible) - _rl_last_c_pos -= prompt_invis_chars_first_line; /* XXX - was wrap_offset */ - else if (linenum == prompt_last_screen_line && prompt_physical_chars > _rl_screenwidth && - (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > (prompt_last_invisible - _rl_screenwidth - prompt_invis_chars_first_line)) - _rl_last_c_pos -= (wrap_offset-prompt_invis_chars_first_line); - - /* 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)) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - nleft = _rl_screenwidth - _rl_last_c_pos; - else - nleft = _rl_screenwidth + wrap_offset - _rl_last_c_pos; - if (nleft) - _rl_clear_to_eol (nleft); - } -#if 0 - /* This segment is intended to handle the case where the prompt - has invisible characters on the second line and the new line - to be displayed needs to clear the rest of the old characters - out (e.g., when printing the i-search prompt). In general, - the case of the new line being shorter than the old. - Incomplete */ - else if (linenum == prompt_last_screen_line && - prompt_physical_chars > _rl_screenwidth && - wrap_offset != prompt_invis_chars_first_line && - _rl_last_c_pos == out && -#endif - - - /* 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 ((MB_CUR_MAX == 1 || rl_byte_oriented) && 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 && -#if 0 - _rl_last_c_pos <= PROMPT_ENDING_INDEX && local_prompt) -#else - _rl_last_c_pos < PROMPT_ENDING_INDEX && local_prompt) -#endif - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - if (_rl_term_cr) - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - if (modmark) - _rl_output_some_chars ("*", 1); - - _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) - wrap_offset + modmark; - else - _rl_last_c_pos = nleft + modmark; - } - - /* 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 desired cursor position. */ - nleft = cpos_buffer_position - pos; - - /* NLEFT is now a number of characters in a buffer. When in a - multibyte locale, however, _rl_last_c_pos is an absolute cursor - position that doesn't take invisible characters in the prompt - into account. We use a fudge factor to compensate. */ - - /* 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) - { - /* TX == new physical cursor position in multibyte locale. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - tx = _rl_col_width (&visible_line[pos], 0, nleft) - visible_wrap_offset; - else - tx = nleft; - if (tx >= 0 && _rl_last_c_pos > tx) - { - _rl_backspace (_rl_last_c_pos - tx); /* XXX */ - _rl_last_c_pos = tx; - } - } - - /* We need to note that in a multibyte locale we are dealing with - _rl_last_c_pos as an absolute cursor position, but moving to a - point specified by a buffer position (NLEFT) that doesn't take - invisible characters into account. */ - 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 = cpos_buffer_position - 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 = cpos_buffer_position - (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 = cpos_buffer_position - (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 = ((cpos_buffer_position - 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 (cpos_buffer_position - lmargin, &invisible_line[lmargin]); - last_lmargin = lmargin; - } - } - fflush (rl_outstream); - - /* Swap visible and non-visible lines. */ - { - struct line_state *vtemp = line_state_visible; - - line_state_visible = line_state_invisible; - line_state_invisible = vtemp; - - 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; - } - - _rl_release_sigint (); -} - -/* 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, twidth, o_cpos; - int current_invis_chars; - int col_lendiff, col_temp; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps_new, ps_old; - int new_offset, old_offset; -#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. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - temp = _rl_last_c_pos; - else - temp = _rl_last_c_pos - WRAP_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 (current_line < line_state_visible->wbsize && line_state_visible->wrapped_line[current_line] > 0) - _rl_clear_to_eol (line_state_visible->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; - _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) /* adding at the end */ - { - 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 ((MB_CUR_MAX == 1 || rl_byte_oriented) && 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_len; - 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_ENDING_INDEX) - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - if (modmark) - _rl_output_some_chars ("*", 1); - _rl_output_some_chars (local_prompt, lendiff); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - /* We take wrap_offset into account here so we can pass correct - information to _rl_move_cursor_relative. */ - _rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff) - wrap_offset + modmark; - cpos_adjusted = 1; - } - else - _rl_last_c_pos = lendiff + modmark; - } - - o_cpos = _rl_last_c_pos; - - /* When this function returns, _rl_last_c_pos is correct, and an absolute - cursor postion in multibyte mode, but a buffer index when not in a - multibyte locale. */ - _rl_move_cursor_relative (od, old); -#if 1 -#if defined (HANDLE_MULTIBYTE) - /* We need to indicate that the cursor position is correct in the presence of - invisible characters in the prompt string. Let's see if setting this when - we make sure we're at the end of the drawn prompt string works. */ - if (current_line == 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0 && - (_rl_last_c_pos > 0 || o_cpos > 0) && - _rl_last_c_pos == prompt_physical_chars) - cpos_adjusted = 1; -#endif -#endif - - /* 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; - /* If col_lendiff is > 0, implying that the new string takes up more - screen real estate than the old, but lendiff is < 0, meaning that it - takes fewer bytes, we need to just output the characters starting - from the first difference. These will overwrite what is on the - display, so there's no reason to do a smart update. This can really - only happen in a multibyte environment. */ - if (lendiff < 0) - { - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += _rl_col_width (nfd, 0, temp); - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - return; - } - /* 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. */ - else 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. */ - /* The same thing happens if we're trying to draw before the last - invisible character in the prompt string and we're not drawing - the entire prompt string. */ - if (*ols && ((_rl_horizontal_scroll_mode && - _rl_last_c_pos == 0 && - lendiff > prompt_visible_length && - current_invis_chars > 0) == 0) && - (((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - current_line == 0 && wrap_offset && - ((nfd - new) <= prompt_last_invisible) && - (col_lendiff < prompt_visible_length)) == 0)) - { - insert_some_chars (nfd, lendiff, col_lendiff); - _rl_last_c_pos += col_lendiff; - } - else if ((MB_CUR_MAX == 1 || rl_byte_oriented != 0) && *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 - { - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - /* If nfd begins before the last invisible character in the - prompt, adjust _rl_last_c_pos to account for wrap_offset - and set cpos_adjusted to let the caller know. */ - if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - 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); - /* 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. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - twidth = _rl_col_width (nfd+lendiff, 0, temp-col_lendiff); - else - twidth = temp - lendiff; - _rl_last_c_pos += twidth; - /* If nfd begins before the last invisible character in the - prompt, adjust _rl_last_c_pos to account for wrap_offset - and set cpos_adjusted to let the caller know. */ - if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - } - else - { - /* cannot insert chars, write to EOL */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - /* If we're in a multibyte locale and were before the last invisible - char in the current line (which implies we just output some invisible - characters) we need to adjust _rl_last_c_pos, since it represents - a physical character position. */ - if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - current_line == prompt_last_screen_line && wrap_offset && - wrap_offset != prompt_invis_chars_first_line && - ((nfd-new) < (prompt_last_invisible-(current_line*_rl_screenwidth)))) - { - _rl_last_c_pos -= wrap_offset - prompt_invis_chars_first_line; - cpos_adjusted = 1; - } - } - } - 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) - { - /* If nfd begins at the prompt, or before the invisible - characters in the prompt, we need to adjust _rl_last_c_pos - in a multibyte locale to account for the wrap offset and - set cpos_adjusted accordingly. */ - _rl_output_some_chars (nfd, temp); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - _rl_last_c_pos += _rl_col_width (nfd, 0, temp); - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - else - _rl_last_c_pos += temp; - } - } - /* Otherwise, print over the existing material. */ - else - { - if (temp > 0) - { - /* If nfd begins at the prompt, or before the invisible - characters in the prompt, we need to adjust _rl_last_c_pos - in a multibyte locale to account for the wrap offset and - set cpos_adjusted accordingly. */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; /* XXX */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - } - 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 0 - if (col_lendiff) -#else - /* If we've already printed over the entire width of the screen, - including the old material, then col_lendiff doesn't matter and - space_to_eol will insert too many spaces. XXX - maybe we should - adjust col_lendiff based on the difference between _rl_last_c_pos - and _rl_screenwidth */ - if (col_lendiff && (_rl_last_c_pos < _rl_screenwidth)) -#endif - { - 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. rl_expand_prompt must have already been called - (explicitly or implicitly). This still doesn't work exactly right. */ -int -rl_on_new_line_with_prompt () -{ - int prompt_size, i, l, real_screenwidth, newlines; - char *prompt_last_line, *lprompt; - - /* 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. */ - lprompt = local_prompt ? local_prompt : rl_prompt; - strcpy (visible_line, lprompt); - strcpy (invisible_line, lprompt); - - /* 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); /* XXX */ - 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 () -{ - register char *temp; - - if (visible_line) - { - 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. - (Well, when we don't have multibyte characters, _rl_last_c_pos is a - buffer index.) - 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; - int woff; /* number of invisible chars on current line */ - int cpos, dpos; /* current and desired cursor positions */ - - woff = WRAP_OFFSET (_rl_last_v_pos, wrap_offset); - cpos = _rl_last_c_pos; -#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. We need to account for invisible characters in this line, - as long as we are past them and they are counted by _rl_col_width. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - dpos = _rl_col_width (data, 0, new); - /* Use NEW when comparing against the last invisible character in the - prompt string, since they're both buffer indices and DPOS is a - desired display position. */ - if ((new > prompt_last_invisible) || /* XXX - don't use woff here */ - (prompt_physical_chars > _rl_screenwidth && - _rl_last_v_pos == prompt_last_screen_line && - wrap_offset != woff && - new > (prompt_last_invisible-(_rl_screenwidth*_rl_last_v_pos)-wrap_offset))) - /* XXX last comparison might need to be >= */ - { - dpos -= woff; - /* Since this will be assigned to _rl_last_c_pos at the end (more - precisely, _rl_last_c_pos == dpos when this function returns), - let the caller know. */ - cpos_adjusted = 1; - } - } - else -#endif - dpos = new; - - /* If we don't have to do anything, then return. */ - if (cpos == dpos) - return; - - /* It may be faster to output a CR, and then move forwards instead - of moving backwards. */ - /* i == current physical cursor position. */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - i = _rl_last_c_pos; - else -#endif - i = _rl_last_c_pos - woff; - if (dpos == 0 || CR_FASTER (dpos, _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__ */ - cpos = _rl_last_c_pos = 0; - } - - if (cpos < dpos) - { - /* 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. */ - - /* However, we need a handle on where the current display position is - in the buffer for the immediately preceding comment to be true. - In multibyte locales, we don't currently have that info available. - Without it, we don't know where the data we have to display begins - in the buffer and we have to go back to the beginning of the screen - line. In this case, we can use the terminal sequence to move forward - if it's available. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (_rl_term_forward_char) - { - for (i = cpos; i < dpos; i++) - tputs (_rl_term_forward_char, 1, _rl_output_character_function); - } - else - { - tputs (_rl_term_cr, 1, _rl_output_character_function); - for (i = 0; i < new; i++) - putc (data[i], rl_outstream); - } - } - else - for (i = cpos; i < new; i++) - putc (data[i], rl_outstream); - } - -#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. */ -#endif - else if (cpos > dpos) - _rl_backspace (cpos - dpos); - - _rl_last_c_pos = dpos; -} - -/* 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. */ -static int msg_saved_prompt = 0; - -#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); - - if (saved_local_prompt == 0) - { - rl_save_prompt (); - msg_saved_prompt = 1; - } - rl_display_prompt = msg_buf; - local_prompt = expand_prompt (msg_buf, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)NULL; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - (*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; - if (saved_local_prompt == 0) - { - rl_save_prompt (); - msg_saved_prompt = 1; - } - local_prompt = expand_prompt (msg_buf, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)NULL; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - (*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; - if (msg_saved_prompt) - { - rl_restore_prompt (); - msg_saved_prompt = 0; - } - (*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; -} - -void -rl_save_prompt () -{ - saved_local_prompt = local_prompt; - saved_local_prefix = local_prompt_prefix; - saved_prefix_length = prompt_prefix_length; - saved_local_length = local_prompt_len; - 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; - local_prompt_len = 0; - prompt_last_invisible = prompt_visible_length = prompt_prefix_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; - local_prompt_len = saved_local_length; - prompt_prefix_length = saved_prefix_length; - 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; - - /* can test saved_local_prompt to see if prompt info has been saved. */ - saved_local_prompt = saved_local_prefix = (char *)0; - saved_local_length = 0; - saved_last_invisible = saved_visible_length = saved_prefix_length = 0; - saved_invis_chars_first_line = saved_physical_chars = 0; -} - -char * -_rl_make_prompt_for_search (pchar) - int pchar; -{ - int len; - char *pmt, *p; - - rl_save_prompt (); - - /* We've saved the prompt, and can do anything with the various prompt - strings we need before they're restored. We want the unexpanded - portion of the prompt string after any final newline. */ - p = rl_prompt ? strrchr (rl_prompt, '\n') : 0; - if (p == 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 - { - p++; - len = strlen (p); - pmt = (char *)xmalloc (len + 2); - if (len) - strcpy (pmt, p); - pmt[len] = pchar; - pmt[len+1] = '\0'; - } - - /* will be overwritten by expand_prompt, called from rl_message */ - prompt_physical_chars = saved_physical_chars + 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; -{ -#if defined (__MSDOS__) || defined (__MINGW32__) - _rl_output_some_chars (string, count); -#else - /* DEBUGGING */ - if (MB_CUR_MAX == 1 || rl_byte_oriented) - if (count != col) - _rl_ttymsg ("debug: insert_some_chars: count (%d) != col (%d)", 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); - } -#endif /* __MSDOS__ || __MINGW32__ */ -} - -/* Delete COUNT characters from the display line. */ -static void -delete_chars (count) - int count; -{ - if (count > _rl_screenwidth) /* XXX */ - return; - -#if !defined (__MSDOS__) && !defined (__MINGW32__) - 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); - } -#endif /* !__MSDOS__ && !__MINGW32__ */ -} - -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]]; - cpos_buffer_position = -1; /* don't know where we are in buffer */ - _rl_move_cursor_relative (_rl_screenwidth - 1, last_line); /* XXX */ - _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; - - oldp = rl_display_prompt; - rl_save_prompt (); - - 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; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - - rl_forced_update_display (); - - rl_display_prompt = oldp; - rl_restore_prompt(); -} - -/* Redisplay the current line after a SIGWINCH is received. */ -void -_rl_redisplay_after_sigwinch () -{ - char *t; - - /* Clear the last line (assuming that the screen size change will result in - either more or fewer characters on that line only) 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) - { - _rl_move_vert (_rl_vis_botlin); - -#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 (_rl_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; - int tmp, point, width, max; - - if (end <= start) - return 0; - if (MB_CUR_MAX == 1 || rl_byte_oriented) -{ -_rl_ttymsg ("_rl_col_width: called with MB_CUR_MAX == 1"); - return (end - start); -} - - memset (&ps, 0, sizeof (mbstate_t)); - - 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/display.c.save~ b/lib/readline/display.c.save~ deleted file mode 100644 index 267ebd93e..000000000 --- a/lib/readline/display.c.save~ +++ /dev/null @@ -1,2610 +0,0 @@ -/* display.c -- readline redisplay facility. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#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__ */ - -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)); - -/* State of visible and invisible lines. */ -struct line_state - { - char *line; - int *lbreaks; - int lbsize; -#if defined (HANDLE_MULTIBYTE) - int *wrapped_line; - int wbsize; -#endif - }; - -/* The line display buffers. One is the line currently displayed on - the screen. The other is the line about to be displayed. */ -static struct line_state line_state_array[2]; -static struct line_state *line_state_visible = &line_state_array[0]; -static struct line_state *line_state_invisible = &line_state_array[1]; -static int line_structures_initialized = 0; - -/* Backwards-compatible names. */ -#define inv_lbreaks (line_state_invisible->lbreaks) -#define inv_lbsize (line_state_invisible->lbsize) -#define vis_lbreaks (line_state_visible->lbreaks) -#define vis_lbsize (line_state_visible->lbsize) - -#define visible_line (line_state_visible->line) -#define invisible_line (line_state_invisible->line) - -#if defined (HANDLE_MULTIBYTE) -static int _rl_col_width PARAMS((const char *, int, int)); -#else -# define _rl_col_width(l, s, e) (((e) <= (s)) ? 0 : (e) - (s)) -#endif - -/* 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. CUR - and NEW are either both buffer positions or absolute screen positions. */ -#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new))) - -/* _rl_last_c_pos is an absolute cursor position in multibyte locales and a - buffer index in others. This macro is used when deciding whether the - current cursor position is in the middle of a prompt string containing - invisible characters. XXX - might need to take `modmark' into account. */ -#define PROMPT_ENDING_INDEX \ - ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) ? prompt_physical_chars : prompt_last_invisible+1) - - -/* **************************************************************** */ -/* */ -/* 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; -int _rl_want_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. */ -/* NOTE: _rl_last_c_pos is used as a buffer index when not in a locale - supporting multibyte characters, and an absolute cursor position when - in such a locale. This is an artifact of the donated multibyte support. - Care must be taken when modifying its value. */ -int _rl_last_c_pos = 0; -int _rl_last_v_pos = 0; - -static int cpos_adjusted; -static int cpos_buffer_position; -static int prompt_multibyte_chars; - -/* 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; - -/* 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 local_prompt_len; -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; - -/* set to a non-zero value by rl_redisplay if we are marking modified history - lines and the current line is so marked. */ -static int modmark; - -/* Variables to save and restore prompt and display information. */ - -/* 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_prefix_length; -static int saved_local_length; -static int saved_invis_chars_first_line; -static int saved_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, *igstart; - int l, rl, last, ignoring, ninvis, invfl, invflset, 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 */ - invflset = 0; /* we only want to set invfl once */ - - igstart = 0; - 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 (ignoring == 0 && *p == RL_PROMPT_START_IGNORE) /* XXX - check ignoring? */ - { - ignoring = 1; - igstart = p; - continue; - } - else if (ignoring && *p == RL_PROMPT_END_IGNORE) - { - ignoring = 0; - if (p != (igstart + 1)) - 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 ends up being assigned to prompt_visible_length, - which is the number of characters in the buffer that - contribute to characters on the screen, which might - not be the same as the number of physical characters - on the screen in the presence of multibyte characters */ - rl += ind - pind; - physchars += _rl_col_width (pmt, pind, ind); - } - else - ninvis += ind - pind; - p--; /* compensate for later increment */ - } - else -#endif - { - *r++ = *p; - if (!ignoring) - { - rl++; /* visible length byte counter */ - physchars++; - } - else - ninvis++; /* invisible chars byte counter */ - } - - if (invflset == 0 && rl >= _rl_screenwidth) - { - invfl = ninvis; - invflset = 1; - } - } - } - - 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; - local_prompt_len = 0; - prompt_last_invisible = prompt_invis_chars_first_line = 0; - prompt_visible_length = prompt_physical_chars = 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; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - return (prompt_visible_length); - } - else - { - /* The prompt spans multiple lines. */ - t = ++p; - local_prompt = expand_prompt (p, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - 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, - (int *)NULL, - (int *)NULL); - *t = c; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - 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; - -#if defined (HANDLE_MULTIBYTE) - line_state_visible->wbsize = vis_lbsize; - line_state_visible->wrapped_line = (int *)xmalloc (line_state_visible->wbsize * sizeof (int)); - - line_state_invisible->wbsize = inv_lbsize; - line_state_invisible->wrapped_line = (int *)xmalloc (line_state_invisible->wbsize * sizeof (int)); -#endif - - inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int)); - vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int)); - inv_lbreaks[0] = vis_lbreaks[0] = 0; - } - - line_structures_initialized = 1; -} - -/* Basic redisplay algorithm. */ -void -rl_redisplay () -{ - register int in, out, c, linenum, cursor_linenum; - register char *line; - int inv_botlin, lb_botlin, lb_linenum, o_cpos; - int newlines, lpos, temp, n0, num, prompt_lines_estimate; - 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 (_rl_echoing_p == 0) - return; - - /* Block keyboard interrupts because this function manipulates global - data structures. */ - _rl_block_sigint (); - - if (!rl_display_prompt) - rl_display_prompt = ""; - - if (line_structures_initialized == 0) - { - init_line_structures (0); - rl_on_new_line (); - } - - /* Draw the line into the buffer. */ - cpos_buffer_position = -1; - - prompt_multibyte_chars = prompt_visible_length - prompt_physical_chars; - - 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) - { - if (local_prompt_prefix && forced_display) - _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix)); - - if (local_prompt_len > 0) - { - temp = local_prompt_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_prompt_len); - out += local_prompt_len; - } - line[out] = '\0'; - wrap_offset = local_prompt_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)); \ - } \ - inv_lbreaks[++newlines] = out; \ - if (newlines >= (line_state_invisible->wbsize - 1)) \ - { \ - line_state_invisible->wbsize *= 2; \ - line_state_invisible->wrapped_line = (int *)xrealloc (line_state_invisible->wrapped_line, line_state_invisible->wbsize * sizeof(int)); \ - } \ - line_state_invisible->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; - lpos = prompt_physical_chars + modmark; - -#if defined (HANDLE_MULTIBYTE) - memset (line_state_invisible->wrapped_line, 0, line_state_invisible->wbsize * sizeof (int)); - num = 0; -#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 (or, more generally, last) line. */ - - /* This is zero-based, used to set the newlines */ - prompt_lines_estimate = lpos / _rl_screenwidth; - - /* what if lpos is already >= _rl_screenwidth before we start drawing the - contents of the command line? */ - while (lpos >= _rl_screenwidth) - { - int z; - /* 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 */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0) - { - n0 = num; - temp = local_prompt_len; - while (num < temp) - { - z = _rl_col_width (local_prompt, n0, num); - if (z > _rl_screenwidth) - { - num = _rl_find_prev_mbchar (local_prompt, num, MB_FIND_ANY); - break; - } - else if (z == _rl_screenwidth) - break; - num++; - } - temp = num; - } - else -#endif /* !HANDLE_MULTIBYTE */ - temp = ((newlines + 1) * _rl_screenwidth); - - /* Now account for invisible characters in the current line. */ - /* XXX - this assumes that the invisible characters may be split, but only - between the first and the last lines. */ - temp += ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line - : ((newlines == prompt_lines_estimate) ? wrap_offset : prompt_invis_chars_first_line)) - : ((newlines == 0) ? wrap_offset : 0)); - - inv_lbreaks[++newlines] = temp; -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0) - lpos -= _rl_col_width (local_prompt, n0, num); - else -#endif - 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 (cpos_buffer_position), 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) - { - cpos_buffer_position = 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) - { - cpos_buffer_position = 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 (cpos_buffer_position < 0) - { - cpos_buffer_position = out; - lb_linenum = newlines; - } - - inv_botlin = lb_botlin = newlines; - CHECK_INV_LBREAKS (); - inv_lbreaks[newlines+1] = out; - cursor_linenum = lb_linenum; - - /* CPOS_BUFFER_POSITION == 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, tx; - - 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 INVIS_FIRST() (prompt_physical_chars > _rl_screenwidth ? prompt_invis_chars_first_line : wrap_offset) -#define WRAP_OFFSET(line, offset) ((line == 0) \ - ? (offset ? INVIS_FIRST() : 0) \ - : ((line == prompt_last_screen_line) ? wrap_offset-prompt_invis_chars_first_line : 0)) -#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++) - { - /* This can lead us astray if we execute a program that changes - the locale from a non-multibyte to a multibyte one. */ - o_cpos = _rl_last_c_pos; - cpos_adjusted = 0; - update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum, - VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin); - - /* update_line potentially changes _rl_last_c_pos, but doesn't - take invisible characters into account, since _rl_last_c_pos - is an absolute cursor position in a multibyte locale. See - if compensating here is the right thing, or if we have to - change update_line itself. There is one case in which - update_line adjusts _rl_last_c_pos itself (so it can pass - _rl_move_cursor_relative accurate values); it communicates - this back by setting cpos_adjusted. If we assume that - _rl_last_c_pos is correct (an absolute cursor position) each - time update_line is called, then we can assume in our - calculations that o_cpos does not need to be adjusted by - wrap_offset. */ - if (linenum == 0 && (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > wrap_offset && - o_cpos < prompt_last_invisible) - _rl_last_c_pos -= prompt_invis_chars_first_line; /* XXX - was wrap_offset */ - else if (linenum == prompt_last_screen_line && prompt_physical_chars > _rl_screenwidth && - (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > (prompt_last_invisible - _rl_screenwidth - prompt_invis_chars_first_line)) - _rl_last_c_pos -= (wrap_offset-prompt_invis_chars_first_line); - - /* 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)) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - nleft = _rl_screenwidth - _rl_last_c_pos; - else - nleft = _rl_screenwidth + wrap_offset - _rl_last_c_pos; - if (nleft) - _rl_clear_to_eol (nleft); - } -#if 0 - /* This segment is intended to handle the case where the prompt - has invisible characters on the second line and the new line - to be displayed needs to clear the rest of the old characters - out (e.g., when printing the i-search prompt). In general, - the case of the new line being shorter than the old. - Incomplete */ - else if (linenum == prompt_last_screen_line && - prompt_physical_chars > _rl_screenwidth && - wrap_offset != prompt_invis_chars_first_line && - _rl_last_c_pos == out && -#endif - - - /* 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 ((MB_CUR_MAX == 1 || rl_byte_oriented) && 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 && -#if 0 - _rl_last_c_pos <= PROMPT_ENDING_INDEX && local_prompt) -#else - _rl_last_c_pos < PROMPT_ENDING_INDEX && local_prompt) -#endif - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - if (_rl_term_cr) - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - if (modmark) - _rl_output_some_chars ("*", 1); - - _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) - wrap_offset + modmark; - else - _rl_last_c_pos = nleft + modmark; - } - - /* 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 desired cursor position. */ - nleft = cpos_buffer_position - pos; - - /* NLEFT is now a number of characters in a buffer. When in a - multibyte locale, however, _rl_last_c_pos is an absolute cursor - position that doesn't take invisible characters in the prompt - into account. We use a fudge factor to compensate. */ - - /* 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) - { - /* TX == new physical cursor position in multibyte locale. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - tx = _rl_col_width (&visible_line[pos], 0, nleft) - visible_wrap_offset; - else - tx = nleft; - if (tx >= 0 && _rl_last_c_pos > tx) - { - _rl_backspace (_rl_last_c_pos - tx); /* XXX */ - _rl_last_c_pos = tx; - } - } - - /* We need to note that in a multibyte locale we are dealing with - _rl_last_c_pos as an absolute cursor position, but moving to a - point specified by a buffer position (NLEFT) that doesn't take - invisible characters into account. */ - 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 = cpos_buffer_position - 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 = cpos_buffer_position - (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 = cpos_buffer_position - (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 = ((cpos_buffer_position - 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 (cpos_buffer_position - lmargin, &invisible_line[lmargin]); - last_lmargin = lmargin; - } - } - fflush (rl_outstream); - - /* Swap visible and non-visible lines. */ - { - struct line_state *vtemp = line_state_visible; - - line_state_visible = line_state_invisible; - line_state_invisible = vtemp; - - 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; - } - - _rl_release_sigint (); -} - -/* 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, twidth, o_cpos; - int current_invis_chars; - int col_lendiff, col_temp; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps_new, ps_old; - int new_offset, old_offset; -#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. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - temp = _rl_last_c_pos; - else - temp = _rl_last_c_pos - WRAP_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 (current_line < line_state_visible->wbsize && line_state_visible->wrapped_line[current_line] > 0) - _rl_clear_to_eol (line_state_visible->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; - _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) /* adding at the end */ - { - 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 ((MB_CUR_MAX == 1 || rl_byte_oriented) && 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_len; - 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_ENDING_INDEX) - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - if (modmark) - _rl_output_some_chars ("*", 1); - _rl_output_some_chars (local_prompt, lendiff); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - /* We take wrap_offset into account here so we can pass correct - information to _rl_move_cursor_relative. */ - _rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff) - wrap_offset + modmark; - cpos_adjusted = 1; - } - else - _rl_last_c_pos = lendiff + modmark; - } - - o_cpos = _rl_last_c_pos; - - /* When this function returns, _rl_last_c_pos is correct, and an absolute - cursor postion in multibyte mode, but a buffer index when not in a - multibyte locale. */ - _rl_move_cursor_relative (od, old); -#if 1 -#if defined (HANDLE_MULTIBYTE) - /* We need to indicate that the cursor position is correct in the presence of - invisible characters in the prompt string. Let's see if setting this when - we make sure we're at the end of the drawn prompt string works. */ - if (current_line == 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0 && - (_rl_last_c_pos > 0 || o_cpos > 0) && - _rl_last_c_pos == prompt_physical_chars) - cpos_adjusted = 1; -#endif -#endif - - /* 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; - /* If col_lendiff is > 0, implying that the new string takes up more - screen real estate than the old, but lendiff is < 0, meaning that it - takes fewer bytes, we need to just output the characters starting - from the first difference. These will overwrite what is on the - display, so there's no reason to do a smart update. This can really - only happen in a multibyte environment. */ - if (lendiff < 0) - { - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += _rl_col_width (nfd, 0, temp); - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - return; - } - /* 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. */ - else 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 ((MB_CUR_MAX == 1 || rl_byte_oriented != 0) && *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 - { - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - 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); - /* 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. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - twidth = _rl_col_width (nfd+lendiff, 0, temp-col_lendiff); - else - twidth = temp - lendiff; - _rl_last_c_pos += twidth; - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - } - else - { - /* cannot insert chars, write to EOL */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - /* If we're in a multibyte locale and were before the last invisible - char in the current line (which implies we just output some invisible - characters) we need to adjust _rl_last_c_pos, since it represents - a physical character position. */ - } - } - 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) - { - /* If nfd begins at the prompt, or before the invisible - characters in the prompt, we need to adjust _rl_last_c_pos - in a multibyte locale to account for the wrap offset and - set cpos_adjusted accordingly. */ - _rl_output_some_chars (nfd, temp); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - _rl_last_c_pos += _rl_col_width (nfd, 0, temp); - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - else - _rl_last_c_pos += temp; - } - } - /* Otherwise, print over the existing material. */ - else - { - if (temp > 0) - { - /* If nfd begins at the prompt, or before the invisible - characters in the prompt, we need to adjust _rl_last_c_pos - in a multibyte locale to account for the wrap offset and - set cpos_adjusted accordingly. */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; /* XXX */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - } - 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 0 - if (col_lendiff) -#else - /* If we've already printed over the entire width of the screen, - including the old material, then col_lendiff doesn't matter and - space_to_eol will insert too many spaces. XXX - maybe we should - adjust col_lendiff based on the difference between _rl_last_c_pos - and _rl_screenwidth */ - if (col_lendiff && (_rl_last_c_pos < _rl_screenwidth)) -#endif - { - 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. rl_expand_prompt must have already been called - (explicitly or implicitly). This still doesn't work exactly right. */ -int -rl_on_new_line_with_prompt () -{ - int prompt_size, i, l, real_screenwidth, newlines; - char *prompt_last_line, *lprompt; - - /* 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. */ - lprompt = local_prompt ? local_prompt : rl_prompt; - strcpy (visible_line, lprompt); - strcpy (invisible_line, lprompt); - - /* 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); /* XXX */ - 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 () -{ - register char *temp; - - if (visible_line) - { - 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. - (Well, when we don't have multibyte characters, _rl_last_c_pos is a - buffer index.) - 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; - int woff; /* number of invisible chars on current line */ - int cpos, dpos; /* current and desired cursor positions */ - - woff = WRAP_OFFSET (_rl_last_v_pos, wrap_offset); - cpos = _rl_last_c_pos; -#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. We need to account for invisible characters in this line, - as long as we are past them and they are counted by _rl_col_width. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - dpos = _rl_col_width (data, 0, new); - /* Use NEW when comparing against the last invisible character in the - prompt string, since they're both buffer indices and DPOS is a - desired display position. */ - if ((new > prompt_last_invisible) || /* XXX - don't use woff here */ - (prompt_physical_chars > _rl_screenwidth && - _rl_last_v_pos == prompt_last_screen_line && - wrap_offset != woff && - new > (prompt_last_invisible-_rl_screenwidth-wrap_offset))) - { - dpos -= woff; - /* Since this will be assigned to _rl_last_c_pos at the end (more - precisely, _rl_last_c_pos == dpos when this function returns), - let the caller know. */ - cpos_adjusted = 1; - } - } - else -#endif - dpos = new; - - /* If we don't have to do anything, then return. */ - if (cpos == dpos) - return; - - /* It may be faster to output a CR, and then move forwards instead - of moving backwards. */ - /* i == current physical cursor position. */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - i = _rl_last_c_pos; - else -#endif - i = _rl_last_c_pos - woff; - if (dpos == 0 || CR_FASTER (dpos, _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__ */ - cpos = _rl_last_c_pos = 0; - } - - if (cpos < dpos) - { - /* 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. */ - - /* However, we need a handle on where the current display position is - in the buffer for the immediately preceding comment to be true. - In multibyte locales, we don't currently have that info available. - Without it, we don't know where the data we have to display begins - in the buffer and we have to go back to the beginning of the screen - line. In this case, we can use the terminal sequence to move forward - if it's available. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (_rl_term_forward_char) - { - for (i = cpos; i < dpos; i++) - tputs (_rl_term_forward_char, 1, _rl_output_character_function); - } - else - { - tputs (_rl_term_cr, 1, _rl_output_character_function); - for (i = 0; i < new; i++) - putc (data[i], rl_outstream); - } - } - else - for (i = cpos; i < new; i++) - putc (data[i], rl_outstream); - } - -#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. */ -#endif - else if (cpos > dpos) - _rl_backspace (cpos - dpos); - - _rl_last_c_pos = dpos; -} - -/* 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. */ -static int msg_saved_prompt = 0; - -#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); - - if (saved_local_prompt == 0) - { - rl_save_prompt (); - msg_saved_prompt = 1; - } - rl_display_prompt = msg_buf; - local_prompt = expand_prompt (msg_buf, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)NULL; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - (*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; - if (saved_local_prompt == 0) - { - rl_save_prompt (); - msg_saved_prompt = 1; - } - local_prompt = expand_prompt (msg_buf, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)NULL; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - (*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; - if (msg_saved_prompt) - { - rl_restore_prompt (); - msg_saved_prompt = 0; - } - (*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; -} - -void -rl_save_prompt () -{ - saved_local_prompt = local_prompt; - saved_local_prefix = local_prompt_prefix; - saved_prefix_length = prompt_prefix_length; - saved_local_length = local_prompt_len; - 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; - local_prompt_len = 0; - prompt_last_invisible = prompt_visible_length = prompt_prefix_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; - local_prompt_len = saved_local_length; - prompt_prefix_length = saved_prefix_length; - 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; - - /* can test saved_local_prompt to see if prompt info has been saved. */ - saved_local_prompt = saved_local_prefix = (char *)0; - saved_local_length = 0; - saved_last_invisible = saved_visible_length = saved_prefix_length = 0; - saved_invis_chars_first_line = saved_physical_chars = 0; -} - -char * -_rl_make_prompt_for_search (pchar) - int pchar; -{ - int len; - char *pmt, *p; - - rl_save_prompt (); - - /* We've saved the prompt, and can do anything with the various prompt - strings we need before they're restored. We want the unexpanded - portion of the prompt string after any final newline. */ - p = rl_prompt ? strrchr (rl_prompt, '\n') : 0; - if (p == 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 - { - p++; - len = strlen (p); - pmt = (char *)xmalloc (len + 2); - if (len) - strcpy (pmt, p); - pmt[len] = pchar; - pmt[len+1] = '\0'; - } - - /* will be overwritten by expand_prompt, called from rl_message */ - prompt_physical_chars = saved_physical_chars + 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; -{ -#if defined (__MSDOS__) || defined (__MINGW32__) - _rl_output_some_chars (string, count); -#else - /* DEBUGGING */ - if (MB_CUR_MAX == 1 || rl_byte_oriented) - if (count != col) - _rl_ttymsg ("debug: insert_some_chars: count (%d) != col (%d)", 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); - } -#endif /* __MSDOS__ || __MINGW32__ */ -} - -/* Delete COUNT characters from the display line. */ -static void -delete_chars (count) - int count; -{ - if (count > _rl_screenwidth) /* XXX */ - return; - -#if !defined (__MSDOS__) && !defined (__MINGW32__) - 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); - } -#endif /* !__MSDOS__ && !__MINGW32__ */ -} - -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]]; - cpos_buffer_position = -1; /* don't know where we are in buffer */ - _rl_move_cursor_relative (_rl_screenwidth - 1, last_line); /* XXX */ - _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; - - oldp = rl_display_prompt; - rl_save_prompt (); - - 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; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - - rl_forced_update_display (); - - rl_display_prompt = oldp; - rl_restore_prompt(); -} - -/* Redisplay the current line after a SIGWINCH is received. */ -void -_rl_redisplay_after_sigwinch () -{ - char *t; - - /* Clear the last line (assuming that the screen size change will result in - either more or fewer characters on that line only) 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) - { - _rl_move_vert (_rl_vis_botlin); - -#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 (_rl_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; - int tmp, point, width, max; - - if (end <= start) - return 0; - if (MB_CUR_MAX == 1 || rl_byte_oriented) -{ -_rl_ttymsg ("_rl_col_width: called with MB_CUR_MAX == 1"); - return (end - start); -} - - memset (&ps, 0, sizeof (mbstate_t)); - - 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/display.c~ b/lib/readline/display.c~ deleted file mode 100644 index 383c00088..000000000 --- a/lib/readline/display.c~ +++ /dev/null @@ -1,2637 +0,0 @@ -/* display.c -- readline redisplay facility. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#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__ */ - -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)); - -/* State of visible and invisible lines. */ -struct line_state - { - char *line; - int *lbreaks; - int lbsize; -#if defined (HANDLE_MULTIBYTE) - int *wrapped_line; - int wbsize; -#endif - }; - -/* The line display buffers. One is the line currently displayed on - the screen. The other is the line about to be displayed. */ -static struct line_state line_state_array[2]; -static struct line_state *line_state_visible = &line_state_array[0]; -static struct line_state *line_state_invisible = &line_state_array[1]; -static int line_structures_initialized = 0; - -/* Backwards-compatible names. */ -#define inv_lbreaks (line_state_invisible->lbreaks) -#define inv_lbsize (line_state_invisible->lbsize) -#define vis_lbreaks (line_state_visible->lbreaks) -#define vis_lbsize (line_state_visible->lbsize) - -#define visible_line (line_state_visible->line) -#define invisible_line (line_state_invisible->line) - -#if defined (HANDLE_MULTIBYTE) -static int _rl_col_width PARAMS((const char *, int, int)); -#else -# define _rl_col_width(l, s, e) (((e) <= (s)) ? 0 : (e) - (s)) -#endif - -/* 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. CUR - and NEW are either both buffer positions or absolute screen positions. */ -#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new))) - -/* _rl_last_c_pos is an absolute cursor position in multibyte locales and a - buffer index in others. This macro is used when deciding whether the - current cursor position is in the middle of a prompt string containing - invisible characters. XXX - might need to take `modmark' into account. */ -#define PROMPT_ENDING_INDEX \ - ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) ? prompt_physical_chars : prompt_last_invisible+1) - - -/* **************************************************************** */ -/* */ -/* 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; -int _rl_want_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. */ -/* NOTE: _rl_last_c_pos is used as a buffer index when not in a locale - supporting multibyte characters, and an absolute cursor position when - in such a locale. This is an artifact of the donated multibyte support. - Care must be taken when modifying its value. */ -int _rl_last_c_pos = 0; -int _rl_last_v_pos = 0; - -static int cpos_adjusted; -static int cpos_buffer_position; -static int prompt_multibyte_chars; - -/* 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; - -/* 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 local_prompt_len; -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; - -/* set to a non-zero value by rl_redisplay if we are marking modified history - lines and the current line is so marked. */ -static int modmark; - -/* Variables to save and restore prompt and display information. */ - -/* 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_prefix_length; -static int saved_local_length; -static int saved_invis_chars_first_line; -static int saved_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, *igstart; - int l, rl, last, ignoring, ninvis, invfl, invflset, 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 */ - invflset = 0; /* we only want to set invfl once */ - - igstart = 0; - 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 (ignoring == 0 && *p == RL_PROMPT_START_IGNORE) /* XXX - check ignoring? */ - { - ignoring = 1; - igstart = p; - continue; - } - else if (ignoring && *p == RL_PROMPT_END_IGNORE) - { - ignoring = 0; - if (p != (igstart + 1)) - 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 ends up being assigned to prompt_visible_length, - which is the number of characters in the buffer that - contribute to characters on the screen, which might - not be the same as the number of physical characters - on the screen in the presence of multibyte characters */ - rl += ind - pind; - physchars += _rl_col_width (pmt, pind, ind); - } - else - ninvis += ind - pind; - p--; /* compensate for later increment */ - } - else -#endif - { - *r++ = *p; - if (!ignoring) - { - rl++; /* visible length byte counter */ - physchars++; - } - else - ninvis++; /* invisible chars byte counter */ - } - - if (invflset == 0 && rl >= _rl_screenwidth) - { - invfl = ninvis; - invflset = 1; - } - } - } - - 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; - local_prompt_len = 0; - prompt_last_invisible = prompt_invis_chars_first_line = 0; - prompt_visible_length = prompt_physical_chars = 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; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - return (prompt_visible_length); - } - else - { - /* The prompt spans multiple lines. */ - t = ++p; - local_prompt = expand_prompt (p, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - 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, - (int *)NULL, - (int *)NULL); - *t = c; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - 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; - -#if defined (HANDLE_MULTIBYTE) - line_state_visible->wbsize = vis_lbsize; - line_state_visible->wrapped_line = (int *)xmalloc (line_state_visible->wbsize * sizeof (int)); - - line_state_invisible->wbsize = inv_lbsize; - line_state_invisible->wrapped_line = (int *)xmalloc (line_state_invisible->wbsize * sizeof (int)); -#endif - - inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int)); - vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int)); - inv_lbreaks[0] = vis_lbreaks[0] = 0; - } - - line_structures_initialized = 1; -} - -/* Basic redisplay algorithm. */ -void -rl_redisplay () -{ - register int in, out, c, linenum, cursor_linenum; - register char *line; - int inv_botlin, lb_botlin, lb_linenum, o_cpos; - int newlines, lpos, temp, n0, num, prompt_lines_estimate; - 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 (_rl_echoing_p == 0) - return; - - /* Block keyboard interrupts because this function manipulates global - data structures. */ - _rl_block_sigint (); - - if (!rl_display_prompt) - rl_display_prompt = ""; - - if (line_structures_initialized == 0) - { - init_line_structures (0); - rl_on_new_line (); - } - - /* Draw the line into the buffer. */ - cpos_buffer_position = -1; - - prompt_multibyte_chars = prompt_visible_length - prompt_physical_chars; - - 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) - { - if (local_prompt_prefix && forced_display) - _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix)); - - if (local_prompt_len > 0) - { - temp = local_prompt_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_prompt_len); - out += local_prompt_len; - } - line[out] = '\0'; - wrap_offset = local_prompt_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)); \ - } \ - inv_lbreaks[++newlines] = out; \ - if (newlines >= (line_state_invisible->wbsize - 1)) \ - { \ - line_state_invisible->wbsize *= 2; \ - line_state_invisible->wrapped_line = (int *)xrealloc (line_state_invisible->wrapped_line, line_state_invisible->wbsize * sizeof(int)); \ - } \ - line_state_invisible->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; - lpos = prompt_physical_chars + modmark; - -#if defined (HANDLE_MULTIBYTE) - memset (line_state_invisible->wrapped_line, 0, line_state_invisible->wbsize * sizeof (int)); - num = 0; -#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 (or, more generally, last) line. */ - - /* This is zero-based, used to set the newlines */ - prompt_lines_estimate = lpos / _rl_screenwidth; - - /* what if lpos is already >= _rl_screenwidth before we start drawing the - contents of the command line? */ - while (lpos >= _rl_screenwidth) - { - int z; - /* 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 */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0) - { - n0 = num; - temp = local_prompt_len; - while (num < temp) - { - z = _rl_col_width (local_prompt, n0, num); - if (z > _rl_screenwidth) - { - num = _rl_find_prev_mbchar (local_prompt, num, MB_FIND_ANY); - break; - } - else if (z == _rl_screenwidth) - break; - num++; - } - temp = num; - } - else -#endif /* !HANDLE_MULTIBYTE */ - temp = ((newlines + 1) * _rl_screenwidth); - - /* Now account for invisible characters in the current line. */ - /* XXX - this assumes that the invisible characters may be split, but only - between the first and the last lines. */ - temp += ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line - : ((newlines == prompt_lines_estimate) ? wrap_offset : prompt_invis_chars_first_line)) - : ((newlines == 0) ? wrap_offset : 0)); - - inv_lbreaks[++newlines] = temp; -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0) - lpos -= _rl_col_width (local_prompt, n0, num); - else -#endif - 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 (cpos_buffer_position), 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) - { - cpos_buffer_position = 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) - { - cpos_buffer_position = 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 (cpos_buffer_position < 0) - { - cpos_buffer_position = out; - lb_linenum = newlines; - } - - inv_botlin = lb_botlin = newlines; - CHECK_INV_LBREAKS (); - inv_lbreaks[newlines+1] = out; - cursor_linenum = lb_linenum; - - /* CPOS_BUFFER_POSITION == 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, tx; - - 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 INVIS_FIRST() (prompt_physical_chars > _rl_screenwidth ? prompt_invis_chars_first_line : wrap_offset) -#define WRAP_OFFSET(line, offset) ((line == 0) \ - ? (offset ? INVIS_FIRST() : 0) \ - : ((line == prompt_last_screen_line) ? wrap_offset-prompt_invis_chars_first_line : 0)) -#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++) - { - /* This can lead us astray if we execute a program that changes - the locale from a non-multibyte to a multibyte one. */ - o_cpos = _rl_last_c_pos; - cpos_adjusted = 0; - update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum, - VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin); - - /* update_line potentially changes _rl_last_c_pos, but doesn't - take invisible characters into account, since _rl_last_c_pos - is an absolute cursor position in a multibyte locale. See - if compensating here is the right thing, or if we have to - change update_line itself. There are several cases in which - update_line adjusts _rl_last_c_pos itself (so it can pass - _rl_move_cursor_relative accurate values); it communicates - this back by setting cpos_adjusted. If we assume that - _rl_last_c_pos is correct (an absolute cursor position) each - time update_line is called, then we can assume in our - calculations that o_cpos does not need to be adjusted by - wrap_offset. */ - if (linenum == 0 && (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > wrap_offset && - o_cpos < prompt_last_invisible) - _rl_last_c_pos -= prompt_invis_chars_first_line; /* XXX - was wrap_offset */ - else if (linenum == prompt_last_screen_line && prompt_physical_chars > _rl_screenwidth && - (MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - cpos_adjusted == 0 && - _rl_last_c_pos != o_cpos && - _rl_last_c_pos > (prompt_last_invisible - _rl_screenwidth - prompt_invis_chars_first_line)) - _rl_last_c_pos -= (wrap_offset-prompt_invis_chars_first_line); - - /* 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)) - { - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - nleft = _rl_screenwidth - _rl_last_c_pos; - else - nleft = _rl_screenwidth + wrap_offset - _rl_last_c_pos; - if (nleft) - _rl_clear_to_eol (nleft); - } -#if 0 - /* This segment is intended to handle the case where the prompt - has invisible characters on the second line and the new line - to be displayed needs to clear the rest of the old characters - out (e.g., when printing the i-search prompt). In general, - the case of the new line being shorter than the old. - Incomplete */ - else if (linenum == prompt_last_screen_line && - prompt_physical_chars > _rl_screenwidth && - wrap_offset != prompt_invis_chars_first_line && - _rl_last_c_pos == out && -#endif - - - /* 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 ((MB_CUR_MAX == 1 || rl_byte_oriented) && 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 && -#if 0 - _rl_last_c_pos <= PROMPT_ENDING_INDEX && local_prompt) -#else - _rl_last_c_pos < PROMPT_ENDING_INDEX && local_prompt) -#endif - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - if (_rl_term_cr) - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - if (modmark) - _rl_output_some_chars ("*", 1); - - _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) - wrap_offset + modmark; - else - _rl_last_c_pos = nleft + modmark; - } - - /* 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 desired cursor position. */ - nleft = cpos_buffer_position - pos; - - /* NLEFT is now a number of characters in a buffer. When in a - multibyte locale, however, _rl_last_c_pos is an absolute cursor - position that doesn't take invisible characters in the prompt - into account. We use a fudge factor to compensate. */ - - /* 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) - { - /* TX == new physical cursor position in multibyte locale. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - tx = _rl_col_width (&visible_line[pos], 0, nleft) - visible_wrap_offset; - else - tx = nleft; - if (tx >= 0 && _rl_last_c_pos > tx) - { - _rl_backspace (_rl_last_c_pos - tx); /* XXX */ - _rl_last_c_pos = tx; - } - } - - /* We need to note that in a multibyte locale we are dealing with - _rl_last_c_pos as an absolute cursor position, but moving to a - point specified by a buffer position (NLEFT) that doesn't take - invisible characters into account. */ - 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 = cpos_buffer_position - 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 = cpos_buffer_position - (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 = cpos_buffer_position - (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 = ((cpos_buffer_position - 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 (cpos_buffer_position - lmargin, &invisible_line[lmargin]); - last_lmargin = lmargin; - } - } - fflush (rl_outstream); - - /* Swap visible and non-visible lines. */ - { - struct line_state *vtemp = line_state_visible; - - line_state_visible = line_state_invisible; - line_state_invisible = vtemp; - - 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; - } - - _rl_release_sigint (); -} - -/* 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, twidth, o_cpos; - int current_invis_chars; - int col_lendiff, col_temp; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps_new, ps_old; - int new_offset, old_offset; -#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. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - temp = _rl_last_c_pos; - else - temp = _rl_last_c_pos - WRAP_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 (current_line < line_state_visible->wbsize && line_state_visible->wrapped_line[current_line] > 0) - _rl_clear_to_eol (line_state_visible->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; - _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) /* adding at the end */ - { - 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 ((MB_CUR_MAX == 1 || rl_byte_oriented) && 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_len; - 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_ENDING_INDEX) - { -#if defined (__MSDOS__) - putc ('\r', rl_outstream); -#else - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif - if (modmark) - _rl_output_some_chars ("*", 1); - _rl_output_some_chars (local_prompt, lendiff); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - /* We take wrap_offset into account here so we can pass correct - information to _rl_move_cursor_relative. */ - _rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff) - wrap_offset + modmark; - cpos_adjusted = 1; - } - else - _rl_last_c_pos = lendiff + modmark; - } - - o_cpos = _rl_last_c_pos; - - /* When this function returns, _rl_last_c_pos is correct, and an absolute - cursor postion in multibyte mode, but a buffer index when not in a - multibyte locale. */ - _rl_move_cursor_relative (od, old); -#if 1 -#if defined (HANDLE_MULTIBYTE) - /* We need to indicate that the cursor position is correct in the presence of - invisible characters in the prompt string. Let's see if setting this when - we make sure we're at the end of the drawn prompt string works. */ - if (current_line == 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0 && - (_rl_last_c_pos > 0 || o_cpos > 0) && - _rl_last_c_pos == prompt_physical_chars) - cpos_adjusted = 1; -#endif -#endif - - /* 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; - /* If col_lendiff is > 0, implying that the new string takes up more - screen real estate than the old, but lendiff is < 0, meaning that it - takes fewer bytes, we need to just output the characters starting - from the first difference. These will overwrite what is on the - display, so there's no reason to do a smart update. This can really - only happen in a multibyte environment. */ - if (lendiff < 0) - { - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += _rl_col_width (nfd, 0, temp); - /* If nfd begins before any invisible characters in the prompt, - adjust _rl_last_c_pos to account for wrap_offset and set - cpos_adjusted to let the caller know. */ - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - return; - } - /* 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. */ - else 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. */ - /* The same thing happens if we're trying to draw before the last - invisible character in the prompt string or we're increasing the - number of invisible characters in the line and we're not drawing - the entire prompt string. */ - if (*ols && ((_rl_horizontal_scroll_mode && - _rl_last_c_pos == 0 && - lendiff > prompt_visible_length && - current_invis_chars > 0) == 0) && - (((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - current_line == 0 && wrap_offset && - ((nfd - new) <= prompt_last_invisible) && - (col_lendiff < prompt_visible_length)) == 0) && - (visible_wrap_offset >= current_invis_chars)) - { - insert_some_chars (nfd, lendiff, col_lendiff); - _rl_last_c_pos += col_lendiff; - } -#if 0 /* XXX - for now */ - else if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && _rl_last_c_pos == 0 && wrap_offset && (nfd-new) <= prompt_last_invisible && col_lendiff < prompt_visible_length && visible_wrap_offset >= current_invis_chars) - { - _rl_output_some_chars (nfd, lendiff); - _rl_last_c_pos += col_lendiff; - } -#endif - else if ((MB_CUR_MAX == 1 || rl_byte_oriented != 0) && *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 - { - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - /* If nfd begins before the last invisible character in the - prompt, adjust _rl_last_c_pos to account for wrap_offset - and set cpos_adjusted to let the caller know. */ - if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - 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); - /* 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. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - twidth = _rl_col_width (nfd+lendiff, 0, temp-col_lendiff); - else - twidth = temp - lendiff; - _rl_last_c_pos += twidth; - /* If nfd begins before the last invisible character in the - prompt, adjust _rl_last_c_pos to account for wrap_offset - and set cpos_adjusted to let the caller know. */ - if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - } - else - { - /* cannot insert chars, write to EOL */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; - /* If we're in a multibyte locale and were before the last invisible - char in the current line (which implies we just output some invisible - characters) we need to adjust _rl_last_c_pos, since it represents - a physical character position. */ - if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && - current_line == prompt_last_screen_line && wrap_offset && - wrap_offset != prompt_invis_chars_first_line && - ((nfd-new) < (prompt_last_invisible-(current_line*_rl_screenwidth)))) - { - _rl_last_c_pos -= wrap_offset - prompt_invis_chars_first_line; - cpos_adjusted = 1; - } - } - } - 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) - { - /* If nfd begins at the prompt, or before the invisible - characters in the prompt, we need to adjust _rl_last_c_pos - in a multibyte locale to account for the wrap offset and - set cpos_adjusted accordingly. */ - _rl_output_some_chars (nfd, temp); - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - _rl_last_c_pos += _rl_col_width (nfd, 0, temp); - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - else - _rl_last_c_pos += temp; - } - } - /* Otherwise, print over the existing material. */ - else - { - if (temp > 0) - { - /* If nfd begins at the prompt, or before the invisible - characters in the prompt, we need to adjust _rl_last_c_pos - in a multibyte locale to account for the wrap offset and - set cpos_adjusted accordingly. */ - _rl_output_some_chars (nfd, temp); - _rl_last_c_pos += col_temp; /* XXX */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible)) - { - _rl_last_c_pos -= wrap_offset; - cpos_adjusted = 1; - } - } - } - 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 0 - if (col_lendiff) -#else - /* If we've already printed over the entire width of the screen, - including the old material, then col_lendiff doesn't matter and - space_to_eol will insert too many spaces. XXX - maybe we should - adjust col_lendiff based on the difference between _rl_last_c_pos - and _rl_screenwidth */ - if (col_lendiff && (_rl_last_c_pos < _rl_screenwidth)) -#endif - { - 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. rl_expand_prompt must have already been called - (explicitly or implicitly). This still doesn't work exactly right. */ -int -rl_on_new_line_with_prompt () -{ - int prompt_size, i, l, real_screenwidth, newlines; - char *prompt_last_line, *lprompt; - - /* 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. */ - lprompt = local_prompt ? local_prompt : rl_prompt; - strcpy (visible_line, lprompt); - strcpy (invisible_line, lprompt); - - /* 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); /* XXX */ - 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 () -{ - register char *temp; - - if (visible_line) - { - 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. - (Well, when we don't have multibyte characters, _rl_last_c_pos is a - buffer index.) - 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; - int woff; /* number of invisible chars on current line */ - int cpos, dpos; /* current and desired cursor positions */ - - woff = WRAP_OFFSET (_rl_last_v_pos, wrap_offset); - cpos = _rl_last_c_pos; -#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. We need to account for invisible characters in this line, - as long as we are past them and they are counted by _rl_col_width. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - dpos = _rl_col_width (data, 0, new); - /* Use NEW when comparing against the last invisible character in the - prompt string, since they're both buffer indices and DPOS is a - desired display position. */ - if ((new > prompt_last_invisible) || /* XXX - don't use woff here */ - (prompt_physical_chars > _rl_screenwidth && - _rl_last_v_pos == prompt_last_screen_line && - wrap_offset != woff && - new > (prompt_last_invisible-(_rl_screenwidth*_rl_last_v_pos)-wrap_offset))) - /* XXX last comparison might need to be >= */ - { - dpos -= woff; - /* Since this will be assigned to _rl_last_c_pos at the end (more - precisely, _rl_last_c_pos == dpos when this function returns), - let the caller know. */ - cpos_adjusted = 1; - } - } - else -#endif - dpos = new; - - /* If we don't have to do anything, then return. */ - if (cpos == dpos) - return; - - /* It may be faster to output a CR, and then move forwards instead - of moving backwards. */ - /* i == current physical cursor position. */ -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - i = _rl_last_c_pos; - else -#endif - i = _rl_last_c_pos - woff; - if (dpos == 0 || CR_FASTER (dpos, _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__ */ - cpos = _rl_last_c_pos = 0; - } - - if (cpos < dpos) - { - /* 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. */ - - /* However, we need a handle on where the current display position is - in the buffer for the immediately preceding comment to be true. - In multibyte locales, we don't currently have that info available. - Without it, we don't know where the data we have to display begins - in the buffer and we have to go back to the beginning of the screen - line. In this case, we can use the terminal sequence to move forward - if it's available. */ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (_rl_term_forward_char) - { - for (i = cpos; i < dpos; i++) - tputs (_rl_term_forward_char, 1, _rl_output_character_function); - } - else - { - tputs (_rl_term_cr, 1, _rl_output_character_function); - for (i = 0; i < new; i++) - putc (data[i], rl_outstream); - } - } - else - for (i = cpos; i < new; i++) - putc (data[i], rl_outstream); - } - -#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. */ -#endif - else if (cpos > dpos) - _rl_backspace (cpos - dpos); - - _rl_last_c_pos = dpos; -} - -/* 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. */ -static int msg_saved_prompt = 0; - -#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); - - if (saved_local_prompt == 0) - { - rl_save_prompt (); - msg_saved_prompt = 1; - } - rl_display_prompt = msg_buf; - local_prompt = expand_prompt (msg_buf, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)NULL; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - (*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; - if (saved_local_prompt == 0) - { - rl_save_prompt (); - msg_saved_prompt = 1; - } - local_prompt = expand_prompt (msg_buf, &prompt_visible_length, - &prompt_last_invisible, - &prompt_invis_chars_first_line, - &prompt_physical_chars); - local_prompt_prefix = (char *)NULL; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - (*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; - if (msg_saved_prompt) - { - rl_restore_prompt (); - msg_saved_prompt = 0; - } - (*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; -} - -void -rl_save_prompt () -{ - saved_local_prompt = local_prompt; - saved_local_prefix = local_prompt_prefix; - saved_prefix_length = prompt_prefix_length; - saved_local_length = local_prompt_len; - 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; - local_prompt_len = 0; - prompt_last_invisible = prompt_visible_length = prompt_prefix_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; - local_prompt_len = saved_local_length; - prompt_prefix_length = saved_prefix_length; - 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; - - /* can test saved_local_prompt to see if prompt info has been saved. */ - saved_local_prompt = saved_local_prefix = (char *)0; - saved_local_length = 0; - saved_last_invisible = saved_visible_length = saved_prefix_length = 0; - saved_invis_chars_first_line = saved_physical_chars = 0; -} - -char * -_rl_make_prompt_for_search (pchar) - int pchar; -{ - int len; - char *pmt, *p; - - rl_save_prompt (); - - /* We've saved the prompt, and can do anything with the various prompt - strings we need before they're restored. We want the unexpanded - portion of the prompt string after any final newline. */ - p = rl_prompt ? strrchr (rl_prompt, '\n') : 0; - if (p == 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 - { - p++; - len = strlen (p); - pmt = (char *)xmalloc (len + 2); - if (len) - strcpy (pmt, p); - pmt[len] = pchar; - pmt[len+1] = '\0'; - } - - /* will be overwritten by expand_prompt, called from rl_message */ - prompt_physical_chars = saved_physical_chars + 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; -{ -#if defined (__MSDOS__) || defined (__MINGW32__) - _rl_output_some_chars (string, count); -#else - /* DEBUGGING */ - if (MB_CUR_MAX == 1 || rl_byte_oriented) - if (count != col) - _rl_ttymsg ("debug: insert_some_chars: count (%d) != col (%d)", 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); - } -#endif /* __MSDOS__ || __MINGW32__ */ -} - -/* Delete COUNT characters from the display line. */ -static void -delete_chars (count) - int count; -{ - if (count > _rl_screenwidth) /* XXX */ - return; - -#if !defined (__MSDOS__) && !defined (__MINGW32__) - 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); - } -#endif /* !__MSDOS__ && !__MINGW32__ */ -} - -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]]; - cpos_buffer_position = -1; /* don't know where we are in buffer */ - _rl_move_cursor_relative (_rl_screenwidth - 1, last_line); /* XXX */ - _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; - - oldp = rl_display_prompt; - rl_save_prompt (); - - 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; - local_prompt_len = local_prompt ? strlen (local_prompt) : 0; - - rl_forced_update_display (); - - rl_display_prompt = oldp; - rl_restore_prompt(); -} - -/* Redisplay the current line after a SIGWINCH is received. */ -void -_rl_redisplay_after_sigwinch () -{ - char *t; - - /* Clear the last line (assuming that the screen size change will result in - either more or fewer characters on that line only) 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) - { - _rl_move_vert (_rl_vis_botlin); - -#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 (_rl_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; - int tmp, point, width, max; - - if (end <= start) - return 0; - if (MB_CUR_MAX == 1 || rl_byte_oriented) -{ -_rl_ttymsg ("_rl_col_width: called with MB_CUR_MAX == 1"); - return (end - start); -} - - memset (&ps, 0, sizeof (mbstate_t)); - - 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/Makefile.old b/lib/readline/doc/Makefile.old deleted file mode 100644 index 58d4dd762..000000000 --- a/lib/readline/doc/Makefile.old +++ /dev/null @@ -1,76 +0,0 @@ -# This makefile for Readline library documentation is in -*- text -*- mode. -# Emacs likes it that way. -RM = rm -f - -MAKEINFO = makeinfo -TEXI2DVI = texi2dvi -TEXI2HTML = texi2html -QUIETPS = #set this to -q to shut up dvips -DVIPS = dvips -D 300 $(QUIETPS) -o $@ # tricky - -INSTALL_DATA = cp -infodir = /usr/local/info - -RLSRC = rlman.texinfo rluser.texinfo rltech.texinfo -HISTSRC = hist.texinfo hsuser.texinfo hstech.texinfo - -DVIOBJ = readline.dvi history.dvi -INFOOBJ = readline.info history.info -PSOBJ = readline.ps history.ps -HTMLOBJ = readline.html history.html - -all: info dvi html ps -nodvi: info html - -readline.dvi: $(RLSRC) - $(TEXI2DVI) rlman.texinfo - mv rlman.dvi readline.dvi - -readline.info: $(RLSRC) - $(MAKEINFO) --no-split -o $@ rlman.texinfo - -history.dvi: ${HISTSRC} - $(TEXI2DVI) hist.texinfo - mv hist.dvi history.dvi - -history.info: ${HISTSRC} - $(MAKEINFO) --no-split -o $@ hist.texinfo - -readline.ps: readline.dvi - $(RM) $@ - $(DVIPS) readline.dvi - -history.ps: history.dvi - $(RM) $@ - $(DVIPS) history.dvi - -readline.html: ${RLSRC} - $(TEXI2HTML) rlman.texinfo - sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman.html > readline.html - sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman_toc.html > readline_toc.html - $(RM) rlman.html rlman_toc.html - -history.html: ${HISTSRC} - $(TEXI2HTML) hist.texinfo - sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist.html > history.html - sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist_toc.html > history_toc.html - $(RM) hist.html hist_toc.html - -info: $(INFOOBJ) -dvi: $(DVIOBJ) -ps: $(PSOBJ) -html: $(HTMLOBJ) - -clean: - $(RM) *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \ - *.fns *.kys *.tps *.vrs *.o core - -distclean: clean -mostlyclean: clean - -maintainer-clean: clean - $(RM) *.dvi *.info *.info-* *.ps *.html - -install: info - ${INSTALL_DATA} readline.info $(infodir)/readline.info - ${INSTALL_DATA} history.info $(infodir)/history.info diff --git a/lib/readline/doc/history.texi~ b/lib/readline/doc/history.texi~ deleted file mode 100644 index 24161447d..000000000 --- a/lib/readline/doc/history.texi~ +++ /dev/null @@ -1,102 +0,0 @@ -\input texinfo @c -*-texinfo-*- -@c %**start of header (This is for running Texinfo on a region.) -@setfilename history.info -@settitle GNU History Library -@c %**end of header (This is for running Texinfo on a region.) - -@include version.texi - -@copying -This document describes the GNU History library -(version @value{VERSION}, @value{UPDATED}), -a programming tool that provides a consistent user interface for -recalling lines of previously typed input. - -Copyright @copyright{} 1988--2007 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.2 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 are free to copy and modify -this GNU Manual. Buying copies from GNU Press supports the FSF in -developing GNU and promoting software freedom.'' -@end quotation -@end copying - -@dircategory Libraries -@direntry -* History: (history). The GNU history library API. -@end direntry - -@titlepage -@title GNU History Library -@subtitle Edition @value{EDITION}, for @code{History Library} 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 -@top GNU History Library - -This document describes the GNU History library, a programming tool that -provides a consistent user interface for recalling lines of previously -typed input. - -@menu -* Using History Interactively:: GNU History User's Manual. -* Programming with GNU History:: GNU History Programmer's Manual. -* Copying This Manual:: Copying This Manual. -* Concept Index:: Index of concepts described in this manual. -* Function and Variable Index:: Index of externally visible functions - and variables. -@end menu -@end ifnottex - -@syncodeindex fn vr - -@include hsuser.texi -@include hstech.texi - -@node Copying This Manual -@appendix Copying This Manual - -@menu -* GNU Free Documentation License:: License for copying this manual. -@end menu - -@include fdl.texi - -@node Concept Index -@appendix Concept Index -@printindex cp - -@node Function and Variable Index -@appendix Function and Variable Index -@printindex vr - -@bye diff --git a/lib/readline/doc/hstech.texi~ b/lib/readline/doc/hstech.texi~ deleted file mode 100644 index 47ba8a550..000000000 --- a/lib/readline/doc/hstech.texi~ +++ /dev/null @@ -1,573 +0,0 @@ -@ignore -This file documents the user interface to the GNU History library. - -Copyright (C) 1988-2006 Free Software Foundation, Inc. -Authored by Brian Fox and Chet Ramey. - -Permission is granted to make and distribute verbatim copies of this manual -provided the copyright notice and this permission notice are preserved on -all copies. - -Permission is granted to process this file through Tex and print the -results, provided the printed document carries copying permission notice -identical to this one except for the removal of this paragraph (this -paragraph not being relevant to the printed manual). - -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided also that the -GNU Copyright statement is available to the distributee, and provided that -the entire resulting derived work is distributed under the terms of a -permission notice identical to this one. - -Permission is granted to copy and distribute translations of this manual -into another language, under the above conditions for modified versions. -@end ignore - -@node Programming with GNU History -@chapter Programming with GNU History - -This chapter describes how to interface programs that you write -with the @sc{gnu} History Library. -It should be considered a technical guide. -For information on the interactive use of @sc{gnu} History, @pxref{Using -History Interactively}. - -@menu -* Introduction to History:: What is the GNU History library for? -* History Storage:: How information is stored. -* History Functions:: Functions that you can use. -* History Variables:: Variables that control behaviour. -* History Programming Example:: Example of using the GNU History Library. -@end menu - -@node Introduction to History -@section Introduction to History - -Many programs read input from the user a line at a time. The @sc{gnu} -History library is able to keep track of those lines, associate arbitrary -data with each line, and utilize information from previous lines in -composing new ones. - -The programmer using the History library has available functions -for remembering lines on a history list, associating arbitrary data -with a line, removing lines from the list, searching through the list -for a line containing an arbitrary text string, and referencing any line -in the list directly. In addition, a history @dfn{expansion} function -is available which provides for a consistent user interface across -different programs. - -The user using programs written with the History library has the -benefit of a consistent user interface with a set of well-known -commands for manipulating the text of previous lines and using that text -in new commands. The basic history manipulation commands are similar to -the history substitution provided by @code{csh}. - -If the programmer desires, he can use the Readline library, which -includes some history manipulation by default, and has the added -advantage of command line editing. - -Before declaring any functions using any functionality the History -library provides in other code, an application writer should include -the file @code{} in any file that uses the -History library's features. It supplies extern declarations for all -of the library's public functions and variables, and declares all of -the public data structures. - -@node History Storage -@section History Storage - -The history list is an array of history entries. A history entry is -declared as follows: - -@example -typedef void *histdata_t; - -typedef struct _hist_entry @{ - char *line; - char *timestamp; - histdata_t data; -@} HIST_ENTRY; -@end example - -The history list itself might therefore be declared as - -@example -HIST_ENTRY **the_history_list; -@end example - -The state of the History library is encapsulated into a single structure: - -@example -/* - * A structure used to pass around the current state of the history. - */ -typedef struct _hist_state @{ - HIST_ENTRY **entries; /* Pointer to the entries themselves. */ - int offset; /* The location pointer within this array. */ - int length; /* Number of elements within this array. */ - int size; /* Number of slots allocated to this array. */ - int flags; -@} HISTORY_STATE; -@end example - -If the flags member includes @code{HS_STIFLED}, the history has been -stifled. - -@node History Functions -@section History Functions - -This section describes the calling sequence for the various functions -exported by the @sc{gnu} History library. - -@menu -* Initializing History and State Management:: Functions to call when you - want to use history in a - program. -* History List Management:: Functions used to manage the list - of history entries. -* Information About the History List:: Functions returning information about - the history list. -* Moving Around the History List:: Functions used to change the position - in the history list. -* Searching the History List:: Functions to search the history list - for entries containing a string. -* Managing the History File:: Functions that read and write a file - containing the history list. -* History Expansion:: Functions to perform csh-like history - expansion. -@end menu - -@node Initializing History and State Management -@subsection Initializing History and State Management - -This section describes functions used to initialize and manage -the state of the History library when you want to use the history -functions in your program. - -@deftypefun void using_history (void) -Begin a session in which the history functions might be used. This -initializes the interactive variables. -@end deftypefun - -@deftypefun {HISTORY_STATE *} history_get_history_state (void) -Return a structure describing the current state of the input history. -@end deftypefun - -@deftypefun void history_set_history_state (HISTORY_STATE *state) -Set the state of the history list according to @var{state}. -@end deftypefun - -@node History List Management -@subsection History List Management - -These functions manage individual entries on the history list, or set -parameters managing the list itself. - -@deftypefun void add_history (const char *string) -Place @var{string} at the end of the history list. The associated data -field (if any) is set to @code{NULL}. -@end deftypefun - -@deftypefun void add_history_time (const char *string) -Change the time stamp associated with the most recent history entry to -@var{string}. -@end deftypefun - -@deftypefun {HIST_ENTRY *} remove_history (int which) -Remove history entry at offset @var{which} from the history. The -removed element is returned so you can free the line, data, -and containing structure. -@end deftypefun - -@deftypefun {histdata_t} free_history_entry (HIST_ENTRY *histent) -Free the history entry @var{histent} and any history library private -data associated with it. Returns the application-specific data -so the caller can dispose of it. -@end deftypefun - -@deftypefun {HIST_ENTRY *} replace_history_entry (int which, const char *line, histdata_t data) -Make the history entry at offset @var{which} have @var{line} and @var{data}. -This returns the old entry so the caller can dispose of any -application-specific data. In the case -of an invalid @var{which}, a @code{NULL} pointer is returned. -@end deftypefun - -@deftypefun void clear_history (void) -Clear the history list by deleting all the entries. -@end deftypefun - -@deftypefun void stifle_history (int max) -Stifle the history list, remembering only the last @var{max} entries. -@end deftypefun - -@deftypefun int unstifle_history (void) -Stop stifling the history. This returns the previously-set -maximum number of history entries (as set by @code{stifle_history()}). -The value is positive if the history was -stifled, negative if it wasn't. -@end deftypefun - -@deftypefun int history_is_stifled (void) -Returns non-zero if the history is stifled, zero if it is not. -@end deftypefun - -@node Information About the History List -@subsection Information About the History List - -These functions return information about the entire history list or -individual list entries. - -@deftypefun {HIST_ENTRY **} history_list (void) -Return a @code{NULL} terminated array of @code{HIST_ENTRY *} which is the -current input history. Element 0 of this list is the beginning of time. -If there is no history, return @code{NULL}. -@end deftypefun - -@deftypefun int where_history (void) -Returns the offset of the current history element. -@end deftypefun - -@deftypefun {HIST_ENTRY *} current_history (void) -Return the history entry at the current position, as determined by -@code{where_history()}. If there is no entry there, return a @code{NULL} -pointer. -@end deftypefun - -@deftypefun {HIST_ENTRY *} history_get (int offset) -Return the history entry at position @var{offset}, starting from -@code{history_base} (@pxref{History Variables}). -If there is no entry there, or if @var{offset} -is greater than the history length, return a @code{NULL} pointer. -@end deftypefun - -@deftypefun time_t history_get_time (HIST_ENTRY *entry) -Return the time stamp associated with the history entry @var{entry}. -@end deftypefun - -@deftypefun int history_total_bytes (void) -Return the number of bytes that the primary history entries are using. -This function returns the sum of the lengths of all the lines in the -history. -@end deftypefun - -@node Moving Around the History List -@subsection Moving Around the History List - -These functions allow the current index into the history list to be -set or changed. - -@deftypefun int history_set_pos (int pos) -Set the current history offset to @var{pos}, an absolute index -into the list. -Returns 1 on success, 0 if @var{pos} is less than zero or greater -than the number of history entries. -@end deftypefun - -@deftypefun {HIST_ENTRY *} previous_history (void) -Back up the current history offset to the previous history entry, and -return a pointer to that entry. If there is no previous entry, return -a @code{NULL} pointer. -@end deftypefun - -@deftypefun {HIST_ENTRY *} next_history (void) -Move the current history offset forward to the next history entry, and -return the a pointer to that entry. If there is no next entry, return -a @code{NULL} pointer. -@end deftypefun - -@node Searching the History List -@subsection Searching the History List -@cindex History Searching - -These functions allow searching of the history list for entries containing -a specific string. Searching may be performed both forward and backward -from the current history position. The search may be @dfn{anchored}, -meaning that the string must match at the beginning of the history entry. -@cindex anchored search - -@deftypefun int history_search (const char *string, int direction) -Search the history for @var{string}, starting at the current history offset. -If @var{direction} is less than 0, then the search is through -previous entries, otherwise through subsequent entries. -If @var{string} is found, then -the current history index is set to that history entry, and the value -returned is the offset in the line of the entry where -@var{string} was found. Otherwise, nothing is changed, and a -1 is -returned. -@end deftypefun - -@deftypefun int history_search_prefix (const char *string, int direction) -Search the history for @var{string}, starting at the current history -offset. The search is anchored: matching lines must begin with -@var{string}. If @var{direction} is less than 0, then the search is -through previous entries, otherwise through subsequent entries. -If @var{string} is found, then the -current history index is set to that entry, and the return value is 0. -Otherwise, nothing is changed, and a -1 is returned. -@end deftypefun - -@deftypefun int history_search_pos (const char *string, int direction, int pos) -Search for @var{string} in the history list, starting at @var{pos}, an -absolute index into the list. If @var{direction} is negative, the search -proceeds backward from @var{pos}, otherwise forward. Returns the absolute -index of the history element where @var{string} was found, or -1 otherwise. -@end deftypefun - -@node Managing the History File -@subsection Managing the History File - -The History library can read the history from and write it to a file. -This section documents the functions for managing a history file. - -@deftypefun int read_history (const char *filename) -Add the contents of @var{filename} to the history list, a line at a time. -If @var{filename} is @code{NULL}, then read from @file{~/.history}. -Returns 0 if successful, or @code{errno} if not. -@end deftypefun - -@deftypefun int read_history_range (const char *filename, int from, int to) -Read a range of lines from @var{filename}, adding them to the history list. -Start reading at line @var{from} and end at @var{to}. -If @var{from} is zero, start at the beginning. If @var{to} is less than -@var{from}, then read until the end of the file. If @var{filename} is -@code{NULL}, then read from @file{~/.history}. Returns 0 if successful, -or @code{errno} if not. -@end deftypefun - -@deftypefun int write_history (const char *filename) -Write the current history to @var{filename}, overwriting @var{filename} -if necessary. -If @var{filename} is @code{NULL}, then write the history list to -@file{~/.history}. -Returns 0 on success, or @code{errno} on a read or write error. -@end deftypefun - -@deftypefun int append_history (int nelements, const char *filename) -Append the last @var{nelements} of the history list to @var{filename}. -If @var{filename} is @code{NULL}, then append to @file{~/.history}. -Returns 0 on success, or @code{errno} on a read or write error. -@end deftypefun - -@deftypefun int history_truncate_file (const char *filename, int nlines) -Truncate the history file @var{filename}, leaving only the last -@var{nlines} lines. -If @var{filename} is @code{NULL}, then @file{~/.history} is truncated. -Returns 0 on success, or @code{errno} on failure. -@end deftypefun - -@node History Expansion -@subsection History Expansion - -These functions implement history expansion. - -@deftypefun int history_expand (char *string, char **output) -Expand @var{string}, placing the result into @var{output}, a pointer -to a string (@pxref{History Interaction}). Returns: -@table @code -@item 0 -If no expansions took place (or, if the only change in -the text was the removal of escape characters preceding the history expansion -character); -@item 1 -if expansions did take place; -@item -1 -if there was an error in expansion; -@item 2 -if the returned line should be displayed, but not executed, -as with the @code{:p} modifier (@pxref{Modifiers}). -@end table - -If an error ocurred in expansion, then @var{output} contains a descriptive -error message. -@end deftypefun - -@deftypefun {char *} get_history_event (const char *string, int *cindex, int qchar) -Returns the text of the history event beginning at @var{string} + -@var{*cindex}. @var{*cindex} is modified to point to after the event -specifier. At function entry, @var{cindex} points to the index into -@var{string} where the history event specification begins. @var{qchar} -is a character that is allowed to end the event specification in addition -to the ``normal'' terminating characters. -@end deftypefun - -@deftypefun {char **} history_tokenize (const char *string) -Return an array of tokens parsed out of @var{string}, much as the -shell might. The tokens are split on the characters in the -@var{history_word_delimiters} variable, -and shell quoting conventions are obeyed. -@end deftypefun - -@deftypefun {char *} history_arg_extract (int first, int last, const char *string) -Extract a string segment consisting of the @var{first} through @var{last} -arguments present in @var{string}. Arguments are split using -@code{history_tokenize}. -@end deftypefun - -@node History Variables -@section History Variables - -This section describes the externally-visible variables exported by -the @sc{gnu} History Library. - -@deftypevar int history_base -The logical offset of the first entry in the history list. -@end deftypevar - -@deftypevar int history_length -The number of entries currently stored in the history list. -@end deftypevar - -@deftypevar int history_max_entries -The maximum number of history entries. This must be changed using -@code{stifle_history()}. -@end deftypevar - -@deftypevar int history_write_timestamps -If non-zero, timestamps are written to the history file, so they can be -preserved between sessions. The default value is 0, meaning that -timestamps are not saved. -@end deftypevar - -@deftypevar char history_expansion_char -The character that introduces a history event. The default is @samp{!}. -Setting this to 0 inhibits history expansion. -@end deftypevar - -@deftypevar char history_subst_char -The character that invokes word substitution if found at the start of -a line. The default is @samp{^}. -@end deftypevar - -@deftypevar char history_comment_char -During tokenization, if this character is seen as the first character -of a word, then it and all subsequent characters up to a newline are -ignored, suppressing history expansion for the remainder of the line. -This is disabled by default. -@end deftypevar - -@deftypevar {char *} history_word_delimiters -The characters that separate tokens for @code{history_tokenize()}. -The default value is @code{" \t\n()<>;&|"}. -@end deftypevar - -@deftypevar {char *} history_search_delimiter_chars -The list of additional characters which can delimit a history search -string, in addition to space, TAB, @samp{:} and @samp{?} in the case of -a substring search. The default is empty. -@end deftypevar - -@deftypevar {char *} history_no_expand_chars -The list of characters which inhibit history expansion if found immediately -following @var{history_expansion_char}. The default is space, tab, newline, -carriage return, and @samp{=}. -@end deftypevar - -@deftypevar int history_quotes_inhibit_expansion -If non-zero, single-quoted words are not scanned for the history expansion -character. The default value is 0. -@end deftypevar - -@deftypevar {rl_linebuf_func_t *} history_inhibit_expansion_function -This should be set to the address of a function that takes two arguments: -a @code{char *} (@var{string}) -and an @code{int} index into that string (@var{i}). -It should return a non-zero value if the history expansion starting at -@var{string[i]} should not be performed; zero if the expansion should -be done. -It is intended for use by applications like Bash that use the history -expansion character for additional purposes. -By default, this variable is set to @code{NULL}. -@end deftypevar - -@node History Programming Example -@section History Programming Example - -The following program demonstrates simple use of the @sc{gnu} History Library. - -@smallexample -#include -#include - -main (argc, argv) - int argc; - char **argv; -@{ - char line[1024], *t; - int len, done = 0; - - line[0] = 0; - - using_history (); - while (!done) - @{ - printf ("history$ "); - fflush (stdout); - t = fgets (line, sizeof (line) - 1, stdin); - if (t && *t) - @{ - len = strlen (t); - if (t[len - 1] == '\n') - t[len - 1] = '\0'; - @} - - if (!t) - strcpy (line, "quit"); - - if (line[0]) - @{ - char *expansion; - int result; - - result = history_expand (line, &expansion); - if (result) - fprintf (stderr, "%s\n", expansion); - - if (result < 0 || result == 2) - @{ - free (expansion); - continue; - @} - - add_history (expansion); - strncpy (line, expansion, sizeof (line) - 1); - free (expansion); - @} - - if (strcmp (line, "quit") == 0) - done = 1; - else if (strcmp (line, "save") == 0) - write_history ("history_file"); - else if (strcmp (line, "read") == 0) - read_history ("history_file"); - else if (strcmp (line, "list") == 0) - @{ - register HIST_ENTRY **the_list; - register int i; - - the_list = history_list (); - if (the_list) - for (i = 0; the_list[i]; i++) - printf ("%d: %s\n", i + history_base, the_list[i]->line); - @} - else if (strncmp (line, "delete", 6) == 0) - @{ - int which; - if ((sscanf (line + 6, "%d", &which)) == 1) - @{ - HIST_ENTRY *entry = remove_history (which); - if (!entry) - fprintf (stderr, "No such entry %d\n", which); - else - @{ - free (entry->line); - free (entry); - @} - @} - else - @{ - fprintf (stderr, "non-numeric arg given to `delete'\n"); - @} - @} - @} -@} -@end smallexample diff --git a/lib/readline/doc/hsuser.texi~ b/lib/readline/doc/hsuser.texi~ deleted file mode 100644 index 846a8d940..000000000 --- a/lib/readline/doc/hsuser.texi~ +++ /dev/null @@ -1,464 +0,0 @@ -@ignore -This file documents the user interface to the GNU History library. - -Copyright (C) 1988-2006 Free Software Foundation, Inc. -Authored by Brian Fox and Chet Ramey. - -Permission is granted to make and distribute verbatim copies of this manual -provided the copyright notice and this permission notice are preserved on -all copies. - -Permission is granted to process this file through Tex and print the -results, provided the printed document carries copying permission notice -identical to this one except for the removal of this paragraph (this -paragraph not being relevant to the printed manual). - -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided also that the -GNU Copyright statement is available to the distributee, and provided that -the entire resulting derived work is distributed under the terms of a -permission notice identical to this one. - -Permission is granted to copy and distribute translations of this manual -into another language, under the above conditions for modified versions. -@end ignore - -@node Using History Interactively -@chapter Using History Interactively - -@ifclear BashFeatures -@defcodeindex bt -@end ifclear - -@ifset BashFeatures -This chapter describes how to use the @sc{gnu} History Library -interactively, from a user's standpoint. -It should be considered a user's guide. -For information on using the @sc{gnu} History Library in other programs, -see the @sc{gnu} Readline Library Manual. -@end ifset -@ifclear BashFeatures -This chapter describes how to use the @sc{gnu} History Library interactively, -from a user's standpoint. It should be considered a user's guide. For -information on using the @sc{gnu} History Library in your own programs, -@pxref{Programming with GNU History}. -@end ifclear - -@ifset BashFeatures -@menu -* Bash History Facilities:: How Bash lets you manipulate your command - history. -* Bash History Builtins:: The Bash builtin commands that manipulate - the command history. -* History Interaction:: What it feels like using History as a user. -@end menu -@end ifset -@ifclear BashFeatures -@menu -* History Interaction:: What it feels like using History as a user. -@end menu -@end ifclear - -@ifset BashFeatures -@node Bash History Facilities -@section Bash History Facilities -@cindex command history -@cindex history list - -When the @option{-o history} option to the @code{set} builtin -is enabled (@pxref{The Set Builtin}), -the shell provides access to the @dfn{command history}, -the list of commands previously typed. -The value of the @env{HISTSIZE} shell variable is used as the -number of commands to save in a history list. -The text of the last @env{$HISTSIZE} -commands (default 500) is saved. -The shell stores each command in the history list prior to -parameter and variable expansion -but after history expansion is performed, subject to the -values of the shell variables -@env{HISTIGNORE} and @env{HISTCONTROL}. - -When the shell starts up, the history is initialized from the -file named by the @env{HISTFILE} variable (default @file{~/.bash_history}). -The file named by the value of @env{HISTFILE} is truncated, if -necessary, to contain no more than the number of lines specified by -the value of the @env{HISTFILESIZE} variable. -When an interactive shell exits, the last -@env{$HISTSIZE} lines are copied from the history list to the file -named by @env{$HISTFILE}. -If the @code{histappend} shell option is set (@pxref{Bash Builtins}), -the lines are appended to the history file, -otherwise the history file is overwritten. -If @env{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 @env{$HISTFILESIZE} -lines. If @env{HISTFILESIZE} is not set, no truncation is performed. - -If the @env{HISTTIMEFORMAT} is set, the time stamp information -associated with each history entry is written to the history file, -marked with the history comment character. -When the history file is read, lines beginning with the history -comment character followed immediately by a digit are interpreted -as timestamps for the previous history line. - -The builtin command @code{fc} may be used to list or edit and re-execute -a portion of the history list. -The @code{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 (@pxref{Commands For History}). - -The shell allows control over which commands are saved on the history -list. The @env{HISTCONTROL} and @env{HISTIGNORE} -variables may be set to cause the shell to save only a subset of the -commands entered. -The @code{cmdhist} -shell option, if enabled, causes the shell to attempt to save each -line of a multi-line command in the same history entry, adding -semicolons where necessary to preserve syntactic correctness. -The @code{lithist} -shell option causes the shell to save the command with embedded newlines -instead of semicolons. -The @code{shopt} builtin is used to set these options. -@xref{Bash Builtins}, for a description of @code{shopt}. - -@node Bash History Builtins -@section Bash History Builtins -@cindex history builtins - -Bash provides two builtin commands which manipulate the -history list and history file. - -@table @code - -@item fc -@btindex fc -@example -@code{fc [-e @var{ename}] [-lnr] [@var{first}] [@var{last}]} -@code{fc -s [@var{pat}=@var{rep}] [@var{command}]} -@end example - -Fix Command. In the first form, a range of commands from @var{first} to -@var{last} is selected from the history list. Both @var{first} and -@var{last} may be specified as a string (to locate the most recent -command beginning with that string) or as a number (an index into the -history list, where a negative number is used as an offset from the -current command number). If @var{last} is not specified it is set to -@var{first}. If @var{first} is not specified it is set to the previous -command for editing and @minus{}16 for listing. If the @option{-l} flag is -given, the commands are listed on standard output. The @option{-n} flag -suppresses the command numbers when listing. The @option{-r} flag -reverses the order of the listing. Otherwise, the editor given by -@var{ename} is invoked on a file containing those commands. If -@var{ename} is not given, the value of the following variable expansion -is used: @code{$@{FCEDIT:-$@{EDITOR:-vi@}@}}. This says to use the -value of the @env{FCEDIT} variable if set, or the value of the -@env{EDITOR} variable if that is set, or @code{vi} if neither is set. -When editing is complete, the edited commands are echoed and executed. - -In the second form, @var{command} is re-executed after each instance -of @var{pat} in the selected command is replaced by @var{rep}. - -A useful alias to use with the @code{fc} command is @code{r='fc -s'}, so -that typing @samp{r cc} runs the last command beginning with @code{cc} -and typing @samp{r} re-executes the last command (@pxref{Aliases}). - -@item history -@btindex history -@example -history [@var{n}] -history -c -history -d @var{offset} -history [-anrw] [@var{filename}] -history -ps @var{arg} -@end example - -With no options, display the history list with line numbers. -Lines prefixed with a @samp{*} have been modified. -An argument of @var{n} lists only the last @var{n} lines. -If the shell variable @env{HISTTIMEFORMAT} is set and not null, -it is used as a format string for @var{strftime} 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. - -Options, if supplied, have the following meanings: - -@table @code -@item -c -Clear the history list. This may be combined -with the other options to replace the history list completely. - -@item -d @var{offset} -Delete the history entry at position @var{offset}. -@var{offset} should be specified as it appears when the history is -displayed. - -@item -a -Append the new -history lines (history lines entered since the beginning of the -current Bash session) to the history file. - -@item -n -Append the history lines not already read from the history file -to the current history list. These are lines appended to the history -file since the beginning of the current Bash session. - -@item -r -Read the current history file and append its contents to -the history list. - -@item -w -Write out the current history to the history file. - -@item -p -Perform history substitution on the @var{arg}s and display the result -on the standard output, without storing the results in the history list. - -@item -s -The @var{arg}s are added to the end of -the history list as a single entry. - -@end table - -When any of the @option{-w}, @option{-r}, @option{-a}, or @option{-n} options is -used, if @var{filename} -is given, then it is used as the history file. If not, then -the value of the @env{HISTFILE} variable is used. - -@end table -@end ifset - -@node History Interaction -@section History Expansion -@cindex history expansion - -The History library provides a history expansion feature that is similar -to the history expansion provided by @code{csh}. This section -describes the syntax used to manipulate the history information. - -History expansions introduce words from the history list into -the input stream, making it easy to repeat commands, insert the -arguments to a previous command into the current input line, or -fix errors in previous commands quickly. - -History expansion takes place in two parts. The first is to determine -which line from the history list should be used during substitution. -The second is to select portions of that line for inclusion into the -current one. The line selected from the history is called the -@dfn{event}, and the portions of that line that are acted upon are -called @dfn{words}. Various @dfn{modifiers} are available to manipulate -the selected words. The line is broken into words in the same fashion -that Bash does, so that several words -surrounded by quotes are considered one word. -History expansions are introduced by the appearance of the -history expansion character, which is @samp{!} by default. -@ifset BashFeatures -Only @samp{\} and @samp{'} may be used to escape the history expansion -character. -@end ifset - -@ifset BashFeatures -Several shell options settable with the @code{shopt} -builtin (@pxref{Bash Builtins}) may be used to tailor -the behavior of history expansion. If the -@code{histverify} shell option is enabled, and Readline -is being used, history substitutions are not immediately passed to -the shell parser. -Instead, the expanded line is reloaded into the Readline -editing buffer for further modification. -If Readline is being used, and the @code{histreedit} -shell option is enabled, a failed history expansion will be -reloaded into the Readline editing buffer for correction. -The @option{-p} option to the @code{history} builtin command -may be used to see what a history expansion will do before using it. -The @option{-s} option to the @code{history} builtin may be used to -add commands to the end of the history list without actually executing -them, so that they are available for subsequent recall. -This is most useful in conjunction with Readline. - -The shell allows control of the various characters used by the -history expansion mechanism with the @code{histchars} variable, -as explained above (@pxref{Bash Variables}). The shell uses -the history comment character to mark history timestamps when -writing the history file. -@end ifset - -@menu -* Event Designators:: How to specify which history line to use. -* Word Designators:: Specifying which words are of interest. -* Modifiers:: Modifying the results of substitution. -@end menu - -@node Event Designators -@subsection Event Designators -@cindex event designators - -An event designator is a reference to a command line entry in the -history list. -@cindex history events - -@table @asis - -@item @code{!} -@ifset BashFeatures -Start a history substitution, except when followed by a space, tab, -the end of the line, @samp{=} or @samp{(} (when the -@code{extglob} shell option is enabled using the @code{shopt} builtin). -@end ifset -@ifclear BashFeatures -Start a history substitution, except when followed by a space, tab, -the end of the line, or @samp{=}. -@end ifclear - -@item @code{!@var{n}} -Refer to command line @var{n}. - -@item @code{!-@var{n}} -Refer to the command @var{n} lines back. - -@item @code{!!} -Refer to the previous command. This is a synonym for @samp{!-1}. - -@item @code{!@var{string}} -Refer to the most recent command starting with @var{string}. - -@item @code{!?@var{string}[?]} -Refer to the most recent command containing @var{string}. The trailing -@samp{?} may be omitted if the @var{string} is followed immediately by -a newline. - -@item @code{^@var{string1}^@var{string2}^} -Quick Substitution. Repeat the last command, replacing @var{string1} -with @var{string2}. Equivalent to -@code{!!:s/@var{string1}/@var{string2}/}. - -@item @code{!#} -The entire command line typed so far. - -@end table - -@node Word Designators -@subsection Word Designators - -Word designators are used to select desired words from the event. -A @samp{:} separates the event specification from the word designator. It -may be omitted if the word designator begins with a @samp{^}, @samp{$}, -@samp{*}, @samp{-}, or @samp{%}. Words are numbered from the beginning -of the line, with the first word being denoted by 0 (zero). Words are -inserted into the current line separated by single spaces. - -@need 0.75 -For example, - -@table @code -@item !! -designates the preceding command. When you type this, the preceding -command is repeated in toto. - -@item !!:$ -designates the last argument of the preceding command. This may be -shortened to @code{!$}. - -@item !fi:2 -designates the second argument of the most recent command starting with -the letters @code{fi}. -@end table - -@need 0.75 -Here are the word designators: - -@table @code - -@item 0 (zero) -The @code{0}th word. For many applications, this is the command word. - -@item @var{n} -The @var{n}th word. - -@item ^ -The first argument; that is, word 1. - -@item $ -The last argument. - -@item % -The word matched by the most recent @samp{?@var{string}?} search. - -@item @var{x}-@var{y} -A range of words; @samp{-@var{y}} abbreviates @samp{0-@var{y}}. - -@item * -All of the words, except the @code{0}th. This is a synonym for @samp{1-$}. -It is not an error to use @samp{*} if there is just one word in the event; -the empty string is returned in that case. - -@item @var{x}* -Abbreviates @samp{@var{x}-$} - -@item @var{x}- -Abbreviates @samp{@var{x}-$} like @samp{@var{x}*}, but omits the last word. - -@end table - -If a word designator is supplied without an event specification, the -previous command is used as the event. - -@node Modifiers -@subsection Modifiers - -After the optional word designator, you can add a sequence of one or more -of the following modifiers, each preceded by a @samp{:}. - -@table @code - -@item h -Remove a trailing pathname component, leaving only the head. - -@item t -Remove all leading pathname components, leaving the tail. - -@item r -Remove a trailing suffix of the form @samp{.@var{suffix}}, leaving -the basename. - -@item e -Remove all but the trailing suffix. - -@item p -Print the new command but do not execute it. - -@ifset BashFeatures -@item q -Quote the substituted words, escaping further substitutions. - -@item x -Quote the substituted words as with @samp{q}, -but break into words at spaces, tabs, and newlines. -@end ifset - -@item s/@var{old}/@var{new}/ -Substitute @var{new} for the first occurrence of @var{old} in the -event line. Any delimiter may be used in place of @samp{/}. -The delimiter may be quoted in @var{old} and @var{new} -with a single backslash. If @samp{&} appears in @var{new}, -it is replaced by @var{old}. A single backslash will quote -the @samp{&}. The final delimiter is optional if it is the last -character on the input line. - -@item & -Repeat the previous substitution. - -@item g -@itemx a -Cause changes to be applied over the entire event line. Used in -conjunction with @samp{s}, as in @code{gs/@var{old}/@var{new}/}, -or with @samp{&}. - -@item G -Apply the following @samp{s} modifier once to each word in the event. - -@end table diff --git a/lib/readline/doc/readline.3~ b/lib/readline/doc/readline.3~ deleted file mode 100644 index 5782ef837..000000000 --- a/lib/readline/doc/readline.3~ +++ /dev/null @@ -1,1320 +0,0 @@ -.\" -.\" MAN PAGE COMMENTS to -.\" -.\" Chet Ramey -.\" Information Network Services -.\" Case Western Reserve University -.\" chet@ins.CWRU.Edu -.\" -.\" Last Change: Thu May 8 09:29:59 EDT 2008 -.\" -.TH READLINE 3 "2008 May 8" "GNU Readline 6.0" -.\" -.\" File Name macro. This used to be `.PN', for Path Name, -.\" but Sun doesn't seem to like that very much. -.\" -.de FN -\fI\|\\$1\|\fP -.. -.SH NAME -readline \- get a line from a user with editing -.SH SYNOPSIS -.LP -.nf -.ft B -#include -#include -#include -.ft -.fi -.LP -.nf -\fIchar *\fP -.br -\fBreadline\fP (\fIconst char *prompt\fP); -.fi -.SH COPYRIGHT -.if n Readline is Copyright (C) 1989\-2008 by the Free Software Foundation, Inc. -.if t Readline is Copyright \(co 1989\-2008 by the Free Software Foundation, Inc. -.SH DESCRIPTION -.LP -.B readline -will read a line from the terminal -and return it, using -.B prompt -as a prompt. If -.B prompt -is \fBNULL\fP or the empty string, no prompt is issued. -The line returned is allocated with -.IR malloc (3); -the caller must free it when finished. The line returned -has the final newline removed, so only the text of the line -remains. -.LP -.B readline -offers editing capabilities while the user is entering the -line. -By default, the line editing commands -are similar to those of emacs. -A vi\-style line editing interface is also available. -.LP -This manual page describes only the most basic use of \fBreadline\fP. -Much more functionality is available; see -\fIThe GNU Readline Library\fP and \fIThe GNU History Library\fP -for additional information. -.SH RETURN VALUE -.LP -.B readline -returns the text of the line read. A blank line -returns the empty string. If -.B EOF -is encountered while reading a line, and the line is empty, -.B NULL -is returned. If an -.B EOF -is read with a non\-empty line, it is -treated as a newline. -.SH NOTATION -.LP -An emacs-style notation is used to denote -keystrokes. Control keys are denoted by C\-\fIkey\fR, e.g., C\-n -means Control\-N. Similarly, -.I meta -keys are denoted by M\-\fIkey\fR, so M\-x means Meta\-X. (On keyboards -without a -.I meta -key, M\-\fIx\fP means ESC \fIx\fP, i.e., press the Escape key -then the -.I x -key. This makes ESC the \fImeta prefix\fP. -The combination M\-C\-\fIx\fP means ESC\-Control\-\fIx\fP, -or press the Escape key -then hold the Control key while pressing the -.I x -key.) -.PP -Readline commands may be given numeric -.IR arguments , -which normally act as a repeat count. Sometimes, however, it is the -sign of the argument that is significant. Passing a negative argument -to a command that acts in the forward direction (e.g., \fBkill\-line\fP) -causes that command to act in a backward direction. Commands whose -behavior with arguments deviates from this are noted. -.PP -When a command is described as \fIkilling\fP text, the text -deleted is saved for possible future retrieval -(\fIyanking\fP). The killed text is saved in a -\fIkill ring\fP. Consecutive kills cause the text to be -accumulated into one unit, which can be yanked all at once. -Commands which do not kill text separate the chunks of text -on the kill ring. -.SH INITIALIZATION FILE -.LP -Readline is customized by putting commands in an initialization -file (the \fIinputrc\fP file). -The name of this file is taken from the value of the -.B INPUTRC -environment variable. If that variable is unset, the default is -.IR ~/.inputrc . -If that file does not exist or cannot be read, the ultimate default is -.IR /etc/inputrc . -When a program which uses the readline library starts up, the -init file is read, and the key bindings and variables are set. -There are only a few basic constructs allowed in the -readline init file. Blank lines are ignored. -Lines beginning with a \fB#\fP are comments. -Lines beginning with a \fB$\fP indicate conditional constructs. -Other lines denote key bindings and variable settings. -Each program using this library may add its own commands -and bindings. -.PP -For example, placing -.RS -.PP -M\-Control\-u: universal\-argument -.RE -or -.RS -C\-Meta\-u: universal\-argument -.RE -.sp -into the -.I inputrc -would make M\-C\-u execute the readline command -.IR universal\-argument . -.PP -The following symbolic character names are recognized while -processing key bindings: -.IR DEL , -.IR ESC , -.IR ESCAPE , -.IR LFD , -.IR NEWLINE , -.IR RET , -.IR RETURN , -.IR RUBOUT , -.IR SPACE , -.IR SPC , -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). -.PP -.SS Key Bindings -.PP -The syntax for controlling key bindings in the -.I inputrc -file is simple. All that is required is the name of the -command or the text of a macro and a key sequence to which -it should be bound. The name may be specified in one of two ways: -as a symbolic key name, possibly with \fIMeta\-\fP or \fIControl\-\fP -prefixes, or as a key sequence. -The name and key sequence are separated by a colon. There can be no -whitespace between the name and the colon. -.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 available when specifying -key 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 ", a double quote -.TP -.B \e' -literal ', a single quote -.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 should -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. Other programs using this library provide -similar mechanisms. The -.I inputrc -file may be edited and re-read if a program does not provide -any other means to incorporate new bindings. -.SS Variables -.PP -Readline has variables that can be used to further customize its -behavior. A variable may be set in the -.I inputrc -file with a statement of the form -.RS -.PP -\fBset\fP \fIvariable\-name\fP \fIvalue\fP -.RE -.PP -Except where noted, readline variables can take the values -.B On -or -.B Off -(without regard to case). -Unrecognized variable names are ignored. -When a variable value is read, empty or null values, "on" (case-insensitive), -and "1" are equivalent to \fBOn\fP. All other values are equivalent to -\fBOff\fP. -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 bind\-tty\-special\-chars (On) -If set to \fBOn\fP, readline attempts to bind the control characters -treated specially by the kernel's terminal driver to their readline -equivalents. -.TP -.B comment\-begin (``#'') -The string that is inserted in \fBvi\fP mode when the -.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\-prefix\-display\-length (0) -The length in characters of the common prefix of a list of possible -completions that is displayed without modification. When set to a -value greater than zero, common prefixes longer than this value are -replaced with an ellipsis when displaying possible completions. -.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. A negative value causes readline to never ask. -.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 it with 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 emacs or vi. -.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 (Off) -If set to \fBon\fP, the history code attempts to place point at the -same location on each history line retrieved with \fBprevious-history\fP -or \fBnext-history\fP. -.TP -.B history\-size (0) -Set the maximum number of history entries saved in the history list. If -set to zero, the number of entries in the history list is not limited. -.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 clear the eighth bit in 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 legal keymap names is -\fIemacs, emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move, -vi-command\fP, and -.IR vi-insert . -\fIvi\fP is equivalent to \fIvi-command\fP; \fIemacs\fP is -equivalent to \fIemacs-standard\fP. The default value is -.IR emacs . -The value of -.B editing\-mode -also affects the default keymap. -.TP -.B 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 revert\-all\-at\-newline (Off) -If set to \fBon\fP, readline will undo all changes to history lines -before returning when \fBaccept\-line\fP is executed. By default, -history lines may be modified and retain individual undo lists across -calls to \fBreadline\fP. -.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 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 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 -.SH SEARCHING -.PP -Readline provides commands for searching through the command history -for lines containing a specified string. -There are two search modes: -.I incremental -and -.IR non-incremental . -.PP -Incremental searches begin before the user has finished typing the -search string. -As each character of the search string is typed, readline displays -the next entry from the history matching the string typed so far. -An incremental search requires only as many characters as needed to -find the desired history entry. -To search backward in the history for a particular string, type -\fBC\-r\fP. Typing \fBC\-s\fP searches forward through the history. -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 \fIEscape\fP and -\fBC\-J\fP characters will terminate an incremental search. -\fBC\-G\fP 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 \fBC\-s\fP or -\fBC\-r\fP as appropriate. -This will search backward or forward in the history for the next -line matching the search string typed so far. -Any other key sequence bound to a readline command will terminate -the search and execute that command. -For instance, a newline 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. -.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. -.SH EDITING COMMANDS -.PP -The following is a list of the names of the commands and the default -key sequences to which they are bound. -Command names without an accompanying key sequence are unbound by default. -.PP -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, it may be added to the history list for future recall with -\fBadd_history()\fP. -If the line is a modified history line, the history line is restored to its original state. -.TP -.B previous\-history (C\-p) -Fetch the previous command from the history list, moving back in -the list. -.TP -.B next\-history (C\-n) -Fetch the next command from the history list, moving forward in the -list. -.TP -.B beginning\-of\-history (M\-<) -Move to the first line in the history. -.TP -.B end\-of\-history (M\->) -Move to the end of the input history, i.e., the line currently being -entered. -.TP -.B reverse\-search\-history (C\-r) -Search backward starting at the current line and moving `up' through -the history as necessary. This is an incremental search. -.TP -.B forward\-search\-history (C\-s) -Search forward starting at the current line and moving `down' through -the history as necessary. This is an incremental search. -.TP -.B non\-incremental\-reverse\-search\-history (M\-p) -Search backward through the history starting at the current line -using a non-incremental search for a string supplied by the user. -.TP -.B non\-incremental\-forward\-search\-history (M\-n) -Search forward through the history using a non-incremental search -for a string supplied by the user. -.TP -.B history\-search\-forward -Search forward through the history for the string of characters -between the start of the current line and the current cursor -position (the \fIpoint\fP). -This is a non-incremental search. -.TP -.B history\-search\-backward -Search backward through the history for the string of characters -between the start of the current line and the 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. -Once the argument \fIn\fP is computed, the argument is extracted -as if the "!\fIn\fP" history expansion had been specified. -.TP -.B -yank\-last\-arg (M\-.\^, M\-_\^) -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. -The history expansion facilities are used to extract the last argument, -as if the "!$" history expansion had been specified. -.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 that you type to the line verbatim. This is -how to insert characters like \fBC\-q\fP, for example. -.TP -.B tab\-insert (M-TAB) -Insert a tab character. -.TP -.B self\-insert (a,\ b,\ A,\ 1,\ !,\ ...) -Insert the character typed. -.TP -.B transpose\-chars (C\-t) -Drag the character before point forward over the character at point, -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 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 between the point and \fImark\fP (saved cursor position). -This text is referred to as the \fIregion\fP. -.TP -.B copy\-region\-as\-kill -Copy the text in the region to the kill buffer. -.TP -.B copy\-backward\-word -Copy the word before point to the kill buffer. -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. -The actual completion performed is application-specific. -.BR Bash , -for instance, attempts completion treating the text as a variable -(if the text begins with \fB$\fP), username (if the text begins with -\fB~\fP), hostname (if the text begins with \fB@\fP), or -command (including aliases and functions) in turn. If none -of these produces a match, filename completion is attempted. -.BR Gdb , -on the other hand, -allows completion of program functions and variables, and -only attempts filename completion under certain circumstances. -.TP -.B possible\-completions (M\-?) -List the possible completions of the text before point. -.TP -.B insert\-completions (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. -.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 -.B comment\-begin -makes 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 dump\-functions -Print all of the functions and their key bindings to the -readline output stream. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an \fIinputrc\fP file. -.TP -.B dump\-variables -Print all of the settable variables and their values to the -readline output stream. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an \fIinputrc\fP file. -.TP -.B dump\-macros -Print all of the readline key sequences bound to macros and the -strings they output. If a numeric argument is supplied, -the output is formatted in such a way that it can be made part -of an \fIinputrc\fP file. -.TP -.B emacs\-editing\-mode (C\-e) -When in -.B vi -command mode, this causes a switch to -.B emacs -editing mode. -.TP -.B vi\-editing\-mode (M\-C\-j) -When in -.B emacs -editing mode, this causes a switch to -.B vi -editing mode. -.PD -.SH DEFAULT KEY BINDINGS -.LP -The following is a list of the default emacs and vi bindings. -Characters with the eighth bit set are written as M\-, and -are referred to as -.I metafied -characters. -The printable ASCII characters not mentioned in the list of emacs -standard bindings are bound to the -.B self\-insert -function, which just inserts the given character into the input line. -In vi insertion mode, all characters not specifically mentioned are -bound to -.BR self\-insert . -Characters assigned to signal generation by -.IR stty (1) -or the terminal driver, such as C-Z or C-C, -retain that function. -Upper and lower case metafied characters are bound to the same function in -the emacs mode meta keymap. -The remaining characters are unbound, which causes readline -to ring the bell (subject to the setting of the -.B bell\-style -variable). -.SS Emacs Mode -.RS +.6i -.nf -.ta 2.5i -.sp -Emacs Standard bindings -.sp -"C-@" set-mark -"C-A" beginning-of-line -"C-B" backward-char -"C-D" delete-char -"C-E" end-of-line -"C-F" forward-char -"C-G" abort -"C-H" backward-delete-char -"C-I" complete -"C-J" accept-line -"C-K" kill-line -"C-L" clear-screen -"C-M" accept-line -"C-N" next-history -"C-P" previous-history -"C-Q" quoted-insert -"C-R" reverse-search-history -"C-S" forward-search-history -"C-T" transpose-chars -"C-U" unix-line-discard -"C-V" quoted-insert -"C-W" unix-word-rubout -"C-Y" yank -"C-]" character-search -"C-_" undo -"\^ " to "/" self-insert -"0" to "9" self-insert -":" to "~" self-insert -"C-?" backward-delete-char -.PP -Emacs Meta bindings -.sp -"M-C-G" abort -"M-C-H" backward-kill-word -"M-C-I" tab-insert -"M-C-J" vi-editing-mode -"M-C-M" vi-editing-mode -"M-C-R" revert-line -"M-C-Y" yank-nth-arg -"M-C-[" complete -"M-C-]" character-search-backward -"M-space" set-mark -"M-#" insert-comment -"M-&" tilde-expand -"M-*" insert-completions -"M--" digit-argument -"M-." yank-last-arg -"M-0" digit-argument -"M-1" digit-argument -"M-2" digit-argument -"M-3" digit-argument -"M-4" digit-argument -"M-5" digit-argument -"M-6" digit-argument -"M-7" digit-argument -"M-8" digit-argument -"M-9" digit-argument -"M-<" beginning-of-history -"M-=" possible-completions -"M->" end-of-history -"M-?" possible-completions -"M-B" backward-word -"M-C" capitalize-word -"M-D" kill-word -"M-F" forward-word -"M-L" downcase-word -"M-N" non-incremental-forward-search-history -"M-P" non-incremental-reverse-search-history -"M-R" revert-line -"M-T" transpose-words -"M-U" upcase-word -"M-Y" yank-pop -"M-\e" delete-horizontal-space -"M-~" tilde-expand -"M-C-?" backward-kill-word -"M-_" yank-last-arg -.PP -Emacs Control-X bindings -.sp -"C-XC-G" abort -"C-XC-R" re-read-init-file -"C-XC-U" undo -"C-XC-X" exchange-point-and-mark -"C-X(" start-kbd-macro -"C-X)" end-kbd-macro -"C-XE" call-last-kbd-macro -"C-XC-?" backward-kill-line -.sp -.RE -.SS VI Mode bindings -.RS +.6i -.nf -.ta 2.5i -.sp -.PP -VI Insert Mode functions -.sp -"C-D" vi-eof-maybe -"C-H" backward-delete-char -"C-I" complete -"C-J" accept-line -"C-M" accept-line -"C-R" reverse-search-history -"C-S" forward-search-history -"C-T" transpose-chars -"C-U" unix-line-discard -"C-V" quoted-insert -"C-W" unix-word-rubout -"C-Y" yank -"C-[" vi-movement-mode -"C-_" undo -"\^ " to "~" self-insert -"C-?" backward-delete-char -.PP -VI Command Mode functions -.sp -"C-D" vi-eof-maybe -"C-E" emacs-editing-mode -"C-G" abort -"C-H" backward-char -"C-J" accept-line -"C-K" kill-line -"C-L" clear-screen -"C-M" accept-line -"C-N" next-history -"C-P" previous-history -"C-Q" quoted-insert -"C-R" reverse-search-history -"C-S" forward-search-history -"C-T" transpose-chars -"C-U" unix-line-discard -"C-V" quoted-insert -"C-W" unix-word-rubout -"C-Y" yank -"C-_" vi-undo -"\^ " forward-char -"#" insert-comment -"$" end-of-line -"%" vi-match -"&" vi-tilde-expand -"*" vi-complete -"+" next-history -"," vi-char-search -"-" previous-history -"." vi-redo -"/" vi-search -"0" beginning-of-line -"1" to "9" vi-arg-digit -";" vi-char-search -"=" vi-complete -"?" vi-search -"A" vi-append-eol -"B" vi-prev-word -"C" vi-change-to -"D" vi-delete-to -"E" vi-end-word -"F" vi-char-search -"G" vi-fetch-history -"I" vi-insert-beg -"N" vi-search-again -"P" vi-put -"R" vi-replace -"S" vi-subst -"T" vi-char-search -"U" revert-line -"W" vi-next-word -"X" backward-delete-char -"Y" vi-yank-to -"\e" vi-complete -"^" vi-first-print -"_" vi-yank-arg -"`" vi-goto-mark -"a" vi-append-mode -"b" vi-prev-word -"c" vi-change-to -"d" vi-delete-to -"e" vi-end-word -"f" vi-char-search -"h" backward-char -"i" vi-insertion-mode -"j" next-history -"k" prev-history -"l" forward-char -"m" vi-set-mark -"n" vi-search-again -"p" vi-put -"r" vi-change-char -"s" vi-subst -"t" vi-char-search -"u" vi-undo -"w" vi-next-word -"x" vi-delete -"y" vi-yank-to -"|" vi-column -"~" vi-change-case -.RE -.SH "SEE ALSO" -.PD 0 -.TP -\fIThe Gnu Readline Library\fP, Brian Fox and Chet Ramey -.TP -\fIThe Gnu History Library\fP, Brian Fox and Chet Ramey -.TP -\fIbash\fP(1) -.PD -.SH FILES -.PD 0 -.TP -.FN ~/.inputrc -Individual \fBreadline\fP initialization file -.PD -.SH AUTHORS -Brian Fox, Free Software Foundation -.br -bfox@gnu.org -.PP -Chet Ramey, Case Western Reserve University -.br -chet@ins.CWRU.Edu -.SH BUG REPORTS -If you find a bug in -.B readline, -you should report it. But first, you should -make sure that it really is a bug, and that it appears in the latest -version of the -.B readline -library that you have. -.PP -Once you have determined that a bug actually exists, mail a -bug report to \fIbug\-readline\fP@\fIgnu.org\fP. -If you have a fix, you are welcome to mail that -as well! Suggestions and `philosophical' bug reports may be mailed -to \fPbug-readline\fP@\fIgnu.org\fP or posted to the Usenet -newsgroup -.BR gnu.bash.bug . -.PP -Comments and bug reports concerning -this manual page should be directed to -.IR chet@ins.CWRU.Edu . -.SH BUGS -.PP -It's too big and too slow. diff --git a/lib/readline/doc/rlman.texi~ b/lib/readline/doc/rlman.texi~ deleted file mode 100644 index 1ca893a96..000000000 --- a/lib/readline/doc/rlman.texi~ +++ /dev/null @@ -1,100 +0,0 @@ -\input texinfo @c -*-texinfo-*- -@comment %**start of header (This is for running Texinfo on a region.) -@setfilename readline.info -@settitle GNU Readline Library -@comment %**end of header (This is for running Texinfo on a region.) -@synindex vr fn - -@include version.texi - -@copying -This manual describes the GNU Readline Library -(version @value{VERSION}, @value{UPDATED}), a library which aids in the -consistency of user interface across discrete programs which provide -a command line interface. - -Copyright @copyright{} 1988--2007 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.2 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 are free to copy and modify -this GNU Manual. Buying copies from GNU Press supports the FSF in -developing GNU and promoting software freedom.'' -@end quotation -@end copying - -@dircategory Libraries -@direntry -* Readline: (readline). The GNU readline library API. -@end direntry - -@titlepage -@title GNU Readline Library -@subtitle Edition @value{EDITION}, for @code{Readline Library} 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 -@top GNU Readline Library - -This document describes the GNU Readline Library, a utility which aids -in the consistency of user interface across discrete programs which -provide a command line interface. - -@menu -* Command Line Editing:: GNU Readline User's Manual. -* Programming with GNU Readline:: GNU Readline Programmer's Manual. -* Copying This Manual:: Copying this manual. -* Concept Index:: Index of concepts described in this manual. -* Function and Variable Index:: Index of externally visible functions - and variables. -@end menu -@end ifnottex - -@include rluser.texi -@include rltech.texi - -@node Copying This Manual -@appendix Copying This Manual - -@menu -* GNU Free Documentation License:: License for copying this manual. -@end menu - -@include fdl.texi - -@node Concept Index -@unnumbered Concept Index -@printindex cp - -@node Function and Variable Index -@unnumbered Function and Variable Index -@printindex fn - -@bye diff --git a/lib/readline/doc/rltech.texi~ b/lib/readline/doc/rltech.texi~ deleted file mode 100644 index 42b761b63..000000000 --- a/lib/readline/doc/rltech.texi~ +++ /dev/null @@ -1,2380 +0,0 @@ -@comment %**start of header (This is for running Texinfo on a region.) -@setfilename rltech.info -@comment %**end of header (This is for running Texinfo on a region.) - -@ifinfo -This document describes the GNU Readline Library, a utility for aiding -in the consistency of user interface across discrete programs that need -to provide a command line interface. - -Copyright (C) 1988-2007 Free Software Foundation, Inc. - -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -pare preserved on all copies. - -@ignore -Permission is granted to process this file through TeX and print the -results, provided the printed document carries copying permission -notice identical to this one except for the removal of this paragraph -(this paragraph not being relevant to the printed manual). -@end ignore - -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided that the entire -resulting derived work is distributed under the terms of a permission -notice identical to this one. - -Permission is granted to copy and distribute translations of this manual -into another language, under the above conditions for modified versions, -except that this permission notice may be stated in a translation approved -by the Foundation. -@end ifinfo - -@node Programming with GNU Readline -@chapter Programming with GNU Readline - -This chapter describes the interface between the @sc{gnu} Readline Library and -other programs. If you are a programmer, and you wish to include the -features found in @sc{gnu} Readline -such as completion, line editing, and interactive history manipulation -in your own programs, this section is for you. - -@menu -* Basic Behavior:: Using the default behavior of Readline. -* Custom Functions:: Adding your own functions to Readline. -* Readline Variables:: Variables accessible to custom - functions. -* Readline Convenience Functions:: Functions which Readline supplies to - aid in writing your own custom - functions. -* Readline Signal Handling:: How Readline behaves when it receives signals. -* Custom Completers:: Supplanting or supplementing Readline's - completion functions. -@end menu - -@node Basic Behavior -@section Basic Behavior - -Many programs provide a command line interface, such as @code{mail}, -@code{ftp}, and @code{sh}. For such programs, the default behaviour of -Readline is sufficient. This section describes how to use Readline in -the simplest way possible, perhaps to replace calls in your code to -@code{gets()} or @code{fgets()}. - -@findex readline -@cindex readline, function - -The function @code{readline()} prints a prompt @var{prompt} -and then reads and returns a single line of text from the user. -If @var{prompt} is @code{NULL} or the empty string, no prompt is displayed. -The line @code{readline} returns is allocated with @code{malloc()}; -the caller should @code{free()} the line when it has finished with it. -The declaration for @code{readline} in ANSI C is - -@example -@code{char *readline (const char *@var{prompt});} -@end example - -@noindent -So, one might say -@example -@code{char *line = readline ("Enter a line: ");} -@end example -@noindent -in order to read a line of text from the user. -The line returned has the final newline removed, so only the -text remains. - -If @code{readline} encounters an @code{EOF} while reading the line, and the -line is empty at that point, then @code{(char *)NULL} is returned. -Otherwise, the line is ended just as if a newline had been typed. - -If you want the user to be able to get at the line later, (with -@key{C-p} for example), you must call @code{add_history()} to save the -line away in a @dfn{history} list of such lines. - -@example -@code{add_history (line)}; -@end example - -@noindent -For full details on the GNU History Library, see the associated manual. - -It is preferable to avoid saving empty lines on the history list, since -users rarely have a burning need to reuse a blank line. Here is -a function which usefully replaces the standard @code{gets()} library -function, and has the advantage of no static buffer to overflow: - -@example -/* A static variable for holding the line. */ -static char *line_read = (char *)NULL; - -/* Read a string, and return a pointer to it. - Returns NULL on EOF. */ -char * -rl_gets () -@{ - /* If the buffer has already been allocated, - return the memory to the free pool. */ - if (line_read) - @{ - free (line_read); - line_read = (char *)NULL; - @} - - /* Get a line from the user. */ - line_read = readline (""); - - /* If the line has any text in it, - save it on the history. */ - if (line_read && *line_read) - add_history (line_read); - - return (line_read); -@} -@end example - -This function gives the user the default behaviour of @key{TAB} -completion: completion on file names. If you do not want Readline to -complete on filenames, you can change the binding of the @key{TAB} key -with @code{rl_bind_key()}. - -@example -@code{int rl_bind_key (int @var{key}, rl_command_func_t *@var{function});} -@end example - -@code{rl_bind_key()} takes two arguments: @var{key} is the character that -you want to bind, and @var{function} is the address of the function to -call when @var{key} is pressed. Binding @key{TAB} to @code{rl_insert()} -makes @key{TAB} insert itself. -@code{rl_bind_key()} returns non-zero if @var{key} is not a valid -ASCII character code (between 0 and 255). - -Thus, to disable the default @key{TAB} behavior, the following suffices: -@example -@code{rl_bind_key ('\t', rl_insert);} -@end example - -This code should be executed once at the start of your program; you -might write a function called @code{initialize_readline()} which -performs this and other desired initializations, such as installing -custom completers (@pxref{Custom Completers}). - -@node Custom Functions -@section Custom Functions - -Readline provides many functions for manipulating the text of -the line, but it isn't possible to anticipate the needs of all -programs. This section describes the various functions and variables -defined within the Readline library which allow a user program to add -customized functionality to Readline. - -Before declaring any functions that customize Readline's behavior, or -using any functionality Readline provides in other code, an -application writer should include the file @code{} -in any file that uses Readline's features. Since some of the definitions -in @code{readline.h} use the @code{stdio} library, the file -@code{} should be included before @code{readline.h}. - -@code{readline.h} defines a C preprocessor variable that should -be treated as an integer, @code{RL_READLINE_VERSION}, which may -be used to conditionally compile application code depending on -the installed Readline version. The value is a hexadecimal -encoding of the major and minor version numbers of the library, -of the form 0x@var{MMmm}. @var{MM} is the two-digit major -version number; @var{mm} is the two-digit minor version number. -For Readline 4.2, for example, the value of -@code{RL_READLINE_VERSION} would be @code{0x0402}. - -@menu -* Readline Typedefs:: C declarations to make code readable. -* Function Writing:: Variables and calling conventions. -@end menu - -@node Readline Typedefs -@subsection Readline Typedefs - -For readabilty, we declare a number of new object types, all pointers -to functions. - -The reason for declaring these new types is to make it easier to write -code describing pointers to C functions with appropriately prototyped -arguments and return values. - -For instance, say we want to declare a variable @var{func} as a pointer -to a function which takes two @code{int} arguments and returns an -@code{int} (this is the type of all of the Readline bindable functions). -Instead of the classic C declaration - -@code{int (*func)();} - -@noindent -or the ANSI-C style declaration - -@code{int (*func)(int, int);} - -@noindent -we may write - -@code{rl_command_func_t *func;} - -The full list of function pointer types available is - -@table @code -@item typedef int rl_command_func_t (int, int); - -@item typedef char *rl_compentry_func_t (const char *, int); - -@item typedef char **rl_completion_func_t (const char *, int, int); - -@item typedef char *rl_quote_func_t (char *, int, char *); - -@item typedef char *rl_dequote_func_t (char *, int); - -@item typedef int rl_compignore_func_t (char **); - -@item typedef void rl_compdisp_func_t (char **, int, int); - -@item typedef int rl_hook_func_t (void); - -@item typedef int rl_getc_func_t (FILE *); - -@item typedef int rl_linebuf_func_t (char *, int); - -@item typedef int rl_intfunc_t (int); -@item #define rl_ivoidfunc_t rl_hook_func_t -@item typedef int rl_icpfunc_t (char *); -@item typedef int rl_icppfunc_t (char **); - -@item typedef void rl_voidfunc_t (void); -@item typedef void rl_vintfunc_t (int); -@item typedef void rl_vcpfunc_t (char *); -@item typedef void rl_vcppfunc_t (char **); - -@end table - -@node Function Writing -@subsection Writing a New Function - -In order to write new functions for Readline, you need to know the -calling conventions for keyboard-invoked functions, and the names of the -variables that describe the current state of the line read so far. - -The calling sequence for a command @code{foo} looks like - -@example -@code{int foo (int count, int key)} -@end example - -@noindent -where @var{count} is the numeric argument (or 1 if defaulted) and -@var{key} is the key that invoked this function. - -It is completely up to the function as to what should be done with the -numeric argument. Some functions use it as a repeat count, some -as a flag, and others to choose alternate behavior (refreshing the current -line as opposed to refreshing the screen, for example). Some choose to -ignore it. In general, if a -function uses the numeric argument as a repeat count, it should be able -to do something useful with both negative and positive arguments. -At the very least, it should be aware that it can be passed a -negative argument. - -A command function should return 0 if its action completes successfully, -and a non-zero value if some error occurs. -This is the convention obeyed by all of the builtin Readline bindable -command functions. - -@node Readline Variables -@section Readline Variables - -These variables are available to function writers. - -@deftypevar {char *} rl_line_buffer -This is the line gathered so far. You are welcome to modify the -contents of the line, but see @ref{Allowing Undoing}. The -function @code{rl_extend_line_buffer} is available to increase -the memory allocated to @code{rl_line_buffer}. -@end deftypevar - -@deftypevar int rl_point -The offset of the current cursor position in @code{rl_line_buffer} -(the @emph{point}). -@end deftypevar - -@deftypevar int rl_end -The number of characters present in @code{rl_line_buffer}. When -@code{rl_point} is at the end of the line, @code{rl_point} and -@code{rl_end} are equal. -@end deftypevar - -@deftypevar int rl_mark -The @var{mark} (saved position) in the current line. If set, the mark -and point define a @emph{region}. -@end deftypevar - -@deftypevar int rl_done -Setting this to a non-zero value causes Readline to return the current -line immediately. -@end deftypevar - -@deftypevar int rl_num_chars_to_read -Setting this to a positive value before calling @code{readline()} causes -Readline to return after accepting that many characters, rather -than reading up to a character bound to @code{accept-line}. -@end deftypevar - -@deftypevar int rl_pending_input -Setting this to a value makes it the next keystroke read. This is a -way to stuff a single character into the input stream. -@end deftypevar - -@deftypevar int rl_dispatching -Set to a non-zero value if a function is being called from a key binding; -zero otherwise. Application functions can test this to discover whether -they were called directly or by Readline's dispatching mechanism. -@end deftypevar - -@deftypevar int rl_erase_empty_line -Setting this to a non-zero value causes Readline to completely erase -the current line, including any prompt, any time a newline is typed as -the only character on an otherwise-empty line. The cursor is moved to -the beginning of the newly-blank line. -@end deftypevar - -@deftypevar {char *} rl_prompt -The prompt Readline uses. This is set from the argument to -@code{readline()}, and should not be assigned to directly. -The @code{rl_set_prompt()} function (@pxref{Redisplay}) may -be used to modify the prompt string after calling @code{readline()}. -@end deftypevar - -@deftypevar {char *} rl_display_prompt -The string displayed as the prompt. This is usually identical to -@var{rl_prompt}, but may be changed temporarily by functions that -use the prompt string as a message area, such as incremental search. -@end deftypevar - -@deftypevar int rl_already_prompted -If an application wishes to display the prompt itself, rather than have -Readline do it the first time @code{readline()} is called, it should set -this variable to a non-zero value after displaying the prompt. -The prompt must also be passed as the argument to @code{readline()} so -the redisplay functions can update the display properly. -The calling application is responsible for managing the value; Readline -never sets it. -@end deftypevar - -@deftypevar {const char *} rl_library_version -The version number of this revision of the library. -@end deftypevar - -@deftypevar int rl_readline_version -An integer encoding the current version of the library. The encoding is -of the form 0x@var{MMmm}, where @var{MM} is the two-digit major version -number, and @var{mm} is the two-digit minor version number. -For example, for Readline-4.2, @code{rl_readline_version} would have the -value 0x0402. -@end deftypevar - -@deftypevar {int} rl_gnu_readline_p -Always set to 1, denoting that this is @sc{gnu} readline rather than some -emulation. -@end deftypevar - -@deftypevar {const char *} rl_terminal_name -The terminal type, used for initialization. If not set by the application, -Readline sets this to the value of the @env{TERM} environment variable -the first time it is called. -@end deftypevar - -@deftypevar {const char *} rl_readline_name -This variable is set to a unique name by each application using Readline. -The value allows conditional parsing of the inputrc file -(@pxref{Conditional Init Constructs}). -@end deftypevar - -@deftypevar {FILE *} rl_instream -The stdio stream from which Readline reads input. -If @code{NULL}, Readline defaults to @var{stdin}. -@end deftypevar - -@deftypevar {FILE *} rl_outstream -The stdio stream to which Readline performs output. -If @code{NULL}, Readline defaults to @var{stdout}. -@end deftypevar - -@deftypevar int rl_prefer_env_winsize -If non-zero, Readline gives values found in the @env{LINES} and -@env{COLUMNS} environment variables greater precedence than values fetched -from the kernel when computing the screen dimensions. -@end deftypevar - -@deftypevar {rl_command_func_t *} rl_last_func -The address of the last command function Readline executed. May be used to -test whether or not a function is being executed twice in succession, for -example. -@end deftypevar - -@deftypevar {rl_hook_func_t *} rl_startup_hook -If non-zero, this is the address of a function to call just -before @code{readline} prints the first prompt. -@end deftypevar - -@deftypevar {rl_hook_func_t *} rl_pre_input_hook -If non-zero, this is the address of a function to call after -the first prompt has been printed and just before @code{readline} -starts reading input characters. -@end deftypevar - -@deftypevar {rl_hook_func_t *} rl_event_hook -If non-zero, this is the address of a function to call periodically -when Readline is waiting for terminal input. -By default, this will be called at most ten times a second if there -is no keyboard input. -@end deftypevar - -@deftypevar {rl_getc_func_t *} rl_getc_function -If non-zero, Readline will call indirectly through this pointer -to get a character from the input stream. By default, it is set to -@code{rl_getc}, the default Readline character input function -(@pxref{Character Input}). -@end deftypevar - -@deftypevar {rl_voidfunc_t *} rl_redisplay_function -If non-zero, Readline will call indirectly through this pointer -to update the display with the current contents of the editing buffer. -By default, it is set to @code{rl_redisplay}, the default Readline -redisplay function (@pxref{Redisplay}). -@end deftypevar - -@deftypevar {rl_vintfunc_t *} rl_prep_term_function -If non-zero, Readline will call indirectly through this pointer -to initialize the terminal. The function takes a single argument, an -@code{int} flag that says whether or not to use eight-bit characters. -By default, this is set to @code{rl_prep_terminal} -(@pxref{Terminal Management}). -@end deftypevar - -@deftypevar {rl_voidfunc_t *} rl_deprep_term_function -If non-zero, Readline will call indirectly through this pointer -to reset the terminal. This function should undo the effects of -@code{rl_prep_term_function}. -By default, this is set to @code{rl_deprep_terminal} -(@pxref{Terminal Management}). -@end deftypevar - -@deftypevar {Keymap} rl_executing_keymap -This variable is set to the keymap (@pxref{Keymaps}) in which the -currently executing readline function was found. -@end deftypevar - -@deftypevar {Keymap} rl_binding_keymap -This variable is set to the keymap (@pxref{Keymaps}) in which the -last key binding occurred. -@end deftypevar - -@deftypevar {char *} rl_executing_macro -This variable is set to the text of any currently-executing macro. -@end deftypevar - -@deftypevar {int} rl_readline_state -A variable with bit values that encapsulate the current Readline state. -A bit is set with the @code{RL_SETSTATE} macro, and unset with the -@code{RL_UNSETSTATE} macro. Use the @code{RL_ISSTATE} macro to test -whether a particular state bit is set. Current state bits include: - -@table @code -@item RL_STATE_NONE -Readline has not yet been called, nor has it begun to intialize. -@item RL_STATE_INITIALIZING -Readline is initializing its internal data structures. -@item RL_STATE_INITIALIZED -Readline has completed its initialization. -@item RL_STATE_TERMPREPPED -Readline has modified the terminal modes to do its own input and redisplay. -@item RL_STATE_READCMD -Readline is reading a command from the keyboard. -@item RL_STATE_METANEXT -Readline is reading more input after reading the meta-prefix character. -@item RL_STATE_DISPATCHING -Readline is dispatching to a command. -@item RL_STATE_MOREINPUT -Readline is reading more input while executing an editing command. -@item RL_STATE_ISEARCH -Readline is performing an incremental history search. -@item RL_STATE_NSEARCH -Readline is performing a non-incremental history search. -@item RL_STATE_SEARCH -Readline is searching backward or forward through the history for a string. -@item RL_STATE_NUMERICARG -Readline is reading a numeric argument. -@item RL_STATE_MACROINPUT -Readline is currently getting its input from a previously-defined keyboard -macro. -@item RL_STATE_MACRODEF -Readline is currently reading characters defining a keyboard macro. -@item RL_STATE_OVERWRITE -Readline is in overwrite mode. -@item RL_STATE_COMPLETING -Readline is performing word completion. -@item RL_STATE_SIGHANDLER -Readline is currently executing the readline signal handler. -@item RL_STATE_UNDOING -Readline is performing an undo. -@item RL_STATE_INPUTPENDING -Readline has input pending due to a call to @code{rl_execute_next()}. -@item RL_STATE_TTYCSAVED -Readline has saved the values of the terminal's special characters. -@item RL_STATE_CALLBACK -Readline is currently using the alternate (callback) interface -(@pxref{Alternate Interface}). -@item RL_STATE_VIMOTION -Readline is reading the argument to a vi-mode "motion" command. -@item RL_STATE_MULTIKEY -Readline is reading a multiple-keystroke command. -@item RL_STATE_VICMDONCE -Readline has entered vi command (movement) mode at least one time during -the current call to @code{readline()}. -@item RL_STATE_DONE -Readline has read a key sequence bound to @code{accept-line} -and is about to return the line to the caller. -@end table - -@end deftypevar - -@deftypevar {int} rl_explicit_arg -Set to a non-zero value if an explicit numeric argument was specified by -the user. Only valid in a bindable command function. -@end deftypevar - -@deftypevar {int} rl_numeric_arg -Set to the value of any numeric argument explicitly specified by the user -before executing the current Readline function. Only valid in a bindable -command function. -@end deftypevar - -@deftypevar {int} rl_editing_mode -Set to a value denoting Readline's current editing mode. A value of -@var{1} means Readline is currently in emacs mode; @var{0} -means that vi mode is active. -@end deftypevar - - -@node Readline Convenience Functions -@section Readline Convenience Functions - -@menu -* Function Naming:: How to give a function you write a name. -* Keymaps:: Making keymaps. -* Binding Keys:: Changing Keymaps. -* Associating Function Names and Bindings:: Translate function names to - key sequences. -* Allowing Undoing:: How to make your functions undoable. -* Redisplay:: Functions to control line display. -* Modifying Text:: Functions to modify @code{rl_line_buffer}. -* Character Input:: Functions to read keyboard input. -* Terminal Management:: Functions to manage terminal settings. -* Utility Functions:: Generally useful functions and hooks. -* Miscellaneous Functions:: Functions that don't fall into any category. -* Alternate Interface:: Using Readline in a `callback' fashion. -* A Readline Example:: An example Readline function. -@end menu - -@node Function Naming -@subsection Naming a Function - -The user can dynamically change the bindings of keys while using -Readline. This is done by representing the function with a descriptive -name. The user is able to type the descriptive name when referring to -the function. Thus, in an init file, one might find - -@example -Meta-Rubout: backward-kill-word -@end example - -This binds the keystroke @key{Meta-Rubout} to the function -@emph{descriptively} named @code{backward-kill-word}. You, as the -programmer, should bind the functions you write to descriptive names as -well. Readline provides a function for doing that: - -@deftypefun int rl_add_defun (const char *name, rl_command_func_t *function, int key) -Add @var{name} to the list of named functions. Make @var{function} be -the function that gets called. If @var{key} is not -1, then bind it to -@var{function} using @code{rl_bind_key()}. -@end deftypefun - -Using this function alone is sufficient for most applications. -It is the recommended way to add a few functions to the default -functions that Readline has built in. -If you need to do something other than adding a function to Readline, -you may need to use the underlying functions described below. - -@node Keymaps -@subsection Selecting a Keymap - -Key bindings take place on a @dfn{keymap}. The keymap is the -association between the keys that the user types and the functions that -get run. You can make your own keymaps, copy existing keymaps, and tell -Readline which keymap to use. - -@deftypefun Keymap rl_make_bare_keymap (void) -Returns a new, empty keymap. The space for the keymap is allocated with -@code{malloc()}; the caller should free it by calling -@code{rl_discard_keymap()} when done. -@end deftypefun - -@deftypefun Keymap rl_copy_keymap (Keymap map) -Return a new keymap which is a copy of @var{map}. -@end deftypefun - -@deftypefun Keymap rl_make_keymap (void) -Return a new keymap with the printing characters bound to rl_insert, -the lowercase Meta characters bound to run their equivalents, and -the Meta digits bound to produce numeric arguments. -@end deftypefun - -@deftypefun void rl_discard_keymap (Keymap keymap) -Free the storage associated with @var{keymap}. -@end deftypefun - -Readline has several internal keymaps. These functions allow you to -change which keymap is active. - -@deftypefun Keymap rl_get_keymap (void) -Returns the currently active keymap. -@end deftypefun - -@deftypefun void rl_set_keymap (Keymap keymap) -Makes @var{keymap} the currently active keymap. -@end deftypefun - -@deftypefun Keymap rl_get_keymap_by_name (const char *name) -Return the keymap matching @var{name}. @var{name} is one which would -be supplied in a @code{set keymap} inputrc line (@pxref{Readline Init File}). -@end deftypefun - -@deftypefun {char *} rl_get_keymap_name (Keymap keymap) -Return the name matching @var{keymap}. @var{name} is one which would -be supplied in a @code{set keymap} inputrc line (@pxref{Readline Init File}). -@end deftypefun - -@node Binding Keys -@subsection Binding Keys - -Key sequences are associate with functions through the keymap. -Readline has several internal keymaps: @code{emacs_standard_keymap}, -@code{emacs_meta_keymap}, @code{emacs_ctlx_keymap}, -@code{vi_movement_keymap}, and @code{vi_insertion_keymap}. -@code{emacs_standard_keymap} is the default, and the examples in -this manual assume that. - -Since @code{readline()} installs a set of default key bindings the first -time it is called, there is always the danger that a custom binding -installed before the first call to @code{readline()} will be overridden. -An alternate mechanism is to install custom key bindings in an -initialization function assigned to the @code{rl_startup_hook} variable -(@pxref{Readline Variables}). - -These functions manage key bindings. - -@deftypefun int rl_bind_key (int key, rl_command_func_t *function) -Binds @var{key} to @var{function} in the currently active keymap. -Returns non-zero in the case of an invalid @var{key}. -@end deftypefun - -@deftypefun int rl_bind_key_in_map (int key, rl_command_func_t *function, Keymap map) -Bind @var{key} to @var{function} in @var{map}. -Returns non-zero in the case of an invalid @var{key}. -@end deftypefun - -@deftypefun int rl_bind_key_if_unbound (int key, rl_command_func_t *function) -Binds @var{key} to @var{function} if it is not already bound in the -currently active keymap. -Returns non-zero in the case of an invalid @var{key} or if @var{key} is -already bound. -@end deftypefun - -@deftypefun int rl_bind_key_if_unbound_in_map (int key, rl_command_func_t *function, Keymap map) -Binds @var{key} to @var{function} if it is not already bound in @var{map}. -Returns non-zero in the case of an invalid @var{key} or if @var{key} is -already bound. -@end deftypefun - -@deftypefun int rl_unbind_key (int key) -Bind @var{key} to the null function in the currently active keymap. -Returns non-zero in case of error. -@end deftypefun - -@deftypefun int rl_unbind_key_in_map (int key, Keymap map) -Bind @var{key} to the null function in @var{map}. -Returns non-zero in case of error. -@end deftypefun - -@deftypefun int rl_unbind_function_in_map (rl_command_func_t *function, Keymap map) -Unbind all keys that execute @var{function} in @var{map}. -@end deftypefun - -@deftypefun int rl_unbind_command_in_map (const char *command, Keymap map) -Unbind all keys that are bound to @var{command} in @var{map}. -@end deftypefun - -@deftypefun int rl_bind_keyseq (const char *keyseq, rl_command_func_t *function) -Bind the key sequence represented by the string @var{keyseq} to the function -@var{function}, beginning in the current keymap. -This makes new keymaps as necessary. -The return value is non-zero if @var{keyseq} is invalid. -@end deftypefun - -@deftypefun int rl_bind_keyseq_in_map (const char *keyseq, rl_command_func_t *function, Keymap map) -Bind the key sequence represented by the string @var{keyseq} to the function -@var{function}. This makes new keymaps as necessary. -Initial bindings are performed in @var{map}. -The return value is non-zero if @var{keyseq} is invalid. -@end deftypefun - -@deftypefun int rl_set_key (const char *keyseq, rl_command_func_t *function, Keymap map) -Equivalent to @code{rl_bind_keyseq_in_map}. -@end deftypefun - -@deftypefun int rl_bind_keyseq_if_unbound (const char *keyseq, rl_command_func_t *function) -Binds @var{keyseq} to @var{function} if it is not already bound in the -currently active keymap. -Returns non-zero in the case of an invalid @var{keyseq} or if @var{keyseq} is -already bound. -@end deftypefun - -@deftypefun int rl_bind_keyseq_if_unbound_in_map (const char *keyseq, rl_command_func_t *function, Keymap map) -Binds @var{keyseq} to @var{function} if it is not already bound in @var{map}. -Returns non-zero in the case of an invalid @var{keyseq} or if @var{keyseq} is -already bound. -@end deftypefun - -@deftypefun int rl_generic_bind (int type, const char *keyseq, char *data, Keymap map) -Bind the key sequence represented by the string @var{keyseq} to the arbitrary -pointer @var{data}. @var{type} says what kind of data is pointed to by -@var{data}; this can be a function (@code{ISFUNC}), a macro -(@code{ISMACR}), or a keymap (@code{ISKMAP}). This makes new keymaps as -necessary. The initial keymap in which to do bindings is @var{map}. -@end deftypefun - -@deftypefun int rl_parse_and_bind (char *line) -Parse @var{line} as if it had been read from the @code{inputrc} file and -perform any key bindings and variable assignments found -(@pxref{Readline Init File}). -@end deftypefun - -@deftypefun int rl_read_init_file (const char *filename) -Read keybindings and variable assignments from @var{filename} -(@pxref{Readline Init File}). -@end deftypefun - -@node Associating Function Names and Bindings -@subsection Associating Function Names and Bindings - -These functions allow you to find out what keys invoke named functions -and the functions invoked by a particular key sequence. You may also -associate a new function name with an arbitrary function. - -@deftypefun {rl_command_func_t *} rl_named_function (const char *name) -Return the function with name @var{name}. -@end deftypefun - -@deftypefun {rl_command_func_t *} rl_function_of_keyseq (const char *keyseq, Keymap map, int *type) -Return the function invoked by @var{keyseq} in keymap @var{map}. -If @var{map} is @code{NULL}, the current keymap is used. If @var{type} is -not @code{NULL}, the type of the object is returned in the @code{int} variable -it points to (one of @code{ISFUNC}, @code{ISKMAP}, or @code{ISMACR}). -@end deftypefun - -@deftypefun {char **} rl_invoking_keyseqs (rl_command_func_t *function) -Return an array of strings representing the key sequences used to -invoke @var{function} in the current keymap. -@end deftypefun - -@deftypefun {char **} rl_invoking_keyseqs_in_map (rl_command_func_t *function, Keymap map) -Return an array of strings representing the key sequences used to -invoke @var{function} in the keymap @var{map}. -@end deftypefun - -@deftypefun void rl_function_dumper (int readable) -Print the readline function names and the key sequences currently -bound to them to @code{rl_outstream}. If @var{readable} is non-zero, -the list is formatted in such a way that it can be made part of an -@code{inputrc} file and re-read. -@end deftypefun - -@deftypefun void rl_list_funmap_names (void) -Print the names of all bindable Readline functions to @code{rl_outstream}. -@end deftypefun - -@deftypefun {const char **} rl_funmap_names (void) -Return a NULL terminated array of known function names. The array is -sorted. The array itself is allocated, but not the strings inside. You -should free the array, but not the pointers, using @code{free} or -@code{rl_free} when you are done. -@end deftypefun - -@deftypefun int rl_add_funmap_entry (const char *name, rl_command_func_t *function) -Add @var{name} to the list of bindable Readline command names, and make -@var{function} the function to be called when @var{name} is invoked. -@end deftypefun - -@node Allowing Undoing -@subsection Allowing Undoing - -Supporting the undo command is a painless thing, and makes your -functions much more useful. It is certainly easy to try -something if you know you can undo it. - -If your function simply inserts text once, or deletes text once, and -uses @code{rl_insert_text()} or @code{rl_delete_text()} to do it, then -undoing is already done for you automatically. - -If you do multiple insertions or multiple deletions, or any combination -of these operations, you should group them together into one operation. -This is done with @code{rl_begin_undo_group()} and -@code{rl_end_undo_group()}. - -The types of events that can be undone are: - -@smallexample -enum undo_code @{ UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END @}; -@end smallexample - -Notice that @code{UNDO_DELETE} means to insert some text, and -@code{UNDO_INSERT} means to delete some text. That is, the undo code -tells what to undo, not how to undo it. @code{UNDO_BEGIN} and -@code{UNDO_END} are tags added by @code{rl_begin_undo_group()} and -@code{rl_end_undo_group()}. - -@deftypefun int rl_begin_undo_group (void) -Begins saving undo information in a group construct. The undo -information usually comes from calls to @code{rl_insert_text()} and -@code{rl_delete_text()}, but could be the result of calls to -@code{rl_add_undo()}. -@end deftypefun - -@deftypefun int rl_end_undo_group (void) -Closes the current undo group started with @code{rl_begin_undo_group -()}. There should be one call to @code{rl_end_undo_group()} -for each call to @code{rl_begin_undo_group()}. -@end deftypefun - -@deftypefun void rl_add_undo (enum undo_code what, int start, int end, char *text) -Remember how to undo an event (according to @var{what}). The affected -text runs from @var{start} to @var{end}, and encompasses @var{text}. -@end deftypefun - -@deftypefun void rl_free_undo_list (void) -Free the existing undo list. -@end deftypefun - -@deftypefun int rl_do_undo (void) -Undo the first thing on the undo list. Returns @code{0} if there was -nothing to undo, non-zero if something was undone. -@end deftypefun - -Finally, if you neither insert nor delete text, but directly modify the -existing text (e.g., change its case), call @code{rl_modifying()} -once, just before you modify the text. You must supply the indices of -the text range that you are going to modify. - -@deftypefun int rl_modifying (int start, int end) -Tell Readline to save the text between @var{start} and @var{end} as a -single undo unit. It is assumed that you will subsequently modify -that text. -@end deftypefun - -@node Redisplay -@subsection Redisplay - -@deftypefun void rl_redisplay (void) -Change what's displayed on the screen to reflect the current contents -of @code{rl_line_buffer}. -@end deftypefun - -@deftypefun int rl_forced_update_display (void) -Force the line to be updated and redisplayed, whether or not -Readline thinks the screen display is correct. -@end deftypefun - -@deftypefun int rl_on_new_line (void) -Tell the update functions that we have moved onto a new (empty) line, -usually after ouputting a newline. -@end deftypefun - -@deftypefun int rl_on_new_line_with_prompt (void) -Tell the update functions that we have moved onto a new line, with -@var{rl_prompt} already displayed. -This could be used by applications that want to output the prompt string -themselves, but still need Readline to know the prompt string length for -redisplay. -It should be used after setting @var{rl_already_prompted}. -@end deftypefun - -@deftypefun int rl_reset_line_state (void) -Reset the display state to a clean state and redisplay the current line -starting on a new line. -@end deftypefun - -@deftypefun int rl_crlf (void) -Move the cursor to the start of the next screen line. -@end deftypefun - -@deftypefun int rl_show_char (int c) -Display character @var{c} on @code{rl_outstream}. -If Readline has not been set to display meta characters directly, this -will convert meta characters to a meta-prefixed key sequence. -This is intended for use by applications which wish to do their own -redisplay. -@end deftypefun - -@deftypefun int rl_message (const char *, @dots{}) -The arguments are a format string as would be supplied to @code{printf}, -possibly containing conversion specifications such as @samp{%d}, and -any additional arguments necessary to satisfy the conversion specifications. -The resulting string is displayed in the @dfn{echo area}. The echo area -is also used to display numeric arguments and search strings. -You should call @code{rl_save_prompt} to save the prompt information -before calling this function. -@end deftypefun - -@deftypefun int rl_clear_message (void) -Clear the message in the echo area. If the prompt was saved with a call to -@code{rl_save_prompt} before the last call to @code{rl_message}, -call @code{rl_restore_prompt} before calling this function. -@end deftypefun - -@deftypefun void rl_save_prompt (void) -Save the local Readline prompt display state in preparation for -displaying a new message in the message area with @code{rl_message()}. -@end deftypefun - -@deftypefun void rl_restore_prompt (void) -Restore the local Readline prompt display state saved by the most -recent call to @code{rl_save_prompt}. -if @code{rl_save_prompt} was called to save the prompt before a call -to @code{rl_message}, this function should be called before the -corresponding call to @code{rl_clear_message}. -@end deftypefun - -@deftypefun int rl_expand_prompt (char *prompt) -Expand any special character sequences in @var{prompt} and set up the -local Readline prompt redisplay variables. -This function is called by @code{readline()}. It may also be called to -expand the primary prompt if the @code{rl_on_new_line_with_prompt()} -function or @code{rl_already_prompted} variable is used. -It returns the number of visible characters on the last line of the -(possibly multi-line) prompt. -Applications may indicate that the prompt contains characters that take -up no physical screen space when displayed by bracketing a sequence of -such characters with the special markers @code{RL_PROMPT_START_IGNORE} -and @code{RL_PROMPT_END_IGNORE} (declared in @file{readline.h}. This may -be used to embed terminal-specific escape sequences in prompts. -@end deftypefun - -@deftypefun int rl_set_prompt (const char *prompt) -Make Readline use @var{prompt} for subsequent redisplay. This calls -@code{rl_expand_prompt()} to expand the prompt and sets @code{rl_prompt} -to the result. -@end deftypefun - -@node Modifying Text -@subsection Modifying Text - -@deftypefun int rl_insert_text (const char *text) -Insert @var{text} into the line at the current cursor position. -Returns the number of characters inserted. -@end deftypefun - -@deftypefun int rl_delete_text (int start, int end) -Delete the text between @var{start} and @var{end} in the current line. -Returns the number of characters deleted. -@end deftypefun - -@deftypefun {char *} rl_copy_text (int start, int end) -Return a copy of the text between @var{start} and @var{end} in -the current line. -@end deftypefun - -@deftypefun int rl_kill_text (int start, int end) -Copy the text between @var{start} and @var{end} in the current line -to the kill ring, appending or prepending to the last kill if the -last command was a kill command. The text is deleted. -If @var{start} is less than @var{end}, -the text is appended, otherwise prepended. If the last command was -not a kill, a new kill ring slot is used. -@end deftypefun - -@deftypefun int rl_push_macro_input (char *macro) -Cause @var{macro} to be inserted into the line, as if it had been invoked -by a key bound to a macro. Not especially useful; use -@code{rl_insert_text()} instead. -@end deftypefun - -@node Character Input -@subsection Character Input - -@deftypefun int rl_read_key (void) -Return the next character available from Readline's current input stream. -This handles input inserted into -the input stream via @var{rl_pending_input} (@pxref{Readline Variables}) -and @code{rl_stuff_char()}, macros, and characters read from the keyboard. -While waiting for input, this function will call any function assigned to -the @code{rl_event_hook} variable. -@end deftypefun - -@deftypefun int rl_getc (FILE *stream) -Return the next character available from @var{stream}, which is assumed to -be the keyboard. -@end deftypefun - -@deftypefun int rl_stuff_char (int c) -Insert @var{c} into the Readline input stream. It will be "read" -before Readline attempts to read characters from the terminal with -@code{rl_read_key()}. Up to 512 characters may be pushed back. -@code{rl_stuff_char} returns 1 if the character was successfully inserted; -0 otherwise. -@end deftypefun - -@deftypefun int rl_execute_next (int c) -Make @var{c} be the next command to be executed when @code{rl_read_key()} -is called. This sets @var{rl_pending_input}. -@end deftypefun - -@deftypefun int rl_clear_pending_input (void) -Unset @var{rl_pending_input}, effectively negating the effect of any -previous call to @code{rl_execute_next()}. This works only if the -pending input has not already been read with @code{rl_read_key()}. -@end deftypefun - -@deftypefun int rl_set_keyboard_input_timeout (int u) -While waiting for keyboard input in @code{rl_read_key()}, Readline will -wait for @var{u} microseconds for input before calling any function -assigned to @code{rl_event_hook}. @var{u} must be greater than or equal -to zero (a zero-length timeout is equivalent to a poll). -The default waiting period is one-tenth of a second. -Returns the old timeout value. -@end deftypefun - -@node Terminal Management -@subsection Terminal Management - -@deftypefun void rl_prep_terminal (int meta_flag) -Modify the terminal settings for Readline's use, so @code{readline()} -can read a single character at a time from the keyboard. -The @var{meta_flag} argument should be non-zero if Readline should -read eight-bit input. -@end deftypefun - -@deftypefun void rl_deprep_terminal (void) -Undo the effects of @code{rl_prep_terminal()}, leaving the terminal in -the state in which it was before the most recent call to -@code{rl_prep_terminal()}. -@end deftypefun - -@deftypefun void rl_tty_set_default_bindings (Keymap kmap) -Read the operating system's terminal editing characters (as would be -displayed by @code{stty}) to their Readline equivalents. -The bindings are performed in @var{kmap}. -@end deftypefun - -@deftypefun void rl_tty_unset_default_bindings (Keymap kmap) -Reset the bindings manipulated by @code{rl_tty_set_default_bindings} so -that the terminal editing characters are bound to @code{rl_insert}. -The bindings are performed in @var{kmap}. -@end deftypefun - -@deftypefun int rl_reset_terminal (const char *terminal_name) -Reinitialize Readline's idea of the terminal settings using -@var{terminal_name} as the terminal type (e.g., @code{vt100}). -If @var{terminal_name} is @code{NULL}, the value of the @code{TERM} -environment variable is used. -@end deftypefun - -@node Utility Functions -@subsection Utility Functions - -@deftypefun int rl_save_state (struct readline_state *sp) -Save a snapshot of Readline's internal state to @var{sp}. -The contents of the @var{readline_state} structure are documented -in @file{readline.h}. -The caller is responsible for allocating the structure. -@end deftypefun - -@deftypefun int rl_restore_state (struct readline_state *sp) -Restore Readline's internal state to that stored in @var{sp}, which must -have been saved by a call to @code{rl_save_state}. -The contents of the @var{readline_state} structure are documented -in @file{readline.h}. -The caller is responsible for freeing the structure. -@end deftypefun - -@deftypefun void rl_free (void *mem) -Deallocate the memory pointed to by @var{mem}. @var{mem} must have been -allocated by @code{malloc}. -@end deftypefun - -@deftypefun void rl_replace_line (const char *text, int clear_undo) -Replace the contents of @code{rl_line_buffer} with @var{text}. -The point and mark are preserved, if possible. -If @var{clear_undo} is non-zero, the undo list associated with the -current line is cleared. -@end deftypefun - -@deftypefun int rl_extend_line_buffer (int len) -Ensure that @code{rl_line_buffer} has enough space to hold @var{len} -characters, possibly reallocating it if necessary. -@end deftypefun - -@deftypefun int rl_initialize (void) -Initialize or re-initialize Readline's internal state. -It's not strictly necessary to call this; @code{readline()} calls it before -reading any input. -@end deftypefun - -@deftypefun int rl_ding (void) -Ring the terminal bell, obeying the setting of @code{bell-style}. -@end deftypefun - -@deftypefun int rl_alphabetic (int c) -Return 1 if @var{c} is an alphabetic character. -@end deftypefun - -@deftypefun void rl_display_match_list (char **matches, int len, int max) -A convenience function for displaying a list of strings in -columnar format on Readline's output stream. @code{matches} is the list -of strings, in argv format, such as a list of completion matches. -@code{len} is the number of strings in @code{matches}, and @code{max} -is the length of the longest string in @code{matches}. This function uses -the setting of @code{print-completions-horizontally} to select how the -matches are displayed (@pxref{Readline Init File Syntax}). -@end deftypefun - -The following are implemented as macros, defined in @code{chardefs.h}. -Applications should refrain from using them. - -@deftypefun int _rl_uppercase_p (int c) -Return 1 if @var{c} is an uppercase alphabetic character. -@end deftypefun - -@deftypefun int _rl_lowercase_p (int c) -Return 1 if @var{c} is a lowercase alphabetic character. -@end deftypefun - -@deftypefun int _rl_digit_p (int c) -Return 1 if @var{c} is a numeric character. -@end deftypefun - -@deftypefun int _rl_to_upper (int c) -If @var{c} is a lowercase alphabetic character, return the corresponding -uppercase character. -@end deftypefun - -@deftypefun int _rl_to_lower (int c) -If @var{c} is an uppercase alphabetic character, return the corresponding -lowercase character. -@end deftypefun - -@deftypefun int _rl_digit_value (int c) -If @var{c} is a number, return the value it represents. -@end deftypefun - -@node Miscellaneous Functions -@subsection Miscellaneous Functions - -@deftypefun int rl_macro_bind (const char *keyseq, const char *macro, Keymap map) -Bind the key sequence @var{keyseq} to invoke the macro @var{macro}. -The binding is performed in @var{map}. When @var{keyseq} is invoked, the -@var{macro} will be inserted into the line. This function is deprecated; -use @code{rl_generic_bind()} instead. -@end deftypefun - -@deftypefun void rl_macro_dumper (int readable) -Print the key sequences bound to macros and their values, using -the current keymap, to @code{rl_outstream}. -If @var{readable} is non-zero, the list is formatted in such a way -that it can be made part of an @code{inputrc} file and re-read. -@end deftypefun - -@deftypefun int rl_variable_bind (const char *variable, const char *value) -Make the Readline variable @var{variable} have @var{value}. -This behaves as if the readline command -@samp{set @var{variable} @var{value}} had been executed in an @code{inputrc} -file (@pxref{Readline Init File Syntax}). -@end deftypefun - -@deftypefun {char *} rl_variable_value (const char *variable) -Return a string representing the value of the Readline variable @var{variable}. -For boolean variables, this string is either @samp{on} or @samp{off}. -@end deftypefun - -@deftypefun void rl_variable_dumper (int readable) -Print the readline variable names and their current values -to @code{rl_outstream}. -If @var{readable} is non-zero, the list is formatted in such a way -that it can be made part of an @code{inputrc} file and re-read. -@end deftypefun - -@deftypefun int rl_set_paren_blink_timeout (int u) -Set the time interval (in microseconds) that Readline waits when showing -a balancing character when @code{blink-matching-paren} has been enabled. -@end deftypefun - -@deftypefun {char *} rl_get_termcap (const char *cap) -Retrieve the string value of the termcap capability @var{cap}. -Readline fetches the termcap entry for the current terminal name and -uses those capabilities to move around the screen line and perform other -terminal-specific operations, like erasing a line. Readline does not -use all of a terminal's capabilities, and this function will return -values for only those capabilities Readline uses. -@end deftypefun - -@node Alternate Interface -@subsection Alternate Interface - -An alternate interface is available to plain @code{readline()}. Some -applications need to interleave keyboard I/O with file, device, or -window system I/O, typically by using a main loop to @code{select()} -on various file descriptors. To accomodate this need, readline can -also be invoked as a `callback' function from an event loop. There -are functions available to make this easy. - -@deftypefun void rl_callback_handler_install (const char *prompt, rl_vcpfunc_t *lhandler) -Set up the terminal for readline I/O and display the initial -expanded value of @var{prompt}. Save the value of @var{lhandler} to -use as a function to call when a complete line of input has been entered. -The function takes the text of the line as an argument. -@end deftypefun - -@deftypefun void rl_callback_read_char (void) -Whenever an application determines that keyboard input is available, it -should call @code{rl_callback_read_char()}, which will read the next -character from the current input source. -If that character completes the line, @code{rl_callback_read_char} will -invoke the @var{lhandler} function saved by @code{rl_callback_handler_install} -to process the line. -Before calling the @var{lhandler} function, the terminal settings are -reset to the values they had before calling -@code{rl_callback_handler_install}. -If the @var{lhandler} function returns, -the terminal settings are modified for Readline's use again. -@code{EOF} is indicated by calling @var{lhandler} with a -@code{NULL} line. -@end deftypefun - -@deftypefun void rl_callback_handler_remove (void) -Restore the terminal to its initial state and remove the line handler. -This may be called from within a callback as well as independently. -If the @var{lhandler} installed by @code{rl_callback_handler_install} -does not exit the program, either this function or the function referred -to by the value of @code{rl_deprep_term_function} should be called before -the program exits to reset the terminal settings. -@end deftypefun - -@node A Readline Example -@subsection A Readline Example - -Here is a function which changes lowercase characters to their uppercase -equivalents, and uppercase characters to lowercase. If -this function was bound to @samp{M-c}, then typing @samp{M-c} would -change the case of the character under point. Typing @samp{M-1 0 M-c} -would change the case of the following 10 characters, leaving the cursor on -the last character changed. - -@example -/* Invert the case of the COUNT following characters. */ -int -invert_case_line (count, key) - int count, key; -@{ - register int start, end, i; - - start = rl_point; - - if (rl_point >= rl_end) - return (0); - - if (count < 0) - @{ - direction = -1; - count = -count; - @} - else - direction = 1; - - /* Find the end of the range to modify. */ - end = start + (count * direction); - - /* Force it to be within range. */ - if (end > rl_end) - end = rl_end; - else if (end < 0) - end = 0; - - if (start == end) - return (0); - - if (start > end) - @{ - int temp = start; - start = end; - end = temp; - @} - - /* Tell readline that we are modifying the line, - so it will save the undo information. */ - rl_modifying (start, end); - - for (i = start; i != end; i++) - @{ - if (_rl_uppercase_p (rl_line_buffer[i])) - rl_line_buffer[i] = _rl_to_lower (rl_line_buffer[i]); - else if (_rl_lowercase_p (rl_line_buffer[i])) - rl_line_buffer[i] = _rl_to_upper (rl_line_buffer[i]); - @} - /* Move point to on top of the last character changed. */ - rl_point = (direction == 1) ? end - 1 : start; - return (0); -@} -@end example - -@node Readline Signal Handling -@section Readline Signal Handling - -Signals are asynchronous events sent to a process by the Unix kernel, -sometimes on behalf of another process. They are intended to indicate -exceptional events, like a user pressing the interrupt key on his terminal, -or a network connection being broken. There is a class of signals that can -be sent to the process currently reading input from the keyboard. Since -Readline changes the terminal attributes when it is called, it needs to -perform special processing when such a signal is received in order to -restore the terminal to a sane state, or provide application writers with -functions to do so manually. - -Readline contains an internal signal handler that is installed for a -number of signals (@code{SIGINT}, @code{SIGQUIT}, @code{SIGTERM}, -@code{SIGALRM}, @code{SIGTSTP}, @code{SIGTTIN}, and @code{SIGTTOU}). -When one of these signals is received, the signal handler -will reset the terminal attributes to those that were in effect before -@code{readline()} was called, reset the signal handling to what it was -before @code{readline()} was called, and resend the signal to the calling -application. -If and when the calling application's signal handler returns, Readline -will reinitialize the terminal and continue to accept input. -When a @code{SIGINT} is received, the Readline signal handler performs -some additional work, which will cause any partially-entered line to be -aborted (see the description of @code{rl_free_line_state()} below). - -There is an additional Readline signal handler, for @code{SIGWINCH}, which -the kernel sends to a process whenever the terminal's size changes (for -example, if a user resizes an @code{xterm}). The Readline @code{SIGWINCH} -handler updates Readline's internal screen size information, and then calls -any @code{SIGWINCH} signal handler the calling application has installed. -Readline calls the application's @code{SIGWINCH} signal handler without -resetting the terminal to its original state. If the application's signal -handler does more than update its idea of the terminal size and return (for -example, a @code{longjmp} back to a main processing loop), it @emph{must} -call @code{rl_cleanup_after_signal()} (described below), to restore the -terminal state. - -Readline provides two variables that allow application writers to -control whether or not it will catch certain signals and act on them -when they are received. It is important that applications change the -values of these variables only when calling @code{readline()}, not in -a signal handler, so Readline's internal signal state is not corrupted. - -@deftypevar int rl_catch_signals -If this variable is non-zero, Readline will install signal handlers for -@code{SIGINT}, @code{SIGQUIT}, @code{SIGTERM}, @code{SIGALRM}, -@code{SIGTSTP}, @code{SIGTTIN}, and @code{SIGTTOU}. - -The default value of @code{rl_catch_signals} is 1. -@end deftypevar - -@deftypevar int rl_catch_sigwinch -If this variable is non-zero, Readline will install a signal handler for -@code{SIGWINCH}. - -The default value of @code{rl_catch_sigwinch} is 1. -@end deftypevar - -If an application does not wish to have Readline catch any signals, or -to handle signals other than those Readline catches (@code{SIGHUP}, -for example), -Readline provides convenience functions to do the necessary terminal -and internal state cleanup upon receipt of a signal. - -@deftypefun void rl_cleanup_after_signal (void) -This function will reset the state of the terminal to what it was before -@code{readline()} was called, and remove the Readline signal handlers for -all signals, depending on the values of @code{rl_catch_signals} and -@code{rl_catch_sigwinch}. -@end deftypefun - -@deftypefun void rl_free_line_state (void) -This will free any partial state associated with the current input line -(undo information, any partial history entry, any partially-entered -keyboard macro, and any partially-entered numeric argument). This -should be called before @code{rl_cleanup_after_signal()}. The -Readline signal handler for @code{SIGINT} calls this to abort the -current input line. -@end deftypefun - -@deftypefun void rl_reset_after_signal (void) -This will reinitialize the terminal and reinstall any Readline signal -handlers, depending on the values of @code{rl_catch_signals} and -@code{rl_catch_sigwinch}. -@end deftypefun - -If an application does not wish Readline to catch @code{SIGWINCH}, it may -call @code{rl_resize_terminal()} or @code{rl_set_screen_size()} to force -Readline to update its idea of the terminal size when a @code{SIGWINCH} -is received. - -@deftypefun void rl_echo_signal_char (int sig) -If an application wishes to install its own signal handlers, but still -have readline display characters that generate signals, calling this -function with @var{sig} set to @code{SIGINT}, @code{SIGQUIT}, or -@code{SIGTSTP} will display the character generating that signal. -@end deftypefun - -@deftypefun void rl_resize_terminal (void) -Update Readline's internal screen size by reading values from the kernel. -@end deftypefun - -@deftypefun void rl_set_screen_size (int rows, int cols) -Set Readline's idea of the terminal size to @var{rows} rows and -@var{cols} columns. If either @var{rows} or @var{columns} is less than -or equal to 0, Readline's idea of that terminal dimension is unchanged. -@end deftypefun - -If an application does not want to install a @code{SIGWINCH} handler, but -is still interested in the screen dimensions, Readline's idea of the screen -size may be queried. - -@deftypefun void rl_get_screen_size (int *rows, int *cols) -Return Readline's idea of the terminal's size in the -variables pointed to by the arguments. -@end deftypefun - -@deftypefun void rl_reset_screen_size (void) -Cause Readline to reobtain the screen size and recalculate its dimensions. -@end deftypefun - -The following functions install and remove Readline's signal handlers. - -@deftypefun int rl_set_signals (void) -Install Readline's signal handler for @code{SIGINT}, @code{SIGQUIT}, -@code{SIGTERM}, @code{SIGALRM}, @code{SIGTSTP}, @code{SIGTTIN}, -@code{SIGTTOU}, and @code{SIGWINCH}, depending on the values of -@code{rl_catch_signals} and @code{rl_catch_sigwinch}. -@end deftypefun - -@deftypefun int rl_clear_signals (void) -Remove all of the Readline signal handlers installed by -@code{rl_set_signals()}. -@end deftypefun - -@node Custom Completers -@section Custom Completers -@cindex application-specific completion functions - -Typically, a program that reads commands from the user has a way of -disambiguating commands and data. If your program is one of these, then -it can provide completion for commands, data, or both. -The following sections describe how your program and Readline -cooperate to provide this service. - -@menu -* How Completing Works:: The logic used to do completion. -* Completion Functions:: Functions provided by Readline. -* Completion Variables:: Variables which control completion. -* A Short Completion Example:: An example of writing completer subroutines. -@end menu - -@node How Completing Works -@subsection How Completing Works - -In order to complete some text, the full list of possible completions -must be available. That is, it is not possible to accurately -expand a partial word without knowing all of the possible words -which make sense in that context. The Readline library provides -the user interface to completion, and two of the most common -completion functions: filename and username. For completing other types -of text, you must write your own completion function. This section -describes exactly what such functions must do, and provides an example. - -There are three major functions used to perform completion: - -@enumerate -@item -The user-interface function @code{rl_complete()}. This function is -called with the same arguments as other bindable Readline functions: -@var{count} and @var{invoking_key}. -It isolates the word to be completed and calls -@code{rl_completion_matches()} to generate a list of possible completions. -It then either lists the possible completions, inserts the possible -completions, or actually performs the -completion, depending on which behavior is desired. - -@item -The internal function @code{rl_completion_matches()} uses an -application-supplied @dfn{generator} function to generate the list of -possible matches, and then returns the array of these matches. -The caller should place the address of its generator function in -@code{rl_completion_entry_function}. - -@item -The generator function is called repeatedly from -@code{rl_completion_matches()}, returning a string each time. The -arguments to the generator function are @var{text} and @var{state}. -@var{text} is the partial word to be completed. @var{state} is zero the -first time the function is called, allowing the generator to perform -any necessary initialization, and a positive non-zero integer for -each subsequent call. The generator function returns -@code{(char *)NULL} to inform @code{rl_completion_matches()} that there are -no more possibilities left. Usually the generator function computes the -list of possible completions when @var{state} is zero, and returns them -one at a time on subsequent calls. Each string the generator function -returns as a match must be allocated with @code{malloc()}; Readline -frees the strings when it has finished with them. -Such a generator function is referred to as an -@dfn{application-specific completion function}. - -@end enumerate - -@deftypefun int rl_complete (int ignore, int invoking_key) -Complete the word at or before point. You have supplied the function -that does the initial simple matching selection algorithm (see -@code{rl_completion_matches()}). The default is to do filename completion. -@end deftypefun - -@deftypevar {rl_compentry_func_t *} rl_completion_entry_function -This is a pointer to the generator function for -@code{rl_completion_matches()}. -If the value of @code{rl_completion_entry_function} is -@code{NULL} then the default filename generator -function, @code{rl_filename_completion_function()}, is used. -An @dfn{application-specific completion function} is a function whose -address is assigned to @code{rl_completion_entry_function} and whose -return values are used to generate possible completions. -@end deftypevar - -@node Completion Functions -@subsection Completion Functions - -Here is the complete list of callable completion functions present in -Readline. - -@deftypefun int rl_complete_internal (int what_to_do) -Complete the word at or before point. @var{what_to_do} says what to do -with the completion. A value of @samp{?} means list the possible -completions. @samp{TAB} means do standard completion. @samp{*} means -insert all of the possible completions. @samp{!} means to display -all of the possible completions, if there is more than one, as well as -performing partial completion. @samp{@@} is similar to @samp{!}, but -possible completions are not listed if the possible completions share -a common prefix. -@end deftypefun - -@deftypefun int rl_complete (int ignore, int invoking_key) -Complete the word at or before point. You have supplied the function -that does the initial simple matching selection algorithm (see -@code{rl_completion_matches()} and @code{rl_completion_entry_function}). -The default is to do filename -completion. This calls @code{rl_complete_internal()} with an -argument depending on @var{invoking_key}. -@end deftypefun - -@deftypefun int rl_possible_completions (int count, int invoking_key) -List the possible completions. See description of @code{rl_complete -()}. This calls @code{rl_complete_internal()} with an argument of -@samp{?}. -@end deftypefun - -@deftypefun int rl_insert_completions (int count, int invoking_key) -Insert the list of possible completions into the line, deleting the -partially-completed word. See description of @code{rl_complete()}. -This calls @code{rl_complete_internal()} with an argument of @samp{*}. -@end deftypefun - -@deftypefun int rl_completion_mode (rl_command_func_t *cfunc) -Returns the apppriate value to pass to @code{rl_complete_internal()} -depending on whether @var{cfunc} was called twice in succession and -the values of the @code{show-all-if-ambiguous} and -@code{show-all-if-unmodified} variables. -Application-specific completion functions may use this function to present -the same interface as @code{rl_complete()}. -@end deftypefun - -@deftypefun {char **} rl_completion_matches (const char *text, rl_compentry_func_t *entry_func) -Returns an array of strings which is a list of completions for -@var{text}. If there are no completions, returns @code{NULL}. -The first entry in the returned array is the substitution for @var{text}. -The remaining entries are the possible completions. The array is -terminated with a @code{NULL} pointer. - -@var{entry_func} is a function of two args, and returns a -@code{char *}. The first argument is @var{text}. The second is a -state argument; it is zero on the first call, and non-zero on subsequent -calls. @var{entry_func} returns a @code{NULL} pointer to the caller -when there are no more matches. -@end deftypefun - -@deftypefun {char *} rl_filename_completion_function (const char *text, int state) -A generator function for filename completion in the general case. -@var{text} is a partial filename. -The Bash source is a useful reference for writing application-specific -completion functions (the Bash completion functions call this and other -Readline functions). -@end deftypefun - -@deftypefun {char *} rl_username_completion_function (const char *text, int state) -A completion generator for usernames. @var{text} contains a partial -username preceded by a random character (usually @samp{~}). As with all -completion generators, @var{state} is zero on the first call and non-zero -for subsequent calls. -@end deftypefun - -@node Completion Variables -@subsection Completion Variables - -@deftypevar {rl_compentry_func_t *} rl_completion_entry_function -A pointer to the generator function for @code{rl_completion_matches()}. -@code{NULL} means to use @code{rl_filename_completion_function()}, -the default filename completer. -@end deftypevar - -@deftypevar {rl_completion_func_t *} rl_attempted_completion_function -A pointer to an alternative function to create matches. -The function is called with @var{text}, @var{start}, and @var{end}. -@var{start} and @var{end} are indices in @code{rl_line_buffer} defining -the boundaries of @var{text}, which is a character string. -If this function exists and returns @code{NULL}, or if this variable is -set to @code{NULL}, then @code{rl_complete()} will call the value of -@code{rl_completion_entry_function} to generate matches, otherwise the -array of strings returned will be used. -If this function sets the @code{rl_attempted_completion_over} -variable to a non-zero value, Readline will not perform its default -completion even if this function returns no matches. -@end deftypevar - -@deftypevar {rl_quote_func_t *} rl_filename_quoting_function -A pointer to a function that will quote a filename in an -application-specific fashion. This is called if filename completion is being -attempted and one of the characters in @code{rl_filename_quote_characters} -appears in a completed filename. The function is called with -@var{text}, @var{match_type}, and @var{quote_pointer}. The @var{text} -is the filename to be quoted. The @var{match_type} is either -@code{SINGLE_MATCH}, if there is only one completion match, or -@code{MULT_MATCH}. Some functions use this to decide whether or not to -insert a closing quote character. The @var{quote_pointer} is a pointer -to any opening quote character the user typed. Some functions choose -to reset this character. -@end deftypevar - -@deftypevar {rl_dequote_func_t *} rl_filename_dequoting_function -A pointer to a function that will remove application-specific quoting -characters from a filename before completion is attempted, so those -characters do not interfere with matching the text against names in -the filesystem. It is called with @var{text}, the text of the word -to be dequoted, and @var{quote_char}, which is the quoting character -that delimits the filename (usually @samp{'} or @samp{"}). If -@var{quote_char} is zero, the filename was not in an embedded string. -@end deftypevar - -@deftypevar {rl_linebuf_func_t *} rl_char_is_quoted_p -A pointer to a function to call that determines whether or not a specific -character in the line buffer is quoted, according to whatever quoting -mechanism the program calling Readline uses. The function is called with -two arguments: @var{text}, the text of the line, and @var{index}, the -index of the character in the line. It is used to decide whether a -character found in @code{rl_completer_word_break_characters} should be -used to break words for the completer. -@end deftypevar - -@deftypevar {rl_compignore_func_t *} rl_ignore_some_completions_function -This function, if defined, is called by the completer when real filename -completion is done, after all the matching names have been generated. -It is passed a @code{NULL} terminated array of matches. -The first element (@code{matches[0]}) is the -maximal substring common to all matches. This function can -re-arrange the list of matches as required, but each element deleted -from the array must be freed. -@end deftypevar - -@deftypevar {rl_icppfunc_t *} rl_directory_completion_hook -This function, if defined, is allowed to modify the directory portion -of filenames Readline completes. It is called with the address of a -string (the current directory name) as an argument, and may modify that string. -If the string is replaced with a new string, the old value should be freed. -Any modified directory name should have a trailing slash. -The modified value will be displayed as part of the completion, replacing -the directory portion of the pathname the user typed. -It returns an integer that should be non-zero if the function modifies -its directory argument. -It could be used to expand symbolic links or shell variables in pathnames. -At the least, even if no other expansion is performed, this function should -remove any quote characters from the directory name, because its result will -be passed directly to @code{opendir()}. -@end deftypevar - -@deftypevar {rl_compdisp_func_t *} rl_completion_display_matches_hook -If non-zero, then this is the address of a function to call when -completing a word would normally display the list of possible matches. -This function is called in lieu of Readline displaying the list. -It takes three arguments: -(@code{char **}@var{matches}, @code{int} @var{num_matches}, @code{int} @var{max_length}) -where @var{matches} is the array of matching strings, -@var{num_matches} is the number of strings in that array, and -@var{max_length} is the length of the longest string in that array. -Readline provides a convenience function, @code{rl_display_match_list}, -that takes care of doing the display to Readline's output stream. That -function may be called from this hook. -@end deftypevar - -@deftypevar {const char *} rl_basic_word_break_characters -The basic list of characters that signal a break between words for the -completer routine. The default value of this variable is the characters -which break words for completion in Bash: -@code{" \t\n\"\\'`@@$><=;|&@{("}. -@end deftypevar - -@deftypevar {const char *} rl_basic_quote_characters -A list of quote characters which can cause a word break. -@end deftypevar - -@deftypevar {const char *} rl_completer_word_break_characters -The list of characters that signal a break between words for -@code{rl_complete_internal()}. The default list is the value of -@code{rl_basic_word_break_characters}. -@end deftypevar - -@deftypevar {rl_cpvfunc_t *} rl_completion_word_break_hook -If non-zero, this is the address of a function to call when Readline is -deciding where to separate words for word completion. It should return -a character string like @code{rl_completer_word_break_characters} to be -used to perform the current completion. The function may choose to set -@code{rl_completer_word_break_characters} itself. If the function -returns @code{NULL}, @code{rl_completer_word_break_characters} is used. -@end deftypevar - -@deftypevar {const char *} rl_completer_quote_characters -A list of characters which can be used to quote a substring of the line. -Completion occurs on the entire substring, and within the substring -@code{rl_completer_word_break_characters} are treated as any other character, -unless they also appear within this list. -@end deftypevar - -@deftypevar {const char *} rl_filename_quote_characters -A list of characters that cause a filename to be quoted by the completer -when they appear in a completed filename. The default is the null string. -@end deftypevar - -@deftypevar {const char *} rl_special_prefixes -The list of characters that are word break characters, but should be -left in @var{text} when it is passed to the completion function. -Programs can use this to help determine what kind of completing to do. -For instance, Bash sets this variable to "$@@" so that it can complete -shell variables and hostnames. -@end deftypevar - -@deftypevar int rl_completion_query_items -Up to this many items will be displayed in response to a -possible-completions call. After that, readline asks the user if she is sure -she wants to see them all. The default value is 100. A negative value -indicates that Readline should never ask the user. -@end deftypevar - -@deftypevar {int} rl_completion_append_character -When a single completion alternative matches at the end of the command -line, this character is appended to the inserted completion text. The -default is a space character (@samp{ }). Setting this to the null -character (@samp{\0}) prevents anything being appended automatically. -This can be changed in application-specific completion functions to -provide the ``most sensible word separator character'' according to -an application-specific command line syntax specification. -@end deftypevar - -@deftypevar int rl_completion_suppress_append -If non-zero, @var{rl_completion_append_character} is not appended to -matches at the end of the command line, as described above. -It is set to 0 before any application-specific completion function -is called, and may only be changed within such a function. -@end deftypevar - -@deftypevar int rl_completion_quote_character -When Readline is completing quoted text, as delimited by one of the -characters in @var{rl_completer_quote_characters}, it sets this variable -to the quoting character found. -This is set before any application-specific completion function is called. -@end deftypevar - -@deftypevar int rl_completion_suppress_quote -If non-zero, Readline does not append a matching quote character when -performing completion on a quoted string. -It is set to 0 before any application-specific completion function -is called, and may only be changed within such a function. -@end deftypevar - -@deftypevar int rl_completion_found_quote -When Readline is completing quoted text, it sets this variable -to a non-zero value if the word being completed contains or is delimited -by any quoting characters, including backslashes. -This is set before any application-specific completion function is called. -@end deftypevar - -@deftypevar int rl_completion_mark_symlink_dirs -If non-zero, a slash will be appended to completed filenames that are -symbolic links to directory names, subject to the value of the -user-settable @var{mark-directories} variable. -This variable exists so that application-specific completion functions -can override the user's global preference (set via the -@var{mark-symlinked-directories} Readline variable) if appropriate. -This variable is set to the user's preference before any -application-specific completion function is called, so unless that -function modifies the value, the user's preferences are honored. -@end deftypevar - -@deftypevar int rl_ignore_completion_duplicates -If non-zero, then duplicates in the matches are removed. -The default is 1. -@end deftypevar - -@deftypevar int rl_filename_completion_desired -Non-zero means that the results of the matches are to be treated as -filenames. This is @emph{always} zero when completion is attempted, -and can only be changed -within an application-specific completion function. If it is set to a -non-zero value by such a function, directory names have a slash appended -and Readline attempts to quote completed filenames if they contain any -characters in @code{rl_filename_quote_characters} and -@code{rl_filename_quoting_desired} is set to a non-zero value. -@end deftypevar - -@deftypevar int rl_filename_quoting_desired -Non-zero means that the results of the matches are to be quoted using -double quotes (or an application-specific quoting mechanism) if the -completed filename contains any characters in -@code{rl_filename_quote_chars}. This is @emph{always} non-zero -when completion is attempted, and can only be changed within an -application-specific completion function. -The quoting is effected via a call to the function pointed to -by @code{rl_filename_quoting_function}. -@end deftypevar - -@deftypevar int rl_attempted_completion_over -If an application-specific completion function assigned to -@code{rl_attempted_completion_function} sets this variable to a non-zero -value, Readline will not perform its default filename completion even -if the application's completion function returns no matches. -It should be set only by an application's completion function. -@end deftypevar - -@deftypevar int rl_sort_completion_matches -If an application sets this variable to 0, Readline will not sort the -list of completions (which implies that it cannot remove any duplicate -completions). The default value is 1, which means that Readline will -sort the completions and, depending on the value of -@code{rl_ignore_completion_duplicates}, will attempt to remove duplicate -matches. -@end deftypevar - -@deftypevar int rl_completion_type -Set to a character describing the type of completion Readline is currently -attempting; see the description of @code{rl_complete_internal()} -(@pxref{Completion Functions}) for the list of characters. -This is set to the appropriate value before any application-specific -completion function is called, allowing such functions to present -the same interface as @code{rl_complete()}. -@end deftypevar - -@deftypevar int rl_completion_invoking_key -Set to the final character in the key sequence that invoked one of the -completion functions that call @code{rl_complete_internal()}. This is -set to the appropriate value before any application-specific completion -function is called. -@end deftypevar - -@deftypevar int rl_inhibit_completion -If this variable is non-zero, completion is inhibited. The completion -character will be inserted as any other bound to @code{self-insert}. -@end deftypevar - -@node A Short Completion Example -@subsection A Short Completion Example - -Here is a small application demonstrating the use of the GNU Readline -library. It is called @code{fileman}, and the source code resides in -@file{examples/fileman.c}. This sample application provides -completion of command names, line editing features, and access to the -history list. - -@page -@smallexample -/* fileman.c -- A tiny application which demonstrates how to use the - GNU Readline library. This application interactively allows users - to manipulate files and their modes. */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#ifdef HAVE_SYS_FILE_H -# include -#endif -#include - -#ifdef HAVE_UNISTD_H -# include -#endif - -#include -#include -#include - -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ - -#ifdef HAVE_STDLIB_H -# include -#endif - -#include - -#include -#include - -extern char *xmalloc PARAMS((size_t)); - -/* The names of functions that actually do the manipulation. */ -int com_list PARAMS((char *)); -int com_view PARAMS((char *)); -int com_rename PARAMS((char *)); -int com_stat PARAMS((char *)); -int com_pwd PARAMS((char *)); -int com_delete PARAMS((char *)); -int com_help PARAMS((char *)); -int com_cd PARAMS((char *)); -int com_quit PARAMS((char *)); - -/* A structure which contains information on the commands this program - can understand. */ - -typedef struct @{ - char *name; /* User printable name of the function. */ - rl_icpfunc_t *func; /* Function to call to do the job. */ - char *doc; /* Documentation for this function. */ -@} COMMAND; - -COMMAND commands[] = @{ - @{ "cd", com_cd, "Change to directory DIR" @}, - @{ "delete", com_delete, "Delete FILE" @}, - @{ "help", com_help, "Display this text" @}, - @{ "?", com_help, "Synonym for `help'" @}, - @{ "list", com_list, "List files in DIR" @}, - @{ "ls", com_list, "Synonym for `list'" @}, - @{ "pwd", com_pwd, "Print the current working directory" @}, - @{ "quit", com_quit, "Quit using Fileman" @}, - @{ "rename", com_rename, "Rename FILE to NEWNAME" @}, - @{ "stat", com_stat, "Print out statistics on FILE" @}, - @{ "view", com_view, "View the contents of FILE" @}, - @{ (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL @} -@}; - -/* Forward declarations. */ -char *stripwhite (); -COMMAND *find_command (); - -/* The name of this program, as taken from argv[0]. */ -char *progname; - -/* When non-zero, this global means the user is done using this program. */ -int done; - -char * -dupstr (s) - char *s; -@{ - char *r; - - r = xmalloc (strlen (s) + 1); - strcpy (r, s); - return (r); -@} - -main (argc, argv) - int argc; - char **argv; -@{ - char *line, *s; - - progname = argv[0]; - - initialize_readline (); /* Bind our completer. */ - - /* Loop reading and executing lines until the user quits. */ - for ( ; done == 0; ) - @{ - line = readline ("FileMan: "); - - if (!line) - break; - - /* Remove leading and trailing whitespace from the line. - Then, if there is anything left, add it to the history list - and execute it. */ - s = stripwhite (line); - - if (*s) - @{ - add_history (s); - execute_line (s); - @} - - free (line); - @} - exit (0); -@} - -/* Execute a command line. */ -int -execute_line (line) - char *line; -@{ - register int i; - COMMAND *command; - char *word; - - /* Isolate the command word. */ - i = 0; - while (line[i] && whitespace (line[i])) - i++; - word = line + i; - - while (line[i] && !whitespace (line[i])) - i++; - - if (line[i]) - line[i++] = '\0'; - - command = find_command (word); - - if (!command) - @{ - fprintf (stderr, "%s: No such command for FileMan.\n", word); - return (-1); - @} - - /* Get argument to command, if any. */ - while (whitespace (line[i])) - i++; - - word = line + i; - - /* Call the function. */ - return ((*(command->func)) (word)); -@} - -/* Look up NAME as the name of a command, and return a pointer to that - command. Return a NULL pointer if NAME isn't a command name. */ -COMMAND * -find_command (name) - char *name; -@{ - register int i; - - for (i = 0; commands[i].name; i++) - if (strcmp (name, commands[i].name) == 0) - return (&commands[i]); - - return ((COMMAND *)NULL); -@} - -/* Strip whitespace from the start and end of STRING. Return a pointer - into STRING. */ -char * -stripwhite (string) - char *string; -@{ - register char *s, *t; - - for (s = string; whitespace (*s); s++) - ; - - if (*s == 0) - return (s); - - t = s + strlen (s) - 1; - while (t > s && whitespace (*t)) - t--; - *++t = '\0'; - - return s; -@} - -/* **************************************************************** */ -/* */ -/* Interface to Readline Completion */ -/* */ -/* **************************************************************** */ - -char *command_generator PARAMS((const char *, int)); -char **fileman_completion PARAMS((const char *, int, int)); - -/* Tell the GNU Readline library how to complete. We want to try to complete - on command names if this is the first word in the line, or on filenames - if not. */ -initialize_readline () -@{ - /* Allow conditional parsing of the ~/.inputrc file. */ - rl_readline_name = "FileMan"; - - /* Tell the completer that we want a crack first. */ - rl_attempted_completion_function = fileman_completion; -@} - -/* Attempt to complete on the contents of TEXT. START and END bound the - region of rl_line_buffer that contains the word to complete. TEXT is - the word to complete. We can use the entire contents of rl_line_buffer - in case we want to do some simple parsing. Return the array of matches, - or NULL if there aren't any. */ -char ** -fileman_completion (text, start, end) - const char *text; - int start, end; -@{ - char **matches; - - matches = (char **)NULL; - - /* If this word is at the start of the line, then it is a command - to complete. Otherwise it is the name of a file in the current - directory. */ - if (start == 0) - matches = rl_completion_matches (text, command_generator); - - return (matches); -@} - -/* Generator function for command completion. STATE lets us know whether - to start from scratch; without any state (i.e. STATE == 0), then we - start at the top of the list. */ -char * -command_generator (text, state) - const char *text; - int state; -@{ - static int list_index, len; - char *name; - - /* If this is a new word to complete, initialize now. This includes - saving the length of TEXT for efficiency, and initializing the index - variable to 0. */ - if (!state) - @{ - list_index = 0; - len = strlen (text); - @} - - /* Return the next name which partially matches from the command list. */ - while (name = commands[list_index].name) - @{ - list_index++; - - if (strncmp (name, text, len) == 0) - return (dupstr(name)); - @} - - /* If no names matched, then return NULL. */ - return ((char *)NULL); -@} - -/* **************************************************************** */ -/* */ -/* FileMan Commands */ -/* */ -/* **************************************************************** */ - -/* String to pass to system (). This is for the LIST, VIEW and RENAME - commands. */ -static char syscom[1024]; - -/* List the file(s) named in arg. */ -com_list (arg) - char *arg; -@{ - if (!arg) - arg = ""; - - sprintf (syscom, "ls -FClg %s", arg); - return (system (syscom)); -@} - -com_view (arg) - char *arg; -@{ - if (!valid_argument ("view", arg)) - return 1; - -#if defined (__MSDOS__) - /* more.com doesn't grok slashes in pathnames */ - sprintf (syscom, "less %s", arg); -#else - sprintf (syscom, "more %s", arg); -#endif - return (system (syscom)); -@} - -com_rename (arg) - char *arg; -@{ - too_dangerous ("rename"); - return (1); -@} - -com_stat (arg) - char *arg; -@{ - struct stat finfo; - - if (!valid_argument ("stat", arg)) - return (1); - - if (stat (arg, &finfo) == -1) - @{ - perror (arg); - return (1); - @} - - printf ("Statistics for `%s':\n", arg); - - printf ("%s has %d link%s, and is %d byte%s in length.\n", - arg, - finfo.st_nlink, - (finfo.st_nlink == 1) ? "" : "s", - finfo.st_size, - (finfo.st_size == 1) ? "" : "s"); - printf ("Inode Last Change at: %s", ctime (&finfo.st_ctime)); - printf (" Last access at: %s", ctime (&finfo.st_atime)); - printf (" Last modified at: %s", ctime (&finfo.st_mtime)); - return (0); -@} - -com_delete (arg) - char *arg; -@{ - too_dangerous ("delete"); - return (1); -@} - -/* Print out help for ARG, or for all of the commands if ARG is - not present. */ -com_help (arg) - char *arg; -@{ - register int i; - int printed = 0; - - for (i = 0; commands[i].name; i++) - @{ - if (!*arg || (strcmp (arg, commands[i].name) == 0)) - @{ - printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc); - printed++; - @} - @} - - if (!printed) - @{ - printf ("No commands match `%s'. Possibilties are:\n", arg); - - for (i = 0; commands[i].name; i++) - @{ - /* Print in six columns. */ - if (printed == 6) - @{ - printed = 0; - printf ("\n"); - @} - - printf ("%s\t", commands[i].name); - printed++; - @} - - if (printed) - printf ("\n"); - @} - return (0); -@} - -/* Change to the directory ARG. */ -com_cd (arg) - char *arg; -@{ - if (chdir (arg) == -1) - @{ - perror (arg); - return 1; - @} - - com_pwd (""); - return (0); -@} - -/* Print out the current working directory. */ -com_pwd (ignore) - char *ignore; -@{ - char dir[1024], *s; - - s = getcwd (dir, sizeof(dir) - 1); - if (s == 0) - @{ - printf ("Error getting pwd: %s\n", dir); - return 1; - @} - - printf ("Current directory is %s\n", dir); - return 0; -@} - -/* The user wishes to quit using this program. Just set DONE non-zero. */ -com_quit (arg) - char *arg; -@{ - done = 1; - return (0); -@} - -/* Function which tells you that you can't do this. */ -too_dangerous (caller) - char *caller; -@{ - fprintf (stderr, - "%s: Too dangerous for me to distribute. Write it yourself.\n", - caller); -@} - -/* Return non-zero if ARG is a valid argument for CALLER, else print - an error message and return zero. */ -int -valid_argument (caller, arg) - char *caller, *arg; -@{ - if (!arg || !*arg) - @{ - fprintf (stderr, "%s: Argument required.\n", caller); - return (0); - @} - - return (1); -@} -@end smallexample diff --git a/lib/readline/doc/rluser.texi~ b/lib/readline/doc/rluser.texi~ deleted file mode 100644 index e5fe03b08..000000000 --- a/lib/readline/doc/rluser.texi~ +++ /dev/null @@ -1,1901 +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.) - -@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--2008 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. -Command line editing is enabled by default when using an interactive shell, -unless the @option{--noediting} option is supplied at shell invocation. -Line editing is also used when using the @option{-e} option to the -@code{read} builtin command (@pxref{Bash Builtins}). -By default, the line editing commands are similar to those of emacs. -A vi-style line editing interface is also available. -@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}. If that -file does not exist or cannot be read, the ultimate default is -@file{/etc/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. Unrecognized variable names are ignored. - -Boolean variables (those that can be set to on or off) are set to on if -the value is null or empty, @var{on} (case-insensitive), or 1. Any other -value results in the variable being set to off. - -@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 bind-tty-special-chars -@vindex bind-tty-special-chars -If set to @samp{on}, Readline attempts to bind the control characters -treated specially by the kernel's terminal driver to their Readline -equivalents. - -@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-prefix-display-length -@vindex completion-prefix-display-length -The length in characters of the common prefix of a list of possible -completions that is displayed without modification. When set to a -value greater than zero, common prefixes longer than this value are -replaced with an ellipsis when displaying possible completions. - -@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. -A negative value means Readline should never ask. -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}. - -@item history-preserve-point -@vindex history-preserve-point -If set to @samp{on}, the history code attempts to place the point (the -current cursor position) at the -same location on each history line retrieved with @code{previous-history} -or @code{next-history}. The default is @samp{off}. - -@item history-size -@vindex history-size -Set the maximum number of history entries saved in the history list. If -set to zero, the number of entries in the history list is not limited. - -@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 revert-all-at-newline -@vindex revert-all-at-newline -If set to @samp{on}, Readline will undo all changes to history lines -before returning when @code{accept-line} is executed. By default, -history lines may be modified and retain individual undo lists across -calls to @code{readline}. 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. -There can be no space between the key name and the colon -- that will be -interpreted as part of the key name. -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. -Once the argument @var{n} is computed, the argument is extracted -as if the @samp{!@var{n}} history expansion had been specified. - -@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. -The history expansion facilities are used to extract the last argument, -as if the @samp{!$} history expansion had been specified. - -@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 dabbrev-expand () -Attempt menu 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{$VISUAL}, @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, and arithmetic 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}, -@env{COMP_POINT}, @env{COMP_KEY}, and @env{COMP_TYPE} 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} and @code{compopt} builtins 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}] [-E] [-A @var{action}] [-G @var{globpat}] [-W @var{wordlist}] -[-F @var{function}] [-C @var{command}] [-X @var{filterpat}] -[-P @var{prefix}] [-S @var{suffix}] @var{name} [@var{name} @dots{}]} -@code{complete -pr [-E] [@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 @option{-E} option indicates that the remaining options and actions should -apply to ``empty'' command completion; that is, completion attempted on a -blank line. - -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. - -@item plusdirs -After any matches defined by the compspec are generated, -directory name completion is attempted and any -matches are added to the results of the other actions. - -@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. - -@item compopt -@btindex compopt -@example -@code{compopt} [-o @var{option}] [+o @var{option}] [@var{name}] -@end example -Modify completion options for each @var{name} according to the -@var{option}s, or for the currently-execution completion if no @var{name}s -are supplied. -If no @var{option}s are given, display the completion options for each -@var{name} or the current completion. -The possible values of @var{option} are those valid for the @code{complete} -builtin described above. - -The return value is true unless an invalid option is supplied, an attempt -is made to modify the options for a @var{name} for which no completion -specification exists, or an output error occurs. - -@end table - -@end ifset diff --git a/lib/readline/doc/rluserman.texi~ b/lib/readline/doc/rluserman.texi~ deleted file mode 100644 index 894292b35..000000000 --- a/lib/readline/doc/rluserman.texi~ +++ /dev/null @@ -1,88 +0,0 @@ -\input texinfo @c -*-texinfo-*- -@comment %**start of header (This is for running Texinfo on a region.) -@setfilename rluserman.info -@settitle GNU Readline Library -@comment %**end of header (This is for running Texinfo on a region.) - -@setchapternewpage odd - -@include version.texi - -@copying -This manual describes the end user interface of the GNU Readline Library -(version @value{VERSION}, @value{UPDATED}), a library which aids in the -consistency of user interface across discrete programs which provide -a command line interface. - -Copyright @copyright{} 1988--2007 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.2 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 are free to copy and modify -this GNU Manual. Buying copies from GNU Press supports the FSF in -developing GNU and promoting software freedom.'' -@end quotation -@end copying - -@dircategory Libraries -@direntry -* RLuserman: (rluserman). The GNU readline library User's Manual. -@end direntry - -@titlepage -@title GNU Readline Library User Interface -@subtitle Edition @value{EDITION}, for @code{Readline Library} 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 -@top GNU Readline Library - -This document describes the end user interface of the GNU Readline Library, -a utility which aids in the consistency of user interface across discrete -programs which provide a command line interface. - -@menu -* Command Line Editing:: GNU Readline User's Manual. -* Copying This Manual:: Copying This Manual. -@end menu -@end ifnottex - -@include rluser.texi - -@node Copying This Manual -@appendix Copying This Manual - -@menu -* GNU Free Documentation License:: License for copying this manual. -@end menu - -@include fdl.texi - -@bye diff --git a/lib/readline/doc/version.texi~ b/lib/readline/doc/version.texi~ deleted file mode 100644 index 0d5c5693b..000000000 --- a/lib/readline/doc/version.texi~ +++ /dev/null @@ -1,10 +0,0 @@ -@ignore -Copyright (C) 1988-2008 Free Software Foundation, Inc. -@end ignore - -@set EDITION 6.0 -@set VERSION 6.0 -@set UPDATED 12 August 2008 -@set UPDATED-MONTH August 2008 - -@set LASTCHANGE Tue Aug 12 16:41:31 EDT 2008 diff --git a/lib/readline/funmap.c~ b/lib/readline/funmap.c~ deleted file mode 100644 index 9c760cc34..000000000 --- a/lib/readline/funmap.c~ +++ /dev/null @@ -1,255 +0,0 @@ -/* funmap.c -- attach names to functions. */ - -/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 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 (BUFSIZ) -#include -#endif /* BUFSIZ */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#include "rlconf.h" -#include "readline.h" - -#include "xmalloc.h" - -#ifdef __STDC__ -typedef int QSFUNC (const void *, const void *); -#else -typedef int QSFUNC (); -#endif - -extern int _rl_qsort_string_compare PARAMS((char **, char **)); - -FUNMAP **funmap; -static int funmap_size; -static int funmap_entry; - -/* After initializing the function map, this is the index of the first - program specific function. */ -int funmap_program_specific_entry_start; - -static FUNMAP default_funmap[] = { - { "abort", rl_abort }, - { "accept-line", rl_newline }, - { "arrow-key-prefix", rl_arrow_keys }, - { "backward-byte", rl_backward_byte }, - { "backward-char", rl_backward_char }, - { "backward-delete-char", rl_rubout }, - { "backward-kill-line", rl_backward_kill_line }, - { "backward-kill-word", rl_backward_kill_word }, - { "backward-word", rl_backward_word }, - { "beginning-of-history", rl_beginning_of_history }, - { "beginning-of-line", rl_beg_of_line }, - { "call-last-kbd-macro", rl_call_last_kbd_macro }, - { "capitalize-word", rl_capitalize_word }, - { "character-search", rl_char_search }, - { "character-search-backward", rl_backward_char_search }, - { "clear-screen", rl_clear_screen }, - { "complete", rl_complete }, - { "copy-backward-word", rl_copy_backward_word }, - { "copy-forward-word", rl_copy_forward_word }, - { "copy-region-as-kill", rl_copy_region_to_kill }, - { "delete-char", rl_delete }, - { "delete-char-or-list", rl_delete_or_show_completions }, - { "delete-horizontal-space", rl_delete_horizontal_space }, - { "digit-argument", rl_digit_argument }, - { "do-lowercase-version", rl_do_lowercase_version }, - { "downcase-word", rl_downcase_word }, - { "dump-functions", rl_dump_functions }, - { "dump-macros", rl_dump_macros }, - { "dump-variables", rl_dump_variables }, - { "emacs-editing-mode", rl_emacs_editing_mode }, - { "end-kbd-macro", rl_end_kbd_macro }, - { "end-of-history", rl_end_of_history }, - { "end-of-line", rl_end_of_line }, - { "exchange-point-and-mark", rl_exchange_point_and_mark }, - { "forward-backward-delete-char", rl_rubout_or_delete }, - { "forward-byte", rl_forward_byte }, - { "forward-char", rl_forward_char }, - { "forward-search-history", rl_forward_search_history }, - { "forward-word", rl_forward_word }, - { "history-search-backward", rl_history_search_backward }, - { "history-search-forward", rl_history_search_forward }, - { "insert-comment", rl_insert_comment }, - { "insert-completions", rl_insert_completions }, - { "kill-whole-line", rl_kill_full_line }, - { "kill-line", rl_kill_line }, - { "kill-region", rl_kill_region }, - { "kill-word", rl_kill_word }, - { "menu-complete", rl_menu_complete }, - { "next-history", rl_get_next_history }, - { "non-incremental-forward-search-history", rl_noninc_forward_search }, - { "non-incremental-reverse-search-history", rl_noninc_reverse_search }, - { "non-incremental-forward-search-history-again", rl_noninc_forward_search_again }, - { "non-incremental-reverse-search-history-again", rl_noninc_reverse_search_again }, - { "overwrite-mode", rl_overwrite_mode }, -#ifdef __CYGWIN__ - { "paste-from-clipboard", rl_paste_from_clipboard }, -#endif - { "possible-completions", rl_possible_completions }, - { "previous-history", rl_get_previous_history }, - { "quoted-insert", rl_quoted_insert }, - { "re-read-init-file", rl_re_read_init_file }, - { "redraw-current-line", rl_refresh_line}, - { "reverse-search-history", rl_reverse_search_history }, - { "revert-line", rl_revert_line }, - { "self-insert", rl_insert }, - { "set-mark", rl_set_mark }, - { "start-kbd-macro", rl_start_kbd_macro }, - { "tab-insert", rl_tab_insert }, - { "tilde-expand", rl_tilde_expand }, - { "transpose-chars", rl_transpose_chars }, - { "transpose-words", rl_transpose_words }, - { "tty-status", rl_tty_status }, - { "undo", rl_undo_command }, - { "universal-argument", rl_universal_argument }, - { "unix-filename-rubout", rl_unix_filename_rubout }, - { "unix-line-discard", rl_unix_line_discard }, - { "unix-word-rubout", rl_unix_word_rubout }, - { "upcase-word", rl_upcase_word }, - { "yank", rl_yank }, - { "yank-last-arg", rl_yank_last_arg }, - { "yank-nth-arg", rl_yank_nth_arg }, - { "yank-pop", rl_yank_pop }, - -#if defined (VI_MODE) - { "vi-append-eol", rl_vi_append_eol }, - { "vi-append-mode", rl_vi_append_mode }, - { "vi-arg-digit", rl_vi_arg_digit }, - { "vi-back-to-indent", rl_vi_back_to_indent }, - { "vi-bWord", rl_vi_bWord }, - { "vi-bword", rl_vi_bword }, - { "vi-change-case", rl_vi_change_case }, - { "vi-change-char", rl_vi_change_char }, - { "vi-change-to", rl_vi_change_to }, - { "vi-char-search", rl_vi_char_search }, - { "vi-column", rl_vi_column }, - { "vi-complete", rl_vi_complete }, - { "vi-delete", rl_vi_delete }, - { "vi-delete-to", rl_vi_delete_to }, - { "vi-eWord", rl_vi_eWord }, - { "vi-editing-mode", rl_vi_editing_mode }, - { "vi-end-word", rl_vi_end_word }, - { "vi-eof-maybe", rl_vi_eof_maybe }, - { "vi-eword", rl_vi_eword }, - { "vi-fWord", rl_vi_fWord }, - { "vi-fetch-history", rl_vi_fetch_history }, - { "vi-first-print", rl_vi_first_print }, - { "vi-fword", rl_vi_fword }, - { "vi-goto-mark", rl_vi_goto_mark }, - { "vi-insert-beg", rl_vi_insert_beg }, - { "vi-insertion-mode", rl_vi_insertion_mode }, - { "vi-match", rl_vi_match }, - { "vi-movement-mode", rl_vi_movement_mode }, - { "vi-next-word", rl_vi_next_word }, - { "vi-overstrike", rl_vi_overstrike }, - { "vi-overstrike-delete", rl_vi_overstrike_delete }, - { "vi-prev-word", rl_vi_prev_word }, - { "vi-put", rl_vi_put }, - { "vi-redo", rl_vi_redo }, - { "vi-replace", rl_vi_replace }, - { "vi-rubout", rl_vi_rubout }, - { "vi-search", rl_vi_search }, - { "vi-search-again", rl_vi_search_again }, - { "vi-set-mark", rl_vi_set_mark }, - { "vi-subst", rl_vi_subst }, - { "vi-tilde-expand", rl_vi_tilde_expand }, - { "vi-yank-arg", rl_vi_yank_arg }, - { "vi-yank-to", rl_vi_yank_to }, -#endif /* VI_MODE */ - - {(char *)NULL, (rl_command_func_t *)NULL } -}; - -int -rl_add_funmap_entry (name, function) - const char *name; - rl_command_func_t *function; -{ - if (funmap_entry + 2 >= funmap_size) - { - funmap_size += 64; - funmap = (FUNMAP **)xrealloc (funmap, funmap_size * sizeof (FUNMAP *)); - } - - funmap[funmap_entry] = (FUNMAP *)xmalloc (sizeof (FUNMAP)); - funmap[funmap_entry]->name = name; - funmap[funmap_entry]->function = function; - - funmap[++funmap_entry] = (FUNMAP *)NULL; - return funmap_entry; -} - -static int funmap_initialized; - -/* Make the funmap contain all of the default entries. */ -void -rl_initialize_funmap () -{ - register int i; - - if (funmap_initialized) - return; - - for (i = 0; default_funmap[i].name; i++) - rl_add_funmap_entry (default_funmap[i].name, default_funmap[i].function); - - funmap_initialized = 1; - funmap_program_specific_entry_start = i; -} - -/* Produce a NULL terminated array of known function names. The array - is sorted. The array itself is allocated, but not the strings inside. - You should free () the array when you done, but not the pointrs. */ -const char ** -rl_funmap_names () -{ - const char **result; - int result_size, result_index; - - /* Make sure that the function map has been initialized. */ - rl_initialize_funmap (); - - for (result_index = result_size = 0, result = (const char **)NULL; funmap[result_index]; result_index++) - { - if (result_index + 2 > result_size) - { - result_size += 20; - result = (const char **)xrealloc (result, result_size * sizeof (char *)); - } - - result[result_index] = funmap[result_index]->name; - result[result_index + 1] = (char *)NULL; - } - - qsort (result, result_index, sizeof (char *), (QSFUNC *)_rl_qsort_string_compare); - return (result); -} diff --git a/lib/readline/histfile.c~ b/lib/readline/histfile.c~ deleted file mode 100644 index 5a782908d..000000000 --- a/lib/readline/histfile.c~ +++ /dev/null @@ -1,546 +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. */ - -#define READLINE_LIBRARY - -#if defined (__TANDEM) -# include -#endif - -#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__) -# 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') - { - /* Change to allow Windows-like \r\n end of line delimiter. */ - if (line_end > line_start && line_end[-1] == '\r') - line_end[-1] = '\0'; - else - *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/history.c~ b/lib/readline/history.c~ deleted file mode 100644 index f5d1201fe..000000000 --- a/lib/readline/history.c~ +++ /dev/null @@ -1,519 +0,0 @@ -/* history.c -- standalone history library */ - -/* Copyright (C) 1989-2008 Free Software Foundation, Inc. - - This file contains the GNU History Library (History), a set of - routines for managing the text of previously typed lines. - - History is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - History is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with History. If not, see . -*/ - -/* The goal is to make the implementation transparent, so that you - don't have to know what data types are used, just what functions - you can call. I think I have done that. */ -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include "history.h" -#include "histlib.h" - -#include "xmalloc.h" - -/* The number of slots to increase the_history by. */ -#define DEFAULT_HISTORY_GROW_SIZE 50 - -static char *hist_inittime PARAMS((void)); - -/* **************************************************************** */ -/* */ -/* History Functions */ -/* */ -/* **************************************************************** */ - -/* An array of HIST_ENTRY. This is where we store the history. */ -static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL; - -/* Non-zero means that we have enforced a limit on the amount of - history that we save. */ -static int history_stifled; - -/* The current number of slots allocated to the input_history. */ -static int history_size; - -/* If HISTORY_STIFLED is non-zero, then this is the maximum number of - entries to remember. */ -int history_max_entries; -int max_input_history; /* backwards compatibility */ - -/* The current location of the interactive history pointer. Just makes - life easier for outside callers. */ -int history_offset; - -/* The number of strings currently stored in the history list. */ -int history_length; - -/* The logical `base' of the history array. It defaults to 1. */ -int history_base = 1; - -/* Return the current HISTORY_STATE of the history. */ -HISTORY_STATE * -history_get_history_state () -{ - HISTORY_STATE *state; - - state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE)); - state->entries = the_history; - state->offset = history_offset; - state->length = history_length; - state->size = history_size; - state->flags = 0; - if (history_stifled) - state->flags |= HS_STIFLED; - - return (state); -} - -/* Set the state of the current history array to STATE. */ -void -history_set_history_state (state) - HISTORY_STATE *state; -{ - the_history = state->entries; - history_offset = state->offset; - history_length = state->length; - history_size = state->size; - if (state->flags & HS_STIFLED) - history_stifled = 1; -} - -/* Begin a session in which the history functions might be used. This - initializes interactive variables. */ -void -using_history () -{ - history_offset = history_length; -} - -/* Return the number of bytes that the primary history entries are using. - This just adds up the lengths of the_history->lines and the associated - timestamps. */ -int -history_total_bytes () -{ - register int i, result; - - for (i = result = 0; the_history && the_history[i]; i++) - result += HISTENT_BYTES (the_history[i]); - - return (result); -} - -/* Returns the magic number which says what history element we are - looking at now. In this implementation, it returns history_offset. */ -int -where_history () -{ - return (history_offset); -} - -/* Make the current history item be the one at POS, an absolute index. - Returns zero if POS is out of range, else non-zero. */ -int -history_set_pos (pos) - int pos; -{ - if (pos > history_length || pos < 0 || !the_history) - return (0); - history_offset = pos; - return (1); -} - -/* Return the current history array. The caller has to be careful, since this - is the actual array of data, and could be bashed or made corrupt easily. - The array is terminated with a NULL pointer. */ -HIST_ENTRY ** -history_list () -{ - return (the_history); -} - -/* Return the history entry at the current position, as determined by - history_offset. If there is no entry there, return a NULL pointer. */ -HIST_ENTRY * -current_history () -{ - return ((history_offset == history_length) || the_history == 0) - ? (HIST_ENTRY *)NULL - : the_history[history_offset]; -} - -/* Back up history_offset to the previous history entry, and return - a pointer to that entry. If there is no previous entry then return - a NULL pointer. */ -HIST_ENTRY * -previous_history () -{ - return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL; -} - -/* Move history_offset forward to the next history entry, and return - a pointer to that entry. If there is no next entry then return a - NULL pointer. */ -HIST_ENTRY * -next_history () -{ - return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset]; -} - -/* Return the history entry which is logically at OFFSET in the history array. - OFFSET is relative to history_base. */ -HIST_ENTRY * -history_get (offset) - int offset; -{ - int local_index; - - local_index = offset - history_base; - return (local_index >= history_length || local_index < 0 || the_history == 0) - ? (HIST_ENTRY *)NULL - : the_history[local_index]; -} - -HIST_ENTRY * -alloc_history_entry (string, ts) - char *string; - char *ts; -{ - HIST_ENTRY *temp; - - temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); - - temp->line = string ? savestring (string) : string; - temp->data = (char *)NULL; - temp->timestamp = ts; - - return temp; -} - -time_t -history_get_time (hist) - HIST_ENTRY *hist; -{ - char *ts; - time_t t; - - if (hist == 0 || hist->timestamp == 0) - return 0; - ts = hist->timestamp; - if (ts[0] != history_comment_char) - return 0; - t = (time_t) atol (ts + 1); /* XXX - should use strtol() here */ - return t; -} - -static char * -hist_inittime () -{ - time_t t; - char ts[64], *ret; - - t = (time_t) time ((time_t *)0); -#if defined (HAVE_VSNPRINTF) /* assume snprintf if vsnprintf exists */ - snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t); -#else - sprintf (ts, "X%lu", (unsigned long) t); -#endif - ret = savestring (ts); - ret[0] = history_comment_char; - - return ret; -} - -/* Place STRING at the end of the history list. The data field - is set to NULL. */ -void -add_history (string) - const char *string; -{ - HIST_ENTRY *temp; - - if (history_stifled && (history_length == history_max_entries)) - { - register int i; - - /* If the history is stifled, and history_length is zero, - and it equals history_max_entries, we don't save items. */ - if (history_length == 0) - return; - - /* If there is something in the slot, then remove it. */ - if (the_history[0]) - (void) free_history_entry (the_history[0]); - - /* Copy the rest of the entries, moving down one slot. */ - for (i = 0; i < history_length; i++) - the_history[i] = the_history[i + 1]; - - history_base++; - } - else - { - if (history_size == 0) - { - history_size = DEFAULT_HISTORY_GROW_SIZE; - the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *)); - history_length = 1; - } - else - { - if (history_length == (history_size - 1)) - { - history_size += DEFAULT_HISTORY_GROW_SIZE; - the_history = (HIST_ENTRY **) - xrealloc (the_history, history_size * sizeof (HIST_ENTRY *)); - } - history_length++; - } - } - - temp = alloc_history_entry (string, hist_inittime ()); - - the_history[history_length] = (HIST_ENTRY *)NULL; - the_history[history_length - 1] = temp; -} - -/* Change the time stamp of the most recent history entry to STRING. */ -void -add_history_time (string) - const char *string; -{ - HIST_ENTRY *hs; - - if (string == 0) - return; - hs = the_history[history_length - 1]; - FREE (hs->timestamp); - hs->timestamp = savestring (string); -} - -/* Free HIST and return the data so the calling application can free it - if necessary and desired. */ -histdata_t -free_history_entry (hist) - HIST_ENTRY *hist; -{ - histdata_t x; - - if (hist == 0) - return ((histdata_t) 0); - FREE (hist->line); - FREE (hist->timestamp); - x = hist->data; - free (hist); - return (x); -} - -HIST_ENTRY * -copy_history_entry (hist) - HIST_ENTRY *hist; -{ - HIST_ENTRY *ret; - char *ts; - - if (hist == 0) - return hist; - - ret = alloc_history_entry (hist->line, (char *)NULL); - - ts = hist->timestamp ? savestring (hist->timestamp) : hist->timestamp; - ret->timestamp = ts; - - ret->data = hist->data; - - return ret; -} - -/* Make the history entry at WHICH have LINE and DATA. This returns - the old entry so you can dispose of the data. In the case of an - invalid WHICH, a NULL pointer is returned. */ -HIST_ENTRY * -replace_history_entry (which, line, data) - int which; - const char *line; - histdata_t data; -{ - HIST_ENTRY *temp, *old_value; - - if (which < 0 || which >= history_length) - return ((HIST_ENTRY *)NULL); - - temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); - old_value = the_history[which]; - - temp->line = savestring (line); - temp->data = data; - temp->timestamp = savestring (old_value->timestamp); - the_history[which] = temp; - - return (old_value); -} - -/* Replace the DATA in the specified history entries, replacing OLD with - NEW. WHICH says which one(s) to replace: WHICH == -1 means to replace - all of the history entries where entry->data == OLD; WHICH == -2 means - to replace the `newest' history entry where entry->data == OLD; and - WHICH >= 0 means to replace that particular history entry's data, as - long as it matches OLD. */ -void -replace_history_data (which,old, new) - int which; - histdata_t *old, *new; -{ - HIST_ENTRY *entry; - register int i, last; - - if (which < -2 || which >= history_length || history_length == 0 || the_history == 0) - return; - - if (which >= 0) - { - entry = the_history[which]; - if (entry && entry->data == old) - entry->data = new; - return; - } - - last = -1; - for (i = 0; i < history_length; i++) - { - entry = the_history[i]; - if (entry == 0) - continue; - if (entry->data == old) - { - last = i; - if (which == -1) - entry->data = new; - } - } - if (which == -2 && last >= 0) - { - entry = the_history[last]; - entry->data = new; /* XXX - we don't check entry->old */ - } -} - -/* Remove history element WHICH from the history. The removed - element is returned to you so you can free the line, data, - and containing structure. */ -HIST_ENTRY * -remove_history (which) - int which; -{ - HIST_ENTRY *return_value; - register int i; - - if (which < 0 || which >= history_length || history_length == 0 || the_history == 0) - return ((HIST_ENTRY *)NULL); - - return_value = the_history[which]; - - for (i = which; i < history_length; i++) - the_history[i] = the_history[i + 1]; - - history_length--; - - return (return_value); -} - -/* Stifle the history list, remembering only MAX number of lines. */ -void -stifle_history (max) - int max; -{ - register int i, j; - - if (max < 0) - max = 0; - - if (history_length > max) - { - /* This loses because we cannot free the data. */ - for (i = 0, j = history_length - max; i < j; i++) - free_history_entry (the_history[i]); - - history_base = i; - for (j = 0, i = history_length - max; j < max; i++, j++) - the_history[j] = the_history[i]; - the_history[j] = (HIST_ENTRY *)NULL; - history_length = j; - } - - history_stifled = 1; - max_input_history = history_max_entries = max; -} - -/* Stop stifling the history. This returns the previous maximum - number of history entries. The value is positive if the history - was stifled, negative if it wasn't. */ -int -unstifle_history () -{ - if (history_stifled) - { - history_stifled = 0; - return (history_max_entries); - } - else - return (-history_max_entries); -} - -int -history_is_stifled () -{ - return (history_stifled); -} - -void -clear_history () -{ - register int i; - - /* This loses because we cannot free the data. */ - for (i = 0; i < history_length; i++) - { - free_history_entry (the_history[i]); - the_history[i] = (HIST_ENTRY *)NULL; - } - - history_offset = history_length = 0; -} diff --git a/lib/readline/input.c~ b/lib/readline/input.c~ deleted file mode 100644 index 4463e84f8..000000000 --- a/lib/readline/input.c~ +++ /dev/null @@ -1,600 +0,0 @@ -/* input.c -- character input functions for readline. */ - -/* Copyright (C) 1994-2009 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (__TANDEM) -# include -#endif - -#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 0 - if (pop_index >= ibuffer_len) -#else - if (pop_index > ibuffer_len) -#endif - 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; - 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 - - chars_avail = 0; - tty = fileno (rl_instream); - -#if defined (HAVE_SELECT) - FD_ZERO (&readfds); - FD_ZERO (&exceptfds); - FD_SET (tty, &readfds); - FD_SET (tty, &exceptfds); - timeout.tv_sec = 0; - timeout.tv_usec = _keyboard_input_timeout; - result = select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout); - if (result <= 0) - return 0; /* Nothing to read. */ -#endif - - result = -1; -#if defined (FIONREAD) - errno = 0; - result = ioctl (tty, FIONREAD, &chars_avail); - if (result == -1 && errno == EIO) - return -1; -#endif - -#if defined (O_NDELAY) - if (result == -1) - { - tem = fcntl (tty, F_GETFL, 0); - - fcntl (tty, F_SETFL, (tem | O_NDELAY)); - chars_avail = read (tty, &input, 1); - - fcntl (tty, F_SETFL, tem); - if (chars_avail == -1 && errno == EAGAIN) - return 0; - if (chars_avail == 0) /* EOF */ - { - rl_stuff_char (EOF); - return (0); - } - } -#endif /* O_NDELAY */ - -#if defined (__MINGW32__) - /* Use getch/_kbhit to check for available console input, in the same way - that we read it normally. */ - chars_avail = isatty (tty) ? _kbhit () : 0; - result = 0; -#endif - - /* 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--) - { - RL_CHECK_SIGNALS (); - k = (*rl_getc_function) (rl_instream); - if (rl_stuff_char (k) == 0) - break; /* some problem; no more room */ - 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 - -#if defined (__MINGW32__) - if (isatty (tty)) - return (_kbhit ()); -#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); - xfree (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 0 - if (push_index >= ibuffer_len) -#else - if (push_index > ibuffer_len) -#endif - 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) - { - RL_CHECK_SIGNALS (); - -#if defined (__MINGW32__) - if (isatty (fileno (stream))) - return (getch ()); -#endif - result = read (fileno (stream), &c, sizeof (unsigned char)); - - if (result == sizeof (unsigned char)) - return (c); - - /* If zero characters are returned, then the file that we are - reading from is empty! Return EOF in that case. */ - if (result == 0) - return (EOF); - -#if defined (__BEOS__) - if (errno == EINTR) - continue; -#endif - -#if defined (EWOULDBLOCK) -# define X_EWOULDBLOCK EWOULDBLOCK -#else -# define X_EWOULDBLOCK -99 -#endif - -#if defined (EAGAIN) -# define X_EAGAIN EAGAIN -#else -# define X_EAGAIN -99 -#endif - - if (errno == X_EWOULDBLOCK || errno == X_EAGAIN) - { - if (sh_unset_nodelay_mode (fileno (stream)) < 0) - return (EOF); - continue; - } - -#undef X_EWOULDBLOCK -#undef X_EAGAIN - - /* If the error that we received was SIGINT, then try again, - this is simply an interrupted system call to read (). - Otherwise, some error ocurred, also signifying EOF. */ - if (errno != EINTR) - return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF); - } -} - -#if defined (HANDLE_MULTIBYTE) -/* read multibyte char */ -int -_rl_read_mbchar (mbchar, size) - char *mbchar; - int size; -{ - int mb_len, c; - 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)); - - mb_len = 0; - while (mb_len < size) - { - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (c < 0) - break; - - mbchar[mb_len++] = c; - - mbchar_bytes_length = mbrtowc (&wc, mbchar, mb_len, &ps); - if (mbchar_bytes_length == (size_t)(-1)) - break; /* invalid byte sequence for the current locale */ - else if (mbchar_bytes_length == (size_t)(-2)) - { - /* shorted bytes */ - ps = ps_back; - continue; - } - else if (mbchar_bytes_length == 0) - { - mbchar[0] = '\0'; /* null wide character */ - mb_len = 1; - break; - } - else if (mbchar_bytes_length > (size_t)(0)) - break; - } - - return mb_len; -} - -/* Read a multibyte-character string whose first character is FIRST into - the buffer MB of length MLEN. 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, mlen) - int first; - char *mb; - int mlen; -{ - int i, c; - mbstate_t ps; - - c = first; - memset (mb, 0, mlen); - for (i = 0; c >= 0 && i < mlen; 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/isearch.c.orig b/lib/readline/isearch.c.orig deleted file mode 100644 index c1ea5b308..000000000 --- a/lib/readline/isearch.c.orig +++ /dev/null @@ -1,560 +0,0 @@ -/* **************************************************************** */ -/* */ -/* I-Search and Searching */ -/* */ -/* **************************************************************** */ - -/* Copyright (C) 1987-2002 Free Software Foundation, Inc. - - This file contains the Readline Library (the Library), a set of - routines for providing Emacs style line input to programs that ask - for it. - - The Library is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 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 - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif - -#include "rldefs.h" -#include "rlmbutil.h" - -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "xmalloc.h" - -/* Variables exported to other files in the readline library. */ -char *_rl_isearch_terminators = (char *)NULL; - -/* Variables imported from other files in the readline library. */ -extern HIST_ENTRY *_rl_saved_line_for_history; - -/* Forward declarations */ -static int rl_search_history PARAMS((int, int)); - -/* Last line found by the current incremental search, so we don't `find' - identical lines many times in a row. */ -static char *prev_line_found; - -/* Last search string and its length. */ -static char *last_isearch_string; -static int last_isearch_string_len; - -static char *default_isearch_terminators = "\033\012"; - -/* Search backwards through the history looking for a string which is typed - interactively. Start with the current line. */ -int -rl_reverse_search_history (sign, key) - int sign, key; -{ - return (rl_search_history (-sign, key)); -} - -/* Search forwards through the history looking for a string which is typed - interactively. Start with the current line. */ -int -rl_forward_search_history (sign, key) - int sign, key; -{ - return (rl_search_history (sign, key)); -} - -/* Display the current state of the search in the echo-area. - SEARCH_STRING contains the string that is being searched for, - DIRECTION is zero for forward, or 1 for reverse, - WHERE is the history list number of the current line. If it is - -1, then this line is the starting one. */ -static void -rl_display_search (search_string, reverse_p, where) - char *search_string; - int reverse_p, where; -{ - char *message; - int msglen, searchlen; - - searchlen = (search_string && *search_string) ? strlen (search_string) : 0; - - message = (char *)xmalloc (searchlen + 33); - msglen = 0; - -#if defined (NOTDEF) - if (where != -1) - { - sprintf (message, "[%d]", where + history_base); - msglen = strlen (message); - } -#endif /* NOTDEF */ - - message[msglen++] = '('; - - if (reverse_p) - { - strcpy (message + msglen, "reverse-"); - msglen += 8; - } - - strcpy (message + msglen, "i-search)`"); - msglen += 10; - - if (search_string) - { - strcpy (message + msglen, search_string); - msglen += searchlen; - } - - strcpy (message + msglen, "': "); - - rl_message ("%s", message); - free (message); - (*rl_redisplay_function) (); -} - -/* Search through the history looking for an interactively typed string. - This is analogous to i-search. We start the search in the current line. - DIRECTION is which direction to search; >= 0 means forward, < 0 means - backwards. */ -static int -rl_search_history (direction, invoking_key) - int direction, invoking_key; -{ - /* The string that the user types in to search for. */ - char *search_string; - - /* The current length of SEARCH_STRING. */ - int search_string_index; - - /* The amount of space that SEARCH_STRING has allocated to it. */ - int search_string_size; - - /* The list of lines to search through. */ - char **lines, *allocated_line; - - /* The length of LINES. */ - int hlen; - - /* Where we get LINES from. */ - HIST_ENTRY **hlist; - - register int i; - int orig_point, orig_mark, orig_line, last_found_line; - int c, found, failed, sline_len; - int n, wstart, wlen; -#if defined (HANDLE_MULTIBYTE) - char mb[MB_LEN_MAX]; -#endif - - /* The line currently being searched. */ - char *sline; - - /* Offset in that line. */ - int line_index; - - /* Non-zero if we are doing a reverse search. */ - int reverse; - - /* The list of characters which terminate the search, but are not - subsequently executed. If the variable isearch-terminators has - been set, we use that value, otherwise we use ESC and C-J. */ - char *isearch_terminators; - - RL_SETSTATE(RL_STATE_ISEARCH); - orig_point = rl_point; - orig_mark = rl_mark; - last_found_line = orig_line = where_history (); - reverse = direction < 0; - hlist = history_list (); - allocated_line = (char *)NULL; - - isearch_terminators = _rl_isearch_terminators ? _rl_isearch_terminators - : default_isearch_terminators; - - /* Create an arrary of pointers to the lines that we want to search. */ - rl_maybe_replace_line (); - i = 0; - if (hlist) - for (i = 0; hlist[i]; i++); - - /* Allocate space for this many lines, +1 for the current input line, - and remember those lines. */ - lines = (char **)xmalloc ((1 + (hlen = i)) * sizeof (char *)); - for (i = 0; i < hlen; i++) - lines[i] = hlist[i]->line; - - if (_rl_saved_line_for_history) - lines[i] = _rl_saved_line_for_history->line; - else - { - /* Keep track of this so we can free it. */ - allocated_line = (char *)xmalloc (1 + strlen (rl_line_buffer)); - strcpy (allocated_line, &rl_line_buffer[0]); - lines[i] = allocated_line; - } - - hlen++; - - /* The line where we start the search. */ - i = orig_line; - - rl_save_prompt (); - - /* Initialize search parameters. */ - search_string = (char *)xmalloc (search_string_size = 128); - *search_string = '\0'; - search_string_index = 0; - prev_line_found = (char *)0; /* XXX */ - - /* Normalize DIRECTION into 1 or -1. */ - direction = (direction >= 0) ? 1 : -1; - - rl_display_search (search_string, reverse, -1); - - sline = rl_line_buffer; - sline_len = strlen (sline); - line_index = rl_point; - - found = failed = 0; - for (;;) - { - rl_command_func_t *f = (rl_command_func_t *)NULL; - - /* Read a key and decide how to proceed. */ - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - c = _rl_read_mbstring (c, mb, MB_LEN_MAX); -#endif - - /* Translate the keys we do something with to opcodes. */ - if (c >= 0 && _rl_keymap[c].type == ISFUNC) - { - f = _rl_keymap[c].function; - - if (f == rl_reverse_search_history) - c = reverse ? -1 : -2; - else if (f == rl_forward_search_history) - c = !reverse ? -1 : -2; - else if (f == rl_rubout) - c = -3; - else if (c == CTRL ('G')) - c = -4; - else if (c == CTRL ('W')) /* XXX */ - c = -5; - else if (c == CTRL ('Y')) /* XXX */ - c = -6; - } - - /* The characters in isearch_terminators (set from the user-settable - variable isearch-terminators) are used to terminate the search but - not subsequently execute the character as a command. The default - value is "\033\012" (ESC and C-J). */ - if (strchr (isearch_terminators, c)) - { - /* ESC still terminates the search, but if there is pending - input or if input arrives within 0.1 seconds (on systems - with select(2)) it is used as a prefix character - with rl_execute_next. WATCH OUT FOR THIS! This is intended - to allow the arrow keys to be used like ^F and ^B are used - to terminate the search and execute the movement command. - XXX - since _rl_input_available depends on the application- - settable keyboard timeout value, this could alternatively - use _rl_input_queued(100000) */ - if (c == ESC && _rl_input_available ()) - rl_execute_next (ESC); - break; - } - -#define ENDSRCH_CHAR(c) \ - ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G'))) - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (c >= 0 && strlen (mb) == 1 && ENDSRCH_CHAR (c)) - { - /* This sets rl_pending_input to c; it will be picked up the next - time rl_read_key is called. */ - rl_execute_next (c); - break; - } - } - else -#endif - if (c >= 0 && ENDSRCH_CHAR (c)) - { - /* This sets rl_pending_input to c; it will be picked up the next - time rl_read_key is called. */ - rl_execute_next (c); - break; - } - - switch (c) - { - case -1: - if (search_string_index == 0) - { - if (last_isearch_string) - { - search_string_size = 64 + last_isearch_string_len; - search_string = (char *)xrealloc (search_string, search_string_size); - strcpy (search_string, last_isearch_string); - search_string_index = last_isearch_string_len; - rl_display_search (search_string, reverse, -1); - break; - } - continue; - } - else if (reverse) - --line_index; - else if (line_index != sline_len) - ++line_index; - else - rl_ding (); - break; - - /* switch directions */ - case -2: - direction = -direction; - reverse = direction < 0; - break; - - /* delete character from search string. */ - case -3: /* C-H, DEL */ - /* This is tricky. To do this right, we need to keep a - stack of search positions for the current search, with - sentinels marking the beginning and end. But this will - do until we have a real isearch-undo. */ - if (search_string_index == 0) - rl_ding (); - else - search_string[--search_string_index] = '\0'; - - break; - - case -4: /* C-G */ - rl_replace_line (lines[orig_line], 0); - rl_point = orig_point; - rl_mark = orig_mark; - rl_restore_prompt(); - rl_clear_message (); - if (allocated_line) - free (allocated_line); - free (lines); - RL_UNSETSTATE(RL_STATE_ISEARCH); - return 0; - - case -5: /* C-W */ - /* skip over portion of line we already matched */ - wstart = rl_point + search_string_index; - if (wstart >= rl_end) - { - rl_ding (); - break; - } - - /* if not in a word, move to one. */ - if (rl_alphabetic(rl_line_buffer[wstart]) == 0) - { - rl_ding (); - break; - } - n = wstart; - while (n < rl_end && rl_alphabetic(rl_line_buffer[n])) - n++; - wlen = n - wstart + 1; - if (search_string_index + wlen + 1 >= search_string_size) - { - search_string_size += wlen + 1; - search_string = (char *)xrealloc (search_string, search_string_size); - } - for (; wstart < n; wstart++) - search_string[search_string_index++] = rl_line_buffer[wstart]; - search_string[search_string_index] = '\0'; - break; - - case -6: /* C-Y */ - /* skip over portion of line we already matched */ - wstart = rl_point + search_string_index; - if (wstart >= rl_end) - { - rl_ding (); - break; - } - n = rl_end - wstart + 1; - if (search_string_index + n + 1 >= search_string_size) - { - search_string_size += n + 1; - search_string = (char *)xrealloc (search_string, search_string_size); - } - for (n = wstart; n < rl_end; n++) - search_string[search_string_index++] = rl_line_buffer[n]; - search_string[search_string_index] = '\0'; - break; - - default: - /* Add character to search string and continue search. */ - if (search_string_index + 2 >= search_string_size) - { - search_string_size += 128; - search_string = (char *)xrealloc (search_string, search_string_size); - } -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - int j, l; - for (j = 0, l = strlen (mb); j < l; ) - search_string[search_string_index++] = mb[j++]; - } - else -#endif - search_string[search_string_index++] = c; - search_string[search_string_index] = '\0'; - break; - } - - for (found = failed = 0;;) - { - int limit = sline_len - search_string_index + 1; - - /* Search the current line. */ - while (reverse ? (line_index >= 0) : (line_index < limit)) - { - if (STREQN (search_string, sline + line_index, search_string_index)) - { - found++; - break; - } - else - line_index += direction; - } - if (found) - break; - - /* Move to the next line, but skip new copies of the line - we just found and lines shorter than the string we're - searching for. */ - do - { - /* Move to the next line. */ - i += direction; - - /* At limit for direction? */ - if (reverse ? (i < 0) : (i == hlen)) - { - failed++; - break; - } - - /* We will need these later. */ - sline = lines[i]; - sline_len = strlen (sline); - } - while ((prev_line_found && STREQ (prev_line_found, lines[i])) || - (search_string_index > sline_len)); - - if (failed) - break; - - /* Now set up the line for searching... */ - line_index = reverse ? sline_len - search_string_index : 0; - } - - if (failed) - { - /* We cannot find the search string. Ding the bell. */ - rl_ding (); - i = last_found_line; - continue; /* XXX - was break */ - } - - /* We have found the search string. Just display it. But don't - actually move there in the history list until the user accepts - the location. */ - if (found) - { - prev_line_found = lines[i]; - rl_replace_line (lines[i], 0); - rl_point = line_index; - last_found_line = i; - rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i); - } - } - - /* The searching is over. The user may have found the string that she - was looking for, or else she may have exited a failing search. If - LINE_INDEX is -1, then that shows that the string searched for was - not found. We use this to determine where to place rl_point. */ - - /* First put back the original state. */ - strcpy (rl_line_buffer, lines[orig_line]); - - rl_restore_prompt (); - - /* Save the search string for possible later use. */ - FREE (last_isearch_string); - last_isearch_string = search_string; - last_isearch_string_len = search_string_index; - - if (last_found_line < orig_line) - rl_get_previous_history (orig_line - last_found_line, 0); - else - rl_get_next_history (last_found_line - orig_line, 0); - - /* If the string was not found, put point at the end of the last matching - line. If last_found_line == orig_line, we didn't find any matching - history lines at all, so put point back in its original position. */ - if (line_index < 0) - { - if (last_found_line == orig_line) - line_index = orig_point; - else - line_index = strlen (rl_line_buffer); - rl_mark = orig_mark; - } - - rl_point = line_index; - /* Don't worry about where to put the mark here; rl_get_previous_history - and rl_get_next_history take care of it. */ - - rl_clear_message (); - - FREE (allocated_line); - free (lines); - - RL_UNSETSTATE(RL_STATE_ISEARCH); - - return 0; -} diff --git a/lib/readline/isearch.c~ b/lib/readline/isearch.c~ deleted file mode 100644 index b359dc05c..000000000 --- a/lib/readline/isearch.c~ +++ /dev/null @@ -1,674 +0,0 @@ -/* isearch.c - incremental searching */ - -/* **************************************************************** */ -/* */ -/* I-Search and Searching */ -/* */ -/* **************************************************************** */ - -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif - -#include "rldefs.h" -#include "rlmbutil.h" - -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "xmalloc.h" - -/* Variables exported to other files in the readline library. */ -char *_rl_isearch_terminators = (char *)NULL; - -_rl_search_cxt *_rl_iscxt = 0; - -/* Variables imported from other files in the readline library. */ -extern HIST_ENTRY *_rl_saved_line_for_history; - -static int rl_search_history PARAMS((int, int)); - -static _rl_search_cxt *_rl_isearch_init PARAMS((int)); -static void _rl_isearch_fini PARAMS((_rl_search_cxt *)); -static int _rl_isearch_cleanup PARAMS((_rl_search_cxt *, int)); - -/* Last line found by the current incremental search, so we don't `find' - identical lines many times in a row. Now part of isearch context. */ -/* static char *prev_line_found; */ - -/* Last search string and its length. */ -static char *last_isearch_string; -static int last_isearch_string_len; - -static char * const default_isearch_terminators = "\033\012"; - -_rl_search_cxt * -_rl_scxt_alloc (type, flags) - int type, flags; -{ - _rl_search_cxt *cxt; - - cxt = (_rl_search_cxt *)xmalloc (sizeof (_rl_search_cxt)); - - cxt->type = type; - cxt->sflags = flags; - - cxt->search_string = 0; - cxt->search_string_size = cxt->search_string_index = 0; - - cxt->lines = 0; - cxt->allocated_line = 0; - cxt->hlen = cxt->hindex = 0; - - cxt->save_point = rl_point; - cxt->save_mark = rl_mark; - cxt->save_line = where_history (); - cxt->last_found_line = cxt->save_line; - cxt->prev_line_found = 0; - - cxt->save_undo_list = 0; - - cxt->history_pos = 0; - cxt->direction = 0; - - cxt->lastc = 0; - - cxt->sline = 0; - cxt->sline_len = cxt->sline_index = 0; - - cxt->search_terminators = 0; - - return cxt; -} - -void -_rl_scxt_dispose (cxt, flags) - _rl_search_cxt *cxt; - int flags; -{ - FREE (cxt->search_string); - FREE (cxt->allocated_line); - FREE (cxt->lines); - - xfree (cxt); -} - -/* Search backwards through the history looking for a string which is typed - interactively. Start with the current line. */ -int -rl_reverse_search_history (sign, key) - int sign, key; -{ - return (rl_search_history (-sign, key)); -} - -/* Search forwards through the history looking for a string which is typed - interactively. Start with the current line. */ -int -rl_forward_search_history (sign, key) - int sign, key; -{ - return (rl_search_history (sign, key)); -} - -/* Display the current state of the search in the echo-area. - SEARCH_STRING contains the string that is being searched for, - DIRECTION is zero for forward, or non-zero for reverse, - WHERE is the history list number of the current line. If it is - -1, then this line is the starting one. */ -static void -rl_display_search (search_string, reverse_p, where) - char *search_string; - int reverse_p, where; -{ - char *message; - int msglen, searchlen; - - searchlen = (search_string && *search_string) ? strlen (search_string) : 0; - - message = (char *)xmalloc (searchlen + 33); - msglen = 0; - -#if defined (NOTDEF) - if (where != -1) - { - sprintf (message, "[%d]", where + history_base); - msglen = strlen (message); - } -#endif /* NOTDEF */ - - message[msglen++] = '('; - - if (reverse_p) - { - strcpy (message + msglen, "reverse-"); - msglen += 8; - } - - strcpy (message + msglen, "i-search)`"); - msglen += 10; - - if (search_string) - { - strcpy (message + msglen, search_string); - msglen += searchlen; - } - - strcpy (message + msglen, "': "); - - rl_message ("%s", message); - xfree (message); - (*rl_redisplay_function) (); -} - -static _rl_search_cxt * -_rl_isearch_init (direction) - int direction; -{ - _rl_search_cxt *cxt; - register int i; - HIST_ENTRY **hlist; - - cxt = _rl_scxt_alloc (RL_SEARCH_ISEARCH, 0); - if (direction < 0) - cxt->sflags |= SF_REVERSE; - - cxt->search_terminators = _rl_isearch_terminators ? _rl_isearch_terminators - : default_isearch_terminators; - - /* Create an arrary of pointers to the lines that we want to search. */ - hlist = history_list (); - rl_maybe_replace_line (); - i = 0; - if (hlist) - for (i = 0; hlist[i]; i++); - - /* Allocate space for this many lines, +1 for the current input line, - and remember those lines. */ - cxt->lines = (char **)xmalloc ((1 + (cxt->hlen = i)) * sizeof (char *)); - for (i = 0; i < cxt->hlen; i++) - cxt->lines[i] = hlist[i]->line; - - if (_rl_saved_line_for_history) - cxt->lines[i] = _rl_saved_line_for_history->line; - else - { - /* Keep track of this so we can free it. */ - cxt->allocated_line = (char *)xmalloc (1 + strlen (rl_line_buffer)); - strcpy (cxt->allocated_line, &rl_line_buffer[0]); - cxt->lines[i] = cxt->allocated_line; - } - - cxt->hlen++; - - /* The line where we start the search. */ - cxt->history_pos = cxt->save_line; - - rl_save_prompt (); - - /* Initialize search parameters. */ - cxt->search_string = (char *)xmalloc (cxt->search_string_size = 128); - cxt->search_string[cxt->search_string_index = 0] = '\0'; - - /* Normalize DIRECTION into 1 or -1. */ - cxt->direction = (direction >= 0) ? 1 : -1; - - cxt->sline = rl_line_buffer; - cxt->sline_len = strlen (cxt->sline); - cxt->sline_index = rl_point; - - _rl_iscxt = cxt; /* save globally */ - - return cxt; -} - -static void -_rl_isearch_fini (cxt) - _rl_search_cxt *cxt; -{ - /* First put back the original state. */ - strcpy (rl_line_buffer, cxt->lines[cxt->save_line]); - - rl_restore_prompt (); - - /* Save the search string for possible later use. */ - FREE (last_isearch_string); - last_isearch_string = cxt->search_string; - last_isearch_string_len = cxt->search_string_index; - cxt->search_string = 0; - - if (cxt->last_found_line < cxt->save_line) - rl_get_previous_history (cxt->save_line - cxt->last_found_line, 0); - else - rl_get_next_history (cxt->last_found_line - cxt->save_line, 0); - - /* If the string was not found, put point at the end of the last matching - line. If last_found_line == orig_line, we didn't find any matching - history lines at all, so put point back in its original position. */ - if (cxt->sline_index < 0) - { - if (cxt->last_found_line == cxt->save_line) - cxt->sline_index = cxt->save_point; - else - cxt->sline_index = strlen (rl_line_buffer); - rl_mark = cxt->save_mark; - } - - rl_point = cxt->sline_index; - /* Don't worry about where to put the mark here; rl_get_previous_history - and rl_get_next_history take care of it. */ - - rl_clear_message (); -} - -int -_rl_search_getchar (cxt) - _rl_search_cxt *cxt; -{ - int c; - - /* Read a key and decide how to proceed. */ - RL_SETSTATE(RL_STATE_MOREINPUT); - c = cxt->lastc = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - c = cxt->lastc = _rl_read_mbstring (cxt->lastc, cxt->mb, MB_LEN_MAX); -#endif - - return c; -} - -/* Process just-read character C according to isearch context CXT. Return - -1 if the caller should just free the context and return, 0 if we should - break out of the loop, and 1 if we should continue to read characters. */ -int -_rl_isearch_dispatch (cxt, c) - _rl_search_cxt *cxt; - int c; -{ - int n, wstart, wlen, limit, cval; - rl_command_func_t *f; - - f = (rl_command_func_t *)NULL; - - if (c < 0) - { - cxt->sflags |= SF_FAILED; - cxt->history_pos = cxt->last_found_line; - return -1; - } - - /* Translate the keys we do something with to opcodes. */ - if (c >= 0 && _rl_keymap[c].type == ISFUNC) - { - f = _rl_keymap[c].function; - - if (f == rl_reverse_search_history) - cxt->lastc = (cxt->sflags & SF_REVERSE) ? -1 : -2; - else if (f == rl_forward_search_history) - cxt->lastc = (cxt->sflags & SF_REVERSE) ? -2 : -1; - else if (f == rl_rubout) - cxt->lastc = -3; - else if (c == CTRL ('G')) - cxt->lastc = -4; - else if (c == CTRL ('W')) /* XXX */ - cxt->lastc = -5; - else if (c == CTRL ('Y')) /* XXX */ - cxt->lastc = -6; - } - - /* The characters in isearch_terminators (set from the user-settable - variable isearch-terminators) are used to terminate the search but - not subsequently execute the character as a command. The default - value is "\033\012" (ESC and C-J). */ - if (strchr (cxt->search_terminators, cxt->lastc)) - { - /* ESC still terminates the search, but if there is pending - input or if input arrives within 0.1 seconds (on systems - with select(2)) it is used as a prefix character - with rl_execute_next. WATCH OUT FOR THIS! This is intended - to allow the arrow keys to be used like ^F and ^B are used - to terminate the search and execute the movement command. - XXX - since _rl_input_available depends on the application- - settable keyboard timeout value, this could alternatively - use _rl_input_queued(100000) */ - if (cxt->lastc == ESC && _rl_input_available ()) - rl_execute_next (ESC); - return (0); - } - -#define ENDSRCH_CHAR(c) \ - ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G'))) - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - if (cxt->lastc >= 0 && (cxt->mb[0] && cxt->mb[1] == '\0') && ENDSRCH_CHAR (cxt->lastc)) - { - /* This sets rl_pending_input to c; it will be picked up the next - time rl_read_key is called. */ - rl_execute_next (cxt->lastc); - return (0); - } - } - else -#endif - if (cxt->lastc >= 0 && ENDSRCH_CHAR (cxt->lastc)) - { - /* This sets rl_pending_input to LASTC; it will be picked up the next - time rl_read_key is called. */ - rl_execute_next (cxt->lastc); - return (0); - } - - /* Now dispatch on the character. `Opcodes' affect the search string or - state. Other characters are added to the string. */ - switch (cxt->lastc) - { - /* search again */ - case -1: - if (cxt->search_string_index == 0) - { - if (last_isearch_string) - { - cxt->search_string_size = 64 + last_isearch_string_len; - cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size); - strcpy (cxt->search_string, last_isearch_string); - cxt->search_string_index = last_isearch_string_len; - rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), -1); - break; - } - return (1); - } - else if (cxt->sflags & SF_REVERSE) - cxt->sline_index--; - else if (cxt->sline_index != cxt->sline_len) - cxt->sline_index++; - else - rl_ding (); - break; - - /* switch directions */ - case -2: - cxt->direction = -cxt->direction; - if (cxt->direction < 0) - cxt->sflags |= SF_REVERSE; - else - cxt->sflags &= ~SF_REVERSE; - break; - - /* delete character from search string. */ - case -3: /* C-H, DEL */ - /* This is tricky. To do this right, we need to keep a - stack of search positions for the current search, with - sentinels marking the beginning and end. But this will - do until we have a real isearch-undo. */ - if (cxt->search_string_index == 0) - rl_ding (); - else - cxt->search_string[--cxt->search_string_index] = '\0'; - break; - - case -4: /* C-G, abort */ - rl_replace_line (cxt->lines[cxt->save_line], 0); - rl_point = cxt->save_point; - rl_mark = cxt->save_mark; - rl_restore_prompt(); - rl_clear_message (); - - return -1; - - case -5: /* C-W */ - /* skip over portion of line we already matched and yank word */ - wstart = rl_point + cxt->search_string_index; - if (wstart >= rl_end) - { - rl_ding (); - break; - } - - /* if not in a word, move to one. */ - cval = _rl_char_value (rl_line_buffer, wstart); - if (_rl_walphabetic (cval) == 0) - { - rl_ding (); - break; - } - n = MB_NEXTCHAR (rl_line_buffer, wstart, 1, MB_FIND_NONZERO);; - while (n < rl_end) - { - cval = _rl_char_value (rl_line_buffer, n); - if (_rl_walphabetic (cval) == 0) - break; - n = MB_NEXTCHAR (rl_line_buffer, n, 1, MB_FIND_NONZERO);; - } - wlen = n - wstart + 1; - if (cxt->search_string_index + wlen + 1 >= cxt->search_string_size) - { - cxt->search_string_size += wlen + 1; - cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size); - } - for (; wstart < n; wstart++) - cxt->search_string[cxt->search_string_index++] = rl_line_buffer[wstart]; - cxt->search_string[cxt->search_string_index] = '\0'; - break; - - case -6: /* C-Y */ - /* skip over portion of line we already matched and yank rest */ - wstart = rl_point + cxt->search_string_index; - if (wstart >= rl_end) - { - rl_ding (); - break; - } - n = rl_end - wstart + 1; - if (cxt->search_string_index + n + 1 >= cxt->search_string_size) - { - cxt->search_string_size += n + 1; - cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size); - } - for (n = wstart; n < rl_end; n++) - cxt->search_string[cxt->search_string_index++] = rl_line_buffer[n]; - cxt->search_string[cxt->search_string_index] = '\0'; - break; - - /* Add character to search string and continue search. */ - default: - if (cxt->search_string_index + 2 >= cxt->search_string_size) - { - cxt->search_string_size += 128; - cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size); - } -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - int j, l; - for (j = 0, l = strlen (cxt->mb); j < l; ) - cxt->search_string[cxt->search_string_index++] = cxt->mb[j++]; - } - else -#endif - cxt->search_string[cxt->search_string_index++] = c; - cxt->search_string[cxt->search_string_index] = '\0'; - break; - } - - for (cxt->sflags &= ~(SF_FOUND|SF_FAILED);; ) - { - limit = cxt->sline_len - cxt->search_string_index + 1; - - /* Search the current line. */ - while ((cxt->sflags & SF_REVERSE) ? (cxt->sline_index >= 0) : (cxt->sline_index < limit)) - { - if (STREQN (cxt->search_string, cxt->sline + cxt->sline_index, cxt->search_string_index)) - { - cxt->sflags |= SF_FOUND; - break; - } - else - cxt->sline_index += cxt->direction; - } - if (cxt->sflags & SF_FOUND) - break; - - /* Move to the next line, but skip new copies of the line - we just found and lines shorter than the string we're - searching for. */ - do - { - /* Move to the next line. */ - cxt->history_pos += cxt->direction; - - /* At limit for direction? */ - if ((cxt->sflags & SF_REVERSE) ? (cxt->history_pos < 0) : (cxt->history_pos == cxt->hlen)) - { - cxt->sflags |= SF_FAILED; - break; - } - - /* We will need these later. */ - cxt->sline = cxt->lines[cxt->history_pos]; - cxt->sline_len = strlen (cxt->sline); - } - while ((cxt->prev_line_found && STREQ (cxt->prev_line_found, cxt->lines[cxt->history_pos])) || - (cxt->search_string_index > cxt->sline_len)); - - if (cxt->sflags & SF_FAILED) - break; - - /* Now set up the line for searching... */ - cxt->sline_index = (cxt->sflags & SF_REVERSE) ? cxt->sline_len - cxt->search_string_index : 0; - } - - if (cxt->sflags & SF_FAILED) - { - /* We cannot find the search string. Ding the bell. */ - rl_ding (); - cxt->history_pos = cxt->last_found_line; - return 1; - } - - /* We have found the search string. Just display it. But don't - actually move there in the history list until the user accepts - the location. */ - if (cxt->sflags & SF_FOUND) - { - cxt->prev_line_found = cxt->lines[cxt->history_pos]; - rl_replace_line (cxt->lines[cxt->history_pos], 0); - rl_point = cxt->sline_index; - cxt->last_found_line = cxt->history_pos; - rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), (cxt->history_pos == cxt->save_line) ? -1 : cxt->history_pos); - } - - return 1; -} - -static int -_rl_isearch_cleanup (cxt, r) - _rl_search_cxt *cxt; - int r; -{ - if (r >= 0) - _rl_isearch_fini (cxt); - _rl_scxt_dispose (cxt, 0); - _rl_iscxt = 0; - - RL_UNSETSTATE(RL_STATE_ISEARCH); - - return (r != 0); -} - -/* Search through the history looking for an interactively typed string. - This is analogous to i-search. We start the search in the current line. - DIRECTION is which direction to search; >= 0 means forward, < 0 means - backwards. */ -static int -rl_search_history (direction, invoking_key) - int direction, invoking_key; -{ - _rl_search_cxt *cxt; /* local for now, but saved globally */ - int c, r; - - RL_SETSTATE(RL_STATE_ISEARCH); - cxt = _rl_isearch_init (direction); - - rl_display_search (cxt->search_string, (cxt->sflags & SF_REVERSE), -1); - - /* If we are using the callback interface, all we do is set up here and - return. The key is that we leave RL_STATE_ISEARCH set. */ - if (RL_ISSTATE (RL_STATE_CALLBACK)) - return (0); - - r = -1; - for (;;) - { - c = _rl_search_getchar (cxt); - /* We might want to handle EOF here (c == 0) */ - r = _rl_isearch_dispatch (cxt, cxt->lastc); - if (r <= 0) - break; - } - - /* The searching is over. The user may have found the string that she - was looking for, or else she may have exited a failing search. If - LINE_INDEX is -1, then that shows that the string searched for was - not found. We use this to determine where to place rl_point. */ - return (_rl_isearch_cleanup (cxt, r)); -} - -#if defined (READLINE_CALLBACKS) -/* Called from the callback functions when we are ready to read a key. The - callback functions know to call this because RL_ISSTATE(RL_STATE_ISEARCH). - If _rl_isearch_dispatch finishes searching, this function is responsible - for turning off RL_STATE_ISEARCH, which it does using _rl_isearch_cleanup. */ -int -_rl_isearch_callback (cxt) - _rl_search_cxt *cxt; -{ - int c, r; - - c = _rl_search_getchar (cxt); - /* We might want to handle EOF here */ - r = _rl_isearch_dispatch (cxt, cxt->lastc); - - return (r <= 0) ? _rl_isearch_cleanup (cxt, r) : 0; -} -#endif diff --git a/lib/readline/keymaps.h~ b/lib/readline/keymaps.h~ deleted file mode 100644 index 6c8760c03..000000000 --- a/lib/readline/keymaps.h~ +++ /dev/null @@ -1,106 +0,0 @@ -/* keymaps.h -- Manipulation of readline keymaps. */ - -/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 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. */ - -#ifndef _KEYMAPS_H_ -#define _KEYMAPS_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined (READLINE_LIBRARY) -# include "rlstdc.h" -# include "chardefs.h" -# include "rltypedefs.h" -#else -# include -# include -# include -#endif - -/* A keymap contains one entry for each key in the ASCII set. - Each entry consists of a type and a pointer. - FUNCTION is the address of a function to run, or the - address of a keymap to indirect through. - TYPE says which kind of thing FUNCTION is. */ -typedef struct _keymap_entry { - char type; - rl_command_func_t *function; -} KEYMAP_ENTRY; - -/* This must be large enough to hold bindings for all of the characters - in a desired character set (e.g, 128 for ASCII, 256 for ISO Latin-x, - and so on) plus one for subsequence matching. */ -#define KEYMAP_SIZE 257 -#define ANYOTHERKEY KEYMAP_SIZE-1 - -/* I wanted to make the above structure contain a union of: - union { rl_command_func_t *function; struct _keymap_entry *keymap; } value; - but this made it impossible for me to create a static array. - Maybe I need C lessons. */ - -typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE]; -typedef KEYMAP_ENTRY *Keymap; - -/* The values that TYPE can have in a keymap entry. */ -#define ISFUNC 0 -#define ISKMAP 1 -#define ISMACR 2 - -extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap; -extern KEYMAP_ENTRY_ARRAY vi_insertion_keymap, vi_movement_keymap; - -#define VI_COMMAND_MODE (editing_mode == vi_mode && _rl_keymap == vi_movement_keymap) -#define VI_INSERT_MODE (editing_mode == vi_mode && _rl_keymap == vi_insertion_keymap) - -/* Return a new, empty keymap. - Free it with free() when you are done. */ -extern Keymap rl_make_bare_keymap PARAMS((void)); - -/* Return a new keymap which is a copy of MAP. */ -extern Keymap rl_copy_keymap PARAMS((Keymap)); - -/* Return a new keymap with the printing characters bound to rl_insert, - the lowercase Meta characters bound to run their equivalents, and - the Meta digits bound to produce numeric arguments. */ -extern Keymap rl_make_keymap PARAMS((void)); - -/* Free the storage associated with a keymap. */ -extern void rl_discard_keymap PARAMS((Keymap)); - -/* These functions actually appear in bind.c */ - -/* Return the keymap corresponding to a given name. Names look like - `emacs' or `emacs-meta' or `vi-insert'. */ -extern Keymap rl_get_keymap_by_name PARAMS((const char *)); - -/* Return the current keymap. */ -extern Keymap rl_get_keymap PARAMS((void)); - -/* Set the current keymap to MAP. */ -extern void rl_set_keymap PARAMS((Keymap)); - -#ifdef __cplusplus -} -#endif - -#endif /* _KEYMAPS_H_ */ diff --git a/lib/readline/mbutil.c~ b/lib/readline/mbutil.c~ deleted file mode 100644 index 6d36d9e5a..000000000 --- a/lib/readline/mbutil.c~ +++ /dev/null @@ -1,372 +0,0 @@ -/* mbutil.c -- readline multibyte character utility functions */ - -/* Copyright (C) 2001-2005 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include -#include "posixjmp.h" - -#if defined (HAVE_UNISTD_H) -# include /* for _POSIX_VERSION */ -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#include -#include - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "rlmbutil.h" - -#if defined (TIOCSTAT_IN_SYS_IOCTL) -# include -#endif /* TIOCSTAT_IN_SYS_IOCTL */ - -/* Some standard library routines. */ -#include "readline.h" - -#include "rlprivate.h" -#include "xmalloc.h" - -/* Declared here so it can be shared between the readline and history - libraries. */ -#if defined (HANDLE_MULTIBYTE) -int rl_byte_oriented = 0; -#else -int rl_byte_oriented = 1; -#endif - -/* **************************************************************** */ -/* */ -/* Multibyte Character Utility Functions */ -/* */ -/* **************************************************************** */ - -#if defined(HANDLE_MULTIBYTE) - -static int -_rl_find_next_mbchar_internal (string, seed, count, find_non_zero) - char *string; - int seed, count, find_non_zero; -{ - size_t tmp; - mbstate_t ps; - int point; - wchar_t wc; - - tmp = 0; - - memset(&ps, 0, sizeof (mbstate_t)); - if (seed < 0) - seed = 0; - if (count <= 0) - return seed; - - point = seed + _rl_adjust_point (string, seed, &ps); - /* if this is true, means that seed was not pointing to a byte indicating - the beginning of a multibyte character. Correct the point and consume - one char. */ - if (seed < point) - count--; - - while (count > 0) - { - tmp = mbrtowc (&wc, string+point, strlen(string + point), &ps); - if (MB_INVALIDCH ((size_t)tmp)) - { - /* invalid bytes. assume a byte represents a character */ - point++; - count--; - /* reset states. */ - memset(&ps, 0, sizeof(mbstate_t)); - } - else if (MB_NULLWCH (tmp)) - break; /* found wide '\0' */ - else - { - /* valid bytes */ - point += tmp; - if (find_non_zero) - { - if (wcwidth (wc) == 0) - continue; - else - count--; - } - else - count--; - } - } - - if (find_non_zero) - { - tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps); - while (MB_NULLWCH (tmp) == 0 && MB_INVALIDCH (tmp) == 0 && wc_width (wc) == 0) - { - point += tmp; - tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps); - } - } - - return point; -} - -static int -_rl_find_prev_mbchar_internal (string, seed, find_non_zero) - char *string; - int seed, find_non_zero; -{ - mbstate_t ps; - int prev, non_zero_prev, point, length; - size_t tmp; - wchar_t wc; - - memset(&ps, 0, sizeof(mbstate_t)); - length = strlen(string); - - if (seed < 0) - return 0; - else if (length < seed) - return length; - - prev = non_zero_prev = point = 0; - while (point < seed) - { - tmp = mbrtowc (&wc, string + point, length - point, &ps); - if (MB_INVALIDCH ((size_t)tmp)) - { - /* in this case, bytes are invalid or shorted to compose - multibyte char, so assume that the first byte represents - a single character anyway. */ - tmp = 1; - /* clear the state of the byte sequence, because - in this case effect of mbstate is undefined */ - memset(&ps, 0, sizeof (mbstate_t)); - - /* Since we're assuming that this byte represents a single - non-zero-width character, don't forget about it. */ - prev = point; - } - else if (MB_NULLWCH (tmp)) - break; /* Found '\0' char. Can this happen? */ - else - { - if (find_non_zero) - { - if (wcwidth (wc) != 0) - prev = point; - } - else - prev = point; - } - - point += tmp; - } - - return prev; -} - -/* return the number of bytes parsed from the multibyte sequence starting - at src, if a non-L'\0' wide character was recognized. It returns 0, - if a L'\0' wide character was recognized. It returns (size_t)(-1), - if an invalid multibyte sequence was encountered. It returns (size_t)(-2) - if it couldn't parse a complete multibyte character. */ -int -_rl_get_char_len (src, ps) - char *src; - mbstate_t *ps; -{ - size_t tmp; - - tmp = mbrlen((const char *)src, (size_t)strlen (src), ps); - if (tmp == (size_t)(-2)) - { - /* shorted to compose multibyte char */ - if (ps) - memset (ps, 0, sizeof(mbstate_t)); - return -2; - } - else if (tmp == (size_t)(-1)) - { - /* invalid to compose multibyte char */ - /* initialize the conversion state */ - if (ps) - memset (ps, 0, sizeof(mbstate_t)); - return -1; - } - else if (tmp == (size_t)0) - return 0; - else - return (int)tmp; -} - -/* compare the specified two characters. If the characters matched, - return 1. Otherwise return 0. */ -int -_rl_compare_chars (buf1, pos1, ps1, buf2, pos2, ps2) - char *buf1; - int pos1; - mbstate_t *ps1; - char *buf2; - int pos2; - mbstate_t *ps2; -{ - int i, w1, w2; - - if ((w1 = _rl_get_char_len (&buf1[pos1], ps1)) <= 0 || - (w2 = _rl_get_char_len (&buf2[pos2], ps2)) <= 0 || - (w1 != w2) || - (buf1[pos1] != buf2[pos2])) - return 0; - - for (i = 1; i < w1; i++) - if (buf1[pos1+i] != buf2[pos2+i]) - return 0; - - return 1; -} - -/* adjust pointed byte and find mbstate of the point of string. - adjusted point will be point <= adjusted_point, and returns - differences of the byte(adjusted_point - point). - if point is invalied (point < 0 || more than string length), - it returns -1 */ -int -_rl_adjust_point(string, point, ps) - char *string; - int point; - mbstate_t *ps; -{ - size_t tmp = 0; - int length; - int pos = 0; - - length = strlen(string); - if (point < 0) - return -1; - if (length < point) - return -1; - - while (pos < point) - { - tmp = mbrlen (string + pos, length - pos, ps); - if (MB_INVALIDCH ((size_t)tmp)) - { - /* in this case, bytes are invalid or shorted to compose - multibyte char, so assume that the first byte represents - a single character anyway. */ - pos++; - /* clear the state of the byte sequence, because - in this case effect of mbstate is undefined */ - if (ps) - memset (ps, 0, sizeof (mbstate_t)); - } - else if (MB_NULLWCH (tmp)) - pos++; - else - pos += tmp; - } - - return (pos - point); -} - -int -_rl_is_mbchar_matched (string, seed, end, mbchar, length) - char *string; - int seed, end; - char *mbchar; - int length; -{ - int i; - - if ((end - seed) < length) - return 0; - - for (i = 0; i < length; i++) - if (string[seed + i] != mbchar[i]) - return 0; - return 1; -} - -wchar_t -_rl_char_value (buf, ind) - char *buf; - int ind; -{ - size_t tmp; - wchar_t wc; - mbstate_t ps; - int l; - - if (MB_LEN_MAX == 1 || rl_byte_oriented) - return ((wchar_t) buf[ind]); - l = strlen (buf); - if (ind >= l - 1) - return ((wchar_t) buf[ind]); - memset (&ps, 0, sizeof (mbstate_t)); - tmp = mbrtowc (&wc, buf + ind, l - ind, &ps); - if (MB_INVALIDCH (tmp) || MB_NULLWCH (tmp)) - return ((wchar_t) buf[ind]); - return wc; -} -#endif /* HANDLE_MULTIBYTE */ - -/* Find next `count' characters started byte point of the specified seed. - If flags is MB_FIND_NONZERO, we look for non-zero-width multibyte - characters. */ -#undef _rl_find_next_mbchar -int -_rl_find_next_mbchar (string, seed, count, flags) - char *string; - int seed, count, flags; -{ -#if defined (HANDLE_MULTIBYTE) - return _rl_find_next_mbchar_internal (string, seed, count, flags); -#else - return (seed + count); -#endif -} - -/* Find previous character started byte point of the specified seed. - Returned point will be point <= seed. If flags is MB_FIND_NONZERO, - we look for non-zero-width multibyte characters. */ -#undef _rl_find_prev_mbchar -int -_rl_find_prev_mbchar (string, seed, flags) - char *string; - int seed, flags; -{ -#if defined (HANDLE_MULTIBYTE) - return _rl_find_prev_mbchar_internal (string, seed, flags); -#else - return ((seed == 0) ? seed : seed - 1); -#endif -} diff --git a/lib/readline/misc.c~ b/lib/readline/misc.c~ deleted file mode 100644 index b779b0590..000000000 --- a/lib/readline/misc.c~ +++ /dev/null @@ -1,655 +0,0 @@ -/* misc.c -- miscellaneous bindable readline functions. */ - -/* Copyright (C) 1987-2006 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; - -_rl_arg_cxt _rl_argcxt; - -/* 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 */ -/* */ -/* **************************************************************** */ - -int -_rl_arg_overflow () -{ - if (rl_numeric_arg > 1000000) - { - _rl_argcxt = 0; - rl_explicit_arg = rl_numeric_arg = 0; - rl_ding (); - rl_restore_prompt (); - rl_clear_message (); - RL_UNSETSTATE(RL_STATE_NUMERICARG); - return 1; - } - return 0; -} - -void -_rl_arg_init () -{ - rl_save_prompt (); - _rl_argcxt = 0; - RL_SETSTATE(RL_STATE_NUMERICARG); -} - -int -_rl_arg_getchar () -{ - int c; - - rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - return c; -} - -/* Process C as part of the current numeric argument. Return -1 if the - argument should be aborted, 0 if we should not read any more chars, and - 1 if we should continue to read chars. */ -int -_rl_arg_dispatch (cxt, c) - _rl_arg_cxt cxt; - int c; -{ - int key, r; - - key = c; - - /* 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 ((cxt & NUM_SAWDIGITS) == 0) - { - rl_numeric_arg *= 4; - return 1; - } - else if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - _rl_argcxt |= NUM_READONE; - return 0; /* XXX */ - } - 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); - if (key < 0) - return -1; - return (_rl_dispatch (key, _rl_keymap)); - } - } - - c = UNMETA (c); - - if (_rl_digit_p (c)) - { - r = _rl_digit_value (c); - rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + r : r; - rl_explicit_arg = 1; - _rl_argcxt |= NUM_SAWDIGITS; - } - else if (c == '-' && rl_explicit_arg == 0) - { - rl_numeric_arg = 1; - _rl_argcxt |= NUM_SAWMINUS; - rl_arg_sign = -1; - } - else - { - /* Make M-- command equivalent to M--1 command. */ - if ((_rl_argcxt & NUM_SAWMINUS) && rl_numeric_arg == 1 && rl_explicit_arg == 0) - rl_explicit_arg = 1; - rl_restore_prompt (); - rl_clear_message (); - RL_UNSETSTATE(RL_STATE_NUMERICARG); - - r = _rl_dispatch (key, _rl_keymap); - if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - /* At worst, this will cause an extra redisplay. Otherwise, - we have to wait until the next character comes in. */ - if (rl_done == 0) - (*rl_redisplay_function) (); - r = 0; - } - return r; - } - - return 1; -} - -/* Handle C-u style numeric args, as well as M--, and M-digits. */ -static int -rl_digit_loop () -{ - int c, r; - - while (1) - { - if (_rl_arg_overflow ()) - return 1; - - c = _rl_arg_getchar (); - - if (c < 0) - { - _rl_abort_internal (); - return -1; - } - - r = _rl_arg_dispatch (_rl_argcxt, c); - if (r <= 0 || (RL_ISSTATE (RL_STATE_NUMERICARG) == 0)) - break; - } - - return r; -} - -/* Create a default argument. */ -void -_rl_reset_argument () -{ - rl_numeric_arg = rl_arg_sign = 1; - rl_explicit_arg = 0; - _rl_argcxt = 0; -} - -/* Start a numeric argument with initial value KEY */ -int -rl_digit_argument (ignore, key) - int ignore, key; -{ - _rl_arg_init (); - if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - _rl_arg_dispatch (_rl_argcxt, key); - rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); - return 0; - } - else - { - rl_execute_next (key); - return (rl_digit_loop ()); - } -} - -/* 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_arg_init (); - rl_numeric_arg *= 4; - - return (RL_ISSTATE (RL_STATE_CALLBACK) ? 0 : rl_digit_loop ()); -} - -int -_rl_arg_callback (cxt) - _rl_arg_cxt cxt; -{ - int c, r; - - c = _rl_arg_getchar (); - - if (_rl_argcxt & NUM_READONE) - { - _rl_argcxt &= ~NUM_READONE; - rl_restore_prompt (); - rl_clear_message (); - RL_UNSETSTATE(RL_STATE_NUMERICARG); - rl_execute_next (c); - return 0; - } - - r = _rl_arg_dispatch (cxt, c); - return (r != 1); -} - -/* What to do when you abort reading an argument. */ -int -rl_discard_argument () -{ - rl_ding (); - rl_clear_message (); - _rl_reset_argument (); - - return 0; -} - -/* **************************************************************** */ -/* */ -/* 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; - - FREE (entry->line); - FREE (entry->timestamp); - - 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->timestamp); - 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->timestamp = (char *)NULL; - _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 -} - -/* Process and free undo lists attached to each history entry prior to the - current entry, inclusive, reverting each line to its saved state. This - is destructive, and state about the current line is lost. This is not - intended to be called while actively editing, and the current line is - not assumed to have been added to the history list. */ -void -_rl_revert_all_lines () -{ - int hpos; - HIST_ENTRY *entry, *cur; - UNDO_LIST *ul, *saved_undo_list; - char *lbuf; - - lbuf = savestring (rl_line_buffer); - saved_undo_list = rl_undo_list; - hpos = where_history (); - - entry = (hpos == history_length) ? previous_history () : current_history (); - while (entry) - { - if (ul = (UNDO_LIST *)entry->data) - { - if (ul == saved_undo_list) - saved_undo_list = 0; - /* Set up rl_line_buffer and other variables from history entry */ - rl_replace_from_history (entry, 0); /* entry->line is now current */ - /* Undo all changes to this history entry */ - while (rl_undo_list) - rl_do_undo (); - /* And copy the reverted line back to the history entry, preserving - the timestamp. */ - FREE (entry->line); - entry->line = savestring (rl_line_buffer); - entry->data = 0; - } - entry = previous_history (); - } - - /* Restore history state */ - rl_undo_list = saved_undo_list; /* may have been set to null */ - history_set_pos (hpos); - - /* reset the line buffer */ - rl_replace_line (lbuf, 0); - _rl_set_the_line (); - - /* and clean up */ - free (lbuf); -} - -/* **************************************************************** */ -/* */ -/* 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_insert_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/readline.c~ b/lib/readline/readline.c~ deleted file mode 100644 index 9f3b13c03..000000000 --- a/lib/readline/readline.c~ +++ /dev/null @@ -1,1249 +0,0 @@ -/* readline.c -- a general facility for reading lines of input - with emacs style editing and completion. */ - -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include "posixstat.h" -#include -#if defined (HAVE_SYS_FILE_H) -# include -#endif /* HAVE_SYS_FILE_H */ - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#if defined (HAVE_LOCALE_H) -# include -#endif - -#include -#include "posixjmp.h" -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -/* 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" - -#ifndef RL_LIBRARY_VERSION -# define RL_LIBRARY_VERSION "5.1" -#endif - -#ifndef RL_READLINE_VERSION -# define RL_READLINE_VERSION 0x0501 -#endif - -extern void _rl_free_history_entry PARAMS((HIST_ENTRY *)); - -/* Forward declarations used in this file. */ -static char *readline_internal PARAMS((void)); -static void readline_initialize_everything PARAMS((void)); - -static void bind_arrow_keys_internal PARAMS((Keymap)); -static void bind_arrow_keys PARAMS((void)); - -static void readline_default_bindings PARAMS((void)); -static void reset_default_bindings PARAMS((void)); - -static int _rl_subseq_result PARAMS((int, Keymap, int, int)); -static int _rl_subseq_getchar PARAMS((int)); - -/* **************************************************************** */ -/* */ -/* Line editing input utility */ -/* */ -/* **************************************************************** */ - -const char *rl_library_version = RL_LIBRARY_VERSION; - -int rl_readline_version = RL_READLINE_VERSION; - -/* True if this is `real' readline as opposed to some stub substitute. */ -int rl_gnu_readline_p = 1; - -/* A pointer to the keymap that is currently in use. - By default, it is the standard emacs keymap. */ -Keymap _rl_keymap = emacs_standard_keymap; - - -/* The current style of editing. */ -int rl_editing_mode = emacs_mode; - -/* The current insert mode: input (the default) or overwrite */ -int rl_insert_mode = RL_IM_DEFAULT; - -/* 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. */ -int rl_dispatching; - -/* Non-zero if the previous command was a kill command. */ -int _rl_last_command_was_kill = 0; - -/* The current value of the numeric argument specified by the user. */ -int rl_numeric_arg = 1; - -/* Non-zero if an argument was typed. */ -int rl_explicit_arg = 0; - -/* Temporary value used while generating the argument. */ -int rl_arg_sign = 1; - -/* Non-zero means we have been called at least once before. */ -static int rl_initialized; - -#if 0 -/* If non-zero, this program is running in an EMACS buffer. */ -static int running_in_emacs; -#endif - -/* Flags word encapsulating the current readline state. */ -int rl_readline_state = RL_STATE_NONE; - -/* The current offset in the current input line. */ -int rl_point; - -/* Mark in the current input line. */ -int rl_mark; - -/* Length of the current input line. */ -int rl_end; - -/* Make this non-zero to return the current input_line. */ -int rl_done; - -/* The last function executed by readline. */ -rl_command_func_t *rl_last_func = (rl_command_func_t *)NULL; - -/* Top level environment for readline_internal (). */ -procenv_t _rl_top_level; - -/* The streams we interact with. */ -FILE *_rl_in_stream, *_rl_out_stream; - -/* The names of the streams that we do input and output to. */ -FILE *rl_instream = (FILE *)NULL; -FILE *rl_outstream = (FILE *)NULL; - -/* Non-zero means echo characters as they are read. Defaults to no echo; - set to 1 if there is a controlling terminal, we can get its attributes, - and the attributes include `echo'. Look at rltty.c:prepare_terminal_settings - for the code that sets it. */ -int _rl_echoing_p = 0; - -/* Current prompt. */ -char *rl_prompt = (char *)NULL; -int rl_visible_prompt_length = 0; - -/* Set to non-zero by calling application if it has already printed rl_prompt - and does not want readline to do it the first time. */ -int rl_already_prompted = 0; - -/* The number of characters read in order to type this complete command. */ -int rl_key_sequence_length = 0; - -/* If non-zero, then this is the address of a function to call just - before readline_internal_setup () prints the first prompt. */ -rl_hook_func_t *rl_startup_hook = (rl_hook_func_t *)NULL; - -/* 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. */ -rl_hook_func_t *rl_pre_input_hook = (rl_hook_func_t *)NULL; - -/* What we use internally. You should always refer to RL_LINE_BUFFER. */ -static char *the_line; - -/* The character that can generate an EOF. Really read from - the terminal driver... just defaulted here. */ -int _rl_eof_char = CTRL ('D'); - -/* Non-zero makes this the next keystroke to read. */ -int rl_pending_input = 0; - -/* Pointer to a useful terminal name. */ -const char *rl_terminal_name = (const char *)NULL; - -/* Non-zero means to always use horizontal scrolling in line display. */ -int _rl_horizontal_scroll_mode = 0; - -/* Non-zero means to display an asterisk at the starts of history lines - which have been modified. */ -int _rl_mark_modified_lines = 0; - -/* The style of `bell' notification preferred. This can be set to NO_BELL, - AUDIBLE_BELL, or VISIBLE_BELL. */ -int _rl_bell_preference = AUDIBLE_BELL; - -/* String inserted into the line by rl_insert_comment (). */ -char *_rl_comment_begin; - -/* Keymap holding the function currently being executed. */ -Keymap rl_executing_keymap; - -/* Keymap we're currently using to dispatch. */ -Keymap _rl_dispatching_keymap; - -/* Non-zero means to erase entire line, including prompt, on empty input lines. */ -int rl_erase_empty_line = 0; - -/* Non-zero means to read only this many characters rather than up to a - character bound to accept-line. */ -int rl_num_chars_to_read; - -/* Line buffer and maintenence. */ -char *rl_line_buffer = (char *)NULL; -int rl_line_buffer_len = 0; - -/* Key sequence `contexts' */ -_rl_keyseq_cxt *_rl_kscxt = 0; - -/* Forward declarations used by the display, termcap, and history code. */ - -/* **************************************************************** */ -/* */ -/* `Forward' declarations */ -/* */ -/* **************************************************************** */ - -/* Non-zero means do not parse any lines other than comments and - parser directives. */ -unsigned char _rl_parsing_conditionalized_out = 0; - -/* Non-zero means to convert characters with the meta bit set to - escape-prefixed characters so we can indirect through - emacs_meta_keymap or vi_escape_keymap. */ -int _rl_convert_meta_chars_to_ascii = 1; - -/* Non-zero means to output characters with the meta bit set directly - rather than as a meta-prefixed escape sequence. */ -int _rl_output_meta_chars = 0; - -/* Non-zero means to look at the termios special characters and bind - them to equivalent readline functions at startup. */ -int _rl_bind_stty_chars = 1; - -/* Non-zero means to go through the history list at every newline (or - whenever rl_done is set and readline returns) and revert each line to - its initial state. */ -int _rl_revert_all_at_newline = 0; - -/* **************************************************************** */ -/* */ -/* Top Level Functions */ -/* */ -/* **************************************************************** */ - -/* Non-zero means treat 0200 bit in terminal input as Meta bit. */ -int _rl_meta_flag = 0; /* Forward declaration */ - -/* Set up the prompt and expand it. Called from readline() and - rl_callback_handler_install (). */ -int -rl_set_prompt (prompt) - const char *prompt; -{ - FREE (rl_prompt); - rl_prompt = prompt ? savestring (prompt) : (char *)NULL; - rl_display_prompt = rl_prompt ? rl_prompt : ""; - - rl_visible_prompt_length = rl_expand_prompt (rl_prompt); - return 0; -} - -/* Read a line of input. Prompt with PROMPT. An empty PROMPT means - none. A return value of NULL means that EOF was encountered. */ -char * -readline (prompt) - const char *prompt; -{ - char *value; -#if 0 - int in_callback; -#endif - - /* If we are at EOF return a NULL string. */ - if (rl_pending_input == EOF) - { - rl_clear_pending_input (); - return ((char *)NULL); - } - -#if 0 - /* If readline() is called after installing a callback handler, temporarily - turn off the callback state to avoid ensuing messiness. Patch supplied - by the gdb folks. XXX -- disabled. This can be fooled and readline - left in a strange state by a poorly-timed longjmp. */ - if (in_callback = RL_ISSTATE (RL_STATE_CALLBACK)) - RL_UNSETSTATE (RL_STATE_CALLBACK); -#endif - - rl_set_prompt (prompt); - - rl_initialize (); - if (rl_prep_term_function) - (*rl_prep_term_function) (_rl_meta_flag); - -#if defined (HANDLE_SIGNALS) - rl_set_signals (); -#endif - - value = readline_internal (); - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); - -#if defined (HANDLE_SIGNALS) - rl_clear_signals (); -#endif - -#if 0 - if (in_callback) - RL_SETSTATE (RL_STATE_CALLBACK); -#endif - - return (value); -} - -#if defined (READLINE_CALLBACKS) -# define STATIC_CALLBACK -#else -# define STATIC_CALLBACK static -#endif - -STATIC_CALLBACK void -readline_internal_setup () -{ - char *nprompt; - - _rl_in_stream = rl_instream; - _rl_out_stream = rl_outstream; - - if (rl_startup_hook) - (*rl_startup_hook) (); - - /* If we're not echoing, we still want to at least print a prompt, because - rl_redisplay will not do it for us. If the calling application has a - custom redisplay function, though, let that function handle it. */ - if (_rl_echoing_p == 0 && rl_redisplay_function == rl_redisplay) - { - if (rl_prompt && rl_already_prompted == 0) - { - nprompt = _rl_strip_prompt (rl_prompt); - fprintf (_rl_out_stream, "%s", nprompt); - fflush (_rl_out_stream); - free (nprompt); - } - } - else - { - if (rl_prompt && rl_already_prompted) - rl_on_new_line_with_prompt (); - else - rl_on_new_line (); - (*rl_redisplay_function) (); - } - -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - rl_vi_insert_mode (1, 'i'); -#endif /* VI_MODE */ - - if (rl_pre_input_hook) - (*rl_pre_input_hook) (); - - RL_CHECK_SIGNALS (); -} - -STATIC_CALLBACK char * -readline_internal_teardown (eof) - int eof; -{ - char *temp; - HIST_ENTRY *entry; - - RL_CHECK_SIGNALS (); - - /* Restore the original of this history line, iff the line that we - are editing was originally in the history, AND the line has changed. */ - entry = current_history (); - - if (entry && rl_undo_list) - { - temp = savestring (the_line); - rl_revert_line (1, 0); - entry = replace_history_entry (where_history (), the_line, (histdata_t)NULL); - _rl_free_history_entry (entry); - - strcpy (the_line, temp); - free (temp); - } - - if (_rl_revert_all_at_newline) - _rl_revert_all_lines (); - - /* At any rate, it is highly likely that this line has an undo list. Get - rid of it now. */ - if (rl_undo_list) - rl_free_undo_list (); - - /* Restore normal cursor, if available. */ - _rl_set_insert_mode (RL_IM_INSERT, 0); - - return (eof ? (char *)NULL : savestring (the_line)); -} - -void -_rl_internal_char_cleanup () -{ -#if defined (VI_MODE) - /* In vi mode, when you exit insert mode, the cursor moves back - over the previous character. We explicitly check for that here. */ - if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap) - rl_vi_check (); -#endif /* VI_MODE */ - - if (rl_num_chars_to_read && rl_end >= rl_num_chars_to_read) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - rl_newline (1, '\n'); - } - - if (rl_done == 0) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - } - - /* If the application writer has told us to erase the entire line if - the only character typed was something bound to rl_newline, do so. */ - if (rl_erase_empty_line && rl_done && rl_last_func == rl_newline && - rl_point == 0 && rl_end == 0) - _rl_erase_entire_line (); -} - -STATIC_CALLBACK int -#if defined (READLINE_CALLBACKS) -readline_internal_char () -#else -readline_internal_charloop () -#endif -{ - static int lastc, eof_found; - int c, code, lk; - - lastc = -1; - eof_found = 0; - -#if !defined (READLINE_CALLBACKS) - while (rl_done == 0) - { -#endif - lk = _rl_last_command_was_kill; - - code = setjmp (_rl_top_level); - - if (code) - { - (*rl_redisplay_function) (); - _rl_want_redisplay = 0; - /* If we get here, we're not being called from something dispatched - from _rl_callback_read_char(), which sets up its own value of - _rl_top_level (saving and restoring the old, of course), so - we can just return here. */ - if (RL_ISSTATE (RL_STATE_CALLBACK)) - return (0); - } - - if (rl_pending_input == 0) - { - /* Then initialize the argument and number of keys read. */ - _rl_reset_argument (); - rl_key_sequence_length = 0; - } - - RL_SETSTATE(RL_STATE_READCMD); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_READCMD); - - /* look at input.c:rl_getc() for the circumstances under which this will - be returned; punt immediately on read error without converting it to - a newline. */ - if (c == READERR) - { -#if defined (READLINE_CALLBACKS) - RL_SETSTATE(RL_STATE_DONE); - return (rl_done = 1); -#else - eof_found = 1; - break; -#endif - } - - /* EOF typed to a non-blank line is a . */ - if (c == EOF && rl_end) - c = NEWLINE; - - /* The character _rl_eof_char typed to blank line, and not as the - previous character is interpreted as EOF. */ - if (((c == _rl_eof_char && lastc != c) || c == EOF) && !rl_end) - { -#if defined (READLINE_CALLBACKS) - RL_SETSTATE(RL_STATE_DONE); - return (rl_done = 1); -#else - eof_found = 1; - break; -#endif - } - - lastc = c; - _rl_dispatch ((unsigned char)c, _rl_keymap); - RL_CHECK_SIGNALS (); - - /* If there was no change in _rl_last_command_was_kill, then no kill - has taken place. Note that if input is pending we are reading - a prefix command, so nothing has changed yet. */ - if (rl_pending_input == 0 && lk == _rl_last_command_was_kill) - _rl_last_command_was_kill = 0; - - _rl_internal_char_cleanup (); - -#if defined (READLINE_CALLBACKS) - return 0; -#else - } - - return (eof_found); -#endif -} - -#if defined (READLINE_CALLBACKS) -static int -readline_internal_charloop () -{ - int eof = 1; - - while (rl_done == 0) - eof = readline_internal_char (); - return (eof); -} -#endif /* READLINE_CALLBACKS */ - -/* Read a line of input from the global rl_instream, doing output on - the global rl_outstream. - If rl_prompt is non-null, then that is our prompt. */ -static char * -readline_internal () -{ - int eof; - - readline_internal_setup (); - eof = readline_internal_charloop (); - return (readline_internal_teardown (eof)); -} - -void -_rl_init_line_state () -{ - rl_point = rl_end = rl_mark = 0; - the_line = rl_line_buffer; - the_line[0] = 0; -} - -void -_rl_set_the_line () -{ - the_line = rl_line_buffer; -} - -#if defined (READLINE_CALLBACKS) -_rl_keyseq_cxt * -_rl_keyseq_cxt_alloc () -{ - _rl_keyseq_cxt *cxt; - - cxt = (_rl_keyseq_cxt *)xmalloc (sizeof (_rl_keyseq_cxt)); - - cxt->flags = cxt->subseq_arg = cxt->subseq_retval = 0; - - cxt->okey = 0; - cxt->ocxt = _rl_kscxt; - cxt->childval = 42; /* sentinel value */ - - return cxt; -} - -void -_rl_keyseq_cxt_dispose (cxt) - _rl_keyseq_cxt *cxt; -{ - free (cxt); -} - -void -_rl_keyseq_chain_dispose () -{ - _rl_keyseq_cxt *cxt; - - while (_rl_kscxt) - { - cxt = _rl_kscxt; - _rl_kscxt = _rl_kscxt->ocxt; - _rl_keyseq_cxt_dispose (cxt); - } -} -#endif - -static int -_rl_subseq_getchar (key) - int key; -{ - int k; - - if (key == ESC) - RL_SETSTATE(RL_STATE_METANEXT); - RL_SETSTATE(RL_STATE_MOREINPUT); - k = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - if (key == ESC) - RL_UNSETSTATE(RL_STATE_METANEXT); - - return k; -} - -#if defined (READLINE_CALLBACKS) -int -_rl_dispatch_callback (cxt) - _rl_keyseq_cxt *cxt; -{ - int nkey, r; - - /* For now */ -#if 1 - /* The first time this context is used, we want to read input and dispatch - on it. When traversing the chain of contexts back `up', we want to use - the value from the next context down. We're simulating recursion using - a chain of contexts. */ - if ((cxt->flags & KSEQ_DISPATCHED) == 0) - { - nkey = _rl_subseq_getchar (cxt->okey); - if (nkey < 0) - { - _rl_abort_internal (); - return -1; - } - r = _rl_dispatch_subseq (nkey, cxt->dmap, cxt->subseq_arg); - cxt->flags |= KSEQ_DISPATCHED; - } - else - r = cxt->childval; -#else - r = _rl_dispatch_subseq (nkey, cxt->dmap, cxt->subseq_arg); -#endif - - /* For now */ - r = _rl_subseq_result (r, cxt->oldmap, cxt->okey, (cxt->flags & KSEQ_SUBSEQ)); - - if (r == 0) /* success! */ - { - _rl_keyseq_chain_dispose (); - RL_UNSETSTATE (RL_STATE_MULTIKEY); - return r; - } - - if (r != -3) /* magic value that says we added to the chain */ - _rl_kscxt = cxt->ocxt; - if (_rl_kscxt) - _rl_kscxt->childval = r; - if (r != -3) - _rl_keyseq_cxt_dispose (cxt); - - return r; -} -#endif /* READLINE_CALLBACKS */ - -/* Do the command associated with KEY in MAP. - If the associated command is really a keymap, then read - another key, and dispatch into that map. */ -int -_rl_dispatch (key, map) - register int key; - Keymap map; -{ - _rl_dispatching_keymap = map; - return _rl_dispatch_subseq (key, map, 0); -} - -int -_rl_dispatch_subseq (key, map, got_subseq) - register int key; - Keymap map; - int got_subseq; -{ - int r, newkey; - char *macro; - rl_command_func_t *func; -#if defined (READLINE_CALLBACKS) - _rl_keyseq_cxt *cxt; -#endif - - if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) - { - if (map[ESC].type == ISKMAP) - { - if (RL_ISSTATE (RL_STATE_MACRODEF)) - _rl_add_macro_char (ESC); - map = FUNCTION_TO_KEYMAP (map, ESC); - key = UNMETA (key); - rl_key_sequence_length += 2; - return (_rl_dispatch (key, map)); - } - else - rl_ding (); - return 0; - } - - if (RL_ISSTATE (RL_STATE_MACRODEF)) - _rl_add_macro_char (key); - - r = 0; - switch (map[key].type) - { - case ISFUNC: - func = map[key].function; - if (func) - { - /* Special case rl_do_lowercase_version (). */ - if (func == rl_do_lowercase_version) - return (_rl_dispatch (_rl_to_lower (key), map)); - - rl_executing_keymap = map; - - rl_dispatching = 1; - RL_SETSTATE(RL_STATE_DISPATCHING); - (*map[key].function)(rl_numeric_arg * rl_arg_sign, key); - RL_UNSETSTATE(RL_STATE_DISPATCHING); - rl_dispatching = 0; - - /* If we have input pending, then the last command was a prefix - command. Don't change the state of rl_last_func. Otherwise, - remember the last command executed in this variable. */ - if (rl_pending_input == 0 && map[key].function != rl_digit_argument) - rl_last_func = map[key].function; - } - else if (map[ANYOTHERKEY].function) - { - /* OK, there's no function bound in this map, but there is a - shadow function that was overridden when the current keymap - was created. Return -2 to note that. */ - _rl_unget_char (key); - return -2; - } - else if (got_subseq) - { - /* Return -1 to note that we're in a subsequence, but we don't - have a matching key, nor was one overridden. This means - we need to back up the recursion chain and find the last - subsequence that is bound to a function. */ - _rl_unget_char (key); - return -1; - } - else - { -#if defined (READLINE_CALLBACKS) - RL_UNSETSTATE (RL_STATE_MULTIKEY); - _rl_keyseq_chain_dispose (); -#endif - _rl_abort_internal (); - return -1; - } - break; - - case ISKMAP: - if (map[key].function != 0) - { -#if defined (VI_MODE) - /* The only way this test will be true is if a subsequence has been - bound starting with ESC, generally the arrow keys. What we do is - check whether there's input in the queue, which there generally - will be if an arrow key has been pressed, and, if there's not, - just dispatch to (what we assume is) rl_vi_movement_mode right - away. This is essentially an input test with a zero timeout. */ - if (rl_editing_mode == vi_mode && key == ESC && map == vi_insertion_keymap - && _rl_input_queued (0) == 0) - return (_rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key))); -#endif - - rl_key_sequence_length++; - _rl_dispatching_keymap = FUNCTION_TO_KEYMAP (map, key); - - /* Allocate new context here. Use linked contexts (linked through - cxt->ocxt) to simulate recursion */ -#if defined (READLINE_CALLBACKS) - if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - /* Return 0 only the first time, to indicate success to - _rl_callback_read_char. The rest of the time, we're called - from _rl_dispatch_callback, so we return 3 to indicate - special handling is necessary. */ - r = RL_ISSTATE (RL_STATE_MULTIKEY) ? -3 : 0; - cxt = _rl_keyseq_cxt_alloc (); - - if (got_subseq) - cxt->flags |= KSEQ_SUBSEQ; - cxt->okey = key; - cxt->oldmap = map; - cxt->dmap = _rl_dispatching_keymap; - cxt->subseq_arg = got_subseq || cxt->dmap[ANYOTHERKEY].function; - - RL_SETSTATE (RL_STATE_MULTIKEY); - _rl_kscxt = cxt; - - return r; /* don't indicate immediate success */ - } -#endif - - newkey = _rl_subseq_getchar (key); - if (newkey < 0) - { - _rl_abort_internal (); - return -1; - } - - r = _rl_dispatch_subseq (newkey, _rl_dispatching_keymap, got_subseq || map[ANYOTHERKEY].function); - return _rl_subseq_result (r, map, key, got_subseq); - } - else - { - _rl_abort_internal (); - return -1; - } - break; - - case ISMACR: - if (map[key].function != 0) - { - macro = savestring ((char *)map[key].function); - _rl_with_macro_input (macro); - return 0; - } - break; - } -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap && - key != ANYOTHERKEY && - _rl_vi_textmod_command (key)) - _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign); -#endif - - return (r); -} - -static int -_rl_subseq_result (r, map, key, got_subseq) - int r; - Keymap map; - int key, got_subseq; -{ - Keymap m; - int type, nt; - rl_command_func_t *func, *nf; - - if (r == -2) - /* We didn't match anything, and the keymap we're indexed into - shadowed a function previously bound to that prefix. Call - the function. The recursive call to _rl_dispatch_subseq has - already taken care of pushing any necessary input back onto - the input queue with _rl_unget_char. */ - { - m = _rl_dispatching_keymap; - type = m[ANYOTHERKEY].type; - func = m[ANYOTHERKEY].function; - if (type == ISFUNC && func == rl_do_lowercase_version) - r = _rl_dispatch (_rl_to_lower (key), map); - else if (type == ISFUNC && func == rl_insert) - { - /* If the function that was shadowed was self-insert, we - somehow need a keymap with map[key].func == self-insert. - Let's use this one. */ - nt = m[key].type; - nf = m[key].function; - - m[key].type = type; - m[key].function = func; - r = _rl_dispatch (key, m); - m[key].type = nt; - m[key].function = nf; - } - else - r = _rl_dispatch (ANYOTHERKEY, m); - } - else if (r && map[ANYOTHERKEY].function) - { - /* We didn't match (r is probably -1), so return something to - tell the caller that it should try ANYOTHERKEY for an - overridden function. */ - _rl_unget_char (key); - _rl_dispatching_keymap = map; - return -2; - } - else if (r && got_subseq) - { - /* OK, back up the chain. */ - _rl_unget_char (key); - _rl_dispatching_keymap = map; - return -1; - } - - return r; -} - -/* **************************************************************** */ -/* */ -/* Initializations */ -/* */ -/* **************************************************************** */ - -/* Initialize readline (and terminal if not already). */ -int -rl_initialize () -{ - /* If we have never been called before, initialize the - terminal and data structures. */ - if (!rl_initialized) - { - RL_SETSTATE(RL_STATE_INITIALIZING); - readline_initialize_everything (); - RL_UNSETSTATE(RL_STATE_INITIALIZING); - rl_initialized++; - RL_SETSTATE(RL_STATE_INITIALIZED); - } - - /* Initalize the current line information. */ - _rl_init_line_state (); - - /* We aren't done yet. We haven't even gotten started yet! */ - rl_done = 0; - RL_UNSETSTATE(RL_STATE_DONE); - - /* Tell the history routines what is going on. */ - _rl_start_using_history (); - - /* Make the display buffer match the state of the line. */ - rl_reset_line_state (); - - /* No such function typed yet. */ - rl_last_func = (rl_command_func_t *)NULL; - - /* Parsing of key-bindings begins in an enabled state. */ - _rl_parsing_conditionalized_out = 0; - -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - _rl_vi_initialize_line (); -#endif - - /* Each line starts in insert mode (the default). */ - _rl_set_insert_mode (RL_IM_DEFAULT, 1); - - return 0; -} - -#if 0 -#if defined (__EMX__) -static void -_emx_build_environ () -{ - TIB *tibp; - PIB *pibp; - char *t, **tp; - int c; - - DosGetInfoBlocks (&tibp, &pibp); - t = pibp->pib_pchenv; - for (c = 1; *t; c++) - t += strlen (t) + 1; - tp = environ = (char **)xmalloc ((c + 1) * sizeof (char *)); - t = pibp->pib_pchenv; - while (*t) - { - *tp++ = t; - t += strlen (t) + 1; - } - *tp = 0; -} -#endif /* __EMX__ */ -#endif - -/* Initialize the entire state of the world. */ -static void -readline_initialize_everything () -{ -#if 0 -#if defined (__EMX__) - if (environ == 0) - _emx_build_environ (); -#endif -#endif - -#if 0 - /* Find out if we are running in Emacs -- UNUSED. */ - running_in_emacs = sh_get_env_value ("EMACS") != (char *)0; -#endif - - /* Set up input and output if they are not already set up. */ - if (!rl_instream) - rl_instream = stdin; - - if (!rl_outstream) - rl_outstream = stdout; - - /* Bind _rl_in_stream and _rl_out_stream immediately. These values - may change, but they may also be used before readline_internal () - is called. */ - _rl_in_stream = rl_instream; - _rl_out_stream = rl_outstream; - - /* Allocate data structures. */ - if (rl_line_buffer == 0) - rl_line_buffer = (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE); - - /* Initialize the terminal interface. */ - if (rl_terminal_name == 0) - rl_terminal_name = sh_get_env_value ("TERM"); - _rl_init_terminal_io (rl_terminal_name); - - /* Bind tty characters to readline functions. */ - readline_default_bindings (); - - /* Initialize the function names. */ - rl_initialize_funmap (); - - /* Decide whether we should automatically go into eight-bit mode. */ - _rl_init_eightbit (); - - /* Read in the init file. */ - rl_read_init_file ((char *)NULL); - - /* XXX */ - if (_rl_horizontal_scroll_mode && _rl_term_autowrap) - { - _rl_screenwidth--; - _rl_screenchars -= _rl_screenheight; - } - - /* Override the effect of any `set keymap' assignments in the - inputrc file. */ - rl_set_keymap_from_edit_mode (); - - /* Try to bind a common arrow key prefix, if not already bound. */ - bind_arrow_keys (); - - /* Enable the meta key, if this terminal has one. */ - if (_rl_enable_meta) - _rl_enable_meta_key (); - - /* If the completion parser's default word break characters haven't - been set yet, then do so now. */ - if (rl_completer_word_break_characters == (char *)NULL) - rl_completer_word_break_characters = (char *)rl_basic_word_break_characters; -} - -/* If this system allows us to look at the values of the regular - input editing characters, then bind them to their readline - equivalents, iff the characters are not bound to keymaps. */ -static void -readline_default_bindings () -{ - if (_rl_bind_stty_chars) - rl_tty_set_default_bindings (_rl_keymap); -} - -/* Reset the default bindings for the terminal special characters we're - interested in back to rl_insert and read the new ones. */ -static void -reset_default_bindings () -{ - if (_rl_bind_stty_chars) - { - rl_tty_unset_default_bindings (_rl_keymap); - rl_tty_set_default_bindings (_rl_keymap); - } -} - -/* Bind some common arrow key sequences in MAP. */ -static void -bind_arrow_keys_internal (map) - Keymap map; -{ - Keymap xkeymap; - - xkeymap = _rl_keymap; - _rl_keymap = map; - -#if defined (__MSDOS__) - rl_bind_keyseq_if_unbound ("\033[0A", rl_get_previous_history); - rl_bind_keyseq_if_unbound ("\033[0B", rl_backward_char); - rl_bind_keyseq_if_unbound ("\033[0C", rl_forward_char); - rl_bind_keyseq_if_unbound ("\033[0D", rl_get_next_history); -#endif - - rl_bind_keyseq_if_unbound ("\033[A", rl_get_previous_history); - rl_bind_keyseq_if_unbound ("\033[B", rl_get_next_history); - rl_bind_keyseq_if_unbound ("\033[C", rl_forward_char); - rl_bind_keyseq_if_unbound ("\033[D", rl_backward_char); - rl_bind_keyseq_if_unbound ("\033[H", rl_beg_of_line); - rl_bind_keyseq_if_unbound ("\033[F", rl_end_of_line); - - rl_bind_keyseq_if_unbound ("\033OA", rl_get_previous_history); - rl_bind_keyseq_if_unbound ("\033OB", rl_get_next_history); - rl_bind_keyseq_if_unbound ("\033OC", rl_forward_char); - rl_bind_keyseq_if_unbound ("\033OD", rl_backward_char); - rl_bind_keyseq_if_unbound ("\033OH", rl_beg_of_line); - rl_bind_keyseq_if_unbound ("\033OF", rl_end_of_line); - -#if defined (__MINGW32__) - rl_bind_keyseq_if_unbound ("\340H", rl_get_previous_history); - rl_bind_keyseq_if_unbound ("\340P", rl_get_next_history); - rl_bind_keyseq_if_unbound ("\340M", rl_forward_char); - rl_bind_keyseq_if_unbound ("\340K", rl_backward_char); -#endif - - _rl_keymap = xkeymap; -} - -/* Try and bind the common arrow key prefixes after giving termcap and - the inputrc file a chance to bind them and create `real' keymaps - for the arrow key prefix. */ -static void -bind_arrow_keys () -{ - bind_arrow_keys_internal (emacs_standard_keymap); - -#if defined (VI_MODE) - bind_arrow_keys_internal (vi_movement_keymap); - bind_arrow_keys_internal (vi_insertion_keymap); -#endif -} - -/* **************************************************************** */ -/* */ -/* Saving and Restoring Readline's state */ -/* */ -/* **************************************************************** */ - -int -rl_save_state (sp) - struct readline_state *sp; -{ - if (sp == 0) - return -1; - - sp->point = rl_point; - sp->end = rl_end; - sp->mark = rl_mark; - sp->buffer = rl_line_buffer; - sp->buflen = rl_line_buffer_len; - sp->ul = rl_undo_list; - sp->prompt = rl_prompt; - - sp->rlstate = rl_readline_state; - sp->done = rl_done; - sp->kmap = _rl_keymap; - - sp->lastfunc = rl_last_func; - sp->insmode = rl_insert_mode; - sp->edmode = rl_editing_mode; - sp->kseqlen = rl_key_sequence_length; - sp->inf = rl_instream; - sp->outf = rl_outstream; - sp->pendingin = rl_pending_input; - sp->macro = rl_executing_macro; - - sp->catchsigs = rl_catch_signals; - sp->catchsigwinch = rl_catch_sigwinch; - - return (0); -} - -int -rl_restore_state (sp) - struct readline_state *sp; -{ - if (sp == 0) - return -1; - - rl_point = sp->point; - rl_end = sp->end; - rl_mark = sp->mark; - the_line = rl_line_buffer = sp->buffer; - rl_line_buffer_len = sp->buflen; - rl_undo_list = sp->ul; - rl_prompt = sp->prompt; - - rl_readline_state = sp->rlstate; - rl_done = sp->done; - _rl_keymap = sp->kmap; - - rl_last_func = sp->lastfunc; - rl_insert_mode = sp->insmode; - rl_editing_mode = sp->edmode; - rl_key_sequence_length = sp->kseqlen; - rl_instream = sp->inf; - rl_outstream = sp->outf; - rl_pending_input = sp->pendingin; - rl_executing_macro = sp->macro; - - rl_catch_signals = sp->catchsigs; - rl_catch_sigwinch = sp->catchsigwinch; - - return (0); -} diff --git a/lib/readline/readline.h~ b/lib/readline/readline.h~ deleted file mode 100644 index ea57b968b..000000000 --- a/lib/readline/readline.h~ +++ /dev/null @@ -1,868 +0,0 @@ -/* Readline.h -- the names of functions callable from within readline. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#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 0x0600 /* Readline 6.0 */ -#define RL_VERSION_MAJOR 6 -#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_insert_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_rubout 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)); - -extern void rl_vi_start_inserting PARAMS((int, int, 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 char *rl_variable_value PARAMS((const char *)); -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 void rl_reset_screen_size PARAMS((void)); - -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)); -extern void rl_free PARAMS((void *)); - -/* 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 prompt string that is actually displayed by rl_redisplay. Public so - applications can more easily supply their own redisplay functions. */ -extern char *rl_display_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, Readline gives values of LINES and COLUMNS from the environment - greater precedence than values fetched from the kernel when computing the - screen dimensions. */ -extern int rl_prefer_env_winsize; - -/* 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; - -/* Optional generator for menu completion. Default is - rl_completion_entry_function (rl_filename_completion_function). */ - extern rl_compentry_func_t *rl_menu_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; - -/* Set to the last key used to invoke one of the completion functions */ -extern int rl_completion_invoking_key; - -/* 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, readline will sort the completion matches. On by default. */ -extern int rl_sort_completion_matches; - -/* 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; - -/* Input error; can be returned by (*rl_getc_function) if readline is reading - a top-level command (RL_ISSTATE (RL_STATE_READCMD)). */ -#define READERR (-2) - -/* 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 0x000000 /* no state; before first call */ - -#define RL_STATE_INITIALIZING 0x000001 /* initializing */ -#define RL_STATE_INITIALIZED 0x000002 /* initialization done */ -#define RL_STATE_TERMPREPPED 0x000004 /* terminal is prepped */ -#define RL_STATE_READCMD 0x000008 /* reading a command key */ -#define RL_STATE_METANEXT 0x000010 /* reading input after ESC */ -#define RL_STATE_DISPATCHING 0x000020 /* dispatching to a command */ -#define RL_STATE_MOREINPUT 0x000040 /* reading more input in a command function */ -#define RL_STATE_ISEARCH 0x000080 /* doing incremental search */ -#define RL_STATE_NSEARCH 0x000100 /* doing non-inc search */ -#define RL_STATE_SEARCH 0x000200 /* doing a history search */ -#define RL_STATE_NUMERICARG 0x000400 /* reading numeric argument */ -#define RL_STATE_MACROINPUT 0x000800 /* getting input from a macro */ -#define RL_STATE_MACRODEF 0x001000 /* defining keyboard macro */ -#define RL_STATE_OVERWRITE 0x002000 /* overwrite mode */ -#define RL_STATE_COMPLETING 0x004000 /* doing completion */ -#define RL_STATE_SIGHANDLER 0x008000 /* in readline sighandler */ -#define RL_STATE_UNDOING 0x010000 /* doing an undo */ -#define RL_STATE_INPUTPENDING 0x020000 /* rl_execute_next called */ -#define RL_STATE_TTYCSAVED 0x040000 /* tty special chars saved */ -#define RL_STATE_CALLBACK 0x080000 /* using the callback interface */ -#define RL_STATE_VIMOTION 0x100000 /* reading vi motion arg */ -#define RL_STATE_MULTIKEY 0x200000 /* reading multiple-key command */ -#define RL_STATE_VICMDONCE 0x400000 /* entered vi command mode at least once */ - -#define RL_STATE_DONE 0x800000 /* 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; - - /* search state */ - - /* completion state */ - - /* options state */ - - /* 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/rldefs.h~ b/lib/readline/rldefs.h~ deleted file mode 100644 index 0f6c87446..000000000 --- a/lib/readline/rldefs.h~ +++ /dev/null @@ -1,160 +0,0 @@ -/* rldefs.h -- an attempt to isolate some of the system-specific defines - for readline. This should be included after any files that define - system-specific constants like _POSIX_VERSION or USG. */ - -/* Copyright (C) 1987-2005 Free Software Foundation, Inc. - - This file contains the Readline Library (the Library), a set of - routines for providing Emacs style line input to programs that ask - for it. - - The Library is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 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. */ - -#if !defined (_RLDEFS_H_) -#define _RLDEFS_H_ - -#if defined (HAVE_CONFIG_H) -# include "config.h" -#endif - -#include "rlstdc.h" - -#if defined (_POSIX_VERSION) && !defined (TERMIOS_MISSING) -# define TERMIOS_TTY_DRIVER -#else -# if defined (HAVE_TERMIO_H) -# define TERMIO_TTY_DRIVER -# else -# if !defined (__MINGW32__) -# define NEW_TTY_DRIVER -# else -# define NO_TTY_DRIVER -# endif -# endif -#endif - -/* Posix macro to check file in statbuf for directory-ness. - This requires that be included before this test. */ -#if defined (S_IFDIR) && !defined (S_ISDIR) -# define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) -#endif - -/* Decide which flavor of the header file describing the C library - string functions to include and include it. */ - -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ - -#if !defined (strchr) && !defined (__STDC__) -extern char *strchr (), *strrchr (); -#endif /* !strchr && !__STDC__ */ - -#if defined (PREFER_STDARG) -# include -#else -# if defined (PREFER_VARARGS) -# include -# endif -#endif - -#if defined (HAVE_STRCASECMP) -#define _rl_stricmp strcasecmp -#define _rl_strnicmp strncasecmp -#else -extern int _rl_stricmp PARAMS((char *, char *)); -extern int _rl_strnicmp PARAMS((char *, char *, int)); -#endif - -#if defined (HAVE_STRPBRK) && !defined (HAVE_MULTIBYTE) -# define _rl_strpbrk(a,b) strpbrk((a),(b)) -#else -extern char *_rl_strpbrk PARAMS((const char *, const char *)); -#endif - -#if !defined (emacs_mode) -# define no_mode -1 -# define vi_mode 0 -# define emacs_mode 1 -#endif - -#if !defined (RL_IM_INSERT) -# define RL_IM_INSERT 1 -# define RL_IM_OVERWRITE 0 -# -# define RL_IM_DEFAULT RL_IM_INSERT -#endif - -/* If you cast map[key].function to type (Keymap) on a Cray, - the compiler takes the value of map[key].function and - divides it by 4 to convert between pointer types (pointers - to functions and pointers to structs are different sizes). - This is not what is wanted. */ -#if defined (CRAY) -# define FUNCTION_TO_KEYMAP(map, key) (Keymap)((int)map[key].function) -# define KEYMAP_TO_FUNCTION(data) (rl_command_func_t *)((int)(data)) -#else -# define FUNCTION_TO_KEYMAP(map, key) (Keymap)(map[key].function) -# define KEYMAP_TO_FUNCTION(data) (rl_command_func_t *)(data) -#endif - -#ifndef savestring -#define savestring(x) strcpy ((char *)xmalloc (1 + strlen (x)), (x)) -#endif - -/* Possible values for _rl_bell_preference. */ -#define NO_BELL 0 -#define AUDIBLE_BELL 1 -#define VISIBLE_BELL 2 - -/* Definitions used when searching the line for characters. */ -/* NOTE: it is necessary that opposite directions are inverses */ -#define FTO 1 /* forward to */ -#define BTO -1 /* backward to */ -#define FFIND 2 /* forward find */ -#define BFIND -2 /* backward find */ - -/* Possible values for the found_quote flags word used by the completion - functions. It says what kind of (shell-like) quoting we found anywhere - in the line. */ -#define RL_QF_SINGLE_QUOTE 0x01 -#define RL_QF_DOUBLE_QUOTE 0x02 -#define RL_QF_BACKSLASH 0x04 -#define RL_QF_OTHER_QUOTE 0x08 - -/* Default readline line buffer length. */ -#define DEFAULT_BUFFER_SIZE 256 - -#if !defined (STREQ) -#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0)) -#define STREQN(a, b, n) (((n) == 0) ? (1) \ - : ((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0)) -#endif - -#if !defined (FREE) -# define FREE(x) if (x) free (x) -#endif - -#if !defined (SWAP) -# define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) -#endif - -/* CONFIGURATION SECTION */ -#include "rlconf.h" - -#endif /* !_RLDEFS_H_ */ diff --git a/lib/readline/rlprivate.h~ b/lib/readline/rlprivate.h~ deleted file mode 100644 index a9ef8248b..000000000 --- a/lib/readline/rlprivate.h~ +++ /dev/null @@ -1,470 +0,0 @@ -/* rlprivate.h -- functions and variables global to the readline library, - but not intended for use by applications. */ - -/* Copyright (C) 1999-2009 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#if !defined (_RL_PRIVATE_H_) -#define _RL_PRIVATE_H_ - -#include "rlconf.h" /* for VISIBLE_STATS */ -#include "rlstdc.h" -#include "posixjmp.h" /* defines procenv_t */ - -/************************************************************************* - * * - * Convenience definitions * - * * - *************************************************************************/ - -#define EMACS_MODE() (rl_editing_mode == emacs_mode) -#define VI_COMMAND_MODE() (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap) -#define VI_INSERT_MODE() (rl_editing_mode == vi_mode && _rl_keymap == vi_insertion_keymap) - -#define RL_CHECK_SIGNALS() \ - do { \ - if (_rl_caught_signal) _rl_signal_handler (_rl_caught_signal); \ - } while (0) - -/************************************************************************* - * * - * Global structs undocumented in texinfo manual and not in readline.h * - * * - *************************************************************************/ -/* search types */ -#define RL_SEARCH_ISEARCH 0x01 /* incremental search */ -#define RL_SEARCH_NSEARCH 0x02 /* non-incremental search */ -#define RL_SEARCH_CSEARCH 0x04 /* intra-line char search */ - -/* search flags */ -#define SF_REVERSE 0x01 -#define SF_FOUND 0x02 -#define SF_FAILED 0x04 - -typedef struct __rl_search_context -{ - int type; - int sflags; - - char *search_string; - int search_string_index; - int search_string_size; - - char **lines; - char *allocated_line; - int hlen; - int hindex; - - int save_point; - int save_mark; - int save_line; - int last_found_line; - char *prev_line_found; - - UNDO_LIST *save_undo_list; - - int history_pos; - int direction; - - int lastc; -#if defined (HANDLE_MULTIBYTE) - char mb[MB_LEN_MAX]; -#endif - - char *sline; - int sline_len; - int sline_index; - - char *search_terminators; -} _rl_search_cxt; - -/* Callback data for reading numeric arguments */ -#define NUM_SAWMINUS 0x01 -#define NUM_SAWDIGITS 0x02 -#define NUM_READONE 0x04 - -typedef int _rl_arg_cxt; - -/* A context for reading key sequences longer than a single character when - using the callback interface. */ -#define KSEQ_DISPATCHED 0x01 -#define KSEQ_SUBSEQ 0x02 -#define KSEQ_RECURSIVE 0x04 - -typedef struct __rl_keyseq_context -{ - int flags; - int subseq_arg; - int subseq_retval; /* XXX */ - Keymap dmap; - - Keymap oldmap; - int okey; - struct __rl_keyseq_context *ocxt; - int childval; -} _rl_keyseq_cxt; - - /* fill in more as needed */ -/* `Generic' callback data and functions */ -typedef struct __rl_callback_generic_arg -{ - int count; - int i1, i2; - /* add here as needed */ -} _rl_callback_generic_arg; - -typedef int _rl_callback_func_t PARAMS((_rl_callback_generic_arg *)); - -/************************************************************************* - * * - * 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 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)); - -extern _rl_keyseq_cxt *_rl_keyseq_cxt_alloc PARAMS((void)); -extern void _rl_keyseq_cxt_dispose PARAMS((_rl_keyseq_cxt *)); -extern void _rl_keyseq_chain_dispose PARAMS((void)); - -extern int _rl_dispatch_callback PARAMS((_rl_keyseq_cxt *)); - -/* callback.c */ -extern _rl_callback_generic_arg *_rl_callback_data_alloc PARAMS((int)); -extern void _rl_callback_data_dispose PARAMS((_rl_callback_generic_arg *)); - -#endif /* READLINE_CALLBACKS */ - -/* bind.c */ - -/* complete.c */ -extern void _rl_reset_completion_state PARAMS((void)); -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)); - -/* isearch.c */ -extern _rl_search_cxt *_rl_scxt_alloc PARAMS((int, int)); -extern void _rl_scxt_dispose PARAMS((_rl_search_cxt *, int)); - -extern int _rl_isearch_dispatch PARAMS((_rl_search_cxt *, int)); -extern int _rl_isearch_callback PARAMS((_rl_search_cxt *)); - -extern int _rl_search_getchar PARAMS((_rl_search_cxt *)); - -/* 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_arg_overflow PARAMS((void)); -extern void _rl_arg_init PARAMS((void)); -extern int _rl_arg_getchar PARAMS((void)); -extern int _rl_arg_callback PARAMS((_rl_arg_cxt)); -extern void _rl_reset_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)); - -extern void _rl_revert_all_lines PARAMS((void)); - -/* 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)); -extern void _rl_internal_char_cleanup PARAMS((void)); - -/* rltty.c */ -extern int _rl_disable_tty_signals PARAMS((void)); -extern int _rl_restore_tty_signals PARAMS((void)); - -/* search.c */ -extern int _rl_nsearch_callback PARAMS((_rl_search_cxt *)); - -/* signals.c */ -extern void _rl_signal_handler PARAMS((int)); - -extern void _rl_block_sigint PARAMS((void)); -extern void _rl_release_sigint 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)); - -/* undo.c */ -extern UNDO_LIST *_rl_copy_undo_entry PARAMS((UNDO_LIST *)); -extern UNDO_LIST *_rl_copy_undo_list PARAMS((UNDO_LIST *)); - -/* util.c */ -#if defined (USE_VARARGS) && defined (PREFER_STDARG) -extern void _rl_ttymsg (const char *, ...) __attribute__((__format__ (printf, 1, 2))); -extern void _rl_errmsg (const char *, ...) __attribute__((__format__ (printf, 1, 2))); -extern void _rl_trace (const char *, ...) __attribute__((__format__ (printf, 1, 2))); -#else -extern void _rl_ttymsg (); -extern void _rl_errmsg (); -extern void _rl_trace (); -#endif - -extern int _rl_tropen PARAMS((void)); - -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((void)); -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 * const _rl_possible_control_prefixes[]; -extern const char * const _rl_possible_meta_prefixes[]; - -/* callback.c */ -extern _rl_callback_func_t *_rl_callback_func; -extern _rl_callback_generic_arg *_rl_callback_data; - -/* 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_completion_prefix_display_length; -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 int _rl_want_redisplay; - -/* isearch.c */ -extern char *_rl_isearch_terminators; - -extern _rl_search_cxt *_rl_iscxt; - -/* macro.c */ -extern char *_rl_executing_macro; - -/* misc.c */ -extern int _rl_history_preserve_point; -extern int _rl_history_saved_point; - -extern _rl_arg_cxt _rl_argcxt; - -/* readline.c */ -extern int _rl_echoing_p; -extern int _rl_horizontal_scroll_mode; -extern int _rl_mark_modified_lines; -extern int _rl_bell_preference; -extern int _rl_meta_flag; -extern int _rl_convert_meta_chars_to_ascii; -extern int _rl_output_meta_chars; -extern int _rl_bind_stty_chars; -extern int _rl_revert_all_at_newline; -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 _rl_top_level; -extern _rl_keyseq_cxt *_rl_kscxt; - -/* search.c */ -extern _rl_search_cxt *_rl_nscxt; - -/* signals.c */ -extern int _rl_interrupt_immediately; -extern int _rl_caught_signal; - -extern int _rl_echoctl; - -extern int _rl_intr_char; -extern int _rl_quit_char; -extern int _rl_susp_char; - -/* 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 char *_rl_term_forward_char; -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/rltty.c~ b/lib/readline/rltty.c~ deleted file mode 100644 index c7552e50b..000000000 --- a/lib/readline/rltty.c~ +++ /dev/null @@ -1,971 +0,0 @@ -/* rltty.c -- functions to prepare and restore the terminal for readline's - use. */ - -/* Copyright (C) 1992-2005 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#include "rldefs.h" - -#if defined (GWINSZ_IN_SYS_IOCTL) -# include -#endif /* GWINSZ_IN_SYS_IOCTL */ - -#include "rltty.h" -#include "readline.h" -#include "rlprivate.h" - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -rl_vintfunc_t *rl_prep_term_function = rl_prep_terminal; -rl_voidfunc_t *rl_deprep_term_function = rl_deprep_terminal; - -static void set_winsize PARAMS((int)); - -/* **************************************************************** */ -/* */ -/* Saving and Restoring the TTY */ -/* */ -/* **************************************************************** */ - -/* Non-zero means that the terminal is in a prepped state. */ -static int terminal_prepped; - -static _RL_TTY_CHARS _rl_tty_chars, _rl_last_tty_chars; - -/* If non-zero, means that this process has called tcflow(fd, TCOOFF) - and output is suspended. */ -#if defined (__ksr1__) -static int ksrflow; -#endif - -/* Dummy call to force a backgrounded readline to stop before it tries - to get the tty settings. */ -static void -set_winsize (tty) - int tty; -{ -#if defined (TIOCGWINSZ) - struct winsize w; - - if (ioctl (tty, TIOCGWINSZ, &w) == 0) - (void) ioctl (tty, TIOCSWINSZ, &w); -#endif /* TIOCGWINSZ */ -} - -#if defined (NO_TTY_DRIVER) -/* Nothing */ -#elif defined (NEW_TTY_DRIVER) - -/* Values for the `flags' field of a struct bsdtty. This tells which - elements of the struct bsdtty have been fetched from the system and - are valid. */ -#define SGTTY_SET 0x01 -#define LFLAG_SET 0x02 -#define TCHARS_SET 0x04 -#define LTCHARS_SET 0x08 - -struct bsdtty { - struct sgttyb sgttyb; /* Basic BSD tty driver information. */ - int lflag; /* Local mode flags, like LPASS8. */ -#if defined (TIOCGETC) - struct tchars tchars; /* Terminal special characters, including ^S and ^Q. */ -#endif -#if defined (TIOCGLTC) - struct ltchars ltchars; /* 4.2 BSD editing characters */ -#endif - int flags; /* Bitmap saying which parts of the struct are valid. */ -}; - -#define TIOTYPE struct bsdtty - -static TIOTYPE otio; - -static void save_tty_chars PARAMS((TIOTYPE *)); -static int _get_tty_settings PARAMS((int, TIOTYPE *)); -static int get_tty_settings PARAMS((int, TIOTYPE *)); -static int _set_tty_settings PARAMS((int, TIOTYPE *)); -static int set_tty_settings PARAMS((int, TIOTYPE *)); - -static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); - -static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t)); - -static void -save_tty_chars (tiop) - TIOTYPE *tiop; -{ - _rl_last_tty_chars = _rl_tty_chars; - - if (tiop->flags & SGTTY_SET) - { - _rl_tty_chars.t_erase = tiop->sgttyb.sg_erase; - _rl_tty_chars.t_kill = tiop->sgttyb.sg_kill; - } - - if (tiop->flags & TCHARS_SET) - { - _rl_intr_char = _rl_tty_chars.t_intr = tiop->tchars.t_intrc; - _rl_quit_char = _rl_tty_chars.t_quit = tiop->tchars.t_quitc; - - _rl_tty_chars.t_start = tiop->tchars.t_startc; - _rl_tty_chars.t_stop = tiop->tchars.t_stopc; - _rl_tty_chars.t_eof = tiop->tchars.t_eofc; - _rl_tty_chars.t_eol = '\n'; - _rl_tty_chars.t_eol2 = tiop->tchars.t_brkc; - } - - if (tiop->flags & LTCHARS_SET) - { - _rl_susp_char = _rl_tty_chars.t_susp = tiop->ltchars.t_suspc; - - _rl_tty_chars.t_dsusp = tiop->ltchars.t_dsuspc; - _rl_tty_chars.t_reprint = tiop->ltchars.t_rprntc; - _rl_tty_chars.t_flush = tiop->ltchars.t_flushc; - _rl_tty_chars.t_werase = tiop->ltchars.t_werasc; - _rl_tty_chars.t_lnext = tiop->ltchars.t_lnextc; - } - - _rl_tty_chars.t_status = -1; -} - -static int -get_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - set_winsize (tty); - - tiop->flags = tiop->lflag = 0; - - errno = 0; - if (ioctl (tty, TIOCGETP, &(tiop->sgttyb)) < 0) - return -1; - tiop->flags |= SGTTY_SET; - -#if defined (TIOCLGET) - if (ioctl (tty, TIOCLGET, &(tiop->lflag)) == 0) - tiop->flags |= LFLAG_SET; -#endif - -#if defined (TIOCGETC) - if (ioctl (tty, TIOCGETC, &(tiop->tchars)) == 0) - tiop->flags |= TCHARS_SET; -#endif - -#if defined (TIOCGLTC) - if (ioctl (tty, TIOCGLTC, &(tiop->ltchars)) == 0) - tiop->flags |= LTCHARS_SET; -#endif - - return 0; -} - -static int -set_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - if (tiop->flags & SGTTY_SET) - { - ioctl (tty, TIOCSETN, &(tiop->sgttyb)); - tiop->flags &= ~SGTTY_SET; - } - _rl_echoing_p = 1; - -#if defined (TIOCLSET) - if (tiop->flags & LFLAG_SET) - { - ioctl (tty, TIOCLSET, &(tiop->lflag)); - tiop->flags &= ~LFLAG_SET; - } -#endif - -#if defined (TIOCSETC) - if (tiop->flags & TCHARS_SET) - { - ioctl (tty, TIOCSETC, &(tiop->tchars)); - tiop->flags &= ~TCHARS_SET; - } -#endif - -#if defined (TIOCSLTC) - if (tiop->flags & LTCHARS_SET) - { - ioctl (tty, TIOCSLTC, &(tiop->ltchars)); - tiop->flags &= ~LTCHARS_SET; - } -#endif - - return 0; -} - -static void -prepare_terminal_settings (meta_flag, oldtio, tiop) - int meta_flag; - TIOTYPE oldtio, *tiop; -{ - _rl_echoing_p = (oldtio.sgttyb.sg_flags & ECHO); - - /* Copy the original settings to the structure we're going to use for - our settings. */ - tiop->sgttyb = oldtio.sgttyb; - tiop->lflag = oldtio.lflag; -#if defined (TIOCGETC) - tiop->tchars = oldtio.tchars; -#endif -#if defined (TIOCGLTC) - tiop->ltchars = oldtio.ltchars; -#endif - tiop->flags = oldtio.flags; - - /* First, the basic settings to put us into character-at-a-time, no-echo - input mode. */ - tiop->sgttyb.sg_flags &= ~(ECHO | CRMOD); - tiop->sgttyb.sg_flags |= CBREAK; - - /* If this terminal doesn't care how the 8th bit is used, then we can - use it for the meta-key. If only one of even or odd parity is - specified, then the terminal is using parity, and we cannot. */ -#if !defined (ANYP) -# define ANYP (EVENP | ODDP) -#endif - if (((oldtio.sgttyb.sg_flags & ANYP) == ANYP) || - ((oldtio.sgttyb.sg_flags & ANYP) == 0)) - { - tiop->sgttyb.sg_flags |= ANYP; - - /* Hack on local mode flags if we can. */ -#if defined (TIOCLGET) -# if defined (LPASS8) - tiop->lflag |= LPASS8; -# endif /* LPASS8 */ -#endif /* TIOCLGET */ - } - -#if defined (TIOCGETC) -# if defined (USE_XON_XOFF) - /* Get rid of terminal output start and stop characters. */ - tiop->tchars.t_stopc = -1; /* C-s */ - tiop->tchars.t_startc = -1; /* C-q */ - - /* If there is an XON character, bind it to restart the output. */ - if (oldtio.tchars.t_startc != -1) - rl_bind_key (oldtio.tchars.t_startc, rl_restart_output); -# endif /* USE_XON_XOFF */ - - /* If there is an EOF char, bind _rl_eof_char to it. */ - if (oldtio.tchars.t_eofc != -1) - _rl_eof_char = oldtio.tchars.t_eofc; - -# if defined (NO_KILL_INTR) - /* Get rid of terminal-generated SIGQUIT and SIGINT. */ - tiop->tchars.t_quitc = -1; /* C-\ */ - tiop->tchars.t_intrc = -1; /* C-c */ -# endif /* NO_KILL_INTR */ -#endif /* TIOCGETC */ - -#if defined (TIOCGLTC) - /* Make the interrupt keys go away. Just enough to make people happy. */ - tiop->ltchars.t_dsuspc = -1; /* C-y */ - tiop->ltchars.t_lnextc = -1; /* C-v */ -#endif /* TIOCGLTC */ -} - -#else /* !defined (NEW_TTY_DRIVER) */ - -#if !defined (VMIN) -# define VMIN VEOF -#endif - -#if !defined (VTIME) -# define VTIME VEOL -#endif - -#if defined (TERMIOS_TTY_DRIVER) -# define TIOTYPE struct termios -# define DRAIN_OUTPUT(fd) tcdrain (fd) -# define GETATTR(tty, tiop) (tcgetattr (tty, tiop)) -# ifdef M_UNIX -# define SETATTR(tty, tiop) (tcsetattr (tty, TCSANOW, tiop)) -# else -# define SETATTR(tty, tiop) (tcsetattr (tty, TCSADRAIN, tiop)) -# endif /* !M_UNIX */ -#else -# define TIOTYPE struct termio -# define DRAIN_OUTPUT(fd) -# define GETATTR(tty, tiop) (ioctl (tty, TCGETA, tiop)) -# define SETATTR(tty, tiop) (ioctl (tty, TCSETAW, tiop)) -#endif /* !TERMIOS_TTY_DRIVER */ - -static TIOTYPE otio; - -static void save_tty_chars PARAMS((TIOTYPE *)); -static int _get_tty_settings PARAMS((int, TIOTYPE *)); -static int get_tty_settings PARAMS((int, TIOTYPE *)); -static int _set_tty_settings PARAMS((int, TIOTYPE *)); -static int set_tty_settings PARAMS((int, TIOTYPE *)); - -static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); - -static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t)); -static void _rl_bind_tty_special_chars PARAMS((Keymap, TIOTYPE)); - -#if defined (FLUSHO) -# define OUTPUT_BEING_FLUSHED(tp) (tp->c_lflag & FLUSHO) -#else -# define OUTPUT_BEING_FLUSHED(tp) 0 -#endif - -static void -save_tty_chars (tiop) - TIOTYPE *tiop; -{ - _rl_last_tty_chars = _rl_tty_chars; - - _rl_tty_chars.t_eof = tiop->c_cc[VEOF]; - _rl_tty_chars.t_eol = tiop->c_cc[VEOL]; -#ifdef VEOL2 - _rl_tty_chars.t_eol2 = tiop->c_cc[VEOL2]; -#endif - _rl_tty_chars.t_erase = tiop->c_cc[VERASE]; -#ifdef VWERASE - _rl_tty_chars.t_werase = tiop->c_cc[VWERASE]; -#endif - _rl_tty_chars.t_kill = tiop->c_cc[VKILL]; -#ifdef VREPRINT - _rl_tty_chars.t_reprint = tiop->c_cc[VREPRINT]; -#endif - _rl_intr_char = _rl_tty_chars.t_intr = tiop->c_cc[VINTR]; - _rl_quit_char = _rl_tty_chars.t_quit = tiop->c_cc[VQUIT]; -#ifdef VSUSP - _rl_susp_char = _rl_tty_chars.t_susp = tiop->c_cc[VSUSP]; -#endif -#ifdef VDSUSP - _rl_tty_chars.t_dsusp = tiop->c_cc[VDSUSP]; -#endif -#ifdef VSTART - _rl_tty_chars.t_start = tiop->c_cc[VSTART]; -#endif -#ifdef VSTOP - _rl_tty_chars.t_stop = tiop->c_cc[VSTOP]; -#endif -#ifdef VLNEXT - _rl_tty_chars.t_lnext = tiop->c_cc[VLNEXT]; -#endif -#ifdef VDISCARD - _rl_tty_chars.t_flush = tiop->c_cc[VDISCARD]; -#endif -#ifdef VSTATUS - _rl_tty_chars.t_status = tiop->c_cc[VSTATUS]; -#endif -} - -#if defined (_AIX) || defined (_AIX41) -/* Currently this is only used on AIX */ -static void -rltty_warning (msg) - char *msg; -{ - _rl_errmsg ("warning: %s", msg); -} -#endif - -#if defined (_AIX) -void -setopost(tp) -TIOTYPE *tp; -{ - if ((tp->c_oflag & OPOST) == 0) - { - _rl_errmsg ("warning: turning on OPOST for terminal\r"); - tp->c_oflag |= OPOST|ONLCR; - } -} -#endif - -static int -_get_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - int ioctl_ret; - - while (1) - { - ioctl_ret = GETATTR (tty, tiop); - if (ioctl_ret < 0) - { - if (errno != EINTR) - return -1; - else - continue; - } - if (OUTPUT_BEING_FLUSHED (tiop)) - { -#if defined (FLUSHO) - _rl_errmsg ("warning: turning off output flushing"); - tiop->c_lflag &= ~FLUSHO; - break; -#else - continue; -#endif - } - break; - } - - return 0; -} - -static int -get_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - set_winsize (tty); - - errno = 0; - if (_get_tty_settings (tty, tiop) < 0) - return -1; - -#if defined (_AIX) - setopost(tiop); -#endif - - return 0; -} - -static int -_set_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - while (SETATTR (tty, tiop) < 0) - { - if (errno != EINTR) - return -1; - errno = 0; - } - return 0; -} - -static int -set_tty_settings (tty, tiop) - int tty; - TIOTYPE *tiop; -{ - if (_set_tty_settings (tty, tiop) < 0) - return -1; - -#if 0 - -#if defined (TERMIOS_TTY_DRIVER) -# if defined (__ksr1__) - if (ksrflow) - { - ksrflow = 0; - tcflow (tty, TCOON); - } -# else /* !ksr1 */ - tcflow (tty, TCOON); /* Simulate a ^Q. */ -# endif /* !ksr1 */ -#else - ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */ -#endif /* !TERMIOS_TTY_DRIVER */ - -#endif /* 0 */ - - return 0; -} - -static void -prepare_terminal_settings (meta_flag, oldtio, tiop) - int meta_flag; - TIOTYPE oldtio, *tiop; -{ - _rl_echoing_p = (oldtio.c_lflag & ECHO); - - tiop->c_lflag &= ~(ICANON | ECHO); - - if ((unsigned char) oldtio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE) - _rl_eof_char = oldtio.c_cc[VEOF]; - -#if defined (USE_XON_XOFF) -#if defined (IXANY) - tiop->c_iflag &= ~(IXON | IXOFF | IXANY); -#else - /* `strict' Posix systems do not define IXANY. */ - tiop->c_iflag &= ~(IXON | IXOFF); -#endif /* IXANY */ -#endif /* USE_XON_XOFF */ - - /* Only turn this off if we are using all 8 bits. */ - if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag) - tiop->c_iflag &= ~(ISTRIP | INPCK); - - /* Make sure we differentiate between CR and NL on input. */ - tiop->c_iflag &= ~(ICRNL | INLCR); - -#if !defined (HANDLE_SIGNALS) - tiop->c_lflag &= ~ISIG; -#else - tiop->c_lflag |= ISIG; -#endif - - tiop->c_cc[VMIN] = 1; - tiop->c_cc[VTIME] = 0; - -#if defined (FLUSHO) - if (OUTPUT_BEING_FLUSHED (tiop)) - { - tiop->c_lflag &= ~FLUSHO; - oldtio.c_lflag &= ~FLUSHO; - } -#endif - - /* Turn off characters that we need on Posix systems with job control, - just to be sure. This includes ^Y and ^V. This should not really - be necessary. */ -#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_VDISABLE) - -#if defined (VLNEXT) - tiop->c_cc[VLNEXT] = _POSIX_VDISABLE; -#endif - -#if defined (VDSUSP) - tiop->c_cc[VDSUSP] = _POSIX_VDISABLE; -#endif - -#endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */ -} -#endif /* !NEW_TTY_DRIVER */ - -/* Put the terminal in CBREAK mode so that we can detect key presses. */ -#if defined (NO_TTY_DRIVER) -void -rl_prep_terminal (meta_flag) - int meta_flag; -{ - _rl_echoing_p = 1; -} - -void -rl_deprep_terminal () -{ -} - -#else /* ! NO_TTY_DRIVER */ -void -rl_prep_terminal (meta_flag) - int meta_flag; -{ - int tty; - TIOTYPE tio; - - if (terminal_prepped) - return; - - /* Try to keep this function from being INTerrupted. */ - _rl_block_sigint (); - - tty = fileno (rl_instream); - - if (get_tty_settings (tty, &tio) < 0) - { -#if defined (ENOTSUP) - /* MacOS X and Linux, at least, lie about the value of errno if - tcgetattr fails. */ - if (errno == ENOTTY || errno == EINVAL || errno == ENOTSUP) -#else - if (errno == ENOTTY || errno == EINVAL) -#endif - _rl_echoing_p = 1; /* XXX */ - - _rl_release_sigint (); - return; - } - - otio = tio; - - if (_rl_bind_stty_chars) - { -#if defined (VI_MODE) - /* If editing in vi mode, make sure we restore the bindings in the - insertion keymap no matter what keymap we ended up in. */ - if (rl_editing_mode == vi_mode) - rl_tty_unset_default_bindings (vi_insertion_keymap); - else -#endif - rl_tty_unset_default_bindings (_rl_keymap); - } - save_tty_chars (&otio); - RL_SETSTATE(RL_STATE_TTYCSAVED); - if (_rl_bind_stty_chars) - { -#if defined (VI_MODE) - /* If editing in vi mode, make sure we set the bindings in the - insertion keymap no matter what keymap we ended up in. */ - if (rl_editing_mode == vi_mode) - _rl_bind_tty_special_chars (vi_insertion_keymap, tio); - else -#endif - _rl_bind_tty_special_chars (_rl_keymap, tio); - } - - prepare_terminal_settings (meta_flag, otio, &tio); - - if (set_tty_settings (tty, &tio) < 0) - { - _rl_release_sigint (); - return; - } - - if (_rl_enable_keypad) - _rl_control_keypad (1); - - fflush (rl_outstream); - terminal_prepped = 1; - RL_SETSTATE(RL_STATE_TERMPREPPED); - - _rl_release_sigint (); -} - -/* Restore the terminal's normal settings and modes. */ -void -rl_deprep_terminal () -{ - int tty; - - if (!terminal_prepped) - return; - - /* Try to keep this function from being interrupted. */ - _rl_block_sigint (); - - tty = fileno (rl_instream); - - if (_rl_enable_keypad) - _rl_control_keypad (0); - - fflush (rl_outstream); - - if (set_tty_settings (tty, &otio) < 0) - { - _rl_release_sigint (); - return; - } - - terminal_prepped = 0; - RL_UNSETSTATE(RL_STATE_TERMPREPPED); - - _rl_release_sigint (); -} -#endif /* !NO_TTY_DRIVER */ - -/* **************************************************************** */ -/* */ -/* Bogus Flow Control */ -/* */ -/* **************************************************************** */ - -int -rl_restart_output (count, key) - int count, key; -{ -#if defined (__MINGW32__) - return 0; -#else /* !__MING32__ */ - - int fildes = fileno (rl_outstream); -#if defined (TIOCSTART) -#if defined (apollo) - ioctl (&fildes, TIOCSTART, 0); -#else - ioctl (fildes, TIOCSTART, 0); -#endif /* apollo */ - -#else /* !TIOCSTART */ -# if defined (TERMIOS_TTY_DRIVER) -# if defined (__ksr1__) - if (ksrflow) - { - ksrflow = 0; - tcflow (fildes, TCOON); - } -# else /* !ksr1 */ - tcflow (fildes, TCOON); /* Simulate a ^Q. */ -# endif /* !ksr1 */ -# else /* !TERMIOS_TTY_DRIVER */ -# if defined (TCXONC) - ioctl (fildes, TCXONC, TCOON); -# endif /* TCXONC */ -# endif /* !TERMIOS_TTY_DRIVER */ -#endif /* !TIOCSTART */ - - return 0; -#endif /* !__MINGW32__ */ -} - -int -rl_stop_output (count, key) - int count, key; -{ -#if defined (__MINGW32__) - return 0; -#else - - int fildes = fileno (rl_instream); - -#if defined (TIOCSTOP) -# if defined (apollo) - ioctl (&fildes, TIOCSTOP, 0); -# else - ioctl (fildes, TIOCSTOP, 0); -# endif /* apollo */ -#else /* !TIOCSTOP */ -# if defined (TERMIOS_TTY_DRIVER) -# if defined (__ksr1__) - ksrflow = 1; -# endif /* ksr1 */ - tcflow (fildes, TCOOFF); -# else -# if defined (TCXONC) - ioctl (fildes, TCXONC, TCOON); -# endif /* TCXONC */ -# endif /* !TERMIOS_TTY_DRIVER */ -#endif /* !TIOCSTOP */ - - return 0; -#endif /* !__MINGW32__ */ -} - -/* **************************************************************** */ -/* */ -/* Default Key Bindings */ -/* */ -/* **************************************************************** */ - -#if !defined (NO_TTY_DRIVER) -#define SET_SPECIAL(sc, func) set_special_char(kmap, &ttybuff, sc, func) -#endif - -#if defined (NO_TTY_DRIVER) - -#define SET_SPECIAL(sc, func) -#define RESET_SPECIAL(c) - -#elif defined (NEW_TTY_DRIVER) -static void -set_special_char (kmap, tiop, sc, func) - Keymap kmap; - TIOTYPE *tiop; - int sc; - rl_command_func_t *func; -{ - if (sc != -1 && kmap[(unsigned char)sc].type == ISFUNC) - kmap[(unsigned char)sc].function = func; -} - -#define RESET_SPECIAL(c) \ - if (c != -1 && kmap[(unsigned char)c].type == ISFUNC) \ - kmap[(unsigned char)c].function = rl_insert; - -static void -_rl_bind_tty_special_chars (kmap, ttybuff) - Keymap kmap; - TIOTYPE ttybuff; -{ - if (ttybuff.flags & SGTTY_SET) - { - SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout); - SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard); - } - -# if defined (TIOCGLTC) - if (ttybuff.flags & LTCHARS_SET) - { - SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout); - SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert); - } -# endif /* TIOCGLTC */ -} - -#else /* !NEW_TTY_DRIVER */ -static void -set_special_char (kmap, tiop, sc, func) - Keymap kmap; - TIOTYPE *tiop; - int sc; - rl_command_func_t *func; -{ - unsigned char uc; - - uc = tiop->c_cc[sc]; - if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) - kmap[uc].function = func; -} - -/* used later */ -#define RESET_SPECIAL(uc) \ - if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \ - kmap[uc].function = rl_insert; - -static void -_rl_bind_tty_special_chars (kmap, ttybuff) - Keymap kmap; - TIOTYPE ttybuff; -{ - SET_SPECIAL (VERASE, rl_rubout); - SET_SPECIAL (VKILL, rl_unix_line_discard); - -# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) - SET_SPECIAL (VLNEXT, rl_quoted_insert); -# endif /* VLNEXT && TERMIOS_TTY_DRIVER */ - -# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER) - SET_SPECIAL (VWERASE, rl_unix_word_rubout); -# endif /* VWERASE && TERMIOS_TTY_DRIVER */ -} - -#endif /* !NEW_TTY_DRIVER */ - -/* Set the system's default editing characters to their readline equivalents - in KMAP. Should be static, now that we have rl_tty_set_default_bindings. */ -void -rltty_set_default_bindings (kmap) - Keymap kmap; -{ -#if !defined (NO_TTY_DRIVER) - TIOTYPE ttybuff; - int tty; - - tty = fileno (rl_instream); - - if (get_tty_settings (tty, &ttybuff) == 0) - _rl_bind_tty_special_chars (kmap, ttybuff); -#endif -} - -/* New public way to set the system default editing chars to their readline - equivalents. */ -void -rl_tty_set_default_bindings (kmap) - Keymap kmap; -{ - rltty_set_default_bindings (kmap); -} - -/* Rebind all of the tty special chars that readline worries about back - to self-insert. Call this before saving the current terminal special - chars with save_tty_chars(). This only works on POSIX termios or termio - systems. */ -void -rl_tty_unset_default_bindings (kmap) - Keymap kmap; -{ - /* Don't bother before we've saved the tty special chars at least once. */ - if (RL_ISSTATE(RL_STATE_TTYCSAVED) == 0) - return; - - RESET_SPECIAL (_rl_tty_chars.t_erase); - RESET_SPECIAL (_rl_tty_chars.t_kill); - -# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) - RESET_SPECIAL (_rl_tty_chars.t_lnext); -# endif /* VLNEXT && TERMIOS_TTY_DRIVER */ - -# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER) - RESET_SPECIAL (_rl_tty_chars.t_werase); -# endif /* VWERASE && TERMIOS_TTY_DRIVER */ -} - -#if defined (HANDLE_SIGNALS) - -#if defined (NEW_TTY_DRIVER) || defined (NO_TTY_DRIVER) -int -_rl_disable_tty_signals () -{ - return 0; -} - -int -_rl_restore_tty_signals () -{ - return 0; -} -#else - -static TIOTYPE sigstty, nosigstty; -static int tty_sigs_disabled = 0; - -int -_rl_disable_tty_signals () -{ - if (tty_sigs_disabled) - return 0; - - if (_get_tty_settings (fileno (rl_instream), &sigstty) < 0) - return -1; - - nosigstty = sigstty; - - nosigstty.c_lflag &= ~ISIG; - nosigstty.c_iflag &= ~IXON; - - if (_set_tty_settings (fileno (rl_instream), &nosigstty) < 0) - return (_set_tty_settings (fileno (rl_instream), &sigstty)); - - tty_sigs_disabled = 1; - return 0; -} - -int -_rl_restore_tty_signals () -{ - int r; - - if (tty_sigs_disabled == 0) - return 0; - - r = _set_tty_settings (fileno (rl_instream), &sigstty); - - if (r == 0) - tty_sigs_disabled = 0; - - return r; -} -#endif /* !NEW_TTY_DRIVER */ - -#endif /* HANDLE_SIGNALS */ diff --git a/lib/readline/rlwinsize.h~ b/lib/readline/rlwinsize.h~ deleted file mode 100644 index 7838154d0..000000000 --- a/lib/readline/rlwinsize.h~ +++ /dev/null @@ -1,57 +0,0 @@ -/* rlwinsize.h -- an attempt to isolate some of the system-specific defines - for `struct winsize' and TIOCGWINSZ. */ - -/* Copyright (C) 1997 Free Software Foundation, Inc. - - This file contains the Readline Library (the Library), a set of - routines for providing Emacs style line input to programs that ask - for it. - - The Library is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 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. */ - -#if !defined (_RLWINSIZE_H_) -#define _RLWINSIZE_H_ - -#if defined (HAVE_CONFIG_H) -# include "config.h" -#endif - -/* Try to find the definitions of `struct winsize' and TIOGCWINSZ */ - -#if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ) -# include -#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */ - -#if defined (STRUCT_WINSIZE_IN_TERMIOS) && !defined (STRUCT_WINSIZE_IN_SYS_IOCTL) -# include -#endif /* STRUCT_WINSIZE_IN_TERMIOS && !STRUCT_WINSIZE_IN_SYS_IOCTL */ - -/* Not in either of the standard places, look around. */ -#if !defined (STRUCT_WINSIZE_IN_TERMIOS) && !defined (STRUCT_WINSIZE_IN_SYS_IOCTL) -# if defined (HAVE_SYS_STREAM_H) -# include -# endif /* HAVE_SYS_STREAM_H */ -# if defined (HAVE_SYS_PTEM_H) /* SVR4.2, at least, has it here */ -# include -# define _IO_PTEM_H /* work around SVR4.2 1.1.4 bug */ -# endif /* HAVE_SYS_PTEM_H */ -# if defined (HAVE_SYS_PTE_H) /* ??? */ -# include -# endif /* HAVE_SYS_PTE_H */ -#endif /* !STRUCT_WINSIZE_IN_TERMIOS && !STRUCT_WINSIZE_IN_SYS_IOCTL */ - -#endif /* _RL_WINSIZE_H */ - diff --git a/lib/readline/signals.c~ b/lib/readline/signals.c~ deleted file mode 100644 index 49f53ab95..000000000 --- a/lib/readline/signals.c~ +++ /dev/null @@ -1,614 +0,0 @@ -/* signals.c -- signal handling support for readline. */ - -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include /* Just for NULL. Yuck. */ -#include -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" - -#if defined (GWINSZ_IN_SYS_IOCTL) -# include -#endif /* GWINSZ_IN_SYS_IOCTL */ - -/* Some standard library routines. */ -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" - -#if defined (HANDLE_SIGNALS) - -#if !defined (RETSIGTYPE) -# if defined (VOID_SIGHANDLER) -# define RETSIGTYPE void -# else -# define RETSIGTYPE int -# endif /* !VOID_SIGHANDLER */ -#endif /* !RETSIGTYPE */ - -#if defined (VOID_SIGHANDLER) -# define SIGHANDLER_RETURN return -#else -# define SIGHANDLER_RETURN return (0) -#endif - -/* This typedef is equivalent to the one for Function; it allows us - to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */ -typedef RETSIGTYPE SigHandler (); - -#if defined (HAVE_POSIX_SIGNALS) -typedef struct sigaction sighandler_cxt; -# define rl_sigaction(s, nh, oh) sigaction(s, nh, oh) -#else -typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt; -# define sigemptyset(m) -#endif /* !HAVE_POSIX_SIGNALS */ - -#ifndef SA_RESTART -# define SA_RESTART 0 -#endif - -static SigHandler *rl_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); -static void rl_maybe_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); - -static RETSIGTYPE rl_signal_handler PARAMS((int)); -static RETSIGTYPE _rl_handle_signal PARAMS((int)); - -/* Exported variables for use by applications. */ - -/* If non-zero, readline will install its own signal handlers for - SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */ -int rl_catch_signals = 1; - -/* If non-zero, readline will install a signal handler for SIGWINCH. */ -#ifdef SIGWINCH -int rl_catch_sigwinch = 1; -#else -int rl_catch_sigwinch = 0; /* for the readline state struct in readline.c */ -#endif - -/* Private variables. */ -int _rl_interrupt_immediately = 0; -int volatile _rl_caught_signal = 0; /* should be sig_atomic_t, but that requires including everywhere */ - -/* If non-zero, print characters corresponding to received signals. */ -int _rl_echoctl = 0; - -int _rl_intr_char = 0; -int _rl_quit_char = 0; -int _rl_susp_char = 0; - -static int signals_set_flag; -static int sigwinch_set_flag; - -/* **************************************************************** */ -/* */ -/* Signal Handling */ -/* */ -/* **************************************************************** */ - -static sighandler_cxt old_int, old_term, old_alrm, old_quit; -#if defined (SIGTSTP) -static sighandler_cxt old_tstp, old_ttou, old_ttin; -#endif -#if defined (SIGWINCH) -static sighandler_cxt old_winch; -#endif - -/* Readline signal handler functions. */ - -/* Called from RL_CHECK_SIGNALS() macro */ -RETSIGTYPE -_rl_signal_handler (sig) -{ - _rl_caught_signal = 0; /* XXX */ - - _rl_handle_signal (sig); - SIGHANDLER_RETURN; -} - -static RETSIGTYPE -rl_signal_handler (sig) - int sig; -{ - _rl_caught_signal = sig; - - if (_rl_interrupt_immediately) - { - _rl_interrupt_immediately = 0; - _rl_handle_signal (sig); - } - - SIGHANDLER_RETURN; -} - -static RETSIGTYPE -_rl_handle_signal (sig) - int sig; -{ -#if defined (HAVE_POSIX_SIGNALS) - sigset_t set; -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) - long omask; -# else /* !HAVE_BSD_SIGNALS */ - sighandler_cxt dummy_cxt; /* needed for rl_set_sighandler call */ -# endif /* !HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - - RL_SETSTATE(RL_STATE_SIGHANDLER); - -#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS) - /* Since the signal will not be blocked while we are in the signal - handler, ignore it until rl_clear_signals resets the catcher. */ -# if defined (SIGALRM) - if (sig == SIGINT || sig == SIGALRM) -# else - if (sig == SIGINT) -# endif - rl_set_sighandler (sig, SIG_IGN, &dummy_cxt); -#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */ - - switch (sig) - { - case SIGINT: - _rl_reset_completion_state (); - rl_free_line_state (); - /* FALLTHROUGH */ - - case SIGTERM: -#if defined (SIGTSTP) - case SIGTSTP: - case SIGTTOU: - case SIGTTIN: -#endif /* SIGTSTP */ -#if defined (SIGALRM) - case SIGALRM: -#endif -#if defined (SIGQUIT) - case SIGQUIT: -#endif - rl_echo_signal_char (sig); - rl_cleanup_after_signal (); - -#if defined (HAVE_POSIX_SIGNALS) - sigemptyset (&set); - sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set); - sigdelset (&set, sig); -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) - omask = sigblock (0); -# endif /* HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - -#if defined (__EMX__) - signal (sig, SIG_ACK); -#endif - -#if defined (HAVE_KILL) - kill (getpid (), sig); -#else - raise (sig); /* assume we have raise */ -#endif - - /* Let the signal that we just sent through. */ -#if defined (HAVE_POSIX_SIGNALS) - sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL); -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) - sigsetmask (omask & ~(sigmask (sig))); -# endif /* HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - - rl_reset_after_signal (); - } - - RL_UNSETSTATE(RL_STATE_SIGHANDLER); - SIGHANDLER_RETURN; -} - -#if defined (SIGWINCH) -static RETSIGTYPE -rl_sigwinch_handler (sig) - int sig; -{ - SigHandler *oh; - -#if defined (MUST_REINSTALL_SIGHANDLERS) - sighandler_cxt dummy_winch; - - /* We don't want to change old_winch -- it holds the state of SIGWINCH - disposition set by the calling application. We need this state - because we call the application's SIGWINCH handler after updating - our own idea of the screen size. */ - rl_set_sighandler (SIGWINCH, rl_sigwinch_handler, &dummy_winch); -#endif - - RL_SETSTATE(RL_STATE_SIGHANDLER); - rl_resize_terminal (); - - /* If another sigwinch handler has been installed, call it. */ - oh = (SigHandler *)old_winch.sa_handler; - if (oh && oh != (SigHandler *)SIG_IGN && oh != (SigHandler *)SIG_DFL) - (*oh) (sig); - - RL_UNSETSTATE(RL_STATE_SIGHANDLER); - SIGHANDLER_RETURN; -} -#endif /* SIGWINCH */ - -/* Functions to manage signal handling. */ - -#if !defined (HAVE_POSIX_SIGNALS) -static int -rl_sigaction (sig, nh, oh) - int sig; - sighandler_cxt *nh, *oh; -{ - oh->sa_handler = signal (sig, nh->sa_handler); - return 0; -} -#endif /* !HAVE_POSIX_SIGNALS */ - -/* Set up a readline-specific signal handler, saving the old signal - information in OHANDLER. Return the old signal handler, like - signal(). */ -static SigHandler * -rl_set_sighandler (sig, handler, ohandler) - int sig; - SigHandler *handler; - sighandler_cxt *ohandler; -{ - sighandler_cxt old_handler; -#if defined (HAVE_POSIX_SIGNALS) - struct sigaction act; - - act.sa_handler = handler; -# if defined (SIGWINCH) - act.sa_flags = (sig == SIGWINCH) ? SA_RESTART : 0; -# else - act.sa_flags = 0; -# endif /* SIGWINCH */ - sigemptyset (&act.sa_mask); - sigemptyset (&ohandler->sa_mask); - sigaction (sig, &act, &old_handler); -#else - old_handler.sa_handler = (SigHandler *)signal (sig, handler); -#endif /* !HAVE_POSIX_SIGNALS */ - - /* XXX -- assume we have memcpy */ - /* If rl_set_signals is called twice in a row, don't set the old handler to - rl_signal_handler, because that would cause infinite recursion. */ - if (handler != rl_signal_handler || old_handler.sa_handler != rl_signal_handler) - memcpy (ohandler, &old_handler, sizeof (sighandler_cxt)); - - return (ohandler->sa_handler); -} - -static void -rl_maybe_set_sighandler (sig, handler, ohandler) - int sig; - SigHandler *handler; - sighandler_cxt *ohandler; -{ - sighandler_cxt dummy; - SigHandler *oh; - - sigemptyset (&dummy.sa_mask); - oh = rl_set_sighandler (sig, handler, ohandler); - if (oh == (SigHandler *)SIG_IGN) - rl_sigaction (sig, ohandler, &dummy); -} - -int -rl_set_signals () -{ - sighandler_cxt dummy; - SigHandler *oh; -#if defined (HAVE_POSIX_SIGNALS) - static int sigmask_set = 0; - static sigset_t bset, oset; -#endif - -#if defined (HAVE_POSIX_SIGNALS) - if (rl_catch_signals && sigmask_set == 0) - { - sigemptyset (&bset); - - sigaddset (&bset, SIGINT); - sigaddset (&bset, SIGTERM); -#if defined (SIGQUIT) - sigaddset (&bset, SIGQUIT); -#endif -#if defined (SIGALRM) - sigaddset (&bset, SIGALRM); -#endif -#if defined (SIGTSTP) - sigaddset (&bset, SIGTSTP); -#endif -#if defined (SIGTTIN) - sigaddset (&bset, SIGTTIN); -#endif -#if defined (SIGTTOU) - sigaddset (&bset, SIGTTOU); -#endif - sigmask_set = 1; - } -#endif /* HAVE_POSIX_SIGNALS */ - - if (rl_catch_signals && signals_set_flag == 0) - { -#if defined (HAVE_POSIX_SIGNALS) - sigemptyset (&oset); - sigprocmask (SIG_BLOCK, &bset, &oset); -#endif - - rl_maybe_set_sighandler (SIGINT, rl_signal_handler, &old_int); - rl_maybe_set_sighandler (SIGTERM, rl_signal_handler, &old_term); -#if defined (SIGQUIT) - rl_maybe_set_sighandler (SIGQUIT, rl_signal_handler, &old_quit); -#endif - -#if defined (SIGALRM) - oh = rl_set_sighandler (SIGALRM, rl_signal_handler, &old_alrm); - if (oh == (SigHandler *)SIG_IGN) - rl_sigaction (SIGALRM, &old_alrm, &dummy); -#if defined (HAVE_POSIX_SIGNALS) && defined (SA_RESTART) - /* If the application using readline has already installed a signal - handler with SA_RESTART, SIGALRM will cause reads to be restarted - automatically, so readline should just get out of the way. Since - we tested for SIG_IGN above, we can just test for SIG_DFL here. */ - if (oh != (SigHandler *)SIG_DFL && (old_alrm.sa_flags & SA_RESTART)) - rl_sigaction (SIGALRM, &old_alrm, &dummy); -#endif /* HAVE_POSIX_SIGNALS */ -#endif /* SIGALRM */ - -#if defined (SIGTSTP) - rl_maybe_set_sighandler (SIGTSTP, rl_signal_handler, &old_tstp); -#endif /* SIGTSTP */ - -#if defined (SIGTTOU) - rl_maybe_set_sighandler (SIGTTOU, rl_signal_handler, &old_ttou); -#endif /* SIGTTOU */ - -#if defined (SIGTTIN) - rl_maybe_set_sighandler (SIGTTIN, rl_signal_handler, &old_ttin); -#endif /* SIGTTIN */ - - signals_set_flag = 1; - -#if defined (HAVE_POSIX_SIGNALS) - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); -#endif - } - -#if defined (SIGWINCH) - if (rl_catch_sigwinch && sigwinch_set_flag == 0) - { - rl_maybe_set_sighandler (SIGWINCH, rl_sigwinch_handler, &old_winch); - sigwinch_set_flag = 1; - } -#endif /* SIGWINCH */ - - return 0; -} - -int -rl_clear_signals () -{ - sighandler_cxt dummy; - - if (rl_catch_signals && signals_set_flag == 1) - { - sigemptyset (&dummy.sa_mask); - - rl_sigaction (SIGINT, &old_int, &dummy); - rl_sigaction (SIGTERM, &old_term, &dummy); -#if defined (SIGQUIT) - rl_sigaction (SIGQUIT, &old_quit, &dummy); -#endif -#if defined (SIGALRM) - rl_sigaction (SIGALRM, &old_alrm, &dummy); -#endif - -#if defined (SIGTSTP) - rl_sigaction (SIGTSTP, &old_tstp, &dummy); -#endif /* SIGTSTP */ - -#if defined (SIGTTOU) - rl_sigaction (SIGTTOU, &old_ttou, &dummy); -#endif /* SIGTTOU */ - -#if defined (SIGTTIN) - rl_sigaction (SIGTTIN, &old_ttin, &dummy); -#endif /* SIGTTIN */ - - signals_set_flag = 0; - } - -#if defined (SIGWINCH) - if (rl_catch_sigwinch && sigwinch_set_flag == 1) - { - sigemptyset (&dummy.sa_mask); - rl_sigaction (SIGWINCH, &old_winch, &dummy); - sigwinch_set_flag = 0; - } -#endif - - return 0; -} - -/* Clean up the terminal and readline state after catching a signal, before - resending it to the calling application. */ -void -rl_cleanup_after_signal () -{ - _rl_clean_up_for_exit (); - if (rl_deprep_term_function) - (*rl_deprep_term_function) (); - rl_clear_pending_input (); - rl_clear_signals (); -} - -/* Reset the terminal and readline state after a signal handler returns. */ -void -rl_reset_after_signal () -{ - if (rl_prep_term_function) - (*rl_prep_term_function) (_rl_meta_flag); - rl_set_signals (); -} - -/* Free up the readline variable line state for the current line (undo list, - any partial history entry, any keyboard macros in progress, and any - numeric arguments in process) after catching a signal, before calling - rl_cleanup_after_signal(). */ -void -rl_free_line_state () -{ - register HIST_ENTRY *entry; - - rl_free_undo_list (); - - entry = current_history (); - if (entry) - entry->data = (char *)NULL; - - _rl_kill_kbd_macro (); - rl_clear_message (); - _rl_reset_argument (); -} - -#endif /* HANDLE_SIGNALS */ - -/* **************************************************************** */ -/* */ -/* SIGINT Management */ -/* */ -/* **************************************************************** */ - -#if defined (HAVE_POSIX_SIGNALS) -static sigset_t sigint_set, sigint_oset; -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) -static int sigint_oldmask; -# endif /* HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - -static int sigint_blocked; - -/* Cause SIGINT to not be delivered until the corresponding call to - release_sigint(). */ -void -_rl_block_sigint () -{ - if (sigint_blocked) - return; - -#if defined (HAVE_POSIX_SIGNALS) - sigemptyset (&sigint_set); - sigemptyset (&sigint_oset); - sigaddset (&sigint_set, SIGINT); - sigprocmask (SIG_BLOCK, &sigint_set, &sigint_oset); -#else /* !HAVE_POSIX_SIGNALS */ -# if defined (HAVE_BSD_SIGNALS) - sigint_oldmask = sigblock (sigmask (SIGINT)); -# else /* !HAVE_BSD_SIGNALS */ -# if defined (HAVE_USG_SIGHOLD) - sighold (SIGINT); -# endif /* HAVE_USG_SIGHOLD */ -# endif /* !HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - - sigint_blocked = 1; -} - -/* Allow SIGINT to be delivered. */ -void -_rl_release_sigint () -{ - if (sigint_blocked == 0) - return; - -#if defined (HAVE_POSIX_SIGNALS) - sigprocmask (SIG_SETMASK, &sigint_oset, (sigset_t *)NULL); -#else -# if defined (HAVE_BSD_SIGNALS) - sigsetmask (sigint_oldmask); -# else /* !HAVE_BSD_SIGNALS */ -# if defined (HAVE_USG_SIGHOLD) - sigrelse (SIGINT); -# endif /* HAVE_USG_SIGHOLD */ -# endif /* !HAVE_BSD_SIGNALS */ -#endif /* !HAVE_POSIX_SIGNALS */ - - sigint_blocked = 0; -} - -/* **************************************************************** */ -/* */ -/* Echoing special control characters */ -/* */ -/* **************************************************************** */ -void -rl_echo_signal_char (sig) - int sig; -{ - char cstr[3]; - int cslen, c; - - if (_rl_echoctl == 0) - return; - - switch (sig) - { - case SIGINT: c = _rl_intr_char; break; - case SIGQUIT: c = _rl_quit_char; break; - case SIGTSTP: c = _rl_susp_char; break; - default: return; - } - - if (CTRL_CHAR (c) || c == RUBOUT) - { - cstr[0] = '^'; - cstr[1] = CTRL_CHAR (c) ? UNCTRL (c) : '?'; - cstr[cslen = 2] = '\0'; - } - else - { - cstr[0] = c; - cstr[cslen = 1] = '\0'; - } - - _rl_output_some_chars (cstr, cslen); -} diff --git a/lib/readline/terminal.c~ b/lib/readline/terminal.c~ deleted file mode 100644 index 413feec74..000000000 --- a/lib/readline/terminal.c~ +++ /dev/null @@ -1,731 +0,0 @@ -/* terminal.c -- controlling the terminal with termcap. */ - -/* Copyright (C) 1996-2006 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 "posixstat.h" -#include -#if defined (HAVE_SYS_FILE_H) -# include -#endif /* HAVE_SYS_FILE_H */ - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#if defined (HAVE_LOCALE_H) -# include -#endif - -#include - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" - -#if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ) -# include -#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */ - -#include "rltty.h" -#include "tcap.h" - -/* Some standard library routines. */ -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "rlshell.h" -#include "xmalloc.h" - -#if defined (__MINGW32__) -# include -# include - -static void _win_get_screensize PARAMS((int *, int *)); -#endif - -#if defined (__EMX__) -static void _emx_get_screensize PARAMS((int *, int *)); -#endif - -#define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay) -#define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc) - -/* If the calling application sets this to a non-zero value, readline will - use the $LINES and $COLUMNS environment variables to set its idea of the - window size before interrogating the kernel. */ -int rl_prefer_env_winsize = 0; - -/* **************************************************************** */ -/* */ -/* Terminal and Termcap */ -/* */ -/* **************************************************************** */ - -static char *term_buffer = (char *)NULL; -static char *term_string_buffer = (char *)NULL; - -static int tcap_initialized; - -#if !defined (__linux__) -# if defined (__EMX__) || defined (NEED_EXTERN_PC) -extern -# endif /* __EMX__ || NEED_EXTERN_PC */ -char PC, *BC, *UP; -#endif /* __linux__ */ - -/* Some strings to control terminal actions. These are output by tputs (). */ -char *_rl_term_clreol; -char *_rl_term_clrpag; -char *_rl_term_cr; -char *_rl_term_backspace; -char *_rl_term_goto; -char *_rl_term_pc; - -/* Non-zero if we determine that the terminal can do character insertion. */ -int _rl_terminal_can_insert = 0; - -/* How to insert characters. */ -char *_rl_term_im; -char *_rl_term_ei; -char *_rl_term_ic; -char *_rl_term_ip; -char *_rl_term_IC; - -/* How to delete characters. */ -char *_rl_term_dc; -char *_rl_term_DC; - -char *_rl_term_forward_char; - -/* How to go up a line. */ -char *_rl_term_up; - -/* A visible bell; char if the terminal can be made to flash the screen. */ -static char *_rl_visible_bell; - -/* Non-zero means the terminal can auto-wrap lines. */ -int _rl_term_autowrap = -1; - -/* Non-zero means that this terminal has a meta key. */ -static int term_has_meta; - -/* The sequences to write to turn on and off the meta key, if this - terminal has one. */ -static char *_rl_term_mm; -static char *_rl_term_mo; - -/* The key sequences output by the arrow keys, if this terminal has any. */ -static char *_rl_term_ku; -static char *_rl_term_kd; -static char *_rl_term_kr; -static char *_rl_term_kl; - -/* How to initialize and reset the arrow keys, if this terminal has any. */ -static char *_rl_term_ks; -static char *_rl_term_ke; - -/* The key sequences sent by the Home and End keys, if any. */ -static char *_rl_term_kh; -static char *_rl_term_kH; -static char *_rl_term_at7; /* @7 */ - -/* Delete key */ -static char *_rl_term_kD; - -/* Insert key */ -static char *_rl_term_kI; - -/* Cursor control */ -static char *_rl_term_vs; /* very visible */ -static char *_rl_term_ve; /* normal */ - -static void bind_termcap_arrow_keys PARAMS((Keymap)); - -/* Variables that hold the screen dimensions, used by the display code. */ -int _rl_screenwidth, _rl_screenheight, _rl_screenchars; - -/* Non-zero means the user wants to enable the keypad. */ -int _rl_enable_keypad; - -/* Non-zero means the user wants to enable a meta key. */ -int _rl_enable_meta = 1; - -#if defined (__EMX__) -static void -_emx_get_screensize (swp, shp) - int *swp, *shp; -{ - int sz[2]; - - _scrsize (sz); - - if (swp) - *swp = sz[0]; - if (shp) - *shp = sz[1]; -} -#endif - -#if defined (__MINGW32__) -static void -_win_get_screensize (swp, shp) - int *swp, *shp; -{ - HANDLE hConOut; - CONSOLE_SCREEN_BUFFER_INFO scr; - - hConOut = GetStdHandle (STD_OUTPUT_HANDLE); - if (hConOut != INVALID_HANDLE_VALUE) - { - if (GetConsoleScreenBufferInfo (hConOut, &scr)) - { - *swp = scr.dwSize.X; - *shp = scr.srWindow.Bottom - scr.srWindow.Top + 1; - } - } -} -#endif - -/* Get readline's idea of the screen size. TTY is a file descriptor open - to the terminal. If IGNORE_ENV is true, we do not pay attention to the - values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being - non-null serve to check whether or not we have initialized termcap. */ -void -_rl_get_screen_size (tty, ignore_env) - int tty, ignore_env; -{ - char *ss; -#if defined (TIOCGWINSZ) - struct winsize window_size; -#endif /* TIOCGWINSZ */ - int wr, wc; - - wr = wc = -1; -#if defined (TIOCGWINSZ) - if (ioctl (tty, TIOCGWINSZ, &window_size) == 0) - { - wc = (int) window_size.ws_col; - wr = (int) window_size.ws_row; - } -#endif /* TIOCGWINSZ */ - -#if defined (__EMX__) - _emx_get_screensize (&wc, &wr); -#elif defined (__MINGW32__) - _win_get_screensize (&wc, &wr); -#endif - - if (ignore_env || rl_prefer_env_winsize == 0) - { - _rl_screenwidth = wc; - _rl_screenheight = wr; - } - else - _rl_screenwidth = _rl_screenheight = -1; - - /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV - is unset. If we prefer the environment, check it first before - assigning the value returned by the kernel. */ - if (_rl_screenwidth <= 0) - { - if (ignore_env == 0 && (ss = sh_get_env_value ("COLUMNS"))) - _rl_screenwidth = atoi (ss); - - if (_rl_screenwidth <= 0) - _rl_screenwidth = wc; - -#if !defined (__DJGPP__) - if (_rl_screenwidth <= 0 && term_string_buffer) - _rl_screenwidth = tgetnum ("co"); -#endif - } - - /* Environment variable LINES overrides setting of "li" if IGNORE_ENV - is unset. */ - if (_rl_screenheight <= 0) - { - if (ignore_env == 0 && (ss = sh_get_env_value ("LINES"))) - _rl_screenheight = atoi (ss); - - if (_rl_screenheight <= 0) - _rl_screenheight = wr; - -#if !defined (__DJGPP__) - if (_rl_screenheight <= 0 && term_string_buffer) - _rl_screenheight = tgetnum ("li"); -#endif - } - - /* If all else fails, default to 80x24 terminal. */ - if (_rl_screenwidth <= 1) - _rl_screenwidth = 80; - - if (_rl_screenheight <= 0) - _rl_screenheight = 24; - - /* If we're being compiled as part of bash, set the environment - variables $LINES and $COLUMNS to new values. Otherwise, just - do a pair of putenv () or setenv () calls. */ - sh_set_lines_and_columns (_rl_screenheight, _rl_screenwidth); - - if (_rl_term_autowrap == 0) - _rl_screenwidth--; - - _rl_screenchars = _rl_screenwidth * _rl_screenheight; -} - -void -_rl_set_screen_size (rows, cols) - int rows, cols; -{ - if (_rl_term_autowrap == -1) - _rl_init_terminal_io (rl_terminal_name); - - if (rows > 0) - _rl_screenheight = rows; - if (cols > 0) - { - _rl_screenwidth = cols; - if (_rl_term_autowrap == 0) - _rl_screenwidth--; - } - - if (rows > 0 || cols > 0) - _rl_screenchars = _rl_screenwidth * _rl_screenheight; -} - -void -rl_set_screen_size (rows, cols) - int rows, cols; -{ - _rl_set_screen_size (rows, cols); -} - -void -rl_get_screen_size (rows, cols) - int *rows, *cols; -{ - if (rows) - *rows = _rl_screenheight; - if (cols) - *cols = _rl_screenwidth; -} - -void -rl_reset_screen_size () -{ - _rl_get_screen_size (fileno (rl_instream), 0); -} - -void -rl_resize_terminal () -{ - if (readline_echoing_p) - { - _rl_get_screen_size (fileno (rl_instream), 1); - if (CUSTOM_REDISPLAY_FUNC ()) - rl_forced_update_display (); - else - _rl_redisplay_after_sigwinch (); - } -} - -struct _tc_string { - const char * const tc_var; - char **tc_value; -}; - -/* This should be kept sorted, just in case we decide to change the - search algorithm to something smarter. */ -static const struct _tc_string tc_strings[] = -{ - { "@7", &_rl_term_at7 }, - { "DC", &_rl_term_DC }, - { "IC", &_rl_term_IC }, - { "ce", &_rl_term_clreol }, - { "cl", &_rl_term_clrpag }, - { "cr", &_rl_term_cr }, - { "dc", &_rl_term_dc }, - { "ei", &_rl_term_ei }, - { "ic", &_rl_term_ic }, - { "im", &_rl_term_im }, - { "kD", &_rl_term_kD }, /* delete */ - { "kH", &_rl_term_kH }, /* home down ?? */ - { "kI", &_rl_term_kI }, /* insert */ - { "kd", &_rl_term_kd }, - { "ke", &_rl_term_ke }, /* end keypad mode */ - { "kh", &_rl_term_kh }, /* home */ - { "kl", &_rl_term_kl }, - { "kr", &_rl_term_kr }, - { "ks", &_rl_term_ks }, /* start keypad mode */ - { "ku", &_rl_term_ku }, - { "le", &_rl_term_backspace }, - { "mm", &_rl_term_mm }, - { "mo", &_rl_term_mo }, - { "nd", &_rl_term_forward_char }, - { "pc", &_rl_term_pc }, - { "up", &_rl_term_up }, - { "vb", &_rl_visible_bell }, - { "vs", &_rl_term_vs }, - { "ve", &_rl_term_ve }, -}; - -#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string)) - -/* Read the desired terminal capability strings into BP. The capabilities - are described in the TC_STRINGS table. */ -static void -get_term_capabilities (bp) - char **bp; -{ -#if !defined (__DJGPP__) /* XXX - doesn't DJGPP have a termcap library? */ - register int i; - - for (i = 0; i < NUM_TC_STRINGS; i++) - *(tc_strings[i].tc_value) = tgetstr ((char *)tc_strings[i].tc_var, bp); -#endif - tcap_initialized = 1; -} - -int -_rl_init_terminal_io (terminal_name) - const char *terminal_name; -{ - const char *term; - char *buffer; - int tty, tgetent_ret; - - term = terminal_name ? terminal_name : sh_get_env_value ("TERM"); - _rl_term_clrpag = _rl_term_cr = _rl_term_clreol = (char *)NULL; - tty = rl_instream ? fileno (rl_instream) : 0; - - if (term == 0) - term = "dumb"; - - /* I've separated this out for later work on not calling tgetent at all - if the calling application has supplied a custom redisplay function, - (and possibly if the application has supplied a custom input function). */ - if (CUSTOM_REDISPLAY_FUNC()) - { - tgetent_ret = -1; - } - else - { - if (term_string_buffer == 0) - term_string_buffer = (char *)xmalloc(2032); - - if (term_buffer == 0) - term_buffer = (char *)xmalloc(4080); - - buffer = term_string_buffer; - - tgetent_ret = tgetent (term_buffer, term); - } - - if (tgetent_ret <= 0) - { - FREE (term_string_buffer); - FREE (term_buffer); - buffer = term_buffer = term_string_buffer = (char *)NULL; - - _rl_term_autowrap = 0; /* used by _rl_get_screen_size */ - - /* Allow calling application to set default height and width, using - rl_set_screen_size */ - if (_rl_screenwidth <= 0 || _rl_screenheight <= 0) - { -#if defined (__EMX__) - _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight); - _rl_screenwidth--; -#else /* !__EMX__ */ - _rl_get_screen_size (tty, 0); -#endif /* !__EMX__ */ - } - - /* Defaults. */ - if (_rl_screenwidth <= 0 || _rl_screenheight <= 0) - { - _rl_screenwidth = 79; - _rl_screenheight = 24; - } - - /* Everything below here is used by the redisplay code (tputs). */ - _rl_screenchars = _rl_screenwidth * _rl_screenheight; - _rl_term_cr = "\r"; - _rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL; - _rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL; - _rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL; - _rl_term_kh = _rl_term_kH = _rl_term_kI = _rl_term_kD = (char *)NULL; - _rl_term_ks = _rl_term_ke = _rl_term_at7 = (char *)NULL; - _rl_term_mm = _rl_term_mo = (char *)NULL; - _rl_term_ve = _rl_term_vs = (char *)NULL; - _rl_term_forward_char = (char *)NULL; - _rl_terminal_can_insert = term_has_meta = 0; - - /* Reasonable defaults for tgoto(). Readline currently only uses - tgoto if _rl_term_IC or _rl_term_DC is defined, but just in case we - change that later... */ - PC = '\0'; - BC = _rl_term_backspace = "\b"; - UP = _rl_term_up; - - return 0; - } - - get_term_capabilities (&buffer); - - /* Set up the variables that the termcap library expects the application - to provide. */ - PC = _rl_term_pc ? *_rl_term_pc : 0; - BC = _rl_term_backspace; - UP = _rl_term_up; - - if (!_rl_term_cr) - _rl_term_cr = "\r"; - - _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn"); - - /* Allow calling application to set default height and width, using - rl_set_screen_size */ - if (_rl_screenwidth <= 0 || _rl_screenheight <= 0) - _rl_get_screen_size (tty, 0); - - /* "An application program can assume that the terminal can do - character insertion if *any one of* the capabilities `IC', - `im', `ic' or `ip' is provided." But we can't do anything if - only `ip' is provided, so... */ - _rl_terminal_can_insert = (_rl_term_IC || _rl_term_im || _rl_term_ic); - - /* Check to see if this terminal has a meta key and clear the capability - variables if there is none. */ - term_has_meta = (tgetflag ("km") || tgetflag ("MT")); - if (!term_has_meta) - _rl_term_mm = _rl_term_mo = (char *)NULL; - - /* Attempt to find and bind the arrow keys. Do not override already - bound keys in an overzealous attempt, however. */ - - bind_termcap_arrow_keys (emacs_standard_keymap); - -#if defined (VI_MODE) - bind_termcap_arrow_keys (vi_movement_keymap); - bind_termcap_arrow_keys (vi_insertion_keymap); -#endif /* VI_MODE */ - - return 0; -} - -/* Bind the arrow key sequences from the termcap description in MAP. */ -static void -bind_termcap_arrow_keys (map) - Keymap map; -{ - Keymap xkeymap; - - xkeymap = _rl_keymap; - _rl_keymap = map; - - rl_bind_keyseq_if_unbound (_rl_term_ku, rl_get_previous_history); - rl_bind_keyseq_if_unbound (_rl_term_kd, rl_get_next_history); - rl_bind_keyseq_if_unbound (_rl_term_kr, rl_forward_char); - rl_bind_keyseq_if_unbound (_rl_term_kl, rl_backward_char); - - rl_bind_keyseq_if_unbound (_rl_term_kh, rl_beg_of_line); /* Home */ - rl_bind_keyseq_if_unbound (_rl_term_at7, rl_end_of_line); /* End */ - - rl_bind_keyseq_if_unbound (_rl_term_kD, rl_delete); - - _rl_keymap = xkeymap; -} - -char * -rl_get_termcap (cap) - const char *cap; -{ - register int i; - - if (tcap_initialized == 0) - return ((char *)NULL); - for (i = 0; i < NUM_TC_STRINGS; i++) - { - if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0) - return *(tc_strings[i].tc_value); - } - return ((char *)NULL); -} - -/* Re-initialize the terminal considering that the TERM/TERMCAP variable - has changed. */ -int -rl_reset_terminal (terminal_name) - const char *terminal_name; -{ - _rl_screenwidth = _rl_screenheight = 0; - _rl_init_terminal_io (terminal_name); - return 0; -} - -/* A function for the use of tputs () */ -#ifdef _MINIX -void -_rl_output_character_function (c) - int c; -{ - putc (c, _rl_out_stream); -} -#else /* !_MINIX */ -int -_rl_output_character_function (c) - int c; -{ - return putc (c, _rl_out_stream); -} -#endif /* !_MINIX */ - -/* Write COUNT characters from STRING to the output stream. */ -void -_rl_output_some_chars (string, count) - const char *string; - int count; -{ - fwrite (string, 1, count, _rl_out_stream); -} - -/* Move the cursor back. */ -int -_rl_backspace (count) - int count; -{ - register int i; - - if (_rl_term_backspace) - for (i = 0; i < count; i++) - tputs (_rl_term_backspace, 1, _rl_output_character_function); - else - for (i = 0; i < count; i++) - putc ('\b', _rl_out_stream); - return 0; -} - -/* Move to the start of the next line. */ -int -rl_crlf () -{ -#if defined (NEW_TTY_DRIVER) - if (_rl_term_cr) - tputs (_rl_term_cr, 1, _rl_output_character_function); -#endif /* NEW_TTY_DRIVER */ - putc ('\n', _rl_out_stream); - return 0; -} - -/* Ring the terminal bell. */ -int -rl_ding () -{ - if (readline_echoing_p) - { - switch (_rl_bell_preference) - { - case NO_BELL: - default: - break; - case VISIBLE_BELL: - if (_rl_visible_bell) - { - tputs (_rl_visible_bell, 1, _rl_output_character_function); - break; - } - /* FALLTHROUGH */ - case AUDIBLE_BELL: - fprintf (stderr, "\007"); - fflush (stderr); - break; - } - return (0); - } - return (-1); -} - -/* **************************************************************** */ -/* */ -/* Controlling the Meta Key and Keypad */ -/* */ -/* **************************************************************** */ - -void -_rl_enable_meta_key () -{ -#if !defined (__DJGPP__) - if (term_has_meta && _rl_term_mm) - tputs (_rl_term_mm, 1, _rl_output_character_function); -#endif -} - -void -_rl_control_keypad (on) - int on; -{ -#if !defined (__DJGPP__) - if (on && _rl_term_ks) - tputs (_rl_term_ks, 1, _rl_output_character_function); - else if (!on && _rl_term_ke) - tputs (_rl_term_ke, 1, _rl_output_character_function); -#endif -} - -/* **************************************************************** */ -/* */ -/* Controlling the Cursor */ -/* */ -/* **************************************************************** */ - -/* Set the cursor appropriately depending on IM, which is one of the - insert modes (insert or overwrite). Insert mode gets the normal - cursor. Overwrite mode gets a very visible cursor. Only does - anything if we have both capabilities. */ -void -_rl_set_cursor (im, force) - int im, force; -{ - if (_rl_term_ve && _rl_term_vs) - { - if (force || im != rl_insert_mode) - { - if (im == RL_IM_OVERWRITE) - tputs (_rl_term_vs, 1, _rl_output_character_function); - else - tputs (_rl_term_ve, 1, _rl_output_character_function); - } - } -} diff --git a/lib/readline/text.c~ b/lib/readline/text.c~ deleted file mode 100644 index 32dfde818..000000000 --- a/lib/readline/text.c~ +++ /dev/null @@ -1,1652 +0,0 @@ -/* text.c -- text handling commands for readline. */ - -/* Copyright (C) 1987-2005 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#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)); - -#if defined (READLINE_CALLBACKS) -static int _rl_insert_next_callback PARAMS((_rl_callback_generic_arg *)); -static int _rl_char_search_callback PARAMS((_rl_callback_generic_arg *)); -#endif - -/* **************************************************************** */ -/* */ -/* 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 - (VI_COMMAND_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) - { - if (rl_point == rl_end && EMACS_MODE) - { - rl_ding (); - return 0; - } - - point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); - -#if defined (VI_MODE) - if (point >= rl_end && VI_COMMAND_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; -} - -/* Move forward a word. We do what Emacs does. Handles multibyte chars. */ -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_char_value (rl_line_buffer, rl_point); - - if (_rl_walphabetic (c) == 0) - { - rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - while (rl_point < rl_end) - { - c = _rl_char_value (rl_line_buffer, rl_point); - if (_rl_walphabetic (c)) - break; - rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - } - } - - if (rl_point == rl_end) - return 0; - - rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - while (rl_point < rl_end) - { - c = _rl_char_value (rl_line_buffer, rl_point); - if (_rl_walphabetic (c) == 0) - break; - rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - } - - --count; - } - - return 0; -} - -/* Move backward a word. We do what Emacs does. Handles multibyte chars. */ -int -rl_backward_word (count, key) - int count, key; -{ - int c, p; - - if (count < 0) - return (rl_forward_word (-count, key)); - - while (count) - { - if (rl_point == 0) - return 0; - - /* Like rl_forward_word (), except that we look at the characters - just before point. */ - - p = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO); - c = _rl_char_value (rl_line_buffer, p); - - if (_rl_walphabetic (c) == 0) - { - rl_point = p; - while (rl_point > 0) - { - p = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO); - c = _rl_char_value (rl_line_buffer, p); - if (_rl_walphabetic (c)) - break; - rl_point = p; - } - } - - while (rl_point) - { - p = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO); - c = _rl_char_value (rl_line_buffer, p); - if (_rl_walphabetic (c) == 0) - break; - else - rl_point = p; - } - - --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 (MB_CUR_MAX == 1 || rl_byte_oriented) - { - /* 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. */ -static int -_rl_insert_next (count) - int count; -{ - int c; - - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (c < 0) - return -1; - -#if defined (HANDLE_SIGNALS) - if (RL_ISSTATE (RL_STATE_CALLBACK) == 0) - _rl_restore_tty_signals (); -#endif - - return (_rl_insert_char (count, c)); -} - -#if defined (READLINE_CALLBACKS) -static int -_rl_insert_next_callback (data) - _rl_callback_generic_arg *data; -{ - int count; - - count = data->count; - - /* Deregister function, let rl_callback_read_char deallocate data */ - _rl_callback_func = 0; - _rl_want_redisplay = 1; - - return _rl_insert_next (count); -} -#endif - -int -rl_quoted_insert (count, key) - int count, key; -{ - /* Let's see...should the callback interface futz with signal handling? */ -#if defined (HANDLE_SIGNALS) - if (RL_ISSTATE (RL_STATE_CALLBACK) == 0) - _rl_disable_tty_signals (); -#endif - -#if defined (READLINE_CALLBACKS) - if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - _rl_callback_data = _rl_callback_data_alloc (count); - _rl_callback_func = _rl_insert_next_callback; - return (0); - } -#endif - - return _rl_insert_next (count); -} - -/* 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; - } - - orig_point = rl_point; - if (count > 1 || rl_explicit_arg) - { - rl_backward_char (count, key); - rl_kill_text (orig_point, rl_point); - } - else if (MB_CUR_MAX == 1 || rl_byte_oriented) - { - c = rl_line_buffer[--rl_point]; - rl_delete_text (rl_point, orig_point); - /* The erase-at-end-of-line hack is of questionable merit now. */ - 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); - } - } - else - { - rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); - rl_delete_text (rl_point, orig_point); - } - - 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 xpoint; - - if (count < 0) - return (_rl_rubout_char (-count, key)); - - if (rl_point == rl_end) - { - rl_ding (); - return -1; - } - - if (count > 1 || rl_explicit_arg) - { - xpoint = rl_point; - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_forward_char (count, key); - else - rl_forward_byte (count, key); - - rl_kill_text (xpoint, rl_point); - rl_point = xpoint; - } - else - { - xpoint = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - rl_delete_text (rl_point, xpoint); - } - return 0; -} - -/* 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; - } - - if (rl_point < 0) - rl_point = 0; - - 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; -{ - int start, next, end; - int inword, c, nc, nop; -#if defined (HANDLE_MULTIBYTE) - wchar_t wc, nwc; - char mb[MB_LEN_MAX+1]; - int mlen; - mbstate_t mps; -#endif - - start = rl_point; - rl_forward_word (count, 0); - end = rl_point; - - if (op != UpCase && op != DownCase && op != CapCase) - { - rl_ding (); - return -1; - } - - if (count < 0) - SWAP (start, end); - -#if defined (HANDLE_MULTIBYTE) - memset (&mps, 0, sizeof (mbstate_t)); -#endif - - /* We are going to modify some text, so let's prepare to undo it. */ - rl_modifying (start, end); - - inword = 0; - while (start < end) - { - c = _rl_char_value (rl_line_buffer, start); - /* This assumes that the upper and lower case versions are the same width. */ - next = MB_NEXTCHAR (rl_line_buffer, start, 1, MB_FIND_NONZERO); - - if (_rl_walphabetic (c) == 0) - { - inword = 0; - start = next; - continue; - } - - if (op == CapCase) - { - nop = inword ? DownCase : UpCase; - inword = 1; - } - else - nop = op; - if (MB_CUR_MAX == 1 || rl_byte_oriented || isascii (c)) - { - nc = (nop == UpCase) ? _rl_to_upper (c) : _rl_to_lower (c); - rl_line_buffer[start] = nc; - } -#if defined (HANDLE_MULTIBYTE) - else - { - mbrtowc (&wc, rl_line_buffer + start, end - start, &mps); - nwc = (nop == UpCase) ? _rl_to_wupper (wc) : _rl_to_wlower (wc); - if (nwc != wc) /* just skip unchanged characters */ - { - mlen = wcrtomb (mb, nwc, &mps); - if (mlen > 0) - mb[mlen] = '\0'; - /* Assume the same width */ - strncpy (rl_line_buffer + start, mb, mlen); - } - } -#endif - - start = next; - } - - 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; -#else - char dummy[2]; -#endif - int char_length, prev_point; - - if (count == 0) - return 0; - - if (!rl_point || rl_end < 2) - { - rl_ding (); - return -1; - } - - rl_begin_undo_group (); - - if (rl_point == rl_end) - { - rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO); - count = 1; - } - - prev_point = rl_point; - rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO); - -#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 (mb_len <= 0) - return -1; - - 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 (c < 0) - return -1; - - if (count < 0) - return (_rl_char_search_internal (-count, bdir, c)); - else - return (_rl_char_search_internal (count, fdir, c)); -} -#endif /* !HANDLE_MULTIBYTE */ - -#if defined (READLINE_CALLBACKS) -static int -_rl_char_search_callback (data) - _rl_callback_generic_arg *data; -{ - _rl_callback_func = 0; - _rl_want_redisplay = 1; - - return (_rl_char_search (data->count, data->i1, data->i2)); -} -#endif - -int -rl_char_search (count, key) - int count, key; -{ -#if defined (READLINE_CALLBACKS) - if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - _rl_callback_data = _rl_callback_data_alloc (count); - _rl_callback_data->i1 = FFIND; - _rl_callback_data->i2 = BFIND; - _rl_callback_func = _rl_char_search_callback; - return (0); - } -#endif - - return (_rl_char_search (count, FFIND, BFIND)); -} - -int -rl_backward_char_search (count, key) - int count, key; -{ -#if defined (READLINE_CALLBACKS) - if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - _rl_callback_data = _rl_callback_data_alloc (count); - _rl_callback_data->i1 = BFIND; - _rl_callback_data->i2 = FFIND; - _rl_callback_func = _rl_char_search_callback; - return (0); - } -#endif - - 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/undo.c~ b/lib/readline/undo.c~ deleted file mode 100644 index c2a7851c7..000000000 --- a/lib/readline/undo.c~ +++ /dev/null @@ -1,328 +0,0 @@ -/* readline.c -- a general facility for reading lines of input - with emacs style editing and completion. */ - -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. - - Readline is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Readline is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline. If not, see . -*/ - -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include - -#if defined (HAVE_UNISTD_H) -# include /* for _POSIX_VERSION */ -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#include - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" - -/* Some standard library routines. */ -#include "readline.h" -#include "history.h" - -#include "rlprivate.h" -#include "xmalloc.h" - -extern void replace_history_data PARAMS((int, histdata_t *, histdata_t *)); - -/* Non-zero tells rl_delete_text and rl_insert_text to not add to - the undo list. */ -int _rl_doing_an_undo = 0; - -/* How many unclosed undo groups we currently have. */ -int _rl_undo_group_level = 0; - -/* The current undo list for THE_LINE. */ -UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL; - -/* **************************************************************** */ -/* */ -/* Undo, and Undoing */ -/* */ -/* **************************************************************** */ - -static UNDO_LIST * -alloc_undo_entry (what, start, end, text) - enum undo_code what; - int start, end; - char *text; -{ - UNDO_LIST *temp; - - temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST)); - temp->what = what; - temp->start = start; - temp->end = end; - temp->text = text; - - temp->next = (UNDO_LIST *)NULL; - return temp; -} - -/* Remember how to undo something. Concatenate some undos if that - seems right. */ -void -rl_add_undo (what, start, end, text) - enum undo_code what; - int start, end; - char *text; -{ - UNDO_LIST *temp; - - temp = alloc_undo_entry (what, start, end, text); - temp->next = rl_undo_list; - rl_undo_list = temp; -} - -/* Free the existing undo list. */ -void -rl_free_undo_list () -{ - UNDO_LIST *release, *orig_list; - - orig_list = rl_undo_list; - while (rl_undo_list) - { - release = rl_undo_list; - rl_undo_list = rl_undo_list->next; - - if (release->what == UNDO_DELETE) - free (release->text); - - xfree (release); - } - rl_undo_list = (UNDO_LIST *)NULL; - replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL); -} - -UNDO_LIST * -_rl_copy_undo_entry (entry) - UNDO_LIST *entry; -{ - UNDO_LIST *new; - - new = alloc_undo_entry (entry->what, entry->start, entry->end, (char *)NULL); - new->text = entry->text ? savestring (entry->text) : 0; - return new; -} - -UNDO_LIST * -_rl_copy_undo_list (head) - UNDO_LIST *head; -{ - UNDO_LIST *list, *new, *roving, *c; - - list = head; - new = 0; - while (list) - { - c = _rl_copy_undo_entry (list); - if (new == 0) - roving = new = c; - else - { - roving->next = c; - roving = roving->next; - } - list = list->next; - } - - roving->next = 0; - return new; -} - -/* Undo the next thing in the list. Return 0 if there - is nothing to undo, or non-zero if there was. */ -int -rl_do_undo () -{ - UNDO_LIST *release; - int waiting_for_begin, start, end; - -#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i))) - - start = end = waiting_for_begin = 0; - do - { - if (rl_undo_list == 0) - return (0); - - _rl_doing_an_undo = 1; - RL_SETSTATE(RL_STATE_UNDOING); - - /* To better support vi-mode, a start or end value of -1 means - rl_point, and a value of -2 means rl_end. */ - if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT) - { - start = TRANS (rl_undo_list->start); - end = TRANS (rl_undo_list->end); - } - - switch (rl_undo_list->what) - { - /* Undoing deletes means inserting some text. */ - case UNDO_DELETE: - rl_point = start; - rl_insert_text (rl_undo_list->text); - free (rl_undo_list->text); - break; - - /* Undoing inserts means deleting some text. */ - case UNDO_INSERT: - rl_delete_text (start, end); - rl_point = start; - break; - - /* Undoing an END means undoing everything 'til we get to a BEGIN. */ - case UNDO_END: - waiting_for_begin++; - break; - - /* Undoing a BEGIN means that we are done with this group. */ - case UNDO_BEGIN: - if (waiting_for_begin) - waiting_for_begin--; - else - rl_ding (); - break; - } - - _rl_doing_an_undo = 0; - RL_UNSETSTATE(RL_STATE_UNDOING); - - release = rl_undo_list; - rl_undo_list = rl_undo_list->next; - replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list); - - xfree (release); - } - while (waiting_for_begin); - - return (1); -} -#undef TRANS - -int -_rl_fix_last_undo_of_type (type, start, end) - int type, start, end; -{ - UNDO_LIST *rl; - - for (rl = rl_undo_list; rl; rl = rl->next) - { - if (rl->what == type) - { - rl->start = start; - rl->end = end; - return 0; - } - } - return 1; -} - -/* Begin a group. Subsequent undos are undone as an atomic operation. */ -int -rl_begin_undo_group () -{ - rl_add_undo (UNDO_BEGIN, 0, 0, 0); - _rl_undo_group_level++; - return 0; -} - -/* End an undo group started with rl_begin_undo_group (). */ -int -rl_end_undo_group () -{ - rl_add_undo (UNDO_END, 0, 0, 0); - _rl_undo_group_level--; - return 0; -} - -/* Save an undo entry for the text from START to END. */ -int -rl_modifying (start, end) - int start, end; -{ - if (start > end) - { - SWAP (start, end); - } - - if (start != end) - { - char *temp = rl_copy_text (start, end); - rl_begin_undo_group (); - rl_add_undo (UNDO_DELETE, start, end, temp); - rl_add_undo (UNDO_INSERT, start, end, (char *)NULL); - rl_end_undo_group (); - } - return 0; -} - -/* Revert the current line to its previous state. */ -int -rl_revert_line (count, key) - int count, key; -{ - if (rl_undo_list == 0) - rl_ding (); - else - { - while (rl_undo_list) - rl_do_undo (); -#if defined (VI_MODE) - if (rl_editing_mode == vi_mode) - rl_point = rl_mark = 0; /* rl_end should be set correctly */ -#endif - } - - return 0; -} - -/* Do some undoing of things that were done. */ -int -rl_undo_command (count, key) - int count, key; -{ - if (count < 0) - return 0; /* Nothing to do. */ - - while (count) - { - if (rl_do_undo ()) - count--; - else - { - rl_ding (); - break; - } - } - return 0; -} diff --git a/lib/readline/util.c~ b/lib/readline/util.c~ deleted file mode 100644 index d166ecf12..000000000 --- a/lib/readline/util.c~ +++ /dev/null @@ -1,501 +0,0 @@ -/* util.c -- readline utility functions */ - -/* Copyright (C) 1987-2005 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2, or - (at your option) any later version. - - The GNU Readline Library is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#define READLINE_LIBRARY - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include -#include -#include "posixjmp.h" - -#if defined (HAVE_UNISTD_H) -# include /* for _POSIX_VERSION */ -#endif /* HAVE_UNISTD_H */ - -#if defined (HAVE_STDLIB_H) -# include -#else -# include "ansi_stdlib.h" -#endif /* HAVE_STDLIB_H */ - -#include -#include - -/* System-specific feature definitions and include files. */ -#include "rldefs.h" -#include "rlmbutil.h" - -#if defined (TIOCSTAT_IN_SYS_IOCTL) -# include -#endif /* TIOCSTAT_IN_SYS_IOCTL */ - -/* Some standard library routines. */ -#include "readline.h" - -#include "rlprivate.h" -#include "xmalloc.h" - -/* **************************************************************** */ -/* */ -/* Utility Functions */ -/* */ -/* **************************************************************** */ - -/* Return 0 if C is not a member of the class of characters that belong - in words, or 1 if it is. */ - -int _rl_allow_pathname_alphabetic_chars = 0; -static const char * const pathname_alphabetic_chars = "/-_=~.#$"; - -int -rl_alphabetic (c) - int c; -{ - if (ALPHABETIC (c)) - return (1); - - return (_rl_allow_pathname_alphabetic_chars && - strchr (pathname_alphabetic_chars, c) != NULL); -} - -#if defined (HANDLE_MULTIBYTE) -int -_rl_walphabetic (wc) - wchar_t wc; -{ - int c; - - if (iswalnum (wc)) - return (1); - - c = wc & 0177; - return (_rl_allow_pathname_alphabetic_chars && - strchr (pathname_alphabetic_chars, c) != NULL); -} -#endif - -/* How to abort things. */ -int -_rl_abort_internal () -{ - rl_ding (); - rl_clear_message (); - _rl_reset_argument (); - rl_clear_pending_input (); - - RL_UNSETSTATE (RL_STATE_MACRODEF); - while (rl_executing_macro) - _rl_pop_executing_macro (); - - rl_last_func = (rl_command_func_t *)NULL; - longjmp (readline_top_level, 1); - return (0); -} - -int -rl_abort (count, key) - int count, key; -{ - return (_rl_abort_internal ()); -} - -int -rl_tty_status (count, key) - int count, key; -{ -#if defined (TIOCSTAT) - ioctl (1, TIOCSTAT, (char *)0); - rl_refresh_line (count, key); -#else - rl_ding (); -#endif - return 0; -} - -/* Return a copy of the string between FROM and TO. - FROM is inclusive, TO is not. */ -char * -rl_copy_text (from, to) - int from, to; -{ - register int length; - char *copy; - - /* Fix it if the caller is confused. */ - if (from > to) - SWAP (from, to); - - length = to - from; - copy = (char *)xmalloc (1 + length); - strncpy (copy, rl_line_buffer + from, length); - copy[length] = '\0'; - return (copy); -} - -/* Increase the size of RL_LINE_BUFFER until it has enough space to hold - LEN characters. */ -void -rl_extend_line_buffer (len) - int len; -{ - while (len >= rl_line_buffer_len) - { - rl_line_buffer_len += DEFAULT_BUFFER_SIZE; - rl_line_buffer = (char *)xrealloc (rl_line_buffer, rl_line_buffer_len); - } - - _rl_set_the_line (); -} - - -/* A function for simple tilde expansion. */ -int -rl_tilde_expand (ignore, key) - int ignore, key; -{ - register int start, end; - char *homedir, *temp; - int len; - - end = rl_point; - start = end - 1; - - if (rl_point == rl_end && rl_line_buffer[rl_point] == '~') - { - homedir = tilde_expand ("~"); - _rl_replace_text (homedir, start, end); - return (0); - } - else if (rl_line_buffer[start] != '~') - { - for (; !whitespace (rl_line_buffer[start]) && start >= 0; start--) - ; - start++; - } - - end = start; - do - end++; - while (whitespace (rl_line_buffer[end]) == 0 && end < rl_end); - - if (whitespace (rl_line_buffer[end]) || end >= rl_end) - end--; - - /* If the first character of the current word is a tilde, perform - tilde expansion and insert the result. If not a tilde, do - nothing. */ - if (rl_line_buffer[start] == '~') - { - len = end - start + 1; - temp = (char *)xmalloc (len + 1); - strncpy (temp, rl_line_buffer + start, len); - temp[len] = '\0'; - homedir = tilde_expand (temp); - xfree (temp); - - _rl_replace_text (homedir, start, end); - } - - return (0); -} - -#if defined (USE_VARARGS) -void -#if defined (PREFER_STDARG) -_rl_ttymsg (const char *format, ...) -#else -_rl_ttymsg (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 - - fprintf (stderr, "readline: "); - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - fflush (stderr); - - va_end (args); - - rl_forced_update_display (); -} - -void -#if defined (PREFER_STDARG) -_rl_errmsg (const char *format, ...) -#else -_rl_errmsg (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 - - fprintf (stderr, "readline: "); - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - fflush (stderr); - - va_end (args); -} - -#else /* !USE_VARARGS */ -void -_rl_ttymsg (format, arg1, arg2) - char *format; -{ - fprintf (stderr, "readline: "); - fprintf (stderr, format, arg1, arg2); - fprintf (stderr, "\n"); - - rl_forced_update_display (); -} - -void -_rl_errmsg (format, arg1, arg2) - char *format; -{ - fprintf (stderr, "readline: "); - fprintf (stderr, format, arg1, arg2); - fprintf (stderr, "\n"); -} -#endif /* !USE_VARARGS */ - -/* **************************************************************** */ -/* */ -/* String Utility Functions */ -/* */ -/* **************************************************************** */ - -/* Determine if s2 occurs in s1. If so, return a pointer to the - match in s1. The compare is case insensitive. */ -char * -_rl_strindex (s1, s2) - register const char *s1, *s2; -{ - register int i, l, len; - - for (i = 0, l = strlen (s2), len = strlen (s1); (len - i) >= l; i++) - if (_rl_strnicmp (s1 + i, s2, l) == 0) - return ((char *) (s1 + i)); - return ((char *)NULL); -} - -#ifndef HAVE_STRPBRK -/* Find the first occurrence in STRING1 of any character from STRING2. - Return a pointer to the character in STRING1. */ -char * -_rl_strpbrk (string1, string2) - const char *string1, *string2; -{ - register const char *scan; -#if defined (HANDLE_MULTIBYTE) - mbstate_t ps; - register int i, v; - - memset (&ps, 0, sizeof (mbstate_t)); -#endif - - for (; *string1; string1++) - { - for (scan = string2; *scan; scan++) - { - if (*string1 == *scan) - return ((char *)string1); - } -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - v = _rl_get_char_len (string1, &ps); - if (v > 1) - string1 += v - 1; /* -1 to account for auto-increment in loop */ - } -#endif - } - return ((char *)NULL); -} -#endif - -#if !defined (HAVE_STRCASECMP) -/* Compare at most COUNT characters from string1 to string2. Case - doesn't matter. */ -int -_rl_strnicmp (string1, string2, count) - char *string1, *string2; - int count; -{ - register char ch1, ch2; - - while (count) - { - ch1 = *string1++; - ch2 = *string2++; - if (_rl_to_upper(ch1) == _rl_to_upper(ch2)) - count--; - else - break; - } - return (count); -} - -/* strcmp (), but caseless. */ -int -_rl_stricmp (string1, string2) - char *string1, *string2; -{ - register char ch1, ch2; - - while (*string1 && *string2) - { - ch1 = *string1++; - ch2 = *string2++; - if (_rl_to_upper(ch1) != _rl_to_upper(ch2)) - return (1); - } - return (*string1 - *string2); -} -#endif /* !HAVE_STRCASECMP */ - -/* Stupid comparison routine for qsort () ing strings. */ -int -_rl_qsort_string_compare (s1, s2) - char **s1, **s2; -{ -#if defined (HAVE_STRCOLL) - return (strcoll (*s1, *s2)); -#else - int result; - - result = **s1 - **s2; - if (result == 0) - result = strcmp (*s1, *s2); - - return result; -#endif -} - -/* Function equivalents for the macros defined in chardefs.h. */ -#define FUNCTION_FOR_MACRO(f) int (f) (c) int c; { return f (c); } - -FUNCTION_FOR_MACRO (_rl_digit_p) -FUNCTION_FOR_MACRO (_rl_digit_value) -FUNCTION_FOR_MACRO (_rl_lowercase_p) -FUNCTION_FOR_MACRO (_rl_pure_alphabetic) -FUNCTION_FOR_MACRO (_rl_to_lower) -FUNCTION_FOR_MACRO (_rl_to_upper) -FUNCTION_FOR_MACRO (_rl_uppercase_p) - -/* A convenience function, to force memory deallocation to be performed - by readline. DLLs on Windows apparently require this. */ -void -rl_free (mem) - void *mem; -{ - if (mem) - free (mem); -} - -/* Backwards compatibility, now that savestring has been removed from - all `public' readline header files. */ -#undef _rl_savestring -char * -_rl_savestring (s) - const char *s; -{ - return (strcpy ((char *)xmalloc (1 + (int)strlen (s)), (s))); -} - -#if defined (USE_VARARGS) -static FILE *_rl_tracefp; - -void -#if defined (PREFER_STDARG) -_rl_trace (const char *format, ...) -#else -_rl_trace (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 (_rl_tracefp == 0) - _rl_tropen (); - vfprintf (_rl_tracefp, format, args); - fprintf (_rl_tracefp, "\n"); - fflush (_rl_tracefp); - - va_end (args); -} - -int -_rl_tropen () -{ - char fnbuf[128]; - - sprintf (fnbuf, "/var/tmp/rltrace.%ld", getpid()); - unlink(fnbuf); - _rl_tracefp = fopen (fnbuf, "w+"); - return _rl_tracefp != 0; -} - -int -_rl_trclose () -{ - int r; - - r = fclose (_rl_tracefp); - _rl_tracefp = 0; - return r; -} - -#endif diff --git a/lib/readline/vi_keymap.c~ b/lib/readline/vi_keymap.c~ deleted file mode 100644 index 3a017cc08..000000000 --- a/lib/readline/vi_keymap.c~ +++ /dev/null @@ -1,877 +0,0 @@ -/* vi_keymap.c -- the keymap for vi_mode in readline (). */ - -/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. - - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. - - The GNU Readline Library is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 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 (BUFSIZ) -#include -#endif /* !BUFSIZ */ - -#include "readline.h" - -#if 0 -extern KEYMAP_ENTRY_ARRAY vi_escape_keymap; -#endif - -/* The keymap arrays for handling vi mode. */ -KEYMAP_ENTRY_ARRAY vi_movement_keymap = { - /* The regular control keys come first. */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-@ */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-a */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-b */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-c */ - { ISFUNC, rl_vi_eof_maybe }, /* Control-d */ - { ISFUNC, rl_emacs_editing_mode }, /* Control-e */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-f */ - { ISFUNC, rl_abort }, /* Control-g */ - { ISFUNC, rl_backward_char }, /* Control-h */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-i */ - { ISFUNC, rl_newline }, /* Control-j */ - { ISFUNC, rl_kill_line }, /* Control-k */ - { ISFUNC, rl_clear_screen }, /* Control-l */ - { ISFUNC, rl_newline }, /* Control-m */ - { ISFUNC, rl_get_next_history }, /* Control-n */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-o */ - { ISFUNC, rl_get_previous_history }, /* Control-p */ - { ISFUNC, rl_quoted_insert }, /* Control-q */ - { ISFUNC, rl_reverse_search_history }, /* Control-r */ - { ISFUNC, rl_forward_search_history }, /* Control-s */ - { ISFUNC, rl_transpose_chars }, /* Control-t */ - { ISFUNC, rl_unix_line_discard }, /* Control-u */ - { ISFUNC, rl_quoted_insert }, /* Control-v */ - { ISFUNC, rl_unix_word_rubout }, /* Control-w */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-x */ - { ISFUNC, rl_yank }, /* Control-y */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-z */ - - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-[ */ /* vi_escape_keymap */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-\ */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-] */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-^ */ - { ISFUNC, rl_vi_undo }, /* Control-_ */ - - /* The start of printing characters. */ - { ISFUNC, rl_forward_char }, /* SPACE */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ! */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* " */ - { ISFUNC, rl_insert_comment }, /* # */ - { ISFUNC, rl_end_of_line }, /* $ */ - { ISFUNC, rl_vi_match }, /* % */ - { ISFUNC, rl_vi_tilde_expand }, /* & */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ' */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ( */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ) */ - { ISFUNC, rl_vi_complete }, /* * */ - { ISFUNC, rl_get_next_history}, /* + */ - { ISFUNC, rl_vi_char_search }, /* , */ - { ISFUNC, rl_get_previous_history }, /* - */ - { ISFUNC, rl_vi_redo }, /* . */ - { ISFUNC, rl_vi_search }, /* / */ - - /* Regular digits. */ - { ISFUNC, rl_beg_of_line }, /* 0 */ - { ISFUNC, rl_vi_arg_digit }, /* 1 */ - { ISFUNC, rl_vi_arg_digit }, /* 2 */ - { ISFUNC, rl_vi_arg_digit }, /* 3 */ - { ISFUNC, rl_vi_arg_digit }, /* 4 */ - { ISFUNC, rl_vi_arg_digit }, /* 5 */ - { ISFUNC, rl_vi_arg_digit }, /* 6 */ - { ISFUNC, rl_vi_arg_digit }, /* 7 */ - { ISFUNC, rl_vi_arg_digit }, /* 8 */ - { ISFUNC, rl_vi_arg_digit }, /* 9 */ - - /* A little more punctuation. */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* : */ - { ISFUNC, rl_vi_char_search }, /* ; */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* < */ - { ISFUNC, rl_vi_complete }, /* = */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* > */ - { ISFUNC, rl_vi_search }, /* ? */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* @ */ - - /* Uppercase alphabet. */ - { ISFUNC, rl_vi_append_eol }, /* A */ - { ISFUNC, rl_vi_prev_word}, /* B */ - { ISFUNC, rl_vi_change_to }, /* C */ - { ISFUNC, rl_vi_delete_to }, /* D */ - { ISFUNC, rl_vi_end_word }, /* E */ - { ISFUNC, rl_vi_char_search }, /* F */ - { ISFUNC, rl_vi_fetch_history }, /* G */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* H */ - { ISFUNC, rl_vi_insert_beg }, /* I */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* J */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* K */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* L */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* M */ - { ISFUNC, rl_vi_search_again }, /* N */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* O */ - { ISFUNC, rl_vi_put }, /* P */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Q */ - { ISFUNC, rl_vi_replace }, /* R */ - { ISFUNC, rl_vi_subst }, /* S */ - { ISFUNC, rl_vi_char_search }, /* T */ - { ISFUNC, rl_revert_line }, /* U */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* V */ - { ISFUNC, rl_vi_next_word }, /* W */ - { ISFUNC, rl_vi_rubout }, /* X */ - { ISFUNC, rl_vi_yank_to }, /* Y */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Z */ - - /* Some more punctuation. */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* [ */ - { ISFUNC, rl_vi_complete }, /* \ */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ] */ - { ISFUNC, rl_vi_first_print }, /* ^ */ - { ISFUNC, rl_vi_yank_arg }, /* _ */ - { ISFUNC, rl_vi_goto_mark }, /* ` */ - - /* Lowercase alphabet. */ - { ISFUNC, rl_vi_append_mode }, /* a */ - { ISFUNC, rl_vi_prev_word }, /* b */ - { ISFUNC, rl_vi_change_to }, /* c */ - { ISFUNC, rl_vi_delete_to }, /* d */ - { ISFUNC, rl_vi_end_word }, /* e */ - { ISFUNC, rl_vi_char_search }, /* f */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* g */ - { ISFUNC, rl_backward_char }, /* h */ - { ISFUNC, rl_vi_insert_mode }, /* i */ - { ISFUNC, rl_get_next_history }, /* j */ - { ISFUNC, rl_get_previous_history }, /* k */ - { ISFUNC, rl_forward_char }, /* l */ - { ISFUNC, rl_vi_set_mark }, /* m */ - { ISFUNC, rl_vi_search_again }, /* n */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* o */ - { ISFUNC, rl_vi_put }, /* p */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* q */ - { ISFUNC, rl_vi_change_char }, /* r */ - { ISFUNC, rl_vi_subst }, /* s */ - { ISFUNC, rl_vi_char_search }, /* t */ - { ISFUNC, rl_vi_undo }, /* u */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* v */ - { ISFUNC, rl_vi_next_word }, /* w */ - { ISFUNC, rl_vi_delete }, /* x */ - { ISFUNC, rl_vi_yank_to }, /* y */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* z */ - - /* Final punctuation. */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* { */ - { ISFUNC, rl_vi_column }, /* | */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* } */ - { ISFUNC, rl_vi_change_case }, /* ~ */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* RUBOUT */ - -#if KEYMAP_SIZE > 128 - /* Undefined keys. */ - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 } -#endif /* KEYMAP_SIZE > 128 */ -}; - - -KEYMAP_ENTRY_ARRAY vi_insertion_keymap = { - /* The regular control keys come first. */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-@ */ - { ISFUNC, rl_insert }, /* Control-a */ - { ISFUNC, rl_insert }, /* Control-b */ - { ISFUNC, rl_insert }, /* Control-c */ - { ISFUNC, rl_vi_eof_maybe }, /* Control-d */ - { ISFUNC, rl_insert }, /* Control-e */ - { ISFUNC, rl_insert }, /* Control-f */ - { ISFUNC, rl_insert }, /* Control-g */ - { ISFUNC, rl_rubout }, /* Control-h */ - { ISFUNC, rl_complete }, /* Control-i */ - { ISFUNC, rl_newline }, /* Control-j */ - { ISFUNC, rl_insert }, /* Control-k */ - { ISFUNC, rl_insert }, /* Control-l */ - { ISFUNC, rl_newline }, /* Control-m */ - { ISFUNC, rl_insert }, /* Control-n */ - { ISFUNC, rl_insert }, /* Control-o */ - { ISFUNC, rl_insert }, /* Control-p */ - { ISFUNC, rl_insert }, /* Control-q */ - { ISFUNC, rl_reverse_search_history }, /* Control-r */ - { ISFUNC, rl_forward_search_history }, /* Control-s */ - { ISFUNC, rl_transpose_chars }, /* Control-t */ - { ISFUNC, rl_unix_line_discard }, /* Control-u */ - { ISFUNC, rl_quoted_insert }, /* Control-v */ - { ISFUNC, rl_unix_word_rubout }, /* Control-w */ - { ISFUNC, rl_insert }, /* Control-x */ - { ISFUNC, rl_yank }, /* Control-y */ - { ISFUNC, rl_insert }, /* Control-z */ - - { ISFUNC, rl_vi_movement_mode }, /* Control-[ */ - { ISFUNC, rl_insert }, /* Control-\ */ - { ISFUNC, rl_insert }, /* Control-] */ - { ISFUNC, rl_insert }, /* Control-^ */ - { ISFUNC, rl_vi_undo }, /* Control-_ */ - - /* The start of printing characters. */ - { ISFUNC, rl_insert }, /* SPACE */ - { ISFUNC, rl_insert }, /* ! */ - { ISFUNC, rl_insert }, /* " */ - { ISFUNC, rl_insert }, /* # */ - { ISFUNC, rl_insert }, /* $ */ - { ISFUNC, rl_insert }, /* % */ - { ISFUNC, rl_insert }, /* & */ - { ISFUNC, rl_insert }, /* ' */ - { ISFUNC, rl_insert }, /* ( */ - { ISFUNC, rl_insert }, /* ) */ - { ISFUNC, rl_insert }, /* * */ - { ISFUNC, rl_insert }, /* + */ - { ISFUNC, rl_insert }, /* , */ - { ISFUNC, rl_insert }, /* - */ - { ISFUNC, rl_insert }, /* . */ - { ISFUNC, rl_insert }, /* / */ - - /* Regular digits. */ - { ISFUNC, rl_insert }, /* 0 */ - { ISFUNC, rl_insert }, /* 1 */ - { ISFUNC, rl_insert }, /* 2 */ - { ISFUNC, rl_insert }, /* 3 */ - { ISFUNC, rl_insert }, /* 4 */ - { ISFUNC, rl_insert }, /* 5 */ - { ISFUNC, rl_insert }, /* 6 */ - { ISFUNC, rl_insert }, /* 7 */ - { ISFUNC, rl_insert }, /* 8 */ - { ISFUNC, rl_insert }, /* 9 */ - - /* A little more punctuation. */ - { ISFUNC, rl_insert }, /* : */ - { ISFUNC, rl_insert }, /* ; */ - { ISFUNC, rl_insert }, /* < */ - { ISFUNC, rl_insert }, /* = */ - { ISFUNC, rl_insert }, /* > */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* @ */ - - /* Uppercase alphabet. */ - { ISFUNC, rl_insert }, /* A */ - { ISFUNC, rl_insert }, /* B */ - { ISFUNC, rl_insert }, /* C */ - { ISFUNC, rl_insert }, /* D */ - { ISFUNC, rl_insert }, /* E */ - { ISFUNC, rl_insert }, /* F */ - { ISFUNC, rl_insert }, /* G */ - { ISFUNC, rl_insert }, /* H */ - { ISFUNC, rl_insert }, /* I */ - { ISFUNC, rl_insert }, /* J */ - { ISFUNC, rl_insert }, /* K */ - { ISFUNC, rl_insert }, /* L */ - { ISFUNC, rl_insert }, /* M */ - { ISFUNC, rl_insert }, /* N */ - { ISFUNC, rl_insert }, /* O */ - { ISFUNC, rl_insert }, /* P */ - { ISFUNC, rl_insert }, /* Q */ - { ISFUNC, rl_insert }, /* R */ - { ISFUNC, rl_insert }, /* S */ - { ISFUNC, rl_insert }, /* T */ - { ISFUNC, rl_insert }, /* U */ - { ISFUNC, rl_insert }, /* V */ - { ISFUNC, rl_insert }, /* W */ - { ISFUNC, rl_insert }, /* X */ - { ISFUNC, rl_insert }, /* Y */ - { ISFUNC, rl_insert }, /* Z */ - - /* Some more punctuation. */ - { ISFUNC, rl_insert }, /* [ */ - { ISFUNC, rl_insert }, /* \ */ - { ISFUNC, rl_insert }, /* ] */ - { ISFUNC, rl_insert }, /* ^ */ - { ISFUNC, rl_insert }, /* _ */ - { ISFUNC, rl_insert }, /* ` */ - - /* Lowercase alphabet. */ - { ISFUNC, rl_insert }, /* a */ - { ISFUNC, rl_insert }, /* b */ - { ISFUNC, rl_insert }, /* c */ - { ISFUNC, rl_insert }, /* d */ - { ISFUNC, rl_insert }, /* e */ - { ISFUNC, rl_insert }, /* f */ - { ISFUNC, rl_insert }, /* g */ - { ISFUNC, rl_insert }, /* h */ - { ISFUNC, rl_insert }, /* i */ - { ISFUNC, rl_insert }, /* j */ - { ISFUNC, rl_insert }, /* k */ - { ISFUNC, rl_insert }, /* l */ - { ISFUNC, rl_insert }, /* m */ - { ISFUNC, rl_insert }, /* n */ - { ISFUNC, rl_insert }, /* o */ - { ISFUNC, rl_insert }, /* p */ - { ISFUNC, rl_insert }, /* q */ - { ISFUNC, rl_insert }, /* r */ - { ISFUNC, rl_insert }, /* s */ - { ISFUNC, rl_insert }, /* t */ - { ISFUNC, rl_insert }, /* u */ - { ISFUNC, rl_insert }, /* v */ - { ISFUNC, rl_insert }, /* w */ - { ISFUNC, rl_insert }, /* x */ - { ISFUNC, rl_insert }, /* y */ - { ISFUNC, rl_insert }, /* z */ - - /* Final punctuation. */ - { ISFUNC, rl_insert }, /* { */ - { ISFUNC, rl_insert }, /* | */ - { ISFUNC, rl_insert }, /* } */ - { ISFUNC, rl_insert }, /* ~ */ - { ISFUNC, rl_rubout }, /* RUBOUT */ - -#if KEYMAP_SIZE > 128 - /* Pure 8-bit characters (128 - 159). - These might be used in some - character sets. */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* ? */ - - /* ISO Latin-1 characters (160 - 255) */ - { ISFUNC, rl_insert }, /* No-break space */ - { ISFUNC, rl_insert }, /* Inverted exclamation mark */ - { ISFUNC, rl_insert }, /* Cent sign */ - { ISFUNC, rl_insert }, /* Pound sign */ - { ISFUNC, rl_insert }, /* Currency sign */ - { ISFUNC, rl_insert }, /* Yen sign */ - { ISFUNC, rl_insert }, /* Broken bar */ - { ISFUNC, rl_insert }, /* Section sign */ - { ISFUNC, rl_insert }, /* Diaeresis */ - { ISFUNC, rl_insert }, /* Copyright sign */ - { ISFUNC, rl_insert }, /* Feminine ordinal indicator */ - { ISFUNC, rl_insert }, /* Left pointing double angle quotation mark */ - { ISFUNC, rl_insert }, /* Not sign */ - { ISFUNC, rl_insert }, /* Soft hyphen */ - { ISFUNC, rl_insert }, /* Registered sign */ - { ISFUNC, rl_insert }, /* Macron */ - { ISFUNC, rl_insert }, /* Degree sign */ - { ISFUNC, rl_insert }, /* Plus-minus sign */ - { ISFUNC, rl_insert }, /* Superscript two */ - { ISFUNC, rl_insert }, /* Superscript three */ - { ISFUNC, rl_insert }, /* Acute accent */ - { ISFUNC, rl_insert }, /* Micro sign */ - { ISFUNC, rl_insert }, /* Pilcrow sign */ - { ISFUNC, rl_insert }, /* Middle dot */ - { ISFUNC, rl_insert }, /* Cedilla */ - { ISFUNC, rl_insert }, /* Superscript one */ - { ISFUNC, rl_insert }, /* Masculine ordinal indicator */ - { ISFUNC, rl_insert }, /* Right pointing double angle quotation mark */ - { ISFUNC, rl_insert }, /* Vulgar fraction one quarter */ - { ISFUNC, rl_insert }, /* Vulgar fraction one half */ - { ISFUNC, rl_insert }, /* Vulgar fraction three quarters */ - { ISFUNC, rl_insert }, /* Inverted questionk mark */ - { ISFUNC, rl_insert }, /* Latin capital letter a with grave */ - { ISFUNC, rl_insert }, /* Latin capital letter a with acute */ - { ISFUNC, rl_insert }, /* Latin capital letter a with circumflex */ - { ISFUNC, rl_insert }, /* Latin capital letter a with tilde */ - { ISFUNC, rl_insert }, /* Latin capital letter a with diaeresis */ - { ISFUNC, rl_insert }, /* Latin capital letter a with ring above */ - { ISFUNC, rl_insert }, /* Latin capital letter ae */ - { ISFUNC, rl_insert }, /* Latin capital letter c with cedilla */ - { ISFUNC, rl_insert }, /* Latin capital letter e with grave */ - { ISFUNC, rl_insert }, /* Latin capital letter e with acute */ - { ISFUNC, rl_insert }, /* Latin capital letter e with circumflex */ - { ISFUNC, rl_insert }, /* Latin capital letter e with diaeresis */ - { ISFUNC, rl_insert }, /* Latin capital letter i with grave */ - { ISFUNC, rl_insert }, /* Latin capital letter i with acute */ - { ISFUNC, rl_insert }, /* Latin capital letter i with circumflex */ - { ISFUNC, rl_insert }, /* Latin capital letter i with diaeresis */ - { ISFUNC, rl_insert }, /* Latin capital letter eth (Icelandic) */ - { ISFUNC, rl_insert }, /* Latin capital letter n with tilde */ - { ISFUNC, rl_insert }, /* Latin capital letter o with grave */ - { ISFUNC, rl_insert }, /* Latin capital letter o with acute */ - { ISFUNC, rl_insert }, /* Latin capital letter o with circumflex */ - { ISFUNC, rl_insert }, /* Latin capital letter o with tilde */ - { ISFUNC, rl_insert }, /* Latin capital letter o with diaeresis */ - { ISFUNC, rl_insert }, /* Multiplication sign */ - { ISFUNC, rl_insert }, /* Latin capital letter o with stroke */ - { ISFUNC, rl_insert }, /* Latin capital letter u with grave */ - { ISFUNC, rl_insert }, /* Latin capital letter u with acute */ - { ISFUNC, rl_insert }, /* Latin capital letter u with circumflex */ - { ISFUNC, rl_insert }, /* Latin capital letter u with diaeresis */ - { ISFUNC, rl_insert }, /* Latin capital letter Y with acute */ - { ISFUNC, rl_insert }, /* Latin capital letter thorn (Icelandic) */ - { ISFUNC, rl_insert }, /* Latin small letter sharp s (German) */ - { ISFUNC, rl_insert }, /* Latin small letter a with grave */ - { ISFUNC, rl_insert }, /* Latin small letter a with acute */ - { ISFUNC, rl_insert }, /* Latin small letter a with circumflex */ - { ISFUNC, rl_insert }, /* Latin small letter a with tilde */ - { ISFUNC, rl_insert }, /* Latin small letter a with diaeresis */ - { ISFUNC, rl_insert }, /* Latin small letter a with ring above */ - { ISFUNC, rl_insert }, /* Latin small letter ae */ - { ISFUNC, rl_insert }, /* Latin small letter c with cedilla */ - { ISFUNC, rl_insert }, /* Latin small letter e with grave */ - { ISFUNC, rl_insert }, /* Latin small letter e with acute */ - { ISFUNC, rl_insert }, /* Latin small letter e with circumflex */ - { ISFUNC, rl_insert }, /* Latin small letter e with diaeresis */ - { ISFUNC, rl_insert }, /* Latin small letter i with grave */ - { ISFUNC, rl_insert }, /* Latin small letter i with acute */ - { ISFUNC, rl_insert }, /* Latin small letter i with circumflex */ - { ISFUNC, rl_insert }, /* Latin small letter i with diaeresis */ - { ISFUNC, rl_insert }, /* Latin small letter eth (Icelandic) */ - { ISFUNC, rl_insert }, /* Latin small letter n with tilde */ - { ISFUNC, rl_insert }, /* Latin small letter o with grave */ - { ISFUNC, rl_insert }, /* Latin small letter o with acute */ - { ISFUNC, rl_insert }, /* Latin small letter o with circumflex */ - { ISFUNC, rl_insert }, /* Latin small letter o with tilde */ - { ISFUNC, rl_insert }, /* Latin small letter o with diaeresis */ - { ISFUNC, rl_insert }, /* Division sign */ - { ISFUNC, rl_insert }, /* Latin small letter o with stroke */ - { ISFUNC, rl_insert }, /* Latin small letter u with grave */ - { ISFUNC, rl_insert }, /* Latin small letter u with acute */ - { ISFUNC, rl_insert }, /* Latin small letter u with circumflex */ - { ISFUNC, rl_insert }, /* Latin small letter u with diaeresis */ - { ISFUNC, rl_insert }, /* Latin small letter y with acute */ - { ISFUNC, rl_insert }, /* Latin small letter thorn (Icelandic) */ - { ISFUNC, rl_insert } /* Latin small letter y with diaeresis */ -#endif /* KEYMAP_SIZE > 128 */ -}; - -/* Unused for the time being. */ -#if 0 -KEYMAP_ENTRY_ARRAY vi_escape_keymap = { - /* The regular control keys come first. */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-@ */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-a */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-b */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-c */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-d */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-e */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-f */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-g */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-h */ - { ISFUNC, rl_tab_insert}, /* Control-i */ - { ISFUNC, rl_emacs_editing_mode}, /* Control-j */ - { ISFUNC, rl_kill_line }, /* Control-k */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-l */ - { ISFUNC, rl_emacs_editing_mode}, /* Control-m */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-n */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-o */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-p */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-q */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-r */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-s */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-t */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-u */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-v */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-w */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-x */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-y */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-z */ - - { ISFUNC, rl_vi_movement_mode }, /* Control-[ */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-\ */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-] */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-^ */ - { ISFUNC, rl_vi_undo }, /* Control-_ */ - - /* The start of printing characters. */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* SPACE */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ! */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* " */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* # */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* $ */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* % */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* & */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ' */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ( */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ) */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* * */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* + */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* , */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* - */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* . */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* / */ - - /* Regular digits. */ - { ISFUNC, rl_vi_arg_digit }, /* 0 */ - { ISFUNC, rl_vi_arg_digit }, /* 1 */ - { ISFUNC, rl_vi_arg_digit }, /* 2 */ - { ISFUNC, rl_vi_arg_digit }, /* 3 */ - { ISFUNC, rl_vi_arg_digit }, /* 4 */ - { ISFUNC, rl_vi_arg_digit }, /* 5 */ - { ISFUNC, rl_vi_arg_digit }, /* 6 */ - { ISFUNC, rl_vi_arg_digit }, /* 7 */ - { ISFUNC, rl_vi_arg_digit }, /* 8 */ - { ISFUNC, rl_vi_arg_digit }, /* 9 */ - - /* A little more punctuation. */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* : */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ; */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* < */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* = */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* > */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ? */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* @ */ - - /* Uppercase alphabet. */ - { ISFUNC, rl_do_lowercase_version }, /* A */ - { ISFUNC, rl_do_lowercase_version }, /* B */ - { ISFUNC, rl_do_lowercase_version }, /* C */ - { ISFUNC, rl_do_lowercase_version }, /* D */ - { ISFUNC, rl_do_lowercase_version }, /* E */ - { ISFUNC, rl_do_lowercase_version }, /* F */ - { ISFUNC, rl_do_lowercase_version }, /* G */ - { ISFUNC, rl_do_lowercase_version }, /* H */ - { ISFUNC, rl_do_lowercase_version }, /* I */ - { ISFUNC, rl_do_lowercase_version }, /* J */ - { ISFUNC, rl_do_lowercase_version }, /* K */ - { ISFUNC, rl_do_lowercase_version }, /* L */ - { ISFUNC, rl_do_lowercase_version }, /* M */ - { ISFUNC, rl_do_lowercase_version }, /* N */ - { ISFUNC, rl_do_lowercase_version }, /* O */ - { ISFUNC, rl_do_lowercase_version }, /* P */ - { ISFUNC, rl_do_lowercase_version }, /* Q */ - { ISFUNC, rl_do_lowercase_version }, /* R */ - { ISFUNC, rl_do_lowercase_version }, /* S */ - { ISFUNC, rl_do_lowercase_version }, /* T */ - { ISFUNC, rl_do_lowercase_version }, /* U */ - { ISFUNC, rl_do_lowercase_version }, /* V */ - { ISFUNC, rl_do_lowercase_version }, /* W */ - { ISFUNC, rl_do_lowercase_version }, /* X */ - { ISFUNC, rl_do_lowercase_version }, /* Y */ - { ISFUNC, rl_do_lowercase_version }, /* Z */ - - /* Some more punctuation. */ - { ISFUNC, rl_arrow_keys }, /* [ */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* \ */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ] */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ^ */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* _ */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ` */ - - /* Lowercase alphabet. */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* a */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* b */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* c */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* d */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* e */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* f */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* g */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* h */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* i */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* j */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* k */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* l */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* m */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* n */ - { ISFUNC, rl_arrow_keys }, /* o */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* p */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* q */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* r */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* s */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* t */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* u */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* v */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* w */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* x */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* y */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* z */ - - /* Final punctuation. */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* { */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* | */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* } */ - { ISFUNC, (rl_command_func_t *)0x0 }, /* ~ */ - { ISFUNC, rl_backward_kill_word }, /* RUBOUT */ - -#if KEYMAP_SIZE > 128 - /* Undefined keys. */ - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 }, - { ISFUNC, (rl_command_func_t *)0x0 } -#endif /* KEYMAP_SIZE > 128 */ -}; -#endif diff --git a/lib/readline/vi_mode.c~ b/lib/readline/vi_mode.c~ deleted file mode 100644 index 75bee748b..000000000 --- a/lib/readline/vi_mode.c~ +++ /dev/null @@ -1,1819 +0,0 @@ -/* vi_mode.c -- A vi emulation mode for Bash. - Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ - -/* Copyright (C) 1987-2008 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 * const 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]; -static int _rl_vi_last_search_mblen; -#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 * const 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 void _rl_vi_backup PARAMS((void)); - -static int _rl_vi_arg_dispatch PARAMS((int)); -static int rl_digit_loop1 PARAMS((void)); - -static int _rl_vi_set_mark PARAMS((void)); -static int _rl_vi_goto_mark PARAMS((void)); - -static void _rl_vi_append_forward PARAMS((int)); - -static int _rl_vi_callback_getchar PARAMS((char *, int)); - -#if defined (READLINE_CALLBACKS) -static int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *)); -static int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *)); -static int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *)); -static int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *)); -#endif - -void -_rl_vi_initialize_line () -{ - register int i; - - for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) - vi_mark_chars[i] = -1; - - RL_UNSETSTATE(RL_STATE_VICMDONCE); -} - -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_vi_backup (); - } - /* Ditto for redoing an insert with `I', but move to the beginning of the - line like the `I' command does. */ - else if (_rl_vi_last_command == 'I' && vi_insert_buffer && *vi_insert_buffer) - { - rl_beg_of_line (1, 'I'); - _rl_vi_stuff_insert (count); - if (rl_point > 0) - _rl_vi_backup (); - } - /* Ditto for redoing an insert with `a', but move forward a character first - like the `a' command does. */ - else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer) - { - _rl_vi_append_forward ('a'); - _rl_vi_stuff_insert (count); - if (rl_point > 0) - _rl_vi_backup (); - } - /* Ditto for redoing an insert with `A', but move to the end of the line - like the `A' command does. */ - else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer) - { - rl_end_of_line (1, 'A'); - _rl_vi_stuff_insert (count); - if (rl_point > 0) - _rl_vi_backup (); - } - 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_free_saved_history_line (); - rl_noninc_forward_search (count, key); - break; - - case '/': - _rl_free_saved_history_line (); - 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_insert_mode (1, key); - return (0); -} - -static void -_rl_vi_append_forward (key) - int key; -{ - int point; - - if (rl_point < rl_end) - { - if (MB_CUR_MAX == 1 || rl_byte_oriented) - rl_point++; - else - { - point = rl_point; - rl_forward_char (1, key); - if (point == rl_point) - rl_point = rl_end; - } - } -} - -int -rl_vi_append_mode (count, key) - int count, key; -{ - _rl_vi_append_forward (key); - rl_vi_start_inserting (key, 1, rl_arg_sign); - return (0); -} - -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); -} - -int -rl_vi_insert_mode (count, key) - int count, key; -{ - rl_vi_start_inserting (key, 1, rl_arg_sign); - return (0); -} - -static void -_rl_vi_save_insert (up) - UNDO_LIST *up; -{ - int len, start, end; - - if (up == 0 || up->what != UNDO_INSERT) - { - 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_undo_list && (_rl_vi_last_key_before_insert == 'i' || - _rl_vi_last_key_before_insert == 'a' || - _rl_vi_last_key_before_insert == 'I' || - _rl_vi_last_key_before_insert == 'A')) - _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 (); - - /* This is how POSIX.2 says `U' should behave -- everything up until the - first time you go into command mode should not be undone. */ - if (RL_ISSTATE (RL_STATE_VICMDONCE) == 0) - rl_free_undo_list (); - - RL_SETSTATE (RL_STATE_VICMDONCE); - 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 mlen, p; - 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) - { - p = rl_point; - mlen = wcrtomb (mb, wc, &ps); - if (mlen >= 0) - mb[mlen] = '\0'; - rl_begin_undo_group (); - rl_vi_delete (1, 0); - if (rl_point < p) /* Did we retreat at EOL? */ - rl_point++; /* XXX - should we advance more than 1 for mbchar? */ - 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; -{ - int c, p; - - /* Don't try this on an empty line. */ - if (rl_point >= rl_end) - return (0); - - c = 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) - { - p = rl_point; - rl_begin_undo_group (); - rl_vi_delete (1, c); - if (rl_point < p) /* Did we retreat at EOL? */ - rl_point++; - _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); - - while (count--) - rl_yank (1, key); - - rl_backward_char (1, key); - return (0); -} - -static void -_rl_vi_backup () -{ - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); - else - rl_point--; -} - -int -rl_vi_check () -{ - 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); - - if (c < 0) - { - *nextkey = 0; - return -1; - } - - *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_SETSTATE (RL_STATE_NUMERICARG|RL_STATE_VIMOTION); - rl_digit_loop1 (); - RL_UNSETSTATE (RL_STATE_VIMOTION); - rl_numeric_arg *= save; - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); /* real command */ - RL_UNSETSTATE(RL_STATE_MOREINPUT); - if (c < 0) - { - *nextkey = 0; - return -1; - } - *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); -} - -/* Process C as part of the current numeric argument. Return -1 if the - argument should be aborted, 0 if we should not read any more chars, and - 1 if we should continue to read chars. */ -static int -_rl_vi_arg_dispatch (c) - int c; -{ - int key; - - key = c; - if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument) - { - rl_numeric_arg *= 4; - return 1; - } - - 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; - return 1; - } - else - { - rl_clear_message (); - rl_stuff_char (key); - 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 c, r; - - while (1) - { - if (_rl_arg_overflow ()) - return 1; - - c = _rl_arg_getchar (); - - r = _rl_vi_arg_dispatch (c); - if (r <= 0) - break; - } - - RL_UNSETSTATE(RL_STATE_NUMERICARG); - return (0); -} - -int -rl_vi_delete_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. */ - if (((strchr (" l|h^0bBFT`", c) == 0) && (rl_point >= start_pos)) && - (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^0bBFT`", c) == 0) && (rl_point >= start_pos)) && - (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, start_pos; - - if (_rl_uppercase_p (key)) - rl_stuff_char ('$'); - - 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. */ - if (((strchr (" l|h^0%bBFT`", c) == 0) && (rl_point >= start_pos)) && - (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 = start_pos; - - return (0); -} - -int -rl_vi_rubout (count, key) - int count, key; -{ - int opoint; - - if (count < 0) - return (rl_vi_delete (-count, key)); - - if (rl_point == 0) - { - rl_ding (); - return -1; - } - - opoint = rl_point; - if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_backward_char (count, key); - else 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; - - if (rl_point < 0) - rl_point = 0; - - rl_kill_text (rl_point, opoint); - - return (0); -} - -int -rl_vi_delete (count, key) - int count, key; -{ - int end; - - if (count < 0) - return (rl_vi_rubout (-count, key)); - - 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)); -} - -static int _rl_cs_dir, _rl_cs_orig_dir; - -#if defined (READLINE_CALLBACKS) -static int -_rl_vi_callback_char_search (data) - _rl_callback_generic_arg *data; -{ - int c; -#if defined (HANDLE_MULTIBYTE) - c = _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); -#else - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); -#endif - - if (c <= 0) - return -1; - -#if !defined (HANDLE_MULTIBYTE) - _rl_vi_last_search_char = c; -#endif - - _rl_callback_func = 0; - _rl_want_redisplay = 1; - -#if defined (HANDLE_MULTIBYTE) - return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen)); -#else - return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char)); -#endif -} -#endif - -int -rl_vi_char_search (count, key) - int count, key; -{ - int c; -#if defined (HANDLE_MULTIBYTE) - static char *target; - static int tlen; -#else - static char target; -#endif - - if (key == ';' || key == ',') - _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir; - else - { - switch (key) - { - case 't': - _rl_cs_orig_dir = _rl_cs_dir = FTO; - break; - - case 'T': - _rl_cs_orig_dir = _rl_cs_dir = BTO; - break; - - case 'f': - _rl_cs_orig_dir = _rl_cs_dir = FFIND; - break; - - case 'F': - _rl_cs_orig_dir = _rl_cs_dir = BFIND; - break; - } - - if (vi_redoing) - { - /* set target and tlen below */ - } -#if defined (READLINE_CALLBACKS) - else if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - _rl_callback_data = _rl_callback_data_alloc (count); - _rl_callback_data->i1 = _rl_cs_dir; - _rl_callback_func = _rl_vi_callback_char_search; - return (0); - } -#endif - else - { -#if defined (HANDLE_MULTIBYTE) - c = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); - if (c <= 0) - return -1; - _rl_vi_last_search_mblen = c; -#else - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - if (c < 0) - return -1; - _rl_vi_last_search_char = c; -#endif - } - } - -#if defined (HANDLE_MULTIBYTE) - target = _rl_vi_last_search_mbchar; - tlen = _rl_vi_last_search_mblen; -#else - target = _rl_vi_last_search_char; -#endif - -#if defined (HANDLE_MULTIBYTE) - return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen)); -#else - return (_rl_char_search_internal (count, _rl_cs_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; - } -} - -static int -_rl_vi_change_char (count, c, mb) - int count, c; - char *mb; -{ - int p; - - 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 (rl_point < p) /* Did we retreat at EOL? */ - rl_point++; -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - rl_insert_text (mb); - else -#endif - _rl_insert_char (1, c); - } - - /* The cursor shall be left on the last character changed. */ - rl_backward_char (1, c); - - rl_end_undo_group (); - - return (0); -} - -static int -_rl_vi_callback_getchar (mb, mlen) - char *mb; - int mlen; -{ - int c; - - RL_SETSTATE(RL_STATE_MOREINPUT); - c = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (c < 0) - return -1; - -#if defined (HANDLE_MULTIBYTE) - if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - c = _rl_read_mbstring (c, mb, mlen); -#endif - - return c; -} - -#if defined (READLINE_CALLBACKS) -static int -_rl_vi_callback_change_char (data) - _rl_callback_generic_arg *data; -{ - int c; - char mb[MB_LEN_MAX]; - - _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); - - if (c < 0) - return -1; - - _rl_callback_func = 0; - _rl_want_redisplay = 1; - - return (_rl_vi_change_char (data->count, c, mb)); -} -#endif - -int -rl_vi_change_char (count, key) - int count, key; -{ - int c; - char mb[MB_LEN_MAX]; - - if (vi_redoing) - { - c = _rl_vi_last_replacement; - mb[0] = c; - mb[1] = '\0'; - } -#if defined (READLINE_CALLBACKS) - else if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - _rl_callback_data = _rl_callback_data_alloc (count); - _rl_callback_func = _rl_vi_callback_change_char; - return (0); - } -#endif - else - _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); - - if (c < 0) - return -1; - - return (_rl_vi_change_char (count, c, mb)); -} - -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. */ -static int -_rl_vi_set_mark () -{ - int ch; - - RL_SETSTATE(RL_STATE_MOREINPUT); - ch = rl_read_key (); - RL_UNSETSTATE(RL_STATE_MOREINPUT); - - if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */ - { - rl_ding (); - return -1; - } - ch -= 'a'; - vi_mark_chars[ch] = rl_point; - return 0; -} - -#if defined (READLINE_CALLBACKS) -static int -_rl_vi_callback_set_mark (data) - _rl_callback_generic_arg *data; -{ - _rl_callback_func = 0; - _rl_want_redisplay = 1; - - return (_rl_vi_set_mark ()); -} -#endif - -int -rl_vi_set_mark (count, key) - int count, key; -{ -#if defined (READLINE_CALLBACKS) - if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - _rl_callback_data = 0; - _rl_callback_func = _rl_vi_callback_set_mark; - return (0); - } -#endif - - return (_rl_vi_set_mark ()); -} - -static int -_rl_vi_goto_mark () -{ - 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 < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */ - { - rl_ding (); - return -1; - } - - ch -= 'a'; - if (vi_mark_chars[ch] == -1) - { - rl_ding (); - return -1; - } - rl_point = vi_mark_chars[ch]; - return 0; -} - -#if defined (READLINE_CALLBACKS) -static int -_rl_vi_callback_goto_mark (data) - _rl_callback_generic_arg *data; -{ - _rl_callback_func = 0; - _rl_want_redisplay = 1; - - return (_rl_vi_goto_mark ()); -} -#endif - -int -rl_vi_goto_mark (count, key) - int count, key; -{ -#if defined (READLINE_CALLBACKS) - if (RL_ISSTATE (RL_STATE_CALLBACK)) - { - _rl_callback_data = 0; - _rl_callback_func = _rl_vi_callback_goto_mark; - return (0); - } -#endif - - return (_rl_vi_goto_mark ()); -} -#endif /* VI_MODE */ diff --git a/lib/sh/Makefile.in~ b/lib/sh/Makefile.in~ deleted file mode 100644 index 55396b056..000000000 --- a/lib/sh/Makefile.in~ +++ /dev/null @@ -1,515 +0,0 @@ -# -# Makefile for the Bash library -# -# -# Copyright (C) 1998-2005 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. - -PACKAGE = @PACKAGE_NAME@ -VERSION = @PACKAGE_VERSION@ - -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_VERSION = @PACKAGE_VERSION@ - -srcdir = @srcdir@ -VPATH = .:@srcdir@ -topdir = @top_srcdir@ -BUILD_DIR = @BUILD_DIR@ - -LIBBUILD = ${BUILD_DIR}/lib - -BASHINCDIR = ${topdir}/include - -INTL_LIBSRC = ${topdir}/lib/intl -INTL_BUILDDIR = ${LIBBUILD}/intl -INTL_INC = @INTL_INC@ -LIBINTL_H = @LIBINTL_H@ - -datarootdir = @datarootdir@ - -INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_DATA = @INSTALL_DATA@ - -CC = @CC@ -RANLIB = @RANLIB@ -AR = @AR@ -ARFLAGS = @ARFLAGS@ -RM = rm -f -CP = cp -MV = mv - -SHELL = @MAKE_SHELL@ - -CFLAGS = @CFLAGS@ -LOCAL_CFLAGS = @LOCAL_CFLAGS@ ${DEBUG} -CPPFLAGS = @CPPFLAGS@ -LDFLAGS = @LDFLAGS@ @LOCAL_LDFLAGS@ - -PROFILE_FLAGS = @PROFILE_FLAGS@ - -DEFS = @DEFS@ -LOCAL_DEFS = @LOCAL_DEFS@ - -INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/lib -I$(BASHINCDIR) -I$(srcdir) $(INTL_INC) - -CCFLAGS = ${PROFILE_FLAGS} ${INCLUDES} $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) \ - $(CFLAGS) $(CPPFLAGS) - -GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual \ - -Wcast-align -Wstrict-prototypes -Wconversion \ - -Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic - -.c.o: - $(CC) -c $(CCFLAGS) $< - -# The name of the library target. -LIBRARY_NAME = libsh.a - -# The C code source files for this library. -CSOURCES = clktck.c clock.c getcwd.c getenv.c oslib.c setlinebuf.c \ - strcasecmp.c strerror.c strtod.c strtol.c strtoul.c \ - vprint.c itos.c rename.c zread.c zwrite.c shtty.c \ - inet_aton.c netconn.c netopen.c strpbrk.c timeval.c makepath.c \ - pathcanon.c pathphys.c tmpfile.c stringlist.c stringvec.c spell.c \ - shquote.c strtrans.c strindex.c snprintf.c mailstat.c \ - fmtulong.c fmtullong.c fmtumax.c shmatch.c strnlen.c \ - strtoll.c strtoull.c strtoimax.c strtoumax.c memset.c strstr.c \ - mktime.c strftime.c xstrchr.c zcatfd.c zmapfd.c winsize.c eaccess.c \ - wcsdup.c fpurge.c zgetline.c mbscmp.c uconvert.c ufuncs.c \ - casemod.c fdprintf.c - -# The header files for this library. -HSOURCES = - -# The object files contained in $(LIBRARY_NAME) -LIBOBJS = @LIBOBJS@ -OBJECTS = clktck.o clock.o getenv.o oslib.o setlinebuf.o strnlen.o \ - itos.o zread.o zwrite.o shtty.o shmatch.o eaccess.o \ - netconn.o netopen.o timeval.o makepath.o pathcanon.o \ - pathphys.o tmpfile.o stringlist.o stringvec.o spell.o shquote.o \ - strtrans.o strindex.o snprintf.o mailstat.o fmtulong.o \ - fmtullong.o fmtumax.o xstrchr.o zcatfd.o zmapfd.o winsize.o wcsdup.o - fpurge.o zgetline.o mbscmp.o uconvert.o ufuncs.o casemod.o ${LIBOBJS} - -SUPPORT = Makefile - -all: $(LIBRARY_NAME) - -$(LIBRARY_NAME): $(OBJECTS) - $(RM) $@ - $(AR) $(ARFLAGS) $@ $(OBJECTS) - -test -n "$(RANLIB)" && $(RANLIB) $@ - -force: - -# The rule for 'includes' is written funny so that the if statement -# always returns TRUE unless there really was an error installing the -# include files. -install: - -clean: - $(RM) $(OBJECTS) $(LIBRARY_NAME) - -realclean distclean maintainer-clean: clean - $(RM) Makefile - -mostlyclean: clean - -# Dependencies - -${BUILD_DIR}/version.h: ${BUILD_DIR}/config.h ${BUILD_DIR}/Makefile Makefile - -( cd ${BUILD_DIR} && ${MAKE} ${MFLAGS} version.h ) - -# rules for losing makes, like SunOS -casemod.o: casemod.c -clktck.o: clktck.c -clock.o: clock.c -eaccess.o: eaccess.c -fmtullong.o: fmtullong.c -fmtulong.o: fmtulong.c -fmtumax.o: fmtumax.c -fpurge.o: fpurge.c -getcwd.o: getcwd.c -getenv.o: getenv.c -inet_aton.o: inet_aton.c -itos.o: itos.c -mailstat.o: mailstat.c -makepath.o: makepath.c -mbscmp.o: mbscmp.c -memset.o: memset.c -mktime.o: mktime.c -netconn.o: netconn.c -netopen.o: netopen.c -oslib.o: oslib.c -pathcanon.o: pathcanon.c -pathphys.o: pathphys.c -rename.o: rename.c -setlinebuf.o: setlinebuf.c -shquote.o: shquote.c -shtty.o: shtty.c -snprintf.o: snprintf.c -spell.o: spell.c -strcasecmp.o: strcasecmp.c -strerror.o: strerror.c -strftime.o: strftime.c -strindex.o: strindex.c -stringlist.o: stringlist.c -stringvec.o: stringvec.c -strnlen.o: strnlen.c -strpbrk.o: strpbrk.c -strtod.o: strtod.c -strtoimax.o: strtoimax.c -strtol.o: strtol.c -strtoll.o: strtoll.c -strtoul.o: strtoul.c -strtoull.o: strtoull.c -strtoumax.o: strtoumax.c -strtrans.o: strtrans.c -times.o: times.c -timeval.o: timeval.c -tmpfile.o: tmpfile.c -uconvert.o: uconvert.c -ufuncs.o: ufuncs.c -vprint.o: vprint.c -wcsdup.o: wcsdup.c -xstrchr.o: xstrchr.c -zcatfd.o: zcatfd.c -zmapfd.o: zmapfd.c -zgetline.o: zgetline.c -zread.o: zread.c -zwrite.o: zwrite.c - -# dependencies for c files that include other c files -fmtullong.o: fmtulong.c -fmtumax.o: fmtulong.c -strtoll.o: strtol.c -strtoul.o: strtol.c -strtoull.o: strtol.c - -# all files in the library depend on config.h -casemod.o: ${BUILD_DIR}/config.h -clktck.o: ${BUILD_DIR}/config.h -clock.o: ${BUILD_DIR}/config.h -eaccess.o: ${BUILD_DIR}/config.h -fmtullong.o: ${BUILD_DIR}/config.h -fmtulong.o: ${BUILD_DIR}/config.h -fmtumax.o: ${BUILD_DIR}/config.h -fpurge.o: ${BUILD_DIR}/config.h -getcwd.o: ${BUILD_DIR}/config.h -getenv.o: ${BUILD_DIR}/config.h -inet_aton.o: ${BUILD_DIR}/config.h -itos.o: ${BUILD_DIR}/config.h -mailstat.o: ${BUILD_DIR}/config.h -makepath.o: ${BUILD_DIR}/config.h -mbscmp.o: ${BUILD_DIR}/config.h -memset.o: ${BUILD_DIR}/config.h -mktime.o: ${BUILD_DIR}/config.h -netconn.o: ${BUILD_DIR}/config.h -netopen.o: ${BUILD_DIR}/config.h -oslib.o: ${BUILD_DIR}/config.h -pathcanon.o: ${BUILD_DIR}/config.h -pathphys.o: ${BUILD_DIR}/config.h -rename.o: ${BUILD_DIR}/config.h -setlinebuf.o: ${BUILD_DIR}/config.h -shquote.o: ${BUILD_DIR}/config.h -shtty.o: ${BUILD_DIR}/config.h -snprintf.o: ${BUILD_DIR}/config.h -spell.o: ${BUILD_DIR}/config.h -strcasecmp.o: ${BUILD_DIR}/config.h -strerror.o: ${BUILD_DIR}/config.h -strftime.o: ${BUILD_DIR}/config.h -strindex.o: ${BUILD_DIR}/config.h -stringlist.o: ${BUILD_DIR}/config.h -stringvec.o: ${BUILD_DIR}/config.h -strnlen.o: ${BUILD_DIR}/config.h -strpbrk.o: ${BUILD_DIR}/config.h -strtod.o: ${BUILD_DIR}/config.h -strtoimax.o: ${BUILD_DIR}/config.h -strtol.o: ${BUILD_DIR}/config.h -strtoll.o: ${BUILD_DIR}/config.h -strtoul.o: ${BUILD_DIR}/config.h -strtoull.o: ${BUILD_DIR}/config.h -strtoumax.o: ${BUILD_DIR}/config.h -strtrans.o: ${BUILD_DIR}/config.h -times.o: ${BUILD_DIR}/config.h -timeval.o: ${BUILD_DIR}/config.h -tmpfile.o: ${BUILD_DIR}/config.h -uconvert.o: ${BUILD_DIR}/config.h -ufuncs.o: ${BUILD_DIR}/config.h -vprint.o: ${BUILD_DIR}/config.h -wcsdup.o: ${BUILD_DIR}/config.h -xstrchr.o: ${BUILD_DIR}/config.h -zcatfd.o: ${BUILD_DIR}/config.h -zgetline.o: ${BUILD_DIR}/config.h -zmapfd.o: ${BUILD_DIR}/config.h -zread.o: ${BUILD_DIR}/config.h -zwrite.o: ${BUILD_DIR}/config.h - -clktck.o: ${topdir}/bashtypes.h - -getcwd.o: ${topdir}/bashtypes.h ${topdir}/bashansi.h ${BASHINCDIR}/maxpath.h -getcwd.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/posixdir.h -getcwd.o: ${BASHINCDIR}/memalloc.h ${BASHINCDIR}/ansi_stdlib.h - -getenv.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h -getenv.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h -getenv.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h -getenv.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h ${topdir}/conftypes.h -getenv.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h -getenv.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h -getenv.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h -getenv.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h -getenv.o: ${BUILD_DIR}/version.h - -inet_aton.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h -inet_aton.o: ${BASHINCDIR}/stdc.h - -itos.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h -itos.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h -itos.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h -itos.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h ${topdir}/conftypes.h -itos.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h -itos.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h -itos.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h -itos.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h ${BUILD_DIR}/version.h - -makepath.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h -makepath.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h -makepath.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h -makepath.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h ${topdir}/conftypes.h -makepath.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h -makepath.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h -makepath.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h -makepath.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h ${BUILD_DIR}/version.h - -netconn.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h -netconn.o: ${topdir}/bashtypes.h - -netopen.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h ${topdir}/xmalloc.h -netopen.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h -netopen.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h -netopen.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h ${topdir}/conftypes.h -netopen.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h -netopen.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h -netopen.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h -netopen.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h ${BUILD_DIR}/version.h -netopen.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h - -oslib.o: ${topdir}/bashtypes.h ${topdir}/bashansi.h ${BASHINCDIR}/maxpath.h -oslib.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h -oslib.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h -oslib.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h ${topdir}/conftypes.h -oslib.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h -oslib.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h -oslib.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h -oslib.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h ${BUILD_DIR}/version.h -oslib.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h -oslib.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h - -pathcanon.o: ${topdir}/bashtypes.h ${topdir}/bashansi.h ${BASHINCDIR}/maxpath.h -pathcanon.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h -pathcanon.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h -pathcanon.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h ${topdir}/conftypes.h -pathcanon.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h -pathcanon.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h -pathcanon.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h -pathcanon.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h ${BUILD_DIR}/version.h -pathcanon.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h -pathcanon.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h - -pathphys.o: ${topdir}/bashtypes.h ${topdir}/bashansi.h ${BASHINCDIR}/maxpath.h -pathphys.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h -pathphys.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h -pathphys.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h ${topdir}/conftypes.h -pathphys.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h -pathphys.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h -pathphys.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h -pathphys.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h ${BUILD_DIR}/version.h -pathphys.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h -pathphys.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h - -rename.o: ${topdir}/bashtypes.h ${BASHINCDIR}/stdc.h -rename.o: ${BASHINCDIR}/posixstat.h - -setlinebuf.o: ${topdir}/xmalloc.h ${topdir}/bashansi.h -setlinebuf.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/stdc.h - -eaccess.o: ${topdir}/bashtypes.h -eaccess.o: ${BASHINCDIR}/posixstat.h -eaccess.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h -eaccess.o: ${BASHINCDIR}/filecntl.h -eaccess.o: ${BASHINCDIR}/stdc.h -eaccess.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h -eaccess.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h -eaccess.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h ${topdir}/conftypes.h -eaccess.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h -eaccess.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h -eaccess.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h -eaccess.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h ${BUILD_DIR}/version.h - -shquote.o: ${BASHINCDIR}/stdc.h ${topdir}/bashansi.h -shquote.o: ${BASHINCDIR}/ansi_stdlib.h ${topdir}/xmalloc.h - -shtty.o: ${BASHINCDIR}/shtty.h -shtty.o: ${BASHINCDIR}/stdc.h - -snprintf.o: ${BASHINCDIR}/stdc.h ${topdir}/bashansi.h ${topdir}/xmalloc.h -snprintf.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h -snprintf.o: ${BASHINCDIR}/typemax.h - -spell.o: ${topdir}/bashtypes.h -spell.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/posixdir.h -spell.o: ${BASHINCDIR}/ansi_stdlib.h - -strcasecmp.o: ${BASHINCDIR}/stdc.h ${topdir}/bashansi.h -strcasecmp.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h - -strerror.o: ${topdir}/bashtypes.h -strerror.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h -strerror.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h -strerror.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h ${topdir}/conftypes.h -strerror.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h -strerror.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h -strerror.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h -strerror.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h ${BUILD_DIR}/version.h - -strindex.o: ${BASHINCDIR}/stdc.h ${topdir}/bashansi.h -strindex.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h - -stringlist.o: ${topdir}/bashansi.h -stringlist.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h -stringlist.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h -stringlist.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h ${topdir}/conftypes.h -stringlist.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h -stringlist.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h -stringlist.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h -stringlist.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h ${BUILD_DIR}/version.h - -stringvec.o: ${topdir}/bashansi.h ${BASHINCDIR}/chartypes.h -stringvec.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h -stringvec.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h -stringvec.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h ${topdir}/conftypes.h -stringvec.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h -stringvec.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h -stringvec.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h -stringvec.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h ${BUILD_DIR}/version.h - -strnlen.o: ${BASHINCDIR}/stdc.h - -strpbrk.o: ${BASHINCDIR}/stdc.h - -strtod.o: ${topdir}/bashansi.h -strtod.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h - -strtoimax.o: ${BASHINCDIR}/stdc.h - -strtol.o: ${topdir}/bashansi.h -strtol.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h -strtol.o: ${BASHINCDIR}/typemax.h - -strtoll.o: ${topdir}/bashansi.h -strtoll.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h -strtoll.o: ${BASHINCDIR}/typemax.h - -strtoul.o: ${topdir}/bashansi.h -strtoul.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h -strtoul.o: ${BASHINCDIR}/typemax.h - -strtoull.o: ${topdir}/bashansi.h -strtoull.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h -strtoull.o: ${BASHINCDIR}/typemax.h - -strtoumax.o: ${BASHINCDIR}/stdc.h - -strtrans.o: ${topdir}/bashansi.h -strtrans.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h -strtrans.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h -strtrans.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h -strtrans.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h ${topdir}/conftypes.h -strtrans.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h -strtrans.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h -strtrans.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h -strtrans.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h ${BUILD_DIR}/version.h - -times.o: ${BASHINCDIR}/systimes.h -times.o: ${BASHINCDIR}/posixtime.h - -timeval.o: ${BASHINCDIR}/posixtime.h - -tmpfile.o: ${topdir}/bashtypes.h -tmpfile.o: ${BASHINCDIR}/posixstat.h -tmpfile.o: ${BASHINCDIR}/filecntl.h - -uconvert.o: ${topdir}/bashtypes.h - -ufuncs.o: ${topdir}/bashtypes.h - -clock.o: ${BASHINCDIR}/posixtime.h - -mailstat.o: ${topdir}/bashansi.h -mailstat.o: ${topdir}/bashtypes.h -mailstat.o: ${BASHINCDIR}/ansi_stdlib.h -mailstat.o: ${BASHINCDIR}/posixstat.h -mailstat.o: ${BASHINCDIR}/posixdir.h -mailstat.o: ${BASHINCDIR}/maxpath.h - -fmtulong.o: ${topdir}/bashansi.h -fmtulong.o: ${BASHINCDIR}/ansi_stdlib.h -fmtulong.o: ${BASHINCDIR}/chartypes.h -fmtulong.o: ${BASHINCDIR}/stdc.h -fmtulong.o: ${BASHINCDIR}/typemax.h -fmtulong.o: ${topdir}/bashintl.h ${LIBINTL_H} ${BASHINCDIR}/gettext.h - -fmtullong.o: ${topdir}/bashansi.h -fmtullong.o: ${BASHINCDIR}/ansi_stdlib.h -fmtullong.o: ${BASHINCDIR}/chartypes.h -fmtullong.o: ${BASHINCDIR}/stdc.h -fmtullong.o: ${BASHINCDIR}/typemax.h -fmtullong.o: ${topdir}/bashintl.h ${LIBINTL_H} ${BASHINCDIR}/gettext.h - -fmtumax.o: ${topdir}/bashansi.h -fmtumax.o: ${BASHINCDIR}/ansi_stdlib.h -fmtumax.o: ${BASHINCDIR}/chartypes.h -fmtumax.o: ${BASHINCDIR}/stdc.h -fmtumax.o: ${BASHINCDIR}/typemax.h -fmtumax.o: ${topdir}/bashintl.h ${LIBINTL_H} ${BASHINCDIR}/gettext.h - -wcsdup.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h -wcsdup.o: ${BASHINCDIR}/stdc.h -wcsdup.o: ${topdir}/xmalloc.h - -xstrchr.o: ${topdir}/bashansi.h -xstrchr.o: ${BASHINCDIR}/ansi_stdlib.h -xstrchr.o: ${BASHINCDIR}/shmbutil.h - -zgetline.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h -zgetline.o: ${BASHINCDIR}/stdc.h -zgetline.o: ${topdir}/xmalloc.h -zgetline.o: ${topdir}/bashtypes.h - -mbscmp.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h -mbscmp.o: ${BASHINCDIR}/stdc.h -mbscmp.o: ${topdir}/xmalloc.h - -casemod.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h -casemod.o: ${BASHINCDIR}/stdc.h -casemod.o: ${topdir}/xmalloc.h -casemod.o: ${topdir}/bashtypes.h -casemod.o: ${BASHINCDIR}/shmbutil.h -casemod.o: ${topdir}/bashintl.h ${LIBINTL_H} ${BASHINCDIR}/gettext.h diff --git a/lib/sh/casemod.c~ b/lib/sh/casemod.c~ deleted file mode 100644 index b26ebeeba..000000000 --- a/lib/sh/casemod.c~ +++ /dev/null @@ -1,239 +0,0 @@ -/* casemod.c -- functions to change case of strings */ - -/* Copyright (C) 2008,2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif /* HAVE_UNISTD_H */ - -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include - -#define _to_wupper(wc) (iswlower (wc) ? towupper (wc) : (wc)) -#define _to_wlower(wc) (iswupper (wc) ? towlower (wc) : (wc)) - -#if !defined (HANDLE_MULTIBYTE) -# define cval(s, i) ((s)[(i)]) -# define iswalnum(c) (isalnum(c)) -# define TOGGLE(x) (ISUPPER (x) ? tolower (x) : (TOUPPER (x))) -#else -# define TOGGLE(x) (iswupper (x) ? towlower (x) : (_to_wupper(x))) -#endif - -/* These must agree with the defines in externs.h */ -#define CASE_NOOP 0x0000 -#define CASE_LOWER 0x0001 -#define CASE_UPPER 0x0002 -#define CASE_CAPITALIZE 0x0004 -#define CASE_UNCAP 0x0008 -#define CASE_TOGGLE 0x0010 -#define CASE_TOGGLEALL 0x0020 -#define CASE_UPFIRST 0x0040 -#define CASE_LOWFIRST 0x0080 - -#define CASE_USEWORDS 0x1000 /* modify behavior to act on words in passed string */ - -extern char *substring __P((char *, int, int)); - -#if defined (HANDLE_MULTIBYTE) -static wchar_t -cval (s, i) - char *s; - int i; -{ - size_t tmp; - wchar_t wc; - int l; - mbstate_t mps; - - if (MB_CUR_MAX == 1) - return ((wchar_t)s[i]); - l = strlen (s); - if (i >= (l - 1)) - return ((wchar_t)s[i]); - memset (&mps, 0, sizeof (mbstate_t)); - tmp = mbrtowc (&wc, s + i, l - i, &mps); - if (MB_INVALIDCH (tmp) || MB_NULLWCH (tmp)) - return ((wchar_t)s[i]); - return wc; -} -#endif - -/* Modify the case of characters in STRING matching PAT based on the value of - FLAGS. If PAT is null, modify the case of each character */ -char * -sh_modcase (string, pat, flags) - const char *string; - char *pat; - int flags; -{ - int start, next, end; - int inword, c, nc, nop, match, usewords; - char *ret, *s; - wchar_t wc; -#if defined (HANDLE_MULTIBYTE) - wchar_t nwc; - char mb[MB_LEN_MAX+1]; - int mlen; - mbstate_t state; -#endif - -#if defined (HANDLE_MULTIBYTE) - memset (&state, 0, sizeof (mbstate_t)); -#endif - - start = 0; - end = strlen (string); - - ret = (char *)xmalloc (end + 1); - strcpy (ret, string); - - /* See if we are supposed to split on alphanumerics and operate on each word */ - usewords = (flags & CASE_USEWORDS); - flags &= ~CASE_USEWORDS; - - inword = 0; - while (start < end) - { - wc = cval (ret, start); - - if (iswalnum (wc) == 0) - { - inword = 0; - ADVANCE_CHAR (ret, end, start); - continue; - } - - if (pat) - { - next = start; - ADVANCE_CHAR (ret, end, next); - s = substring (ret, start, next); - match = strmatch (pat, s, FNM_EXTMATCH) != FNM_NOMATCH; - free (s); - if (match == 0) - { - start = next; - inword = 1; - continue; - } - } - - /* XXX - for now, the toggling operators work on the individual - words in the string, breaking on alphanumerics. Should I - leave the capitalization operators to do that also? */ - if (flags == CASE_CAPITALIZE) - { - if (usewords) - nop = inword ? CASE_LOWER : CASE_UPPER; - else - nop = (start > 0) ? CASE_NOOP : CASE_UPPER; - inword = 1; - } - else if (flags == CASE_UNCAP) - { - if (usewords) - nop = inword ? CASE_UPPER : CASE_LOWER; - else - nop = (start > 0) ? CASE_NOOP : CASE_LOWER; - inword = 1; - } - else if (flags == CASE_UPFIRST) - { - if (usewords) - nop = inword ? CASE_NOOP : CASE_UPPER; - else - nop = (start > 0) ? CASE_NOOP : CASE_UPPER; - inword = 1; - } - else if (flags == CASE_LOWFIRST) - { - if (usewords) - nop = inword ? CASE_NOOP : CASE_LOWER; - else - nop = (start > 0) ? CASE_NOOP : CASE_LOWER; - inword = 1; - } - else if (flags == CASE_TOGGLE) - { - nop = inword ? CASE_NOOP : CASE_TOGGLE; - inword = 1; - } - else - nop = flags; - - if (MB_CUR_MAX == 1 || isascii (wc)) - { - switch (nop) - { - default: - case CASE_NOOP: nc = wc; break; - case CASE_UPPER: nc = TOUPPER (wc); break; - case CASE_LOWER: nc = TOLOWER (wc); break; - case CASE_TOGGLEALL: - case CASE_TOGGLE: nc = TOGGLE (wc); break; - } - ret[start] = nc; - } -#if defined (HANDLE_MULTIBYTE) - else - { - mbrtowc (&wc, string + start, end - start, &state); - switch (nop) - { - default: - case CASE_NOOP: nwc = wc; break; - case CASE_UPPER: nwc = TOUPPER (wc); break; - case CASE_LOWER: nwc = TOLOWER (wc); break; - case CASE_TOGGLEALL: - case CASE_TOGGLE: nwc = TOGGLE (wc); break; - } - if (nwc != wc) /* just skip unchanged characters */ - { - mlen = wcrtomb (mb, nwc, &state); - if (mlen > 0) - mb[mlen] = '\0'; - /* Assume the same width */ - strncpy (ret + start, mb, mlen); - } - } -#endif - - /* This assumes that the upper and lower case versions are the same width. */ - ADVANCE_CHAR (ret, end, start); - } - - return ret; -} diff --git a/lib/sh/fdprintf.c~ b/lib/sh/fdprintf.c~ deleted file mode 100644 index f66822aaf..000000000 --- a/lib/sh/fdprintf.c~ +++ /dev/null @@ -1,63 +0,0 @@ -/* fdprintf -- printf to a file descriptor - - Copyright (C) 2008 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (PREFER_STDARG) -# include -#else -# include -#endif - -#include - -int -#if defined (PREFER_STDARG) -fdprintf(int fd, const char *format, ...) -#else -fdprintf(fd, format, va_alist) - int fd; - const char *format; - va_dcl -#endif -{ - FILE *fp; - int rc, r2; - va_list args; - - fp = fdopen (dup (fd), "w"); - if (fp == 0) - return -1; - - SH_VA_START (args, format); - rc = vfprintf (fp, fmt, ap); - fflush (fp); - va_end (args); - - r2 = fclose (fp); /* check here */ - - return rc; -} diff --git a/lib/sh/getcwd.c~ b/lib/sh/getcwd.c~ deleted file mode 100644 index c1cbaa7e9..000000000 --- a/lib/sh/getcwd.c~ +++ /dev/null @@ -1,349 +0,0 @@ -/* getcwd.c -- stolen from the GNU C library and modified to work with bash. */ - -/* Copyright (C) 1991 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include - -#if !defined (HAVE_GETCWD) - -#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) - #pragma alloca -#endif /* _AIX && RISC6000 && !__GNUC__ */ - -#if defined (__QNX__) -# undef HAVE_LSTAT -#endif - -#include -#include - -#if defined (HAVE_LIMITS_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include -#include -#include - -#include - -#include - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#if !defined (HAVE_LSTAT) -# define lstat stat -#endif - -#if !defined (NULL) -# define NULL 0 -#endif - -/* If the d_fileno member of a struct dirent doesn't return anything useful, - we need to check inode number equivalence the hard way. */ -#if defined (BROKEN_DIRENT_D_INO) -static int -_path_checkino (dotp, name, thisino) - char *dotp; - char *name; - ino_t thisino; -{ - char *fullpath; - int r, e; - struct stat st; - - e = errno; - fullpath = sh_makepath (dotp, name, MP_RMDOT); - if (stat (fullpath, &st) < 0) - { - errno = e; - return 0; - } - free (fullpath); - errno = e; - return (st.st_ino == thisino); -} -#endif - -/* Get the pathname of the current working directory, - and put it in SIZE bytes of BUF. Returns NULL if the - directory couldn't be determined or SIZE was too small. - If successful, returns BUF. In GNU, if BUF is NULL, - an array is allocated with `malloc'; the array is SIZE - bytes long, unless SIZE <= 0, in which case it is as - big as necessary. */ -#if defined (__STDC__) -char * -getcwd (char *buf, size_t size) -#else /* !__STDC__ */ -char * -getcwd (buf, size) - char *buf; - size_t size; -#endif /* !__STDC__ */ -{ - static const char dots[] - = "../../../../../../../../../../../../../../../../../../../../../../../\ -../../../../../../../../../../../../../../../../../../../../../../../../../../\ -../../../../../../../../../../../../../../../../../../../../../../../../../.."; - const char *dotp, *dotlist; - size_t dotsize; - dev_t rootdev, thisdev; - ino_t rootino, thisino; - char path[PATH_MAX + 1]; - register char *pathp; - char *pathbuf; - size_t pathsize; - struct stat st; - int saved_errno; - - if (buf != NULL && size == 0) - { - errno = EINVAL; - return ((char *)NULL); - } - - pathsize = sizeof (path); - pathp = &path[pathsize]; - *--pathp = '\0'; - pathbuf = path; - - if (stat (".", &st) < 0) - return ((char *)NULL); - thisdev = st.st_dev; - thisino = st.st_ino; - - if (stat ("/", &st) < 0) - return ((char *)NULL); - rootdev = st.st_dev; - rootino = st.st_ino; - - saved_errno = 0; - - dotsize = sizeof (dots) - 1; - dotp = &dots[sizeof (dots)]; - dotlist = dots; - while (!(thisdev == rootdev && thisino == rootino)) - { - register DIR *dirstream; - register struct dirent *d; - dev_t dotdev; - ino_t dotino; - char mount_point; - int namlen; - - /* Look at the parent directory. */ - if (dotp == dotlist) - { - /* My, what a deep directory tree you have, Grandma. */ - char *new; - if (dotlist == dots) - { - new = (char *)malloc (dotsize * 2 + 1); - if (new == NULL) - goto lose; - memcpy (new, dots, dotsize); - } - else - { - new = (char *)realloc ((PTR_T) dotlist, dotsize * 2 + 1); - if (new == NULL) - goto lose; - } - memcpy (&new[dotsize], new, dotsize); - dotp = &new[dotsize]; - dotsize *= 2; - new[dotsize] = '\0'; - dotlist = new; - } - - dotp -= 3; - - /* Figure out if this directory is a mount point. */ - if (stat (dotp, &st) < 0) - goto lose; - dotdev = st.st_dev; - dotino = st.st_ino; - mount_point = dotdev != thisdev; - - /* Search for the last directory. */ - dirstream = opendir (dotp); - if (dirstream == NULL) - goto lose; - while ((d = readdir (dirstream)) != NULL) - { - if (d->d_name[0] == '.' && - (d->d_name[1] == '\0' || - (d->d_name[1] == '.' && d->d_name[2] == '\0'))) - continue; -#if !defined (BROKEN_DIRENT_D_INO) - if (mount_point || d->d_fileno == thisino) -#else - if (mount_point || _path_checkino (dotp, d->d_name, thisino)) -#endif - { - char *name; - - namlen = D_NAMLEN(d); - name = (char *) - alloca (dotlist + dotsize - dotp + 1 + namlen + 1); - memcpy (name, dotp, dotlist + dotsize - dotp); - name[dotlist + dotsize - dotp] = '/'; - memcpy (&name[dotlist + dotsize - dotp + 1], - d->d_name, namlen + 1); - if (lstat (name, &st) < 0) - { -#if 0 - int save = errno; - (void) closedir (dirstream); - errno = save; - goto lose; -#else - saved_errno = errno; -#endif - } - if (st.st_dev == thisdev && st.st_ino == thisino) - break; - } - } - if (d == NULL) - { -#if 0 - int save = errno; -#else - int save = errno ? errno : saved_errno; -#endif - (void) closedir (dirstream); - errno = save; - goto lose; - } - else - { - size_t space; - - while ((space = pathp - pathbuf) <= namlen) - { - char *new; - - if (pathbuf == path) - { - new = (char *)malloc (pathsize * 2); - if (!new) - goto lose; - } - else - { - new = (char *)realloc ((PTR_T) pathbuf, (pathsize * 2)); - if (!new) - goto lose; - pathp = new + space; - } - (void) memcpy (new + pathsize + space, pathp, pathsize - space); - pathp = new + pathsize + space; - pathbuf = new; - pathsize *= 2; - } - - pathp -= namlen; - (void) memcpy (pathp, d->d_name, namlen); - *--pathp = '/'; - (void) closedir (dirstream); - } - - thisdev = dotdev; - thisino = dotino; - } - - if (pathp == &path[sizeof(path) - 1]) - *--pathp = '/'; - - if (dotlist != dots) - free ((PTR_T) dotlist); - - { - size_t len = pathbuf + pathsize - pathp; - if (buf == NULL && size <= 0) - size = len; - - if ((size_t) size < len) - { - errno = ERANGE; - goto lose2; - } - if (buf == NULL) - { - buf = (char *) malloc (size); - if (buf == NULL) - goto lose2; - } - - (void) memcpy((PTR_T) buf, (PTR_T) pathp, len); - } - - if (pathbuf != path) - free (pathbuf); - - return (buf); - - lose: - if ((dotlist != dots) && dotlist) - { - int e = errno; - free ((PTR_T) dotlist); - errno = e; - } - - lose2: - if ((pathbuf != path) && pathbuf) - { - int e = errno; - free ((PTR_T) pathbuf); - errno = e; - } - return ((char *)NULL); -} - -#if defined (TEST) -# include -main (argc, argv) - int argc; - char **argv; -{ - char b[PATH_MAX]; - - if (getcwd(b, sizeof(b))) - { - printf ("%s\n", b); - exit (0); - } - else - { - perror ("cwd: getcwd"); - exit (1); - } -} -#endif /* TEST */ -#endif /* !HAVE_GETCWD */ diff --git a/lib/sh/makepath.c~ b/lib/sh/makepath.c~ deleted file mode 100644 index c496154b7..000000000 --- a/lib/sh/makepath.c~ +++ /dev/null @@ -1,118 +0,0 @@ -/* makepath.c - glue PATH and DIR together into a full pathname. */ - -/* 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 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 "shell.h" - -#include - -#ifndef NULL -# define NULL 0 -#endif - -/* MAKE SURE THESE AGREE WITH ../../externs.h. */ - -#ifndef MP_DOTILDE -# define MP_DOTILDE 0x01 -# define MP_DOCWD 0x02 -# define MP_RMDOT 0x04 -#endif - -extern char *get_working_directory __P((char *)); - -/* Take PATH, an element from, e.g., $CDPATH, and DIR, a directory name, - and paste them together into PATH/DIR. Tilde expansion is performed on - PATH if (flags & MP_DOTILDE) is non-zero. If PATH is NULL or the empty - string, it is converted to the current directory. A full pathname is - used if (flags & MP_DOCWD) is non-zero, otherwise `./' is used. If - (flags & MP_RMDOT) is non-zero, any `./' is removed from the beginning - of DIR. */ - -#define MAKEDOT() \ - do { \ - xpath = (char *)xmalloc (2); \ - xpath[0] = '.'; \ - xpath[1] = '\0'; \ - pathlen = 1; \ - } while (0) - -char * -sh_makepath (path, dir, flags) - const char *path, *dir; - int flags; -{ - int dirlen, pathlen; - char *ret, *xpath, *xdir, *r, *s; - - if (path == 0 || *path == '\0') - { - if (flags & MP_DOCWD) - { - xpath = get_working_directory ("sh_makepath"); - if (xpath == 0) - { - ret = get_string_value ("PWD"); - if (ret) - xpath = savestring (ret); - } - if (xpath == 0) - MAKEDOT(); - else - pathlen = strlen (xpath); - } - else - MAKEDOT(); - } - else - { - xpath = ((flags & MP_DOTILDE) && *path == '~') ? bash_tilde_expand (path, 0) : (char *)path; - pathlen = strlen (xpath); - } - - xdir = (char *)dir; - dirlen = strlen (xdir); - if ((flags & MP_RMDOT) && dir[0] == '.' && dir[1] == '/') - { - xdir += 2; - dirlen -= 2; - } - - r = ret = (char *)xmalloc (2 + dirlen + pathlen); - s = xpath; - while (*s) - *r++ = *s++; - if (s[-1] != '/') - *r++ = '/'; - s = xdir; - while (*r++ = *s++) - ; - if (xpath != path) - free (xpath); - return (ret); -} diff --git a/lib/sh/mbscmp.c~ b/lib/sh/mbscmp.c~ deleted file mode 100644 index c79035f54..000000000 --- a/lib/sh/mbscmp.c~ +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -The GNU C Library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -#include - -#if !defined (HAVE_MBSCMP) && defined (HANDLE_MULTIBYTE) - -#include -#include - - -/* Compare MBS1 and MBS2. */ -int -mbscmp (mbs1, mbs2) - const char *mbs1; - const char *mbs2; -{ - int len1 = 0; - int len2 = 0; - uwchar_t c1; - uwchar_t c2; - - /* Reset multibyte characters to their initial state. */ - (void) mblen ((char *) NULL, 0); - - do - { - len1 = mbtowc ((wchar_t *) &c1, mbs1, MB_CUR_MAX); - len2 = mbtowc ((wchar_t *) &c2, mbs2, MB_CUR_MAX); - - if (len1 == 0) - return len2 == 0 ? 0 : -1; - if (len2 == 0) - return 1; - if (len1 < 0 || len2 < 0) - /* FIXME: an illegal character appears. What to do? */ - return c1 - c2; - - mbs1 += len1; - mbs2 += len2; - } - while (c1 == c2); - - return c1 - c2; -} - -#endif diff --git a/lib/sh/mktime.c~ b/lib/sh/mktime.c~ deleted file mode 100644 index c84cbdb9f..000000000 --- a/lib/sh/mktime.c~ +++ /dev/null @@ -1,426 +0,0 @@ -/* mktime - convert struct tm to a time_t value */ - -/* Copyright (C) 1993-2002 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - Contributed by Paul Eggert (eggert@twinsun.com). - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ -/* Define this to have a standalone program to test this implementation of - mktime. */ -/* #define DEBUG 1 */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef _LIBC -# define HAVE_LIMITS_H 1 -# define HAVE_LOCALTIME_R 1 -# define STDC_HEADERS 1 -#endif - -/* Assume that leap seconds are possible, unless told otherwise. - If the host has a `zic' command with a `-L leapsecondfilename' option, - then it supports leap seconds; otherwise it probably doesn't. */ -#ifndef LEAP_SECONDS_POSSIBLE -#define LEAP_SECONDS_POSSIBLE 1 -#endif - -#ifndef VMS -#include /* Some systems define `time_t' here. */ -#else -#include -#endif -#include - -#if HAVE_LIMITS_H -#include -#endif - -#if DEBUG -#include -#if STDC_HEADERS -#include -#endif -/* Make it work even if the system's libc has its own mktime routine. */ -#define mktime my_mktime -#endif /* DEBUG */ - -#ifndef __P -#if defined (__GNUC__) || (defined (__STDC__) && __STDC__) -#define __P(args) args -#else -#define __P(args) () -#endif /* GCC. */ -#endif /* Not __P. */ - -#ifndef CHAR_BIT -#define CHAR_BIT 8 -#endif - -#ifndef INT_MIN -#define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1)) -#endif -#ifndef INT_MAX -#define INT_MAX (~0 - INT_MIN) -#endif - -#ifndef TIME_T_MIN -#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \ - : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)) -#endif -#ifndef TIME_T_MAX -#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN) -#endif - -#define TM_YEAR_BASE 1900 -#define EPOCH_YEAR 1970 - -#ifndef __isleap -/* Nonzero if YEAR is a leap year (every 4 years, - except every 100th isn't, and every 400th is). */ -#define __isleap(year) \ - ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) -#endif - -/* How many days come before each month (0-12). */ -const unsigned short int __mon_yday[2][13] = - { - /* Normal years. */ - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, - /* Leap years. */ - { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } - }; - -static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *)); -time_t __mktime_internal __P ((struct tm *, - struct tm *(*) (const time_t *, struct tm *), - time_t *)); - - -static struct tm *my_localtime_r __P ((const time_t *, struct tm *)); -static struct tm * -my_localtime_r (t, tp) - const time_t *t; - struct tm *tp; -{ - struct tm *l = localtime (t); - if (! l) - return 0; - *tp = *l; - return tp; -} - - -/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP), - measured in seconds, ignoring leap seconds. - YEAR uses the same numbering as TM->tm_year. - All values are in range, except possibly YEAR. - If overflow occurs, yield the low order bits of the correct answer. */ -static time_t -ydhms_tm_diff (year, yday, hour, min, sec, tp) - int year, yday, hour, min, sec; - const struct tm *tp; -{ - /* Compute intervening leap days correctly even if year is negative. - Take care to avoid int overflow. time_t overflow is OK, since - only the low order bits of the correct time_t answer are needed. - Don't convert to time_t until after all divisions are done, since - time_t might be unsigned. */ - int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3); - int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3); - int a100 = a4 / 25 - (a4 % 25 < 0); - int b100 = b4 / 25 - (b4 % 25 < 0); - int a400 = a100 >> 2; - int b400 = b100 >> 2; - int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); - time_t years = year - (time_t) tp->tm_year; - time_t days = (365 * years + intervening_leap_days - + (yday - tp->tm_yday)); - return (60 * (60 * (24 * days + (hour - tp->tm_hour)) - + (min - tp->tm_min)) - + (sec - tp->tm_sec)); -} - - -static time_t localtime_offset; - -/* Convert *TP to a time_t value. */ -time_t -mktime (tp) - struct tm *tp; -{ -#ifdef _LIBC - /* POSIX.1 8.1.1 requires that whenever mktime() is called, the - time zone names contained in the external variable `tzname' shall - be set as if the tzset() function had been called. */ - __tzset (); -#endif - - return __mktime_internal (tp, my_localtime_r, &localtime_offset); -} - -/* Convert *TP to a time_t value, inverting - the monotonic and mostly-unit-linear conversion function CONVERT. - Use *OFFSET to keep track of a guess at the offset of the result, - compared to what the result would be for UTC without leap seconds. - If *OFFSET's guess is correct, only one CONVERT call is needed. */ -time_t -__mktime_internal (tp, convert, offset) - struct tm *tp; - struct tm *(*convert) __P ((const time_t *, struct tm *)); - time_t *offset; -{ - time_t t, dt, t0; - struct tm tm; - - /* The maximum number of probes (calls to CONVERT) should be enough - to handle any combinations of time zone rule changes, solar time, - and leap seconds. Posix.1 prohibits leap seconds, but some hosts - have them anyway. */ - int remaining_probes = 4; - - /* Time requested. Copy it in case CONVERT modifies *TP; this can - occur if TP is localtime's returned value and CONVERT is localtime. */ - int sec = tp->tm_sec; - int min = tp->tm_min; - int hour = tp->tm_hour; - int mday = tp->tm_mday; - int mon = tp->tm_mon; - int year_requested = tp->tm_year; - int isdst = tp->tm_isdst; - - /* Ensure that mon is in range, and set year accordingly. */ - int mon_remainder = mon % 12; - int negative_mon_remainder = mon_remainder < 0; - int mon_years = mon / 12 - negative_mon_remainder; - int year = year_requested + mon_years; - - /* The other values need not be in range: - the remaining code handles minor overflows correctly, - assuming int and time_t arithmetic wraps around. - Major overflows are caught at the end. */ - - /* Calculate day of year from year, month, and day of month. - The result need not be in range. */ - int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)] - [mon_remainder + 12 * negative_mon_remainder]) - + mday - 1); - -#if LEAP_SECONDS_POSSIBLE - /* Handle out-of-range seconds specially, - since ydhms_tm_diff assumes every minute has 60 seconds. */ - int sec_requested = sec; - if (sec < 0) - sec = 0; - if (59 < sec) - sec = 59; -#endif - - /* Invert CONVERT by probing. First assume the same offset as last time. - Then repeatedly use the error to improve the guess. */ - - tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE; - tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0; - t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm); - - for (t = t0 + *offset; - (dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm))); - t += dt) - if (--remaining_probes == 0) - return -1; - - /* Check whether tm.tm_isdst has the requested value, if any. */ - if (0 <= isdst && 0 <= tm.tm_isdst) - { - int dst_diff = (isdst != 0) - (tm.tm_isdst != 0); - if (dst_diff) - { - /* Move two hours in the direction indicated by the disagreement, - probe some more, and switch to a new time if found. - The largest known fallback due to daylight savings is two hours: - once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */ - time_t ot = t - 2 * 60 * 60 * dst_diff; - while (--remaining_probes != 0) - { - struct tm otm; - if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec, - (*convert) (&ot, &otm)))) - { - t = ot; - tm = otm; - break; - } - if ((ot += dt) == t) - break; /* Avoid a redundant probe. */ - } - } - } - - *offset = t - t0; - -#if LEAP_SECONDS_POSSIBLE - if (sec_requested != tm.tm_sec) - { - /* Adjust time to reflect the tm_sec requested, not the normalized value. - Also, repair any damage from a false match due to a leap second. */ - t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60); - (*convert) (&t, &tm); - } -#endif - - if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3) - { - /* time_t isn't large enough to rule out overflows in ydhms_tm_diff, - so check for major overflows. A gross check suffices, - since if t has overflowed, it is off by a multiple of - TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of - the difference that is bounded by a small value. */ - - double dyear = (double) year_requested + mon_years - tm.tm_year; - double dday = 366 * dyear + mday; - double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested; - - if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec)) - return -1; - } - - *tp = tm; - return t; -} - -#ifdef weak_alias -weak_alias (mktime, timelocal) -#endif - -#if DEBUG - -static int -not_equal_tm (a, b) - struct tm *a; - struct tm *b; -{ - return ((a->tm_sec ^ b->tm_sec) - | (a->tm_min ^ b->tm_min) - | (a->tm_hour ^ b->tm_hour) - | (a->tm_mday ^ b->tm_mday) - | (a->tm_mon ^ b->tm_mon) - | (a->tm_year ^ b->tm_year) - | (a->tm_mday ^ b->tm_mday) - | (a->tm_yday ^ b->tm_yday) - | (a->tm_isdst ^ b->tm_isdst)); -} - -static void -print_tm (tp) - struct tm *tp; -{ - printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d", - tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday, - tp->tm_hour, tp->tm_min, tp->tm_sec, - tp->tm_yday, tp->tm_wday, tp->tm_isdst); -} - -static int -check_result (tk, tmk, tl, tml) - time_t tk; - struct tm tmk; - time_t tl; - struct tm tml; -{ - if (tk != tl || not_equal_tm (&tmk, &tml)) - { - printf ("mktime ("); - print_tm (&tmk); - printf (")\nyields ("); - print_tm (&tml); - printf (") == %ld, should be %ld\n", (long) tl, (long) tk); - return 1; - } - - return 0; -} - -int -main (argc, argv) - int argc; - char **argv; -{ - int status = 0; - struct tm tm, tmk, tml; - time_t tk, tl; - char trailer; - - if ((argc == 3 || argc == 4) - && (sscanf (argv[1], "%d-%d-%d%c", - &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer) - == 3) - && (sscanf (argv[2], "%d:%d:%d%c", - &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer) - == 3)) - { - tm.tm_year -= TM_YEAR_BASE; - tm.tm_mon--; - tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]); - tmk = tm; - tl = mktime (&tmk); - tml = *localtime (&tl); - printf ("mktime returns %ld == ", (long) tl); - print_tm (&tmk); - printf ("\n"); - status = check_result (tl, tmk, tl, tml); - } - else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0)) - { - time_t from = atol (argv[1]); - time_t by = atol (argv[2]); - time_t to = atol (argv[3]); - - if (argc == 4) - for (tl = from; tl <= to; tl += by) - { - tml = *localtime (&tl); - tmk = tml; - tk = mktime (&tmk); - status |= check_result (tk, tmk, tl, tml); - } - else - for (tl = from; tl <= to; tl += by) - { - /* Null benchmark. */ - tml = *localtime (&tl); - tmk = tml; - tk = tl; - status |= check_result (tk, tmk, tl, tml); - } - } - else - printf ("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", - argv[0], argv[0], argv[0]); - - return status; -} - -#endif /* DEBUG */ - -/* -Local Variables: -compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime" -End: -*/ diff --git a/lib/sh/shmatch.c.save b/lib/sh/shmatch.c.save deleted file mode 100644 index f03a2ee52..000000000 --- a/lib/sh/shmatch.c.save +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright (C) 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. */ - -/* - * shmatch.c -- shell interface to posix regular expression matching. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if defined (HAVE_POSIX_REGEXP) - -#ifdef HAVE_UNISTD_H -# include -#endif - -#include "bashansi.h" - -#include -#include - -#include "shell.h" -#include "variables.h" -#include "externs.h" - -extern int glob_ignore_case, match_ignore_case; - -int -sh_regmatch (string, pattern, flags) - const char *string; - const char *pattern; - int flags; -{ - regex_t regex = { 0 }; - regmatch_t *matches; - int rflags; -#if defined (ARRAY_VARS) - SHELL_VAR *rematch; - ARRAY *amatch; - int subexp_ind; - char *subexp_str; - int subexp_len; -#endif - int result; - -#if defined (ARRAY_VARS) - rematch = (SHELL_VAR *)NULL; -#endif - - rflags = REG_EXTENDED; - if (glob_ignore_case || match_ignore_case) - rflags |= REG_ICASE; -#if !defined (ARRAY_VARS) - rflags |= REG_NOSUB; -#endif - - if (regcomp (®ex, pattern, rflags)) - return 2; /* flag for printing a warning here. */ - -#if defined (ARRAY_VARS) - matches = (regmatch_t *)malloc (sizeof (regmatch_t) * (regex.re_nsub + 1)); -#else - matches = NULL; -#endif - - if (regexec (®ex, string, regex.re_nsub + 1, matches, 0)) - result = EXECUTION_FAILURE; - else - result = EXECUTION_SUCCESS; /* match */ - -#if defined (ARRAY_VARS) - subexp_len = strlen (string) + 10; - subexp_str = malloc (subexp_len + 1); - - /* Store the parenthesized subexpressions in the array BASH_REMATCH. - Element 0 is the portion that matched the entire regexp. Element 1 - is the part that matched the first subexpression, and so on. */ - unbind_variable ("BASH_REMATCH"); - rematch = make_new_array_variable ("BASH_REMATCH"); - amatch = array_cell (rematch); - - if ((flags & SHMAT_SUBEXP) && result == EXECUTION_SUCCESS && subexp_str) - { - for (subexp_ind = 0; subexp_ind <= regex.re_nsub; subexp_ind++) - { - memset (subexp_str, 0, subexp_len); - strncpy (subexp_str, string + matches[subexp_ind].rm_so, - matches[subexp_ind].rm_eo - matches[subexp_ind].rm_so); - array_insert (amatch, subexp_ind, subexp_str); - } - } - - VSETATTR (rematch, att_readonly); - - free (subexp_str); - free (matches); -#endif /* ARRAY_VARS */ - - regfree (®ex); - - return result; -} - -#endif /* HAVE_POSIX_REGEXP */ diff --git a/lib/sh/shtty.c~ b/lib/sh/shtty.c~ deleted file mode 100644 index 2381ee2fa..000000000 --- a/lib/sh/shtty.c~ +++ /dev/null @@ -1,329 +0,0 @@ -/* Copyright (C) 1999 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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. */ - -/* - * shtty.c -- abstract interface to the terminal, focusing on capabilities. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef HAVE_UNISTD_H -# include -#endif - -#include - -static TTYSTRUCT ttin, ttout; -static int ttsaved = 0; - -int -ttgetattr(fd, ttp) -int fd; -TTYSTRUCT *ttp; -{ -#ifdef TERMIOS_TTY_DRIVER - return tcgetattr(fd, ttp); -#else -# ifdef TERMIO_TTY_DRIVER - return ioctl(fd, TCGETA, ttp); -# else - return ioctl(fd, TIOCGETP, ttp); -# endif -#endif -} - -int -ttsetattr(fd, ttp) -int fd; -TTYSTRUCT *ttp; -{ -#ifdef TERMIOS_TTY_DRIVER - return tcsetattr(fd, TCSADRAIN, ttp); -#else -# ifdef TERMIO_TTY_DRIVER - return ioctl(fd, TCSETAW, ttp); -# else - return ioctl(fd, TIOCSETN, ttp); -# endif -#endif -} - -void -ttsave() -{ - if (ttsaved) - return; - ttgetattr (0, &ttin); - ttgetattr (1, &ttout); - ttsaved = 1; -} - -void -ttrestore() -{ - if (ttsaved == 0) - return; - ttsetattr (0, &ttin); - ttsetattr (1, &ttout); - ttsaved = 0; -} - -/* Retrieve the internally-saved attributes associated with tty fd FD. */ -TTYSTRUCT * -ttattr (fd) - int fd; -{ - if (ttsaved == 0) - return ((TTYSTRUCT *)0); - if (fd == 0) - return &ttin; - else if (fd == 1) - return &ttout; - else - return ((TTYSTRUCT *)0); -} - -/* - * Change attributes in ttp so that when it is installed using - * ttsetattr, the terminal will be in one-char-at-a-time mode. - */ -int -tt_setonechar(ttp) - TTYSTRUCT *ttp; -{ -#if defined (TERMIOS_TTY_DRIVER) || defined (TERMIO_TTY_DRIVER) - - /* XXX - might not want this -- it disables erase and kill processing. */ - ttp->c_lflag &= ~ICANON; - - ttp->c_lflag |= ISIG; -# ifdef IEXTEN - ttp->c_lflag |= IEXTEN; -# endif - - ttp->c_iflag |= ICRNL; /* make sure we get CR->NL on input */ - ttp->c_iflag &= ~INLCR; /* but no NL->CR */ - -# ifdef OPOST - ttp->c_oflag |= OPOST; -# endif -# ifdef ONLCR - ttp->c_oflag |= ONLCR; -# endif -# ifdef OCRNL - ttp->c_oflag &= ~OCRNL; -# endif -# ifdef ONOCR - ttp->c_oflag &= ~ONOCR; -# endif -# ifdef ONLRET - ttp->c_oflag &= ~ONLRET; -# endif - - ttp->c_cc[VMIN] = 1; - ttp->c_cc[VTIME] = 0; - -#else - - ttp->sg_flags |= CBREAK; - -#endif - - return 0; -} - -/* Set the tty associated with FD and TTP into one-character-at-a-time mode */ -int -ttfd_onechar (fd, ttp) - int fd; - TTYSTRUCT *ttp; -{ - if (tt_setonechar(ttp) < 0) - return -1; - return (ttsetattr (fd, ttp)); -} - -/* Set the terminal into one-character-at-a-time mode */ -int -ttonechar () -{ - TTYSTRUCT tt; - - if (ttsaved == 0) - return -1; - tt = ttin; - return (ttfd_onechar (0, &tt)); -} - -/* - * Change attributes in ttp so that when it is installed using - * ttsetattr, the terminal will be in no-echo mode. - */ -int -tt_setnoecho(ttp) - TTYSTRUCT *ttp; -{ -#if defined (TERMIOS_TTY_DRIVER) || defined (TERMIO_TTY_DRIVER) - ttp->c_lflag &= ~(ECHO|ECHOK|ECHONL); -#else - ttp->sg_flags &= ~ECHO; -#endif - - return 0; -} - -/* Set the tty associated with FD and TTP into no-echo mode */ -int -ttfd_noecho (fd, ttp) - int fd; - TTYSTRUCT *ttp; -{ - if (tt_setnoecho (ttp) < 0) - return -1; - return (ttsetattr (fd, ttp)); -} - -/* Set the terminal into no-echo mode */ -int -ttnoecho () -{ - TTYSTRUCT tt; - - if (ttsaved == 0) - return -1; - tt = ttin; - return (ttfd_noecho (0, &tt)); -} - -/* - * Change attributes in ttp so that when it is installed using - * ttsetattr, the terminal will be in eight-bit mode (pass8). - */ -int -tt_seteightbit (ttp) - TTYSTRUCT *ttp; -{ -#if defined (TERMIOS_TTY_DRIVER) || defined (TERMIO_TTY_DRIVER) - ttp->c_iflag &= ~ISTRIP; - ttp->c_cflag |= CS8; - ttp->c_cflag &= ~PARENB; -#else - ttp->sg_flags |= ANYP; -#endif - - return 0; -} - -/* Set the tty associated with FD and TTP into eight-bit mode */ -int -ttfd_eightbit (fd, ttp) - int fd; - TTYSTRUCT *ttp; -{ - if (tt_seteightbit (ttp) < 0) - return -1; - return (ttsetattr (fd, ttp)); -} - -/* Set the terminal into eight-bit mode */ -int -tteightbit () -{ - TTYSTRUCT tt; - - if (ttsaved == 0) - return -1; - tt = ttin; - return (ttfd_eightbit (0, &tt)); -} - -/* - * Change attributes in ttp so that when it is installed using - * ttsetattr, the terminal will be in non-canonical input mode. - */ -int -tt_setnocanon (ttp) - TTYSTRUCT *ttp; -{ -#if defined (TERMIOS_TTY_DRIVER) || defined (TERMIO_TTY_DRIVER) - ttp->c_lflag &= ~ICANON; -#endif - - return 0; -} - -/* Set the tty associated with FD and TTP into non-canonical mode */ -int -ttfd_nocanon (fd, ttp) - int fd; - TTYSTRUCT *ttp; -{ - if (tt_setnocanon (ttp) < 0) - return -1; - return (ttsetattr (fd, ttp)); -} - -/* Set the terminal into non-canonical mode */ -int -ttnocanon () -{ - TTYSTRUCT tt; - - if (ttsaved == 0) - return -1; - tt = ttin; - return (ttfd_nocanon (0, &tt)); -} - -/* - * Change attributes in ttp so that when it is installed using - * ttsetattr, the terminal will be in cbreak, no-echo mode. - */ -int -tt_setcbreak(ttp) - TTYSTRUCT *ttp; -{ - if (tt_setonechar (ttp) < 0) - return -1; - return (tt_setnoecho (ttp)); -} - -/* Set the terminal into cbreak (no-echo, one-character-at-a-time) mode */ -int -ttfd_cbreak (fd, ttp) - int fd; - TTYSTRUCT *ttp; -{ - if (tt_setcbreak (ttp) < 0) - return -1; - return (ttsetattr (fd, ttp)); -} - -/* Set the terminal into cbreak (no-echo, one-character-at-a-time) mode */ -int -ttcbreak () -{ - TTYSTRUCT tt; - - if (ttsaved == 0) - return -1; - tt = ttin; - return (ttfd_cbreak (0, &tt)); -} diff --git a/lib/sh/snprintf.c.save b/lib/sh/snprintf.c.save deleted file mode 100644 index d7c60864f..000000000 --- a/lib/sh/snprintf.c.save +++ /dev/null @@ -1,2152 +0,0 @@ -/* - build a test version with - gcc -g -DDRIVER -I../.. -I../../include -o test-snprintf snprintf.c fmtu*long.o -*/ - -/* - Unix snprintf implementation. - derived from inetutils/libinetutils/snprintf.c Version 1.1 - - Copyright (C) 2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General License for more details. - - You should have received a copy of the GNU General License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Revision History: - - 1.1: - * added changes from Miles Bader - * corrected a bug with %f - * added support for %#g - * added more comments :-) - 1.0: - * supporting must ANSI syntaxic_sugars - 0.0: - * support %s %c %d - - THANKS(for the patches and ideas): - Miles Bader - Cyrille Rustom - Jacek Slabocewiz - Mike Parker(mouse) - -*/ - -/* - * Currently doesn't handle (and bash/readline doesn't use): - * * *M$ width, precision specifications - * * %N$ numbered argument conversions - * * inf, nan floating values imperfect (if isinf(), isnan() not in libc) - * * support for `F' is imperfect with ldfallback(), since underlying - * printf may not handle it -- should ideally have another autoconf test - */ - -#define FLOATING_POINT - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if defined(DEBUG) -# undef HAVE_SNPRINTF -# undef HAVE_ASPRINTF -#endif - -#if defined(DRIVER) && !defined(HAVE_CONFIG_H) -#define HAVE_LONG_LONG -#define HAVE_LONG_DOUBLE -#ifdef __linux__ -#define HAVE_PRINTF_A_FORMAT -#endif -#define HAVE_ISINF_IN_LIBC -#define HAVE_ISNAN_IN_LIBC -#define PREFER_STDARG -#define HAVE_STRINGIZE -#define HAVE_LIMITS_H -#define HAVE_STDDEF_H -#define HAVE_LOCALE_H -#define intmax_t long -#endif - -#if !defined (HAVE_SNPRINTF) || !defined (HAVE_ASPRINTF) - -#include - -#if defined(PREFER_STDARG) -# include -#else -# include -#endif - -#ifdef HAVE_LIMITS_H -# include -#endif -#include -#ifdef HAVE_STDDEF_H -# include -#endif -#include - -#ifdef HAVE_STDINT_H -# include -#endif - -#ifdef FLOATING_POINT -# include /* for manifest constants */ -# include /* for sprintf */ -#endif - -#include - -#ifdef HAVE_LOCALE_H -# include -#endif - -#include "stdc.h" -#include - -#ifndef DRIVER -# include "shell.h" -#else -# 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)); -extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int)); -#endif - -#ifndef FREE -# define FREE(x) if (x) free (x) -#endif - -/* 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)) - -/* conversion flags */ -#define PF_ALTFORM 0x00001 /* # */ -#define PF_HEXPREFIX 0x00002 /* 0[Xx] */ -#define PF_LADJUST 0x00004 /* - */ -#define PF_ZEROPAD 0x00008 /* 0 */ -#define PF_PLUS 0x00010 /* + */ -#define PF_SPACE 0x00020 /* ' ' */ -#define PF_THOUSANDS 0x00040 /* ' */ - -#define PF_DOT 0x00080 /* `.precision' */ -#define PF_STAR_P 0x00100 /* `*' after precision */ -#define PF_STAR_W 0x00200 /* `*' before or without precision */ - -/* length modifiers */ -#define PF_SIGNEDCHAR 0x00400 /* hh */ -#define PF_SHORTINT 0x00800 /* h */ -#define PF_LONGINT 0x01000 /* l */ -#define PF_LONGLONG 0x02000 /* ll */ -#define PF_LONGDBL 0x04000 /* L */ -#define PF_INTMAX_T 0x08000 /* j */ -#define PF_SIZE_T 0x10000 /* z */ -#define PF_PTRDIFF_T 0x20000 /* t */ - -#define PF_ALLOCBUF 0x40000 /* for asprintf, vasprintf */ - -#define PFM_SN 0x01 /* snprintf, vsnprintf */ -#define PFM_AS 0x02 /* asprintf, vasprintf */ - -#define ASBUFSIZE 128 - -#define x_digs "0123456789abcdef" -#define X_digs "0123456789ABCDEF" - -static char intbuf[INT_STRLEN_BOUND(unsigned long) + 1]; - -static int decpoint; -static int thoussep; -static char *grouping; - -/* - * For the FLOATING POINT FORMAT : - * the challenge was finding a way to - * manipulate the Real numbers without having - * to resort to mathematical function(it - * would require to link with -lm) and not - * going down to the bit pattern(not portable) - * - * so a number, a real is: - - real = integral + fraction - - integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0 - fraction = b(1)*10^-1 + b(2)*10^-2 + ... - - where: - 0 <= a(i) => 9 - 0 <= b(i) => 9 - - from then it was simple math - */ - -/* - * size of the buffer for the integral part - * and the fraction part - */ -#define MAX_INT 99 + 1 /* 1 for the null */ -#define MAX_FRACT 307 + 1 - -/* - * These functions use static buffers to store the results, - * and so are not reentrant - */ -#define itoa(n) fmtulong(n, 10, intbuf, sizeof(intbuf), 0); -#define dtoa(n, p, f) numtoa(n, 10, p, f) - -#define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;} - -#define GETARG(type) (va_arg(args, type)) - -/* Macros that do proper sign extension and handle length modifiers. Used - for the integer conversion specifiers. */ -#define GETSIGNED(p) \ - (((p)->flags & PF_LONGINT) \ - ? GETARG (long) \ - : (((p)->flags & PF_SHORTINT) ? (long)(short)GETARG (int) \ - : (long)GETARG (int))) - -#define GETUNSIGNED(p) \ - (((p)->flags & PF_LONGINT) \ - ? GETARG (unsigned long) \ - : (((p)->flags & PF_SHORTINT) ? (unsigned long)(unsigned short)GETARG (int) \ - : (unsigned long)GETARG (unsigned int))) - - -#ifdef HAVE_LONG_DOUBLE -#define GETLDOUBLE(p) GETARG (long double) -#endif -#define GETDOUBLE(p) GETARG (double) - -#define SET_SIZE_FLAGS(p, type) \ - if (sizeof (type) > sizeof (int)) \ - (p)->flags |= PF_LONGINT; \ - if (sizeof (type) > sizeof (long)) \ - (p)->flags |= PF_LONGLONG; - -/* this struct holds everything we need */ -struct DATA -{ - int length; - char *base; /* needed for [v]asprintf */ - char *holder; - int counter; - const char *pf; - -/* FLAGS */ - int flags; - int justify; - int width, precision; - char pad; -}; - -/* the floating point stuff */ -#ifdef FLOATING_POINT -static double pow_10 __P((int)); -static int log_10 __P((double)); -static double integral __P((double, double *)); -static char *numtoa __P((double, int, int, char **)); -#endif - -static void init_data __P((struct DATA *, char *, size_t, const char *, int)); -static void init_conv_flag __P((struct DATA *)); - -/* for the format */ -#ifdef FLOATING_POINT -static void floating __P((struct DATA *, double)); -static void exponent __P((struct DATA *, double)); -#endif -static void number __P((struct DATA *, unsigned long, int)); -#ifdef HAVE_LONG_LONG -static void lnumber __P((struct DATA *, unsigned long long, int)); -#endif -static void pointer __P((struct DATA *, unsigned long)); -static void strings __P((struct DATA *, char *)); - -#ifdef FLOATING_POINT -# define FALLBACK_FMTSIZE 32 -# define FALLBACK_BASE 4096 -# define LFALLBACK_BASE 5120 -# ifdef HAVE_LONG_DOUBLE -static void ldfallback __P((struct DATA *, const char *, const char *, long double)); -# endif -static void dfallback __P((struct DATA *, const char *, const char *, double)); -#endif - -static char *groupnum __P((char *)); - -#ifdef DRIVER -static void memory_error_and_abort (); -static void *xmalloc __P((size_t)); -static void *xrealloc __P((void *, size_t)); -static void xfree __P((void *)); -#else -# include -#endif - -/* those are defines specific to snprintf to hopefully - * make the code clearer :-) - */ -#define RIGHT 1 -#define LEFT 0 -#define NOT_FOUND -1 -#define FOUND 1 -#define MAX_FIELD 15 - -/* round off to the precision */ -#define ROUND(d, p) \ - (d < 0.) ? \ - d - pow_10(-(p)->precision) * 0.5 : \ - d + pow_10(-(p)->precision) * 0.5 - -/* set default precision */ -#define DEF_PREC(p) \ - if ((p)->precision == NOT_FOUND) \ - (p)->precision = 6 - -/* put a char. increment the number of chars written even if we've exceeded - the vsnprintf/snprintf buffer size (for the return value) */ -#define PUT_CHAR(c, p) \ - do \ - { \ - if (((p)->flags & PF_ALLOCBUF) && ((p)->counter >= (p)->length - 1)) \ - { \ - (p)->length += ASBUFSIZE; \ - (p)->base = (char *)xrealloc((p)->base, (p)->length); \ - (p)->holder = (p)->base + (p)->counter; /* in case reallocated */ \ - } \ - if ((p)->counter < (p)->length) \ - *(p)->holder++ = (c); \ - (p)->counter++; \ - } \ - while (0) - -/* Output a string. P->WIDTH has already been adjusted for padding. */ -#define PUT_STRING(string, len, p) \ - do \ - { \ - PAD_RIGHT (p); \ - while ((len)-- > 0) \ - { \ - PUT_CHAR (*(string), (p)); \ - (string)++; \ - } \ - PAD_LEFT (p); \ - } \ - while (0) - -#define PUT_PLUS(d, p, zero) \ - if ((d) > zero && (p)->justify == RIGHT) \ - PUT_CHAR('+', p) - -#define PUT_SPACE(d, p, zero) \ - if (((p)->flags & PF_SPACE) && (d) > zero) \ - PUT_CHAR(' ', p) - -/* pad right */ -#define PAD_RIGHT(p) \ - if ((p)->width > 0 && (p)->justify != LEFT) \ - for (; (p)->width > 0; (p)->width--) \ - PUT_CHAR((p)->pad, p) - -/* pad left */ -#define PAD_LEFT(p) \ - if ((p)->width > 0 && (p)->justify == LEFT) \ - for (; (p)->width > 0; (p)->width--) \ - PUT_CHAR((p)->pad, p) - -/* pad with zeros from decimal precision */ -#define PAD_ZERO(p) \ - if ((p)->precision > 0) \ - for (; (p)->precision > 0; (p)->precision--) \ - PUT_CHAR('0', p) - -/* if width and prec. in the args */ -#define STAR_ARGS(p) \ - do { \ - if ((p)->flags & PF_STAR_W) \ - { \ - (p)->width = GETARG (int); \ - if ((p)->width < 0) \ - { \ - (p)->flags |= PF_LADJUST; \ - (p)->justify = LEFT; \ - (p)->width = -(p)->width; \ - } \ - } \ - if ((p)->flags & PF_STAR_P) \ - { \ - (p)->precision = GETARG (int); \ - if ((p)->precision < 0) \ - { \ - (p)->flags &= ~PF_STAR_P; \ - (p)->precision = NOT_FOUND; \ - } \ - } \ - } while (0) - -#if defined (HAVE_LOCALE_H) -# define GETLOCALEDATA(d, t, g) \ - do \ - { \ - struct lconv *lv; \ - if ((d) == 0) { \ - (d) = '.'; (t) = -1; (g) = 0; /* defaults */ \ - lv = localeconv(); \ - if (lv) \ - { \ - if (lv->decimal_point && lv->decimal_point[0]) \ - (d) = lv->decimal_point[0]; \ - if (lv->thousands_sep && lv->thousands_sep[0]) \ - (t) = lv->thousands_sep[0]; \ - (g) = lv->grouping ? lv->grouping : ""; \ - if (*(g) == '\0' || *(g) == CHAR_MAX || (t) == -1) (g) = 0; \ - } \ - } \ - } \ - while (0); -#else -# define GETLOCALEDATA(d, t, g) \ - ( (d) = '.', (t) = ',', g = "\003" ) -#endif - -#ifdef FLOATING_POINT -/* - * Find the nth power of 10 - */ -static double -pow_10(n) - int n; -{ - double P; - - /* handle common cases with fast switch statement. */ - switch (n) - { - case -3: return .001; - case -2: return .01; - case -1: return .1; - case 0: return 1.; - case 1: return 10.; - case 2: return 100.; - case 3: return 1000.; - } - - if (n < 0) - { - P = .0001; - for (n += 4; n < 0; n++) - P /= 10.; - } - else - { - P = 10000.; - for (n -= 4; n > 0; n--) - P *= 10.; - } - - return P; -} - -/* - * Find the integral part of the log in base 10 - * Note: this not a real log10() - I just need and approximation(integerpart) of x in: - 10^x ~= r - * log_10(200) = 2; - * log_10(250) = 2; - * - * NOTE: do not call this with r == 0 -- an infinite loop results. - */ -static int -log_10(r) - double r; -{ - int i = 0; - double result = 1.; - - if (r < 0.) - r = -r; - - if (r < 1.) - { - while (result >= r) - { - result /= 10.; - i++; - } - return (-i); - } - else - { - while (result <= r) - { - result *= 10.; - i++; - } - return (i - 1); - } -} - -/* - * This function return the fraction part of a double - * and set in ip the integral part. - * In many ways it resemble the modf() found on most Un*x - */ -static double -integral(real, ip) - double real; - double *ip; -{ - int j; - double i, s, p; - double real_integral = 0.; - - /* take care of the obvious */ - /* equal to zero ? */ - if (real == 0.) - { - *ip = 0.; - return (0.); - } - - /* negative number ? */ - if (real < 0.) - real = -real; - - /* a fraction ? */ - if ( real < 1.) - { - *ip = 0.; - return real; - } - - /* the real work :-) */ - for (j = log_10(real); j >= 0; j--) - { - p = pow_10(j); - s = (real - real_integral)/p; - i = 0.; - while (i + 1. <= s) - i++; - real_integral += i*p; - } - *ip = real_integral; - return (real - real_integral); -} - -#define PRECISION 1.e-6 -/* - * return an ascii representation of the integral part of the number - * and set fract to be an ascii representation of the fraction part - * the container for the fraction and the integral part or staticly - * declare with fix size - */ -static char * -numtoa(number, base, precision, fract) - double number; - int base, precision; - char **fract; -{ - register int i, j; - double ip, fp; /* integer and fraction part */ - double fraction; - int digits = MAX_INT - 1; - static char integral_part[MAX_INT]; - static char fraction_part[MAX_FRACT]; - double sign; - int ch; - - /* taking care of the obvious case: 0.0 */ - if (number == 0.) - { - integral_part[0] = '0'; - integral_part[1] = '\0'; - fraction_part[0] = '0'; - fraction_part[1] = '\0'; - if (fract) - *fract = fraction_part; - return integral_part; - } - - /* for negative numbers */ - if ((sign = number) < 0.) - { - number = -number; - digits--; /* sign consume one digit */ - } - - fraction = integral(number, &ip); - number = ip; - - /* do the integral part */ - if (ip == 0.) - { - integral_part[0] = '0'; - i = 1; - } - else - { - for ( i = 0; i < digits && number != 0.; ++i) - { - number /= base; - fp = integral(number, &ip); - ch = (int)((fp + PRECISION)*base); /* force to round */ - integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10; - if (! ISXDIGIT((unsigned char)integral_part[i])) - break; /* bail out overflow !! */ - number = ip; - } - } - - /* Oh No !! out of bound, ho well fill it up ! */ - if (number != 0.) - for (i = 0; i < digits; ++i) - integral_part[i] = '9'; - - /* put the sign ? */ - if (sign < 0.) - integral_part[i++] = '-'; - - integral_part[i] = '\0'; - - /* reverse every thing */ - for ( i--, j = 0; j < i; j++, i--) - SWAP_INT(integral_part[i], integral_part[j]); - - /* the fractional part */ - for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision--) - { - fraction_part[i] = (int)((fp + PRECISION)*10. + '0'); - if (! DIGIT(fraction_part[i])) /* underflow ? */ - break; - fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.); - } - fraction_part[i] = '\0'; - - if (fract != (char **)0) - *fract = fraction_part; - - return integral_part; -} -#endif - -/* for %d and friends, it puts in holder - * the representation with the right padding - */ -static void -number(p, d, base) - struct DATA *p; - unsigned long d; - int base; -{ - char *tmp, *t; - long sd; - int flags; - - /* An explicit precision turns off the zero-padding flag. */ - if ((p->flags & PF_ZEROPAD) && p->precision >= 0 && (p->flags & PF_DOT)) - p->flags &= ~PF_ZEROPAD; - - sd = d; /* signed for ' ' padding in base 10 */ - flags = (*p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0; - if (*p->pf == 'X') - flags |= FL_HEXUPPER; - - tmp = fmtulong (d, base, intbuf, sizeof(intbuf), flags); - t = 0; - if ((p->flags & PF_THOUSANDS)) - { - GETLOCALEDATA(decpoint, thoussep, grouping); - if (grouping && (t = groupnum (tmp))) - tmp = t; - } - - p->width -= strlen(tmp); - PAD_RIGHT(p); - - if ((p->flags & PF_DOT) && p->precision > 0) - { - p->precision -= strlen(tmp); - PAD_ZERO(p); - } - - switch (base) - { - case 10: - PUT_PLUS(sd, p, 0); - PUT_SPACE(sd, p, 0); - break; - case 8: - if (p->flags & PF_ALTFORM) - PUT_CHAR('0', p); - break; - case 16: - if (p->flags & PF_ALTFORM) - { - PUT_CHAR('0', p); - PUT_CHAR(*p->pf, p); - } - break; - } - - while (*tmp) - { - PUT_CHAR(*tmp, p); - tmp++; - } - - PAD_LEFT(p); - FREE (t); -} - -#ifdef HAVE_LONG_LONG -/* - * identical to number() but works for `long long' - */ -static void -lnumber(p, d, base) - struct DATA *p; - unsigned long long d; - int base; -{ - char *tmp, *t; - long long sd; - int flags; - - /* An explicit precision turns off the zero-padding flag. */ - if ((p->flags & PF_ZEROPAD) && p->precision >= 0 && (p->flags & PF_DOT)) - p->flags &= ~PF_ZEROPAD; - - sd = d; /* signed for ' ' padding in base 10 */ - flags = (*p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0; - if (*p->pf == 'X') - flags |= FL_HEXUPPER; - - tmp = fmtullong (d, base, intbuf, sizeof(intbuf), flags); - t = 0; - if ((p->flags & PF_THOUSANDS)) - { - GETLOCALEDATA(decpoint, thoussep, grouping); - if (grouping && (t = groupnum (tmp))) - tmp = t; - } - - p->width -= strlen(tmp); - PAD_RIGHT(p); - - if ((p->flags & PF_DOT) && p->precision > 0) - { - p->precision -= strlen(tmp); - PAD_ZERO(p); - } - - switch (base) - { - case 10: - PUT_PLUS(sd, p, 0); - PUT_SPACE(sd, p, 0); - break; - case 8: - if (p->flags & PF_ALTFORM) - PUT_CHAR('0', p); - break; - case 16: - if (p->flags & PF_ALTFORM) - { - PUT_CHAR('0', p); - PUT_CHAR(*p->pf, p); - } - break; - } - - while (*tmp) - { - PUT_CHAR(*tmp, p); - tmp++; - } - - PAD_LEFT(p); - FREE (t); -} -#endif - -static void -pointer(p, d) - struct DATA *p; - unsigned long d; -{ - char *tmp; - - tmp = fmtulong(d, 16, intbuf, sizeof(intbuf), 0); - p->width -= strlen(tmp); - PAD_RIGHT(p); - - /* prefix '0x' for pointers */ - PUT_CHAR('0', p); - PUT_CHAR('x', p); - - while (*tmp) - { - PUT_CHAR(*tmp, p); - tmp++; - } - PAD_LEFT(p); -} - -/* %s strings */ -static void -strings(p, tmp) - struct DATA *p; - char *tmp; -{ - size_t len; - - len = strlen(tmp); - if (p->precision != NOT_FOUND) /* the smallest number */ - len = (len < p->precision ? len : p->precision); - p->width -= len; - - PUT_STRING (tmp, len, p); -} - -#if HANDLE_MULTIBYTE -/* %ls wide-character strings */ -static void -wstrings(p, tmp) - struct DATA *p; - wchar_t *tmp; -{ - size_t len; - mbstate_t mbs; - char *os; - const wchar_t *ws; - - memset (&mbs, '\0', sizeof (mbstate_t)); - ws = (const wchar_t *)tmp; - - os = (char *)NULL; - if (p->precision != NOT_FOUND) - { - os = (char *)xmalloc (p->precision + 1); - len = wcsrtombs (os, &ws, p->precision, &mbs); - } - else - { - len = wcsrtombs (NULL, &ws, 0, &mbs); - if (len != (size_t)-1) - { - memset (&mbs, '\0', sizeof (mbstate_t)); - os = (char *)xmalloc (len + 1); - (void)wcsrtombs (os, &ws, len + 1, &mbs); - } - } - if (len == (size_t)-1) - { - /* invalid multibyte sequence; bail now. */ - FREE (os); - return; - } - - p->width -= len; - PUT_STRING (os, len, p); - free (os); -} - -static void -wchars (p, wc) - struct DATA *p; - wint_t wc; -{ - char *lbuf, *l; - mbstate_t mbs; - size_t len; - - lbuf = (char *)malloc (MB_CUR_MAX+1); - if (lbuf == 0) - return; - memset (&mbs, '\0', sizeof (mbstate_t)); - len = wcrtomb (lbuf, wc, &mbs); - if (len == (size_t)-1) - /* conversion failed; bail now. */ - return; - p->width -= len; - l = lbuf; - PUT_STRING (l, len, p); - free (lbuf); -} -#endif /* HANDLE_MULTIBYTE */ - -#ifdef FLOATING_POINT - -#ifndef HAVE_ISINF_IN_LIBC -/* Half-assed versions, since we don't want to link with libm. */ -static int -isinf(d) - double d; -{ -#ifdef DBL_MAX - if (d < DBL_MIN) - return -1; - else if (d > DBL_MAX) - return 1; - else -#endif - return 0; -} -#endif - -#ifndef HAVE_ISNAN_IN_LIBC -static int -isnan(d) - double d; -{ - return 0; -} -#endif - -/* Check for [+-]infinity and NaN. If MODE == 1, we check for Infinity, else - (mode == 2) we check for NaN. This does the necessary printing. Returns - 1 if Inf or Nan, 0 if not. */ -static int -chkinfnan(p, d, mode) - struct DATA *p; - double d; - int mode; /* == 1 for inf, == 2 for nan */ -{ - int i; - char *tmp; - char *big, *small; - - i = (mode == 1) ? isinf(d) : isnan(d); - if (i == 0) - return 0; - big = (mode == 1) ? "INF" : "NAN"; - small = (mode == 1) ? "inf" : "nan"; - - tmp = (*p->pf == 'F' || *p->pf == 'G' || *p->pf == 'E') ? big : small; - - if (i < 0) - PUT_CHAR('-', p); - - while (*tmp) - { - PUT_CHAR (*tmp, p); - tmp++; - } - - return 1; -} - -/* %f %F %g %G floating point representation */ -static void -floating(p, d) - struct DATA *p; - double d; -{ - char *tmp, *tmp2, *t; - int i; - - if (d != 0 && (chkinfnan(p, d, 1) || chkinfnan(p, d, 2))) - return; /* already printed nan or inf */ - - GETLOCALEDATA(decpoint, thoussep, grouping); - DEF_PREC(p); - d = ROUND(d, p); - tmp = dtoa(d, p->precision, &tmp2); - t = 0; - if ((p->flags & PF_THOUSANDS) && grouping && (t = groupnum (tmp))) - tmp = t; - - /* calculate the padding. 1 for the dot */ - p->width = p->width - - ((d > 0. && p->justify == RIGHT) ? 1:0) - - ((p->flags & PF_SPACE) ? 1:0) - - strlen(tmp) - p->precision - 1; - PAD_RIGHT(p); - PUT_PLUS(d, p, 0.); - PUT_SPACE(d, p, 0.); - - while (*tmp) - { - PUT_CHAR(*tmp, p); /* the integral */ - tmp++; - } - FREE (t); - - if (p->precision != 0 || (p->flags & PF_ALTFORM)) - PUT_CHAR(decpoint, p); /* put the '.' */ - - if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0) - /* smash the trailing zeros unless altform */ - for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--) - tmp2[i] = '\0'; - - for (; *tmp2; tmp2++) - PUT_CHAR(*tmp2, p); /* the fraction */ - - PAD_LEFT(p); -} - -/* %e %E %g %G exponent representation */ -static void -exponent(p, d) - struct DATA *p; - double d; -{ - char *tmp, *tmp2; - int j, i; - - if (chkinfnan(p, d, 1) || chkinfnan(p, d, 2)) - return; /* already printed nan or inf */ - - GETLOCALEDATA(decpoint, thoussep, grouping); - DEF_PREC(p); - j = log_10(d); - d = d / pow_10(j); /* get the Mantissa */ - d = ROUND(d, p); - tmp = dtoa(d, p->precision, &tmp2); - - /* 1 for unit, 1 for the '.', 1 for 'e|E', - * 1 for '+|-', 2 for 'exp' */ - /* calculate how much padding need */ - p->width = p->width - - ((d > 0. && p->justify == RIGHT) ? 1:0) - - ((p->flags & PF_SPACE) ? 1:0) - p->precision - 6; - - PAD_RIGHT(p); - PUT_PLUS(d, p, 0.); - PUT_SPACE(d, p, 0.); - - while (*tmp) - { - PUT_CHAR(*tmp, p); - tmp++; - } - - if (p->precision != 0 || (p->flags & PF_ALTFORM)) - PUT_CHAR(decpoint, p); /* the '.' */ - - if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0) - /* smash the trailing zeros unless altform */ - for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--) - tmp2[i] = '\0'; - - for (; *tmp2; tmp2++) - PUT_CHAR(*tmp2, p); /* the fraction */ - - /* the exponent put the 'e|E' */ - if (*p->pf == 'g' || *p->pf == 'e') - PUT_CHAR('e', p); - else - PUT_CHAR('E', p); - - /* the sign of the exp */ - if (j >= 0) - PUT_CHAR('+', p); - else - { - PUT_CHAR('-', p); - j = -j; - } - - tmp = itoa(j); - /* pad out to at least two spaces. pad with `0' if the exponent is a - single digit. */ - if (j <= 9) - PUT_CHAR('0', p); - - /* the exponent */ - while (*tmp) - { - PUT_CHAR(*tmp, p); - tmp++; - } - PAD_LEFT(p); -} -#endif - -/* Return a new string with the digits in S grouped according to the locale's - grouping info and thousands separator. If no grouping should be performed, - this returns NULL; the caller needs to check for it. */ -static char * -groupnum (s) - char *s; -{ - char *se, *ret, *re, *g; - int len, slen; - - if (grouping == 0 || *grouping <= 0 || *grouping == CHAR_MAX) - return ((char *)NULL); - - /* find min grouping to size returned string */ - for (len = *grouping, g = grouping; *g; g++) - if (*g > 0 && *g < len) - len = *g; - - slen = strlen (s); - len = slen / len + 1; - ret = (char *)xmalloc (slen + len + 1); - re = ret + slen + len; - *re = '\0'; - - g = grouping; - se = s + slen; - len = *g; - - while (se > s) - { - *--re = *--se; - - /* handle `-' inserted by numtoa() and the fmtu* family here. */ - if (se > s && se[-1] == '-') - continue; - - /* begin new group. */ - if (--len == 0 && se > s) - { - *--re = thoussep; - len = *++g; /* was g++, but that uses first char twice (glibc bug, too) */ - if (*g == '\0') - len = *--g; /* use previous grouping */ - else if (*g == CHAR_MAX) - { - do - *--re = *--se; - while (se > s); - break; - } - } - } - - if (re > ret) -#ifdef HAVE_MEMMOVE - memmove (ret, re, strlen (re) + 1); -#else - strcpy (ret, re); -#endif - - return ret; -} - -/* initialize the conversion specifiers */ -static void -init_conv_flag (p) - struct DATA *p; -{ - p->flags &= PF_ALLOCBUF; /* preserve PF_ALLOCBUF flag */ - p->precision = p->width = NOT_FOUND; - p->justify = NOT_FOUND; - p->pad = ' '; -} - -static void -init_data (p, string, length, format, mode) - struct DATA *p; - char *string; - size_t length; - const char *format; - int mode; -{ - p->length = length - 1; /* leave room for '\0' */ - p->holder = p->base = string; - p->pf = format; - p->counter = 0; - p->flags = (mode == PFM_AS) ? PF_ALLOCBUF : 0; -} - -static int -#if defined (__STDC__) -vsnprintf_internal(struct DATA *data, char *string, size_t length, const char *format, va_list args) -#else -vsnprintf_internal(data, string, length, format, args) - struct DATA *data; - char *string; - size_t length; - const char *format; - va_list args; -#endif -{ - double d; /* temporary holder */ -#ifdef HAVE_LONG_DOUBLE - long double ld; /* for later */ -#endif - unsigned long ul; -#ifdef HAVE_LONG_LONG - unsigned long long ull; -#endif - int state, i, c, n; - char *s; -#if HANDLE_MULTIBYTE - wchar_t *ws; - wint_t wc; -#endif - const char *convstart; - int negprec; - - /* Sanity check, the string length must be >= 0. C99 actually says that - LENGTH can be zero here, in the case of snprintf/vsnprintf (it's never - 0 in the case of asprintf/vasprintf), and the return value is the number - of characters that would have been written. */ - if (length < 0) - return -1; - - if (format == 0) - return 0; - - /* Reset these for each call because the locale might have changed. */ - decpoint = thoussep = 0; - grouping = 0; - - negprec = 0; - for (; c = *(data->pf); data->pf++) - { - if (c != '%') - { - PUT_CHAR (c, data); - continue; - } - - convstart = data->pf; - init_conv_flag (data); /* initialise format flags */ - - state = 1; - for (state = 1; state && *data->pf; ) - { - c = *(++data->pf); - /* fmtend = data->pf */ -#if defined (FLOATING_POINT) && defined (HAVE_LONG_DOUBLE) - if (data->flags & PF_LONGDBL) - { - switch (c) - { - case 'f': case 'F': - case 'e': case 'E': - case 'g': case 'G': -# ifdef HAVE_PRINTF_A_FORMAT - case 'a': case 'A': -# endif - STAR_ARGS (data); - ld = GETLDOUBLE (data); - ldfallback (data, convstart, data->pf, ld); - goto conv_break; - } - } -#endif /* FLOATING_POINT && HAVE_LONG_DOUBLE */ - - switch (c) - { - /* Parse format flags */ - case '\0': /* a NULL here ? ? bail out */ - *data->holder = '\0'; - return data->counter; - break; - case '#': - data->flags |= PF_ALTFORM; - continue; - case '0': - data->flags |= PF_ZEROPAD; - data->pad = '0'; - continue; - case '*': - if (data->flags & PF_DOT) - data->flags |= PF_STAR_P; - else - data->flags |= PF_STAR_W; - continue; - case '-': - if ((data->flags & PF_DOT) == 0) - { - data->flags |= PF_LADJUST; - data->justify = LEFT; - } - else - negprec = 1; - continue; - case ' ': - if ((data->flags & PF_PLUS) == 0) - data->flags |= PF_SPACE; - continue; - case '+': - if ((data->flags & PF_DOT) == 0) - { - data->flags |= PF_PLUS; - data->justify = RIGHT; - } - continue; - case '\'': - data->flags |= PF_THOUSANDS; - continue; - - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - n = 0; - do - { - n = n * 10 + TODIGIT(c); - c = *(++data->pf); - } - while (DIGIT(c)); - data->pf--; /* went too far */ - if (n < 0) - n = 0; - if (data->flags & PF_DOT) - data->precision = negprec ? NOT_FOUND : n; - else - data->width = n; - continue; - - /* optional precision */ - case '.': - data->flags |= PF_DOT; - data->precision = 0; - continue; - - /* length modifiers */ - case 'h': - data->flags |= (data->flags & PF_SHORTINT) ? PF_SIGNEDCHAR : PF_SHORTINT; - continue; - case 'l': - data->flags |= (data->flags & PF_LONGINT) ? PF_LONGLONG : PF_LONGINT; - continue; - case 'L': - data->flags |= PF_LONGDBL; - continue; - case 'q': - data->flags |= PF_LONGLONG; - continue; - case 'j': - data->flags |= PF_INTMAX_T; - SET_SIZE_FLAGS(data, intmax_t); - continue; - case 'z': - data->flags |= PF_SIZE_T; - SET_SIZE_FLAGS(data, size_t); - continue; - case 't': - data->flags |= PF_PTRDIFF_T; - SET_SIZE_FLAGS(data, ptrdiff_t); - continue; - - /* Conversion specifiers */ -#ifdef FLOATING_POINT - case 'f': /* float, double */ - case 'F': - STAR_ARGS(data); - d = GETDOUBLE(data); - floating(data, d); -conv_break: - state = 0; - break; - case 'g': - case 'G': - STAR_ARGS(data); - d = GETDOUBLE(data); - if (d == 0) /* XXX */ - { - if (data->precision == NOT_FOUND) - data->precision = 0; - floating (data, d); - } - /* - * for '%g|%G' ANSI: use f if exponent - * is in the range or [-4,p] exclusively - * else use %e|%E - */ - else - { - i = log_10(d); - DEF_PREC(data); - if (-4 < i && i < data->precision) - { - /* reset precision */ - data->precision -= i + 1; - floating(data, d); - } - else - { - /* reduce precision by 1 because of leading digit before - decimal point in e format. */ - data->precision--; - exponent(data, d); - } - } - state = 0; - break; - case 'e': - case 'E': /* Exponent double */ - STAR_ARGS(data); - d = GETDOUBLE(data); - exponent(data, d); - state = 0; - break; -# ifdef HAVE_PRINTF_A_FORMAT - case 'a': - case 'A': - STAR_ARGS(data); - d = GETDOUBLE(data); - dfallback(data, convstart, data->pf, d); - state = 0; - break; -# endif /* HAVE_PRINTF_A_FORMAT */ -#endif /* FLOATING_POINT */ - case 'U': - data->flags |= PF_LONGINT; - /* FALLTHROUGH */ - case 'u': - STAR_ARGS(data); -#ifdef HAVE_LONG_LONG - if (data->flags & PF_LONGLONG) - { - ull = GETARG (unsigned long long); - lnumber(data, ull, 10); - } - else -#endif - { - ul = GETUNSIGNED(data); - number(data, ul, 10); - } - state = 0; - break; - case 'D': - data->flags |= PF_LONGINT; - /* FALLTHROUGH */ - case 'd': /* decimal */ - case 'i': - STAR_ARGS(data); -#ifdef HAVE_LONG_LONG - if (data->flags & PF_LONGLONG) - { - ull = GETARG (long long); - lnumber(data, ull, 10); - } - else -#endif - { - ul = GETSIGNED(data); - number(data, ul, 10); - } - state = 0; - break; - case 'o': /* octal */ - STAR_ARGS(data); -#ifdef HAVE_LONG_LONG - if (data->flags & PF_LONGLONG) - { - ull = GETARG (unsigned long long); - lnumber(data, ull, 8); - } - else -#endif - { - ul = GETUNSIGNED(data); - number(data, ul, 8); - } - state = 0; - break; - case 'x': - case 'X': /* hexadecimal */ - STAR_ARGS(data); -#ifdef HAVE_LONG_LONG - if (data->flags & PF_LONGLONG) - { - ull = GETARG (unsigned long long); - lnumber(data, ull, 16); - } - else -#endif - { - ul = GETUNSIGNED(data); - number(data, ul, 16); - } - state = 0; - break; - case 'p': - STAR_ARGS(data); - ul = (unsigned long)GETARG (void *); - pointer(data, ul); - state = 0; - break; -#if HANDLE_MULTIBYTE - case 'C': - data->flags |= PF_LONGINT; - /* FALLTHROUGH */ -#endif - case 'c': /* character */ - STAR_ARGS(data); -#if HANDLE_MULTIBYTE - if (data->flags & PF_LONGINT) - { - wc = GETARG (wint_t); - wchars (data, wc); - } - else -#endif - { - ul = GETARG (int); - PUT_CHAR(ul, data); - } - state = 0; - break; -#if HANDLE_MULTIBYTE - case 'S': - data->flags |= PF_LONGINT; - /* FALLTHROUGH */ -#endif - case 's': /* string */ - STAR_ARGS(data); -#if HANDLE_MULTIBYTE - if (data->flags & PF_LONGINT) - { - ws = GETARG (wchar_t *); - wstrings (data, ws); - } - else -#endif - { - s = GETARG (char *); - strings(data, s); - } - state = 0; - break; - case 'n': -#ifdef HAVE_LONG_LONG - if (data->flags & PF_LONGLONG) - *(GETARG (long long *)) = data->counter; - else -#endif - if (data->flags & PF_LONGINT) - *(GETARG (long *)) = data->counter; - else if (data->flags & PF_SHORTINT) - *(GETARG (short *)) = data->counter; - else - *(GETARG (int *)) = data->counter; - state = 0; - break; - case '%': /* nothing just % */ - PUT_CHAR('%', data); - state = 0; - break; - default: - /* is this an error ? maybe bail out */ - state = 0; - break; - } /* end switch */ - } /* end of `%' for loop */ - } /* end of format string for loop */ - - if (data->length >= 0) - *data->holder = '\0'; /* the end ye ! */ - - return data->counter; -} - -#if defined (FLOATING_POINT) && defined (HAVE_LONG_DOUBLE) -/* - * Printing floating point numbers accurately is an art. I'm not good - * at it. Fall back to sprintf for long double formats. - */ -static void -ldfallback (data, fs, fe, ld) - struct DATA *data; - const char *fs, *fe; - long double ld; -{ - register char *x; - char fmtbuf[FALLBACK_FMTSIZE], *obuf; - int fl; - - fl = LFALLBACK_BASE + (data->precision < 6 ? 6 : data->precision) + 2; - obuf = (char *)xmalloc (fl); - fl = fe - fs + 1; - strncpy (fmtbuf, fs, fl); - fmtbuf[fl] = '\0'; - - if ((data->flags & PF_STAR_W) && (data->flags & PF_STAR_P)) - sprintf (obuf, fmtbuf, data->width, data->precision, ld); - else if (data->flags & PF_STAR_W) - sprintf (obuf, fmtbuf, data->width, ld); - else if (data->flags & PF_STAR_P) - sprintf (obuf, fmtbuf, data->precision, ld); - else - sprintf (obuf, fmtbuf, ld); - - for (x = obuf; *x; x++) - PUT_CHAR (*x, data); - xfree (obuf); -} -#endif /* FLOATING_POINT && HAVE_LONG_DOUBLE */ - -#ifdef FLOATING_POINT -/* Used for %a, %A if the libc printf supports them. */ -static void -dfallback (data, fs, fe, d) - struct DATA *data; - const char *fs, *fe; - double d; -{ - register char *x; - char fmtbuf[FALLBACK_FMTSIZE], obuf[FALLBACK_BASE]; - int fl; - - fl = fe - fs + 1; - strncpy (fmtbuf, fs, fl); - fmtbuf[fl] = '\0'; - - if ((data->flags & PF_STAR_W) && (data->flags & PF_STAR_P)) - sprintf (obuf, fmtbuf, data->width, data->precision, d); - else if (data->flags & PF_STAR_W) - sprintf (obuf, fmtbuf, data->width, d); - else if (data->flags & PF_STAR_P) - sprintf (obuf, fmtbuf, data->precision, d); - else - sprintf (obuf, fmtbuf, d); - - for (x = obuf; *x; x++) - PUT_CHAR (*x, data); -} -#endif /* FLOATING_POINT */ - -#ifndef HAVE_SNPRINTF - -int -#if defined (__STDC__) -vsnprintf(char *string, size_t length, const char *format, va_list args) -#else -vsnprintf(string, length, format, args) - char *string; - size_t length; - const char *format; - va_list args; -#endif -{ - struct DATA data; - - if (string == 0 && length != 0) - return 0; - init_data (&data, string, length, format, PFM_SN); - return (vsnprintf_internal(&data, string, length, format, args)); -} - -int -#if defined(PREFER_STDARG) -snprintf(char *string, size_t length, const char * format, ...) -#else -snprintf(string, length, format, va_alist) - char *string; - size_t length; - const char *format; - va_dcl -#endif -{ - struct DATA data; - int rval; - va_list args; - - SH_VA_START(args, format); - - if (string == 0 && length != 0) - return 0; - init_data (&data, string, length, format, PFM_SN); - rval = vsnprintf_internal (&data, string, length, format, args); - - va_end(args); - - return rval; -} - -#endif /* HAVE_SNPRINTF */ - -#ifndef HAVE_ASPRINTF - -int -#if defined (__STDC__) -vasprintf(char **stringp, const char *format, va_list args) -#else -vasprintf(stringp, format, args) - char **stringp; - const char *format; - va_list args; -#endif -{ - struct DATA data; - char *string; - int r; - - string = (char *)xmalloc(ASBUFSIZE); - init_data (&data, string, ASBUFSIZE, format, PFM_AS); - r = vsnprintf_internal(&data, string, ASBUFSIZE, format, args); - *stringp = data.base; /* not string in case reallocated */ - return r; -} - -int -#if defined(PREFER_STDARG) -asprintf(char **stringp, const char * format, ...) -#else -asprintf(stringp, format, va_alist) - char **stringp; - const char *format; - va_dcl -#endif -{ - int rval; - va_list args; - - SH_VA_START(args, format); - - rval = vasprintf (stringp, format, args); - - va_end(args); - - return rval; -} - -#endif - -#endif - -#ifdef DRIVER - -static void -memory_error_and_abort () -{ - write (2, "out of virtual memory\n", 22); - abort (); -} - -static void * -xmalloc(bytes) - size_t bytes; -{ - void *ret; - - ret = malloc(bytes); - if (ret == 0) - memory_error_and_abort (); - return ret; -} - -static void * -xrealloc (pointer, bytes) - void *pointer; - size_t bytes; -{ - void *ret; - - ret = pointer ? realloc(pointer, bytes) : malloc(bytes); - if (ret == 0) - memory_error_and_abort (); - return ret; -} - -static void -xfree(x) - void *x; -{ - if (x) - free (x); -} - -/* set of small tests for snprintf() */ -main() -{ - char holder[100]; - char *h; - int i, si, ai; - -#ifdef HAVE_LOCALE_H - setlocale(LC_ALL, ""); -#endif - -#if 1 - si = snprintf((char *)NULL, 0, "abcde\n"); - printf("snprintf returns %d with NULL first argument and size of 0\n", si); - si = snprintf(holder, 0, "abcde\n"); - printf("snprintf returns %d with non-NULL first argument and size of 0\n", si); - si = snprintf((char *)NULL, 16, "abcde\n"); - printf("snprintf returns %d with NULL first argument and non-zero size\n", si); - -/* - printf("Suite of test for snprintf:\n"); - printf("a_format\n"); - printf("printf() format\n"); - printf("snprintf() format\n\n"); -*/ -/* Checking the field widths */ - - printf("/%%ld %%ld/, 336, 336\n"); - snprintf(holder, sizeof holder, "/%ld %ld/\n", 336, 336); - asprintf(&h, "/%ld %ld/\n", 336, 336); - printf("/%ld %ld/\n", 336, 336); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%d/, 336\n"); - snprintf(holder, sizeof holder, "/%d/\n", 336); - asprintf(&h, "/%d/\n", 336); - printf("/%d/\n", 336); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%2d/, 336\n"); - snprintf(holder, sizeof holder, "/%2d/\n", 336); - asprintf(&h, "/%2d/\n", 336); - printf("/%2d/\n", 336); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%10d/, 336\n"); - snprintf(holder, sizeof holder, "/%10d/\n", 336); - asprintf(&h, "/%10d/\n", 336); - printf("/%10d/\n", 336); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%-10d/, 336\n"); - snprintf(holder, sizeof holder, "/%-10d/\n", 336); - asprintf(&h, "/%-10d/\n", 336); - printf("/%-10d/\n", 336); - printf("%s", holder); - printf("%s\n", h); - - -/* floating points */ - - printf("/%%f/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%f/\n", 1234.56); - asprintf(&h, "/%f/\n", 1234.56); - printf("/%f/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%e/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%e/\n", 1234.56); - asprintf(&h, "/%e/\n", 1234.56); - printf("/%e/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%4.2f/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56); - asprintf(&h, "/%4.2f/\n", 1234.56); - printf("/%4.2f/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%3.1f/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56); - asprintf(&h, "/%3.1f/\n", 1234.56); - printf("/%3.1f/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%10.3f/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56); - asprintf(&h, "/%10.3f/\n", 1234.56); - printf("/%10.3f/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%10.3e/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56); - asprintf(&h, "/%10.3e/\n", 1234.56); - printf("/%10.3e/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%+4.2f/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56); - asprintf(&h, "/%+4.2f/\n", 1234.56); - printf("/%+4.2f/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%010.2f/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56); - asprintf(&h, "/%010.2f/\n", 1234.56); - printf("/%010.2f/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - -#define BLURB "Outstanding acting !" -/* strings precisions */ - - printf("/%%2s/, \"%s\"\n", BLURB); - snprintf(holder, sizeof holder, "/%2s/\n", BLURB); - asprintf(&h, "/%2s/\n", BLURB); - printf("/%2s/\n", BLURB); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%22s/ %s\n", BLURB); - snprintf(holder, sizeof holder, "/%22s/\n", BLURB); - asprintf(&h, "/%22s/\n", BLURB); - printf("/%22s/\n", BLURB); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%22.5s/ %s\n", BLURB); - snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB); - asprintf(&h, "/%22.5s/\n", BLURB); - printf("/%22.5s/\n", BLURB); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%-22.5s/ %s\n", BLURB); - snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB); - asprintf(&h, "/%-22.5s/\n", BLURB); - printf("/%-22.5s/\n", BLURB); - printf("%s", holder); - printf("%s\n", h); - -/* see some flags */ - - printf("%%x %%X %%#x, 31, 31, 31\n"); - snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31); - asprintf(&h, "%x %X %#x\n", 31, 31, 31); - printf("%x %X %#x\n", 31, 31, 31); - printf("%s", holder); - printf("%s\n", h); - - printf("**%%d**%% d**%% d**, 42, 42, -42\n"); - snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42); - asprintf(&h, "**%d**% d**% d**\n", 42, 42, -42); - printf("**%d**% d**% d**\n", 42, 42, -42); - printf("%s", holder); - printf("%s\n", h); - -/* other flags */ - - printf("/%%g/, 31.4\n"); - snprintf(holder, sizeof holder, "/%g/\n", 31.4); - asprintf(&h, "/%g/\n", 31.4); - printf("/%g/\n", 31.4); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%.6g/, 31.4\n"); - snprintf(holder, sizeof holder, "/%.6g/\n", 31.4); - asprintf(&h, "/%.6g/\n", 31.4); - printf("/%.6g/\n", 31.4); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%.1G/, 31.4\n"); - snprintf(holder, sizeof holder, "/%.1G/\n", 31.4); - asprintf(&h, "/%.1G/\n", 31.4); - printf("/%.1G/\n", 31.4); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%.1G/, 3100000000.4\n"); - snprintf(holder, sizeof holder, "/%.1G/\n", 3100000000.4); - asprintf(&h, "/%.1G/\n", 3100000000.4); - printf("/%.1G/\n", 3100000000.4); - printf("%s", holder); - printf("%s\n", h); - - printf("abc%%n\n"); - printf("abc%n", &i); printf("%d\n", i); - snprintf(holder, sizeof holder, "abc%n", &i); - printf("%s", holder); printf("%d\n\n", i); - asprintf(&h, "abc%n", &i); - printf("%s", h); printf("%d\n\n", i); - - printf("%%*.*s --> 10.10\n"); - snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB); - asprintf(&h, "%*.*s\n", 10, 10, BLURB); - printf("%*.*s\n", 10, 10, BLURB); - printf("%s", holder); - printf("%s\n", h); - - printf("%%%%%%%%\n"); - snprintf(holder, sizeof holder, "%%%%\n"); - asprintf(&h, "%%%%\n"); - printf("%%%%\n"); - printf("%s", holder); - printf("%s\n", h); - -#define BIG "Hello this is a too big string for the buffer" -/* printf("A buffer to small of 10, trying to put this:\n");*/ - printf("<%%>, %s\n", BIG); - i = snprintf(holder, 10, "%s\n", BIG); - i = asprintf(&h, "%s", BIG); - printf("<%s>\n", BIG); - printf("<%s>\n", holder); - printf("<%s>\n\n", h); - - printf ("<%%p> vsnprintf\n"); - i = snprintf(holder, 100, "%p", vsnprintf); - i = asprintf(&h, "%p", vsnprintf); - printf("<%p>\n", vsnprintf); - printf("<%s>\n", holder); - printf("<%s>\n\n", h); - - printf ("<%%lu> LONG_MAX+1\n"); - i = snprintf(holder, 100, "%lu", (unsigned long)(LONG_MAX)+1); - i = asprintf(&h, "%lu", (unsigned long)(LONG_MAX)+1); - printf("<%lu>\n", (unsigned long)(LONG_MAX)+1); - printf("<%s>\n", holder); - printf("<%s>\n\n", h); - -#ifdef HAVE_LONG_LONG - printf ("<%%llu> LLONG_MAX+1\n"); - i = snprintf(holder, 100, "%llu", (unsigned long long)(LLONG_MAX)+1); - i = asprintf(&h, "%llu", (unsigned long long)(LLONG_MAX)+1); - printf("<%llu>\n", (unsigned long long)(LLONG_MAX)+1); - printf("<%s>\n", holder); - printf("<%s>\n\n", h); -#endif - -#ifdef HAVE_LONG_DOUBLE - printf ("<%%6.2LE> 42.42\n"); - i = snprintf(holder, 100, "%6.2LE", (long double)42.42); - i = asprintf(&h, "%6.2LE", (long double)42.42); - printf ("<%6.2LE>\n", (long double)42.42); - printf ("<%s>\n", holder); - printf ("<%s>\n\n", h); -#endif - -#ifdef HAVE_PRINTF_A_FORMAT - printf ("<%%6.2A> 42.42\n"); - i = snprintf(holder, 100, "%6.2A", 42.42); - i = asprintf(&h, "%6.2A", 42.42); - printf ("<%6.2A>\n", 42.42); - printf ("<%s>\n", holder); - printf ("<%s>\n\n", h); - - printf ("<%%6.2LA> 42.42\n"); - i = snprintf(holder, 100, "%6.2LA", (long double)42.42); - i = asprintf(&h, "%6.2LA", (long double)42.42); - printf ("<%6.2LA>\n", (long double)42.42); - printf ("<%s>\n", holder); - printf ("<%s>\n\n", h); -#endif - - printf ("<%%.10240f> DBL_MAX\n"); - si = snprintf(holder, 100, "%.10240f", DBL_MAX); - ai = asprintf(&h, "%.10240f", DBL_MAX); - printf ("<%.10240f>\n", DBL_MAX); - printf ("<%d> <%s>\n", si, holder); - printf ("<%d> <%s>\n\n", ai, h); - - printf ("<%%.10240Lf> LDBL_MAX\n"); - si = snprintf(holder, 100, "%.10240Lf", (long double)LDBL_MAX); - ai = asprintf(&h, "%.10240Lf", (long double)LDBL_MAX); - printf ("<%.10240Lf>\n", (long double)LDBL_MAX); - printf ("<%d> <%s>\n", si, holder); - printf ("<%d> <%s>\n\n", ai, h); - - /* huh? */ - printf("/%%g/, 421.2345\n"); - snprintf(holder, sizeof holder, "/%g/\n", 421.2345); - asprintf(&h, "/%g/\n", 421.2345); - printf("/%g/\n", 421.2345); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%g/, 4214.2345\n"); - snprintf(holder, sizeof holder, "/%g/\n", 4214.2345); - asprintf(&h, "/%g/\n", 4214.2345); - printf("/%g/\n", 4214.2345); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%.5g/, 4214.2345\n"); - snprintf(holder, sizeof holder, "/%.5g/\n", 4214.2345); - asprintf(&h, "/%.5g/\n", 4214.2345); - printf("/%.5g/\n", 4214.2345); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%.4g/, 4214.2345\n"); - snprintf(holder, sizeof holder, "/%.4g/\n", 4214.2345); - asprintf(&h, "/%.4g/\n", 4214.2345); - printf("/%.4g/\n", 4214.2345); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'ld %%'ld/, 12345, 1234567\n"); - snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 12345, 1234567); - asprintf(&h, "/%'ld %'ld/\n", 12345, 1234567); - printf("/%'ld %'ld/\n", 12345, 1234567); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'ld %%'ld/, 336, 3336\n"); - snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 336, 3336); - asprintf(&h, "/%'ld %'ld/\n", 336, 3336); - printf("/%'ld %'ld/\n", 336, 3336); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'ld %%'ld/, -42786, -142786\n"); - snprintf(holder, sizeof holder, "/%'ld %'ld/\n", -42786, -142786); - asprintf(&h, "/%'ld %'ld/\n", -42786, -142786); - printf("/%'ld %'ld/\n", -42786, -142786); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'f %%'f/, 421.2345, 421234.56789\n"); - snprintf(holder, sizeof holder, "/%'f %'f/\n", 421.2345, 421234.56789); - asprintf(&h, "/%'f %'f/\n", 421.2345, 421234.56789); - printf("/%'f %'f/\n", 421.2345, 421234.56789); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'f %%'f/, -421.2345, -421234.56789\n"); - snprintf(holder, sizeof holder, "/%'f %'f/\n", -421.2345, -421234.56789); - asprintf(&h, "/%'f %'f/\n", -421.2345, -421234.56789); - printf("/%'f %'f/\n", -421.2345, -421234.56789); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'g %%'g/, 421.2345, 421234.56789\n"); - snprintf(holder, sizeof holder, "/%'g %'g/\n", 421.2345, 421234.56789); - asprintf(&h, "/%'g %'g/\n", 421.2345, 421234.56789); - printf("/%'g %'g/\n", 421.2345, 421234.56789); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'g %%'g/, -421.2345, -421234.56789\n"); - snprintf(holder, sizeof holder, "/%'g %'g/\n", -421.2345, -421234.56789); - asprintf(&h, "/%'g %'g/\n", -421.2345, -421234.56789); - printf("/%'g %'g/\n", -421.2345, -421234.56789); - printf("%s", holder); - printf("%s\n", h); -#endif - - printf("/%%'g/, 4213455.8392\n"); - snprintf(holder, sizeof holder, "/%'g/\n", 4213455.8392); - asprintf(&h, "/%'g/\n", 4213455.8392); - printf("/%'g/\n", 4213455.8392); - printf("%s", holder); - printf("%s\n", h); - - exit (0); -} -#endif diff --git a/lib/sh/snprintf.c~ b/lib/sh/snprintf.c~ deleted file mode 100644 index 7bbf2c359..000000000 --- a/lib/sh/snprintf.c~ +++ /dev/null @@ -1,2158 +0,0 @@ -/* - build a test version with - gcc -g -DDRIVER -I../.. -I../../include -o test-snprintf snprintf.c fmtu*long.o -*/ - -/* - Unix snprintf implementation. - derived from inetutils/libinetutils/snprintf.c Version 1.1 - - Copyright (C) 2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General License for more details. - - You should have received a copy of the GNU General License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Revision History: - - 1.1: - * added changes from Miles Bader - * corrected a bug with %f - * added support for %#g - * added more comments :-) - 1.0: - * supporting must ANSI syntaxic_sugars - 0.0: - * support %s %c %d - - THANKS(for the patches and ideas): - Miles Bader - Cyrille Rustom - Jacek Slabocewiz - Mike Parker(mouse) - -*/ - -/* - * Currently doesn't handle (and bash/readline doesn't use): - * * *M$ width, precision specifications - * * %N$ numbered argument conversions - * * inf, nan floating values imperfect (if isinf(), isnan() not in libc) - * * support for `F' is imperfect with ldfallback(), since underlying - * printf may not handle it -- should ideally have another autoconf test - */ - -#define FLOATING_POINT - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if defined(DEBUG) -# undef HAVE_SNPRINTF -# undef HAVE_ASPRINTF -#endif - -#if defined(DRIVER) && !defined(HAVE_CONFIG_H) -#define HAVE_LONG_LONG -#define HAVE_LONG_DOUBLE -#ifdef __linux__ -#define HAVE_PRINTF_A_FORMAT -#endif -#define HAVE_ISINF_IN_LIBC -#define HAVE_ISNAN_IN_LIBC -#define PREFER_STDARG -#define HAVE_STRINGIZE -#define HAVE_LIMITS_H -#define HAVE_STDDEF_H -#define HAVE_LOCALE_H -#define intmax_t long -#endif - -#if !defined (HAVE_SNPRINTF) || !defined (HAVE_ASPRINTF) - -#include - -#if defined(PREFER_STDARG) -# include -#else -# include -#endif - -#ifdef HAVE_LIMITS_H -# include -#endif -#include -#ifdef HAVE_STDDEF_H -# include -#endif -#include - -#ifdef HAVE_STDINT_H -# include -#endif - -#ifdef FLOATING_POINT -# include /* for manifest constants */ -# include /* for sprintf */ -#endif - -#include - -#ifdef HAVE_LOCALE_H -# include -#endif - -#include "stdc.h" -#include - -#ifndef DRIVER -# include "shell.h" -#else -# 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)); -extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int)); -#endif - -#ifndef FREE -# define FREE(x) if (x) free (x) -#endif - -/* 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)) - -/* conversion flags */ -#define PF_ALTFORM 0x00001 /* # */ -#define PF_HEXPREFIX 0x00002 /* 0[Xx] */ -#define PF_LADJUST 0x00004 /* - */ -#define PF_ZEROPAD 0x00008 /* 0 */ -#define PF_PLUS 0x00010 /* + */ -#define PF_SPACE 0x00020 /* ' ' */ -#define PF_THOUSANDS 0x00040 /* ' */ - -#define PF_DOT 0x00080 /* `.precision' */ -#define PF_STAR_P 0x00100 /* `*' after precision */ -#define PF_STAR_W 0x00200 /* `*' before or without precision */ - -/* length modifiers */ -#define PF_SIGNEDCHAR 0x00400 /* hh */ -#define PF_SHORTINT 0x00800 /* h */ -#define PF_LONGINT 0x01000 /* l */ -#define PF_LONGLONG 0x02000 /* ll */ -#define PF_LONGDBL 0x04000 /* L */ -#define PF_INTMAX_T 0x08000 /* j */ -#define PF_SIZE_T 0x10000 /* z */ -#define PF_PTRDIFF_T 0x20000 /* t */ - -#define PF_ALLOCBUF 0x40000 /* for asprintf, vasprintf */ - -#define PFM_SN 0x01 /* snprintf, vsnprintf */ -#define PFM_AS 0x02 /* asprintf, vasprintf */ - -#define ASBUFSIZE 128 - -#define x_digs "0123456789abcdef" -#define X_digs "0123456789ABCDEF" - -static char intbuf[INT_STRLEN_BOUND(unsigned long) + 1]; - -static int decpoint; -static int thoussep; -static char *grouping; - -/* - * For the FLOATING POINT FORMAT : - * the challenge was finding a way to - * manipulate the Real numbers without having - * to resort to mathematical function(it - * would require to link with -lm) and not - * going down to the bit pattern(not portable) - * - * so a number, a real is: - - real = integral + fraction - - integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0 - fraction = b(1)*10^-1 + b(2)*10^-2 + ... - - where: - 0 <= a(i) => 9 - 0 <= b(i) => 9 - - from then it was simple math - */ - -/* - * size of the buffer for the integral part - * and the fraction part - */ -#define MAX_INT 99 + 1 /* 1 for the null */ -#define MAX_FRACT 307 + 1 - -/* - * These functions use static buffers to store the results, - * and so are not reentrant - */ -#define itoa(n) fmtulong(n, 10, intbuf, sizeof(intbuf), 0); -#define dtoa(n, p, f) numtoa(n, 10, p, f) - -#define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;} - -#define GETARG(type) (va_arg(args, type)) - -/* Macros that do proper sign extension and handle length modifiers. Used - for the integer conversion specifiers. */ -#define GETSIGNED(p) \ - (((p)->flags & PF_LONGINT) \ - ? GETARG (long) \ - : (((p)->flags & PF_SHORTINT) ? (long)(short)GETARG (int) \ - : (long)GETARG (int))) - -#define GETUNSIGNED(p) \ - (((p)->flags & PF_LONGINT) \ - ? GETARG (unsigned long) \ - : (((p)->flags & PF_SHORTINT) ? (unsigned long)(unsigned short)GETARG (int) \ - : (unsigned long)GETARG (unsigned int))) - - -#ifdef HAVE_LONG_DOUBLE -#define GETLDOUBLE(p) GETARG (long double) -#endif -#define GETDOUBLE(p) GETARG (double) - -#define SET_SIZE_FLAGS(p, type) \ - if (sizeof (type) > sizeof (int)) \ - (p)->flags |= PF_LONGINT; \ - if (sizeof (type) > sizeof (long)) \ - (p)->flags |= PF_LONGLONG; - -/* this struct holds everything we need */ -struct DATA -{ - int length; - char *base; /* needed for [v]asprintf */ - char *holder; - int counter; - const char *pf; - -/* FLAGS */ - int flags; - int justify; - int width, precision; - char pad; -}; - -/* the floating point stuff */ -#ifdef FLOATING_POINT -static double pow_10 __P((int)); -static int log_10 __P((double)); -static double integral __P((double, double *)); -static char *numtoa __P((double, int, int, char **)); -#endif - -static void init_data __P((struct DATA *, char *, size_t, const char *, int)); -static void init_conv_flag __P((struct DATA *)); - -/* for the format */ -#ifdef FLOATING_POINT -static void floating __P((struct DATA *, double)); -static void exponent __P((struct DATA *, double)); -#endif -static void number __P((struct DATA *, unsigned long, int)); -#ifdef HAVE_LONG_LONG -static void lnumber __P((struct DATA *, unsigned long long, int)); -#endif -static void pointer __P((struct DATA *, unsigned long)); -static void strings __P((struct DATA *, char *)); - -#ifdef FLOATING_POINT -# define FALLBACK_FMTSIZE 32 -# define FALLBACK_BASE 4096 -# define LFALLBACK_BASE 5120 -# ifdef HAVE_LONG_DOUBLE -static void ldfallback __P((struct DATA *, const char *, const char *, long double)); -# endif -static void dfallback __P((struct DATA *, const char *, const char *, double)); -#endif - -static char *groupnum __P((char *)); - -#ifdef DRIVER -static void memory_error_and_abort (); -static void *xmalloc __P((size_t)); -static void *xrealloc __P((void *, size_t)); -static void xfree __P((void *)); -#else -# include -#endif - -/* those are defines specific to snprintf to hopefully - * make the code clearer :-) - */ -#define RIGHT 1 -#define LEFT 0 -#define NOT_FOUND -1 -#define FOUND 1 -#define MAX_FIELD 15 - -/* round off to the precision */ -#define ROUND(d, p) \ - (d < 0.) ? \ - d - pow_10(-(p)->precision) * 0.5 : \ - d + pow_10(-(p)->precision) * 0.5 - -/* set default precision */ -#define DEF_PREC(p) \ - if ((p)->precision == NOT_FOUND) \ - (p)->precision = 6 - -/* put a char. increment the number of chars written even if we've exceeded - the vsnprintf/snprintf buffer size (for the return value) */ -#define PUT_CHAR(c, p) \ - do \ - { \ - if (((p)->flags & PF_ALLOCBUF) && ((p)->counter >= (p)->length - 1)) \ - { \ - (p)->length += ASBUFSIZE; \ - (p)->base = (char *)xrealloc((p)->base, (p)->length); \ - (p)->holder = (p)->base + (p)->counter; /* in case reallocated */ \ - } \ - if ((p)->counter < (p)->length) \ - *(p)->holder++ = (c); \ - (p)->counter++; \ - } \ - while (0) - -/* Output a string. P->WIDTH has already been adjusted for padding. */ -#define PUT_STRING(string, len, p) \ - do \ - { \ - PAD_RIGHT (p); \ - while ((len)-- > 0) \ - { \ - PUT_CHAR (*(string), (p)); \ - (string)++; \ - } \ - PAD_LEFT (p); \ - } \ - while (0) - -#define PUT_PLUS(d, p, zero) \ - if ((d) > zero && (p)->justify == RIGHT) \ - PUT_CHAR('+', p) - -#define PUT_SPACE(d, p, zero) \ - if (((p)->flags & PF_SPACE) && (d) > zero) \ - PUT_CHAR(' ', p) - -/* pad right */ -#define PAD_RIGHT(p) \ - if ((p)->width > 0 && (p)->justify != LEFT) \ - for (; (p)->width > 0; (p)->width--) \ - PUT_CHAR((p)->pad, p) - -/* pad left */ -#define PAD_LEFT(p) \ - if ((p)->width > 0 && (p)->justify == LEFT) \ - for (; (p)->width > 0; (p)->width--) \ - PUT_CHAR((p)->pad, p) - -/* pad with zeros from decimal precision */ -#define PAD_ZERO(p) \ - if ((p)->precision > 0) \ - for (; (p)->precision > 0; (p)->precision--) \ - PUT_CHAR('0', p) - -/* if width and prec. in the args */ -#define STAR_ARGS(p) \ - do { \ - if ((p)->flags & PF_STAR_W) \ - { \ - (p)->width = GETARG (int); \ - if ((p)->width < 0) \ - { \ - (p)->flags |= PF_LADJUST; \ - (p)->justify = LEFT; \ - (p)->width = -(p)->width; \ - } \ - } \ - if ((p)->flags & PF_STAR_P) \ - { \ - (p)->precision = GETARG (int); \ - if ((p)->precision < 0) \ - { \ - (p)->flags &= ~PF_STAR_P; \ - (p)->precision = NOT_FOUND; \ - } \ - } \ - } while (0) - -#if defined (HAVE_LOCALE_H) && defined (HAVE_LOCALECONV) -# define GETLOCALEDATA(d, t, g) \ - do \ - { \ - struct lconv *lv; \ - if ((d) == 0) { \ - (d) = '.'; (t) = -1; (g) = 0; /* defaults */ \ - lv = localeconv(); \ - if (lv) \ - { \ - if (lv->decimal_point && lv->decimal_point[0]) \ - (d) = lv->decimal_point[0]; \ - if (lv->thousands_sep && lv->thousands_sep[0]) \ - (t) = lv->thousands_sep[0]; \ - (g) = lv->grouping ? lv->grouping : ""; \ - if (*(g) == '\0' || *(g) == CHAR_MAX || (t) == -1) (g) = 0; \ - } \ - } \ - } \ - while (0); -#else -# define GETLOCALEDATA(d, t, g) \ - ( (d) = '.', (t) = ',', g = "\003" ) -#endif - -#ifdef FLOATING_POINT -/* - * Find the nth power of 10 - */ -static double -pow_10(n) - int n; -{ - double P; - - /* handle common cases with fast switch statement. */ - switch (n) - { - case -3: return .001; - case -2: return .01; - case -1: return .1; - case 0: return 1.; - case 1: return 10.; - case 2: return 100.; - case 3: return 1000.; - } - - if (n < 0) - { - P = .0001; - for (n += 4; n < 0; n++) - P /= 10.; - } - else - { - P = 10000.; - for (n -= 4; n > 0; n--) - P *= 10.; - } - - return P; -} - -/* - * Find the integral part of the log in base 10 - * Note: this not a real log10() - I just need and approximation(integerpart) of x in: - 10^x ~= r - * log_10(200) = 2; - * log_10(250) = 2; - * - * NOTE: do not call this with r == 0 -- an infinite loop results. - */ -static int -log_10(r) - double r; -{ - int i = 0; - double result = 1.; - - if (r < 0.) - r = -r; - - if (r < 1.) - { - while (result >= r) - { - result /= 10.; - i++; - } - return (-i); - } - else - { - while (result <= r) - { - result *= 10.; - i++; - } - return (i - 1); - } -} - -/* - * This function return the fraction part of a double - * and set in ip the integral part. - * In many ways it resemble the modf() found on most Un*x - */ -static double -integral(real, ip) - double real; - double *ip; -{ - int j; - double i, s, p; - double real_integral = 0.; - - /* take care of the obvious */ - /* equal to zero ? */ - if (real == 0.) - { - *ip = 0.; - return (0.); - } - - /* negative number ? */ - if (real < 0.) - real = -real; - - /* a fraction ? */ - if ( real < 1.) - { - *ip = 0.; - return real; - } - - /* the real work :-) */ - for (j = log_10(real); j >= 0; j--) - { - p = pow_10(j); - s = (real - real_integral)/p; - i = 0.; - while (i + 1. <= s) - i++; - real_integral += i*p; - } - *ip = real_integral; - return (real - real_integral); -} - -#define PRECISION 1.e-6 -/* - * return an ascii representation of the integral part of the number - * and set fract to be an ascii representation of the fraction part - * the container for the fraction and the integral part or staticly - * declare with fix size - */ -static char * -numtoa(number, base, precision, fract) - double number; - int base, precision; - char **fract; -{ - register int i, j; - double ip, fp; /* integer and fraction part */ - double fraction; - int digits = MAX_INT - 1; - static char integral_part[MAX_INT]; - static char fraction_part[MAX_FRACT]; - double sign; - int ch; - - /* taking care of the obvious case: 0.0 */ - if (number == 0.) - { - integral_part[0] = '0'; - integral_part[1] = '\0'; - /* The fractional part has to take the precision into account */ - for (ch = 0; ch < precision-1; ch++) - fraction_part[ch] = '0'; - fraction_part[ch] = '0'; - fraction_part[ch+1] = '\0'; - if (fract) - *fract = fraction_part; - return integral_part; - } - - /* for negative numbers */ - if ((sign = number) < 0.) - { - number = -number; - digits--; /* sign consume one digit */ - } - - fraction = integral(number, &ip); - number = ip; - - /* do the integral part */ - if (ip == 0.) - { - integral_part[0] = '0'; - i = 1; - } - else - { - for ( i = 0; i < digits && number != 0.; ++i) - { - number /= base; - fp = integral(number, &ip); - ch = (int)((fp + PRECISION)*base); /* force to round */ - integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10; - if (! ISXDIGIT((unsigned char)integral_part[i])) - break; /* bail out overflow !! */ - number = ip; - } - } - - /* Oh No !! out of bound, ho well fill it up ! */ - if (number != 0.) - for (i = 0; i < digits; ++i) - integral_part[i] = '9'; - - /* put the sign ? */ - if (sign < 0.) - integral_part[i++] = '-'; - - integral_part[i] = '\0'; - - /* reverse every thing */ - for ( i--, j = 0; j < i; j++, i--) - SWAP_INT(integral_part[i], integral_part[j]); - - /* the fractional part */ - for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision--) - { - fraction_part[i] = (int)((fp + PRECISION)*10. + '0'); - if (! DIGIT(fraction_part[i])) /* underflow ? */ - break; - fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.); - } - fraction_part[i] = '\0'; - - if (fract != (char **)0) - *fract = fraction_part; - - return integral_part; -} -#endif - -/* for %d and friends, it puts in holder - * the representation with the right padding - */ -static void -number(p, d, base) - struct DATA *p; - unsigned long d; - int base; -{ - char *tmp, *t; - long sd; - int flags; - - /* An explicit precision turns off the zero-padding flag. */ - if ((p->flags & PF_ZEROPAD) && p->precision >= 0 && (p->flags & PF_DOT)) - p->flags &= ~PF_ZEROPAD; - - sd = d; /* signed for ' ' padding in base 10 */ - flags = (*p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0; - if (*p->pf == 'X') - flags |= FL_HEXUPPER; - - tmp = fmtulong (d, base, intbuf, sizeof(intbuf), flags); - t = 0; - if ((p->flags & PF_THOUSANDS)) - { - GETLOCALEDATA(decpoint, thoussep, grouping); - if (grouping && (t = groupnum (tmp))) - tmp = t; - } - - p->width -= strlen(tmp); - PAD_RIGHT(p); - - if ((p->flags & PF_DOT) && p->precision > 0) - { - p->precision -= strlen(tmp); - PAD_ZERO(p); - } - - switch (base) - { - case 10: - PUT_PLUS(sd, p, 0); - PUT_SPACE(sd, p, 0); - break; - case 8: - if (p->flags & PF_ALTFORM) - PUT_CHAR('0', p); - break; - case 16: - if (p->flags & PF_ALTFORM) - { - PUT_CHAR('0', p); - PUT_CHAR(*p->pf, p); - } - break; - } - - while (*tmp) - { - PUT_CHAR(*tmp, p); - tmp++; - } - - PAD_LEFT(p); - FREE (t); -} - -#ifdef HAVE_LONG_LONG -/* - * identical to number() but works for `long long' - */ -static void -lnumber(p, d, base) - struct DATA *p; - unsigned long long d; - int base; -{ - char *tmp, *t; - long long sd; - int flags; - - /* An explicit precision turns off the zero-padding flag. */ - if ((p->flags & PF_ZEROPAD) && p->precision >= 0 && (p->flags & PF_DOT)) - p->flags &= ~PF_ZEROPAD; - - sd = d; /* signed for ' ' padding in base 10 */ - flags = (*p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0; - if (*p->pf == 'X') - flags |= FL_HEXUPPER; - - tmp = fmtullong (d, base, intbuf, sizeof(intbuf), flags); - t = 0; - if ((p->flags & PF_THOUSANDS)) - { - GETLOCALEDATA(decpoint, thoussep, grouping); - if (grouping && (t = groupnum (tmp))) - tmp = t; - } - - p->width -= strlen(tmp); - PAD_RIGHT(p); - - if ((p->flags & PF_DOT) && p->precision > 0) - { - p->precision -= strlen(tmp); - PAD_ZERO(p); - } - - switch (base) - { - case 10: - PUT_PLUS(sd, p, 0); - PUT_SPACE(sd, p, 0); - break; - case 8: - if (p->flags & PF_ALTFORM) - PUT_CHAR('0', p); - break; - case 16: - if (p->flags & PF_ALTFORM) - { - PUT_CHAR('0', p); - PUT_CHAR(*p->pf, p); - } - break; - } - - while (*tmp) - { - PUT_CHAR(*tmp, p); - tmp++; - } - - PAD_LEFT(p); - FREE (t); -} -#endif - -static void -pointer(p, d) - struct DATA *p; - unsigned long d; -{ - char *tmp; - - tmp = fmtulong(d, 16, intbuf, sizeof(intbuf), 0); - p->width -= strlen(tmp); - PAD_RIGHT(p); - - /* prefix '0x' for pointers */ - PUT_CHAR('0', p); - PUT_CHAR('x', p); - - while (*tmp) - { - PUT_CHAR(*tmp, p); - tmp++; - } - - PAD_LEFT(p); -} - -/* %s strings */ -static void -strings(p, tmp) - struct DATA *p; - char *tmp; -{ - size_t len; - - len = strlen(tmp); - if (p->precision != NOT_FOUND) /* the smallest number */ - len = (len < p->precision ? len : p->precision); - p->width -= len; - - PUT_STRING (tmp, len, p); -} - -#if HANDLE_MULTIBYTE -/* %ls wide-character strings */ -static void -wstrings(p, tmp) - struct DATA *p; - wchar_t *tmp; -{ - size_t len; - mbstate_t mbs; - char *os; - const wchar_t *ws; - - memset (&mbs, '\0', sizeof (mbstate_t)); - ws = (const wchar_t *)tmp; - - os = (char *)NULL; - if (p->precision != NOT_FOUND) - { - os = (char *)xmalloc (p->precision + 1); - len = wcsrtombs (os, &ws, p->precision, &mbs); - } - else - { - len = wcsrtombs (NULL, &ws, 0, &mbs); - if (len != (size_t)-1) - { - memset (&mbs, '\0', sizeof (mbstate_t)); - os = (char *)xmalloc (len + 1); - (void)wcsrtombs (os, &ws, len + 1, &mbs); - } - } - if (len == (size_t)-1) - { - /* invalid multibyte sequence; bail now. */ - FREE (os); - return; - } - - p->width -= len; - PUT_STRING (os, len, p); - free (os); -} - -static void -wchars (p, wc) - struct DATA *p; - wint_t wc; -{ - char *lbuf, *l; - mbstate_t mbs; - size_t len; - - lbuf = (char *)malloc (MB_CUR_MAX+1); - if (lbuf == 0) - return; - memset (&mbs, '\0', sizeof (mbstate_t)); - len = wcrtomb (lbuf, wc, &mbs); - if (len == (size_t)-1) - /* conversion failed; bail now. */ - return; - p->width -= len; - l = lbuf; - PUT_STRING (l, len, p); - free (lbuf); -} -#endif /* HANDLE_MULTIBYTE */ - -#ifdef FLOATING_POINT - -#ifndef HAVE_ISINF_IN_LIBC -/* Half-assed versions, since we don't want to link with libm. */ -static int -isinf(d) - double d; -{ -#ifdef DBL_MAX - if (d < DBL_MIN) - return -1; - else if (d > DBL_MAX) - return 1; - else -#endif - return 0; -} -#endif - -#ifndef HAVE_ISNAN_IN_LIBC -static int -isnan(d) - double d; -{ - return 0; -} -#endif - -/* Check for [+-]infinity and NaN. If MODE == 1, we check for Infinity, else - (mode == 2) we check for NaN. This does the necessary printing. Returns - 1 if Inf or Nan, 0 if not. */ -static int -chkinfnan(p, d, mode) - struct DATA *p; - double d; - int mode; /* == 1 for inf, == 2 for nan */ -{ - int i; - char *tmp; - char *big, *small; - - i = (mode == 1) ? isinf(d) : isnan(d); - if (i == 0) - return 0; - big = (mode == 1) ? "INF" : "NAN"; - small = (mode == 1) ? "inf" : "nan"; - - tmp = (*p->pf == 'F' || *p->pf == 'G' || *p->pf == 'E') ? big : small; - - if (i < 0) - PUT_CHAR('-', p); - - while (*tmp) - { - PUT_CHAR (*tmp, p); - tmp++; - } - - return 1; -} - -/* %f %F %g %G floating point representation */ -static void -floating(p, d) - struct DATA *p; - double d; -{ - char *tmp, *tmp2, *t; - int i; - - if (d != 0 && (chkinfnan(p, d, 1) || chkinfnan(p, d, 2))) - return; /* already printed nan or inf */ - - GETLOCALEDATA(decpoint, thoussep, grouping); - DEF_PREC(p); - d = ROUND(d, p); - tmp = dtoa(d, p->precision, &tmp2); - t = 0; - if ((p->flags & PF_THOUSANDS) && grouping && (t = groupnum (tmp))) - tmp = t; - - if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0) - { - /* smash the trailing zeros unless altform */ - for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--) - tmp2[i] = '\0'; - if (tmp2[0] == '\0') - p->precision = 0; - } - - /* calculate the padding. 1 for the dot */ - p->width = p->width - - ((d > 0. && p->justify == RIGHT) ? 1:0) - - ((p->flags & PF_SPACE) ? 1:0) - - strlen(tmp) - p->precision - - ((p->precision != 0 || (p->flags & PF_ALTFORM)) ? 1 : 0); /* radix char */ - PAD_RIGHT(p); - PUT_PLUS(d, p, 0.); - PUT_SPACE(d, p, 0.); - - while (*tmp) - { - PUT_CHAR(*tmp, p); /* the integral */ - tmp++; - } - FREE (t); - - if (p->precision != 0 || (p->flags & PF_ALTFORM)) - PUT_CHAR(decpoint, p); /* put the '.' */ - - for (; *tmp2; tmp2++) - PUT_CHAR(*tmp2, p); /* the fraction */ - - PAD_LEFT(p); -} - -/* %e %E %g %G exponent representation */ -static void -exponent(p, d) - struct DATA *p; - double d; -{ - char *tmp, *tmp2; - int j, i; - - if (d != 0 && (chkinfnan(p, d, 1) || chkinfnan(p, d, 2))) - return; /* already printed nan or inf */ - - GETLOCALEDATA(decpoint, thoussep, grouping); - DEF_PREC(p); - if (d == 0.) - j = 0; - else - { - j = log_10(d); - d = d / pow_10(j); /* get the Mantissa */ - d = ROUND(d, p); - } - tmp = dtoa(d, p->precision, &tmp2); - - /* 1 for unit, 1 for the '.', 1 for 'e|E', - * 1 for '+|-', 2 for 'exp' */ - /* calculate how much padding need */ - p->width = p->width - - ((d > 0. && p->justify == RIGHT) ? 1:0) - - ((p->flags & PF_SPACE) ? 1:0) - p->precision - 6; - - PAD_RIGHT(p); - PUT_PLUS(d, p, 0.); - PUT_SPACE(d, p, 0.); - - while (*tmp) - { - PUT_CHAR(*tmp, p); - tmp++; - } - - if (p->precision != 0 || (p->flags & PF_ALTFORM)) - PUT_CHAR(decpoint, p); /* the '.' */ - - if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0) - /* smash the trailing zeros unless altform */ - for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--) - tmp2[i] = '\0'; - - for (; *tmp2; tmp2++) - PUT_CHAR(*tmp2, p); /* the fraction */ - - /* the exponent put the 'e|E' */ - if (*p->pf == 'g' || *p->pf == 'e') - PUT_CHAR('e', p); - else - PUT_CHAR('E', p); - - /* the sign of the exp */ - if (j >= 0) - PUT_CHAR('+', p); - else - { - PUT_CHAR('-', p); - j = -j; - } - - tmp = itoa(j); - /* pad out to at least two spaces. pad with `0' if the exponent is a - single digit. */ - if (j <= 9) - PUT_CHAR('0', p); - - /* the exponent */ - while (*tmp) - { - PUT_CHAR(*tmp, p); - tmp++; - } - - PAD_LEFT(p); -} -#endif - -/* Return a new string with the digits in S grouped according to the locale's - grouping info and thousands separator. If no grouping should be performed, - this returns NULL; the caller needs to check for it. */ -static char * -groupnum (s) - char *s; -{ - char *se, *ret, *re, *g; - int len, slen; - - if (grouping == 0 || *grouping <= 0 || *grouping == CHAR_MAX) - return ((char *)NULL); - - /* find min grouping to size returned string */ - for (len = *grouping, g = grouping; *g; g++) - if (*g > 0 && *g < len) - len = *g; - - slen = strlen (s); - len = slen / len + 1; - ret = (char *)xmalloc (slen + len + 1); - re = ret + slen + len; - *re = '\0'; - - g = grouping; - se = s + slen; - len = *g; - - while (se > s) - { - *--re = *--se; - - /* handle `-' inserted by numtoa() and the fmtu* family here. */ - if (se > s && se[-1] == '-') - continue; - - /* begin new group. */ - if (--len == 0 && se > s) - { - *--re = thoussep; - len = *++g; /* was g++, but that uses first char twice (glibc bug, too) */ - if (*g == '\0') - len = *--g; /* use previous grouping */ - else if (*g == CHAR_MAX) - { - do - *--re = *--se; - while (se > s); - break; - } - } - } - - if (re > ret) -#ifdef HAVE_MEMMOVE - memmove (ret, re, strlen (re) + 1); -#else - strcpy (ret, re); -#endif - - return ret; -} - -/* initialize the conversion specifiers */ -static void -init_conv_flag (p) - struct DATA *p; -{ - p->flags &= PF_ALLOCBUF; /* preserve PF_ALLOCBUF flag */ - p->precision = p->width = NOT_FOUND; - p->justify = NOT_FOUND; - p->pad = ' '; -} - -static void -init_data (p, string, length, format, mode) - struct DATA *p; - char *string; - size_t length; - const char *format; - int mode; -{ - p->length = length - 1; /* leave room for '\0' */ - p->holder = p->base = string; - p->pf = format; - p->counter = 0; - p->flags = (mode == PFM_AS) ? PF_ALLOCBUF : 0; -} - -static int -#if defined (__STDC__) -vsnprintf_internal(struct DATA *data, char *string, size_t length, const char *format, va_list args) -#else -vsnprintf_internal(data, string, length, format, args) - struct DATA *data; - char *string; - size_t length; - const char *format; - va_list args; -#endif -{ - double d; /* temporary holder */ -#ifdef HAVE_LONG_DOUBLE - long double ld; /* for later */ -#endif - unsigned long ul; -#ifdef HAVE_LONG_LONG - unsigned long long ull; -#endif - int state, i, c, n; - char *s; -#if HANDLE_MULTIBYTE - wchar_t *ws; - wint_t wc; -#endif - const char *convstart; - int negprec; - - /* Sanity check, the string length must be >= 0. C99 actually says that - LENGTH can be zero here, in the case of snprintf/vsnprintf (it's never - 0 in the case of asprintf/vasprintf), and the return value is the number - of characters that would have been written. */ - if (length < 0) - return -1; - - if (format == 0) - return 0; - - /* Reset these for each call because the locale might have changed. */ - decpoint = thoussep = 0; - grouping = 0; - - negprec = 0; - for (; c = *(data->pf); data->pf++) - { - if (c != '%') - { - PUT_CHAR (c, data); - continue; - } - - convstart = data->pf; - init_conv_flag (data); /* initialise format flags */ - - state = 1; - for (state = 1; state && *data->pf; ) - { - c = *(++data->pf); - /* fmtend = data->pf */ -#if defined (FLOATING_POINT) && defined (HAVE_LONG_DOUBLE) - if (data->flags & PF_LONGDBL) - { - switch (c) - { - case 'f': case 'F': - case 'e': case 'E': - case 'g': case 'G': -# ifdef HAVE_PRINTF_A_FORMAT - case 'a': case 'A': -# endif - STAR_ARGS (data); - ld = GETLDOUBLE (data); - ldfallback (data, convstart, data->pf, ld); - goto conv_break; - } - } -#endif /* FLOATING_POINT && HAVE_LONG_DOUBLE */ - - switch (c) - { - /* Parse format flags */ - case '\0': /* a NULL here ? ? bail out */ - *data->holder = '\0'; - return data->counter; - break; - case '#': - data->flags |= PF_ALTFORM; - continue; - case '0': - data->flags |= PF_ZEROPAD; - data->pad = '0'; - continue; - case '*': - if (data->flags & PF_DOT) - data->flags |= PF_STAR_P; - else - data->flags |= PF_STAR_W; - continue; - case '-': - if ((data->flags & PF_DOT) == 0) - { - data->flags |= PF_LADJUST; - data->justify = LEFT; - } - else - negprec = 1; - continue; - case ' ': - if ((data->flags & PF_PLUS) == 0) - data->flags |= PF_SPACE; - continue; - case '+': - if ((data->flags & PF_DOT) == 0) - { - data->flags |= PF_PLUS; - data->justify = RIGHT; - } - continue; - case '\'': - data->flags |= PF_THOUSANDS; - continue; - - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - n = 0; - do - { - n = n * 10 + TODIGIT(c); - c = *(++data->pf); - } - while (DIGIT(c)); - data->pf--; /* went too far */ - if (n < 0) - n = 0; - if (data->flags & PF_DOT) - data->precision = negprec ? NOT_FOUND : n; - else - data->width = n; - continue; - - /* optional precision */ - case '.': - data->flags |= PF_DOT; - data->precision = 0; - continue; - - /* length modifiers */ - case 'h': - data->flags |= (data->flags & PF_SHORTINT) ? PF_SIGNEDCHAR : PF_SHORTINT; - continue; - case 'l': - data->flags |= (data->flags & PF_LONGINT) ? PF_LONGLONG : PF_LONGINT; - continue; - case 'L': - data->flags |= PF_LONGDBL; - continue; - case 'q': - data->flags |= PF_LONGLONG; - continue; - case 'j': - data->flags |= PF_INTMAX_T; - SET_SIZE_FLAGS(data, intmax_t); - continue; - case 'z': - data->flags |= PF_SIZE_T; - SET_SIZE_FLAGS(data, size_t); - continue; - case 't': - data->flags |= PF_PTRDIFF_T; - SET_SIZE_FLAGS(data, ptrdiff_t); - continue; - - /* Conversion specifiers */ -#ifdef FLOATING_POINT - case 'f': /* float, double */ - case 'F': - STAR_ARGS(data); - d = GETDOUBLE(data); - floating(data, d); -conv_break: - state = 0; - break; - case 'g': - case 'G': - STAR_ARGS(data); - DEF_PREC(data); - d = GETDOUBLE(data); - i = (d != 0.) ? log_10(d) : -1; - /* - * for '%g|%G' ANSI: use f if exponent - * is in the range or [-4,p] exclusively - * else use %e|%E - */ - if (-4 < i && i < data->precision) - { - /* reset precision */ - data->precision -= i + 1; - floating(data, d); - } - else - { - /* reduce precision by 1 because of leading digit before - decimal point in e format. */ - data->precision--; - exponent(data, d); - } - state = 0; - break; - case 'e': - case 'E': /* Exponent double */ - STAR_ARGS(data); - d = GETDOUBLE(data); - exponent(data, d); - state = 0; - break; -# ifdef HAVE_PRINTF_A_FORMAT - case 'a': - case 'A': - STAR_ARGS(data); - d = GETDOUBLE(data); - dfallback(data, convstart, data->pf, d); - state = 0; - break; -# endif /* HAVE_PRINTF_A_FORMAT */ -#endif /* FLOATING_POINT */ - case 'U': - data->flags |= PF_LONGINT; - /* FALLTHROUGH */ - case 'u': - STAR_ARGS(data); -#ifdef HAVE_LONG_LONG - if (data->flags & PF_LONGLONG) - { - ull = GETARG (unsigned long long); - lnumber(data, ull, 10); - } - else -#endif - { - ul = GETUNSIGNED(data); - number(data, ul, 10); - } - state = 0; - break; - case 'D': - data->flags |= PF_LONGINT; - /* FALLTHROUGH */ - case 'd': /* decimal */ - case 'i': - STAR_ARGS(data); -#ifdef HAVE_LONG_LONG - if (data->flags & PF_LONGLONG) - { - ull = GETARG (long long); - lnumber(data, ull, 10); - } - else -#endif - { - ul = GETSIGNED(data); - number(data, ul, 10); - } - state = 0; - break; - case 'o': /* octal */ - STAR_ARGS(data); -#ifdef HAVE_LONG_LONG - if (data->flags & PF_LONGLONG) - { - ull = GETARG (unsigned long long); - lnumber(data, ull, 8); - } - else -#endif - { - ul = GETUNSIGNED(data); - number(data, ul, 8); - } - state = 0; - break; - case 'x': - case 'X': /* hexadecimal */ - STAR_ARGS(data); -#ifdef HAVE_LONG_LONG - if (data->flags & PF_LONGLONG) - { - ull = GETARG (unsigned long long); - lnumber(data, ull, 16); - } - else -#endif - { - ul = GETUNSIGNED(data); - number(data, ul, 16); - } - state = 0; - break; - case 'p': - STAR_ARGS(data); - ul = (unsigned long)GETARG (void *); - pointer(data, ul); - state = 0; - break; -#if HANDLE_MULTIBYTE - case 'C': - data->flags |= PF_LONGINT; - /* FALLTHROUGH */ -#endif - case 'c': /* character */ - STAR_ARGS(data); -#if HANDLE_MULTIBYTE - if (data->flags & PF_LONGINT) - { - wc = GETARG (wint_t); - wchars (data, wc); - } - else -#endif - { - ul = GETARG (int); - PUT_CHAR(ul, data); - } - state = 0; - break; -#if HANDLE_MULTIBYTE - case 'S': - data->flags |= PF_LONGINT; - /* FALLTHROUGH */ -#endif - case 's': /* string */ - STAR_ARGS(data); -#if HANDLE_MULTIBYTE - if (data->flags & PF_LONGINT) - { - ws = GETARG (wchar_t *); - wstrings (data, ws); - } - else -#endif - { - s = GETARG (char *); - strings(data, s); - } - state = 0; - break; - case 'n': -#ifdef HAVE_LONG_LONG - if (data->flags & PF_LONGLONG) - *(GETARG (long long *)) = data->counter; - else -#endif - if (data->flags & PF_LONGINT) - *(GETARG (long *)) = data->counter; - else if (data->flags & PF_SHORTINT) - *(GETARG (short *)) = data->counter; - else - *(GETARG (int *)) = data->counter; - state = 0; - break; - case '%': /* nothing just % */ - PUT_CHAR('%', data); - state = 0; - break; - default: - /* is this an error ? maybe bail out */ - state = 0; - break; - } /* end switch */ - } /* end of `%' for loop */ - } /* end of format string for loop */ - - if (data->length >= 0) - *data->holder = '\0'; /* the end ye ! */ - - return data->counter; -} - -#if defined (FLOATING_POINT) && defined (HAVE_LONG_DOUBLE) -/* - * Printing floating point numbers accurately is an art. I'm not good - * at it. Fall back to sprintf for long double formats. - */ -static void -ldfallback (data, fs, fe, ld) - struct DATA *data; - const char *fs, *fe; - long double ld; -{ - register char *x; - char fmtbuf[FALLBACK_FMTSIZE], *obuf; - int fl; - - fl = LFALLBACK_BASE + (data->precision < 6 ? 6 : data->precision) + 2; - obuf = (char *)xmalloc (fl); - fl = fe - fs + 1; - strncpy (fmtbuf, fs, fl); - fmtbuf[fl] = '\0'; - - if ((data->flags & PF_STAR_W) && (data->flags & PF_STAR_P)) - sprintf (obuf, fmtbuf, data->width, data->precision, ld); - else if (data->flags & PF_STAR_W) - sprintf (obuf, fmtbuf, data->width, ld); - else if (data->flags & PF_STAR_P) - sprintf (obuf, fmtbuf, data->precision, ld); - else - sprintf (obuf, fmtbuf, ld); - - for (x = obuf; *x; x++) - PUT_CHAR (*x, data); - xfree (obuf); -} -#endif /* FLOATING_POINT && HAVE_LONG_DOUBLE */ - -#ifdef FLOATING_POINT -/* Used for %a, %A if the libc printf supports them. */ -static void -dfallback (data, fs, fe, d) - struct DATA *data; - const char *fs, *fe; - double d; -{ - register char *x; - char fmtbuf[FALLBACK_FMTSIZE], obuf[FALLBACK_BASE]; - int fl; - - fl = fe - fs + 1; - strncpy (fmtbuf, fs, fl); - fmtbuf[fl] = '\0'; - - if ((data->flags & PF_STAR_W) && (data->flags & PF_STAR_P)) - sprintf (obuf, fmtbuf, data->width, data->precision, d); - else if (data->flags & PF_STAR_W) - sprintf (obuf, fmtbuf, data->width, d); - else if (data->flags & PF_STAR_P) - sprintf (obuf, fmtbuf, data->precision, d); - else - sprintf (obuf, fmtbuf, d); - - for (x = obuf; *x; x++) - PUT_CHAR (*x, data); -} -#endif /* FLOATING_POINT */ - -#ifndef HAVE_SNPRINTF - -int -#if defined (__STDC__) -vsnprintf(char *string, size_t length, const char *format, va_list args) -#else -vsnprintf(string, length, format, args) - char *string; - size_t length; - const char *format; - va_list args; -#endif -{ - struct DATA data; - - if (string == 0 && length != 0) - return 0; - init_data (&data, string, length, format, PFM_SN); - return (vsnprintf_internal(&data, string, length, format, args)); -} - -int -#if defined(PREFER_STDARG) -snprintf(char *string, size_t length, const char * format, ...) -#else -snprintf(string, length, format, va_alist) - char *string; - size_t length; - const char *format; - va_dcl -#endif -{ - struct DATA data; - int rval; - va_list args; - - SH_VA_START(args, format); - - if (string == 0 && length != 0) - return 0; - init_data (&data, string, length, format, PFM_SN); - rval = vsnprintf_internal (&data, string, length, format, args); - - va_end(args); - - return rval; -} - -#endif /* HAVE_SNPRINTF */ - -#ifndef HAVE_ASPRINTF - -int -#if defined (__STDC__) -vasprintf(char **stringp, const char *format, va_list args) -#else -vasprintf(stringp, format, args) - char **stringp; - const char *format; - va_list args; -#endif -{ - struct DATA data; - char *string; - int r; - - string = (char *)xmalloc(ASBUFSIZE); - init_data (&data, string, ASBUFSIZE, format, PFM_AS); - r = vsnprintf_internal(&data, string, ASBUFSIZE, format, args); - *stringp = data.base; /* not string in case reallocated */ - return r; -} - -int -#if defined(PREFER_STDARG) -asprintf(char **stringp, const char * format, ...) -#else -asprintf(stringp, format, va_alist) - char **stringp; - const char *format; - va_dcl -#endif -{ - int rval; - va_list args; - - SH_VA_START(args, format); - - rval = vasprintf (stringp, format, args); - - va_end(args); - - return rval; -} - -#endif - -#endif - -#ifdef DRIVER - -static void -memory_error_and_abort () -{ - write (2, "out of virtual memory\n", 22); - abort (); -} - -static void * -xmalloc(bytes) - size_t bytes; -{ - void *ret; - - ret = malloc(bytes); - if (ret == 0) - memory_error_and_abort (); - return ret; -} - -static void * -xrealloc (pointer, bytes) - void *pointer; - size_t bytes; -{ - void *ret; - - ret = pointer ? realloc(pointer, bytes) : malloc(bytes); - if (ret == 0) - memory_error_and_abort (); - return ret; -} - -static void -xfree(x) - void *x; -{ - if (x) - free (x); -} - -/* set of small tests for snprintf() */ -main() -{ - char holder[100]; - char *h; - int i, si, ai; - -#ifdef HAVE_LOCALE_H - setlocale(LC_ALL, ""); -#endif - -#if 1 - si = snprintf((char *)NULL, 0, "abcde\n"); - printf("snprintf returns %d with NULL first argument and size of 0\n", si); - si = snprintf(holder, 0, "abcde\n"); - printf("snprintf returns %d with non-NULL first argument and size of 0\n", si); - si = snprintf((char *)NULL, 16, "abcde\n"); - printf("snprintf returns %d with NULL first argument and non-zero size\n", si); - -/* - printf("Suite of test for snprintf:\n"); - printf("a_format\n"); - printf("printf() format\n"); - printf("snprintf() format\n\n"); -*/ -/* Checking the field widths */ - - printf("/%%ld %%ld/, 336, 336\n"); - snprintf(holder, sizeof holder, "/%ld %ld/\n", 336, 336); - asprintf(&h, "/%ld %ld/\n", 336, 336); - printf("/%ld %ld/\n", 336, 336); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%d/, 336\n"); - snprintf(holder, sizeof holder, "/%d/\n", 336); - asprintf(&h, "/%d/\n", 336); - printf("/%d/\n", 336); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%2d/, 336\n"); - snprintf(holder, sizeof holder, "/%2d/\n", 336); - asprintf(&h, "/%2d/\n", 336); - printf("/%2d/\n", 336); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%10d/, 336\n"); - snprintf(holder, sizeof holder, "/%10d/\n", 336); - asprintf(&h, "/%10d/\n", 336); - printf("/%10d/\n", 336); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%-10d/, 336\n"); - snprintf(holder, sizeof holder, "/%-10d/\n", 336); - asprintf(&h, "/%-10d/\n", 336); - printf("/%-10d/\n", 336); - printf("%s", holder); - printf("%s\n", h); - - -/* floating points */ - - printf("/%%f/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%f/\n", 1234.56); - asprintf(&h, "/%f/\n", 1234.56); - printf("/%f/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%e/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%e/\n", 1234.56); - asprintf(&h, "/%e/\n", 1234.56); - printf("/%e/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%4.2f/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56); - asprintf(&h, "/%4.2f/\n", 1234.56); - printf("/%4.2f/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%3.1f/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56); - asprintf(&h, "/%3.1f/\n", 1234.56); - printf("/%3.1f/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%10.3f/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56); - asprintf(&h, "/%10.3f/\n", 1234.56); - printf("/%10.3f/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%10.3e/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56); - asprintf(&h, "/%10.3e/\n", 1234.56); - printf("/%10.3e/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%+4.2f/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56); - asprintf(&h, "/%+4.2f/\n", 1234.56); - printf("/%+4.2f/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%010.2f/, 1234.56\n"); - snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56); - asprintf(&h, "/%010.2f/\n", 1234.56); - printf("/%010.2f/\n", 1234.56); - printf("%s", holder); - printf("%s\n", h); - -#define BLURB "Outstanding acting !" -/* strings precisions */ - - printf("/%%2s/, \"%s\"\n", BLURB); - snprintf(holder, sizeof holder, "/%2s/\n", BLURB); - asprintf(&h, "/%2s/\n", BLURB); - printf("/%2s/\n", BLURB); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%22s/ %s\n", BLURB); - snprintf(holder, sizeof holder, "/%22s/\n", BLURB); - asprintf(&h, "/%22s/\n", BLURB); - printf("/%22s/\n", BLURB); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%22.5s/ %s\n", BLURB); - snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB); - asprintf(&h, "/%22.5s/\n", BLURB); - printf("/%22.5s/\n", BLURB); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%-22.5s/ %s\n", BLURB); - snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB); - asprintf(&h, "/%-22.5s/\n", BLURB); - printf("/%-22.5s/\n", BLURB); - printf("%s", holder); - printf("%s\n", h); - -/* see some flags */ - - printf("%%x %%X %%#x, 31, 31, 31\n"); - snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31); - asprintf(&h, "%x %X %#x\n", 31, 31, 31); - printf("%x %X %#x\n", 31, 31, 31); - printf("%s", holder); - printf("%s\n", h); - - printf("**%%d**%% d**%% d**, 42, 42, -42\n"); - snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42); - asprintf(&h, "**%d**% d**% d**\n", 42, 42, -42); - printf("**%d**% d**% d**\n", 42, 42, -42); - printf("%s", holder); - printf("%s\n", h); - -/* other flags */ - - printf("/%%g/, 31.4\n"); - snprintf(holder, sizeof holder, "/%g/\n", 31.4); - asprintf(&h, "/%g/\n", 31.4); - printf("/%g/\n", 31.4); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%.6g/, 31.4\n"); - snprintf(holder, sizeof holder, "/%.6g/\n", 31.4); - asprintf(&h, "/%.6g/\n", 31.4); - printf("/%.6g/\n", 31.4); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%.1G/, 31.4\n"); - snprintf(holder, sizeof holder, "/%.1G/\n", 31.4); - asprintf(&h, "/%.1G/\n", 31.4); - printf("/%.1G/\n", 31.4); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%.1G/, 3100000000.4\n"); - snprintf(holder, sizeof holder, "/%.1G/\n", 3100000000.4); - asprintf(&h, "/%.1G/\n", 3100000000.4); - printf("/%.1G/\n", 3100000000.4); - printf("%s", holder); - printf("%s\n", h); - - printf("abc%%n\n"); - printf("abc%n", &i); printf("%d\n", i); - snprintf(holder, sizeof holder, "abc%n", &i); - printf("%s", holder); printf("%d\n\n", i); - asprintf(&h, "abc%n", &i); - printf("%s", h); printf("%d\n\n", i); - - printf("%%*.*s --> 10.10\n"); - snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB); - asprintf(&h, "%*.*s\n", 10, 10, BLURB); - printf("%*.*s\n", 10, 10, BLURB); - printf("%s", holder); - printf("%s\n", h); - - printf("%%%%%%%%\n"); - snprintf(holder, sizeof holder, "%%%%\n"); - asprintf(&h, "%%%%\n"); - printf("%%%%\n"); - printf("%s", holder); - printf("%s\n", h); - -#define BIG "Hello this is a too big string for the buffer" -/* printf("A buffer to small of 10, trying to put this:\n");*/ - printf("<%%>, %s\n", BIG); - i = snprintf(holder, 10, "%s\n", BIG); - i = asprintf(&h, "%s", BIG); - printf("<%s>\n", BIG); - printf("<%s>\n", holder); - printf("<%s>\n\n", h); - - printf ("<%%p> vsnprintf\n"); - i = snprintf(holder, 100, "%p", vsnprintf); - i = asprintf(&h, "%p", vsnprintf); - printf("<%p>\n", vsnprintf); - printf("<%s>\n", holder); - printf("<%s>\n\n", h); - - printf ("<%%lu> LONG_MAX+1\n"); - i = snprintf(holder, 100, "%lu", (unsigned long)(LONG_MAX)+1); - i = asprintf(&h, "%lu", (unsigned long)(LONG_MAX)+1); - printf("<%lu>\n", (unsigned long)(LONG_MAX)+1); - printf("<%s>\n", holder); - printf("<%s>\n\n", h); - -#ifdef HAVE_LONG_LONG - printf ("<%%llu> LLONG_MAX+1\n"); - i = snprintf(holder, 100, "%llu", (unsigned long long)(LLONG_MAX)+1); - i = asprintf(&h, "%llu", (unsigned long long)(LLONG_MAX)+1); - printf("<%llu>\n", (unsigned long long)(LLONG_MAX)+1); - printf("<%s>\n", holder); - printf("<%s>\n\n", h); -#endif - -#ifdef HAVE_LONG_DOUBLE - printf ("<%%6.2LE> 42.42\n"); - i = snprintf(holder, 100, "%6.2LE", (long double)42.42); - i = asprintf(&h, "%6.2LE", (long double)42.42); - printf ("<%6.2LE>\n", (long double)42.42); - printf ("<%s>\n", holder); - printf ("<%s>\n\n", h); -#endif - -#ifdef HAVE_PRINTF_A_FORMAT - printf ("<%%6.2A> 42.42\n"); - i = snprintf(holder, 100, "%6.2A", 42.42); - i = asprintf(&h, "%6.2A", 42.42); - printf ("<%6.2A>\n", 42.42); - printf ("<%s>\n", holder); - printf ("<%s>\n\n", h); - - printf ("<%%6.2LA> 42.42\n"); - i = snprintf(holder, 100, "%6.2LA", (long double)42.42); - i = asprintf(&h, "%6.2LA", (long double)42.42); - printf ("<%6.2LA>\n", (long double)42.42); - printf ("<%s>\n", holder); - printf ("<%s>\n\n", h); -#endif - - printf ("<%%.10240f> DBL_MAX\n"); - si = snprintf(holder, 100, "%.10240f", DBL_MAX); - ai = asprintf(&h, "%.10240f", DBL_MAX); - printf ("<%.10240f>\n", DBL_MAX); - printf ("<%d> <%s>\n", si, holder); - printf ("<%d> <%s>\n\n", ai, h); - - printf ("<%%.10240Lf> LDBL_MAX\n"); - si = snprintf(holder, 100, "%.10240Lf", (long double)LDBL_MAX); - ai = asprintf(&h, "%.10240Lf", (long double)LDBL_MAX); - printf ("<%.10240Lf>\n", (long double)LDBL_MAX); - printf ("<%d> <%s>\n", si, holder); - printf ("<%d> <%s>\n\n", ai, h); - - /* huh? */ - printf("/%%g/, 421.2345\n"); - snprintf(holder, sizeof holder, "/%g/\n", 421.2345); - asprintf(&h, "/%g/\n", 421.2345); - printf("/%g/\n", 421.2345); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%g/, 4214.2345\n"); - snprintf(holder, sizeof holder, "/%g/\n", 4214.2345); - asprintf(&h, "/%g/\n", 4214.2345); - printf("/%g/\n", 4214.2345); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%.5g/, 4214.2345\n"); - snprintf(holder, sizeof holder, "/%.5g/\n", 4214.2345); - asprintf(&h, "/%.5g/\n", 4214.2345); - printf("/%.5g/\n", 4214.2345); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%.4g/, 4214.2345\n"); - snprintf(holder, sizeof holder, "/%.4g/\n", 4214.2345); - asprintf(&h, "/%.4g/\n", 4214.2345); - printf("/%.4g/\n", 4214.2345); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'ld %%'ld/, 12345, 1234567\n"); - snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 12345, 1234567); - asprintf(&h, "/%'ld %'ld/\n", 12345, 1234567); - printf("/%'ld %'ld/\n", 12345, 1234567); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'ld %%'ld/, 336, 3336\n"); - snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 336, 3336); - asprintf(&h, "/%'ld %'ld/\n", 336, 3336); - printf("/%'ld %'ld/\n", 336, 3336); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'ld %%'ld/, -42786, -142786\n"); - snprintf(holder, sizeof holder, "/%'ld %'ld/\n", -42786, -142786); - asprintf(&h, "/%'ld %'ld/\n", -42786, -142786); - printf("/%'ld %'ld/\n", -42786, -142786); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'f %%'f/, 421.2345, 421234.56789\n"); - snprintf(holder, sizeof holder, "/%'f %'f/\n", 421.2345, 421234.56789); - asprintf(&h, "/%'f %'f/\n", 421.2345, 421234.56789); - printf("/%'f %'f/\n", 421.2345, 421234.56789); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'f %%'f/, -421.2345, -421234.56789\n"); - snprintf(holder, sizeof holder, "/%'f %'f/\n", -421.2345, -421234.56789); - asprintf(&h, "/%'f %'f/\n", -421.2345, -421234.56789); - printf("/%'f %'f/\n", -421.2345, -421234.56789); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'g %%'g/, 421.2345, 421234.56789\n"); - snprintf(holder, sizeof holder, "/%'g %'g/\n", 421.2345, 421234.56789); - asprintf(&h, "/%'g %'g/\n", 421.2345, 421234.56789); - printf("/%'g %'g/\n", 421.2345, 421234.56789); - printf("%s", holder); - printf("%s\n", h); - - printf("/%%'g %%'g/, -421.2345, -421234.56789\n"); - snprintf(holder, sizeof holder, "/%'g %'g/\n", -421.2345, -421234.56789); - asprintf(&h, "/%'g %'g/\n", -421.2345, -421234.56789); - printf("/%'g %'g/\n", -421.2345, -421234.56789); - printf("%s", holder); - printf("%s\n", h); -#endif - - printf("/%%'g/, 4213455.8392\n"); - snprintf(holder, sizeof holder, "/%'g/\n", 4213455.8392); - asprintf(&h, "/%'g/\n", 4213455.8392); - printf("/%'g/\n", 4213455.8392); - printf("%s", holder); - printf("%s\n", h); - - exit (0); -} -#endif diff --git a/lib/sh/zgetline.c.new b/lib/sh/zgetline.c.new deleted file mode 100644 index 7e9077e2b..000000000 --- a/lib/sh/zgetline.c.new +++ /dev/null @@ -1,146 +0,0 @@ -/* zgetline - read a line of input from a specified file descriptor and return - a pointer to a newly-allocated buffer containing the data. */ - -/* Copyright (C) 2008,2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include "xmalloc.h" - -#if !defined (errno) -extern int errno; -#endif - -extern ssize_t zread __P((int, char *, size_t)); -extern ssize_t zreadc __P((int, char *)); -extern ssize_t zreadintr __P((int, char *, size_t)); -extern ssize_t zreadcintr __P((int, char *)); - -typedef ssize_t breadfunc_t __P((int, char *, size_t)); -typedef ssize_t creadfunc_t __P((int, char *)); - -static ssize_t _internal_zgetline __P((int, char **, size_t *, int, breadfunc_t *, creadfunc_t *)); - -/* Initial memory allocation for automatic growing buffer in zreadlinec */ -#define GET_LINE_INITIAL_ALLOCATION 16 - -/* Derived from GNU libc's getline. - The behavior is almost the same as getline. See man getline. - The differences are - (1) using file descriptor instead of FILE *, - (2) the order of arguments; the file descriptor comes the first, and - (3) the addtion of thired argument, UNBUFFERED_READ; this argument - controls whether get_line uses buffering or not to get a byte data - from FD. get_line uses zreadc if UNBUFFERED_READ is zero; and - uses zread if UNBUFFERED_READ is non-zero. - - Returns number of bytes read or -1 on error. */ - -static ssize_t -_internal_zgetline (fd, lineptr, n, unbuffered_read, brfunc, crfunc) - int fd; - char **lineptr; - size_t *n; - int unbuffered_read; - breadfunc_t *brfunc; - creadfunc_t *crfunc; -{ - int nr, retval; - char *line, c; - - if (lineptr == 0 || n == 0 || (*lineptr == 0 && *n != 0)) - return -1; - - nr = 0; - line = *lineptr; - - while (1) - { - retval = unbuffered_read ? (*brfunc) (fd, &c, 1) : (*crfunc) (fd, &c); - - if (retval <= 0) - { - if (line) - line[nr] = '\0'; - break; - } - - if (nr + 2 >= *n) - { - size_t new_size; - - new_size = (*n == 0) ? GET_LINE_INITIAL_ALLOCATION : *n * 2; - line = xrealloc (*lineptr, new_size); - - if (line) - { - *lineptr = line; - *n = new_size; - } - else - { - if (*n > 0) - { - (*lineptr)[*n - 1] = '\0'; - nr = *n - 2; - } - break; - } - } - - line[nr] = c; - nr++; - - if (c == '\n') - { - line[nr] = '\0'; - break; - } - } - -itrace("zgetline: returning %d", nr-1); - return nr - 1; -} - -ssize_t -zgetline (fd, lineptr, n, unbuffered_read) - int fd; - char **lineptr; - size_t *n; - int unbuffered_read; -{ - return _internal_zgetline (fd, lineptr, n, unbuffered_read, zread, zreadc); -} - -ssize_t -zgetlineintr (fd, lineptr, n, unbuffered_read) - int fd; - char **lineptr; - size_t *n; - int unbuffered_read; -{ - return _internal_zgetline (fd, lineptr, n, unbuffered_read, zreadintr, zreadcintr); -} diff --git a/lib/sh/zgetline.c~ b/lib/sh/zgetline.c~ deleted file mode 100644 index f5604c50f..000000000 --- a/lib/sh/zgetline.c~ +++ /dev/null @@ -1,121 +0,0 @@ -/* zgetline - read a line of input from a specified file descriptor and return - a pointer to a newly-allocated buffer containing the data. */ - -/* Copyright (C) 2008,2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include "xmalloc.h" - -#if !defined (errno) -extern int errno; -#endif - -extern ssize_t zread __P((int, char *, size_t)); -extern ssize_t zreadc __P((int, char *)); -extern ssize_t zreadintr __P((int, char *, size_t)); -extern ssize_t zreadcintr __P((int, char *)); - -typedef ssize_t breadfunc_t __P((int, char *, size_t)); -typedef ssize_t creadfunc_t __P((int, char *)); - -/* Initial memory allocation for automatic growing buffer in zreadlinec */ -#define GET_LINE_INITIAL_ALLOCATION 16 - -/* Derived from GNU libc's getline. - The behavior is almost the same as getline. See man getline. - The differences are - (1) using file descriptor instead of FILE *, - (2) the order of arguments; the file descriptor comes the first, and - (3) the addtion of thired argument, UNBUFFERED_READ; this argument - controls whether get_line uses buffering or not to get a byte data - from FD. get_line uses zreadc if UNBUFFERED_READ is zero; and - uses zread if UNBUFFERED_READ is non-zero. - - Returns number of bytes read or -1 on error. */ - -ssize_t -zgetline (fd, lineptr, n, unbuffered_read) - int fd; - char **lineptr; - size_t *n; - int unbuffered_read; -{ - int nr, retval; - char *line, c; - - if (lineptr == 0 || n == 0 || (*lineptr == 0 && *n != 0)) - return -1; - - nr = 0; - line = *lineptr; - - while (1) - { - retval = unbuffered_read ? zread (fd, &c, 1) : zreadc(fd, &c); - - if (retval <= 0) - { - if (line) - line[nr] = '\0'; - break; - } - - if (nr + 2 >= *n) - { - size_t new_size; - - new_size = (*n == 0) ? GET_LINE_INITIAL_ALLOCATION : *n * 2; - line = xrealloc (*lineptr, new_size); - - if (line) - { - *lineptr = line; - *n = new_size; - } - else - { - if (*n > 0) - { - (*lineptr)[*n - 1] = '\0'; - nr = *n - 2; - } - break; - } - } - - line[nr] = c; - nr++; - - if (c == '\n') - { - line[nr] = '\0'; - break; - } - } - - return nr - 1; -} diff --git a/lib/termcap/termcap.c~ b/lib/termcap/termcap.c~ deleted file mode 100644 index a7e71c44f..000000000 --- a/lib/termcap/termcap.c~ +++ /dev/null @@ -1,815 +0,0 @@ -/* termcap.c - Work-alike for termcap, plus extra features. */ - -/* Copyright (C) 1985, 1986, 1993,1994, 1995, 1998, 2001,2003,2005,2006,2008Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -/* Emacs config.h may rename various library functions such as malloc. */ -#ifdef HAVE_CONFIG_H - -#include - -/* Get the O_* definitions for open et al. */ -#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif - -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_STDLIB_H -# include -#else -extern char *getenv (); -extern char *malloc (); -extern char *realloc (); -#endif - -#if defined (HAVE_STRING_H) -#include -#endif - -#if !defined (HAVE_BCOPY) && (defined (HAVE_STRING_H) || defined (STDC_HEADERS)) -# define bcopy(s, d, n) memcpy ((d), (s), (n)) -#endif - -#else /* not HAVE_CONFIG_H */ - -#ifdef STDC_HEADERS -#include -#include -#else -char *getenv (); -char *malloc (); -char *realloc (); -#endif - -/* Do this after the include, in case string.h prototypes bcopy. */ -#if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy) -#define bcopy(s, d, n) memcpy ((d), (s), (n)) -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef _POSIX_VERSION -#include -#endif - -#endif /* not HAVE_CONFIG_H */ - -#ifndef NULL -#define NULL (char *) 0 -#endif - -#ifndef O_RDONLY -#define O_RDONLY 0 -#endif - -/* BUFSIZE is the initial size allocated for the buffer - for reading the termcap file. - It is not a limit. - Make it large normally for speed. - Make it variable when debugging, so can exercise - increasing the space dynamically. */ - -#ifndef BUFSIZE -#ifdef DEBUG -#define BUFSIZE bufsize - -int bufsize = 128; -#else -#define BUFSIZE 2048 -#endif -#endif - -#include "ltcap.h" - -#ifndef TERMCAP_FILE -#define TERMCAP_FILE "/etc/termcap" -#endif - -#ifndef emacs -static void -memory_out () -{ - write (2, "virtual memory exhausted\n", 25); - exit (1); -} - -static char * -xmalloc (size) - unsigned size; -{ - register char *tem = malloc (size); - - if (!tem) - memory_out (); - return tem; -} - -static char * -xrealloc (ptr, size) - char *ptr; - unsigned size; -{ - register char *tem = realloc (ptr, size); - - if (!tem) - memory_out (); - return tem; -} -#endif /* not emacs */ - -/* Looking up capabilities in the entry already found. */ - -/* The pointer to the data made by tgetent is left here - for tgetnum, tgetflag and tgetstr to find. */ -static char *term_entry; - -static char *tgetst1 (); - -/* Search entry BP for capability CAP. - Return a pointer to the capability (in BP) if found, - 0 if not found. */ - -static char * -find_capability (bp, cap) - register char *bp, *cap; -{ - for (; *bp; bp++) - if (bp[0] == ':' - && bp[1] == cap[0] - && bp[2] == cap[1]) - return &bp[4]; - return NULL; -} - -__private_extern__ -int -tgetnum (cap) - char *cap; -{ - register char *ptr = find_capability (term_entry, cap); - if (!ptr || ptr[-1] != '#') - return -1; - return atoi (ptr); -} - -__private_extern__ -int -tgetflag (cap) - char *cap; -{ - register char *ptr = find_capability (term_entry, cap); - return ptr && ptr[-1] == ':'; -} - -/* Look up a string-valued capability CAP. - If AREA is non-null, it points to a pointer to a block in which - to store the string. That pointer is advanced over the space used. - If AREA is null, space is allocated with `malloc'. */ - -__private_extern__ -char * -tgetstr (cap, area) - char *cap; - char **area; -{ - register char *ptr = find_capability (term_entry, cap); - if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~')) - return NULL; - return tgetst1 (ptr, area); -} - -/* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted, - gives meaning of character following \, or a space if no special meaning. - Eight characters per line within the string. */ - -static char esctab[] - = " \007\010 \033\014 \ - \012 \ - \015 \011 \013 \ - "; - -/* PTR points to a string value inside a termcap entry. - Copy that value, processing \ and ^ abbreviations, - into the block that *AREA points to, - or to newly allocated storage if AREA is NULL. - Return the address to which we copied the value, - or NULL if PTR is NULL. */ - -static char * -tgetst1 (ptr, area) - char *ptr; - char **area; -{ - register char *p, *r; - register int c; - register int size; - char *ret; - register int c1; - - if (!ptr) - return NULL; - - /* `ret' gets address of where to store the string. */ - if (!area) - { - /* Compute size of block needed (may overestimate). */ - p = ptr; - while ((c = *p++) && c != ':' && c != '\n') - ; - ret = (char *) xmalloc (p - ptr + 1); - } - else - ret = *area; - - /* Copy the string value, stopping at null or colon. - Also process ^ and \ abbreviations. */ - p = ptr; - r = ret; - while ((c = *p++) && c != ':' && c != '\n') - { - if (c == '^') - { - c = *p++; - if (c == '?') - c = 0177; - else - c &= 037; - } - else if (c == '\\') - { - c = *p++; - if (c >= '0' && c <= '7') - { - c -= '0'; - size = 0; - - while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7') - { - c *= 8; - c += c1 - '0'; - p++; - } - } - else if (c >= 0100 && c < 0200) - { - c1 = esctab[(c & ~040) - 0100]; - if (c1 != ' ') - c = c1; - } - } - *r++ = c; - } - *r = '\0'; - /* Update *AREA. */ - if (area) - *area = r + 1; - return ret; -} - -/* Outputting a string with padding. */ - -short ospeed; -/* If OSPEED is 0, we use this as the actual baud rate. */ -int tputs_baud_rate; -__private_extern__ char PC = '\0'; - -/* Actual baud rate if positive; - - baud rate / 100 if negative. */ - -static int speeds[] = - { -#ifdef VMS - 0, 50, 75, 110, 134, 150, -3, -6, -12, -18, - -20, -24, -36, -48, -72, -96, -192 -#else /* not VMS */ - 0, 50, 75, 110, 135, 150, -2, -3, -6, -12, - -18, -24, -48, -96, -192, -288, -384, -576, -1152 -#endif /* not VMS */ - }; - -__private_extern__ -void -tputs (str, nlines, outfun) - register char *str; - int nlines; - register int (*outfun) (); -{ - register int padcount = 0; - register int speed; - -#ifdef emacs - extern baud_rate; - speed = baud_rate; - /* For quite high speeds, convert to the smaller - units to avoid overflow. */ - if (speed > 10000) - speed = - speed / 100; -#else - if (ospeed == 0) - speed = tputs_baud_rate; - else if (ospeed > 0 && ospeed < (sizeof speeds / sizeof speeds[0])) - speed = speeds[ospeed]; - else - speed = 0; -#endif - - if (!str) - return; - - while (*str >= '0' && *str <= '9') - { - padcount += *str++ - '0'; - padcount *= 10; - } - if (*str == '.') - { - str++; - padcount += *str++ - '0'; - } - if (*str == '*') - { - str++; - padcount *= nlines; - } - while (*str) - (*outfun) (*str++); - - /* PADCOUNT is now in units of tenths of msec. - SPEED is measured in characters per 10 seconds - or in characters per .1 seconds (if negative). - We use the smaller units for larger speeds to avoid overflow. */ - padcount *= speed; - padcount += 500; - padcount /= 1000; - if (speed < 0) - padcount = -padcount; - else - { - padcount += 50; - padcount /= 100; - } - - while (padcount-- > 0) - (*outfun) (PC); -} - -/* Finding the termcap entry in the termcap data base. */ - -struct buffer - { - char *beg; - int size; - char *ptr; - int ateof; - int full; - }; - -/* Forward declarations of static functions. */ - -static int scan_file (); -static char *gobble_line (); -static int compare_contin (); -static int name_match (); - -#ifdef VMS - -#include -#include -#include - -static int -valid_filename_p (fn) - char *fn; -{ - struct FAB fab = cc$rms_fab; - struct NAM nam = cc$rms_nam; - char esa[NAM$C_MAXRSS]; - - fab.fab$l_fna = fn; - fab.fab$b_fns = strlen(fn); - fab.fab$l_nam = &nam; - fab.fab$l_fop = FAB$M_NAM; - - nam.nam$l_esa = esa; - nam.nam$b_ess = sizeof esa; - - return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL; -} - -#else /* !VMS */ - -#ifdef MSDOS /* MW, May 1993 */ -static int -valid_filename_p (fn) - char *fn; -{ - return *fn == '\\' || *fn == '/' || - (*fn >= 'A' && *fn <= 'z' && fn[1] == ':'); -} -#else -#define valid_filename_p(fn) (*(fn) == '/') -#endif - -#endif /* !VMS */ - -/* Find the termcap entry data for terminal type NAME - and store it in the block that BP points to. - Record its address for future use. - - If BP is null, space is dynamically allocated. - - Return -1 if there is some difficulty accessing the data base - of terminal types, - 0 if the data base is accessible but the type NAME is not defined - in it, and some other value otherwise. */ - -__private_extern__ -int -tgetent (bp, name) - char *bp, *name; -{ - register char *termcap_name; - register int fd; - struct buffer buf; - register char *bp1; - char *bp2; - char *term; - int malloc_size = 0; - register int c; - char *tcenv; /* TERMCAP value, if it contains :tc=. */ - char *indirect = NULL; /* Terminal type in :tc= in TERMCAP value. */ - int filep; - -#ifdef INTERNAL_TERMINAL - /* For the internal terminal we don't want to read any termcap file, - so fake it. */ - if (!strcmp (name, "internal")) - { - term = INTERNAL_TERMINAL; - if (!bp) - { - malloc_size = 1 + strlen (term); - bp = (char *) xmalloc (malloc_size); - } - strcpy (bp, term); - goto ret; - } -#endif /* INTERNAL_TERMINAL */ - - /* For compatibility with programs like `less' that want to - put data in the termcap buffer themselves as a fallback. */ - if (bp) - term_entry = bp; - - termcap_name = getenv ("TERMCAP"); - if (termcap_name && *termcap_name == '\0') - termcap_name = NULL; -#if 0 -#if defined (MSDOS) && !defined (TEST) - if (termcap_name && (*termcap_name == '\\' - || *termcap_name == '/' - || termcap_name[1] == ':')) - dostounix_filename(termcap_name); -#endif -#endif - - filep = termcap_name && valid_filename_p (termcap_name); - - /* If termcap_name is non-null and starts with / (in the un*x case, that is), - it is a file name to use instead of /etc/termcap. - If it is non-null and does not start with /, - it is the entry itself, but only if - the name the caller requested matches the TERM variable. */ - - if (termcap_name && !filep && !strcmp (name, getenv ("TERM"))) - { - indirect = tgetst1 (find_capability (termcap_name, "tc"), (char **) 0); - if (!indirect) - { - if (!bp) - bp = termcap_name; - else - strcpy (bp, termcap_name); - goto ret; - } - else - { /* It has tc=. Need to read /etc/termcap. */ - tcenv = termcap_name; - termcap_name = NULL; - } - } - - if (!termcap_name || !filep) - termcap_name = TERMCAP_FILE; - - /* Here we know we must search a file and termcap_name has its name. */ - -#ifdef MSDOS - fd = open (termcap_name, O_RDONLY|O_TEXT, 0); -#else - fd = open (termcap_name, O_RDONLY, 0); -#endif - if (fd < 0) - return -1; - - buf.size = BUFSIZE; - /* Add 1 to size to ensure room for terminating null. */ - buf.beg = (char *) xmalloc (buf.size + 1); - term = indirect ? indirect : name; - - if (!bp) - { - malloc_size = indirect ? strlen (tcenv) + 1 : buf.size; - bp = (char *) xmalloc (malloc_size); - } - bp1 = bp; - - if (indirect) - /* Copy the data from the environment variable. */ - { - strcpy (bp, tcenv); - bp1 += strlen (tcenv); - } - - while (term) - { - /* Scan the file, reading it via buf, till find start of main entry. */ - if (scan_file (term, fd, &buf) == 0) - { - close (fd); - free (buf.beg); - if (malloc_size) - free (bp); - return 0; - } - - /* Free old `term' if appropriate. */ - if (term != name) - free (term); - - /* If BP is malloc'd by us, make sure it is big enough. */ - if (malloc_size) - { - malloc_size = bp1 - bp + buf.size; - termcap_name = (char *) xrealloc (bp, malloc_size); - bp1 += termcap_name - bp; - bp = termcap_name; - } - - bp2 = bp1; - - /* Copy the line of the entry from buf into bp. */ - termcap_name = buf.ptr; - while ((*bp1++ = c = *termcap_name++) && c != '\n') - /* Drop out any \ newline sequence. */ - if (c == '\\' && *termcap_name == '\n') - { - bp1--; - termcap_name++; - } - *bp1 = '\0'; - - /* Does this entry refer to another terminal type's entry? - If something is found, copy it into heap and null-terminate it. */ - term = tgetst1 (find_capability (bp2, "tc"), (char **) 0); - } - - close (fd); - free (buf.beg); - - if (malloc_size) - bp = (char *) xrealloc (bp, bp1 - bp + 1); - - ret: - term_entry = bp; - return 1; -} - -/* Given file open on FD and buffer BUFP, - scan the file from the beginning until a line is found - that starts the entry for terminal type STR. - Return 1 if successful, with that line in BUFP, - or 0 if no entry is found in the file. */ - -static int -scan_file (str, fd, bufp) - char *str; - int fd; - register struct buffer *bufp; -{ - register char *end; - - bufp->ptr = bufp->beg; - bufp->full = 0; - bufp->ateof = 0; - *bufp->ptr = '\0'; - - lseek (fd, 0L, 0); - - while (!bufp->ateof) - { - /* Read a line into the buffer. */ - end = NULL; - do - { - /* if it is continued, append another line to it, - until a non-continued line ends. */ - end = gobble_line (fd, bufp, end); - } - while (!bufp->ateof && end[-2] == '\\'); - - if (*bufp->ptr != '#' - && name_match (bufp->ptr, str)) - return 1; - - /* Discard the line just processed. */ - bufp->ptr = end; - } - return 0; -} - -/* Return nonzero if NAME is one of the names specified - by termcap entry LINE. */ - -static int -name_match (line, name) - char *line, *name; -{ - register char *tem; - - if (!compare_contin (line, name)) - return 1; - /* This line starts an entry. Is it the right one? */ - for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++) - if (*tem == '|' && !compare_contin (tem + 1, name)) - return 1; - - return 0; -} - -static int -compare_contin (str1, str2) - register char *str1, *str2; -{ - register int c1, c2; - while (1) - { - c1 = *str1++; - c2 = *str2++; - while (c1 == '\\' && *str1 == '\n') - { - str1++; - while ((c1 = *str1++) == ' ' || c1 == '\t'); - } - if (c2 == '\0') - { - /* End of type being looked up. */ - if (c1 == '|' || c1 == ':') - /* If end of name in data base, we win. */ - return 0; - else - return 1; - } - else if (c1 != c2) - return 1; - } -} - -/* Make sure that the buffer <- BUFP contains a full line - of the file open on FD, starting at the place BUFP->ptr - points to. Can read more of the file, discard stuff before - BUFP->ptr, or make the buffer bigger. - - Return the pointer to after the newline ending the line, - or to the end of the file, if there is no newline to end it. - - Can also merge on continuation lines. If APPEND_END is - non-null, it points past the newline of a line that is - continued; we add another line onto it and regard the whole - thing as one line. The caller decides when a line is continued. */ - -static char * -gobble_line (fd, bufp, append_end) - int fd; - register struct buffer *bufp; - char *append_end; -{ - register char *end; - register int nread; - register char *buf = bufp->beg; - register char *tem; - - if (!append_end) - append_end = bufp->ptr; - - while (1) - { - end = append_end; - while (*end && *end != '\n') end++; - if (*end) - break; - if (bufp->ateof) - return buf + bufp->full; - if (bufp->ptr == buf) - { - if (bufp->full == bufp->size) - { - bufp->size *= 2; - /* Add 1 to size to ensure room for terminating null. */ - tem = (char *) xrealloc (buf, bufp->size + 1); - bufp->ptr = (bufp->ptr - buf) + tem; - append_end = (append_end - buf) + tem; - bufp->beg = buf = tem; - } - } - else - { - append_end -= bufp->ptr - buf; - bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf); - bufp->ptr = buf; - } - if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full))) - bufp->ateof = 1; - bufp->full += nread; - buf[bufp->full] = '\0'; - } - return end + 1; -} - -#ifdef TEST - -#ifdef NULL -#undef NULL -#endif - -#include - -main (argc, argv) - int argc; - char **argv; -{ - char *term; - char *buf; - - term = argv[1]; - printf ("TERM: %s\n", term); - - buf = (char *) tgetent (0, term); - if ((int) buf <= 0) - { - printf ("No entry.\n"); - return 0; - } - - printf ("Entry: %s\n", buf); - - tprint ("cm"); - tprint ("AL"); - - printf ("co: %d\n", tgetnum ("co")); - printf ("am: %d\n", tgetflag ("am")); -} - -tprint (cap) - char *cap; -{ - char *x = tgetstr (cap, 0); - register char *y; - - printf ("%s: ", cap); - if (x) - { - for (y = x; *y; y++) - if (*y <= ' ' || *y == 0177) - printf ("\\%0o", *y); - else - putchar (*y); - free (x); - } - else - printf ("none"); - putchar ('\n'); -} - -#endif /* TEST */ diff --git a/lib/termcap/tparam.c~ b/lib/termcap/tparam.c~ deleted file mode 100644 index c19471f9c..000000000 --- a/lib/termcap/tparam.c~ +++ /dev/null @@ -1,345 +0,0 @@ -/* tparam.c - merge parameters into a termcap entry string. */ - -/* Copyright (C) 1985, 1986, 1993,1994, 1995, 1998, 2001,2003,2005,2006,2008Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -/* Emacs config.h may rename various library functions such as malloc. */ -#ifdef HAVE_CONFIG_H -#include - -#ifdef HAVE_STDLIB_H -# include -#else -extern char *getenv (); -extern char *malloc (); -extern char *realloc (); -#endif - -#if defined (HAVE_STRING_H) -#include -#endif - -#if !defined (HAVE_BCOPY) && (defined (HAVE_STRING_H) || defined (STDC_HEADERS)) -# define bcopy(s, d, n) memcpy ((d), (s), (n)) -#endif - -#else /* not HAVE_CONFIG_H */ - -#if defined(HAVE_STRING_H) || defined(STDC_HEADERS) -#define bcopy(s, d, n) memcpy ((d), (s), (n)) -#endif - -#ifdef STDC_HEADERS -#include -#include -#else -char *malloc (); -char *realloc (); -#endif - -#endif /* not HAVE_CONFIG_H */ - -#include "ltcap.h" - -#ifndef NULL -#define NULL (char *) 0 -#endif - -#ifndef emacs -static void -memory_out () -{ - write (2, "virtual memory exhausted\n", 25); - exit (1); -} - -static char * -xmalloc (size) - unsigned size; -{ - register char *tem = malloc (size); - - if (!tem) - memory_out (); - return tem; -} - -static char * -xrealloc (ptr, size) - char *ptr; - unsigned size; -{ - register char *tem = realloc (ptr, size); - - if (!tem) - memory_out (); - return tem; -} -#endif /* not emacs */ - -/* Assuming STRING is the value of a termcap string entry - containing `%' constructs to expand parameters, - merge in parameter values and store result in block OUTSTRING points to. - LEN is the length of OUTSTRING. If more space is needed, - a block is allocated with `malloc'. - - The value returned is the address of the resulting string. - This may be OUTSTRING or may be the address of a block got with `malloc'. - In the latter case, the caller must free the block. - - The fourth and following args to tparam serve as the parameter values. */ - -static char *tparam1 (); - -/* VARARGS 2 */ -char * -tparam (string, outstring, len, arg0, arg1, arg2, arg3) - char *string; - char *outstring; - int len; - int arg0, arg1, arg2, arg3; -{ - int arg[4]; - - arg[0] = arg0; - arg[1] = arg1; - arg[2] = arg2; - arg[3] = arg3; - return tparam1 (string, outstring, len, NULL, NULL, arg); -} - -__private_extern__ char *BC; -__private_extern__ char *UP; - -static char tgoto_buf[50]; - -__private_extern__ -char * -tgoto (cm, hpos, vpos) - char *cm; - int hpos, vpos; -{ - int args[2]; - if (!cm) - return NULL; - args[0] = vpos; - args[1] = hpos; - return tparam1 (cm, tgoto_buf, 50, UP, BC, args); -} - -static char * -tparam1 (string, outstring, len, up, left, argp) - char *string; - char *outstring; - int len; - char *up, *left; - register int *argp; -{ - register int c; - register char *p = string; - register char *op = outstring; - char *outend; - int outlen = 0; - - register int tem; - int *old_argp = argp; - int doleft = 0; - int doup = 0; - - outend = outstring + len; - - while (1) - { - /* If the buffer might be too short, make it bigger. */ - if (op + 5 >= outend) - { - register char *new; - if (outlen == 0) - { - outlen = len + 40; - new = (char *) xmalloc (outlen); - outend += 40; - bcopy (outstring, new, op - outstring); - } - else - { - outend += outlen; - outlen *= 2; - new = (char *) xrealloc (outstring, outlen); - } - op += new - outstring; - outend += new - outstring; - outstring = new; - } - c = *p++; - if (!c) - break; - if (c == '%') - { - c = *p++; - tem = *argp; - switch (c) - { - case 'd': /* %d means output in decimal. */ - if (tem < 10) - goto onedigit; - if (tem < 100) - goto twodigit; - case '3': /* %3 means output in decimal, 3 digits. */ - if (tem > 999) - { - *op++ = tem / 1000 + '0'; - tem %= 1000; - } - *op++ = tem / 100 + '0'; - case '2': /* %2 means output in decimal, 2 digits. */ - twodigit: - tem %= 100; - *op++ = tem / 10 + '0'; - onedigit: - *op++ = tem % 10 + '0'; - argp++; - break; - - case 'C': - /* For c-100: print quotient of value by 96, if nonzero, - then do like %+. */ - if (tem >= 96) - { - *op++ = tem / 96; - tem %= 96; - } - case '+': /* %+x means add character code of char x. */ - tem += *p++; - case '.': /* %. means output as character. */ - if (left) - { - /* If want to forbid output of 0 and \n and \t, - and this is one of them, increment it. */ - while (tem == 0 || tem == '\n' || tem == '\t') - { - tem++; - if (argp == old_argp) - doup++, outend -= strlen (up); - else - doleft++, outend -= strlen (left); - } - } - *op++ = tem ? tem : 0200; - case 'f': /* %f means discard next arg. */ - argp++; - break; - - case 'b': /* %b means back up one arg (and re-use it). */ - argp--; - break; - - case 'r': /* %r means interchange following two args. */ - argp[0] = argp[1]; - argp[1] = tem; - old_argp++; - break; - - case '>': /* %>xy means if arg is > char code of x, */ - if (argp[0] > *p++) /* then add char code of y to the arg, */ - argp[0] += *p; /* and in any case don't output. */ - p++; /* Leave the arg to be output later. */ - break; - - case 'a': /* %a means arithmetic. */ - /* Next character says what operation. - Add or subtract either a constant or some other arg. */ - /* First following character is + to add or - to subtract - or = to assign. */ - /* Next following char is 'p' and an arg spec - (0100 plus position of that arg relative to this one) - or 'c' and a constant stored in a character. */ - tem = p[2] & 0177; - if (p[1] == 'p') - tem = argp[tem - 0100]; - if (p[0] == '-') - argp[0] -= tem; - else if (p[0] == '+') - argp[0] += tem; - else if (p[0] == '*') - argp[0] *= tem; - else if (p[0] == '/') - argp[0] /= tem; - else - argp[0] = tem; - - p += 3; - break; - - case 'i': /* %i means add one to arg, */ - argp[0] ++; /* and leave it to be output later. */ - argp[1] ++; /* Increment the following arg, too! */ - break; - - case '%': /* %% means output %; no arg. */ - goto ordinary; - - case 'n': /* %n means xor each of next two args with 140. */ - argp[0] ^= 0140; - argp[1] ^= 0140; - break; - - case 'm': /* %m means xor each of next two args with 177. */ - argp[0] ^= 0177; - argp[1] ^= 0177; - break; - - case 'B': /* %B means express arg as BCD char code. */ - argp[0] += 6 * (tem / 10); - break; - - case 'D': /* %D means weird Delta Data transformation. */ - argp[0] -= 2 * (tem % 16); - break; - } - } - else - /* Ordinary character in the argument string. */ - ordinary: - *op++ = c; - } - *op = 0; - while (doup-- > 0) - strcat (op, up); - while (doleft-- > 0) - strcat (op, left); - return outstring; -} - -#ifdef DEBUG - -main (argc, argv) - int argc; - char **argv; -{ - char buf[50]; - int args[3]; - args[0] = atoi (argv[2]); - args[1] = atoi (argv[3]); - args[2] = atoi (argv[4]); - tparam1 (argv[1], buf, "LEFT", "UP", args); - printf ("%s\n", buf); - return 0; -} - -#endif /* DEBUG */ diff --git a/locale.c.save b/locale.c.save deleted file mode 100644 index 1a222dc46..000000000 --- a/locale.c.save +++ /dev/null @@ -1,509 +0,0 @@ -/* locale.c - Miscellaneous internationalization functions. */ - -/* Copyright (C) 1996-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" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashintl.h" -#include "bashansi.h" -#include -#include "chartypes.h" - -#include "shell.h" -#include "input.h" /* For bash_input */ - -extern int dump_translatable_strings, dump_po_strings; - -/* The current locale when the program begins */ -static char *default_locale; - -/* The current domain for textdomain(3). */ -static char *default_domain; -static char *default_dir; - -/* tracks the value of LC_ALL; used to override values for other locale - categories */ -static char *lc_all; - -/* tracks the value of LC_ALL; used to provide defaults for locale - categories */ -static char *lang; - -/* Called to reset all of the locale variables to their appropriate values - if (and only if) LC_ALL has not been assigned a value. */ -static int reset_locale_vars __P((void)); - -static void locale_setblanks __P((void)); - -/* Set the value of default_locale and make the current locale the - system default locale. This should be called very early in main(). */ -void -set_default_locale () -{ -#if defined (HAVE_SETLOCALE) - default_locale = setlocale (LC_ALL, ""); - if (default_locale) - default_locale = savestring (default_locale); -#endif /* HAVE_SETLOCALE */ - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); -} - -/* Set default values for LC_CTYPE, LC_COLLATE, LC_MESSAGES, LC_NUMERIC and - LC_TIME if they are not specified in the environment, but LC_ALL is. This - should be called from main() after parsing the environment. */ -void -set_default_locale_vars () -{ - char *val; - -#if defined (HAVE_SETLOCALE) - -# if defined (LC_CTYPE) - val = get_string_value ("LC_CTYPE"); - if (val == 0 && lc_all && *lc_all) - { - setlocale (LC_CTYPE, lc_all); - locale_setblanks (); - } -# endif - -# if defined (LC_COLLATE) - val = get_string_value ("LC_COLLATE"); - if (val == 0 && lc_all && *lc_all) - setlocale (LC_COLLATE, lc_all); -# endif /* LC_COLLATE */ - -# if defined (LC_MESSAGES) - val = get_string_value ("LC_MESSAGES"); - if (val == 0 && lc_all && *lc_all) - setlocale (LC_MESSAGES, lc_all); -# endif /* LC_MESSAGES */ - -# if defined (LC_NUMERIC) - val = get_string_value ("LC_NUMERIC"); - if (val == 0 && lc_all && *lc_all) - setlocale (LC_NUMERIC, lc_all); -# endif /* LC_NUMERIC */ - -# if defined (LC_TIME) - val = get_string_value ("LC_TIME"); - if (val == 0 && lc_all && *lc_all) - setlocale (LC_TIME, lc_all); -# endif /* LC_TIME */ - -#endif /* HAVE_SETLOCALE */ - - val = get_string_value ("TEXTDOMAIN"); - if (val && *val) - { - FREE (default_domain); - default_domain = savestring (val); -#if 0 - /* Don't want to override the shell's textdomain as the default */ - textdomain (default_domain); -#endif - } - - val = get_string_value ("TEXTDOMAINDIR"); - if (val && *val) - { - FREE (default_dir); - default_dir = savestring (val); - if (default_domain && *default_domain) - bindtextdomain (default_domain, default_dir); - } -} - -/* Set one of the locale categories (specified by VAR) to VALUE. Returns 1 - if successful, 0 otherwise. */ -int -set_locale_var (var, value) - char *var, *value; -{ - int r; - - if (var[0] == 'T' && var[10] == 0) /* TEXTDOMAIN */ - { - FREE (default_domain); - default_domain = value ? savestring (value) : (char *)NULL; -#if 0 - /* Don't want to override the shell's textdomain as the default */ - textdomain (default_domain); -#endif - return (1); - } - else if (var[0] == 'T') /* TEXTDOMAINDIR */ - { - FREE (default_dir); - default_dir = value ? savestring (value) : (char *)NULL; - if (default_domain && *default_domain) - bindtextdomain (default_domain, default_dir); - return (1); - } - - /* var[0] == 'L' && var[1] == 'C' && var[2] == '_' */ - - else if (var[3] == 'A') /* LC_ALL */ - { - FREE (lc_all); - if (value) - lc_all = savestring (value); - else - { - lc_all = (char *)xmalloc (1); - lc_all[0] = '\0'; - } -#if defined (HAVE_SETLOCALE) - r = *lc_all ? (setlocale (LC_ALL, lc_all) != 0) : reset_locale_vars (); - locale_setblanks (); - return r; -#else - return (1); -#endif - } - -#if defined (HAVE_SETLOCALE) - else if (var[3] == 'C' && var[4] == 'T') /* LC_CTYPE */ - { -# if defined (LC_CTYPE) - if (lc_all == 0 || *lc_all == '\0') - { - r = (setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE")) != 0); - locale_setblanks (); - return r; - } -# endif - } - else if (var[3] == 'C' && var[4] == 'O') /* LC_COLLATE */ - { -# if defined (LC_COLLATE) - if (lc_all == 0 || *lc_all == '\0') - return (setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE")) != 0); -# endif /* LC_COLLATE */ - } - else if (var[3] == 'M' && var[4] == 'E') /* LC_MESSAGES */ - { -# if defined (LC_MESSAGES) - if (lc_all == 0 || *lc_all == '\0') - return (setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES")) != 0); -# endif /* LC_MESSAGES */ - } - else if (var[3] == 'N' && var[4] == 'U') /* LC_NUMERIC */ - { -# if defined (LC_NUMERIC) - if (lc_all == 0 || *lc_all == '\0') - return (setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC")) != 0); -# endif /* LC_NUMERIC */ - } - else if (var[3] == 'T' && var[4] == 'I') /* LC_TIME */ - { -# if defined (LC_TIME) - if (lc_all == 0 || *lc_all == '\0') - return (setlocale (LC_TIME, get_locale_var ("LC_TIME")) != 0); -# endif /* LC_TIME */ - } -#endif /* HAVE_SETLOCALE */ - - - return (0); -} - -/* Called when LANG is assigned a value. Tracks value in `lang'. Calls - reset_locale_vars() to reset any default values if LC_ALL is unset or - null. */ -int -set_lang (var, value) - char *var, *value; -{ - FREE (lang); - if (value) - lang = savestring (value); - else - { - lang = (char *)xmalloc (1); - lang[0] = '\0'; - } - - return ((lc_all == 0 || *lc_all == 0) ? reset_locale_vars () : 0); -} - -/* Set default values for LANG and LC_ALL. Default values for all other - locale-related variables depend on these. */ -void -set_default_lang () -{ - char *v; - - v = get_string_value ("LC_ALL"); - set_locale_var ("LC_ALL", v); - - v = get_string_value ("LANG"); - set_lang ("LANG", v); -} - -/* Get the value of one of the locale variables (LC_MESSAGES, LC_CTYPE). - The precedence is as POSIX.2 specifies: LC_ALL has precedence over - the specific locale variables, and LANG, if set, is used as the default. */ -char * -get_locale_var (var) - char *var; -{ - char *locale; - - locale = lc_all; - - if (locale == 0 || *locale == 0) - locale = get_string_value (var); - if (locale == 0 || *locale == 0) - locale = lang; - if (locale == 0 || *locale == 0) - locale = default_locale; /* system-dependent; not really portable. should it be "C"? */ - - return (locale); -} - -/* Called to reset all of the locale variables to their appropriate values - if (and only if) LC_ALL has not been assigned a value. DO NOT CALL THIS - IF LC_ALL HAS BEEN ASSIGNED A VALUE. */ -static int -reset_locale_vars () -{ -#if defined (HAVE_SETLOCALE) - if (lang == 0 || *lang == '\0') - maybe_make_export_env (); /* trust that this will change environment for setlocale */ - if (setlocale (LC_ALL, lang ? lang : "") == 0) - return 0; - -# if defined (LC_CTYPE) - setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE")); -# endif -# if defined (LC_COLLATE) - setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE")); -# endif -# if defined (LC_MESSAGES) - setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES")); -# endif -# if defined (LC_NUMERIC) - setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC")); -# endif -# if defined (LC_TIME) - setlocale (LC_TIME, get_locale_var ("LC_TIME")); -# endif - - locale_setblanks (); - -#endif - return 1; -} - -/* Translate the contents of STRING, a $"..." quoted string, according - to the current locale. In the `C' or `POSIX' locale, or if gettext() - is not available, the passed string is returned unchanged. The - length of the translated string is returned in LENP, if non-null. */ -char * -localetrans (string, len, lenp) - char *string; - int len, *lenp; -{ - char *locale, *t; - char *translated; - int tlen; - - /* Don't try to translate null strings. */ - if (string == 0 || *string == 0) - { - if (lenp) - *lenp = 0; - return ((char *)NULL); - } - - locale = get_locale_var ("LC_MESSAGES"); - - /* If we don't have setlocale() or the current locale is `C' or `POSIX', - just return the string. If we don't have gettext(), there's no use - doing anything else. */ - if (locale == 0 || locale[0] == '\0' || - (locale[0] == 'C' && locale[1] == '\0') || STREQ (locale, "POSIX")) - { - t = (char *)xmalloc (len + 1); - strcpy (t, string); - if (lenp) - *lenp = len; - return (t); - } - - /* Now try to translate it. */ - if (default_domain && *default_domain) - translated = dgettext (default_domain, string); - else - translated = string; - - if (translated == string) /* gettext returns its argument if untranslatable */ - { - t = (char *)xmalloc (len + 1); - strcpy (t, string); - if (lenp) - *lenp = len; - } - else - { - tlen = strlen (translated); - t = (char *)xmalloc (tlen + 1); - strcpy (t, translated); - if (lenp) - *lenp = tlen; - } - return (t); -} - -/* Change a bash string into a string suitable for inclusion in a `po' file. - This backslash-escapes `"' and `\' and changes newlines into \\\n"\n". */ -char * -mk_msgstr (string, foundnlp) - char *string; - int *foundnlp; -{ - register int c, len; - char *result, *r, *s; - - for (len = 0, s = string; s && *s; s++) - { - len++; - if (*s == '"' || *s == '\\') - len++; - else if (*s == '\n') - len += 5; - } - - r = result = (char *)xmalloc (len + 3); - *r++ = '"'; - - for (s = string; s && (c = *s); s++) - { - if (c == '\n') /* -> \n"" */ - { - *r++ = '\\'; - *r++ = 'n'; - *r++ = '"'; - *r++ = '\n'; - *r++ = '"'; - if (foundnlp) - *foundnlp = 1; - continue; - } - if (c == '"' || c == '\\') - *r++ = '\\'; - *r++ = c; - } - - *r++ = '"'; - *r++ = '\0'; - - return result; -} - -/* $"..." -- Translate the portion of STRING between START and END - according to current locale using gettext (if available) and return - the result. The caller will take care of leaving the quotes intact. - The string will be left without the leading `$' by the caller. - If translation is performed, the translated string will be double-quoted - by the caller. The length of the translated string is returned in LENP, - if non-null. */ -char * -localeexpand (string, start, end, lineno, lenp) - char *string; - int start, end, lineno, *lenp; -{ - int len, tlen, foundnl; - char *temp, *t, *t2; - - temp = (char *)xmalloc (end - start + 1); - for (tlen = 0, len = start; len < end; ) - temp[tlen++] = string[len++]; - temp[tlen] = '\0'; - - /* If we're just dumping translatable strings, don't do anything with the - string itself, but if we're dumping in `po' file format, convert it into - a form more palatable to gettext(3) and friends by quoting `"' and `\' - with backslashes and converting into `\n""'. If we find a - newline in TEMP, we first output a `msgid ""' line and then the - translated string; otherwise we output the `msgid' and translated - string all on one line. */ - if (dump_translatable_strings) - { - if (dump_po_strings) - { - foundnl = 0; - t = mk_msgstr (temp, &foundnl); - t2 = foundnl ? "\"\"\n" : ""; - - printf ("#: %s:%d\nmsgid %s%s\nmsgstr \"\"\n", - yy_input_name (), lineno, t2, t); - free (t); - } - else - printf ("\"%s\"\n", temp); - - if (lenp) - *lenp = tlen; - return (temp); - } - else if (*temp) - { - t = localetrans (temp, tlen, &len); - free (temp); - if (lenp) - *lenp = len; - return (t); - } - else - { - if (lenp) - *lenp = 0; - return (temp); - } -} - -/* Set every character in the character class to be a shell break - character for the lexical analyzer when the locale changes. */ -static void -locale_setblanks () -{ - int x; - - for (x = 0; x < sh_syntabsiz; x++) - { - if (isblank (x)) - sh_syntaxtab[x] |= CSHBRK|CBLANK; - else if (member (x, shell_break_chars)) - { - sh_syntaxtab[x] |= CSHBRK; - sh_syntaxtab[x] &= ~CBLANK; - } - else - sh_syntaxtab[x] &= ~(CSHBRK|CBLANK); - } -} diff --git a/locale.c~ b/locale.c~ deleted file mode 100644 index 53b447a32..000000000 --- a/locale.c~ +++ /dev/null @@ -1,524 +0,0 @@ -/* locale.c - Miscellaneous internationalization functions. */ - -/* Copyright (C) 1996-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include "config.h" - -#include "bashtypes.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashintl.h" -#include "bashansi.h" -#include -#include "chartypes.h" -#include - -#include "shell.h" -#include "input.h" /* For bash_input */ - -#ifndef errno -extern int errno; -#endif - -extern int dump_translatable_strings, dump_po_strings; - -/* The current locale when the program begins */ -static char *default_locale; - -/* The current domain for textdomain(3). */ -static char *default_domain; -static char *default_dir; - -/* tracks the value of LC_ALL; used to override values for other locale - categories */ -static char *lc_all; - -/* tracks the value of LC_ALL; used to provide defaults for locale - categories */ -static char *lang; - -/* Called to reset all of the locale variables to their appropriate values - if (and only if) LC_ALL has not been assigned a value. */ -static int reset_locale_vars __P((void)); - -static void locale_setblanks __P((void)); - -/* Set the value of default_locale and make the current locale the - system default locale. This should be called very early in main(). */ -void -set_default_locale () -{ -#if defined (HAVE_SETLOCALE) - default_locale = setlocale (LC_ALL, ""); - if (default_locale) - default_locale = savestring (default_locale); -#endif /* HAVE_SETLOCALE */ - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); -} - -/* Set default values for LC_CTYPE, LC_COLLATE, LC_MESSAGES, LC_NUMERIC and - LC_TIME if they are not specified in the environment, but LC_ALL is. This - should be called from main() after parsing the environment. */ -void -set_default_locale_vars () -{ - char *val; - -#if defined (HAVE_SETLOCALE) - -# if defined (LC_CTYPE) - val = get_string_value ("LC_CTYPE"); - if (val == 0 && lc_all && *lc_all) - { - setlocale (LC_CTYPE, lc_all); - locale_setblanks (); - } -# endif - -# if defined (LC_COLLATE) - val = get_string_value ("LC_COLLATE"); - if (val == 0 && lc_all && *lc_all) - setlocale (LC_COLLATE, lc_all); -# endif /* LC_COLLATE */ - -# if defined (LC_MESSAGES) - val = get_string_value ("LC_MESSAGES"); - if (val == 0 && lc_all && *lc_all) - setlocale (LC_MESSAGES, lc_all); -# endif /* LC_MESSAGES */ - -# if defined (LC_NUMERIC) - val = get_string_value ("LC_NUMERIC"); - if (val == 0 && lc_all && *lc_all) - setlocale (LC_NUMERIC, lc_all); -# endif /* LC_NUMERIC */ - -# if defined (LC_TIME) - val = get_string_value ("LC_TIME"); - if (val == 0 && lc_all && *lc_all) - setlocale (LC_TIME, lc_all); -# endif /* LC_TIME */ - -#endif /* HAVE_SETLOCALE */ - - val = get_string_value ("TEXTDOMAIN"); - if (val && *val) - { - FREE (default_domain); - default_domain = savestring (val); -#if 0 - /* Don't want to override the shell's textdomain as the default */ - textdomain (default_domain); -#endif - } - - val = get_string_value ("TEXTDOMAINDIR"); - if (val && *val) - { - FREE (default_dir); - default_dir = savestring (val); - if (default_domain && *default_domain) - bindtextdomain (default_domain, default_dir); - } -} - -/* Set one of the locale categories (specified by VAR) to VALUE. Returns 1 - if successful, 0 otherwise. */ -int -set_locale_var (var, value) - char *var, *value; -{ - int r; - char *x; - - x = ""; - errno = 0; - if (var[0] == 'T' && var[10] == 0) /* TEXTDOMAIN */ - { - FREE (default_domain); - default_domain = value ? savestring (value) : (char *)NULL; -#if 0 - /* Don't want to override the shell's textdomain as the default */ - textdomain (default_domain); -#endif - return (1); - } - else if (var[0] == 'T') /* TEXTDOMAINDIR */ - { - FREE (default_dir); - default_dir = value ? savestring (value) : (char *)NULL; - if (default_domain && *default_domain) - bindtextdomain (default_domain, default_dir); - return (1); - } - - /* var[0] == 'L' && var[1] == 'C' && var[2] == '_' */ - - else if (var[3] == 'A') /* LC_ALL */ - { - FREE (lc_all); - if (value) - lc_all = savestring (value); - else - { - lc_all = (char *)xmalloc (1); - lc_all[0] = '\0'; - } -#if defined (HAVE_SETLOCALE) - r = *lc_all ? ((x = setlocale (LC_ALL, lc_all)) != 0) : reset_locale_vars (); - if (x == 0) - internal_warning("setlocale: LC_ALL: cannot change locale (%s): %s", lc_all, strerror(errno)); - locale_setblanks (); - return r; -#else - return (1); -#endif - } - -#if defined (HAVE_SETLOCALE) - else if (var[3] == 'C' && var[4] == 'T') /* LC_CTYPE */ - { -# if defined (LC_CTYPE) - if (lc_all == 0 || *lc_all == '\0') - { - x = setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE")); - locale_setblanks (); - } -# endif - } - else if (var[3] == 'C' && var[4] == 'O') /* LC_COLLATE */ - { -# if defined (LC_COLLATE) - if (lc_all == 0 || *lc_all == '\0') - x = setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE")); -# endif /* LC_COLLATE */ - } - else if (var[3] == 'M' && var[4] == 'E') /* LC_MESSAGES */ - { -# if defined (LC_MESSAGES) - if (lc_all == 0 || *lc_all == '\0') - x = setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES")); -# endif /* LC_MESSAGES */ - } - else if (var[3] == 'N' && var[4] == 'U') /* LC_NUMERIC */ - { -# if defined (LC_NUMERIC) - if (lc_all == 0 || *lc_all == '\0') - x = setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC")); -# endif /* LC_NUMERIC */ - } - else if (var[3] == 'T' && var[4] == 'I') /* LC_TIME */ - { -# if defined (LC_TIME) - if (lc_all == 0 || *lc_all == '\0') - x = setlocale (LC_TIME, get_locale_var ("LC_TIME")); -# endif /* LC_TIME */ - } -#endif /* HAVE_SETLOCALE */ - - if (x == 0) - internal_warning("setlocale: %s: cannot change locale (%s): %s", var, get_locale_var (var), strerror(errno)); - - return (x != 0); -} - -/* Called when LANG is assigned a value. Tracks value in `lang'. Calls - reset_locale_vars() to reset any default values if LC_ALL is unset or - null. */ -int -set_lang (var, value) - char *var, *value; -{ - FREE (lang); - if (value) - lang = savestring (value); - else - { - lang = (char *)xmalloc (1); - lang[0] = '\0'; - } - - return ((lc_all == 0 || *lc_all == 0) ? reset_locale_vars () : 0); -} - -/* Set default values for LANG and LC_ALL. Default values for all other - locale-related variables depend on these. */ -void -set_default_lang () -{ - char *v; - - v = get_string_value ("LC_ALL"); - set_locale_var ("LC_ALL", v); - - v = get_string_value ("LANG"); - set_lang ("LANG", v); -} - -/* Get the value of one of the locale variables (LC_MESSAGES, LC_CTYPE). - The precedence is as POSIX.2 specifies: LC_ALL has precedence over - the specific locale variables, and LANG, if set, is used as the default. */ -char * -get_locale_var (var) - char *var; -{ - char *locale; - - locale = lc_all; - - if (locale == 0 || *locale == 0) - locale = get_string_value (var); - if (locale == 0 || *locale == 0) - locale = lang; - if (locale == 0 || *locale == 0) -#if 0 - locale = default_locale; /* system-dependent; not really portable. should it be "C"? */ -#else - locale = ""; -#endif - return (locale); -} - -/* Called to reset all of the locale variables to their appropriate values - if (and only if) LC_ALL has not been assigned a value. DO NOT CALL THIS - IF LC_ALL HAS BEEN ASSIGNED A VALUE. */ -static int -reset_locale_vars () -{ - char *t; -#if defined (HAVE_SETLOCALE) - if (lang == 0 || *lang == '\0') - maybe_make_export_env (); /* trust that this will change environment for setlocale */ - if (setlocale (LC_ALL, lang ? lang : "") == 0) - return 0; - -# if defined (LC_CTYPE) - t = setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE")); -# endif -# if defined (LC_COLLATE) - t = setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE")); -# endif -# if defined (LC_MESSAGES) - t = setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES")); -# endif -# if defined (LC_NUMERIC) - t = setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC")); -# endif -# if defined (LC_TIME) - t = setlocale (LC_TIME, get_locale_var ("LC_TIME")); -# endif - - locale_setblanks (); - -#endif - return 1; -} - -/* Translate the contents of STRING, a $"..." quoted string, according - to the current locale. In the `C' or `POSIX' locale, or if gettext() - is not available, the passed string is returned unchanged. The - length of the translated string is returned in LENP, if non-null. */ -char * -localetrans (string, len, lenp) - char *string; - int len, *lenp; -{ - char *locale, *t; - char *translated; - int tlen; - - /* Don't try to translate null strings. */ - if (string == 0 || *string == 0) - { - if (lenp) - *lenp = 0; - return ((char *)NULL); - } - - locale = get_locale_var ("LC_MESSAGES"); - - /* If we don't have setlocale() or the current locale is `C' or `POSIX', - just return the string. If we don't have gettext(), there's no use - doing anything else. */ - if (locale == 0 || locale[0] == '\0' || - (locale[0] == 'C' && locale[1] == '\0') || STREQ (locale, "POSIX")) - { - t = (char *)xmalloc (len + 1); - strcpy (t, string); - if (lenp) - *lenp = len; - return (t); - } - - /* Now try to translate it. */ - if (default_domain && *default_domain) - translated = dgettext (default_domain, string); - else - translated = string; - - if (translated == string) /* gettext returns its argument if untranslatable */ - { - t = (char *)xmalloc (len + 1); - strcpy (t, string); - if (lenp) - *lenp = len; - } - else - { - tlen = strlen (translated); - t = (char *)xmalloc (tlen + 1); - strcpy (t, translated); - if (lenp) - *lenp = tlen; - } - return (t); -} - -/* Change a bash string into a string suitable for inclusion in a `po' file. - This backslash-escapes `"' and `\' and changes newlines into \\\n"\n". */ -char * -mk_msgstr (string, foundnlp) - char *string; - int *foundnlp; -{ - register int c, len; - char *result, *r, *s; - - for (len = 0, s = string; s && *s; s++) - { - len++; - if (*s == '"' || *s == '\\') - len++; - else if (*s == '\n') - len += 5; - } - - r = result = (char *)xmalloc (len + 3); - *r++ = '"'; - - for (s = string; s && (c = *s); s++) - { - if (c == '\n') /* -> \n"" */ - { - *r++ = '\\'; - *r++ = 'n'; - *r++ = '"'; - *r++ = '\n'; - *r++ = '"'; - if (foundnlp) - *foundnlp = 1; - continue; - } - if (c == '"' || c == '\\') - *r++ = '\\'; - *r++ = c; - } - - *r++ = '"'; - *r++ = '\0'; - - return result; -} - -/* $"..." -- Translate the portion of STRING between START and END - according to current locale using gettext (if available) and return - the result. The caller will take care of leaving the quotes intact. - The string will be left without the leading `$' by the caller. - If translation is performed, the translated string will be double-quoted - by the caller. The length of the translated string is returned in LENP, - if non-null. */ -char * -localeexpand (string, start, end, lineno, lenp) - char *string; - int start, end, lineno, *lenp; -{ - int len, tlen, foundnl; - char *temp, *t, *t2; - - temp = (char *)xmalloc (end - start + 1); - for (tlen = 0, len = start; len < end; ) - temp[tlen++] = string[len++]; - temp[tlen] = '\0'; - - /* If we're just dumping translatable strings, don't do anything with the - string itself, but if we're dumping in `po' file format, convert it into - a form more palatable to gettext(3) and friends by quoting `"' and `\' - with backslashes and converting into `\n""'. If we find a - newline in TEMP, we first output a `msgid ""' line and then the - translated string; otherwise we output the `msgid' and translated - string all on one line. */ - if (dump_translatable_strings) - { - if (dump_po_strings) - { - foundnl = 0; - t = mk_msgstr (temp, &foundnl); - t2 = foundnl ? "\"\"\n" : ""; - - printf ("#: %s:%d\nmsgid %s%s\nmsgstr \"\"\n", - yy_input_name (), lineno, t2, t); - free (t); - } - else - printf ("\"%s\"\n", temp); - - if (lenp) - *lenp = tlen; - return (temp); - } - else if (*temp) - { - t = localetrans (temp, tlen, &len); - free (temp); - if (lenp) - *lenp = len; - return (t); - } - else - { - if (lenp) - *lenp = 0; - return (temp); - } -} - -/* Set every character in the character class to be a shell break - character for the lexical analyzer when the locale changes. */ -static void -locale_setblanks () -{ - int x; - - for (x = 0; x < sh_syntabsiz; x++) - { - if (isblank (x)) - sh_syntaxtab[x] |= CSHBRK|CBLANK; - else if (member (x, shell_break_chars)) - { - sh_syntaxtab[x] |= CSHBRK; - sh_syntaxtab[x] &= ~CBLANK; - } - else - sh_syntaxtab[x] &= ~(CSHBRK|CBLANK); - } -} diff --git a/mailcheck.c~ b/mailcheck.c~ deleted file mode 100644 index 93b3167ea..000000000 --- a/mailcheck.c~ +++ /dev/null @@ -1,481 +0,0 @@ -/* mailcheck.c -- The check is in the mail... */ - -/* 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 -#include "bashtypes.h" -#include "posixstat.h" -#ifndef _MINIX -# include -#endif -#if defined (HAVE_UNISTD_H) -# include -#endif -#include "posixtime.h" -#include "bashansi.h" -#include "bashintl.h" - -#include "shell.h" -#include "execute_cmd.h" -#include "mailcheck.h" -#include - -/* Values for flags word in struct _fileinfo */ -#define MBOX_INITIALIZED 0x01 - -extern int mailstat __P((const char *, struct stat *)); - -typedef struct _fileinfo { - char *name; - char *msg; - time_t access_time; - time_t mod_time; - off_t file_size; - int flags; -} FILEINFO; - -/* The list of remembered mail files. */ -static FILEINFO **mailfiles = (FILEINFO **)NULL; - -/* Number of mail files that we have. */ -static int mailfiles_count; - -/* The last known time that mail was checked. */ -static time_t last_time_mail_checked; - -/* Non-zero means warn if a mail file has been read since last checked. */ -int mail_warning; - -static int find_mail_file __P((char *)); -static void init_mail_file __P((int)); -static void update_mail_file __P((int)); -static int add_mail_file __P((char *, char *)); - -static FILEINFO *alloc_mail_file __P((char *, char *)); -static void dispose_mail_file __P((FILEINFO *)); - -static int file_mod_date_changed __P((int)); -static int file_access_date_changed __P((int)); -static int file_has_grown __P((int)); - -static char *parse_mailpath_spec __P((char *)); - -/* Returns non-zero if it is time to check mail. */ -int -time_to_check_mail () -{ - char *temp; - time_t now; - intmax_t seconds; - - temp = get_string_value ("MAILCHECK"); - - /* Negative number, or non-numbers (such as empty string) cause no - checking to take place. */ - if (temp == 0 || legal_number (temp, &seconds) == 0 || seconds < 0) - return (0); - - now = NOW; - /* Time to check if MAILCHECK is explicitly set to zero, or if enough - time has passed since the last check. */ - return (seconds == 0 || ((now - last_time_mail_checked) >= seconds)); -} - -/* Okay, we have checked the mail. Perhaps I should make this function - go away. */ -void -reset_mail_timer () -{ - last_time_mail_checked = NOW; -} - -/* Locate a file in the list. Return index of - entry, or -1 if not found. */ -static int -find_mail_file (file) - char *file; -{ - register int i; - - for (i = 0; i < mailfiles_count; i++) - if (STREQ (mailfiles[i]->name, file)) - return i; - - return -1; -} - -#define RESET_MAIL_FILE(i) \ - do \ - { \ - mailfiles[i]->access_time = mailfiles[i]->mod_time = 0; \ - mailfiles[i]->file_size = 0; \ - mailfiles[i]->flags = 0; \ - } \ - while (0) - -#define UPDATE_MAIL_FILE(i, finfo) \ - do \ - { \ - mailfiles[i]->access_time = finfo.st_atime; \ - mailfiles[i]->mod_time = finfo.st_mtime; \ - mailfiles[i]->file_size = finfo.st_size; \ - mailfiles[i]->flags |= MBOX_INITIALIZED; \ - } \ - while (0) - -static void -init_mail_file (i) - int i; -{ - RESET_MAIL_FILE (i); -} - -static void -update_mail_file (i) - int i; -{ - char *file; - struct stat finfo; - - file = mailfiles[i]->name; - if (mailstat (file, &finfo) == 0) - UPDATE_MAIL_FILE (i, finfo); - else - RESET_MAIL_FILE (i); -} - -/* Add this file to the list of remembered files and return its index - in the list of mail files. */ -static int -add_mail_file (file, msg) - char *file, *msg; -{ - struct stat finfo; - char *filename; - int i; - - filename = full_pathname (file); - i = find_mail_file (filename); - if (i >= 0) - { - if (mailstat (filename, &finfo) == 0) - UPDATE_MAIL_FILE (i, finfo); - - free (filename); - return i; - } - - i = mailfiles_count++; - mailfiles = (FILEINFO **)xrealloc - (mailfiles, mailfiles_count * sizeof (FILEINFO *)); - - mailfiles[i] = alloc_mail_file (filename, msg); - init_mail_file (i); - - return i; -} - -/* Reset the existing mail files access and modification times to zero. */ -void -reset_mail_files () -{ - register int i; - - for (i = 0; i < mailfiles_count; i++) - RESET_MAIL_FILE (i); -} - -static FILEINFO * -alloc_mail_file (filename, msg) - char *filename, *msg; -{ - FILEINFO *mf; - - mf = (FILEINFO *)xmalloc (sizeof (FILEINFO)); - mf->name = filename; - mf->msg = msg ? savestring (msg) : (char *)NULL; - mf->flags = 0; - - return mf; -} - -static void -dispose_mail_file (mf) - FILEINFO *mf; -{ - free (mf->name); - FREE (mf->msg); - free (mf); -} - -/* Free the information that we have about the remembered mail files. */ -void -free_mail_files () -{ - register int i; - - for (i = 0; i < mailfiles_count; i++) - dispose_mail_file (mailfiles[i]); - - if (mailfiles) - free (mailfiles); - - mailfiles_count = 0; - mailfiles = (FILEINFO **)NULL; -} - -void -init_mail_dates () -{ - if (mailfiles == 0) - remember_mail_dates (); -} - -/* Return non-zero if FILE's mod date has changed and it has not been - accessed since modified. If the size has dropped to zero, reset - the cached mail file info. */ -static int -file_mod_date_changed (i) - int i; -{ - time_t mtime; - struct stat finfo; - char *file; - - file = mailfiles[i]->name; - mtime = mailfiles[i]->mod_time; - - if ((mailstat (file, &finfo) == 0) && (finfo.st_size > 0)) - return (mtime != finfo.st_mtime); - - if (finfo.st_size == 0 && mailfiles[i]->file_size > 0) - UPDATE_MAIL_FILE (i, finfo); - - return (0); -} - -/* Return non-zero if FILE's access date has changed. */ -static int -file_access_date_changed (i) - int i; -{ - time_t atime; - struct stat finfo; - char *file; - - file = mailfiles[i]->name; - atime = mailfiles[i]->access_time; - - if ((mailstat (file, &finfo) == 0) && (finfo.st_size > 0)) - return (atime != finfo.st_atime); - - return (0); -} - -/* Return non-zero if FILE's size has increased. */ -static int -file_has_grown (i) - int i; -{ - off_t size; - struct stat finfo; - char *file; - - file = mailfiles[i]->name; - size = mailfiles[i]->file_size; - - return ((mailstat (file, &finfo) == 0) && (finfo.st_size > size)); -} - -/* Take an element from $MAILPATH and return the portion from - the first unquoted `?' or `%' to the end of the string. This is the - message to be printed when the file contents change. */ -static char * -parse_mailpath_spec (str) - char *str; -{ - char *s; - int pass_next; - - for (s = str, pass_next = 0; s && *s; s++) - { - if (pass_next) - { - pass_next = 0; - continue; - } - if (*s == '\\') - { - pass_next++; - continue; - } - if (*s == '?' || *s == '%') - return s; - } - return ((char *)NULL); -} - -char * -make_default_mailpath () -{ -#if defined (DEFAULT_MAIL_DIRECTORY) - char *mp; - - get_current_user_info (); - mp = (char *)xmalloc (2 + sizeof (DEFAULT_MAIL_DIRECTORY) + strlen (current_user.user_name)); - strcpy (mp, DEFAULT_MAIL_DIRECTORY); - mp[sizeof(DEFAULT_MAIL_DIRECTORY) - 1] = '/'; - strcpy (mp + sizeof (DEFAULT_MAIL_DIRECTORY), current_user.user_name); - return (mp); -#else - return ((char *)NULL); -#endif -} - -/* Remember the dates of the files specified by MAILPATH, or if there is - no MAILPATH, by the file specified in MAIL. If neither exists, use a - default value, which we randomly concoct from using Unix. */ - -void -remember_mail_dates () -{ - char *mailpaths; - char *mailfile, *mp; - int i = 0; - - mailpaths = get_string_value ("MAILPATH"); - - /* If no $MAILPATH, but $MAIL, use that as a single filename to check. */ - if (mailpaths == 0 && (mailpaths = get_string_value ("MAIL"))) - { - add_mail_file (mailpaths, (char *)NULL); - return; - } - - if (mailpaths == 0) - { - mailpaths = make_default_mailpath (); - if (mailpaths) - { - add_mail_file (mailpaths, (char *)NULL); - free (mailpaths); - } - return; - } - - while (mailfile = extract_colon_unit (mailpaths, &i)) - { - mp = parse_mailpath_spec (mailfile); - if (mp && *mp) - *mp++ = '\0'; - add_mail_file (mailfile, mp); - free (mailfile); - } -} - -/* check_mail () is useful for more than just checking mail. Since it has - the paranoids dream ability of telling you when someone has read your - mail, it can just as easily be used to tell you when someones .profile - file has been read, thus letting one know when someone else has logged - in. Pretty good, huh? */ - -/* Check for mail in some files. If the modification date of any - of the files in MAILPATH has changed since we last did a - remember_mail_dates () then mention that the user has mail. - Special hack: If the variable MAIL_WARNING is non-zero and the - mail file has been accessed since the last time we remembered, then - the message "The mail in has been read" is printed. */ -void -check_mail () -{ - char *current_mail_file, *message; - int i, use_user_notification; - char *dollar_underscore, *temp; - - dollar_underscore = get_string_value ("_"); - if (dollar_underscore) - dollar_underscore = savestring (dollar_underscore); - - for (i = 0; i < mailfiles_count; i++) - { - current_mail_file = mailfiles[i]->name; - - if (*current_mail_file == '\0') - continue; - - if (file_mod_date_changed (i)) - { - int file_is_bigger; - - use_user_notification = mailfiles[i]->msg != (char *)NULL; - message = mailfiles[i]->msg ? mailfiles[i]->msg : _("You have mail in $_"); - - bind_variable ("_", current_mail_file, 0); - -#define atime mailfiles[i]->access_time -#define mtime mailfiles[i]->mod_time - - /* Have to compute this before the call to update_mail_file, which - resets all the information. */ - file_is_bigger = file_has_grown (i); - - update_mail_file (i); - - /* If the user has just run a program which manipulates the - mail file, then don't bother explaining that the mail - file has been manipulated. Since some systems don't change - the access time to be equal to the modification time when - the mail in the file is manipulated, check the size also. If - the file has not grown, continue. */ - if ((atime >= mtime) && !file_is_bigger) - continue; - - /* If the mod time is later than the access time and the file - has grown, note the fact that this is *new* mail. */ - if (use_user_notification == 0 && (atime < mtime) && file_is_bigger) - message = _("You have new mail in $_"); -#undef atime -#undef mtime - - if (temp = expand_string_to_string (message, Q_DOUBLE_QUOTES)) - { - puts (temp); - free (temp); - } - else - putchar ('\n'); - } - - if (mail_warning && file_access_date_changed (i)) - { - update_mail_file (i); - printf (_("The mail in %s has been read\n"), current_mail_file); - } - } - - if (dollar_underscore) - { - bind_variable ("_", dollar_underscore, 0); - free (dollar_underscore); - } - else - unbind_variable ("_"); -} diff --git a/mailcheck.h~ b/mailcheck.h~ deleted file mode 100644 index 1c6f24ff9..000000000 --- a/mailcheck.h~ +++ /dev/null @@ -1,33 +0,0 @@ -/* mailcheck.h -- variables and function declarations for mail checking. */ - -/* Copyright (C) 1987,1991 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 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 (_MAILCHECK_H_) -#define _MAILCHECK_H_ - -/* Functions from mailcheck.c */ -extern int time_to_check_mail __P((void)); -extern void reset_mail_timer __P((void)); -extern void reset_mail_files __P((void)); -extern void free_mail_files __P((void)); -extern char *make_default_mailpath __P((void)); -extern void remember_mail_dates __P((void)); -extern void check_mail __P((void)); - -#endif /* _MAILCHECK_H */ diff --git a/make_cmd.c~ b/make_cmd.c~ deleted file mode 100644 index 76a3bbfb5..000000000 --- a/make_cmd.c~ +++ /dev/null @@ -1,878 +0,0 @@ -/* make_cmd.c -- Functions for making instances of the various - parser constructs. */ - -/* Copyright (C) 1989-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 -#include "bashtypes.h" -#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "filecntl.h" -#include "bashansi.h" -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashintl.h" - -#include "syntax.h" -#include "parser.h" -#include "command.h" -#include "general.h" -#include "error.h" -#include "flags.h" -#include "make_cmd.h" -#include "dispose_cmd.h" -#include "variables.h" -#include "subst.h" -#include "input.h" -#include "ocache.h" -#include "externs.h" - -#if defined (JOB_CONTROL) -#include "jobs.h" -#endif - -#include "shmbutil.h" - -extern int line_number, current_command_line_count; -extern int last_command_exit_value; - -/* Object caching */ -sh_obj_cache_t wdcache = {0, 0, 0}; -sh_obj_cache_t wlcache = {0, 0, 0}; - -#define WDCACHESIZE 60 -#define WLCACHESIZE 60 - -static COMMAND *make_for_or_select __P((enum command_type, WORD_DESC *, WORD_LIST *, COMMAND *, int)); -#if defined (ARITH_FOR_COMMAND) -static WORD_LIST *make_arith_for_expr __P((char *)); -#endif -static COMMAND *make_until_or_while __P((enum command_type, COMMAND *, COMMAND *)); - -void -cmd_init () -{ - ocache_create (wdcache, WORD_DESC, WDCACHESIZE); - ocache_create (wlcache, WORD_LIST, WLCACHESIZE); -} - -WORD_DESC * -alloc_word_desc () -{ - WORD_DESC *temp; - - ocache_alloc (wdcache, WORD_DESC, temp); - temp->flags = 0; - temp->word = 0; - return temp; -} - -WORD_DESC * -make_bare_word (string) - const char *string; -{ - WORD_DESC *temp; - - temp = alloc_word_desc (); - - if (*string) - temp->word = savestring (string); - else - { - temp->word = (char *)xmalloc (1); - temp->word[0] = '\0'; - } - - return (temp); -} - -WORD_DESC * -make_word_flags (w, string) - WORD_DESC *w; - const char *string; -{ - register int i; - size_t slen; - DECLARE_MBSTATE; - - i = 0; - slen = strlen (string); - while (i < slen) - { - switch (string[i]) - { - case '$': - w->flags |= W_HASDOLLAR; - break; - case '\\': - break; /* continue the loop */ - case '\'': - case '`': - case '"': - w->flags |= W_QUOTED; - break; - } - - ADVANCE_CHAR (string, slen, i); - } - - return (w); -} - -WORD_DESC * -make_word (string) - const char *string; -{ - WORD_DESC *temp; - - temp = make_bare_word (string); - return (make_word_flags (temp, string)); -} - -WORD_DESC * -make_word_from_token (token) - int token; -{ - char tokenizer[2]; - - tokenizer[0] = token; - tokenizer[1] = '\0'; - - return (make_word (tokenizer)); -} - -WORD_LIST * -make_word_list (word, wlink) - WORD_DESC *word; - WORD_LIST *wlink; -{ - WORD_LIST *temp; - - ocache_alloc (wlcache, WORD_LIST, temp); - - temp->word = word; - temp->next = wlink; - return (temp); -} - -COMMAND * -make_command (type, pointer) - enum command_type type; - SIMPLE_COM *pointer; -{ - COMMAND *temp; - - temp = (COMMAND *)xmalloc (sizeof (COMMAND)); - temp->type = type; - temp->value.Simple = pointer; - temp->value.Simple->flags = temp->flags = 0; - temp->redirects = (REDIRECT *)NULL; - return (temp); -} - -COMMAND * -command_connect (com1, com2, connector) - COMMAND *com1, *com2; - int connector; -{ - CONNECTION *temp; - - temp = (CONNECTION *)xmalloc (sizeof (CONNECTION)); - temp->connector = connector; - temp->first = com1; - temp->second = com2; - return (make_command (cm_connection, (SIMPLE_COM *)temp)); -} - -static COMMAND * -make_for_or_select (type, name, map_list, action, lineno) - enum command_type type; - WORD_DESC *name; - WORD_LIST *map_list; - COMMAND *action; - int lineno; -{ - FOR_COM *temp; - - temp = (FOR_COM *)xmalloc (sizeof (FOR_COM)); - temp->flags = 0; - temp->name = name; - temp->line = lineno; - temp->map_list = map_list; - temp->action = action; - return (make_command (type, (SIMPLE_COM *)temp)); -} - -COMMAND * -make_for_command (name, map_list, action, lineno) - WORD_DESC *name; - WORD_LIST *map_list; - COMMAND *action; - int lineno; -{ - return (make_for_or_select (cm_for, name, map_list, action, lineno)); -} - -COMMAND * -make_select_command (name, map_list, action, lineno) - WORD_DESC *name; - WORD_LIST *map_list; - COMMAND *action; - int lineno; -{ -#if defined (SELECT_COMMAND) - return (make_for_or_select (cm_select, name, map_list, action, lineno)); -#else - last_command_exit_value = 2; - return ((COMMAND *)NULL); -#endif -} - -#if defined (ARITH_FOR_COMMAND) -static WORD_LIST * -make_arith_for_expr (s) - char *s; -{ - WORD_LIST *result; - WORD_DESC *wd; - - if (s == 0 || *s == '\0') - return ((WORD_LIST *)NULL); - wd = make_word (s); - wd->flags |= W_NOGLOB|W_NOSPLIT|W_QUOTED|W_DQUOTE; /* no word splitting or globbing */ - result = make_word_list (wd, (WORD_LIST *)NULL); - return result; -} -#endif - -/* Note that this function calls dispose_words on EXPRS, since it doesn't - use the word list directly. We free it here rather than at the caller - because no other function in this file requires that the caller free - any arguments. */ -COMMAND * -make_arith_for_command (exprs, action, lineno) - WORD_LIST *exprs; - COMMAND *action; - int lineno; -{ -#if defined (ARITH_FOR_COMMAND) - ARITH_FOR_COM *temp; - WORD_LIST *init, *test, *step; - char *s, *t, *start; - int nsemi; - - init = test = step = (WORD_LIST *)NULL; - /* Parse the string into the three component sub-expressions. */ - start = t = s = exprs->word->word; - for (nsemi = 0; ;) - { - /* skip whitespace at the start of each sub-expression. */ - while (whitespace (*s)) - s++; - start = s; - /* skip to the semicolon or EOS */ - while (*s && *s != ';') - s++; - - t = (s > start) ? substring (start, 0, s - start) : (char *)NULL; - - nsemi++; - switch (nsemi) - { - case 1: - init = make_arith_for_expr (t); - break; - case 2: - test = make_arith_for_expr (t); - break; - case 3: - step = make_arith_for_expr (t); - break; - } - - FREE (t); - if (*s == '\0') - break; - s++; /* skip over semicolon */ - } - - if (nsemi != 3) - { - if (nsemi < 3) - parser_error (lineno, _("syntax error: arithmetic expression required")); - else - parser_error (lineno, _("syntax error: `;' unexpected")); - parser_error (lineno, _("syntax error: `((%s))'"), exprs->word->word); - last_command_exit_value = 2; - return ((COMMAND *)NULL); - } - - temp = (ARITH_FOR_COM *)xmalloc (sizeof (ARITH_FOR_COM)); - temp->flags = 0; - temp->line = lineno; - temp->init = init ? init : make_arith_for_expr ("1"); - temp->test = test ? test : make_arith_for_expr ("1"); - temp->step = step ? step : make_arith_for_expr ("1"); - temp->action = action; - - dispose_words (exprs); - return (make_command (cm_arith_for, (SIMPLE_COM *)temp)); -#else - dispose_words (exprs); - last_command_exit_value = 2; - return ((COMMAND *)NULL); -#endif /* ARITH_FOR_COMMAND */ -} - -COMMAND * -make_group_command (command) - COMMAND *command; -{ - GROUP_COM *temp; - - temp = (GROUP_COM *)xmalloc (sizeof (GROUP_COM)); - temp->command = command; - return (make_command (cm_group, (SIMPLE_COM *)temp)); -} - -COMMAND * -make_case_command (word, clauses, lineno) - WORD_DESC *word; - PATTERN_LIST *clauses; - int lineno; -{ - CASE_COM *temp; - - temp = (CASE_COM *)xmalloc (sizeof (CASE_COM)); - temp->flags = 0; - temp->line = lineno; - temp->word = word; - temp->clauses = REVERSE_LIST (clauses, PATTERN_LIST *); - return (make_command (cm_case, (SIMPLE_COM *)temp)); -} - -PATTERN_LIST * -make_pattern_list (patterns, action) - WORD_LIST *patterns; - COMMAND *action; -{ - PATTERN_LIST *temp; - - temp = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST)); - temp->patterns = REVERSE_LIST (patterns, WORD_LIST *); - temp->action = action; - temp->next = NULL; - temp->flags = 0; - return (temp); -} - -COMMAND * -make_if_command (test, true_case, false_case) - COMMAND *test, *true_case, *false_case; -{ - IF_COM *temp; - - temp = (IF_COM *)xmalloc (sizeof (IF_COM)); - temp->flags = 0; - temp->test = test; - temp->true_case = true_case; - temp->false_case = false_case; - return (make_command (cm_if, (SIMPLE_COM *)temp)); -} - -static COMMAND * -make_until_or_while (which, test, action) - enum command_type which; - COMMAND *test, *action; -{ - WHILE_COM *temp; - - temp = (WHILE_COM *)xmalloc (sizeof (WHILE_COM)); - temp->flags = 0; - temp->test = test; - temp->action = action; - return (make_command (which, (SIMPLE_COM *)temp)); -} - -COMMAND * -make_while_command (test, action) - COMMAND *test, *action; -{ - return (make_until_or_while (cm_while, test, action)); -} - -COMMAND * -make_until_command (test, action) - COMMAND *test, *action; -{ - return (make_until_or_while (cm_until, test, action)); -} - -COMMAND * -make_arith_command (exp) - WORD_LIST *exp; -{ -#if defined (DPAREN_ARITHMETIC) - COMMAND *command; - ARITH_COM *temp; - - command = (COMMAND *)xmalloc (sizeof (COMMAND)); - command->value.Arith = temp = (ARITH_COM *)xmalloc (sizeof (ARITH_COM)); - - temp->flags = 0; - temp->line = line_number; - temp->exp = exp; - - command->type = cm_arith; - command->redirects = (REDIRECT *)NULL; - command->flags = 0; - - return (command); -#else - last_command_exit_value = 2; - return ((COMMAND *)NULL); -#endif -} - -#if defined (COND_COMMAND) -struct cond_com * -make_cond_node (type, op, left, right) - int type; - WORD_DESC *op; - struct cond_com *left, *right; -{ - COND_COM *temp; - - temp = (COND_COM *)xmalloc (sizeof (COND_COM)); - temp->flags = 0; - temp->line = line_number; - temp->type = type; - temp->op = op; - temp->left = left; - temp->right = right; - - return (temp); -} -#endif - -COMMAND * -make_cond_command (cond_node) - COND_COM *cond_node; -{ -#if defined (COND_COMMAND) - COMMAND *command; - - command = (COMMAND *)xmalloc (sizeof (COMMAND)); - command->value.Cond = cond_node; - - command->type = cm_cond; - command->redirects = (REDIRECT *)NULL; - command->flags = 0; - command->line = cond_node ? cond_node->line : 0; - - return (command); -#else - last_command_exit_value = 2; - return ((COMMAND *)NULL); -#endif -} - -COMMAND * -make_bare_simple_command () -{ - COMMAND *command; - SIMPLE_COM *temp; - - command = (COMMAND *)xmalloc (sizeof (COMMAND)); - command->value.Simple = temp = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM)); - - temp->flags = 0; - temp->line = line_number; - temp->words = (WORD_LIST *)NULL; - temp->redirects = (REDIRECT *)NULL; - - command->type = cm_simple; - command->redirects = (REDIRECT *)NULL; - command->flags = 0; - - return (command); -} - -/* Return a command which is the connection of the word or redirection - in ELEMENT, and the command * or NULL in COMMAND. */ -COMMAND * -make_simple_command (element, command) - ELEMENT element; - COMMAND *command; -{ - /* If we are starting from scratch, then make the initial command - structure. Also note that we have to fill in all the slots, since - malloc doesn't return zeroed space. */ - if (!command) - command = make_bare_simple_command (); - - if (element.word) - command->value.Simple->words = make_word_list (element.word, command->value.Simple->words); - else if (element.redirect) - { - REDIRECT *r = element.redirect; - /* Due to the way <> is implemented, there may be more than a single - redirection in element.redirect. We just follow the chain as far - as it goes, and hook onto the end. */ - while (r->next) - r = r->next; - r->next = command->value.Simple->redirects; - command->value.Simple->redirects = element.redirect; - } - return (command); -} - -/* Because we are Bourne compatible, we read the input for this - << or <<- redirection now, from wherever input is coming from. - We store the input read into a WORD_DESC. Replace the text of - the redirectee.word with the new input text. If <<- is on, - then remove leading TABS from each line. */ -void -make_here_document (temp, lineno) - REDIRECT *temp; - int lineno; -{ - int kill_leading, redir_len; - char *redir_word, *document, *full_line; - int document_index, document_size, delim_unquoted; - - if (temp->instruction != r_deblank_reading_until && - temp->instruction != r_reading_until) - { - internal_error (_("make_here_document: bad instruction type %d"), temp->instruction); - return; - } - - kill_leading = temp->instruction == r_deblank_reading_until; - - document = (char *)NULL; - document_index = document_size = 0; - - /* Quote removal is the only expansion performed on the delimiter - for here documents, making it an extremely special case. */ - redir_word = string_quote_removal (temp->redirectee.filename->word, 0); - - /* redirection_expand will return NULL if the expansion results in - multiple words or no words. Check for that here, and just abort - this here document if it does. */ - if (redir_word) - redir_len = strlen (redir_word); - else - { - temp->here_doc_eof = (char *)xmalloc (1); - temp->here_doc_eof[0] = '\0'; - goto document_done; - } - - free (temp->redirectee.filename->word); - temp->here_doc_eof = redir_word; - - /* Read lines from wherever lines are coming from. - For each line read, if kill_leading, then kill the - leading tab characters. - If the line matches redir_word exactly, then we have - manufactured the document. Otherwise, add the line to the - list of lines in the document. */ - - /* If the here-document delimiter was quoted, the lines should - be read verbatim from the input. If it was not quoted, we - need to perform backslash-quoted newline removal. */ - delim_unquoted = (temp->redirectee.filename->flags & W_QUOTED) == 0; - while (full_line = read_secondary_line (delim_unquoted)) - { - register char *line; - int len; - - line = full_line; - line_number++; - - /* If set -v is in effect, echo the line read. read_secondary_line/ - read_a_line leaves the newline at the end, so don't print another. */ - if (echo_input_at_read) - fprintf (stderr, "%s", line); - - if (kill_leading && *line) - { - /* Hack: To be compatible with some Bourne shells, we - check the word before stripping the whitespace. This - is a hack, though. */ - if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n') - goto document_done; - - while (*line == '\t') - line++; - } - - if (*line == 0) - continue; - - if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n') - goto document_done; - - len = strlen (line); - if (len + document_index >= document_size) - { - document_size = document_size ? 2 * (document_size + len) : len + 2; - document = (char *)xrealloc (document, document_size); - } - - /* len is guaranteed to be > 0 because of the check for line - being an empty string before the call to strlen. */ - FASTCOPY (line, document + document_index, len); - document_index += len; - } - - if (full_line == 0) - internal_warning (_("here-document at line %d delimited by end-of-file (wanted `%s')"), lineno, redir_word); - -document_done: - if (document) - document[document_index] = '\0'; - else - { - document = (char *)xmalloc (1); - document[0] = '\0'; - } - temp->redirectee.filename->word = document; -} - -/* Generate a REDIRECT from SOURCE, DEST, and INSTRUCTION. - INSTRUCTION is the instruction type, SOURCE is a file descriptor, - and DEST is a file descriptor or a WORD_DESC *. */ -REDIRECT * -make_redirection (source, instruction, dest_and_filename) - int source; - enum r_instruction instruction; - REDIRECTEE dest_and_filename; -{ - REDIRECT *temp; - WORD_DESC *w; - int wlen; - intmax_t lfd; - - temp = (REDIRECT *)xmalloc (sizeof (REDIRECT)); - - /* First do the common cases. */ - temp->redirector = source; - temp->redirectee = dest_and_filename; - temp->instruction = instruction; - temp->flags = 0; - temp->next = (REDIRECT *)NULL; - - switch (instruction) - { - - case r_output_direction: /* >foo */ - case r_output_force: /* >| foo */ - case r_err_and_out: /* &>filename */ - temp->flags = O_TRUNC | O_WRONLY | O_CREAT; - break; - - case r_appending_to: /* >>foo */ - case r_append_err_and_out: /* &>> filename */ - temp->flags = O_APPEND | O_WRONLY | O_CREAT; - break; - - case r_input_direction: /* flags = O_RDONLY; - break; - - case r_input_output: /* <>foo */ - temp->flags = O_RDWR | O_CREAT; - break; - - case r_deblank_reading_until: /* <<-foo */ - case r_reading_until: /* << foo */ - case r_reading_string: /* <<< foo */ - case r_close_this: /* <&- */ - case r_duplicating_input: /* 1<&2 */ - case r_duplicating_output: /* 1>&2 */ - break; - - /* the parser doesn't pass these. */ - case r_move_input: /* 1<&2- */ - case r_move_output: /* 1>&2- */ - case r_move_input_word: /* 1<&$foo- */ - case r_move_output_word: /* 1>&$foo- */ - break; - - /* The way the lexer works we have to do this here. */ - case r_duplicating_input_word: /* 1<&$foo */ - case r_duplicating_output_word: /* 1>&$foo */ - w = dest_and_filename.filename; - wlen = strlen (w->word) - 1; - if (w->word[wlen] == '-') /* Yuck */ - { - w->word[wlen] = '\0'; - if (all_digits (w->word) && legal_number (w->word, &lfd) && lfd == (int)lfd) - { - dispose_word (w); - temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input : r_move_output; - temp->redirectee.dest = lfd; - } - else - temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input_word : r_move_output_word; - } - - break; - - default: - programming_error (_("make_redirection: redirection instruction `%d' out of range"), instruction); - abort (); - break; - } - return (temp); -} - -COMMAND * -make_function_def (name, command, lineno, lstart) - WORD_DESC *name; - COMMAND *command; - int lineno, lstart; -{ - FUNCTION_DEF *temp; -#if defined (ARRAY_VARS) - SHELL_VAR *bash_source_v; - ARRAY *bash_source_a; -#endif - - temp = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF)); - temp->command = command; - temp->name = name; - temp->line = lineno; - temp->flags = 0; - command->line = lstart; - - /* Information used primarily for debugging. */ - temp->source_file = 0; -#if defined (ARRAY_VARS) - GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a); - if (bash_source_a && array_num_elements (bash_source_a) > 0) - temp->source_file = array_reference (bash_source_a, 0); -#endif -#if defined (DEBUGGER) - bind_function_def (name->word, temp); -#endif - - temp->source_file = 0; - return (make_command (cm_function_def, (SIMPLE_COM *)temp)); -} - -COMMAND * -make_subshell_command (command) - COMMAND *command; -{ - SUBSHELL_COM *temp; - - temp = (SUBSHELL_COM *)xmalloc (sizeof (SUBSHELL_COM)); - temp->command = command; - temp->flags = CMD_WANT_SUBSHELL; - return (make_command (cm_subshell, (SIMPLE_COM *)temp)); -} - -COMMAND * -make_coproc_command (name, command) - char *name; - COMMAND *command; -{ - COPROC_COM *temp; - - temp = (COPROC_COM *)xmalloc (sizeof (COPROC_COM)); - temp->name = savestring (name); - temp->command = command; - temp->flags = CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; - return (make_command (cm_coproc, (SIMPLE_COM *)temp)); -} - -/* Reverse the word list and redirection list in the simple command - has just been parsed. It seems simpler to do this here the one - time then by any other method that I can think of. */ -COMMAND * -clean_simple_command (command) - COMMAND *command; -{ - if (command->type != cm_simple) - command_error ("clean_simple_command", CMDERR_BADTYPE, command->type, 0); - else - { - command->value.Simple->words = - REVERSE_LIST (command->value.Simple->words, WORD_LIST *); - command->value.Simple->redirects = - REVERSE_LIST (command->value.Simple->redirects, REDIRECT *); - } - - return (command); -} - -/* The Yacc grammar productions have a problem, in that they take a - list followed by an ampersand (`&') and do a simple command connection, - making the entire list effectively asynchronous, instead of just - the last command. This means that when the list is executed, all - the commands have stdin set to /dev/null when job control is not - active, instead of just the last. This is wrong, and needs fixing - up. This function takes the `&' and applies it to the last command - in the list. This is done only for lists connected by `;'; it makes - `;' bind `tighter' than `&'. */ -COMMAND * -connect_async_list (command, command2, connector) - COMMAND *command, *command2; - int connector; -{ - COMMAND *t, *t1, *t2; - - t1 = command; - t = command->value.Connection->second; - - if (!t || (command->flags & CMD_WANT_SUBSHELL) || - command->value.Connection->connector != ';') - { - t = command_connect (command, command2, connector); - return t; - } - - /* This is just defensive programming. The Yacc precedence rules - will generally hand this function a command where t points directly - to the command we want (e.g. given a ; b ; c ; d &, t1 will point - to the `a ; b ; c' list and t will be the `d'). We only want to do - this if the list is not being executed as a unit in the background - with `( ... )', so we have to check for CMD_WANT_SUBSHELL. That's - the only way to tell. */ - while (((t->flags & CMD_WANT_SUBSHELL) == 0) && t->type == cm_connection && - t->value.Connection->connector == ';') - { - t1 = t; - t = t->value.Connection->second; - } - /* Now we have t pointing to the last command in the list, and - t1->value.Connection->second == t. */ - t2 = command_connect (t, command2, connector); - t1->value.Connection->second = t2; - return command; -} diff --git a/make_cmd.h~ b/make_cmd.h~ deleted file mode 100644 index 2c3b3a816..000000000 --- a/make_cmd.h~ +++ /dev/null @@ -1,69 +0,0 @@ -/* make_cmd.h -- Declarations of functions found in make_cmd.c */ - -/* Copyright (C) 1993-2005 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#if !defined (_MAKE_CMD_H_) -#define _MAKE_CMD_H_ - -#include "stdc.h" - -extern void cmd_init __P((void)); - -extern WORD_DESC *alloc_word_desc __P((void)); -extern WORD_DESC *make_bare_word __P((const char *)); -extern WORD_DESC *make_word_flags __P((WORD_DESC *, const char *)); -extern WORD_DESC *make_word __P((const char *)); -extern WORD_DESC *make_word_from_token __P((int)); - -extern WORD_LIST *make_word_list __P((WORD_DESC *, WORD_LIST *)); - -#define add_string_to_list(s, l) make_word_list (make_word(s), (l)) - -extern COMMAND *make_command __P((enum command_type, SIMPLE_COM *)); -extern COMMAND *command_connect __P((COMMAND *, COMMAND *, int)); -extern COMMAND *make_for_command __P((WORD_DESC *, WORD_LIST *, COMMAND *, int)); -extern COMMAND *make_group_command __P((COMMAND *)); -extern COMMAND *make_case_command __P((WORD_DESC *, PATTERN_LIST *, int)); -extern PATTERN_LIST *make_pattern_list __P((WORD_LIST *, COMMAND *)); -extern COMMAND *make_if_command __P((COMMAND *, COMMAND *, COMMAND *)); -extern COMMAND *make_while_command __P((COMMAND *, COMMAND *)); -extern COMMAND *make_until_command __P((COMMAND *, COMMAND *)); -extern COMMAND *make_bare_simple_command __P((void)); -extern COMMAND *make_simple_command __P((ELEMENT, COMMAND *)); -extern void make_here_document __P((REDIRECT *, int)); -extern REDIRECT *make_redirection __P((int, enum r_instruction, REDIRECTEE)); -extern COMMAND *make_function_def __P((WORD_DESC *, COMMAND *, int, int)); -extern COMMAND *clean_simple_command __P((COMMAND *)); - -extern COMMAND *make_arith_command __P((WORD_LIST *)); - -extern COMMAND *make_select_command __P((WORD_DESC *, WORD_LIST *, COMMAND *, int)); - -#if defined (COND_COMMAND) -extern COND_COM *make_cond_node __P((int, WORD_DESC *, COND_COM *, COND_COM *)); -extern COMMAND *make_cond_command __P((COND_COM *)); -#endif - -extern COMMAND *make_arith_for_command __P((WORD_LIST *, COMMAND *, int)); - -extern COMMAND *make_subshell_command __P((COMMAND *)); - -extern COMMAND *connect_async_list __P((COMMAND *, COMMAND *, int)); - -#endif /* !_MAKE_CMD_H */ diff --git a/mksyntax.c~ b/mksyntax.c~ deleted file mode 100644 index 1bbaa424e..000000000 --- a/mksyntax.c~ +++ /dev/null @@ -1,415 +0,0 @@ -/* - * mksyntax.c - construct shell syntax table for fast char attribute lookup. - */ - -/* Copyright (C) 2000-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 -#include "bashansi.h" -#include "chartypes.h" -#include - -#ifdef HAVE_UNISTD_H -# include -#endif - -#include "syntax.h" - -extern int optind; -extern char *optarg; - -#ifndef errno -extern int errno; -#endif - -#ifndef HAVE_STRERROR -extern char *strerror(); -#endif - -struct wordflag { - int flag; - char *fstr; -} wordflags[] = { - { CWORD, "CWORD" }, - { CSHMETA, "CSHMETA" }, - { CSHBRK, "CSHBRK" }, - { CBACKQ, "CBACKQ" }, - { CQUOTE, "CQUOTE" }, - { CSPECL, "CSPECL" }, - { CEXP, "CEXP" }, - { CBSDQUOTE, "CBSDQUOTE" }, - { CBSHDOC, "CBSHDOC" }, - { CGLOB, "CGLOB" }, - { CXGLOB, "CXGLOB" }, - { CXQUOTE, "CXQUOTE" }, - { CSPECVAR, "CSPECVAR" }, - { CSUBSTOP, "CSUBSTOP" }, - { CBLANK, "CBLANK" }, -}; - -#define N_WFLAGS (sizeof (wordflags) / sizeof (wordflags[0])) -#define SYNSIZE 256 - -int lsyntax[SYNSIZE]; -int debug; -char *progname; - -char preamble[] = "\ -/*\n\ - * This file was generated by mksyntax. DO NOT EDIT.\n\ - */\n\ -\n"; - -char includes[] = "\ -#include \"config.h\"\n\ -#include \"stdc.h\"\n\ -#include \"syntax.h\"\n\n"; - -static void -usage() -{ - fprintf (stderr, _("%s: usage: %s [-d] [-o filename]\n"), progname, progname); - exit (2); -} - -#ifdef INCLUDE_UNUSED -static int -getcflag (s) - char *s; -{ - int i; - - for (i = 0; i < N_WFLAGS; i++) - if (strcmp (s, wordflags[i].fstr) == 0) - return wordflags[i].flag; - return -1; -} -#endif - -static char * -cdesc (i) - int i; -{ - static char xbuf[16]; - - if (i == ' ') - return "SPC"; - else if (ISPRINT (i)) - { - xbuf[0] = i; - xbuf[1] = '\0'; - return (xbuf); - } - else if (i == CTLESC) - return "CTLESC"; - else if (i == CTLNUL) - return "CTLNUL"; - else if (i == '\033') /* ASCII */ - return "ESC"; - - xbuf[0] = '\\'; - xbuf[2] = '\0'; - - switch (i) - { -#ifdef __STDC__ - case '\a': xbuf[1] = 'a'; break; - case '\v': xbuf[1] = 'v'; break; -#else - case '\007': xbuf[1] = 'a'; break; - case 0x0B: xbuf[1] = 'v'; break; -#endif - case '\b': xbuf[1] = 'b'; break; - case '\f': xbuf[1] = 'f'; break; - case '\n': xbuf[1] = 'n'; break; - case '\r': xbuf[1] = 'r'; break; - case '\t': xbuf[1] = 't'; break; - default: sprintf (xbuf, "%d", i); break; - } - - return xbuf; -} - -static char * -getcstr (f) - int f; -{ - int i; - - for (i = 0; i < N_WFLAGS; i++) - if (f == wordflags[i].flag) - return (wordflags[i].fstr); - return ((char *)NULL); -} - -static void -addcstr (str, flag) - char *str; - int flag; -{ - char *s, *fstr; - unsigned char uc; - - for (s = str; s && *s; s++) - { - uc = *s; - - if (debug) - { - fstr = getcstr (flag); - fprintf(stderr, _("added %s for character %s\n"), fstr, cdesc(uc)); - } - - lsyntax[uc] |= flag; - } -} - -static void -addcchar (c, flag) - unsigned char c; - int flag; -{ - char *fstr; - - if (debug) - { - fstr = getcstr (flag); - fprintf (stderr, _("added %s for character %s\n"), fstr, cdesc(c)); - } - lsyntax[c] |= flag; -} - -static void -addblanks () -{ - register int i; - unsigned char uc; - - for (i = 0; i < SYNSIZE; i++) - { - uc = i; - /* Since we don't call setlocale(), this defaults to the "C" locale, and - the default blank characters will be space and tab. */ - if (isblank (uc)) - lsyntax[uc] |= CBLANK; - } -} - -/* load up the correct flag values in lsyntax */ -static void -load_lsyntax () -{ - /* shell metacharacters */ - addcstr (shell_meta_chars, CSHMETA); - - /* shell word break characters */ - addcstr (shell_break_chars, CSHBRK); - - addcchar ('`', CBACKQ); - - addcstr (shell_quote_chars, CQUOTE); - - addcchar (CTLESC, CSPECL); - addcchar (CTLNUL, CSPECL); - - addcstr (shell_exp_chars, CEXP); - - addcstr (slashify_in_quotes, CBSDQUOTE); - addcstr (slashify_in_here_document, CBSHDOC); - - addcstr (shell_glob_chars, CGLOB); - -#if defined (EXTENDED_GLOB) - addcstr (ext_glob_chars, CXGLOB); -#endif - - addcstr (shell_quote_chars, CXQUOTE); - addcchar ('\\', CXQUOTE); - - addcstr ("@*#?-$!", CSPECVAR); /* omits $0...$9 and $_ */ - - addcstr ("-=?+", CSUBSTOP); /* OP in ${paramOPword} */ - - addblanks (); -} - -static void -dump_lflags (fp, ind) - FILE *fp; - int ind; -{ - int xflags, first, i; - - xflags = lsyntax[ind]; - first = 1; - - if (xflags == 0) - fputs (wordflags[0].fstr, fp); - else - { - for (i = 1; i < N_WFLAGS; i++) - if (xflags & wordflags[i].flag) - { - if (first) - first = 0; - else - putc ('|', fp); - fputs (wordflags[i].fstr, fp); - } - } -} - -static void -wcomment (fp, i) - FILE *fp; - int i; -{ - fputs ("\t\t/* ", fp); - - fprintf (fp, "%s", cdesc(i)); - - fputs (" */", fp); -} - -static void -dump_lsyntax (fp) - FILE *fp; -{ - int i; - - fprintf (fp, "int sh_syntabsiz = %d;\n", SYNSIZE); - fprintf (fp, "int sh_syntaxtab[%d] = {\n", SYNSIZE); - - for (i = 0; i < SYNSIZE; i++) - { - putc ('\t', fp); - dump_lflags (fp, i); - putc (',', fp); - wcomment (fp, i); - putc ('\n', fp); - } - - fprintf (fp, "};\n"); -} - -int -main(argc, argv) - int argc; - char **argv; -{ - int opt, i; - char *filename; - FILE *fp; - - if ((progname = strrchr (argv[0], '/')) == 0) - progname = argv[0]; - else - progname++; - - filename = (char *)NULL; - debug = 0; - - while ((opt = getopt (argc, argv, "do:")) != EOF) - { - switch (opt) - { - case 'd': - debug = 1; - break; - case 'o': - filename = optarg; - break; - default: - usage(); - } - } - - argc -= optind; - argv += optind; - - if (filename) - { - fp = fopen (filename, "w"); - if (fp == 0) - { - fprintf (stderr, _("%s: %s: cannot open: %s\n"), progname, filename, strerror(errno)); - exit (1); - } - } - else - { - filename = "stdout"; - fp = stdout; - } - - - for (i = 0; i < SYNSIZE; i++) - lsyntax[i] = CWORD; - - load_lsyntax (); - - fprintf (fp, "%s\n", preamble); - fprintf (fp, "%s\n", includes); - - dump_lsyntax (fp); - - if (fp != stdout) - fclose (fp); - exit (0); -} - - -#if !defined (HAVE_STRERROR) - -#include -#ifndef _MINIX -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -/* Return a string corresponding to the error number E. From - the ANSI C spec. */ -#if defined (strerror) -# undef strerror -#endif - -char * -strerror (e) - int e; -{ - static char emsg[40]; -#if defined (HAVE_SYS_ERRLIST) - extern int sys_nerr; - extern char *sys_errlist[]; - - if (e > 0 && e < sys_nerr) - return (sys_errlist[e]); - else -#endif /* HAVE_SYS_ERRLIST */ - { - sprintf (emsg, _("Unknown system error %d"), e); - return (&emsg[0]); - } -} -#endif /* HAVE_STRERROR */ diff --git a/nojobs.c~ b/nojobs.c~ deleted file mode 100644 index dc70eafca..000000000 --- a/nojobs.c~ +++ /dev/null @@ -1,934 +0,0 @@ -/* nojobs.c - functions that make children, remember them, and handle their termination. */ - -/* This file works under BSD, System V, minix, and Posix systems. It does - not implement job control. */ - -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include "config.h" - -#include "bashtypes.h" -#include "filecntl.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include -#include - -#if defined (BUFFERED_INPUT) -# include "input.h" -#endif - -/* Need to include this up here for *_TTY_DRIVER definitions. */ -#include "shtty.h" - -#include "bashintl.h" - -#include "shell.h" -#include "jobs.h" -#include "execute_cmd.h" - -#include "builtins/builtext.h" /* for wait_builtin */ - -#define DEFAULT_CHILD_MAX 32 - -#if defined (_POSIX_VERSION) || !defined (HAVE_KILLPG) -# define killpg(pg, sig) kill(-(pg),(sig)) -#endif /* USG || _POSIX_VERSION */ - -#if !defined (HAVE_SIGINTERRUPT) && !defined (HAVE_POSIX_SIGNALS) -# define siginterrupt(sig, code) -#endif /* !HAVE_SIGINTERRUPT && !HAVE_POSIX_SIGNALS */ - -#if defined (HAVE_WAITPID) -# define WAITPID(pid, statusp, options) waitpid (pid, statusp, options) -#else -# define WAITPID(pid, statusp, options) wait (statusp) -#endif /* !HAVE_WAITPID */ - -/* Return the fd from which we are actually getting input. */ -#define input_tty() (shell_tty != -1) ? shell_tty : fileno (stderr) - -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -extern int interactive, interactive_shell, login_shell; -extern int subshell_environment; -extern int last_command_exit_value, last_command_exit_signal; -extern int interrupt_immediately; -extern sh_builtin_func_t *this_shell_builtin; -#if defined (HAVE_POSIX_SIGNALS) -extern sigset_t top_level_mask; -#endif -extern procenv_t wait_intr_buf; -extern int wait_signal_received; - -pid_t last_made_pid = NO_PID; -pid_t last_asynchronous_pid = NO_PID; - -/* Call this when you start making children. */ -int already_making_children = 0; - -/* The controlling tty for this shell. */ -int shell_tty = -1; - -/* If this is non-zero, $LINES and $COLUMNS are reset after every process - exits from get_tty_state(). */ -int check_window_size; - -/* STATUS and FLAGS are only valid if pid != NO_PID - STATUS is only valid if (flags & PROC_RUNNING) == 0 */ -struct proc_status { - pid_t pid; - int status; /* Exit status of PID or 128 + fatal signal number */ - int flags; -}; - -/* Values for proc_status.flags */ -#define PROC_RUNNING 0x01 -#define PROC_NOTIFIED 0x02 -#define PROC_ASYNC 0x04 -#define PROC_SIGNALED 0x10 - -/* Return values from find_status_by_pid */ -#define PROC_BAD -1 -#define PROC_STILL_ALIVE -2 - -static struct proc_status *pid_list = (struct proc_status *)NULL; -static int pid_list_size; -static int wait_sigint_received; - -static long child_max = -1L; - -static void alloc_pid_list __P((void)); -static int find_proc_slot __P((void)); -static int find_index_by_pid __P((pid_t)); -static int find_status_by_pid __P((pid_t)); -static int process_exit_status __P((WAIT)); -static int find_termsig_by_pid __P((pid_t)); -static int get_termsig __P((WAIT)); -static void set_pid_status __P((pid_t, WAIT)); -static void set_pid_flags __P((pid_t, int)); -static void unset_pid_flags __P((pid_t, int)); -static int get_pid_flags __P((pid_t)); -static void add_pid __P((pid_t, int)); -static void mark_dead_jobs_as_notified __P((int)); - -static sighandler wait_sigint_handler __P((int)); -static char *j_strsignal __P((int)); - -#if defined (HAVE_WAITPID) -static void reap_zombie_children __P((void)); -#endif - -#if !defined (HAVE_SIGINTERRUPT) && defined (HAVE_POSIX_SIGNALS) -static int siginterrupt __P((int, int)); -#endif - -static void restore_sigint_handler __P((void)); - -/* Allocate new, or grow existing PID_LIST. */ -static void -alloc_pid_list () -{ - register int i; - int old = pid_list_size; - - pid_list_size += 10; - pid_list = (struct proc_status *)xrealloc (pid_list, pid_list_size * sizeof (struct proc_status)); - - /* None of the newly allocated slots have process id's yet. */ - for (i = old; i < pid_list_size; i++) - pid_list[i].pid = NO_PID; -} - -/* Return the offset within the PID_LIST array of an empty slot. This can - create new slots if all of the existing slots are taken. */ -static int -find_proc_slot () -{ - register int i; - - for (i = 0; i < pid_list_size; i++) - if (pid_list[i].pid == NO_PID) - return (i); - - if (i == pid_list_size) - alloc_pid_list (); - - return (i); -} - -/* Return the offset within the PID_LIST array of a slot containing PID, - or the value NO_PID if the pid wasn't found. */ -static int -find_index_by_pid (pid) - pid_t pid; -{ - register int i; - - for (i = 0; i < pid_list_size; i++) - if (pid_list[i].pid == pid) - return (i); - - return (NO_PID); -} - -/* Return the status of PID as looked up in the PID_LIST array. A - return value of PROC_BAD indicates that PID wasn't found. */ -static int -find_status_by_pid (pid) - pid_t pid; -{ - int i; - - i = find_index_by_pid (pid); - if (i == NO_PID) - return (PROC_BAD); - if (pid_list[i].flags & PROC_RUNNING) - return (PROC_STILL_ALIVE); - return (pid_list[i].status); -} - -static int -process_exit_status (status) - WAIT status; -{ - if (WIFSIGNALED (status)) - return (128 + WTERMSIG (status)); - else - return (WEXITSTATUS (status)); -} - -/* Return the status of PID as looked up in the PID_LIST array. A - return value of PROC_BAD indicates that PID wasn't found. */ -static int -find_termsig_by_pid (pid) - pid_t pid; -{ - int i; - - i = find_index_by_pid (pid); - if (i == NO_PID) - return (0); - if (pid_list[i].flags & PROC_RUNNING) - return (0); - return (get_termsig ((WAIT)pid_list[i].status)); -} - -/* Set LAST_COMMAND_EXIT_SIGNAL depending on STATUS. If STATUS is -1, look - up PID in the pid array and set LAST_COMMAND_EXIT_SIGNAL appropriately - depending on its flags and exit status. */ -static int -get_termsig (status) - WAIT status; -{ - if (WIFSTOPPED (status) == 0 && WIFSIGNALED (status)) - return (WTERMSIG (status)); - else - return (0); -} - -/* Give PID the status value STATUS in the PID_LIST array. */ -static void -set_pid_status (pid, status) - pid_t pid; - WAIT status; -{ - int slot; - -#if defined (COPROCESS_SUPPORT) - coproc_pidchk (pid, status); -#endif - - slot = find_index_by_pid (pid); - if (slot == NO_PID) - return; - - pid_list[slot].status = process_exit_status (status); - pid_list[slot].flags &= ~PROC_RUNNING; - if (WIFSIGNALED (status)) - pid_list[slot].flags |= PROC_SIGNALED; - /* If it's not a background process, mark it as notified so it gets - cleaned up. */ - if ((pid_list[slot].flags & PROC_ASYNC) == 0) - pid_list[slot].flags |= PROC_NOTIFIED; -} - -/* Give PID the flags FLAGS in the PID_LIST array. */ -static void -set_pid_flags (pid, flags) - pid_t pid; - int flags; -{ - int slot; - - slot = find_index_by_pid (pid); - if (slot == NO_PID) - return; - - pid_list[slot].flags |= flags; -} - -/* Unset FLAGS for PID in the pid list */ -static void -unset_pid_flags (pid, flags) - pid_t pid; - int flags; -{ - int slot; - - slot = find_index_by_pid (pid); - if (slot == NO_PID) - return; - - pid_list[slot].flags &= ~flags; -} - -/* Return the flags corresponding to PID in the PID_LIST array. */ -static int -get_pid_flags (pid) - pid_t pid; -{ - int slot; - - slot = find_index_by_pid (pid); - if (slot == NO_PID) - return 0; - - return (pid_list[slot].flags); -} - -static void -add_pid (pid, async) - pid_t pid; - int async; -{ - int slot; - - slot = find_proc_slot (); - - pid_list[slot].pid = pid; - pid_list[slot].status = -1; - pid_list[slot].flags = PROC_RUNNING; - if (async) - pid_list[slot].flags |= PROC_ASYNC; -} - -static void -mark_dead_jobs_as_notified (force) - int force; -{ - register int i, ndead; - - /* first, count the number of non-running async jobs if FORCE == 0 */ - for (i = ndead = 0; force == 0 && i < pid_list_size; i++) - { - if (pid_list[i].pid == NO_PID) - continue; - if (((pid_list[i].flags & PROC_RUNNING) == 0) && - (pid_list[i].flags & PROC_ASYNC)) - ndead++; - } - - if (child_max < 0) - child_max = getmaxchild (); - if (child_max < 0) - child_max = DEFAULT_CHILD_MAX; - - if (force == 0 && ndead <= child_max) - return; - - /* If FORCE == 0, we just mark as many non-running async jobs as notified - to bring us under the CHILD_MAX limit. */ - for (i = 0; i < pid_list_size; i++) - { - if (pid_list[i].pid == NO_PID) - continue; - if (((pid_list[i].flags & PROC_RUNNING) == 0) && - pid_list[i].pid != last_asynchronous_pid) - { - pid_list[i].flags |= PROC_NOTIFIED; - if (force == 0 && (pid_list[i].flags & PROC_ASYNC) && --ndead <= child_max) - break; - } - } -} - -/* Remove all dead, notified jobs from the pid_list. */ -int -cleanup_dead_jobs () -{ - register int i; - -#if defined (HAVE_WAITPID) - reap_zombie_children (); -#endif - - for (i = 0; i < pid_list_size; i++) - { - if ((pid_list[i].flags & PROC_RUNNING) == 0 && - (pid_list[i].flags & PROC_NOTIFIED)) - pid_list[i].pid = NO_PID; - } - - return 0; -} - -void -reap_dead_jobs () -{ - mark_dead_jobs_as_notified (0); - cleanup_dead_jobs (); -} - -/* Initialize the job control mechanism, and set up the tty stuff. */ -initialize_job_control (force) - int force; -{ - shell_tty = fileno (stderr); - - if (interactive) - get_tty_state (); -} - -/* Setup this shell to handle C-C, etc. */ -void -initialize_job_signals () -{ - set_signal_handler (SIGINT, sigint_sighandler); - - /* If this is a login shell we don't wish to be disturbed by - stop signals. */ - if (login_shell) - ignore_tty_job_signals (); -} - -#if defined (HAVE_WAITPID) -/* Collect the status of all zombie children so that their system - resources can be deallocated. */ -static void -reap_zombie_children () -{ -# if defined (WNOHANG) - pid_t pid; - WAIT status; - - CHECK_TERMSIG; - while ((pid = waitpid (-1, (int *)&status, WNOHANG)) > 0) - set_pid_status (pid, status); -# endif /* WNOHANG */ - CHECK_TERMSIG; -} -#endif /* WAITPID */ - -#if !defined (HAVE_SIGINTERRUPT) && defined (HAVE_POSIX_SIGNALS) -static int -siginterrupt (sig, flag) - int sig, flag; -{ - struct sigaction act; - - sigaction (sig, (struct sigaction *)NULL, &act); - - if (flag) - act.sa_flags &= ~SA_RESTART; - else - act.sa_flags |= SA_RESTART; - - return (sigaction (sig, &act, (struct sigaction *)NULL)); -} -#endif /* !HAVE_SIGINTERRUPT && HAVE_POSIX_SIGNALS */ - -/* Fork, handling errors. Returns the pid of the newly made child, or 0. - COMMAND is just for remembering the name of the command; we don't do - anything else with it. ASYNC_P says what to do with the tty. If - non-zero, then don't give it away. */ -pid_t -make_child (command, async_p) - char *command; - int async_p; -{ - pid_t pid; - int forksleep; - - /* Discard saved memory. */ - if (command) - free (command); - - start_pipeline (); - -#if defined (BUFFERED_INPUT) - /* If default_buffered_input is active, we are reading a script. If - the command is asynchronous, we have already duplicated /dev/null - as fd 0, but have not changed the buffered stream corresponding to - the old fd 0. We don't want to sync the stream in this case. */ - if (default_buffered_input != -1 && (!async_p || default_buffered_input > 0)) - sync_buffered_stream (default_buffered_input); -#endif /* BUFFERED_INPUT */ - - /* Create the child, handle severe errors. Retry on EAGAIN. */ - forksleep = 1; - while ((pid = fork ()) < 0 && errno == EAGAIN && forksleep < FORKSLEEP_MAX) - { - sys_error ("fork: retry"); -#if defined (HAVE_WAITPID) - /* Posix systems with a non-blocking waitpid () system call available - get another chance after zombies are reaped. */ - reap_zombie_children (); - if (forksleep > 1 && sleep (forksleep) != 0) - break; -#else - if (sleep (forksleep) != 0) - break; -#endif /* HAVE_WAITPID */ - forksleep <<= 1; - } - - if (pid < 0) - { - sys_error ("fork"); - throw_to_top_level (); - } - - if (pid == 0) - { -#if defined (BUFFERED_INPUT) - unset_bash_input (0); -#endif /* BUFFERED_INPUT */ - -#if defined (HAVE_POSIX_SIGNALS) - /* Restore top-level signal mask. */ - sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); -#endif - -#if 0 - /* Ignore INT and QUIT in asynchronous children. */ - if (async_p) - last_asynchronous_pid = getpid (); -#endif - - default_tty_job_signals (); - } - else - { - /* In the parent. */ - - last_made_pid = pid; - - if (async_p) - last_asynchronous_pid = pid; - - add_pid (pid, async_p); - } - return (pid); -} - -void -ignore_tty_job_signals () -{ -#if defined (SIGTSTP) - set_signal_handler (SIGTSTP, SIG_IGN); - set_signal_handler (SIGTTIN, SIG_IGN); - set_signal_handler (SIGTTOU, SIG_IGN); -#endif -} - -void -default_tty_job_signals () -{ -#if defined (SIGTSTP) - set_signal_handler (SIGTSTP, SIG_DFL); - set_signal_handler (SIGTTIN, SIG_DFL); - set_signal_handler (SIGTTOU, SIG_DFL); -#endif -} - -/* Wait for a single pid (PID) and return its exit status. Called by - the wait builtin. */ -int -wait_for_single_pid (pid) - pid_t pid; -{ - pid_t got_pid; - WAIT status; - int pstatus, flags; - - pstatus = find_status_by_pid (pid); - - if (pstatus == PROC_BAD) - { - internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid); - return (127); - } - - if (pstatus != PROC_STILL_ALIVE) - { - if (pstatus > 128) - last_command_exit_signal = find_termsig_by_pid (pid); - return (pstatus); - } - - siginterrupt (SIGINT, 1); - while ((got_pid = WAITPID (pid, &status, 0)) != pid) - { - CHECK_TERMSIG; - if (got_pid < 0) - { - if (errno != EINTR && errno != ECHILD) - { - siginterrupt (SIGINT, 0); - sys_error ("wait"); - } - break; - } - else if (got_pid > 0) - set_pid_status (got_pid, status); - } - - if (got_pid > 0) - { - set_pid_status (got_pid, status); - set_pid_flags (got_pid, PROC_NOTIFIED); - } - - siginterrupt (SIGINT, 0); - QUIT; - - return (got_pid > 0 ? process_exit_status (status) : -1); -} - -/* Wait for all of the shell's children to exit. Called by the `wait' - builtin. */ -void -wait_for_background_pids () -{ - pid_t got_pid; - WAIT status; - - /* If we aren't using job control, we let the kernel take care of the - bookkeeping for us. wait () will return -1 and set errno to ECHILD - when there are no more unwaited-for child processes on both - 4.2 BSD-based and System V-based systems. */ - - siginterrupt (SIGINT, 1); - - /* Wait for ECHILD */ - while ((got_pid = WAITPID (-1, &status, 0)) != -1) - set_pid_status (got_pid, status); - - if (errno != EINTR && errno != ECHILD) - { - siginterrupt (SIGINT, 0); - sys_error("wait"); - } - - siginterrupt (SIGINT, 0); - QUIT; - - 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; - } -} - -/* Handle SIGINT while we are waiting for children in a script to exit. - All interrupts are effectively ignored by the shell, but allowed to - kill a running job. */ -static sighandler -wait_sigint_handler (sig) - int sig; -{ - SigHandler *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)) - { - last_command_exit_value = EXECUTION_FAILURE; - restore_sigint_handler (); - interrupt_immediately = 0; - trap_handler (SIGINT); /* set pending_traps[SIGINT] */ - wait_signal_received = SIGINT; - longjmp (wait_intr_buf, 1); - } - - if (interrupt_immediately) - { - last_command_exit_value = EXECUTION_FAILURE; - restore_sigint_handler (); - ADDINTERRUPT; - QUIT; - } - - wait_sigint_received = 1; - - SIGRETURN (0); -} - -static char * -j_strsignal (s) - int s; -{ - static char retcode_name_buffer[64] = { '\0' }; - char *x; - - x = strsignal (s); - if (x == 0) - { - x = retcode_name_buffer; - sprintf (x, "Signal %d", s); - } - return x; -} - -/* Wait for pid (one of our children) to terminate. This is called only - by the execution code in execute_cmd.c. */ -int -wait_for (pid) - pid_t pid; -{ - int return_val, pstatus; - pid_t got_pid; - WAIT status; - - pstatus = find_status_by_pid (pid); - - if (pstatus == PROC_BAD) - return (0); - - if (pstatus != PROC_STILL_ALIVE) - { - if (pstatus > 128) - last_command_exit_signal = find_termsig_by_pid (pid); - return (pstatus); - } - - /* If we are running a script, ignore SIGINT while we're waiting for - a child to exit. The loop below does some of this, but not all. */ - wait_sigint_received = 0; - if (interactive_shell == 0) - old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); - - while ((got_pid = WAITPID (-1, &status, 0)) != pid) /* XXX was pid now -1 */ - { - CHECK_TERMSIG; - if (got_pid < 0 && errno == ECHILD) - { -#if !defined (_POSIX_VERSION) - status.w_termsig = status.w_retcode = 0; -#else - status = 0; -#endif /* _POSIX_VERSION */ - break; - } - else if (got_pid < 0 && errno != EINTR) - programming_error ("wait_for(%ld): %s", (long)pid, strerror(errno)); - else if (got_pid > 0) - set_pid_status (got_pid, status); - } - - if (got_pid > 0) - set_pid_status (got_pid, status); - -#if defined (HAVE_WAITPID) - if (got_pid >= 0) - reap_zombie_children (); -#endif /* HAVE_WAITPID */ - - if (interactive_shell == 0) - { - SigHandler *temp_handler; - - temp_handler = old_sigint_handler; - restore_sigint_handler (); - - /* If the job exited because of SIGINT, make sure the shell acts as if - it had received one also. */ - if (WIFSIGNALED (status) && (WTERMSIG (status) == SIGINT)) - { - - if (maybe_call_trap_handler (SIGINT) == 0) - { - if (temp_handler == SIG_DFL) - termsig_handler (SIGINT); - else if (temp_handler != INVALID_SIGNAL_HANDLER && temp_handler != SIG_IGN) - (*temp_handler) (SIGINT); - } - } - } - - /* Default return value. */ - /* ``a full 8 bits of status is returned'' */ - return_val = process_exit_status (status); - last_command_exit_signal = get_termsig (status); - -#if !defined (DONT_REPORT_SIGPIPE) - if ((WIFSTOPPED (status) == 0) && WIFSIGNALED (status) && - (WTERMSIG (status) != SIGINT)) -#else - if ((WIFSTOPPED (status) == 0) && WIFSIGNALED (status) && - (WTERMSIG (status) != SIGINT) && (WTERMSIG (status) != SIGPIPE)) -#endif - { - fprintf (stderr, "%s", j_strsignal (WTERMSIG (status))); - if (WIFCORED (status)) - fprintf (stderr, _(" (core dumped)")); - fprintf (stderr, "\n"); - } - - if (interactive_shell && subshell_environment == 0) - { - if (WIFSIGNALED (status) || WIFSTOPPED (status)) - set_tty_state (); - else - get_tty_state (); - } - - return (return_val); -} - -/* Send PID SIGNAL. Returns -1 on failure, 0 on success. If GROUP is non-zero, - or PID is less than -1, then kill the process group associated with PID. */ -int -kill_pid (pid, signal, group) - pid_t pid; - int signal, group; -{ - int result; - - if (pid < -1) - { - pid = -pid; - group = 1; - } - result = group ? killpg (pid, signal) : kill (pid, signal); - return (result); -} - -static TTYSTRUCT shell_tty_info; -static int got_tty_state; - -/* Fill the contents of shell_tty_info with the current tty info. */ -get_tty_state () -{ - int tty; - - tty = input_tty (); - if (tty != -1) - { - ttgetattr (tty, &shell_tty_info); - got_tty_state = 1; - if (check_window_size) - get_new_window_size (0, (int *)0, (int *)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 (got_tty_state == 0) - return 0; - ttsetattr (tty, &shell_tty_info); - } - return 0; -} - -/* Give the terminal to PGRP. */ -give_terminal_to (pgrp, force) - pid_t pgrp; - int force; -{ -} - -/* Stop a pipeline. */ -int -stop_pipeline (async, ignore) - int async; - COMMAND *ignore; -{ - already_making_children = 0; - return 0; -} - -void -start_pipeline () -{ - already_making_children = 1; -} - -void -stop_making_children () -{ - already_making_children = 0; -} - -int -get_job_by_pid (pid, block) - pid_t pid; - int block; -{ - int i; - - i = find_index_by_pid (pid); - return ((i == NO_PID) ? PROC_BAD : i); -} - -/* Print descriptive information about the job with leader pid PID. */ -void -describe_pid (pid) - pid_t pid; -{ - fprintf (stderr, "%ld\n", (long) pid); -} - -void -unfreeze_jobs_list () -{ -} - -int -count_all_jobs () -{ - return 0; -} diff --git a/parse.y.orig b/parse.y.orig deleted file mode 100644 index 21a8b0f3b..000000000 --- a/parse.y.orig +++ /dev/null @@ -1,4948 +0,0 @@ -/* Yacc grammar for bash. */ - -/* Copyright (C) 1989-2006 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file 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.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 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 (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 - { - if ($2) - $2->flags |= CMD_INVERT_RETURN; - $$ = $2; - } - | timespec pipeline - { - if ($2) - $2->flags |= $1; - $$ = $2; - } - | timespec BANG pipeline - { - if ($3) - $3->flags |= $1|CMD_INVERT_RETURN; - $$ = $3; - } - | BANG timespec pipeline - { - if ($3) - $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 */ -#define PST_ASSIGNOK 0x4000 /* assignment statement ok in this context */ -#define PST_REGEXP 0x8000 /* parsing an ERE/BRE as a single word */ - -/* 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++; - } - terminate_immediately = 1; - - current_readline_line = readline (current_readline_prompt ? - current_readline_prompt : ""); - - terminate_immediately = 0; - 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) - { - if (interactive) - { - interrupt_immediately++; - terminate_immediately++; - } - result = getc_with_restart (bash_input.location.file); - if (interactive) - { - interrupt_immediately--; - terminate_immediately--; - } - } - 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) - { - /* Allow immediate exit if interrupted during input. */ - QUIT; - - c = yy_getc (); - - /* 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; - - QUIT; - - if (sigwinch_received) - { - sigwinch_received = 0; - get_new_window_size (0, (int *)0, (int *)0); - } - - 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 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 MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n') - { - if (SHOULD_PROMPT ()) - prompt_again (); - line_number++; - goto restart_read; - } - - 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_variable_command (command, vname) - char *command, *vname; -{ - 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), vname, SEVAL_NONINT|SEVAL_NOHIST); - - restore_parser_state (&ps); - bind_variable ("_", last_lastarg, 0); - 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 && shellblank (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 */ - - parser_state &= ~PST_ASSIGNOK; - - 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 */ - - parser_state &= ~PST_ASSIGNOK; - - 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, and returning - * correct error values if it reads EOF. - */ -#define P_FIRSTCLOSE 0x01 -#define P_ALLOWESC 0x02 -#define P_DQUOTE 0x04 -#define P_COMMAND 0x08 /* parsing a command, so look for comments */ -#define P_BACKQUOTE 0x10 /* parsing a backquoted command substitution */ - -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, in_comment, check_comment; - int pass_next_character, backq_backslash, nestlen, ttranslen, start_lineno; - char *ret, *nestret, *ttrans; - int retind, retsize, rflags; - -/* itrace("parse_matched_pair: open = %c close = %c", open, close); */ - count = 1; - pass_next_character = backq_backslash = was_dollar = in_comment = 0; - check_comment = (flags & P_COMMAND) && qc != '`' && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 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 != '\'' && pass_next_character == 0 && backq_backslash == 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 (in_comment) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if (ch == '\n') - in_comment = 0; - - continue; - } - /* Not exactly right yet, should handle shell metacharacters, too. If - any changes are made to this test, make analogous changes to subst.c: - extract_delimited_string(). */ - else if MBTEST(check_comment && in_comment == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || whitespace (ret[retind - 1]))) - in_comment = 1; - - /* last char was backslash inside backquoted command substitution */ - if (backq_backslash) - { - backq_backslash = 0; - /* Placeholder for adding special characters */ - } - - 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--; - /* handle nested ${...} specially. */ - else if MBTEST(open != close && was_dollar && open == '{' && ch == open) /* } */ - count++; - 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++; -#if 0 - else if MBTEST((flags & P_BACKQUOTE) && ch == '\\') - backq_backslash++; -#endif - 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); - - if ((rflags & P_DQUOTE) == 0) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else - { - nestret = ttrans; - nestlen = ttranslen; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - nestlen = ttranslen + 2; - 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); -add_nestret: - 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); - } -#if 0 - else if MBTEST(qc == '`' && (ch == '"' || ch == '\'') && in_comment == 0) - { - /* Add P_BACKQUOTE so backslash quotes the next character and - shell_getc does the right thing with \. We do this for - a measure of backwards compatibility -- it's not strictly the - right POSIX thing. */ - nestret = parse_matched_pair (0, ch, ch, &nestlen, rflags|P_BACKQUOTE); - goto add_nestret; - } -#endif - else if MBTEST(open != '`' && 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 & ~P_DQUOTE); - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - - goto add_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, sline; - char *wval; - 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 = alloc_word_desc (); - wd->word = wval; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - return (ARITH_FOR_EXPRS); - } - else - return -1; /* ERROR */ - } -#endif - -#if defined (DPAREN_ARITHMETIC) - if (reserved_word_acceptable (last_read_token)) - { - sline = line_number; - - cmdtyp = parse_arith_cmd (&wval, 0); - if (cmdtyp == 1) /* arithmetic command */ - { - wd = alloc_word_desc (); - wd->word = wval; - wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - 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; -} - -/* XXX - possible changes here for `+=' */ -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; - - /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound - assignment. */ - int compound_assignment; - - /* 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 = compound_assignment = 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, (character == '`') ? P_COMMAND : 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, P_COMMAND); - 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); - ttranslen = strlen (ttok); - ttrans = ttok; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - ttranslen += 2; - 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 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && 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; - compound_assignment = 1; -#if 1 - goto next_character; -#else - goto got_token; /* ksh93 seems to do this */ -#endif - } - 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; /*(*/ - if (compound_assignment && token[token_index-1] == ')') - the_word->flags |= W_COMPASSIGN; - /* 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; - } - - if (command_token_position (last_read_token)) - { - struct builtin *b; - b = builtin_address_internal (token, 0); - if (b && (b->flags & ASSIGNMENT_BUILTIN)) - parser_state |= PST_ASSIGNOK; - else if (STREQ (token, "eval") || STREQ (token, "let")) - parser_state |= PST_ASSIGNOK; - } - - 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 ";"; - } - else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT)) - 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, i; - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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]; - 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, t_string) == 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); - n = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; - i = 0; - if (n == CTLESC || n == CTLNUL) - temp[i++] = CTLESC; - temp[i++] = n; - temp[i] = '\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 (tok) - int tok; -{ - char *t; - - if (t = find_token_in_alist (tok, word_token_alist, 0)) - return t; - - if (t = find_token_in_alist (tok, 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 (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, orig_last_token, assignok; - char *saved_token, *ret; - - saved_token = token; - orig_token_size = token_buffer_size; - orig_line_number = line_number; - orig_last_token = last_read_token; - - last_read_token = WORD; /* WORD to allow reserved words here */ - - token = (char *)NULL; - token_buffer_size = 0; - - assignok = parser_state&PST_ASSIGNOK; /* XXX */ - - 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(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 = orig_last_token; /* XXX - was 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; - - if (assignok) - parser_state |= PST_ASSIGNOK; - - 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 = (sh_parser_state_t *)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/parse.y.regexp~ b/parse.y.regexp~ deleted file mode 100644 index 63e577eca..000000000 --- a/parse.y.regexp~ +++ /dev/null @@ -1,4981 +0,0 @@ -/* Yacc grammar for bash. */ - -/* Copyright (C) 1989-2006 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file 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.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 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 (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 - { - if ($2) - $2->flags |= CMD_INVERT_RETURN; - $$ = $2; - } - | timespec pipeline - { - if ($2) - $2->flags |= $1; - $$ = $2; - } - | timespec BANG pipeline - { - if ($3) - $3->flags |= $1|CMD_INVERT_RETURN; - $$ = $3; - } - | BANG timespec pipeline - { - if ($3) - $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 */ -#define PST_ASSIGNOK 0x4000 /* assignment statement ok in this context */ -#define PST_REGEXP 0x8000 /* parsing an ERE/BRE as a single word */ - -/* 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++; - } - terminate_immediately = 1; - - current_readline_line = readline (current_readline_prompt ? - current_readline_prompt : ""); - - terminate_immediately = 0; - 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) - { - if (interactive) - { - interrupt_immediately++; - terminate_immediately++; - } - result = getc_with_restart (bash_input.location.file); - if (interactive) - { - interrupt_immediately--; - terminate_immediately--; - } - } - 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) - { - /* Allow immediate exit if interrupted during input. */ - QUIT; - - c = yy_getc (); - - /* 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; - - QUIT; - - if (sigwinch_received) - { - sigwinch_received = 0; - get_new_window_size (0, (int *)0, (int *)0); - } - - 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 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 MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n') - { - if (SHOULD_PROMPT ()) - prompt_again (); - line_number++; - goto restart_read; - } - - 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_variable_command (command, vname) - char *command, *vname; -{ - 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), vname, SEVAL_NONINT|SEVAL_NOHIST); - - restore_parser_state (&ps); - bind_variable ("_", last_lastarg, 0); - 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 && shellblank (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 */ - - parser_state &= ~PST_ASSIGNOK; - - return (character); - } - - if (parser_state & PST_REGEXP) - goto tokword; - - /* 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 */ - - parser_state &= ~PST_ASSIGNOK; - - 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); - -tokword: - /* 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, and returning - * correct error values if it reads EOF. - */ -#define P_FIRSTCLOSE 0x01 -#define P_ALLOWESC 0x02 -#define P_DQUOTE 0x04 -#define P_COMMAND 0x08 /* parsing a command, so look for comments */ -#define P_BACKQUOTE 0x10 /* parsing a backquoted command substitution */ - -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, in_comment, check_comment; - int pass_next_character, backq_backslash, nestlen, ttranslen, start_lineno; - char *ret, *nestret, *ttrans; - int retind, retsize, rflags; - -/* itrace("parse_matched_pair: open = %c close = %c", open, close); */ - count = 1; - pass_next_character = backq_backslash = was_dollar = in_comment = 0; - check_comment = (flags & P_COMMAND) && qc != '`' && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 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 != '\'' && pass_next_character == 0 && backq_backslash == 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 (in_comment) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if (ch == '\n') - in_comment = 0; - - continue; - } - /* Not exactly right yet, should handle shell metacharacters, too. If - any changes are made to this test, make analogous changes to subst.c: - extract_delimited_string(). */ - else if MBTEST(check_comment && in_comment == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || whitespace (ret[retind - 1]))) - in_comment = 1; - - /* last char was backslash inside backquoted command substitution */ - if (backq_backslash) - { - backq_backslash = 0; - /* Placeholder for adding special characters */ - } - - 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--; - /* handle nested ${...} specially. */ - else if MBTEST(open != close && was_dollar && open == '{' && ch == open) /* } */ - count++; - 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++; -#if 0 - else if MBTEST((flags & P_BACKQUOTE) && ch == '\\') - backq_backslash++; -#endif - 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); - - if ((rflags & P_DQUOTE) == 0) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else - { - nestret = ttrans; - nestlen = ttranslen; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - nestlen = ttranslen + 2; - 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); -add_nestret: - 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); - } -#if 0 - else if MBTEST(qc == '`' && (ch == '"' || ch == '\'') && in_comment == 0) - { - /* Add P_BACKQUOTE so backslash quotes the next character and - shell_getc does the right thing with \. We do this for - a measure of backwards compatibility -- it's not strictly the - right POSIX thing. */ - nestret = parse_matched_pair (0, ch, ch, &nestlen, rflags|P_BACKQUOTE); - goto add_nestret; - } -#endif - else if MBTEST(open != '`' && 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 & ~P_DQUOTE); - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - - goto add_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, sline; - char *wval; - 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 = alloc_word_desc (); - wd->word = wval; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - return (ARITH_FOR_EXPRS); - } - else - return -1; /* ERROR */ - } -#endif - -#if defined (DPAREN_ARITHMETIC) - if (reserved_word_acceptable (last_read_token)) - { - sline = line_number; - - cmdtyp = parse_arith_cmd (&wval, 0); - if (cmdtyp == 1) /* arithmetic command */ - { - wd = alloc_word_desc (); - wd->word = wval; - wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - 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; - parser_state |= PST_REGEXP; - } -#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); - parser_state &= ~PST_REGEXP; - 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; -} - -/* XXX - possible changes here for `+=' */ -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; - - /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound - assignment. */ - int compound_assignment; - - /* 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 = compound_assignment = 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, (character == '`') ? P_COMMAND : 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 COND_REGEXP - /* When parsing a regexp as a single word inside a conditional command, - we need to special-case characters special to both the shell and - regular expressions. Right now, that is only '(' and '|'. */ /*)*/ - if MBTEST((parser_state & PST_REGEXP) && (character == '(' || character == '|')) /*)*/ - { - if (character == '|') - goto got_character; - - push_delimiter (dstack, character); - 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; - strcpy (token + token_index, ttok); - token_index += ttoklen; - FREE (ttok); - dollar_present = all_digit_token = 0; - goto next_character; - } -#endif /* COND_REGEXP */ - -#ifdef EXTENDED_GLOB - /* Parse a ksh-style extended pattern matching specification. */ - if MBTEST(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, P_COMMAND); - 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); - ttranslen = strlen (ttok); - ttrans = ttok; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - ttranslen += 2; - 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 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && 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; - compound_assignment = 1; -#if 1 - goto next_character; -#else - goto got_token; /* ksh93 seems to do this */ -#endif - } - 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; /*(*/ - if (compound_assignment && token[token_index-1] == ')') - the_word->flags |= W_COMPASSIGN; - /* 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; - } - - if (command_token_position (last_read_token)) - { - struct builtin *b; - b = builtin_address_internal (token, 0); - if (b && (b->flags & ASSIGNMENT_BUILTIN)) - parser_state |= PST_ASSIGNOK; - else if (STREQ (token, "eval") || STREQ (token, "let")) - parser_state |= PST_ASSIGNOK; - } - - 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 ";"; - } - else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT)) - 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, i; - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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]; - 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, t_string) == 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); - n = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; - i = 0; - if (n == CTLESC || n == CTLNUL) - temp[i++] = CTLESC; - temp[i++] = n; - temp[i] = '\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 (tok) - int tok; -{ - char *t; - - if (t = find_token_in_alist (tok, word_token_alist, 0)) - return t; - - if (t = find_token_in_alist (tok, 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 (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, orig_last_token, assignok; - char *saved_token, *ret; - - saved_token = token; - orig_token_size = token_buffer_size; - orig_line_number = line_number; - orig_last_token = last_read_token; - - last_read_token = WORD; /* WORD to allow reserved words here */ - - token = (char *)NULL; - token_buffer_size = 0; - - assignok = parser_state&PST_ASSIGNOK; /* XXX */ - - 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(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 = orig_last_token; /* XXX - was 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; - - if (assignok) - parser_state |= PST_ASSIGNOK; - - 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 = (sh_parser_state_t *)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/parse.y.save1 b/parse.y.save1 deleted file mode 100644 index b7b35e5e9..000000000 --- a/parse.y.save1 +++ /dev/null @@ -1,5512 +0,0 @@ -/* Yacc grammar for bash. */ - -/* Copyright (C) 1989-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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.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 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 void rewind_input_string __P((void)); -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)); -static char *parse_comsub __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 (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; - -/* The token that currently denotes the end of parse. */ -int shell_eof_token; - -/* The token currently being read. */ -int current_token; - -/* 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 current parser state. */ -static int parser_state; - -/* 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 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 SEMI_AND SEMI_SEMI_AND -%token LESS_LESS_MINUS AND_GREATER AND_GREATER_GREATER LESS_GREATER -%token GREATER_BAR BAR_AND - -/* 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 '|' BAR_AND -%% - -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); - } - | AND_GREATER_GREATER WORD - { - redir.filename = $2; - $$ = make_redirection (1, r_append_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 - { $$ = $1; } - | case_clause_sequence pattern_list SEMI_SEMI - { $2->next = $1; $$ = $2; } - | pattern_list SEMI_AND - { $1->flags |= CASEPAT_FALLTHROUGH; $$ = $1; } - | case_clause_sequence pattern_list SEMI_AND - { $2->flags |= CASEPAT_FALLTHROUGH; $2->next = $1; $$ = $2; } - | pattern_list SEMI_SEMI_AND - { $1->flags |= CASEPAT_TESTNEXT; $$ = $1; } - | case_clause_sequence pattern_list SEMI_SEMI_AND - { $2->flags |= CASEPAT_TESTNEXT; $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 - { - if ($2) - $2->flags |= CMD_INVERT_RETURN; - $$ = $2; - } - | timespec pipeline - { - if ($2) - $2->flags |= $1; - $$ = $2; - } - | timespec BANG pipeline - { - if ($3) - $3->flags |= $1|CMD_INVERT_RETURN; - $$ = $3; - } - | BANG timespec pipeline - { - if ($3) - $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, '|'); } - | pipeline BAR_AND newline_list pipeline - { - /* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */ - COMMAND *tc; - REDIRECTEE rd; - REDIRECT *r; - - tc = $1; - rd.dest = 1; - r = make_redirection (2, r_duplicating_output, rd); - if (tc->redirects) - { - register REDIRECT *t; - for (t = tc->redirects; t->next; t = t->next) - ; - t->next = r; - } - else - tc->redirects = r; - - $$ = command_connect ($1, $4, '|'); - } - | command - { $$ = $1; } - ; - -timespec: TIME - { $$ = CMD_TIME_PIPELINE; } - | TIME TIMEOPT - { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } - ; -%% - -/* 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 - -/* 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++; - } - terminate_immediately = 1; - - current_readline_line = readline (current_readline_prompt ? - current_readline_prompt : ""); - - terminate_immediately = 0; - 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); -} - -/* Count the number of characters we've consumed from bash_input.location.string - and read into shell_input_line, but have not returned from shell_getc. - That is the true input location. Rewind bash_input.location.string by - that number of characters, so it points to the last character actually - consumed by the parser. */ -void -rewind_input_string () -{ - int xchars; - - /* number of unconsumed characters in the input -- XXX need to take newlines - into account, e.g., $(...\n) */ - xchars = shell_input_line_len - shell_input_line_index; - - /* XXX - how to reflect bash_input.location.string back to string passed to - parse_and_execute or xparse_dolparen? xparse_dolparen needs to know how - far into the string we parsed. parse_and_execute knows where bash_input. - location.string is, and how far from orig_string that is -- that's the - number of characters the command consumed. */ - - /* bash_input.location.string - xchars should be where we parsed to */ - /* need to do more validation on xchars value for sanity -- test cases. */ - bash_input.location.string -= xchars; -} - -/* **************************************************************** */ -/* */ -/* 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) - { - if (interactive) - { - interrupt_immediately++; - terminate_immediately++; - } - result = getc_with_restart (bash_input.location.file); - if (interactive) - { - interrupt_immediately--; - terminate_immediately--; - } - } - 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) - { - /* Allow immediate exit if interrupted during input. */ - QUIT; - - c = yy_getc (); - - /* 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 }, - { ";&", SEMI_AND }, - { ";;&", SEMI_SEMI_AND }, - { "<<-", LESS_LESS_MINUS }, - { "<<<", LESS_LESS_LESS }, - { "&>", AND_GREATER }, - { "&>>", AND_GREATER_GREATER }, - { "<>", LESS_GREATER }, - { ">|", GREATER_BAR }, - { "|&", BAR_AND }, - { "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; - - QUIT; - - if (sigwinch_received) - { - sigwinch_received = 0; - get_new_window_size (0, (int *)0, (int *)0); - } - - 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 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 MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n') - { - if (SHOULD_PROMPT ()) - prompt_again (); - line_number++; - goto restart_read; - } - - 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_variable_command (command, vname) - char *command, *vname; -{ - 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), vname, SEVAL_NONINT|SEVAL_NOHIST); - - restore_parser_state (&ps); - bind_variable ("_", last_lastarg, 0); - 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 && (token) != SEMI_AND && (token) != SEMI_SEMI_AND && 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 && shellblank (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 */ - - parser_state &= ~PST_ASSIGNOK; - - return (character); - } - - if (parser_state & PST_REGEXP) - goto tokword; - - /* 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 */ - - parser_state &= ~PST_ASSIGNOK; - - 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 MBTEST(peek_char == '-') - return (LESS_LESS_MINUS); - else if MBTEST(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 */ - peek_char = shell_getc (1); - if MBTEST(peek_char == '&') - return (SEMI_SEMI_AND); - else - { - shell_ungetc (peek_char); - 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(character == '&' && peek_char == '>') - { - peek_char = shell_getc (1); - if MBTEST(peek_char == '>') - return (AND_GREATER_GREATER); - else - { - shell_ungetc (peek_char); - return (AND_GREATER); - } - } - else if MBTEST(character == '|' && peek_char == '&') - return (BAR_AND); - else if MBTEST(character == ';' && peek_char == '&') - { - parser_state |= PST_CASEPAT; -#if defined (ALIAS) - parser_state &= ~PST_ALEXPNEXT; -#endif /* ALIAS */ - return (SEMI_AND); - } - - 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); - -tokword: - /* 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, and returning - * correct error values if it reads EOF. - */ -#define P_FIRSTCLOSE 0x01 -#define P_ALLOWESC 0x02 -#define P_DQUOTE 0x04 -#define P_COMMAND 0x08 /* parsing a command, so look for comments */ -#define P_BACKQUOTE 0x10 /* parsing a backquoted command substitution */ - -/* Lexical state while parsing a grouping construct or $(...). */ -#define LEX_WASDOL 0x001 -#define LEX_CKCOMMENT 0x002 -#define LEX_INCOMMENT 0x004 -#define LEX_PASSNEXT 0x008 -#define LEX_RESWDOK 0x010 -#define LEX_CKCASE 0x020 -#define LEX_INCASE 0x040 -#define LEX_INHEREDOC 0x080 -#define LEX_HEREDELIM 0x100 /* reading here-doc delimiter */ -#define LEX_STRIPDOC 0x200 /* <<- strip tabs from here doc delim */ - -#define COMSUB_META(ch) ((ch) == ';' || (ch) == '&' || (ch) == '|') - -#define CHECK_NESTRET_ERROR() \ - do { \ - if (nestret == &matched_pair_error) \ - { \ - free (ret); \ - return &matched_pair_error; \ - } \ - } while (0) - -#define APPEND_NESTRET() \ - do { \ - if (nestlen) \ - { \ - RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); \ - strcpy (ret + retind, nestret); \ - retind += nestlen; \ - } \ - } while (0) - -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, in_comment, check_comment; - int pass_next_character, backq_backslash, nestlen, ttranslen, start_lineno; - char *ret, *nestret, *ttrans; - int retind, retsize, rflags; - -/* itrace("parse_matched_pair: open = %c close = %c", open, close); */ - count = 1; - pass_next_character = backq_backslash = was_dollar = in_comment = 0; - check_comment = (flags & P_COMMAND) && qc != '`' && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 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 != '\'' && pass_next_character == 0 && backq_backslash == 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 (); - - /* Don't bother counting parens or doing anything else if in a comment - or part of a case statement */ - if (in_comment) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if (ch == '\n') - in_comment = 0; - - continue; - } - - /* Not exactly right yet, should handle shell metacharacters, too. If - any changes are made to this test, make analogous changes to subst.c: - extract_delimited_string(). */ - else if MBTEST(check_comment && in_comment == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || whitespace (ret[retind - 1]))) - in_comment = 1; - - /* last char was backslash inside backquoted command substitution */ - if (backq_backslash) - { - backq_backslash = 0; - /* Placeholder for adding special characters */ - } - - 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--; - /* handle nested ${...} specially. */ - else if MBTEST(open != close && was_dollar && open == '{' && ch == open) /* } */ - count++; - 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 we just read the ending character, don't bother continuing. */ - if (count == 0) - break; - - if (open == '\'') /* '' inside grouping construct */ - { - if MBTEST((flags & P_ALLOWESC) && ch == '\\') - pass_next_character++; -#if 0 - else if MBTEST((flags & P_BACKQUOTE) && ch == '\\') - backq_backslash++; -#endif - continue; - } - - if MBTEST(ch == '\\') /* backslashes */ - pass_next_character++; - - /* Could also check open == '`' if we want to parse grouping constructs - inside old-style command substitution. */ - 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); - CHECK_NESTRET_ERROR (); - - if MBTEST(was_dollar && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Translate $'...' here. */ - ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen); - xfree (nestret); - - if ((rflags & P_DQUOTE) == 0) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else - { - nestret = ttrans; - nestlen = ttranslen; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - nestlen = ttranslen + 2; - retind -= 2; /* back up before the $" */ - } - - APPEND_NESTRET (); - 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); - - CHECK_NESTRET_ERROR (); - APPEND_NESTRET (); - - FREE (nestret); - } - else if MBTEST(open != '`' && 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 & ~P_DQUOTE); - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - - CHECK_NESTRET_ERROR (); - APPEND_NESTRET (); - - FREE (nestret); - } - was_dollar = MBTEST(ch == '$'); - } - - ret[retind] = '\0'; - if (lenp) - *lenp = retind; - return ret; -} - -/* Parse a $(...) command substitution. This is messier than I'd like, and - reproduces a lot more of the token-reading code than I'd like. */ -static char * -parse_comsub (qc, open, close, lenp, flags) - int qc; /* `"' if this construct is within double quotes */ - int open, close; - int *lenp, flags; -{ - int count, ch, peekc, tflags, lex_rwlen, lex_firstind; - int nestlen, ttranslen, start_lineno; - char *ret, *nestret, *ttrans, *heredelim; - int retind, retsize, rflags, hdlen; - -/*itrace("parse_comsub: qc = `%c' open = %c close = %c", qc, open, close);*/ - count = 1; - tflags = LEX_RESWDOK; - - if ((flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0) - tflags |= LEX_CKCASE; - if ((tflags & LEX_CKCASE) && (interactive == 0 || interactive_comments)) - tflags |= LEX_CKCOMMENT; - - /* RFLAGS is the set of flags we want to pass to recursive calls. */ - rflags = (flags & P_DQUOTE); - - ret = (char *)xmalloc (retsize = 64); - retind = 0; - - start_lineno = line_number; - lex_rwlen = 0; - - heredelim = 0; - lex_firstind = -1; - - while (count) - { -comsub_readchar: - ch = shell_getc (qc != '\'' && (tflags & LEX_PASSNEXT) == 0); - - if (ch == EOF) - { -eof_error: - free (ret); - FREE (heredelim); - parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), close); - EOF_Reached = 1; /* XXX */ - return (&matched_pair_error); - } - - /* If we hit the end of a line and are reading the contents of a here - document, and it's not the same line that the document starts on, - check for this line being the here doc delimiter. Otherwise, if - we're in a here document, mark the next character as the beginning - of a line. */ - if (ch == '\n') - { - if ((tflags & LEX_HEREDELIM) && heredelim) - { - tflags &= ~LEX_HEREDELIM; - tflags |= LEX_INHEREDOC; - lex_firstind = retind + 1; - } - else if (tflags & LEX_INHEREDOC) - { - int tind; - tind = lex_firstind; - while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t') - tind++; - if (STREQN (ret + tind, heredelim, hdlen)) - { - tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC); -/*itrace("parse_comsub:%d: found here doc end `%s'", line_number, ret + tind);*/ - lex_firstind = -1; - } - else - lex_firstind = retind + 1; - } - } - - /* Possible reprompting. */ - if (ch == '\n' && SHOULD_PROMPT ()) - prompt_again (); - - /* Don't bother counting parens or doing anything else if in a comment */ - if (tflags & (LEX_INCOMMENT|LEX_INHEREDOC)) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if ((tflags & LEX_INCOMMENT) && ch == '\n') - tflags &= ~LEX_INCOMMENT; - - continue; - } - - /* Skip whitespace */ - if MBTEST(shellblank (ch) && lex_rwlen == 0) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - continue; - } - - /* Either we are looking for the start of the here-doc delimiter - (lex_firstind == -1) or we are reading one (lex_firstind >= 0). - If this character is a shell break character and we are reading - the delimiter, save it and note that we are now reading a here - document. If we've found the start of the delimiter, note it by - setting lex_firstind. Backslashes can quote shell metacharacters - in here-doc delimiters. */ - if (tflags & LEX_HEREDELIM) - { - if (lex_firstind == -1 && shellbreak (ch) == 0) - lex_firstind = retind; - else if (lex_firstind >= 0 && (tflags & LEX_PASSNEXT) == 0 && shellbreak (ch)) - { - nestret = substring (ret, lex_firstind, retind); - heredelim = string_quote_removal (nestret, 0); - free (nestret); - hdlen = STRLEN(heredelim); -/*itrace("parse_comsub:%d: found here doc delimiter `%s' (%d)", line_number, heredelim, hdlen);*/ - if (ch == '\n') - { - tflags |= LEX_INHEREDOC; - tflags &= ~LEX_HEREDELIM; - lex_firstind = retind + 1; - } - else - lex_firstind = -1; - } - } - - /* Meta-characters that can introduce a reserved word. Not perfect yet. */ - if MBTEST((tflags & LEX_RESWDOK) == 0 && (tflags & LEX_CKCASE) && (tflags & LEX_INCOMMENT) == 0 && shellmeta(ch)) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - peekc = shell_getc (1); - if (ch == peekc && (ch == '&' || ch == '|' || ch == ';')) /* two-character tokens */ - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = peekc; -/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch); */ - tflags |= LEX_RESWDOK; - lex_rwlen = 0; - continue; - } - else if (ch == '\n' || COMSUB_META(ch)) - { - shell_ungetc (peekc); - tflags |= LEX_RESWDOK; -/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch);*/ - lex_rwlen = 0; - continue; - } - else if (ch == EOF) - goto eof_error; - else - { - /* `unget' the character we just added and fall through */ - retind--; - shell_ungetc (peekc); - } - } - - /* If we can read a reserved word, try to read one. */ - if (tflags & LEX_RESWDOK) - { - if MBTEST(islower (ch)) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - lex_rwlen++; - continue; - } - else if MBTEST(lex_rwlen == 4 && shellbreak (ch)) - { - if (STREQN (ret + retind - 4, "case", 4)) -{ - tflags |= LEX_INCASE; -/*itrace("parse_comsub:%d: found `case', lex_incase -> 1", line_number);*/ -} - else if (STREQN (ret + retind - 4, "esac", 4)) -{ - tflags &= ~LEX_INCASE; -/*itrace("parse_comsub:%d: found `esac', lex_incase -> 0", line_number);*/ -} - tflags &= ~LEX_RESWDOK; - } - else if (shellbreak (ch) == 0) -{ - tflags &= ~LEX_RESWDOK; -/*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/ -} - } - - if MBTEST((tflags & LEX_INCOMMENT) == 0 && (tflags & LEX_CKCASE) && ch == '<') - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - peekc = shell_getc (1); - if (peekc == EOF) - goto eof_error; - if (peekc == ch) - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = peekc; - peekc = shell_getc (1); - if (peekc == EOF) - goto eof_error; - if (peekc == '-') - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = peekc; - tflags |= LEX_STRIPDOC; - } - else - shell_ungetc (peekc); - tflags |= LEX_HEREDELIM; - lex_firstind = -1; - continue; - } - else - ch = peekc; /* fall through and continue XXX - this skips comments if peekc == '#' */ - } - /* Not exactly right yet, should handle shell metacharacters, too. If - any changes are made to this test, make analogous changes to subst.c: - extract_delimited_string(). */ - else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1]))) - tflags |= LEX_INCOMMENT; - - if (tflags & LEX_PASSNEXT) /* last char was backslash */ - { - tflags &= ~LEX_PASSNEXT; - 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; - } -#if 0 - else if MBTEST((tflags & LEX_INCASE) && ch == close && close == ')') - tflags &= ~LEX_INCASE; /* XXX */ -#endif - else if MBTEST(ch == close && (tflags & LEX_INCASE) == 0) /* ending delimiter */ -{ - count--; -/*itrace("parse_comsub:%d: found close: count = %d", line_number, count);*/ -} - else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && (tflags & LEX_INCASE) == 0 && ch == open) /* nested begin */ - count++; - - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - /* If we just read the ending character, don't bother continuing. */ - if (count == 0) - break; - - if MBTEST(ch == '\\') /* backslashes */ - tflags |= LEX_PASSNEXT; - - if MBTEST(shellquote (ch)) - { - /* '', ``, or "" inside $(...). */ - push_delimiter (dstack, ch); - if MBTEST((tflags & LEX_WASDOL) && 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); - CHECK_NESTRET_ERROR (); - - if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Translate $'...' here. */ - ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen); - xfree (nestret); - - if ((rflags & P_DQUOTE) == 0) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else - { - nestret = ttrans; - nestlen = ttranslen; - } - retind -= 2; /* back up before the $' */ - } - else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Locale expand $"..." here. */ - ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen); - xfree (nestret); - - nestret = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - nestlen = ttranslen + 2; - retind -= 2; /* back up before the $" */ - } - - APPEND_NESTRET (); - FREE (nestret); - } - else if MBTEST((tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ - /* check for $(), $[], or ${} inside command substitution. */ - { - if ((tflags & LEX_INCASE) == 0 && open == ch) /* undo previous increment */ - count--; - if (ch == '(') /* ) */ -#if 0 - nestret = parse_comsub (0, '(', ')', &nestlen, rflags & ~P_DQUOTE); -#else - nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE); -#endif - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - - CHECK_NESTRET_ERROR (); - APPEND_NESTRET (); - - FREE (nestret); - } - if MBTEST(ch == '$') - tflags |= LEX_WASDOL; - else - tflags &= ~LEX_WASDOL; - } - - FREE (heredelim); - ret[retind] = '\0'; - if (lenp) - *lenp = retind; -/*itrace("parse_comsub:%d: returning `%s'", line_number, ret);*/ - return ret; -} - -/* XXX - this needs to handle functionality like subst.c:no_longjmp_on_fatal_error; - maybe extract_command_subst should handle it. */ -char * -xparse_dolparen (base, string, indp, flags) - char *base; - char *string; - int *indp; - int flags; -{ - sh_parser_state_t ps; - int orig_ind, nc, sflags; - char *ret, *s, *ep, *ostring; - - /*yydebug = 1;*/ - orig_ind = *indp; - ostring = string; - - sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE; - if (flags & 0x010) /* EX_NOLONGJMP */ - sflags |= SEVAL_NOLONGJMP; - save_parser_state (&ps); - - /*(*/ - parser_state |= PST_CMDSUBST|PST_EOFTOKEN; /* allow instant ')' */ /*(*/ - shell_eof_token = ')'; - parse_string (string, "command substitution", sflags, &ep); - - restore_parser_state (&ps); - reset_parser (); - if (interactive) - token_to_read = 0; - - /* Need to find how many characters parse_and_execute consumed, update - *indp, if flags != 0, copy the portion of the string parsed into RET - and return it. If flags & 1 (EX_NOALLOC) we can return NULL. */ - - /*(*/ - if (ep[-1] != ')') - { -#if DEBUG - itrace("xparse_dolparen:%d: ep[-1] != RPAREN (%d), ep = `%s'", line_number, ep[-1], ep); -#endif - while (ep > ostring && ep[-1] == '\n') ep--; - } - - nc = ep - ostring; - *indp = ep - base - 1; - - /*(*/ -#if DEBUG - if (base[*indp] != ')') - itrace("xparse_dolparen:%d: base[%d] != RPAREN (%d), base = `%s'", line_number, *indp, base[*indp], base); -#endif - - if (flags & 1) - return (char *)NULL; - - if (nc == 0) - { - ret = xmalloc (1); - ret[0] = '\0'; - } - else - ret = substring (ostring, 0, nc - 1); - - 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, sline; - char *wval; - 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 = alloc_word_desc (); - wd->word = wval; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - return (ARITH_FOR_EXPRS); - } - else - return -1; /* ERROR */ - } -#endif - -#if defined (DPAREN_ARITHMETIC) - if (reserved_word_acceptable (last_read_token)) - { - sline = line_number; - - cmdtyp = parse_arith_cmd (&wval, 0); - if (cmdtyp == 1) /* arithmetic command */ - { - wd = alloc_word_desc (); - wd->word = wval; - wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - 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 && yylval.word->word[0] == '-' && yylval.word->word[2] == 0 && 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; - parser_state |= PST_REGEXP; - } -#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); - parser_state &= ~PST_REGEXP; - 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; -} - -/* XXX - possible changes here for `+=' */ -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; - - /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound - assignment. */ - int compound_assignment; - - /* 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 = compound_assignment = 0; - - for (;;) - { - if (character == EOF) - goto got_token; - - if (pass_next_character) - { - pass_next_character = 0; - goto got_escaped_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, (character == '`') ? P_COMMAND : 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 COND_REGEXP - /* When parsing a regexp as a single word inside a conditional command, - we need to special-case characters special to both the shell and - regular expressions. Right now, that is only '(' and '|'. */ /*)*/ - if MBTEST((parser_state & PST_REGEXP) && (character == '(' || character == '|')) /*)*/ - { - if (character == '|') - goto got_character; - - push_delimiter (dstack, character); - 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; - strcpy (token + token_index, ttok); - token_index += ttoklen; - FREE (ttok); - dollar_present = all_digit_token = 0; - goto next_character; - } -#endif /* COND_REGEXP */ - -#ifdef EXTENDED_GLOB - /* Parse a ksh-style extended pattern matching specification. */ - if MBTEST(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, P_COMMAND); - 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); - ttranslen = strlen (ttok); - ttrans = ttok; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - ttranslen += 2; - 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 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && 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; - compound_assignment = 1; -#if 1 - goto next_character; -#else - goto got_token; /* ksh93 seems to do this */ -#endif - } - 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: - - if (character == CTLESC || character == CTLNUL) - token[token_index++] = CTLESC; - - got_escaped_character: - - all_digit_token &= DIGIT (character); - dollar_present |= character == '$'; - - 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; /*(*/ - if (compound_assignment && token[token_index-1] == ')') - the_word->flags |= W_COMPASSIGN; - /* 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; - } - - if (command_token_position (last_read_token)) - { - struct builtin *b; - b = builtin_address_internal (token, 0); - if (b && (b->flags & ASSIGNMENT_BUILTIN)) - parser_state |= PST_ASSIGNOK; - else if (STREQ (token, "eval") || STREQ (token, "let")) - parser_state |= PST_ASSIGNOK; - } - - 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 SEMI_AND: - case SEMI_SEMI_AND: - 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 const int no_semi_successors[] = { - '\n', '{', '(', ')', ';', '&', '|', - CASE, DO, ELSE, IF, SEMI_SEMI, SEMI_AND, SEMI_SEMI_AND, 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 ";"; - } - else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT)) - 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, i; - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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]; - 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, t_string) == 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); - n = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; - i = 0; - if (n == CTLESC || n == CTLNUL) - temp[i++] = CTLESC; - temp[i++] = n; - temp[i] = '\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, 0); - 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 (tok) - int tok; -{ - char *t; - - if (t = find_token_in_alist (tok, word_token_alist, 0)) - return t; - - if (t = find_token_in_alist (tok, 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 (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, orig_last_token, assignok; - char *saved_token, *ret; - - saved_token = token; - orig_token_size = token_buffer_size; - orig_line_number = line_number; - orig_last_token = last_read_token; - - last_read_token = WORD; /* WORD to allow reserved words here */ - - token = (char *)NULL; - token_buffer_size = 0; - - assignok = parser_state&PST_ASSIGNOK; /* XXX */ - - 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(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 = orig_last_token; /* XXX - was 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; - - if (assignok) - parser_state |= PST_ASSIGNOK; - - 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 = (sh_parser_state_t *)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/parse.y.save2 b/parse.y.save2 deleted file mode 100644 index 2b1163742..000000000 --- a/parse.y.save2 +++ /dev/null @@ -1,5538 +0,0 @@ -/* Yacc grammar for bash. */ - -/* Copyright (C) 1989-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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.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 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 void rewind_input_string __P((void)); -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)); -static char *parse_comsub __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 (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; - -/* The token that currently denotes the end of parse. */ -int shell_eof_token; - -/* The token currently being read. */ -int current_token; - -/* 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 current parser state. */ -static int parser_state; - -/* 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 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 SEMI_AND SEMI_SEMI_AND -%token LESS_LESS_MINUS AND_GREATER AND_GREATER_GREATER LESS_GREATER -%token GREATER_BAR BAR_AND - -/* 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 '|' BAR_AND -%% - -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); */ - if (parser_state & PST_CMDSUBST) - parser_state |= PST_EOFTOKEN; - YYACCEPT; - } - | '\n' - { - /* Case of regular command, but not a very - interesting one. Return a NULL command. */ - global_command = (COMMAND *)NULL; - if (parser_state & PST_CMDSUBST) - parser_state |= PST_EOFTOKEN; - 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); - } - | AND_GREATER_GREATER WORD - { - redir.filename = $2; - $$ = make_redirection (1, r_append_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 - { $$ = $1; } - | case_clause_sequence pattern_list SEMI_SEMI - { $2->next = $1; $$ = $2; } - | pattern_list SEMI_AND - { $1->flags |= CASEPAT_FALLTHROUGH; $$ = $1; } - | case_clause_sequence pattern_list SEMI_AND - { $2->flags |= CASEPAT_FALLTHROUGH; $2->next = $1; $$ = $2; } - | pattern_list SEMI_SEMI_AND - { $1->flags |= CASEPAT_TESTNEXT; $$ = $1; } - | case_clause_sequence pattern_list SEMI_SEMI_AND - { $2->flags |= CASEPAT_TESTNEXT; $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 (); - if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) - { - global_command = $1; - eof_encountered = 0; - rewind_input_string (); - YYACCEPT; - } - } - | 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 (); - if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) - { - global_command = $1; - eof_encountered = 0; - rewind_input_string (); - YYACCEPT; - } - } - | simple_list1 ';' - { - $$ = $1; - if (need_here_doc) - gather_here_documents (); - if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) - { - global_command = $1; - eof_encountered = 0; - rewind_input_string (); - YYACCEPT; - } - } - ; - -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 - { - if ($2) - $2->flags |= CMD_INVERT_RETURN; - $$ = $2; - } - | timespec pipeline - { - if ($2) - $2->flags |= $1; - $$ = $2; - } - | timespec BANG pipeline - { - if ($3) - $3->flags |= $1|CMD_INVERT_RETURN; - $$ = $3; - } - | BANG timespec pipeline - { - if ($3) - $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, '|'); } - | pipeline BAR_AND newline_list pipeline - { - /* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */ - COMMAND *tc; - REDIRECTEE rd; - REDIRECT *r; - - tc = $1; - rd.dest = 1; - r = make_redirection (2, r_duplicating_output, rd); - if (tc->redirects) - { - register REDIRECT *t; - for (t = tc->redirects; t->next; t = t->next) - ; - t->next = r; - } - else - tc->redirects = r; - - $$ = command_connect ($1, $4, '|'); - } - | command - { $$ = $1; } - ; - -timespec: TIME - { $$ = CMD_TIME_PIPELINE; } - | TIME TIMEOPT - { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } - ; -%% - -/* 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 - -/* 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++; - } - terminate_immediately = 1; - - current_readline_line = readline (current_readline_prompt ? - current_readline_prompt : ""); - - terminate_immediately = 0; - 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); -} - -/* Count the number of characters we've consumed from bash_input.location.string - and read into shell_input_line, but have not returned from shell_getc. - That is the true input location. Rewind bash_input.location.string by - that number of characters, so it points to the last character actually - consumed by the parser. */ -void -rewind_input_string () -{ - int xchars; - - /* number of unconsumed characters in the input -- XXX need to take newlines - into account, e.g., $(...\n) */ - xchars = shell_input_line_len - shell_input_line_index; - - /* XXX - how to reflect bash_input.location.string back to string passed to - parse_and_execute or xparse_dolparen? xparse_dolparen needs to know how - far into the string we parsed. parse_and_execute knows where bash_input. - location.string is, and how far from orig_string that is -- that's the - number of characters the command consumed. */ - - /* bash_input.location.string - xchars should be where we parsed to */ - /* need to do more validation on xchars value for sanity -- test cases. */ - bash_input.location.string -= xchars; -} - -/* **************************************************************** */ -/* */ -/* 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) - { - if (interactive) - { - interrupt_immediately++; - terminate_immediately++; - } - result = getc_with_restart (bash_input.location.file); - if (interactive) - { - interrupt_immediately--; - terminate_immediately--; - } - } - 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) - { - /* Allow immediate exit if interrupted during input. */ - QUIT; - - c = yy_getc (); - - /* 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 }, - { ";&", SEMI_AND }, - { ";;&", SEMI_SEMI_AND }, - { "<<-", LESS_LESS_MINUS }, - { "<<<", LESS_LESS_LESS }, - { "&>", AND_GREATER }, - { "&>>", AND_GREATER_GREATER }, - { "<>", LESS_GREATER }, - { ">|", GREATER_BAR }, - { "|&", BAR_AND }, - { "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; - - QUIT; - - if (sigwinch_received) - { - sigwinch_received = 0; - get_new_window_size (0, (int *)0, (int *)0); - } - - 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 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 MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n') - { - if (SHOULD_PROMPT ()) - prompt_again (); - line_number++; - goto restart_read; - } - - 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_variable_command (command, vname) - char *command, *vname; -{ - 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), vname, SEVAL_NONINT|SEVAL_NOHIST); - - restore_parser_state (&ps); - bind_variable ("_", last_lastarg, 0); - 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); - - if ((parser_state & PST_EOFTOKEN) && current_token == shell_eof_token) - { - current_token = yacc_EOF; - if (bash_input.type == st_string) - rewind_input_string (); - } - parser_state &= ~PST_EOFTOKEN; - - 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 && (token) != SEMI_AND && (token) != SEMI_SEMI_AND && 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 && shellblank (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 */ - - parser_state &= ~PST_ASSIGNOK; - - return (character); - } - - if (parser_state & PST_REGEXP) - goto tokword; - - /* 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 */ - - parser_state &= ~PST_ASSIGNOK; - - 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 MBTEST(peek_char == '-') - return (LESS_LESS_MINUS); - else if MBTEST(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 */ - peek_char = shell_getc (1); - if MBTEST(peek_char == '&') - return (SEMI_SEMI_AND); - else - { - shell_ungetc (peek_char); - 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(character == '&' && peek_char == '>') - { - peek_char = shell_getc (1); - if MBTEST(peek_char == '>') - return (AND_GREATER_GREATER); - else - { - shell_ungetc (peek_char); - return (AND_GREATER); - } - } - else if MBTEST(character == '|' && peek_char == '&') - return (BAR_AND); - else if MBTEST(character == ';' && peek_char == '&') - { - parser_state |= PST_CASEPAT; -#if defined (ALIAS) - parser_state &= ~PST_ALEXPNEXT; -#endif /* ALIAS */ - return (SEMI_AND); - } - - 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); - -tokword: - /* 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, and returning - * correct error values if it reads EOF. - */ -#define P_FIRSTCLOSE 0x01 -#define P_ALLOWESC 0x02 -#define P_DQUOTE 0x04 -#define P_COMMAND 0x08 /* parsing a command, so look for comments */ -#define P_BACKQUOTE 0x10 /* parsing a backquoted command substitution */ - -/* Lexical state while parsing a grouping construct or $(...). */ -#define LEX_WASDOL 0x001 -#define LEX_CKCOMMENT 0x002 -#define LEX_INCOMMENT 0x004 -#define LEX_PASSNEXT 0x008 -#define LEX_RESWDOK 0x010 -#define LEX_CKCASE 0x020 -#define LEX_INCASE 0x040 -#define LEX_INHEREDOC 0x080 -#define LEX_HEREDELIM 0x100 /* reading here-doc delimiter */ -#define LEX_STRIPDOC 0x200 /* <<- strip tabs from here doc delim */ - -#define COMSUB_META(ch) ((ch) == ';' || (ch) == '&' || (ch) == '|') - -#define CHECK_NESTRET_ERROR() \ - do { \ - if (nestret == &matched_pair_error) \ - { \ - free (ret); \ - return &matched_pair_error; \ - } \ - } while (0) - -#define APPEND_NESTRET() \ - do { \ - if (nestlen) \ - { \ - RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); \ - strcpy (ret + retind, nestret); \ - retind += nestlen; \ - } \ - } while (0) - -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, tflags; - int nestlen, ttranslen, start_lineno; - char *ret, *nestret, *ttrans; - int retind, retsize, rflags; - -/* itrace("parse_matched_pair: open = %c close = %c", open, close); */ - count = 1; - tflags = 0; - - if ((flags & P_COMMAND) && qc != '`' && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0) - tflags |= LEX_CKCOMMENT; - - /* 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 != '\'' && (tflags & LEX_PASSNEXT) == 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 (); - - /* Don't bother counting parens or doing anything else if in a comment - or part of a case statement */ - if (tflags & LEX_INCOMMENT) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if (ch == '\n') - tflags &= ~LEX_INCOMMENT; - - continue; - } - - /* Not exactly right yet, should handle shell metacharacters, too. If - any changes are made to this test, make analogous changes to subst.c: - extract_delimited_string(). */ - else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1]))) - tflags |= LEX_INCOMMENT; - - if (tflags & LEX_PASSNEXT) /* last char was backslash */ - { - tflags &= ~LEX_PASSNEXT; - 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--; - /* handle nested ${...} specially. */ - else if MBTEST(open != close && (tflags & LEX_WASDOL) && open == '{' && ch == open) /* } */ - count++; - 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 we just read the ending character, don't bother continuing. */ - if (count == 0) - break; - - if (open == '\'') /* '' inside grouping construct */ - { - if MBTEST((flags & P_ALLOWESC) && ch == '\\') - tflags |= LEX_PASSNEXT; - continue; - } - - if MBTEST(ch == '\\') /* backslashes */ - tflags |= LEX_PASSNEXT; - - /* Could also check open == '`' if we want to parse grouping constructs - inside old-style command substitution. */ - if (open != close) /* a grouping construct */ - { - if MBTEST(shellquote (ch)) - { - /* '', ``, or "" inside $(...) or other grouping construct. */ - push_delimiter (dstack, ch); - if MBTEST((tflags & LEX_WASDOL) && 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); - CHECK_NESTRET_ERROR (); - - if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Translate $'...' here. */ - ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen); - xfree (nestret); - - if ((rflags & P_DQUOTE) == 0) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else - { - nestret = ttrans; - nestlen = ttranslen; - } - retind -= 2; /* back up before the $' */ - } - else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Locale expand $"..." here. */ - ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen); - xfree (nestret); - - nestret = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - nestlen = ttranslen + 2; - retind -= 2; /* back up before the $" */ - } - - APPEND_NESTRET (); - 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); - - CHECK_NESTRET_ERROR (); - APPEND_NESTRET (); - - FREE (nestret); - } - else if MBTEST(open != '`' && (tflags & LEX_WASDOL) && (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 & ~P_DQUOTE); - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - - CHECK_NESTRET_ERROR (); - APPEND_NESTRET (); - - FREE (nestret); - } - if MBTEST(ch == '$') - tflags |= LEX_WASDOL; - else - tflags &= ~LEX_WASDOL; - } - - ret[retind] = '\0'; - if (lenp) - *lenp = retind; - return ret; -} - -/* Parse a $(...) command substitution. This is messier than I'd like, and - reproduces a lot more of the token-reading code than I'd like. */ -static char * -parse_comsub (qc, open, close, lenp, flags) - int qc; /* `"' if this construct is within double quotes */ - int open, close; - int *lenp, flags; -{ - int count, ch, peekc, tflags, lex_rwlen, lex_firstind; - int nestlen, ttranslen, start_lineno; - char *ret, *nestret, *ttrans, *heredelim; - int retind, retsize, rflags, hdlen; - -/*itrace("parse_comsub: qc = `%c' open = %c close = %c", qc, open, close);*/ - count = 1; - tflags = LEX_RESWDOK; - - if ((flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0) - tflags |= LEX_CKCASE; - if ((tflags & LEX_CKCASE) && (interactive == 0 || interactive_comments)) - tflags |= LEX_CKCOMMENT; - - /* RFLAGS is the set of flags we want to pass to recursive calls. */ - rflags = (flags & P_DQUOTE); - - ret = (char *)xmalloc (retsize = 64); - retind = 0; - - start_lineno = line_number; - lex_rwlen = 0; - - heredelim = 0; - lex_firstind = -1; - - while (count) - { -comsub_readchar: - ch = shell_getc (qc != '\'' && (tflags & LEX_PASSNEXT) == 0); - - if (ch == EOF) - { -eof_error: - free (ret); - FREE (heredelim); - parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), close); - EOF_Reached = 1; /* XXX */ - return (&matched_pair_error); - } - - /* If we hit the end of a line and are reading the contents of a here - document, and it's not the same line that the document starts on, - check for this line being the here doc delimiter. Otherwise, if - we're in a here document, mark the next character as the beginning - of a line. */ - if (ch == '\n') - { - if ((tflags & LEX_HEREDELIM) && heredelim) - { - tflags &= ~LEX_HEREDELIM; - tflags |= LEX_INHEREDOC; - lex_firstind = retind + 1; - } - else if (tflags & LEX_INHEREDOC) - { - int tind; - tind = lex_firstind; - while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t') - tind++; - if (STREQN (ret + tind, heredelim, hdlen)) - { - tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC); -/*itrace("parse_comsub:%d: found here doc end `%s'", line_number, ret + tind);*/ - lex_firstind = -1; - } - else - lex_firstind = retind + 1; - } - } - - /* Possible reprompting. */ - if (ch == '\n' && SHOULD_PROMPT ()) - prompt_again (); - - /* Don't bother counting parens or doing anything else if in a comment */ - if (tflags & (LEX_INCOMMENT|LEX_INHEREDOC)) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if ((tflags & LEX_INCOMMENT) && ch == '\n') - tflags &= ~LEX_INCOMMENT; - - continue; - } - - /* Skip whitespace */ - if MBTEST(shellblank (ch) && lex_rwlen == 0) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - continue; - } - - /* Either we are looking for the start of the here-doc delimiter - (lex_firstind == -1) or we are reading one (lex_firstind >= 0). - If this character is a shell break character and we are reading - the delimiter, save it and note that we are now reading a here - document. If we've found the start of the delimiter, note it by - setting lex_firstind. Backslashes can quote shell metacharacters - in here-doc delimiters. */ - if (tflags & LEX_HEREDELIM) - { - if (lex_firstind == -1 && shellbreak (ch) == 0) - lex_firstind = retind; - else if (lex_firstind >= 0 && (tflags & LEX_PASSNEXT) == 0 && shellbreak (ch)) - { - nestret = substring (ret, lex_firstind, retind); - heredelim = string_quote_removal (nestret, 0); - free (nestret); - hdlen = STRLEN(heredelim); -/*itrace("parse_comsub:%d: found here doc delimiter `%s' (%d)", line_number, heredelim, hdlen);*/ - if (ch == '\n') - { - tflags |= LEX_INHEREDOC; - tflags &= ~LEX_HEREDELIM; - lex_firstind = retind + 1; - } - else - lex_firstind = -1; - } - } - - /* Meta-characters that can introduce a reserved word. Not perfect yet. */ - if MBTEST((tflags & LEX_RESWDOK) == 0 && (tflags & LEX_CKCASE) && (tflags & LEX_INCOMMENT) == 0 && shellmeta(ch)) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - peekc = shell_getc (1); - if (ch == peekc && (ch == '&' || ch == '|' || ch == ';')) /* two-character tokens */ - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = peekc; -/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch); */ - tflags |= LEX_RESWDOK; - lex_rwlen = 0; - continue; - } - else if (ch == '\n' || COMSUB_META(ch)) - { - shell_ungetc (peekc); - tflags |= LEX_RESWDOK; -/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch);*/ - lex_rwlen = 0; - continue; - } - else if (ch == EOF) - goto eof_error; - else - { - /* `unget' the character we just added and fall through */ - retind--; - shell_ungetc (peekc); - } - } - - /* If we can read a reserved word, try to read one. */ - if (tflags & LEX_RESWDOK) - { - if MBTEST(islower (ch)) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - lex_rwlen++; - continue; - } - else if MBTEST(lex_rwlen == 4 && shellbreak (ch)) - { - if (STREQN (ret + retind - 4, "case", 4)) -{ - tflags |= LEX_INCASE; -/*itrace("parse_comsub:%d: found `case', lex_incase -> 1", line_number);*/ -} - else if (STREQN (ret + retind - 4, "esac", 4)) -{ - tflags &= ~LEX_INCASE; -/*itrace("parse_comsub:%d: found `esac', lex_incase -> 0", line_number);*/ -} - tflags &= ~LEX_RESWDOK; - } - else if (shellbreak (ch) == 0) -{ - tflags &= ~LEX_RESWDOK; -/*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/ -} - } - - if MBTEST((tflags & LEX_INCOMMENT) == 0 && (tflags & LEX_CKCASE) && ch == '<') - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - peekc = shell_getc (1); - if (peekc == EOF) - goto eof_error; - if (peekc == ch) - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = peekc; - peekc = shell_getc (1); - if (peekc == EOF) - goto eof_error; - if (peekc == '-') - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = peekc; - tflags |= LEX_STRIPDOC; - } - else - shell_ungetc (peekc); - tflags |= LEX_HEREDELIM; - lex_firstind = -1; - continue; - } - else - ch = peekc; /* fall through and continue XXX - this skips comments if peekc == '#' */ - } - /* Not exactly right yet, should handle shell metacharacters, too. If - any changes are made to this test, make analogous changes to subst.c: - extract_delimited_string(). */ - else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1]))) - tflags |= LEX_INCOMMENT; - - if (tflags & LEX_PASSNEXT) /* last char was backslash */ - { - tflags &= ~LEX_PASSNEXT; - 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; - } -#if 0 - else if MBTEST((tflags & LEX_INCASE) && ch == close && close == ')') - tflags &= ~LEX_INCASE; /* XXX */ -#endif - else if MBTEST(ch == close && (tflags & LEX_INCASE) == 0) /* ending delimiter */ -{ - count--; -/*itrace("parse_comsub:%d: found close: count = %d", line_number, count);*/ -} - else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && (tflags & LEX_INCASE) == 0 && ch == open) /* nested begin */ - count++; - - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - /* If we just read the ending character, don't bother continuing. */ - if (count == 0) - break; - - if MBTEST(ch == '\\') /* backslashes */ - tflags |= LEX_PASSNEXT; - - if MBTEST(shellquote (ch)) - { - /* '', ``, or "" inside $(...). */ - push_delimiter (dstack, ch); - if MBTEST((tflags & LEX_WASDOL) && 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); - CHECK_NESTRET_ERROR (); - - if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Translate $'...' here. */ - ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen); - xfree (nestret); - - if ((rflags & P_DQUOTE) == 0) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else - { - nestret = ttrans; - nestlen = ttranslen; - } - retind -= 2; /* back up before the $' */ - } - else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Locale expand $"..." here. */ - ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen); - xfree (nestret); - - nestret = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - nestlen = ttranslen + 2; - retind -= 2; /* back up before the $" */ - } - - APPEND_NESTRET (); - FREE (nestret); - } - else if MBTEST((tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ - /* check for $(), $[], or ${} inside command substitution. */ - { - if ((tflags & LEX_INCASE) == 0 && open == ch) /* undo previous increment */ - count--; - if (ch == '(') /* ) */ - nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE); - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - - CHECK_NESTRET_ERROR (); - APPEND_NESTRET (); - - FREE (nestret); - } - if MBTEST(ch == '$') - tflags |= LEX_WASDOL; - else - tflags &= ~LEX_WASDOL; - } - - FREE (heredelim); - ret[retind] = '\0'; - if (lenp) - *lenp = retind; -/*itrace("parse_comsub:%d: returning `%s'", line_number, ret);*/ - return ret; -} - -/* XXX - this needs to handle functionality like subst.c:no_longjmp_on_fatal_error; - maybe extract_command_subst should handle it. */ -char * -xparse_dolparen (base, string, indp, flags) - char *base; - char *string; - int *indp; - int flags; -{ - sh_parser_state_t ps; - int orig_ind, nc, sflags; - char *ret, *s, *ep, *ostring; - - /*yydebug = 1;*/ - orig_ind = *indp; - ostring = string; - - sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE; - if (flags & 0x010) /* EX_NOLONGJMP */ - sflags |= SEVAL_NOLONGJMP; - save_parser_state (&ps); - - /*(*/ - parser_state |= PST_CMDSUBST|PST_EOFTOKEN; /* allow instant ')' */ /*(*/ - shell_eof_token = ')'; - parse_string (string, "command substitution", sflags, &ep); - - restore_parser_state (&ps); - reset_parser (); - if (interactive) - token_to_read = 0; - - /* Need to find how many characters parse_and_execute consumed, update - *indp, if flags != 0, copy the portion of the string parsed into RET - and return it. If flags & 1 (EX_NOALLOC) we can return NULL. */ - - /*(*/ - if (ep[-1] != ')') - { -#if DEBUG - itrace("xparse_dolparen:%d: ep[-1] != RPAREN (%d), ep = `%s'", line_number, ep[-1], ep); -#endif - while (ep > ostring && ep[-1] == '\n') ep--; - } - - nc = ep - ostring; - *indp = ep - base - 1; - - /*(*/ -#if DEBUG - if (base[*indp] != ')') - itrace("xparse_dolparen:%d: base[%d] != RPAREN (%d), base = `%s'", line_number, *indp, base[*indp], base); -#endif - - if (flags & 1) - return (char *)NULL; - - if (nc == 0) - { - ret = xmalloc (1); - ret[0] = '\0'; - } - else - ret = substring (ostring, 0, nc - 1); - - 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, sline; - char *wval; - 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 = alloc_word_desc (); - wd->word = wval; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - return (ARITH_FOR_EXPRS); - } - else - return -1; /* ERROR */ - } -#endif - -#if defined (DPAREN_ARITHMETIC) - if (reserved_word_acceptable (last_read_token)) - { - sline = line_number; - - cmdtyp = parse_arith_cmd (&wval, 0); - if (cmdtyp == 1) /* arithmetic command */ - { - wd = alloc_word_desc (); - wd->word = wval; - wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - 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 && yylval.word->word[0] == '-' && yylval.word->word[2] == 0 && 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; - parser_state |= PST_REGEXP; - } -#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); - parser_state &= ~PST_REGEXP; - 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; -} - -/* XXX - possible changes here for `+=' */ -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; - - /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound - assignment. */ - int compound_assignment; - - /* 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 = compound_assignment = 0; - - for (;;) - { - if (character == EOF) - goto got_token; - - if (pass_next_character) - { - pass_next_character = 0; - goto got_escaped_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, (character == '`') ? P_COMMAND : 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 COND_REGEXP - /* When parsing a regexp as a single word inside a conditional command, - we need to special-case characters special to both the shell and - regular expressions. Right now, that is only '(' and '|'. */ /*)*/ - if MBTEST((parser_state & PST_REGEXP) && (character == '(' || character == '|')) /*)*/ - { - if (character == '|') - goto got_character; - - push_delimiter (dstack, character); - 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; - strcpy (token + token_index, ttok); - token_index += ttoklen; - FREE (ttok); - dollar_present = all_digit_token = 0; - goto next_character; - } -#endif /* COND_REGEXP */ - -#ifdef EXTENDED_GLOB - /* Parse a ksh-style extended pattern matching specification. */ - if MBTEST(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, P_COMMAND); - 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); - ttranslen = strlen (ttok); - ttrans = ttok; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - ttranslen += 2; - 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 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && 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; - compound_assignment = 1; -#if 1 - goto next_character; -#else - goto got_token; /* ksh93 seems to do this */ -#endif - } - 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: - - if (character == CTLESC || character == CTLNUL) - token[token_index++] = CTLESC; - - got_escaped_character: - - all_digit_token &= DIGIT (character); - dollar_present |= character == '$'; - - 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; /*(*/ - if (compound_assignment && token[token_index-1] == ')') - the_word->flags |= W_COMPASSIGN; - /* 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; - } - - if (command_token_position (last_read_token)) - { - struct builtin *b; - b = builtin_address_internal (token, 0); - if (b && (b->flags & ASSIGNMENT_BUILTIN)) - parser_state |= PST_ASSIGNOK; - else if (STREQ (token, "eval") || STREQ (token, "let")) - parser_state |= PST_ASSIGNOK; - } - - 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 SEMI_AND: - case SEMI_SEMI_AND: - 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 const int no_semi_successors[] = { - '\n', '{', '(', ')', ';', '&', '|', - CASE, DO, ELSE, IF, SEMI_SEMI, SEMI_AND, SEMI_SEMI_AND, 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 ";"; - } - else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT)) - 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, i; - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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]; - 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, t_string) == 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)); - - temp = trim_pathname (t_string, PATH_MAX - 1); - /* 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); - n = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; - i = 0; - if (n == CTLESC || n == CTLNUL) - temp[i++] = CTLESC; - temp[i++] = n; - temp[i] = '\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, 0); - 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 (tok) - int tok; -{ - char *t; - - if (t = find_token_in_alist (tok, word_token_alist, 0)) - return t; - - if (t = find_token_in_alist (tok, 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 (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, orig_last_token, assignok; - char *saved_token, *ret; - - saved_token = token; - orig_token_size = token_buffer_size; - orig_line_number = line_number; - orig_last_token = last_read_token; - - last_read_token = WORD; /* WORD to allow reserved words here */ - - token = (char *)NULL; - token_buffer_size = 0; - - assignok = parser_state&PST_ASSIGNOK; /* XXX */ - - 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(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 = orig_last_token; /* XXX - was 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; - - if (assignok) - parser_state |= PST_ASSIGNOK; - - 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 = (sh_parser_state_t *)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/parse.y.save26 b/parse.y.save26 deleted file mode 100644 index 97f603b7a..000000000 --- a/parse.y.save26 +++ /dev/null @@ -1,4927 +0,0 @@ -/* Yacc grammar for bash. */ - -/* Copyright (C) 1989-2005 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file 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.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 - { - if ($2) - $2->flags |= CMD_INVERT_RETURN; - $$ = $2; - } - | timespec pipeline - { - if ($2) - $2->flags |= $1; - $$ = $2; - } - | timespec BANG pipeline - { - if ($3) - $3->flags |= $1|CMD_INVERT_RETURN; - $$ = $3; - } - | BANG timespec pipeline - { - if ($3) - $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 */ -#define PST_ASSIGNOK 0x4000 /* assignment statement ok in this context */ - -/* 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) - { - if (interactive) - interrupt_immediately++; - result = getc_with_restart (bash_input.location.file); - if (interactive) - interrupt_immediately--; - } - 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) - { - /* Allow immediate exit if interrupted during input. */ - QUIT; - - c = yy_getc (); - - /* 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 (sigwinch_received) - { - sigwinch_received = 0; - get_new_window_size (0, (int *)0, (int *)0); - } - - 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 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 MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n') - { - if (SHOULD_PROMPT ()) - prompt_again (); - line_number++; - goto restart_read; - } - - 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, 0); - 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 */ - - parser_state &= ~PST_ASSIGNOK; - - 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 */ - - parser_state &= ~PST_ASSIGNOK; - - 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, and returning - * correct error values if it reads EOF. - */ -#define P_FIRSTCLOSE 0x01 -#define P_ALLOWESC 0x02 -#define P_DQUOTE 0x04 -#define P_COMMAND 0x08 /* parsing a command, so look for comments */ - -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, in_comment, check_comment; - int pass_next_character, nestlen, ttranslen, start_lineno; - char *ret, *nestret, *ttrans; - int retind, retsize, rflags; - - count = 1; - pass_next_character = was_dollar = in_comment = 0; - check_comment = (flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 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) - { -#if 0 - ch = shell_getc ((qc != '\'' || (flags & P_ALLOWESC)) && pass_next_character == 0); -#else - ch = shell_getc (qc != '\'' && pass_next_character == 0); -#endif - 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 (in_comment) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if (ch == '\n') - in_comment = 0; - - continue; - } - /* Not exactly right yet */ - else if (check_comment && in_comment == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || whitespace (ret[retind -1]))) - in_comment = 1; - - 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); - - if ((rflags & P_DQUOTE) == 0) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else - { - nestret = ttrans; - nestlen = ttranslen; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - nestlen = ttranslen + 2; - 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); -add_nestret: - 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(qc == '`' && (ch == '"' || ch == '\'') && in_comment == 0) - { - nestret = parse_matched_pair (0, ch, ch, &nestlen, rflags); - goto add_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 & ~P_DQUOTE); - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - - goto add_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 = alloc_word_desc (); - wd->word = wval; - wd = make_word (wval); - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - return (ARITH_FOR_EXPRS); - } - else - return -1; /* ERROR */ - } -#endif - -#if defined (DPAREN_ARITHMETIC) - if (reserved_word_acceptable (last_read_token)) - { - sline = line_number; - - cmdtyp = parse_arith_cmd (&wval, 0); - if (cmdtyp == 1) /* arithmetic command */ - { - wd = alloc_word_desc (); - wd->word = wval; - wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - 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; -} - -/* XXX - possible changes here for `+=' */ -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; - - /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound - assignment. */ - int compound_assignment; - - /* 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 = compound_assignment = 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, (character == '`') ? P_COMMAND : 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, P_COMMAND); - 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); - ttranslen = strlen (ttok); - ttrans = ttok; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - ttranslen += 2; - 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 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && 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; - compound_assignment = 1; -#if 0 - goto next_character; -#else - goto got_token; /* ksh93 seems to do this */ -#endif - } - 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; - if (compound_assignment) - the_word->flags |= W_COMPASSIGN; - /* 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; - } - - if (command_token_position (last_read_token)) - { - struct builtin *b; - b = builtin_address_internal (token, 0); - if (b && (b->flags & ASSIGNMENT_BUILTIN)) - parser_state |= PST_ASSIGNOK; - else if (STREQ (token, "eval") || STREQ (token, "let")) - parser_state |= PST_ASSIGNOK; - } - - 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 ";"; - } - else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT)) - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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, t_string) == 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] = CTLESC; - 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 (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, orig_last_token, assignok; - char *saved_token, *ret; - - saved_token = token; - orig_token_size = token_buffer_size; - orig_line_number = line_number; - orig_last_token = last_read_token; - - last_read_token = WORD; /* WORD to allow reserved words here */ - - token = (char *)NULL; - token_buffer_size = 0; - - assignok = parser_state&PST_ASSIGNOK; /* XXX */ - - 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(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 = orig_last_token; /* XXX - was 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; - - if (assignok) - parser_state |= PST_ASSIGNOK; - - 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 = (sh_parser_state_t *)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/parse.y~ b/parse.y~ deleted file mode 100644 index df950cf07..000000000 --- a/parse.y~ +++ /dev/null @@ -1,5649 +0,0 @@ -/* parse.y - Yacc grammar for bash. */ - -/* Copyright (C) 1989-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -%{ -#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.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, parse_and_execute_level; -extern int posixly_correct; -extern int last_command_exit_value; -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 void rewind_input_string __P((void)); -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)); -static char *parse_comsub __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 (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; - -/* The token that currently denotes the end of parse. */ -int shell_eof_token; - -/* The token currently being read. */ -int current_token; - -/* 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 current parser state. */ -static int parser_state; - -/* 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 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 COPROC -%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 SEMI_AND SEMI_SEMI_AND -%token LESS_LESS_MINUS AND_GREATER AND_GREATER_GREATER LESS_GREATER -%token GREATER_BAR BAR_AND - -/* 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 coproc -%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 '|' BAR_AND -%% - -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); */ - if (parser_state & PST_CMDSUBST) - parser_state |= PST_EOFTOKEN; - YYACCEPT; - } - | '\n' - { - /* Case of regular command, but not a very - interesting one. Return a NULL command. */ - global_command = (COMMAND *)NULL; - if (parser_state & PST_CMDSUBST) - parser_state |= PST_EOFTOKEN; - YYACCEPT; - } - | error '\n' - { - /* Error during parsing. Return NULL command. */ - global_command = (COMMAND *)NULL; - eof_encountered = 0; - /* discard_parser_constructs (1); */ - if (interactive && parse_and_execute_level == 0) - { - 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); - } - | AND_GREATER_GREATER WORD - { - redir.filename = $2; - $$ = make_redirection (1, r_append_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; } - | coproc - { $$ = $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; - } - ; - -coproc: COPROC shell_command - { - $$ = make_coproc_command ("COPROC", $2); - $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; - } - | COPROC shell_command redirection_list - { - COMMAND *tc; - - tc = $2; - if (tc->redirects) - { - register REDIRECT *t; - for (t = tc->redirects; t->next; t = t->next) - ; - t->next = $3; - } - else - tc->redirects = $3; - $$ = make_coproc_command ("COPROC", $2); - $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; - } - | COPROC WORD shell_command - { - $$ = make_coproc_command ($2->word, $3); - $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; - } - | COPROC WORD shell_command redirection_list - { - COMMAND *tc; - - tc = $3; - if (tc->redirects) - { - register REDIRECT *t; - for (t = tc->redirects; t->next; t = t->next) - ; - t->next = $4; - } - else - tc->redirects = $4; - $$ = make_coproc_command ($2->word, $3); - $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; - } - | COPROC simple_command - { - $$ = make_coproc_command ("COPROC", clean_simple_command ($2)); - $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_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 - { $$ = $1; } - | case_clause_sequence pattern_list SEMI_SEMI - { $2->next = $1; $$ = $2; } - | pattern_list SEMI_AND - { $1->flags |= CASEPAT_FALLTHROUGH; $$ = $1; } - | case_clause_sequence pattern_list SEMI_AND - { $2->flags |= CASEPAT_FALLTHROUGH; $2->next = $1; $$ = $2; } - | pattern_list SEMI_SEMI_AND - { $1->flags |= CASEPAT_TESTNEXT; $$ = $1; } - | case_clause_sequence pattern_list SEMI_SEMI_AND - { $2->flags |= CASEPAT_TESTNEXT; $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 (); - if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) - { - global_command = $1; - eof_encountered = 0; - rewind_input_string (); - YYACCEPT; - } - } - | 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 (); - if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) - { - global_command = $1; - eof_encountered = 0; - rewind_input_string (); - YYACCEPT; - } - } - | simple_list1 ';' - { - $$ = $1; - if (need_here_doc) - gather_here_documents (); - if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) - { - global_command = $1; - eof_encountered = 0; - rewind_input_string (); - YYACCEPT; - } - } - ; - -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 - { - if ($2) - $2->flags |= CMD_INVERT_RETURN; - $$ = $2; - } - | timespec pipeline - { - if ($2) - $2->flags |= $1; - $$ = $2; - } - | timespec BANG pipeline - { - if ($3) - $3->flags |= $1|CMD_INVERT_RETURN; - $$ = $3; - } - | BANG timespec pipeline - { - if ($3) - $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, '|'); } - | pipeline BAR_AND newline_list pipeline - { - /* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */ - COMMAND *tc; - REDIRECTEE rd; - REDIRECT *r; - - tc = $1; - rd.dest = 1; - r = make_redirection (2, r_duplicating_output, rd); - if (tc->redirects) - { - register REDIRECT *t; - for (t = tc->redirects; t->next; t = t->next) - ; - t->next = r; - } - else - tc->redirects = r; - - $$ = command_connect ($1, $4, '|'); - } - | command - { $$ = $1; } - ; - -timespec: TIME - { $$ = CMD_TIME_PIPELINE; } - | TIME TIMEOPT - { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } - ; -%% - -/* 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 - -/* 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++; - } - terminate_immediately = 1; - - current_readline_line = readline (current_readline_prompt ? - current_readline_prompt : ""); - - terminate_immediately = 0; - 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); -} - -/* Count the number of characters we've consumed from bash_input.location.string - and read into shell_input_line, but have not returned from shell_getc. - That is the true input location. Rewind bash_input.location.string by - that number of characters, so it points to the last character actually - consumed by the parser. */ -void -rewind_input_string () -{ - int xchars; - - /* number of unconsumed characters in the input -- XXX need to take newlines - into account, e.g., $(...\n) */ - xchars = shell_input_line_len - shell_input_line_index; - - /* XXX - how to reflect bash_input.location.string back to string passed to - parse_and_execute or xparse_dolparen? xparse_dolparen needs to know how - far into the string we parsed. parse_and_execute knows where bash_input. - location.string is, and how far from orig_string that is -- that's the - number of characters the command consumed. */ - - /* bash_input.location.string - xchars should be where we parsed to */ - /* need to do more validation on xchars value for sanity -- test cases. */ - bash_input.location.string -= xchars; -} - -/* **************************************************************** */ -/* */ -/* 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) - { - if (interactive) - { - interrupt_immediately++; - terminate_immediately++; - } - result = getc_with_restart (bash_input.location.file); - if (interactive) - { - interrupt_immediately--; - terminate_immediately--; - } - } - 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) - { - /* Allow immediate exit if interrupted during input. */ - QUIT; - - c = yy_getc (); - - /* 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; -{ - char *ret; - int n, c; - - prompt_string_pointer = &ps2_prompt; - if (SHOULD_PROMPT()) - prompt_again (); - ret = read_a_line (remove_quoted_newline); - if (remember_on_history && (parser_state & PST_HEREDOC)) - { - /* To make adding the the here-document body right, we need to rely - on history_delimiting_chars() returning \n for the first line of - the here-document body and the null string for the second and - subsequent lines, so we avoid double newlines. - current_command_line_count == 2 for the first line of the body. */ - - current_command_line_count++; - maybe_add_history (ret); - } - return ret; -} - -/* **************************************************************** */ -/* */ -/* 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 -#if defined (COPROCESS_SUPPORT) - { "coproc", COPROC }, -#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 }, - { ";&", SEMI_AND }, - { ";;&", SEMI_SEMI_AND }, - { "<<-", LESS_LESS_MINUS }, - { "<<<", LESS_LESS_LESS }, - { "&>", AND_GREATER }, - { "&>>", AND_GREATER_GREATER }, - { "<>", LESS_GREATER }, - { ">|", GREATER_BAR }, - { "|&", BAR_AND }, - { "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; - - QUIT; - - if (sigwinch_received) - { - sigwinch_received = 0; - get_new_window_size (0, (int *)0, (int *)0); - } - - 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 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 MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n') - { - if (SHOULD_PROMPT ()) - prompt_again (); - line_number++; - goto restart_read; - } - - 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_variable_command (command, vname) - char *command, *vname; -{ - 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), vname, SEVAL_NONINT|SEVAL_NOHIST); - - restore_parser_state (&ps); - bind_variable ("_", last_lastarg, 0); - 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); - - if ((parser_state & PST_EOFTOKEN) && current_token == shell_eof_token) - { - current_token = yacc_EOF; - if (bash_input.type == st_string) - rewind_input_string (); - } - parser_state &= ~PST_EOFTOKEN; - - 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; - - r = 0; - while (need_here_doc) - { - parser_state |= PST_HEREDOC; - make_here_document (redir_stack[r++], line_number); - parser_state &= ~PST_HEREDOC; - 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 && (token) != SEMI_AND && (token) != SEMI_SEMI_AND && 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 && shellblank (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 */ - - parser_state &= ~PST_ASSIGNOK; - - return (character); - } - - if (parser_state & PST_REGEXP) - goto tokword; - - /* 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 */ - - parser_state &= ~PST_ASSIGNOK; - - 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 MBTEST(peek_char == '-') - return (LESS_LESS_MINUS); - else if MBTEST(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 */ - - peek_char = shell_getc (1); - if MBTEST(peek_char == '&') - return (SEMI_SEMI_AND); - else - { - shell_ungetc (peek_char); - 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(character == '&' && peek_char == '>') - { - peek_char = shell_getc (1); - if MBTEST(peek_char == '>') - return (AND_GREATER_GREATER); - else - { - shell_ungetc (peek_char); - return (AND_GREATER); - } - } - else if MBTEST(character == '|' && peek_char == '&') - return (BAR_AND); - else if MBTEST(character == ';' && peek_char == '&') - { - parser_state |= PST_CASEPAT; -#if defined (ALIAS) - parser_state &= ~PST_ALEXPNEXT; -#endif /* ALIAS */ - return (SEMI_AND); - } - - 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); - -tokword: - /* 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, and returning - * correct error values if it reads EOF. - */ -#define P_FIRSTCLOSE 0x01 -#define P_ALLOWESC 0x02 -#define P_DQUOTE 0x04 -#define P_COMMAND 0x08 /* parsing a command, so look for comments */ -#define P_BACKQUOTE 0x10 /* parsing a backquoted command substitution */ - -/* Lexical state while parsing a grouping construct or $(...). */ -#define LEX_WASDOL 0x001 -#define LEX_CKCOMMENT 0x002 -#define LEX_INCOMMENT 0x004 -#define LEX_PASSNEXT 0x008 -#define LEX_RESWDOK 0x010 -#define LEX_CKCASE 0x020 -#define LEX_INCASE 0x040 -#define LEX_INHEREDOC 0x080 -#define LEX_HEREDELIM 0x100 /* reading here-doc delimiter */ -#define LEX_STRIPDOC 0x200 /* <<- strip tabs from here doc delim */ - -#define COMSUB_META(ch) ((ch) == ';' || (ch) == '&' || (ch) == '|') - -#define CHECK_NESTRET_ERROR() \ - do { \ - if (nestret == &matched_pair_error) \ - { \ - free (ret); \ - return &matched_pair_error; \ - } \ - } while (0) - -#define APPEND_NESTRET() \ - do { \ - if (nestlen) \ - { \ - RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64); \ - strcpy (ret + retind, nestret); \ - retind += nestlen; \ - } \ - } while (0) - -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, tflags; - int nestlen, ttranslen, start_lineno; - char *ret, *nestret, *ttrans; - int retind, retsize, rflags; - -/* itrace("parse_matched_pair: open = %c close = %c flags = %d", open, close, flags); */ - count = 1; - tflags = 0; - - if ((flags & P_COMMAND) && qc != '`' && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0) - tflags |= LEX_CKCOMMENT; - - /* 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 != '\'' && (tflags & LEX_PASSNEXT) == 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 (); - - /* Don't bother counting parens or doing anything else if in a comment - or part of a case statement */ - if (tflags & LEX_INCOMMENT) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if (ch == '\n') - tflags &= ~LEX_INCOMMENT; - - continue; - } - - /* Not exactly right yet, should handle shell metacharacters, too. If - any changes are made to this test, make analogous changes to subst.c: - extract_delimited_string(). */ - else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1]))) - tflags |= LEX_INCOMMENT; - - if (tflags & LEX_PASSNEXT) /* last char was backslash */ - { - tflags &= ~LEX_PASSNEXT; - 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; - } - /* If we're reparsing the input (e.g., from parse_string_to_word_list), - we've already prepended CTLESC to single-quoted results of $'...'. - We may want to do this for other CTLESC-quoted characters in - reparse, too. */ - else if MBTEST((parser_state & PST_REPARSE) && open == '\'' && (ch == CTLESC || ch == CTLNUL)) - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - 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--; - /* handle nested ${...} specially. */ - else if MBTEST(open != close && (tflags & LEX_WASDOL) && open == '{' && ch == open) /* } */ - count++; - 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 we just read the ending character, don't bother continuing. */ - if (count == 0) - break; - - if (open == '\'') /* '' inside grouping construct */ - { - if MBTEST((flags & P_ALLOWESC) && ch == '\\') - tflags |= LEX_PASSNEXT; - continue; - } - - if MBTEST(ch == '\\') /* backslashes */ - tflags |= LEX_PASSNEXT; - -#if 0 - /* The big hammer. Single quotes aren't special in double quotes. The - problem is that Posix says the single quotes are semi-special: - within a double-quoted ${...} construct "an even number of - unescaped double-quotes or single-quotes, if any, shall occur." */ - if MBTEST(open == '{' && (flags & P_DQUOTE) && ch == '\'') /* } */ - continue; -#endif - - /* Could also check open == '`' if we want to parse grouping constructs - inside old-style command substitution. */ - if (open != close) /* a grouping construct */ - { - if MBTEST(shellquote (ch)) - { - /* '', ``, or "" inside $(...) or other grouping construct. */ - push_delimiter (dstack, ch); - if MBTEST((tflags & LEX_WASDOL) && 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); - CHECK_NESTRET_ERROR (); - - if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Translate $'...' here. */ - ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen); - xfree (nestret); - - if ((rflags & P_DQUOTE) == 0) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else - { - nestret = ttrans; - nestlen = ttranslen; - } - retind -= 2; /* back up before the $' */ - } - else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Locale expand $"..." here. */ - ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen); - xfree (nestret); - - nestret = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - nestlen = ttranslen + 2; - retind -= 2; /* back up before the $" */ - } - - APPEND_NESTRET (); - 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); - - CHECK_NESTRET_ERROR (); - APPEND_NESTRET (); - - FREE (nestret); - } - else if MBTEST(open != '`' && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ - /* check for $(), $[], or ${} inside quoted string. */ - { - if (open == ch) /* undo previous increment */ - count--; - if (ch == '(') /* ) */ - nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE); - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - - CHECK_NESTRET_ERROR (); - APPEND_NESTRET (); - - FREE (nestret); - } - if MBTEST(ch == '$') - tflags |= LEX_WASDOL; - else - tflags &= ~LEX_WASDOL; - } - - ret[retind] = '\0'; - if (lenp) - *lenp = retind; - return ret; -} - -/* Parse a $(...) command substitution. This is messier than I'd like, and - reproduces a lot more of the token-reading code than I'd like. */ -static char * -parse_comsub (qc, open, close, lenp, flags) - int qc; /* `"' if this construct is within double quotes */ - int open, close; - int *lenp, flags; -{ - int count, ch, peekc, tflags, lex_rwlen, lex_firstind; - int nestlen, ttranslen, start_lineno; - char *ret, *nestret, *ttrans, *heredelim; - int retind, retsize, rflags, hdlen; - -/*itrace("parse_comsub: qc = `%c' open = %c close = %c", qc, open, close);*/ - count = 1; - tflags = LEX_RESWDOK; - - if ((flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0) - tflags |= LEX_CKCASE; - if ((tflags & LEX_CKCASE) && (interactive == 0 || interactive_comments)) - tflags |= LEX_CKCOMMENT; - - /* RFLAGS is the set of flags we want to pass to recursive calls. */ - rflags = (flags & P_DQUOTE); - - ret = (char *)xmalloc (retsize = 64); - retind = 0; - - start_lineno = line_number; - lex_rwlen = 0; - - heredelim = 0; - lex_firstind = -1; - - while (count) - { -comsub_readchar: - ch = shell_getc (qc != '\'' && (tflags & LEX_PASSNEXT) == 0); - - if (ch == EOF) - { -eof_error: - free (ret); - FREE (heredelim); - parser_error (start_lineno, _("unexpected EOF while looking for matching `%c'"), close); - EOF_Reached = 1; /* XXX */ - return (&matched_pair_error); - } - - /* If we hit the end of a line and are reading the contents of a here - document, and it's not the same line that the document starts on, - check for this line being the here doc delimiter. Otherwise, if - we're in a here document, mark the next character as the beginning - of a line. */ - if (ch == '\n') - { - if ((tflags & LEX_HEREDELIM) && heredelim) - { - tflags &= ~LEX_HEREDELIM; - tflags |= LEX_INHEREDOC; - lex_firstind = retind + 1; - } - else if (tflags & LEX_INHEREDOC) - { - int tind; - tind = lex_firstind; - while ((tflags & LEX_STRIPDOC) && ret[tind] == '\t') - tind++; - if (STREQN (ret + tind, heredelim, hdlen)) - { - tflags &= ~(LEX_STRIPDOC|LEX_INHEREDOC); -/*itrace("parse_comsub:%d: found here doc end `%s'", line_number, ret + tind);*/ - lex_firstind = -1; - } - else - lex_firstind = retind + 1; - } - } - - /* Possible reprompting. */ - if (ch == '\n' && SHOULD_PROMPT ()) - prompt_again (); - - /* Don't bother counting parens or doing anything else if in a comment */ - if (tflags & (LEX_INCOMMENT|LEX_INHEREDOC)) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - if ((tflags & LEX_INCOMMENT) && ch == '\n') - tflags &= ~LEX_INCOMMENT; - - continue; - } - - /* Skip whitespace */ - if MBTEST(shellblank (ch) && lex_rwlen == 0) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - continue; - } - - /* Either we are looking for the start of the here-doc delimiter - (lex_firstind == -1) or we are reading one (lex_firstind >= 0). - If this character is a shell break character and we are reading - the delimiter, save it and note that we are now reading a here - document. If we've found the start of the delimiter, note it by - setting lex_firstind. Backslashes can quote shell metacharacters - in here-doc delimiters. */ - if (tflags & LEX_HEREDELIM) - { - if (lex_firstind == -1 && shellbreak (ch) == 0) - lex_firstind = retind; - else if (lex_firstind >= 0 && (tflags & LEX_PASSNEXT) == 0 && shellbreak (ch)) - { - nestret = substring (ret, lex_firstind, retind); - heredelim = string_quote_removal (nestret, 0); - free (nestret); - hdlen = STRLEN(heredelim); -/*itrace("parse_comsub:%d: found here doc delimiter `%s' (%d)", line_number, heredelim, hdlen);*/ - if (ch == '\n') - { - tflags |= LEX_INHEREDOC; - tflags &= ~LEX_HEREDELIM; - lex_firstind = retind + 1; - } - else - lex_firstind = -1; - } - } - - /* Meta-characters that can introduce a reserved word. Not perfect yet. */ - if MBTEST((tflags & LEX_RESWDOK) == 0 && (tflags & LEX_CKCASE) && (tflags & LEX_INCOMMENT) == 0 && shellmeta(ch)) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - peekc = shell_getc (1); - if (ch == peekc && (ch == '&' || ch == '|' || ch == ';')) /* two-character tokens */ - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = peekc; -/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch); */ - tflags |= LEX_RESWDOK; - lex_rwlen = 0; - continue; - } - else if (ch == '\n' || COMSUB_META(ch)) - { - shell_ungetc (peekc); - tflags |= LEX_RESWDOK; -/*itrace("parse_comsub:%d: set lex_reswordok = 1, ch = `%c'", line_number, ch);*/ - lex_rwlen = 0; - continue; - } - else if (ch == EOF) - goto eof_error; - else - { - /* `unget' the character we just added and fall through */ - retind--; - shell_ungetc (peekc); - } - } - - /* If we can read a reserved word, try to read one. */ - if (tflags & LEX_RESWDOK) - { - if MBTEST(islower (ch)) - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - lex_rwlen++; - continue; - } - else if MBTEST(lex_rwlen == 4 && shellbreak (ch)) - { - if (STREQN (ret + retind - 4, "case", 4)) -{ - tflags |= LEX_INCASE; -/*itrace("parse_comsub:%d: found `case', lex_incase -> 1", line_number);*/ -} - else if (STREQN (ret + retind - 4, "esac", 4)) -{ - tflags &= ~LEX_INCASE; -/*itrace("parse_comsub:%d: found `esac', lex_incase -> 0", line_number);*/ -} - tflags &= ~LEX_RESWDOK; - } - else if (shellbreak (ch) == 0) -{ - tflags &= ~LEX_RESWDOK; -/*itrace("parse_comsub:%d: found `%c', lex_reswordok -> 0", line_number, ch);*/ -} - } - - if MBTEST((tflags & LEX_INCOMMENT) == 0 && (tflags & LEX_CKCASE) && ch == '<') - { - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - peekc = shell_getc (1); - if (peekc == EOF) - goto eof_error; - if (peekc == ch) - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = peekc; - peekc = shell_getc (1); - if (peekc == EOF) - goto eof_error; - if (peekc == '-') - { - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = peekc; - tflags |= LEX_STRIPDOC; - } - else - shell_ungetc (peekc); - tflags |= LEX_HEREDELIM; - lex_firstind = -1; - continue; - } - else - ch = peekc; /* fall through and continue XXX - this skips comments if peekc == '#' */ - } - /* Not exactly right yet, should handle shell metacharacters, too. If - any changes are made to this test, make analogous changes to subst.c: - extract_delimited_string(). */ - else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1]))) - tflags |= LEX_INCOMMENT; - - if (tflags & LEX_PASSNEXT) /* last char was backslash */ - { - tflags &= ~LEX_PASSNEXT; - 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; - } -#if 0 - else if MBTEST((tflags & LEX_INCASE) && ch == close && close == ')') - tflags &= ~LEX_INCASE; /* XXX */ -#endif - else if MBTEST(ch == close && (tflags & LEX_INCASE) == 0) /* ending delimiter */ -{ - count--; -/*itrace("parse_comsub:%d: found close: count = %d", line_number, count);*/ -} - else if MBTEST(((flags & P_FIRSTCLOSE) == 0) && (tflags & LEX_INCASE) == 0 && ch == open) /* nested begin */ - count++; - - /* Add this character. */ - RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64); - ret[retind++] = ch; - - /* If we just read the ending character, don't bother continuing. */ - if (count == 0) - break; - - if MBTEST(ch == '\\') /* backslashes */ - tflags |= LEX_PASSNEXT; - - if MBTEST(shellquote (ch)) - { - /* '', ``, or "" inside $(...). */ - push_delimiter (dstack, ch); - if MBTEST((tflags & LEX_WASDOL) && 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); - CHECK_NESTRET_ERROR (); - - if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Translate $'...' here. */ - ttrans = ansiexpand (nestret, 0, nestlen - 1, &ttranslen); - xfree (nestret); - - if ((rflags & P_DQUOTE) == 0) - { - nestret = sh_single_quote (ttrans); - free (ttrans); - nestlen = strlen (nestret); - } - else - { - nestret = ttrans; - nestlen = ttranslen; - } - retind -= 2; /* back up before the $' */ - } - else if MBTEST((tflags & LEX_WASDOL) && ch == '"' && (extended_quote || (rflags & P_DQUOTE) == 0)) - { - /* Locale expand $"..." here. */ - ttrans = localeexpand (nestret, 0, nestlen - 1, start_lineno, &ttranslen); - xfree (nestret); - - nestret = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - nestlen = ttranslen + 2; - retind -= 2; /* back up before the $" */ - } - - APPEND_NESTRET (); - FREE (nestret); - } - else if MBTEST((tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '[')) /* ) } ] */ - /* check for $(), $[], or ${} inside command substitution. */ - { - if ((tflags & LEX_INCASE) == 0 && open == ch) /* undo previous increment */ - count--; - if (ch == '(') /* ) */ - nestret = parse_comsub (0, '(', ')', &nestlen, (rflags|P_COMMAND) & ~P_DQUOTE); - else if (ch == '{') /* } */ - nestret = parse_matched_pair (0, '{', '}', &nestlen, P_FIRSTCLOSE|rflags); - else if (ch == '[') /* ] */ - nestret = parse_matched_pair (0, '[', ']', &nestlen, rflags); - - CHECK_NESTRET_ERROR (); - APPEND_NESTRET (); - - FREE (nestret); - } - if MBTEST(ch == '$') - tflags |= LEX_WASDOL; - else - tflags &= ~LEX_WASDOL; - } - - FREE (heredelim); - ret[retind] = '\0'; - if (lenp) - *lenp = retind; -/*itrace("parse_comsub:%d: returning `%s'", line_number, ret);*/ - return ret; -} - -/* XXX - this needs to handle functionality like subst.c:no_longjmp_on_fatal_error; - maybe extract_command_subst should handle it. */ -char * -xparse_dolparen (base, string, indp, flags) - char *base; - char *string; - int *indp; - int flags; -{ - sh_parser_state_t ps; - int orig_ind, nc, sflags; - char *ret, *s, *ep, *ostring; - - /*yydebug = 1;*/ - orig_ind = *indp; - ostring = string; - - sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE; - if (flags & SX_NOLONGJMP) - sflags |= SEVAL_NOLONGJMP; - save_parser_state (&ps); - - /*(*/ - parser_state |= PST_CMDSUBST|PST_EOFTOKEN; /* allow instant ')' */ /*(*/ - shell_eof_token = ')'; - parse_string (string, "command substitution", sflags, &ep); - - restore_parser_state (&ps); - reset_parser (); - if (interactive) - token_to_read = 0; - - /* Need to find how many characters parse_and_execute consumed, update - *indp, if flags != 0, copy the portion of the string parsed into RET - and return it. If flags & 1 (EX_NOALLOC) we can return NULL. */ - - /*(*/ - if (ep[-1] != ')') - { -#if DEBUG - if (ep[-1] != '\n') - itrace("xparse_dolparen:%d: ep[-1] != RPAREN (%d), ep = `%s'", line_number, ep[-1], ep); -#endif - while (ep > ostring && ep[-1] == '\n') ep--; - } - - nc = ep - ostring; - *indp = ep - base - 1; - - /*(*/ -#if DEBUG - if (base[*indp] != ')') - itrace("xparse_dolparen:%d: base[%d] != RPAREN (%d), base = `%s'", line_number, *indp, base[*indp], base); -#endif - - if (flags & SX_NOALLOC) - return (char *)NULL; - - if (nc == 0) - { - ret = xmalloc (1); - ret[0] = '\0'; - } - else - ret = substring (ostring, 0, nc - 1); - - 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, sline; - char *wval; - 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 = alloc_word_desc (); - wd->word = wval; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - return (ARITH_FOR_EXPRS); - } - else - return -1; /* ERROR */ - } -#endif - -#if defined (DPAREN_ARITHMETIC) - if (reserved_word_acceptable (last_read_token)) - { - sline = line_number; - - cmdtyp = parse_arith_cmd (&wval, 0); - if (cmdtyp == 1) /* arithmetic command */ - { - wd = alloc_word_desc (); - wd->word = wval; - wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE; - yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); - 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 && yylval.word->word[0] == '-' && yylval.word->word[2] == 0 && 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; - parser_state |= PST_REGEXP; - } -#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); - parser_state &= ~PST_REGEXP; - 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; -} - -/* XXX - possible changes here for `+=' */ -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; - - /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound - assignment. */ - int compound_assignment; - - /* 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 = compound_assignment = 0; - - for (;;) - { - if (character == EOF) - goto got_token; - - if (pass_next_character) - { - pass_next_character = 0; - goto got_escaped_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, (character == '`') ? P_COMMAND : 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 COND_REGEXP - /* When parsing a regexp as a single word inside a conditional command, - we need to special-case characters special to both the shell and - regular expressions. Right now, that is only '(' and '|'. */ /*)*/ - if MBTEST((parser_state & PST_REGEXP) && (character == '(' || character == '|')) /*)*/ - { - if (character == '|') - goto got_character; - - push_delimiter (dstack, character); - 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; - strcpy (token + token_index, ttok); - token_index += ttoklen; - FREE (ttok); - dollar_present = all_digit_token = 0; - goto next_character; - } -#endif /* COND_REGEXP */ - -#ifdef EXTENDED_GLOB - /* Parse a ksh-style extended pattern matching specification. */ - if MBTEST(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_comsub (cd, '(', ')', &ttoklen, P_COMMAND); - 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); - ttranslen = strlen (ttok); - ttrans = ttok; - } - 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 = sh_mkdoublequoted (ttrans, ttranslen, 0); - free (ttrans); - ttranslen += 2; - 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 [...]. If - parser_state&PST_COMPASSIGN, we need to parse [sub]=words treating - `sub' as if it were enclosed in double quotes. */ - else if MBTEST(character == '[' && /* ] */ - ((token_index > 0 && assignment_acceptable (last_read_token) && token_is_ident (token, token_index)) || - (token_index == 0 && (parser_state&PST_COMPASSIGN)))) - { - 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 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && 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; - compound_assignment = 1; -#if 1 - goto next_character; -#else - goto got_token; /* ksh93 seems to do this */ -#endif - } - 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: - - if (character == CTLESC || character == CTLNUL) - token[token_index++] = CTLESC; - - got_escaped_character: - - all_digit_token &= DIGIT (character); - dollar_present |= character == '$'; - - 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; /*(*/ - if (compound_assignment && token[token_index-1] == ')') - the_word->flags |= W_COMPASSIGN; - /* 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; - } - - if (command_token_position (last_read_token)) - { - struct builtin *b; - b = builtin_address_internal (token, 0); - if (b && (b->flags & ASSIGNMENT_BUILTIN)) - parser_state |= PST_ASSIGNOK; - else if (STREQ (token, "eval") || STREQ (token, "let")) - parser_state |= PST_ASSIGNOK; - } - - 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 SEMI_AND: - case SEMI_SEMI_AND: - case THEN: - case TIME: - case TIMEOPT: - case COPROC: - case UNTIL: - case WHILE: - case 0: - return 1; - default: -#if defined (COPROCESS_SUPPORT) - if (last_read_token == WORD && token_before_that == COPROC) - return 1; -#endif - 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 const int no_semi_successors[] = { - '\n', '{', '(', ')', ';', '&', '|', - CASE, DO, ELSE, IF, SEMI_SEMI, SEMI_AND, SEMI_SEMI_AND, 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"); - - /* We look for current_command_line_count == 2 because we are looking to - add the first line of the body of the here document (the second line - of the command). */ - if (parser_state & PST_HEREDOC) - return (current_command_line_count == 2 ? "\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 ";"; - } - else if (two_tokens_ago == CASE && token_before_that == WORD && (parser_state & PST_CASESTMT)) - 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, i; - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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); - - if (n == 0) - timebuf[0] = '\0'; - else - 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]; - 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, t_string) == 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)); - - temp = trim_pathname (t_string, PATH_MAX - 1); - /* 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); - n = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; - i = 0; - if (n == CTLESC || n == CTLNUL) - temp[i++] = CTLESC; - temp[i++] = n; - temp[i] = '\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, 0); - 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 (tok) - int tok; -{ - char *t; - - if (t = find_token_in_alist (tok, word_token_alist, 0)) - return t; - - if (t = find_token_in_alist (tok, 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|PST_REPARSE; - - 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 (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|PST_REPARSE); - - 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, orig_last_token, assignok; - char *saved_token, *ret; - - saved_token = token; - orig_token_size = token_buffer_size; - orig_line_number = line_number; - orig_last_token = last_read_token; - - last_read_token = WORD; /* WORD to allow reserved words here */ - - token = (char *)NULL; - token_buffer_size = 0; - - assignok = parser_state&PST_ASSIGNOK; /* XXX */ - - 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(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 = orig_last_token; /* XXX - was 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; - - if (assignok) - parser_state |= PST_ASSIGNOK; - - 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 = (sh_parser_state_t *)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/parser.h~ b/parser.h~ deleted file mode 100644 index 826322ce4..000000000 --- a/parser.h~ +++ /dev/null @@ -1,61 +0,0 @@ -/* parser.h -- Everything you wanted to know about the parser, but were - afraid to ask. */ - -/* Copyright (C) 1995, 2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#if !defined (_PARSER_H_) -# define _PARSER_H_ - -# include "command.h" -# include "input.h" - -/* Possible states for the parser that require it to do special things. */ -#define PST_CASEPAT 0x00001 /* in a case pattern list */ -#define PST_ALEXPNEXT 0x00002 /* expand next word for aliases */ -#define PST_ALLOWOPNBRC 0x00004 /* allow open brace for function def */ -#define PST_NEEDCLOSBRC 0x00008 /* need close brace */ -#define PST_DBLPAREN 0x00010 /* double-paren parsing */ -#define PST_SUBSHELL 0x00020 /* ( ... ) subshell */ -#define PST_CMDSUBST 0x00040 /* $( ... ) command substitution */ -#define PST_CASESTMT 0x00080 /* parsing a case statement */ -#define PST_CONDCMD 0x00100 /* parsing a [[...]] command */ -#define PST_CONDEXPR 0x00200 /* parsing the guts of [[...]] */ -#define PST_ARITHFOR 0x00400 /* parsing an arithmetic for command */ -#define PST_ALEXPAND 0x00800 /* OK to expand aliases - unused */ -#define PST_CMDTOKEN 0x01000 /* command token OK - unused */ -#define PST_COMPASSIGN 0x02000 /* parsing x=(...) compound assignment */ -#define PST_ASSIGNOK 0x04000 /* assignment statement ok in this context */ -#define PST_EOFTOKEN 0x08000 /* yylex checks against shell_eof_token */ -#define PST_REGEXP 0x10000 /* parsing an ERE/BRE as a single word */ -#define PST_HEREDOC 0x20000 /* reading body of here-document */ - -/* Definition of the delimiter stack. Needed by parse.y and bashhist.c. */ -struct dstack { -/* DELIMITERS is a stack of the nested delimiters that we have - encountered so far. */ - char *delimiters; - -/* Offset into the stack of delimiters. */ - int delimiter_depth; - -/* How many slots are allocated to DELIMITERS. */ - int delimiter_space; -}; - -#endif /* _PARSER_H_ */ diff --git a/patchlevel.h~ b/patchlevel.h~ deleted file mode 100644 index 6d86562fd..000000000 --- a/patchlevel.h~ +++ /dev/null @@ -1,30 +0,0 @@ -/* patchlevel.h -- current bash patch level */ - -/* Copyright (C) 2001-2007 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 (_PATCHLEVEL_H_) -#define _PATCHLEVEL_H_ - -/* It's important that there be no other strings in this file that match the - regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh - looks for to find the patch level (for the sccs version string). */ - -#define PATCHLEVEL 33 - -#endif /* _PATCHLEVEL_H_ */ diff --git a/pathexp.c~ b/pathexp.c~ deleted file mode 100644 index f5c5da2a6..000000000 --- a/pathexp.c~ +++ /dev/null @@ -1,488 +0,0 @@ -/* pathexp.c -- The shell interface to the globbing library. */ - -/* Copyright (C) 1995-2007 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" - -#include "shell.h" -#include "pathexp.h" -#include "flags.h" - -#include "shmbutil.h" -#include "bashintl.h" - -#include - -static int glob_name_is_acceptable __P((const char *)); -static void ignore_globbed_names __P((char **, sh_ignore_func_t *)); - -#if defined (USE_POSIX_GLOB_LIBRARY) -# include -typedef int posix_glob_errfunc_t __P((const char *, int)); -#else -# include -#endif - -/* Control whether * matches .files in globbing. */ -int glob_dot_filenames; - -/* Control whether the extended globbing features are enabled. */ -int extended_glob = 0; - -/* Control enabling special handling of `**' */ -int glob_star = 0; - -/* Return nonzero if STRING has any unquoted special globbing chars in it. */ -int -unquoted_glob_pattern_p (string) - register char *string; -{ - register int c; - char *send; - int open; - - DECLARE_MBSTATE; - - open = 0; - send = string + strlen (string); - - while (c = *string++) - { - switch (c) - { - case '?': - case '*': - return (1); - - case '[': - open++; - continue; - - case ']': - if (open) - return (1); - continue; - - case '+': - case '@': - case '!': - if (*string == '(') /*)*/ - return (1); - continue; - - case CTLESC: - case '\\': - if (*string++ == '\0') - return (0); - } - - /* Advance one fewer byte than an entire multibyte character to - account for the auto-increment in the loop above. */ -#ifdef HANDLE_MULTIBYTE - string--; - ADVANCE_CHAR_P (string, send - string); - string++; -#else - ADVANCE_CHAR_P (string, send - string); -#endif - } - return (0); -} - -/* Return 1 if C is a character that is `special' in a POSIX ERE and needs to - be quoted to match itself. */ -static inline int -ere_char (c) - int c; -{ - switch (c) - { - case '.': - case '[': - case '\\': - case '(': - case ')': - case '*': - case '+': - case '?': - case '{': - case '|': - case '^': - case '$': - return 1; - default: - return 0; - } - return (0); -} - -int -glob_char_p (s) - const char *s; -{ - switch (*s) - { - case '*': - case '[': - case ']': - case '?': - case '\\': - return 1; - case '+': - case '@': - case '!': - if (s[1] == '(') /*(*/ - return 1; - break; - } - return 0; -} - -/* PATHNAME can contain characters prefixed by CTLESC; this indicates - that the character is to be quoted. We quote it here in the style - that the glob library recognizes. If flags includes QGLOB_CVTNULL, - we change quoted null strings (pathname[0] == CTLNUL) into empty - strings (pathname[0] == 0). If this is called after quote removal - is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote - removal has not been done (for example, before attempting to match a - pattern while executing a case statement), flags should include - QGLOB_CVTNULL. If flags includes QGLOB_FILENAME, appropriate quoting - to match a filename should be performed. */ -char * -quote_string_for_globbing (pathname, qflags) - const char *pathname; - int qflags; -{ - char *temp; - register int i, j; - - temp = (char *)xmalloc (strlen (pathname) + 1); - - if ((qflags & QGLOB_CVTNULL) && QUOTED_NULL (pathname)) - { - temp[0] = '\0'; - return temp; - } - - for (i = j = 0; pathname[i]; i++) - { - if (pathname[i] == CTLESC) - { - if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/') - continue; - if ((qflags & QGLOB_REGEXP) && ere_char (pathname[i+1]) == 0) - continue; - temp[j++] = '\\'; - i++; - if (pathname[i] == '\0') - break; - } - else if (pathname[i] == '\\') - { - temp[j++] = '\\'; - i++; - if (pathname[i] == '\0') - break; - } - temp[j++] = pathname[i]; - } - temp[j] = '\0'; - - return (temp); -} - -char * -quote_globbing_chars (string) - char *string; -{ - size_t slen; - char *temp, *s, *t, *send; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - temp = (char *)xmalloc (slen * 2 + 1); - for (t = temp, s = string; *s; ) - { - if (glob_char_p (s)) - *t++ = '\\'; - - /* Copy a single (possibly multibyte) character from s to t, - incrementing both. */ - COPY_CHAR_P (t, s, send); - } - *t = '\0'; - return temp; -} - -/* Call the glob library to do globbing on PATHNAME. */ -char ** -shell_glob_filename (pathname) - const char *pathname; -{ -#if defined (USE_POSIX_GLOB_LIBRARY) - register int i; - char *temp, **results; - glob_t filenames; - int glob_flags; - - temp = quote_string_for_globbing (pathname, QGLOB_FILENAME); - - filenames.gl_offs = 0; - -# if defined (GLOB_PERIOD) - glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0; -# else - glob_flags = 0; -# endif /* !GLOB_PERIOD */ - - glob_flags |= (GLOB_ERR | GLOB_DOOFFS); - - i = glob (temp, glob_flags, (posix_glob_errfunc_t *)NULL, &filenames); - - free (temp); - - if (i == GLOB_NOSPACE || i == GLOB_ABORTED) - return ((char **)NULL); - else if (i == GLOB_NOMATCH) - filenames.gl_pathv = (char **)NULL; - else if (i != 0) /* other error codes not in POSIX.2 */ - filenames.gl_pathv = (char **)NULL; - - results = filenames.gl_pathv; - - if (results && ((GLOB_FAILED (results)) == 0)) - { - if (should_ignore_glob_matches ()) - ignore_glob_matches (results); - if (results && results[0]) - strvec_sort (results); - else - { - FREE (results); - results = (char **)NULL; - } - } - - return (results); - -#else /* !USE_POSIX_GLOB_LIBRARY */ - - char *temp, **results; - - noglob_dot_filenames = glob_dot_filenames == 0; - - temp = quote_string_for_globbing (pathname, QGLOB_FILENAME); - results = glob_filename (temp, glob_star ? GX_GLOBSTAR : 0); - free (temp); - -itrace("shell_glob_filename: LC_COLLATE = %s", setlocale(LC_COLLATE, (char *)NULL)); - - if (results && ((GLOB_FAILED (results)) == 0)) - { - if (should_ignore_glob_matches ()) - ignore_glob_matches (results); - if (results && results[0]) - strvec_sort (results); - else - { - FREE (results); - results = (char **)&glob_error_return; - } - } - - return (results); -#endif /* !USE_POSIX_GLOB_LIBRARY */ -} - -/* Stuff for GLOBIGNORE. */ - -static struct ignorevar globignore = -{ - "GLOBIGNORE", - (struct ign *)0, - 0, - (char *)0, - (sh_iv_item_func_t *)0, -}; - -/* Set up to ignore some glob matches because the value of GLOBIGNORE - has changed. If GLOBIGNORE is being unset, we also need to disable - the globbing of filenames beginning with a `.'. */ -void -setup_glob_ignore (name) - char *name; -{ - char *v; - - v = get_string_value (name); - setup_ignore_patterns (&globignore); - - if (globignore.num_ignores) - glob_dot_filenames = 1; - else if (v == 0) - glob_dot_filenames = 0; -} - -int -should_ignore_glob_matches () -{ - return globignore.num_ignores; -} - -/* Return 0 if NAME matches a pattern in the globignore.ignores list. */ -static int -glob_name_is_acceptable (name) - const char *name; -{ - struct ign *p; - int flags; - - /* . and .. are never matched */ - if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) - return (0); - - flags = FNM_PATHNAME | FNMATCH_EXTFLAG; - for (p = globignore.ignores; p->val; p++) - { - if (strmatch (p->val, (char *)name, flags) != FNM_NOMATCH) - return (0); - } - return (1); -} - -/* Internal function to test whether filenames in NAMES should be - ignored. NAME_FUNC is a pointer to a function to call with each - name. It returns non-zero if the name is acceptable to the particular - ignore function which called _ignore_names; zero if the name should - be removed from NAMES. */ - -static void -ignore_globbed_names (names, name_func) - char **names; - sh_ignore_func_t *name_func; -{ - char **newnames; - int n, i; - - for (i = 0; names[i]; i++) - ; - newnames = strvec_create (i + 1); - - for (n = i = 0; names[i]; i++) - { - if ((*name_func) (names[i])) - newnames[n++] = names[i]; - else - free (names[i]); - } - - newnames[n] = (char *)NULL; - - if (n == 0) - { - names[0] = (char *)NULL; - free (newnames); - return; - } - - /* Copy the acceptable names from NEWNAMES back to NAMES and set the - new array end. */ - for (n = 0; newnames[n]; n++) - names[n] = newnames[n]; - names[n] = (char *)NULL; - free (newnames); -} - -void -ignore_glob_matches (names) - char **names; -{ - if (globignore.num_ignores == 0) - return; - - ignore_globbed_names (names, glob_name_is_acceptable); -} - -void -setup_ignore_patterns (ivp) - struct ignorevar *ivp; -{ - int numitems, maxitems, ptr; - char *colon_bit, *this_ignoreval; - struct ign *p; - - this_ignoreval = get_string_value (ivp->varname); - - /* If nothing has changed then just exit now. */ - if ((this_ignoreval && ivp->last_ignoreval && STREQ (this_ignoreval, ivp->last_ignoreval)) || - (!this_ignoreval && !ivp->last_ignoreval)) - return; - - /* Oops. The ignore variable has changed. Re-parse it. */ - ivp->num_ignores = 0; - - if (ivp->ignores) - { - for (p = ivp->ignores; p->val; p++) - free(p->val); - free (ivp->ignores); - ivp->ignores = (struct ign *)NULL; - } - - if (ivp->last_ignoreval) - { - free (ivp->last_ignoreval); - ivp->last_ignoreval = (char *)NULL; - } - - if (this_ignoreval == 0 || *this_ignoreval == '\0') - return; - - ivp->last_ignoreval = savestring (this_ignoreval); - - numitems = maxitems = ptr = 0; - - while (colon_bit = extract_colon_unit (this_ignoreval, &ptr)) - { - if (numitems + 1 >= maxitems) - { - maxitems += 10; - ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign)); - } - ivp->ignores[numitems].val = colon_bit; - ivp->ignores[numitems].len = strlen (colon_bit); - ivp->ignores[numitems].flags = 0; - if (ivp->item_func) - (*ivp->item_func) (&ivp->ignores[numitems]); - numitems++; - } - ivp->ignores[numitems].val = (char *)NULL; - ivp->num_ignores = numitems; -} diff --git a/pathexp.h~ b/pathexp.h~ deleted file mode 100644 index 1d1216fd2..000000000 --- a/pathexp.h~ +++ /dev/null @@ -1,101 +0,0 @@ -/* pathexp.h -- The shell interface to the globbing library. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 (_PATHEXP_H_) -#define _PATHEXP_H_ - -#if defined (USE_POSIX_GLOB_LIBRARY) -# define GLOB_FAILED(glist) !(glist) -#else /* !USE_POSIX_GLOB_LIBRARY */ -# define GLOB_FAILED(glist) (glist) == (char **)&glob_error_return -extern int noglob_dot_filenames; -extern char *glob_error_return; -#endif /* !USE_POSIX_GLOB_LIBRARY */ - -/* Flag values for quote_string_for_globbing */ -#define QGLOB_CVTNULL 0x01 /* convert QUOTED_NULL strings to '\0' */ -#define QGLOB_FILENAME 0x02 /* do correct quoting for matching filenames */ -#define QGLOB_REGEXP 0x04 /* quote an ERE for regcomp/regexec */ - -#if defined (EXTENDED_GLOB) -/* Flags to OR with other flag args to strmatch() to enabled the extended - pattern matching. */ -# define FNMATCH_EXTFLAG (extended_glob ? FNM_EXTMATCH : 0) -#else -# define FNMATCH_EXTFLAG 0 -#endif /* !EXTENDED_GLOB */ - -#define FNMATCH_IGNCASE (match_ignore_case ? FNM_CASEFOLD : 0) - -extern int glob_dot_filenames; -extern int extended_glob; -extern int glob_star; -extern int match_ignore_case; /* doesn't really belong here */ - -extern int unquoted_glob_pattern_p __P((char *)); - -/* PATHNAME can contain characters prefixed by CTLESC; this indicates - that the character is to be quoted. We quote it here in the style - that the glob library recognizes. If flags includes QGLOB_CVTNULL, - we change quoted null strings (pathname[0] == CTLNUL) into empty - strings (pathname[0] == 0). If this is called after quote removal - is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote - removal has not been done (for example, before attempting to match a - pattern while executing a case statement), flags should include - QGLOB_CVTNULL. If flags includes QGLOB_FILENAME, appropriate quoting - to match a filename should be performed. */ -extern char *quote_string_for_globbing __P((const char *, int)); - -extern char *quote_globbing_chars __P((char *)); - -/* Call the glob library to do globbing on PATHNAME. */ -extern char **shell_glob_filename __P((const char *)); - -/* Filename completion ignore. Used to implement the "fignore" facility of - tcsh and GLOBIGNORE (like ksh-93 FIGNORE). - - It is passed a NULL-terminated array of (char *)'s that must be - free()'d if they are deleted. The first element (names[0]) is the - least-common-denominator string of the matching patterns (i.e. - u produces names[0] = "und", names[1] = "under.c", names[2] = - "undun.c", name[3] = NULL). */ - -struct ign { - char *val; - int len, flags; -}; - -typedef int sh_iv_item_func_t __P((struct ign *)); - -struct ignorevar { - char *varname; /* FIGNORE or GLOBIGNORE */ - struct ign *ignores; /* Store the ignore strings here */ - int num_ignores; /* How many are there? */ - char *last_ignoreval; /* Last value of variable - cached for speed */ - sh_iv_item_func_t *item_func; /* Called when each item is parsed from $`varname' */ -}; - -extern void setup_ignore_patterns __P((struct ignorevar *)); - -extern void setup_glob_ignore __P((char *)); -extern int should_ignore_glob_matches __P((void)); -extern void ignore_glob_matches __P((char **)); - -#endif diff --git a/pcomplete.c~ b/pcomplete.c~ deleted file mode 100644 index e2ddd87c3..000000000 --- a/pcomplete.c~ +++ /dev/null @@ -1,1462 +0,0 @@ -/* pcomplete.c - functions to generate lists of matches for programmable completion. */ - -/* Copyright (C) 1999-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include - -#if defined (PROGRAMMABLE_COMPLETION) - -#include "bashtypes.h" -#include "posixstat.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include - -#if defined (PREFER_STDARG) -# include -#else -# include -#endif - -#include -#include "bashansi.h" -#include "bashintl.h" - -#include "shell.h" -#include "pcomplete.h" -#include "alias.h" -#include "bashline.h" -#include "execute_cmd.h" -#include "pathexp.h" - -#if defined (JOB_CONTROL) -# include "jobs.h" -#endif - -#if !defined (NSIG) -# include "trap.h" -#endif - -#include "builtins.h" -#include "builtins/common.h" - -#include -#include - -#include -#include -#include - -#ifdef STRDUP -# undef STRDUP -#endif -#define STRDUP(x) ((x) ? savestring (x) : (char *)NULL) - -typedef SHELL_VAR **SVFUNC (); - -#ifndef HAVE_STRPBRK -extern char *strpbrk __P((char *, char *)); -#endif - -extern int array_needs_making; -extern STRING_INT_ALIST word_token_alist[]; -extern char *signal_names[]; - -#if defined (DEBUG) -#if defined (PREFER_STDARG) -static void debug_printf (const char *, ...) __attribute__((__format__ (printf, 1, 2))); -#endif -#endif /* DEBUG */ - -static int it_init_joblist __P((ITEMLIST *, int)); - -static int it_init_aliases __P((ITEMLIST *)); -static int it_init_arrayvars __P((ITEMLIST *)); -static int it_init_bindings __P((ITEMLIST *)); -static int it_init_builtins __P((ITEMLIST *)); -static int it_init_disabled __P((ITEMLIST *)); -static int it_init_enabled __P((ITEMLIST *)); -static int it_init_exported __P((ITEMLIST *)); -static int it_init_functions __P((ITEMLIST *)); -static int it_init_hostnames __P((ITEMLIST *)); -static int it_init_jobs __P((ITEMLIST *)); -static int it_init_running __P((ITEMLIST *)); -static int it_init_stopped __P((ITEMLIST *)); -static int it_init_keywords __P((ITEMLIST *)); -static int it_init_signals __P((ITEMLIST *)); -static int it_init_variables __P((ITEMLIST *)); -static int it_init_setopts __P((ITEMLIST *)); -static int it_init_shopts __P((ITEMLIST *)); - -static int shouldexp_filterpat __P((char *)); -static char *preproc_filterpat __P((char *, char *)); - -static void init_itemlist_from_varlist __P((ITEMLIST *, SVFUNC *)); - -static STRINGLIST *gen_matches_from_itemlist __P((ITEMLIST *, const char *)); -static STRINGLIST *gen_action_completions __P((COMPSPEC *, const char *)); -static STRINGLIST *gen_globpat_matches __P((COMPSPEC *, const char *)); -static STRINGLIST *gen_wordlist_matches __P((COMPSPEC *, const char *)); -static STRINGLIST *gen_shell_function_matches __P((COMPSPEC *, const char *, - char *, int, WORD_LIST *, - int, int)); -static STRINGLIST *gen_command_matches __P((COMPSPEC *, const char *, char *, - int, WORD_LIST *, int, int)); - -static char *pcomp_filename_completion_function __P((const char *, int)); - -#if defined (ARRAY_VARS) -static SHELL_VAR *bind_comp_words __P((WORD_LIST *)); -#endif -static void bind_compfunc_variables __P((char *, int, WORD_LIST *, int, int)); -static void unbind_compfunc_variables __P((int)); -static WORD_LIST *build_arg_list __P((char *, const char *, WORD_LIST *, int)); -static WORD_LIST *command_line_to_word_list __P((char *, int, int, int *, int *)); - -#ifdef DEBUG -static int progcomp_debug = 0; -#endif - -int prog_completion_enabled = 1; - -/* These are used to manage the arrays of strings for possible completions. */ -ITEMLIST it_aliases = { 0, it_init_aliases, (STRINGLIST *)0 }; -ITEMLIST it_arrayvars = { LIST_DYNAMIC, it_init_arrayvars, (STRINGLIST *)0 }; -ITEMLIST it_bindings = { 0, it_init_bindings, (STRINGLIST *)0 }; -ITEMLIST it_builtins = { 0, it_init_builtins, (STRINGLIST *)0 }; -ITEMLIST it_commands = { LIST_DYNAMIC }; /* unused */ -ITEMLIST it_directories = { LIST_DYNAMIC }; /* unused */ -ITEMLIST it_disabled = { 0, it_init_disabled, (STRINGLIST *)0 }; -ITEMLIST it_enabled = { 0, it_init_enabled, (STRINGLIST *)0 }; -ITEMLIST it_exports = { LIST_DYNAMIC, it_init_exported, (STRINGLIST *)0 }; -ITEMLIST it_files = { LIST_DYNAMIC }; /* unused */ -ITEMLIST it_functions = { 0, it_init_functions, (STRINGLIST *)0 }; -ITEMLIST it_hostnames = { LIST_DYNAMIC, it_init_hostnames, (STRINGLIST *)0 }; -ITEMLIST it_groups = { LIST_DYNAMIC }; /* unused */ -ITEMLIST it_jobs = { LIST_DYNAMIC, it_init_jobs, (STRINGLIST *)0 }; -ITEMLIST it_keywords = { 0, it_init_keywords, (STRINGLIST *)0 }; -ITEMLIST it_running = { LIST_DYNAMIC, it_init_running, (STRINGLIST *)0 }; -ITEMLIST it_services = { LIST_DYNAMIC }; /* unused */ -ITEMLIST it_setopts = { 0, it_init_setopts, (STRINGLIST *)0 }; -ITEMLIST it_shopts = { 0, it_init_shopts, (STRINGLIST *)0 }; -ITEMLIST it_signals = { 0, it_init_signals, (STRINGLIST *)0 }; -ITEMLIST it_stopped = { LIST_DYNAMIC, it_init_stopped, (STRINGLIST *)0 }; -ITEMLIST it_users = { LIST_DYNAMIC }; /* unused */ -ITEMLIST it_variables = { LIST_DYNAMIC, it_init_variables, (STRINGLIST *)0 }; - -COMPSPEC *pcomp_curcs; -const char *pcomp_curcmd; - -#ifdef DEBUG -/* Debugging code */ -static void -#if defined (PREFER_STDARG) -debug_printf (const char *format, ...) -#else -debug_printf (format, va_alist) - const char *format; - va_dcl -#endif -{ - va_list args; - - if (progcomp_debug == 0) - return; - - SH_VA_START (args, format); - - fprintf (stdout, "DEBUG: "); - vfprintf (stdout, format, args); - fprintf (stdout, "\n"); - - rl_on_new_line (); - - va_end (args); -} -#endif - -/* Functions to manage the item lists */ - -void -set_itemlist_dirty (it) - ITEMLIST *it; -{ - it->flags |= LIST_DIRTY; -} - -void -initialize_itemlist (itp) - ITEMLIST *itp; -{ - (*itp->list_getter) (itp); - itp->flags |= LIST_INITIALIZED; - itp->flags &= ~LIST_DIRTY; -} - -void -clean_itemlist (itp) - ITEMLIST *itp; -{ - STRINGLIST *sl; - - sl = itp->slist; - if (sl) - { - if ((itp->flags & (LIST_DONTFREEMEMBERS|LIST_DONTFREE)) == 0) - strvec_flush (sl->list); - if ((itp->flags & LIST_DONTFREE) == 0) - free (sl->list); - free (sl); - } - itp->slist = (STRINGLIST *)NULL; - itp->flags &= ~(LIST_DONTFREE|LIST_DONTFREEMEMBERS|LIST_INITIALIZED|LIST_DIRTY); -} - - -static int -shouldexp_filterpat (s) - char *s; -{ - register char *p; - - for (p = s; p && *p; p++) - { - if (*p == '\\') - p++; - else if (*p == '&') - return 1; - } - return 0; -} - -/* Replace any instance of `&' in PAT with TEXT. Backslash may be used to - quote a `&' and inhibit substitution. Returns a new string. This just - calls stringlib.c:strcreplace(). */ -static char * -preproc_filterpat (pat, text) - char *pat; - char *text; -{ - char *ret; - - ret = strcreplace (pat, '&', text, 1); - return ret; -} - -/* Remove any match of FILTERPAT from SL. A `&' in FILTERPAT is replaced by - TEXT. A leading `!' in FILTERPAT negates the pattern; in this case - any member of SL->list that does *not* match will be removed. This returns - a new STRINGLIST with the matching members of SL *copied*. Any - non-matching members of SL->list are *freed*. */ -STRINGLIST * -filter_stringlist (sl, filterpat, text) - STRINGLIST *sl; - char *filterpat, *text; -{ - int i, m, not; - STRINGLIST *ret; - char *npat, *t; - - if (sl == 0 || sl->list == 0 || sl->list_len == 0) - return sl; - - npat = shouldexp_filterpat (filterpat) ? preproc_filterpat (filterpat, text) : filterpat; - - not = (npat[0] == '!'); - t = not ? npat + 1 : npat; - - ret = strlist_create (sl->list_size); - for (i = 0; i < sl->list_len; i++) - { - m = strmatch (t, sl->list[i], FNMATCH_EXTFLAG); - if ((not && m == FNM_NOMATCH) || (not == 0 && m != FNM_NOMATCH)) - free (sl->list[i]); - else - ret->list[ret->list_len++] = sl->list[i]; - } - - ret->list[ret->list_len] = (char *)NULL; - if (npat != filterpat) - free (npat); - - return ret; -} - -/* Turn an array of strings returned by rl_completion_matches into a STRINGLIST. - This understands how rl_completion_matches sets matches[0] (the lcd of the - strings in the list, unless it's the only match). */ -STRINGLIST * -completions_to_stringlist (matches) - char **matches; -{ - STRINGLIST *sl; - int mlen, i, n; - - mlen = (matches == 0) ? 0 : strvec_len (matches); - sl = strlist_create (mlen + 1); - - if (matches == 0 || matches[0] == 0) - return sl; - - if (matches[1] == 0) - { - sl->list[0] = STRDUP (matches[0]); - sl->list[sl->list_len = 1] = (char *)NULL; - return sl; - } - - for (i = 1, n = 0; i < mlen; i++, n++) - sl->list[n] = STRDUP (matches[i]); - sl->list_len = n; - sl->list[n] = (char *)NULL; - - return sl; -} - -/* Functions to manage the various ITEMLISTs that we populate internally. - The caller is responsible for setting ITP->flags correctly. */ - -static int -it_init_aliases (itp) - ITEMLIST *itp; -{ -#ifdef ALIAS - alias_t **alias_list; - register int i, n; - STRINGLIST *sl; - - alias_list = all_aliases (); - if (alias_list == 0) - { - itp->slist = (STRINGLIST *)NULL; - return 0; - } - for (n = 0; alias_list[n]; n++) - ; - sl = strlist_create (n+1); - for (i = 0; i < n; i++) - sl->list[i] = STRDUP (alias_list[i]->name); - sl->list[n] = (char *)NULL; - sl->list_size = sl->list_len = n; - itp->slist = sl; -#else - itp->slist = (STRINGLIST *)NULL; -#endif - return 1; -} - -static void -init_itemlist_from_varlist (itp, svfunc) - ITEMLIST *itp; - SVFUNC *svfunc; -{ - SHELL_VAR **vlist; - STRINGLIST *sl; - register int i, n; - - vlist = (*svfunc) (); - if (vlist == 0) - { - itp->slist = (STRINGLIST *)NULL; - return; - } - for (n = 0; vlist[n]; n++) - ; - sl = strlist_create (n+1); - for (i = 0; i < n; i++) - sl->list[i] = savestring (vlist[i]->name); - sl->list[sl->list_len = n] = (char *)NULL; - itp->slist = sl; -} - -static int -it_init_arrayvars (itp) - ITEMLIST *itp; -{ -#if defined (ARRAY_VARS) - init_itemlist_from_varlist (itp, all_array_variables); - return 1; -#else - return 0; -#endif -} - -static int -it_init_bindings (itp) - ITEMLIST *itp; -{ - char **blist; - STRINGLIST *sl; - - /* rl_funmap_names allocates blist, but not its members */ - blist = (char **)rl_funmap_names (); /* XXX fix const later */ - sl = strlist_create (0); - sl->list = blist; - sl->list_size = 0; - sl->list_len = strvec_len (sl->list); - itp->flags |= LIST_DONTFREEMEMBERS; - itp->slist = sl; - - return 0; -} - -static int -it_init_builtins (itp) - ITEMLIST *itp; -{ - STRINGLIST *sl; - register int i, n; - - sl = strlist_create (num_shell_builtins); - for (i = n = 0; i < num_shell_builtins; i++) - if (shell_builtins[i].function) - sl->list[n++] = shell_builtins[i].name; - sl->list[sl->list_len = n] = (char *)NULL; - itp->flags |= LIST_DONTFREEMEMBERS; - itp->slist = sl; - return 0; -} - -static int -it_init_enabled (itp) - ITEMLIST *itp; -{ - STRINGLIST *sl; - register int i, n; - - sl = strlist_create (num_shell_builtins); - for (i = n = 0; i < num_shell_builtins; i++) - { - if (shell_builtins[i].function && (shell_builtins[i].flags & BUILTIN_ENABLED)) - sl->list[n++] = shell_builtins[i].name; - } - sl->list[sl->list_len = n] = (char *)NULL; - itp->flags |= LIST_DONTFREEMEMBERS; - itp->slist = sl; - return 0; -} - -static int -it_init_disabled (itp) - ITEMLIST *itp; -{ - STRINGLIST *sl; - register int i, n; - - sl = strlist_create (num_shell_builtins); - for (i = n = 0; i < num_shell_builtins; i++) - { - if (shell_builtins[i].function && ((shell_builtins[i].flags & BUILTIN_ENABLED) == 0)) - sl->list[n++] = shell_builtins[i].name; - } - sl->list[sl->list_len = n] = (char *)NULL; - itp->flags |= LIST_DONTFREEMEMBERS; - itp->slist = sl; - return 0; -} - -static int -it_init_exported (itp) - ITEMLIST *itp; -{ - init_itemlist_from_varlist (itp, all_exported_variables); - return 0; -} - -static int -it_init_functions (itp) - ITEMLIST *itp; -{ - init_itemlist_from_varlist (itp, all_visible_functions); - return 0; -} - -static int -it_init_hostnames (itp) - ITEMLIST *itp; -{ - STRINGLIST *sl; - - sl = strlist_create (0); - sl->list = get_hostname_list (); - sl->list_len = sl->list ? strvec_len (sl->list) : 0; - sl->list_size = sl->list_len; - itp->slist = sl; - itp->flags |= LIST_DONTFREEMEMBERS|LIST_DONTFREE; - return 0; -} - -static int -it_init_joblist (itp, jstate) - ITEMLIST *itp; - int jstate; -{ -#if defined (JOB_CONTROL) - STRINGLIST *sl; - register int i; - register PROCESS *p; - char *s, *t; - JOB *j; - JOB_STATE ws; /* wanted state */ - - ws = JNONE; - if (jstate == 0) - ws = JRUNNING; - else if (jstate == 1) - ws = JSTOPPED; - - sl = strlist_create (js.j_jobslots); - for (i = js.j_jobslots - 1; i >= 0; i--) - { - j = get_job_by_jid (i); - if (j == 0) - continue; - p = j->pipe; - if (jstate == -1 || JOBSTATE(i) == ws) - { - s = savestring (p->command); - t = strpbrk (s, " \t\n"); - if (t) - *t = '\0'; - sl->list[sl->list_len++] = s; - } - } - itp->slist = sl; -#else - itp->slist = (STRINGLIST *)NULL; -#endif - return 0; -} - -static int -it_init_jobs (itp) - ITEMLIST *itp; -{ - return (it_init_joblist (itp, -1)); -} - -static int -it_init_running (itp) - ITEMLIST *itp; -{ - return (it_init_joblist (itp, 0)); -} - -static int -it_init_stopped (itp) - ITEMLIST *itp; -{ - return (it_init_joblist (itp, 1)); -} - -static int -it_init_keywords (itp) - ITEMLIST *itp; -{ - STRINGLIST *sl; - register int i, n; - - for (n = 0; word_token_alist[n].word; n++) - ; - sl = strlist_create (n); - for (i = 0; i < n; i++) - sl->list[i] = word_token_alist[i].word; - sl->list[sl->list_len = i] = (char *)NULL; - itp->flags |= LIST_DONTFREEMEMBERS; - itp->slist = sl; - return 0; -} - -static int -it_init_signals (itp) - ITEMLIST *itp; -{ - STRINGLIST *sl; - - sl = strlist_create (0); - sl->list = signal_names; - sl->list_len = strvec_len (sl->list); - itp->flags |= LIST_DONTFREE; - itp->slist = sl; - return 0; -} - -static int -it_init_variables (itp) - ITEMLIST *itp; -{ - init_itemlist_from_varlist (itp, all_visible_variables); - return 0; -} - -static int -it_init_setopts (itp) - ITEMLIST *itp; -{ - STRINGLIST *sl; - - sl = strlist_create (0); - sl->list = get_minus_o_opts (); - sl->list_len = strvec_len (sl->list); - itp->slist = sl; - itp->flags |= LIST_DONTFREEMEMBERS; - return 0; -} - -static int -it_init_shopts (itp) - ITEMLIST *itp; -{ - STRINGLIST *sl; - - sl = strlist_create (0); - sl->list = get_shopt_options (); - sl->list_len = strvec_len (sl->list); - itp->slist = sl; - itp->flags |= LIST_DONTFREEMEMBERS; - return 0; -} - -/* Generate a list of all matches for TEXT using the STRINGLIST in itp->slist - as the list of possibilities. If the itemlist has been marked dirty or - it should be regenerated every time, destroy the old STRINGLIST and make a - new one before trying the match. TEXT is dequoted before attempting a - match. */ -static STRINGLIST * -gen_matches_from_itemlist (itp, text) - ITEMLIST *itp; - const char *text; -{ - STRINGLIST *ret, *sl; - int tlen, i, n; - char *ntxt; - - if ((itp->flags & (LIST_DIRTY|LIST_DYNAMIC)) || - (itp->flags & LIST_INITIALIZED) == 0) - { - if (itp->flags & (LIST_DIRTY | LIST_DYNAMIC)) - clean_itemlist (itp); - if ((itp->flags & LIST_INITIALIZED) == 0) - initialize_itemlist (itp); - } - if (itp->slist == 0) - return ((STRINGLIST *)NULL); - ret = strlist_create (itp->slist->list_len+1); - sl = itp->slist; - - ntxt = bash_dequote_text (text); - tlen = STRLEN (ntxt); - - for (i = n = 0; i < sl->list_len; i++) - { - if (tlen == 0 || STREQN (sl->list[i], ntxt, tlen)) - ret->list[n++] = STRDUP (sl->list[i]); - } - ret->list[ret->list_len = n] = (char *)NULL; - - FREE (ntxt); - return ret; -} - -/* A wrapper for rl_filename_completion_function that dequotes the filename - before attempting completions. */ -static char * -pcomp_filename_completion_function (text, state) - const char *text; - int state; -{ - static char *dfn; /* dequoted filename */ - int qc; - - if (state == 0) - { - FREE (dfn); - /* remove backslashes quoting special characters in filenames. */ -#if 1 - if (RL_ISSTATE (RL_STATE_COMPLETING) && rl_filename_dequoting_function) -#else - if (rl_filename_dequoting_function) -#endif - { - /* Use rl_completion_quote_character because any single or - double quotes have been removed by the time TEXT makes it - here, and we don't want to remove backslashes inside - quoted strings. */ - dfn = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character); - } - else - dfn = savestring (text); - } - - return (rl_filename_completion_function (dfn, state)); -} - -#define GEN_COMPS(bmap, flag, it, text, glist, tlist) \ - do { \ - if (bmap & flag) \ - { \ - tlist = gen_matches_from_itemlist (it, text); \ - if (tlist) \ - { \ - glist = strlist_append (glist, tlist); \ - strlist_dispose (tlist); \ - } \ - } \ - } while (0) - -#define GEN_XCOMPS(bmap, flag, text, func, cmatches, glist, tlist) \ - do { \ - if (bmap & flag) \ - { \ - cmatches = rl_completion_matches (text, func); \ - tlist = completions_to_stringlist (cmatches); \ - glist = strlist_append (glist, tlist); \ - strvec_dispose (cmatches); \ - strlist_dispose (tlist); \ - } \ - } while (0) - -/* Functions to generate lists of matches from the actions member of CS. */ - -static STRINGLIST * -gen_action_completions (cs, text) - COMPSPEC *cs; - const char *text; -{ - STRINGLIST *ret, *tmatches; - char **cmatches; /* from rl_completion_matches ... */ - unsigned long flags; - - ret = tmatches = (STRINGLIST *)NULL; - flags = cs->actions; - - GEN_COMPS (flags, CA_ALIAS, &it_aliases, text, ret, tmatches); - GEN_COMPS (flags, CA_ARRAYVAR, &it_arrayvars, text, ret, tmatches); - GEN_COMPS (flags, CA_BINDING, &it_bindings, text, ret, tmatches); - GEN_COMPS (flags, CA_BUILTIN, &it_builtins, text, ret, tmatches); - GEN_COMPS (flags, CA_DISABLED, &it_disabled, text, ret, tmatches); - GEN_COMPS (flags, CA_ENABLED, &it_enabled, text, ret, tmatches); - GEN_COMPS (flags, CA_EXPORT, &it_exports, text, ret, tmatches); - GEN_COMPS (flags, CA_FUNCTION, &it_functions, text, ret, tmatches); - GEN_COMPS (flags, CA_HOSTNAME, &it_hostnames, text, ret, tmatches); - GEN_COMPS (flags, CA_JOB, &it_jobs, text, ret, tmatches); - GEN_COMPS (flags, CA_KEYWORD, &it_keywords, text, ret, tmatches); - GEN_COMPS (flags, CA_RUNNING, &it_running, text, ret, tmatches); - GEN_COMPS (flags, CA_SETOPT, &it_setopts, text, ret, tmatches); - GEN_COMPS (flags, CA_SHOPT, &it_shopts, text, ret, tmatches); - GEN_COMPS (flags, CA_SIGNAL, &it_signals, text, ret, tmatches); - GEN_COMPS (flags, CA_STOPPED, &it_stopped, text, ret, tmatches); - GEN_COMPS (flags, CA_VARIABLE, &it_variables, text, ret, tmatches); - - GEN_XCOMPS(flags, CA_COMMAND, text, command_word_completion_function, cmatches, ret, tmatches); - GEN_XCOMPS(flags, CA_FILE, text, pcomp_filename_completion_function, cmatches, ret, tmatches); - GEN_XCOMPS(flags, CA_USER, text, rl_username_completion_function, cmatches, ret, tmatches); - GEN_XCOMPS(flags, CA_GROUP, text, bash_groupname_completion_function, cmatches, ret, tmatches); - GEN_XCOMPS(flags, CA_SERVICE, text, bash_servicename_completion_function, cmatches, ret, tmatches); - - /* And lastly, the special case for directories */ - if (flags & CA_DIRECTORY) - { - rl_completion_mark_symlink_dirs = 1; /* override user preference */ - cmatches = bash_directory_completion_matches (text); - tmatches = completions_to_stringlist (cmatches); - ret = strlist_append (ret, tmatches); - strvec_dispose (cmatches); - strlist_dispose (tmatches); - } - - return ret; -} - -/* Generate a list of matches for CS->globpat. Unresolved: should this use - TEXT as a match prefix, or just go without? Currently, the code does not - use TEXT, just globs CS->globpat and returns the results. If we do decide - to use TEXT, we should call quote_string_for_globbing before the call to - glob_filename. */ -static STRINGLIST * -gen_globpat_matches (cs, text) - COMPSPEC *cs; - const char *text; -{ - STRINGLIST *sl; - - sl = strlist_create (0); - sl->list = glob_filename (cs->globpat, 0); - if (GLOB_FAILED (sl->list)) - sl->list = (char **)NULL; - if (sl->list) - sl->list_len = sl->list_size = strvec_len (sl->list); - return sl; -} - -/* Perform the shell word expansions on CS->words and return the results. - Again, this ignores TEXT. */ -static STRINGLIST * -gen_wordlist_matches (cs, text) - COMPSPEC *cs; - const char *text; -{ - WORD_LIST *l, *l2; - STRINGLIST *sl; - int nw, tlen; - char *ntxt; /* dequoted TEXT to use in comparisons */ - - if (cs->words == 0 || cs->words[0] == '\0') - return ((STRINGLIST *)NULL); - - /* This used to be a simple expand_string(cs->words, 0), but that won't - do -- there's no way to split a simple list into individual words - that way, since the shell semantics say that word splitting is done - only on the results of expansion. */ - l = split_at_delims (cs->words, strlen (cs->words), (char *)NULL, -1, (int *)NULL, (int *)NULL); - if (l == 0) - return ((STRINGLIST *)NULL); - /* This will jump back to the top level if the expansion fails... */ - l2 = expand_words_shellexp (l); - dispose_words (l); - - nw = list_length (l2); - sl = strlist_create (nw + 1); - - ntxt = bash_dequote_text (text); - tlen = STRLEN (ntxt); - - for (nw = 0, l = l2; l; l = l->next) - { - if (tlen == 0 || STREQN (l->word->word, ntxt, tlen)) - sl->list[nw++] = STRDUP (l->word->word); - } - sl->list[sl->list_len = nw] = (char *)NULL; - - dispose_words (l2); - FREE (ntxt); - return sl; -} - -#ifdef ARRAY_VARS - -static SHELL_VAR * -bind_comp_words (lwords) - WORD_LIST *lwords; -{ - SHELL_VAR *v; - - v = find_variable ("COMP_WORDS"); - if (v == 0) - v = make_new_array_variable ("COMP_WORDS"); - if (readonly_p (v)) - VUNSETATTR (v, att_readonly); - if (array_p (v) == 0) - v = convert_var_to_array (v); - v = assign_array_var_from_word_list (v, lwords, 0); - - VUNSETATTR (v, att_invisible); - return v; -} -#endif /* ARRAY_VARS */ - -static void -bind_compfunc_variables (line, ind, lwords, cw, exported) - char *line; - int ind; - WORD_LIST *lwords; - int cw, exported; -{ - char ibuf[INT_STRLEN_BOUND(int) + 1]; - char *value; - SHELL_VAR *v; - - /* Set the variables that the function expects while it executes. Maybe - these should be in the function environment (temporary_env). */ - v = bind_variable ("COMP_LINE", line, 0); - if (v && exported) - VSETATTR(v, att_exported); - - value = inttostr (ind, ibuf, sizeof(ibuf)); - v = bind_int_variable ("COMP_POINT", value); - if (v && exported) - VSETATTR(v, att_exported); - - value = inttostr (rl_completion_type, ibuf, sizeof (ibuf)); - v = bind_int_variable ("COMP_TYPE", value); - if (v && exported) - VSETATTR(v, att_exported); - - value = inttostr (rl_completion_invoking_key, ibuf, sizeof (ibuf)); - v = bind_int_variable ("COMP_KEY", value); - if (v && exported) - VSETATTR(v, att_exported); - - /* Since array variables can't be exported, we don't bother making the - array of words. */ - if (exported == 0) - { -#ifdef ARRAY_VARS - v = bind_comp_words (lwords); - value = inttostr (cw, ibuf, sizeof(ibuf)); - bind_int_variable ("COMP_CWORD", value); -#endif - } - else - array_needs_making = 1; -} - -static void -unbind_compfunc_variables (exported) - int exported; -{ - unbind_variable ("COMP_LINE"); - unbind_variable ("COMP_POINT"); - unbind_variable ("COMP_TYPE"); - unbind_variable ("COMP_KEY"); -#ifdef ARRAY_VARS - unbind_variable ("COMP_WORDS"); - unbind_variable ("COMP_CWORD"); -#endif - if (exported) - array_needs_making = 1; -} - -/* Build the list of words to pass to a function or external command - as arguments. When the function or command is invoked, - - $0 == function or command being invoked - $1 == command name - $2 == word to be completed (possibly null) - $3 == previous word - - Functions can access all of the words in the current command line - with the COMP_WORDS array. External commands cannot; they have to - make do with the COMP_LINE and COMP_POINT variables. */ - -static WORD_LIST * -build_arg_list (cmd, text, lwords, ind) - char *cmd; - const char *text; - WORD_LIST *lwords; - int ind; -{ - WORD_LIST *ret, *cl, *l; - WORD_DESC *w; - int i; - - ret = (WORD_LIST *)NULL; - w = make_word (cmd); - ret = make_word_list (w, (WORD_LIST *)NULL); - - w = (lwords && lwords->word) ? copy_word (lwords->word) : make_word (""); - cl = ret->next = make_word_list (w, (WORD_LIST *)NULL); - - w = make_word (text); - cl->next = make_word_list (w, (WORD_LIST *)NULL); - cl = cl->next; - - /* Search lwords for current word */ - for (l = lwords, i = 1; l && i < ind-1; l = l->next, i++) - ; - w = (l && l->word) ? copy_word (l->word) : make_word (""); - cl->next = make_word_list (w, (WORD_LIST *)NULL); - - return ret; -} - -/* Build a command string with - $0 == cs->funcname (function to execute for completion list) - $1 == command name (command being completed) - $2 = word to be completed (possibly null) - $3 = previous word - and run in the current shell. The function should put its completion - list into the array variable COMPREPLY. We build a STRINGLIST - from the results and return it. - - Since the shell function should return its list of matches in an array - variable, this does nothing if arrays are not compiled into the shell. */ - -static STRINGLIST * -gen_shell_function_matches (cs, text, line, ind, lwords, nw, cw) - COMPSPEC *cs; - const char *text; - char *line; - int ind; - WORD_LIST *lwords; - int nw, cw; -{ - char *funcname; - STRINGLIST *sl; - SHELL_VAR *f, *v; - WORD_LIST *cmdlist; - int fval; - sh_parser_state_t ps; - sh_parser_state_t * restrict pps; -#if defined (ARRAY_VARS) - ARRAY *a; -#endif - - funcname = cs->funcname; - f = find_function (funcname); - if (f == 0) - { - internal_error (_("completion: function `%s' not found"), funcname); - rl_ding (); - rl_on_new_line (); - return ((STRINGLIST *)NULL); - } - -#if !defined (ARRAY_VARS) - return ((STRINGLIST *)NULL); -#else - - /* We pass cw - 1 because command_line_to_word_list returns indices that are - 1-based, while bash arrays are 0-based. */ - bind_compfunc_variables (line, ind, lwords, cw - 1, 0); - - cmdlist = build_arg_list (funcname, text, lwords, cw); - - pps = &ps; - begin_unwind_frame ("gen-shell-function-matches"); - add_unwind_protect (restore_parser_state, (char *)pps); - add_unwind_protect (dispose_words, (char *)cmdlist); - add_unwind_protect (unbind_compfunc_variables, (char *)0); - - fval = execute_shell_func`tion (f, cmdlist); - - discard_unwind_frame ("gen-shell-function-matches"); - restore_parser_state (pps); - - /* Now clean up and destroy everything. */ - dispose_words (cmdlist); - unbind_compfunc_variables (0); - - /* The list of completions is returned in the array variable COMPREPLY. */ - v = find_variable ("COMPREPLY"); - if (v == 0) - return ((STRINGLIST *)NULL); - if (array_p (v) == 0) - v = convert_var_to_array (v); - - VUNSETATTR (v, att_invisible); - - a = array_cell (v); - if (a == 0 || array_empty (a)) - sl = (STRINGLIST *)NULL; - else - { - /* XXX - should we filter the list of completions so only those matching - TEXT are returned? Right now, we do not. */ - sl = strlist_create (0); - sl->list = array_to_argv (a); - sl->list_len = sl->list_size = array_num_elements (a); - } - - /* XXX - should we unbind COMPREPLY here? */ - unbind_variable ("COMPREPLY"); - - return (sl); -#endif -} - -/* Build a command string with - $0 == cs->command (command to execute for completion list) - $1 == command name (command being completed) - $2 = word to be completed (possibly null) - $3 = previous word - and run in with command substitution. Parse the results, one word - per line, with backslashes allowed to escape newlines. Build a - STRINGLIST from the results and return it. */ - -static STRINGLIST * -gen_command_matches (cs, text, line, ind, lwords, nw, cw) - COMPSPEC *cs; - const char *text; - char *line; - int ind; - WORD_LIST *lwords; - int nw, cw; -{ - char *csbuf, *cscmd, *t; - int cmdlen, cmdsize, n, ws, we; - WORD_LIST *cmdlist, *cl; - WORD_DESC *tw; - STRINGLIST *sl; - - bind_compfunc_variables (line, ind, lwords, cw, 1); - cmdlist = build_arg_list (cs->command, text, lwords, cw); - - /* Estimate the size needed for the buffer. */ - n = strlen (cs->command); - cmdsize = n + 1; - for (cl = cmdlist->next; cl; cl = cl->next) - cmdsize += STRLEN (cl->word->word) + 3; - cmdsize += 2; - - /* allocate the string for the command and fill it in. */ - cscmd = (char *)xmalloc (cmdsize + 1); - - strcpy (cscmd, cs->command); /* $0 */ - cmdlen = n; - cscmd[cmdlen++] = ' '; - for (cl = cmdlist->next; cl; cl = cl->next) /* $1, $2, $3, ... */ - { - t = sh_single_quote (cl->word->word ? cl->word->word : ""); - n = strlen (t); - RESIZE_MALLOCED_BUFFER (cscmd, cmdlen, n + 2, cmdsize, 64); - strcpy (cscmd + cmdlen, t); - cmdlen += n; - if (cl->next) - cscmd[cmdlen++] = ' '; - free (t); - } - cscmd[cmdlen] = '\0'; - - tw = command_substitute (cscmd, 0); - csbuf = tw ? tw->word : (char *)NULL; - dispose_word_desc (tw); - - /* Now clean up and destroy everything. */ - dispose_words (cmdlist); - free (cscmd); - unbind_compfunc_variables (1); - - if (csbuf == 0 || *csbuf == '\0') - { - FREE (csbuf); - return ((STRINGLIST *)NULL); - } - - /* Now break CSBUF up at newlines, with backslash allowed to escape a - newline, and put the individual words into a STRINGLIST. */ - sl = strlist_create (16); - for (ws = 0; csbuf[ws]; ) - { - we = ws; - while (csbuf[we] && csbuf[we] != '\n') - { - if (csbuf[we] == '\\' && csbuf[we+1] == '\n') - we++; - we++; - } - t = substring (csbuf, ws, we); - if (sl->list_len >= sl->list_size - 1) - strlist_resize (sl, sl->list_size + 16); - sl->list[sl->list_len++] = t; - while (csbuf[we] == '\n') we++; - ws = we; - } - sl->list[sl->list_len] = (char *)NULL; - - free (csbuf); - return (sl); -} - -static WORD_LIST * -command_line_to_word_list (line, llen, sentinel, nwp, cwp) - char *line; - int llen, sentinel, *nwp, *cwp; -{ - WORD_LIST *ret; - char *delims; - -#if 0 - delims = "()<>;&| \t\n"; /* shell metacharacters break words */ -#else - delims = rl_completer_word_break_characters; -#endif - ret = split_at_delims (line, llen, delims, sentinel, nwp, cwp); - return (ret); -} - -/* Evaluate COMPSPEC *cs and return all matches for WORD. */ - -STRINGLIST * -gen_compspec_completions (cs, cmd, word, start, end) - COMPSPEC *cs; - const char *cmd; - const char *word; - int start, end; -{ - STRINGLIST *ret, *tmatches; - char *line; - int llen, nw, cw; - WORD_LIST *lwords; - COMPSPEC *tcs; - -#ifdef DEBUG - debug_printf ("gen_compspec_completions (%s, %s, %d, %d)", cmd, word, start, end); - debug_printf ("gen_compspec_completions: %s -> %p", cmd, cs); -#endif - ret = gen_action_completions (cs, word); -#ifdef DEBUG - if (ret && progcomp_debug) - { - debug_printf ("gen_action_completions (%p, %s) -->", cs, word); - strlist_print (ret, "\t"); - rl_on_new_line (); - } -#endif - - /* Now we start generating completions based on the other members of CS. */ - if (cs->globpat) - { - tmatches = gen_globpat_matches (cs, word); - if (tmatches) - { -#ifdef DEBUG - if (progcomp_debug) - { - debug_printf ("gen_globpat_matches (%p, %s) -->", cs, word); - strlist_print (tmatches, "\t"); - rl_on_new_line (); - } -#endif - ret = strlist_append (ret, tmatches); - strlist_dispose (tmatches); - rl_filename_completion_desired = 1; - } - } - - if (cs->words) - { - tmatches = gen_wordlist_matches (cs, word); - if (tmatches) - { -#ifdef DEBUG - if (progcomp_debug) - { - debug_printf ("gen_wordlist_matches (%p, %s) -->", cs, word); - strlist_print (tmatches, "\t"); - rl_on_new_line (); - } -#endif - ret = strlist_append (ret, tmatches); - strlist_dispose (tmatches); - } - } - - lwords = (WORD_LIST *)NULL; - line = (char *)NULL; - if (cs->command || cs->funcname) - { - /* If we have a command or function to execute, we need to first break - the command line into individual words, find the number of words, - and find the word in the list containing the word to be completed. */ - line = substring (rl_line_buffer, start, end); - llen = end - start; - -#ifdef DEBUG - debug_printf ("command_line_to_word_list (%s, %d, %d, %p, %p)", - line, llen, rl_point - start, &nw, &cw); -#endif - lwords = command_line_to_word_list (line, llen, rl_point - start, &nw, &cw); -#ifdef DEBUG - if (lwords == 0 && llen > 0) - debug_printf ("ERROR: command_line_to_word_list returns NULL"); - else if (progcomp_debug) - { - debug_printf ("command_line_to_word_list -->"); - printf ("\t"); - print_word_list (lwords, "!"); - printf ("\n"); - fflush(stdout); - rl_on_new_line (); - } -#endif - } - - if (cs->funcname) - { - tmatches = gen_shell_function_matches (cs, word, line, rl_point - start, lwords, nw, cw); - if (tmatches) - { -#ifdef DEBUG - if (progcomp_debug) - { - debug_printf ("gen_shell_function_matches (%p, %s, %p, %d, %d) -->", cs, word, lwords, nw, cw); - strlist_print (tmatches, "\t"); - rl_on_new_line (); - } -#endif - ret = strlist_append (ret, tmatches); - strlist_dispose (tmatches); - } - } - - if (cs->command) - { - tmatches = gen_command_matches (cs, word, line, rl_point - start, lwords, nw, cw); - if (tmatches) - { -#ifdef DEBUG - if (progcomp_debug) - { - debug_printf ("gen_command_matches (%p, %s, %p, %d, %d) -->", cs, word, lwords, nw, cw); - strlist_print (tmatches, "\t"); - rl_on_new_line (); - } -#endif - ret = strlist_append (ret, tmatches); - strlist_dispose (tmatches); - } - } - - if (cs->command || cs->funcname) - { - if (lwords) - dispose_words (lwords); - FREE (line); - } - - if (cs->filterpat) - { - tmatches = filter_stringlist (ret, cs->filterpat, word); -#ifdef DEBUG - if (progcomp_debug) - { - debug_printf ("filter_stringlist (%p, %s, %s) -->", ret, cs->filterpat, word); - strlist_print (tmatches, "\t"); - rl_on_new_line (); - } -#endif - if (ret && ret != tmatches) - { - FREE (ret->list); - free (ret); - } - ret = tmatches; - } - - if (cs->prefix || cs->suffix) - ret = strlist_prefix_suffix (ret, cs->prefix, cs->suffix); - - /* If no matches have been generated and the user has specified that - directory completion should be done as a default, call - gen_action_completions again to generate a list of matching directory - names. */ - if ((ret == 0 || ret->list_len == 0) && (cs->options & COPT_DIRNAMES)) - { - tcs = compspec_create (); - tcs->actions = CA_DIRECTORY; - ret = gen_action_completions (tcs, word); - compspec_dispose (tcs); - } - else if (cs->options & COPT_PLUSDIRS) - { - tcs = compspec_create (); - tcs->actions = CA_DIRECTORY; - tmatches = gen_action_completions (tcs, word); - ret = strlist_append (ret, tmatches); - strlist_dispose (tmatches); - compspec_dispose (tcs); - } - - return (ret); -} - -void -pcomp_set_readline_variables (flags, nval) - int flags, nval; -{ - /* If the user specified that the compspec returns filenames, make - sure that readline knows it. */ - if (flags & COPT_FILENAMES) - rl_filename_completion_desired = nval; - /* If the user doesn't want a space appended, tell readline. */ - if (flags & COPT_NOSPACE) - rl_completion_suppress_append = nval; -} - -/* Set or unset FLAGS in the options word of the current compspec. - SET_OR_UNSET is 1 for setting, 0 for unsetting. */ -void -pcomp_set_compspec_options (cs, flags, set_or_unset) - COMPSPEC *cs; - int flags, set_or_unset; -{ - if (cs == 0 && ((cs = pcomp_curcs) == 0)) - return; - if (set_or_unset) - cs->options |= flags; - else - cs->options &= ~flags; -} - -/* The driver function for the programmable completion code. Returns a list - of matches for WORD, which is an argument to command CMD. START and END - bound the command currently being completed in rl_line_buffer. */ -char ** -programmable_completions (cmd, word, start, end, foundp) - const char *cmd; - const char *word; - int start, end, *foundp; -{ - COMPSPEC *cs, *oldcs; - STRINGLIST *ret; - char **rmatches, *t; - const char *oldcmd; - - /* We look at the basename of CMD if the full command does not have - an associated COMPSPEC. */ - cs = progcomp_search (cmd); - if (cs == 0) - { - t = strrchr (cmd, '/'); - if (t) - cs = progcomp_search (++t); - } - if (cs == 0) - { - if (foundp) - *foundp = 0; - return ((char **)NULL); - } - - cs = compspec_copy (cs); - - oldcs = pcomp_curcs; - oldcmd = pcomp_curcmd; - - pcomp_curcs = cs; - pcomp_curcmd = cmd; - - /* Signal the caller that we found a COMPSPEC for this command, and pass - back any meta-options associated with the compspec. */ - if (foundp) - *foundp = 1|cs->options; - - ret = gen_compspec_completions (cs, cmd, word, start, end); - - pcomp_curcs = oldcs; - pcomp_curcmd = oldcmd; - - compspec_dispose (cs); - - if (ret) - { - rmatches = ret->list; - free (ret); - } - else - rmatches = (char **)NULL; - - return (rmatches); -} - -#endif /* PROGRAMMABLE_COMPLETION */ diff --git a/pcomplete.h~ b/pcomplete.h~ deleted file mode 100644 index 1bbb1d211..000000000 --- a/pcomplete.h~ +++ /dev/null @@ -1,157 +0,0 @@ -/* pcomplete.h - structure definitions and other stuff for programmable - completion. */ - -/* Copyright (C) 1999-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 (_PCOMPLETE_H_) -# define _PCOMPLETE_H_ - -#include "stdc.h" -#include "hashlib.h" - -typedef struct compspec { - int refcount; - unsigned long actions; - unsigned long options; - char *globpat; - char *words; - char *prefix; - char *suffix; - char *funcname; - char *command; - char *filterpat; -} COMPSPEC; - -/* Values for COMPSPEC actions. These are things the shell knows how to - build internally. */ -#define CA_ALIAS (1<<0) -#define CA_ARRAYVAR (1<<1) -#define CA_BINDING (1<<2) -#define CA_BUILTIN (1<<3) -#define CA_COMMAND (1<<4) -#define CA_DIRECTORY (1<<5) -#define CA_DISABLED (1<<6) -#define CA_ENABLED (1<<7) -#define CA_EXPORT (1<<8) -#define CA_FILE (1<<9) -#define CA_FUNCTION (1<<10) -#define CA_GROUP (1<<11) -#define CA_HELPTOPIC (1<<12) -#define CA_HOSTNAME (1<<13) -#define CA_JOB (1<<14) -#define CA_KEYWORD (1<<15) -#define CA_RUNNING (1<<16) -#define CA_SERVICE (1<<17) -#define CA_SETOPT (1<<18) -#define CA_SHOPT (1<<19) -#define CA_SIGNAL (1<<20) -#define CA_STOPPED (1<<21) -#define CA_USER (1<<22) -#define CA_VARIABLE (1<<23) - -/* Values for COMPSPEC options field. */ -#define COPT_RESERVED (1<<0) /* reserved for other use */ -#define COPT_DEFAULT (1<<1) -#define COPT_FILENAMES (1<<2) -#define COPT_DIRNAMES (1<<3) -#define COPT_NOSPACE (1<<4) -#define COPT_BASHDEFAULT (1<<5) -#define COPT_PLUSDIRS (1<<6) - -/* List of items is used by the code that implements the programmable - completions. */ -typedef struct _list_of_items { - int flags; - int (*list_getter) __P((struct _list_of_items *)); /* function to call to get the list */ - - STRINGLIST *slist; - - /* These may or may not be used. */ - STRINGLIST *genlist; /* for handing to the completion code one item at a time */ - int genindex; /* index of item last handed to completion code */ - -} ITEMLIST; - -/* Values for ITEMLIST -> flags */ -#define LIST_DYNAMIC 0x001 -#define LIST_DIRTY 0x002 -#define LIST_INITIALIZED 0x004 -#define LIST_MUSTSORT 0x008 -#define LIST_DONTFREE 0x010 -#define LIST_DONTFREEMEMBERS 0x020 - -extern HASH_TABLE *prog_completes; -extern int prog_completion_enabled; - -/* Not all of these are used yet. */ -extern ITEMLIST it_aliases; -extern ITEMLIST it_arrayvars; -extern ITEMLIST it_bindings; -extern ITEMLIST it_builtins; -extern ITEMLIST it_commands; -extern ITEMLIST it_directories; -extern ITEMLIST it_disabled; -extern ITEMLIST it_enabled; -extern ITEMLIST it_exports; -extern ITEMLIST it_files; -extern ITEMLIST it_functions; -extern ITEMLIST it_groups; -extern ITEMLIST it_hostnames; -extern ITEMLIST it_jobs; -extern ITEMLIST it_keywords; -extern ITEMLIST it_running; -extern ITEMLIST it_services; -extern ITEMLIST it_setopts; -extern ITEMLIST it_shopts; -extern ITEMLIST it_signals; -extern ITEMLIST it_stopped; -extern ITEMLIST it_users; -extern ITEMLIST it_variables; - -extern COMPSPEC *curcs; - -/* Functions from pcomplib.c */ -extern COMPSPEC *compspec_create __P((void)); -extern void compspec_dispose __P((COMPSPEC *)); -extern COMPSPEC *compspec_copy __P((COMPSPEC *)); - -extern void progcomp_create __P((void)); -extern void progcomp_flush __P((void)); -extern void progcomp_dispose __P((void)); - -extern int progcomp_size __P((void)); - -extern int progcomp_insert __P((char *, COMPSPEC *)); -extern int progcomp_remove __P((char *)); - -extern COMPSPEC *progcomp_search __P((const char *)); - -extern void progcomp_walk __P((hash_wfunc *)); - -/* Functions from pcomplete.c */ -extern void set_itemlist_dirty __P((ITEMLIST *)); - -extern STRINGLIST *completions_to_stringlist __P((char **)); - -extern STRINGLIST *gen_compspec_completions __P((COMPSPEC *, const char *, const char *, int, int)); -extern char **programmable_completions __P((const char *, const char *, int, int, int *)); - -extern void pcomp_set_readline_variables __P((int, int)); -extern void pcomp_set_compspec_options __P((COMPSPEC *, int, int)); -#endif /* _PCOMPLETE_H_ */ diff --git a/po/Makefile.in.in~ b/po/Makefile.in.in~ deleted file mode 100644 index 1af6fd25f..000000000 --- a/po/Makefile.in.in~ +++ /dev/null @@ -1,358 +0,0 @@ -# Makefile for PO directory in any package using GNU gettext. -# Copyright (C) 1995-1997, 2000-2003 by Ulrich Drepper -# -# This file can be copied and used freely without restrictions. It can -# be used in projects which are not available under the GNU General Public -# License but which still want to provide support for the GNU gettext -# functionality. -# Please note that the actual code of GNU gettext is covered by the GNU -# General Public License and is *not* in the public domain. - -PACKAGE = @PACKAGE_NAME@ -VERSION = @PACKAGE_VERSION@ - -SHELL = /bin/sh -@SET_MAKE@ - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -topdir = @top_srcdir@ -BUILD_DIR = @BUILD_DIR@ - -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -datarootdir = @datarootdir@ -datadir = @datadir@ -localedir = $(datadir)/locale -gettextsrcdir = $(datadir)/gettext/po - -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -MKINSTALLDIRS = @MKINSTALLDIRS@ -mkinstalldirs = $(SHELL) $(MKINSTALLDIRS) - -GMSGFMT = @GMSGFMT@ -MSGFMT = @MSGFMT@ -XGETTEXT = @XGETTEXT@ -MSGMERGE = msgmerge -MSGMERGE_UPDATE = @MSGMERGE@ --update -MSGINIT = msginit -MSGCONV = msgconv -MSGFILTER = msgfilter - -POFILES = @POFILES@ -GMOFILES = @GMOFILES@ -UPDATEPOFILES = @UPDATEPOFILES@ -DUMMYPOFILES = @DUMMYPOFILES@ -DISTFILES.common = Makefile.in.in remove-potcdate.sin \ -$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) -DISTFILES = $(DISTFILES.common) Makevars POTFILES.in $(DOMAIN).pot stamp-po \ -$(POFILES) $(GMOFILES) \ -$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) - -POTFILES = \ - -CATALOGS = @CATALOGS@ - -# Makevars gets inserted here. (Don't remove this line!) - -.SUFFIXES: -.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-update - -.po.mo: - @echo "$(MSGFMT) -c -o $@ $<"; \ - $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ - -.po.gmo: - @lang=`echo $* | sed -e 's,.*/,,'`; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \ - cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo - -.sin.sed: - sed -e '/^#/d' $< > t-$@ - mv t-$@ $@ - - -all: all-@USE_NLS@ - -all-yes: stamp-po -all-no: - -# stamp-po is a timestamp denoting the last time at which the CATALOGS have -# been loosely updated. Its purpose is that when a developer or translator -# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, -# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent -# invocations of "make" will do nothing. This timestamp would not be necessary -# if updating the $(CATALOGS) would always touch them; however, the rule for -# $(POFILES) has been designed to not touch files that don't need to be -# changed. -stamp-po: $(srcdir)/$(DOMAIN).pot - test -z "$(CATALOGS)" || $(MAKE) $(CATALOGS) - @echo "touch stamp-po" - @echo timestamp > stamp-poT - @mv stamp-poT stamp-po - -# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', -# otherwise packages like GCC can not be built if only parts of the source -# have been downloaded. - -# This target rebuilds $(DOMAIN).pot; it is an expensive operation. -# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed. -$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed - $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ - --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \ - --files-from=$(srcdir)/POTFILES.in \ - --copyright-holder='$(COPYRIGHT_HOLDER)' - $(MAKE) $(MFLAGS) builtins.pot-update - test ! -f $(DOMAIN).po || { \ - if test -f $(srcdir)/$(DOMAIN).pot; then \ - sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ - sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \ - if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \ - rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \ - else \ - rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \ - mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ - fi; \ - else \ - mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ - fi; \ - } - -# This rule has no dependencies: we don't need to update $(DOMAIN).pot at -# every "make" invocation, only create it when it is missing. -# Only "make $(DOMAIN).pot-update" or "make dist" will force an update. -$(srcdir)/$(DOMAIN).pot: - $(MAKE) $(DOMAIN).pot-update - -# This target rebuilds a PO file if $(DOMAIN).pot has changed. -# Note that a PO file is not touched if it doesn't need to be changed. -$(POFILES): $(srcdir)/$(DOMAIN).pot - @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \ - cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot - - -install: install-exec install-data -install-exec: -install-data: install-data-@USE_NLS@ - if test "$(PACKAGE)" = "gettext-tools"; then \ - $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ - for file in $(DISTFILES.common) Makevars.template; do \ - $(INSTALL_DATA) $(srcdir)/$$file \ - $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - for file in Makevars; do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi -install-data-no: all -install-data-yes: all - $(mkinstalldirs) $(DESTDIR)$(datadir) - @catalogs='$(CATALOGS)'; \ - for cat in $$catalogs; do \ - cat=`basename $$cat`; \ - lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ - dir=$(localedir)/$$lang/LC_MESSAGES; \ - $(mkinstalldirs) $(DESTDIR)$$dir; \ - if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ - $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ - echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ - for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ - if test -n "$$lc"; then \ - if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ - link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ - mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ - for file in *; do \ - if test -f $$file; then \ - ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ - fi; \ - done); \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - else \ - if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ - :; \ - else \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - fi; \ - fi; \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ - ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ - ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ - cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ - echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ - fi; \ - done; \ - done - -install-strip: install - -installdirs: installdirs-exec installdirs-data -installdirs-exec: -installdirs-data: installdirs-data-@USE_NLS@ - if test "$(PACKAGE)" = "gettext-tools"; then \ - $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \ - else \ - : ; \ - fi -installdirs-data-no: -installdirs-data-yes: - $(mkinstalldirs) $(DESTDIR)$(datadir) - @catalogs='$(CATALOGS)'; \ - for cat in $$catalogs; do \ - cat=`basename $$cat`; \ - lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ - dir=$(localedir)/$$lang/LC_MESSAGES; \ - $(mkinstalldirs) $(DESTDIR)$$dir; \ - for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ - if test -n "$$lc"; then \ - if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ - link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ - mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ - for file in *; do \ - if test -f $$file; then \ - ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ - fi; \ - done); \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ - else \ - if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ - :; \ - else \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ - mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ - fi; \ - fi; \ - fi; \ - done; \ - done - -# Define this as empty until I found a useful application. -installcheck: - -uninstall: uninstall-exec uninstall-data -uninstall-exec: -uninstall-data: uninstall-data-@USE_NLS@ - if test "$(PACKAGE)" = "gettext-tools"; then \ - for file in $(DISTFILES.common) Makevars.template; do \ - rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ - done; \ - else \ - : ; \ - fi -uninstall-data-no: -uninstall-data-yes: - catalogs='$(CATALOGS)'; \ - for cat in $$catalogs; do \ - cat=`basename $$cat`; \ - lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ - for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ - rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ - done; \ - done - -check: all - -info dvi ps pdf html tags TAGS ctags CTAGS ID: - -mostlyclean: - rm -f remove-potcdate.sed - rm -f stamp-poT - rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po - rm -fr *.o - -clean: mostlyclean - -distclean: clean - rm -f Makefile Makefile.in POTFILES *.mo - -maintainer-clean: distclean - @echo "This command is intended for maintainers to use;" - @echo "it deletes files that may require special tools to rebuild." - rm -f stamp-po $(GMOFILES) - -distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) -dist distdir: - $(MAKE) update-po - @$(MAKE) dist2 -# This is a separate target because 'update-po' must be executed before. -dist2: $(DISTFILES) - dists="$(DISTFILES)"; \ - if test "$(PACKAGE)" = "gettext-tools"; then \ - dists="$$dists Makevars.template"; \ - fi; \ - if test -f $(srcdir)/ChangeLog; then \ - dists="$$dists ChangeLog"; \ - fi; \ - for i in 0 1 2 3 4 5 6 7 8 9; do \ - if test -f $(srcdir)/ChangeLog.$$i; then \ - dists="$$dists ChangeLog.$$i"; \ - fi; \ - done; \ - if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ - for file in $$dists; do \ - if test -f $$file; then \ - cp -p $$file $(distdir); \ - else \ - cp -p $(srcdir)/$$file $(distdir); \ - fi; \ - done - -update-po: Makefile - $(MAKE) $(DOMAIN).pot-update - test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) - $(MAKE) update-gmo - -# General rule for updating PO files. - -.nop.po-update: - @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ - tmpdir=`pwd`; \ - echo "$$lang:"; \ - test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ - echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ - cd $(srcdir); \ - if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ - if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ - rm -f $$tmpdir/$$lang.new.po; \ - else \ - if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ - :; \ - else \ - echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ - exit 1; \ - fi; \ - fi; \ - else \ - echo "msgmerge for $$lang.po failed!" 1>&2; \ - rm -f $$tmpdir/$$lang.new.po; \ - fi - -$(DUMMYPOFILES): - -update-gmo: Makefile $(GMOFILES) - @: - -Makefile: Makefile.in.in $(top_builddir)/config.status @POMAKEFILEDEPS@ $(srcdir)/Rules-builtins - cd $(top_builddir) \ - && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \ - $(SHELL) ./config.status - -force: - -# Tell versions [3.59,3.63) of GNU make not to export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/print_cmd.c.save b/print_cmd.c.save deleted file mode 100644 index f156d47a4..000000000 --- a/print_cmd.c.save +++ /dev/null @@ -1,1326 +0,0 @@ -/* print_command -- A way to make readable commands from a command tree. */ - -/* Copyright (C) 1989-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 "shmbutil.h" - -#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; - - case cm_coproc: - cprintf ("coproc %s ", command->value.Coproc->name); - skip_this_indent++; - make_command_string_internal (command->value.Coproc->command); - 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; - char ps4_firstc[MB_LEN_MAX+1]; - int ps4_firstc_len, ps4_len; - - 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); - -#if defined (HANDLE_MULTIBYTE) - ps4_len = strnlen (ps4, MB_CUR_MAX); - ps4_firstc_len = MBLEN (ps4, ps4_len); - if (ps4_firstc_len == 1 || ps4_firstc_len == 0 || MB_INVALIDCH (ps4_firstc_len)) - { - ps4_firstc[0] = ps4[0]; - ps4_firstc[ps4_firstc_len = 1] = '\0'; - } - else - memcpy (ps4_firstc, ps4, ps4_firstc_len); -#else - ps4_firstc[0] = ps4[0]; - ps4_firstc[ps4_firstc_len = 1] = '\0'; -#endif - - for (i = j = 0; ps4_firstc[0] && j < indirection_level && i < 99; i += ps4_firstc_len, j++) - { - if (ps4_firstc_len == 1) - indirection_string[i] = ps4_firstc[0]; - else - memcpy (indirection_string+i, ps4_firstc, ps4_firstc_len); - } - - for (j = ps4_firstc_len; *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; - if (clauses->flags & CASEPAT_FALLTHROUGH) - newline (";&"); - else if (clauses->flags & CASEPAT_TESTNEXT) - newline (";;&"); - else - 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_append_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. - flags&FUNC_MULTILINE is non-zero to pretty-print, or zero for all on one line. - flags&FUNC_EXTERNAL means convert from internal to external form - */ -char * -named_function_string (name, command, flags) - char *name; - COMMAND *command; - int flags; -{ - 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 ((flags & FUNC_MULTILINE) == 0) - { - indentation = 1; - indentation_amount = 0; - } - else - { - cprintf ("\n"); - indentation += indentation_amount; - } - - inside_function_def++; - - cprintf ((flags & FUNC_MULTILINE) ? "{ \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 ((flags & FUNC_MULTILINE) == 0) - { -#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); - - if (flags & FUNC_EXTERNAL) - result = remove_quoted_escapes (result); - - 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/print_cmd.c~ b/print_cmd.c~ deleted file mode 100644 index 963969920..000000000 --- a/print_cmd.c~ +++ /dev/null @@ -1,1412 +0,0 @@ -/* print_command -- A way to make readable commands from a command tree. */ - -/* Copyright (C) 1989-2008 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can 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 "shmbutil.h" - -#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_heredoc_header __P((REDIRECT *)); -static void print_heredoc_body __P((REDIRECT *)); -static void print_heredocs __P((REDIRECT *)); -static void print_deferred_heredocs __P((const char *)); - -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; -static int printing_connection; -static REDIRECT *deferred_heredocs; - -/* 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; - deferred_heredocs = 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; -{ - char s[3]; - - 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++; - printing_connection++; - make_command_string_internal (command->value.Connection->first); - - switch (command->value.Connection->connector) - { - case '&': - case '|': - { - char c = command->value.Connection->connector; - - s[0] = ' '; - s[1] = c; - s[2] = '\0'; - - print_deferred_heredocs (s); - - if (c != '&' || command->value.Connection->second) - { - cprintf (" "); - skip_this_indent++; - } - } - break; - - case AND_AND: - print_deferred_heredocs (" && "); - if (command->value.Connection->second) - skip_this_indent++; - break; - - case OR_OR: - print_deferred_heredocs (" || "); - if (command->value.Connection->second) - skip_this_indent++; - break; - - case ';': -#if 0 - if (was_heredoc == 0) - cprintf (";"); - else - was_heredoc = 0; -#else - if (deferred_heredocs == 0) - cprintf (";"); - else - print_deferred_heredocs (";"); -#endif - - 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); - printing_connection--; - 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; - - case cm_coproc: - cprintf ("coproc %s ", command->value.Coproc->name); - skip_this_indent++; - make_command_string_internal (command->value.Coproc->command); - 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; - char ps4_firstc[MB_LEN_MAX+1]; - int ps4_firstc_len, ps4_len; - - 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); - -#if defined (HANDLE_MULTIBYTE) - ps4_len = strnlen (ps4, MB_CUR_MAX); - ps4_firstc_len = MBLEN (ps4, ps4_len); - if (ps4_firstc_len == 1 || ps4_firstc_len == 0 || MB_INVALIDCH (ps4_firstc_len)) - { - ps4_firstc[0] = ps4[0]; - ps4_firstc[ps4_firstc_len = 1] = '\0'; - } - else - memcpy (ps4_firstc, ps4, ps4_firstc_len); -#else - ps4_firstc[0] = ps4[0]; - ps4_firstc[ps4_firstc_len = 1] = '\0'; -#endif - - for (i = j = 0; ps4_firstc[0] && j < indirection_level && i < 99; i += ps4_firstc_len, j++) - { - if (ps4_firstc_len == 1) - indirection_string[i] = ps4_firstc[0]; - else - memcpy (indirection_string+i, ps4_firstc, ps4_firstc_len); - } - - for (j = ps4_firstc_len; *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; - if (clauses->flags & CASEPAT_FALLTHROUGH) - newline (";&"); - else if (clauses->flags & CASEPAT_TESTNEXT) - newline (";;&"); - else - 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_heredocs (heredocs) - REDIRECT *heredocs; -{ - REDIRECT *hdtail; - - cprintf (" "); - for (hdtail = heredocs; hdtail; hdtail = hdtail->next) - { - print_redirection (hdtail); - cprintf ("\n"); - } - was_heredoc = 1; -} - -static void -print_deferred_heredocs (cstring) - const char *cstring; -{ - REDIRECT *hdtail; - - for (hdtail = deferred_heredocs; hdtail; hdtail = hdtail->next) - { - cprintf (" "); - print_heredoc_header (hdtail); - } - if (cstring[0] != ';' || cstring[1]) - cprintf ("%s", cstring); - if (deferred_heredocs) - cprintf ("\n"); - for (hdtail = deferred_heredocs; hdtail; hdtail = hdtail->next) - { - print_heredoc_body (hdtail); - cprintf ("\n"); - } - if (deferred_heredocs) - { - if (cstring[0] != ';' || cstring[1]) - cprintf (" "); /* make sure there's at least one space */ - dispose_redirects (deferred_heredocs); - } - deferred_heredocs = (REDIRECT *)NULL; -} - -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 && printing_connection) - deferred_heredocs = heredocs; - else if (heredocs) - { - print_heredocs (heredocs); - dispose_redirects (heredocs); - } -} - -static void -print_heredoc_header (redirect) - REDIRECT *redirect; -{ - int kill_leading; - char *x; - - kill_leading = redirect->instruction == r_deblank_reading_until; - - /* Here doc header */ - if (redirect->redirector != 0) - cprintf ("%d", redirect->redirector); - - /* If the here document delimiter is quoted, single-quote it. */ - if (redirect->redirectee.filename->flags & W_QUOTED) - { - x = sh_single_quote (redirect->here_doc_eof); - cprintf ("<<%s%s", kill_leading ? "-" : "", x); - free (x); - } - else - cprintf ("<<%s%s", kill_leading ? "-" : "", redirect->here_doc_eof); -} - -static void -print_heredoc_body (redirect) - REDIRECT *redirect; -{ - /* Here doc body */ - cprintf ("%s%s", redirect->redirectee.filename->word, redirect->here_doc_eof); -} - -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: - case r_reading_until: - print_heredoc_header (redirect); - cprintf ("\n"); - print_heredoc_body (redirect); - 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_append_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; - printing_connection = 0; - deferred_heredocs = 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. - flags&FUNC_MULTILINE is non-zero to pretty-print, or zero for all on one line. - flags&FUNC_EXTERNAL means convert from internal to external form - */ -char * -named_function_string (name, command, flags) - char *name; - COMMAND *command; - int flags; -{ - 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; - deferred_heredocs = 0; - - if (name && *name) - cprintf ("%s ", name); - - cprintf ("() "); - - if ((flags & FUNC_MULTILINE) == 0) - { - indentation = 1; - indentation_amount = 0; - } - else - { - cprintf ("\n"); - indentation += indentation_amount; - } - - inside_function_def++; - - cprintf ((flags & FUNC_MULTILINE) ? "{ \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 ((flags & FUNC_MULTILINE) == 0) - { -#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); - - if (flags & FUNC_EXTERNAL) - result = remove_quoted_escapes (result); - - 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/redir.c~ b/redir.c~ deleted file mode 100644 index 2d512f16d..000000000 --- a/redir.c~ +++ /dev/null @@ -1,1155 +0,0 @@ -/* redir.c -- Functions to perform input and output redirection. */ - -/* Copyright (C) 1997-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include "config.h" - -#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) - #pragma alloca -#endif /* _AIX && RISC6000 && !__GNUC__ */ - -#include -#include "bashtypes.h" -#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) -# include -#endif -#include "filecntl.h" -#include "posixstat.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include - -#if !defined (errno) -extern int errno; -#endif - -#include "bashansi.h" -#include "bashintl.h" -#include "memalloc.h" - -#define NEED_FPURGE_DECL - -#include "shell.h" -#include "flags.h" -#include "execute_cmd.h" -#include "redir.h" - -#if defined (BUFFERED_INPUT) -# include "input.h" -#endif - -#define SHELL_FD_BASE 10 - -int expanding_redir; - -extern int posixly_correct; -extern REDIRECT *redirection_undo_list; -extern REDIRECT *exec_redirection_undo_list; - -/* Static functions defined and used in this file. */ -static void add_undo_close_redirect __P((int)); -static void add_exec_redirect __P((REDIRECT *)); -static int add_undo_redirect __P((int, enum r_instruction, int)); -static int expandable_redirection_filename __P((REDIRECT *)); -static int stdin_redirection __P((enum r_instruction, int)); -static int undoablefd __P((int)); -static int do_redirection_internal __P((REDIRECT *, int)); - -static int write_here_document __P((int, WORD_DESC *)); -static int write_here_string __P((int, WORD_DESC *)); -static int here_document_to_fd __P((WORD_DESC *, enum r_instruction)); - -static int redir_special_open __P((int, char *, int, int, enum r_instruction)); -static int noclobber_open __P((char *, int, int, enum r_instruction)); -static int redir_open __P((char *, int, int, enum r_instruction)); - -/* Spare redirector used when translating [N]>&WORD[-] or [N]<&WORD[-] to - a new redirection and when creating the redirection undo list. */ -static REDIRECTEE rd; - -/* Set to errno when a here document cannot be created for some reason. - Used to print a reasonable error message. */ -static int heredoc_errno; - -void -redirection_error (temp, error) - REDIRECT *temp; - int error; -{ - char *filename, *allocname; - int oflags; - - allocname = 0; - if (temp->redirector < 0) - /* This can happen when read_token_word encounters overflow, like in - exec 4294967297>x */ - filename = _("file descriptor out of range"); -#ifdef EBADF - /* This error can never involve NOCLOBBER */ - else if (error != NOCLOBBER_REDIRECT && temp->redirector >= 0 && error == EBADF) - { - /* If we're dealing with two file descriptors, we have to guess about - which one is invalid; in the cases of r_{duplicating,move}_input and - r_{duplicating,move}_output we're here because dup2() failed. */ - switch (temp->instruction) - { - case r_duplicating_input: - case r_duplicating_output: - case r_move_input: - case r_move_output: - filename = allocname = itos (temp->redirectee.dest); - break; - default: - filename = allocname = itos (temp->redirector); - break; - } - } -#endif - else if (expandable_redirection_filename (temp)) - { - if (posixly_correct && interactive_shell == 0) - { - oflags = temp->redirectee.filename->flags; - temp->redirectee.filename->flags |= W_NOGLOB; - } - filename = allocname = redirection_expand (temp->redirectee.filename); - if (posixly_correct && interactive_shell == 0) - temp->redirectee.filename->flags = oflags; - if (filename == 0) - filename = temp->redirectee.filename->word; - } - else if (temp->redirectee.dest < 0) - filename = "file descriptor out of range"; - else - filename = allocname = itos (temp->redirectee.dest); - - switch (error) - { - case AMBIGUOUS_REDIRECT: - internal_error (_("%s: ambiguous redirect"), filename); - break; - - case NOCLOBBER_REDIRECT: - internal_error (_("%s: cannot overwrite existing file"), filename); - break; - -#if defined (RESTRICTED_SHELL) - case RESTRICTED_REDIRECT: - internal_error (_("%s: restricted: cannot redirect output"), filename); - break; -#endif /* RESTRICTED_SHELL */ - - case HEREDOC_REDIRECT: - internal_error (_("cannot create temp file for here-document: %s"), strerror (heredoc_errno)); - break; - - default: - internal_error ("%s: %s", filename, strerror (error)); - break; - } - - FREE (allocname); -} - -/* Perform the redirections on LIST. If flags & RX_ACTIVE, then actually - make input and output file descriptors, otherwise just do whatever is - neccessary for side effecting. flags & RX_UNDOABLE says to remember - how to undo the redirections later, if non-zero. If flags & RX_CLEXEC - is non-zero, file descriptors opened in do_redirection () have their - close-on-exec flag set. */ -int -do_redirections (list, flags) - REDIRECT *list; - int flags; -{ - int error; - REDIRECT *temp; - - if (flags & RX_UNDOABLE) - { - if (redirection_undo_list) - { - dispose_redirects (redirection_undo_list); - redirection_undo_list = (REDIRECT *)NULL; - } - if (exec_redirection_undo_list) - dispose_exec_redirects (); - } - - for (temp = list; temp; temp = temp->next) - { - error = do_redirection_internal (temp, flags); - if (error) - { - redirection_error (temp, error); - return (error); - } - } - return (0); -} - -/* Return non-zero if the redirection pointed to by REDIRECT has a - redirectee.filename that can be expanded. */ -static int -expandable_redirection_filename (redirect) - REDIRECT *redirect; -{ - switch (redirect->instruction) - { - case r_output_direction: - case r_appending_to: - case r_input_direction: - case r_inputa_direction: - case r_err_and_out: - case r_append_err_and_out: - case r_input_output: - case r_output_force: - case r_duplicating_input_word: - case r_duplicating_output_word: - case r_move_input_word: - case r_move_output_word: - return 1; - - default: - return 0; - } -} - -/* Expand the word in WORD returning a string. If WORD expands to - multiple words (or no words), then return NULL. */ -char * -redirection_expand (word) - WORD_DESC *word; -{ - char *result; - WORD_LIST *tlist1, *tlist2; - WORD_DESC *w; - - w = copy_word (word); - if (posixly_correct) - w->flags |= W_NOSPLIT; - - tlist1 = make_word_list (w, (WORD_LIST *)NULL); - expanding_redir = 1; - tlist2 = expand_words_no_vars (tlist1); - expanding_redir = 0; - dispose_words (tlist1); - - if (!tlist2 || tlist2->next) - { - /* We expanded to no words, or to more than a single word. - Dispose of the word list and return NULL. */ - if (tlist2) - dispose_words (tlist2); - return ((char *)NULL); - } - result = string_list (tlist2); /* XXX savestring (tlist2->word->word)? */ - dispose_words (tlist2); - return (result); -} - -static int -write_here_string (fd, redirectee) - int fd; - WORD_DESC *redirectee; -{ - char *herestr; - int herelen, n, e; - - herestr = expand_string_to_string (redirectee->word, 0); - herelen = STRLEN (herestr); - - n = write (fd, herestr, herelen); - if (n == herelen) - { - n = write (fd, "\n", 1); - herelen = 1; - } - e = errno; - FREE (herestr); - if (n != herelen) - { - if (e == 0) - e = ENOSPC; - return e; - } - return 0; -} - -/* Write the text of the here document pointed to by REDIRECTEE to the file - descriptor FD, which is already open to a temp file. Return 0 if the - write is successful, otherwise return errno. */ -static int -write_here_document (fd, redirectee) - int fd; - WORD_DESC *redirectee; -{ - char *document; - int document_len, fd2; - FILE *fp; - register WORD_LIST *t, *tlist; - - /* Expand the text if the word that was specified had - no quoting. The text that we expand is treated - exactly as if it were surrounded by double quotes. */ - - if (redirectee->flags & W_QUOTED) - { - document = redirectee->word; - document_len = strlen (document); - /* Set errno to something reasonable if the write fails. */ - if (write (fd, document, document_len) < document_len) - { - if (errno == 0) - errno = ENOSPC; - return (errno); - } - else - return 0; - } - - tlist = expand_string (redirectee->word, Q_HERE_DOCUMENT); - if (tlist) - { - /* Try using buffered I/O (stdio) and writing a word - at a time, letting stdio do the work of buffering - for us rather than managing our own strings. Most - stdios are not particularly fast, however -- this - may need to be reconsidered later. */ - if ((fd2 = dup (fd)) < 0 || (fp = fdopen (fd2, "w")) == NULL) - { - if (fd2 >= 0) - close (fd2); - return (errno); - } - errno = 0; - for (t = tlist; t; t = t->next) - { - /* This is essentially the body of - string_list_internal expanded inline. */ - document = t->word->word; - document_len = strlen (document); - if (t != tlist) - putc (' ', fp); /* separator */ - fwrite (document, document_len, 1, fp); - if (ferror (fp)) - { - if (errno == 0) - errno = ENOSPC; - fd2 = errno; - fclose(fp); - dispose_words (tlist); - return (fd2); - } - } - dispose_words (tlist); - if (fclose (fp) != 0) - { - if (errno == 0) - errno = ENOSPC; - return (errno); - } - } - return 0; -} - -/* Create a temporary file holding the text of the here document pointed to - by REDIRECTEE, and return a file descriptor open for reading to the temp - file. Return -1 on any error, and make sure errno is set appropriately. */ -static int -here_document_to_fd (redirectee, ri) - WORD_DESC *redirectee; - enum r_instruction ri; -{ - char *filename; - int r, fd, fd2; - - fd = sh_mktmpfd ("sh-thd", MT_USERANDOM|MT_USETMPDIR, &filename); - - /* If we failed for some reason other than the file existing, abort */ - if (fd < 0) - { - FREE (filename); - return (fd); - } - - errno = r = 0; /* XXX */ - /* write_here_document returns 0 on success, errno on failure. */ - if (redirectee->word) - r = (ri != r_reading_string) ? write_here_document (fd, redirectee) - : write_here_string (fd, redirectee); - - if (r) - { - close (fd); - unlink (filename); - free (filename); - errno = r; - return (-1); - } - - /* In an attempt to avoid races, we close the first fd only after opening - the second. */ - /* Make the document really temporary. Also make it the input. */ - fd2 = open (filename, O_RDONLY, 0600); - - if (fd2 < 0) - { - r = errno; - unlink (filename); - free (filename); - close (fd); - errno = r; - return -1; - } - - close (fd); - if (unlink (filename) < 0) - { - r = errno; -#if defined (__CYGWIN__) - /* Under CygWin 1.1.0, the unlink will fail if the file is - open. This hack will allow the previous action of silently - ignoring the error, but will still leave the file there. This - needs some kind of magic. */ - if (r == EACCES) - return (fd2); -#endif /* __CYGWIN__ */ - close (fd2); - free (filename); - errno = r; - return (-1); - } - - free (filename); - return (fd2); -} - -#define RF_DEVFD 1 -#define RF_DEVSTDERR 2 -#define RF_DEVSTDIN 3 -#define RF_DEVSTDOUT 4 -#define RF_DEVTCP 5 -#define RF_DEVUDP 6 - -/* A list of pattern/value pairs for filenames that the redirection - code handles specially. */ -static STRING_INT_ALIST _redir_special_filenames[] = { -#if !defined (HAVE_DEV_FD) - { "/dev/fd/[0-9]*", RF_DEVFD }, -#endif -#if !defined (HAVE_DEV_STDIN) - { "/dev/stderr", RF_DEVSTDERR }, - { "/dev/stdin", RF_DEVSTDIN }, - { "/dev/stdout", RF_DEVSTDOUT }, -#endif -#if defined (NETWORK_REDIRECTIONS) - { "/dev/tcp/*/*", RF_DEVTCP }, - { "/dev/udp/*/*", RF_DEVUDP }, -#endif - { (char *)NULL, -1 } -}; - -static int -redir_special_open (spec, filename, flags, mode, ri) - int spec; - char *filename; - int flags, mode; - enum r_instruction ri; -{ - int fd; -#if !defined (HAVE_DEV_FD) - intmax_t lfd; -#endif - - fd = -1; - switch (spec) - { -#if !defined (HAVE_DEV_FD) - case RF_DEVFD: - if (all_digits (filename+8) && legal_number (filename+8, &lfd) && lfd == (int)lfd) - { - fd = lfd; - fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE); - } - else - fd = AMBIGUOUS_REDIRECT; - break; -#endif - -#if !defined (HAVE_DEV_STDIN) - case RF_DEVSTDIN: - fd = fcntl (0, F_DUPFD, SHELL_FD_BASE); - break; - case RF_DEVSTDOUT: - fd = fcntl (1, F_DUPFD, SHELL_FD_BASE); - break; - case RF_DEVSTDERR: - fd = fcntl (2, F_DUPFD, SHELL_FD_BASE); - break; -#endif - -#if defined (NETWORK_REDIRECTIONS) - case RF_DEVTCP: - case RF_DEVUDP: -#if defined (HAVE_NETWORK) - fd = netopen (filename); -#else - internal_warning (_("/dev/(tcp|udp)/host/port not supported without networking")); - fd = open (filename, flags, mode); -#endif - break; -#endif /* NETWORK_REDIRECTIONS */ - } - - return fd; -} - -/* Open FILENAME with FLAGS in noclobber mode, hopefully avoiding most - race conditions and avoiding the problem where the file is replaced - between the stat(2) and open(2). */ -static int -noclobber_open (filename, flags, mode, ri) - char *filename; - int flags, mode; - enum r_instruction ri; -{ - int r, fd; - struct stat finfo, finfo2; - - /* If the file exists and is a regular file, return an error - immediately. */ - r = stat (filename, &finfo); - if (r == 0 && (S_ISREG (finfo.st_mode))) - return (NOCLOBBER_REDIRECT); - - /* If the file was not present (r != 0), make sure we open it - exclusively so that if it is created before we open it, our open - will fail. Make sure that we do not truncate an existing file. - Note that we don't turn on O_EXCL unless the stat failed -- if - the file was not a regular file, we leave O_EXCL off. */ - flags &= ~O_TRUNC; - if (r != 0) - { - fd = open (filename, flags|O_EXCL, mode); - return ((fd < 0 && errno == EEXIST) ? NOCLOBBER_REDIRECT : fd); - } - fd = open (filename, flags, mode); - - /* If the open failed, return the file descriptor right away. */ - if (fd < 0) - return (errno == EEXIST ? NOCLOBBER_REDIRECT : fd); - - /* OK, the open succeeded, but the file may have been changed from a - non-regular file to a regular file between the stat and the open. - We are assuming that the O_EXCL open handles the case where FILENAME - did not exist and is symlinked to an existing file between the stat - and open. */ - - /* If we can open it and fstat the file descriptor, and neither check - revealed that it was a regular file, and the file has not been replaced, - return the file descriptor. */ - if ((fstat (fd, &finfo2) == 0) && (S_ISREG (finfo2.st_mode) == 0) && - r == 0 && (S_ISREG (finfo.st_mode) == 0) && - same_file (filename, filename, &finfo, &finfo2)) - return fd; - - /* The file has been replaced. badness. */ - close (fd); - errno = EEXIST; - return (NOCLOBBER_REDIRECT); -} - -static int -redir_open (filename, flags, mode, ri) - char *filename; - int flags, mode; - enum r_instruction ri; -{ - int fd, r; - - r = find_string_in_alist (filename, _redir_special_filenames, 1); - if (r >= 0) - return (redir_special_open (r, filename, flags, mode, ri)); - - /* If we are in noclobber mode, you are not allowed to overwrite - existing files. Check before opening. */ - if (noclobber && CLOBBERING_REDIRECT (ri)) - { - fd = noclobber_open (filename, flags, mode, ri); - if (fd == NOCLOBBER_REDIRECT) - return (NOCLOBBER_REDIRECT); - } - else - { - fd = open (filename, flags, mode); -#if defined (AFS) - if ((fd < 0) && (errno == EACCES)) - { - fd = open (filename, flags & ~O_CREAT, mode); - errno = EACCES; /* restore errno */ - } -#endif /* AFS */ - } - - return fd; -} - -static int -undoablefd (fd) - int fd; -{ - int clexec; - - clexec = fcntl (fd, F_GETFD, 0); - if (clexec == -1 || (fd >= SHELL_FD_BASE && clexec == 1)) - return 0; - return 1; -} - -/* Do the specific redirection requested. Returns errno or one of the - special redirection errors (*_REDIRECT) in case of error, 0 on success. - If flags & RX_ACTIVE is zero, then just do whatever is neccessary to - produce the appropriate side effects. flags & RX_UNDOABLE, if non-zero, - says to remember how to undo each redirection. If flags & RX_CLEXEC is - non-zero, then we set all file descriptors > 2 that we open to be - close-on-exec. */ -static int -do_redirection_internal (redirect, flags) - REDIRECT *redirect; - int flags; -{ - WORD_DESC *redirectee; - int redir_fd, fd, redirector, r, oflags; - intmax_t lfd; - char *redirectee_word; - enum r_instruction ri; - REDIRECT *new_redirect; - - redirectee = redirect->redirectee.filename; - redir_fd = redirect->redirectee.dest; - redirector = redirect->redirector; - ri = redirect->instruction; - - if (redirect->flags & RX_INTERNAL) - flags |= RX_INTERNAL; - - if (TRANSLATE_REDIRECT (ri)) - { - /* We have [N]>&WORD[-] or [N]<&WORD[-]. Expand WORD, then translate - the redirection into a new one and continue. */ - redirectee_word = redirection_expand (redirectee); - - /* XXX - what to do with [N]<&$w- where w is unset or null? ksh93 - closes N. */ - if (redirectee_word == 0) - return (AMBIGUOUS_REDIRECT); - else if (redirectee_word[0] == '-' && redirectee_word[1] == '\0') - { - rd.dest = 0; - new_redirect = make_redirection (redirector, r_close_this, rd); - } - else if (all_digits (redirectee_word)) - { - if (legal_number (redirectee_word, &lfd) && (int)lfd == lfd) - rd.dest = lfd; - else - rd.dest = -1; /* XXX */ - switch (ri) - { - case r_duplicating_input_word: - new_redirect = make_redirection (redirector, r_duplicating_input, rd); - break; - case r_duplicating_output_word: - new_redirect = make_redirection (redirector, r_duplicating_output, rd); - break; - case r_move_input_word: - new_redirect = make_redirection (redirector, r_move_input, rd); - break; - case r_move_output_word: - new_redirect = make_redirection (redirector, r_move_output, rd); - break; - } - } - else if (ri == r_duplicating_output_word && redirector == 1) - { - rd.filename = make_bare_word (redirectee_word); - new_redirect = make_redirection (1, r_err_and_out, rd); - } - else - { - free (redirectee_word); - return (AMBIGUOUS_REDIRECT); - } - - free (redirectee_word); - - /* Set up the variables needed by the rest of the function from the - new redirection. */ - if (new_redirect->instruction == r_err_and_out) - { - char *alloca_hack; - - /* Copy the word without allocating any memory that must be - explicitly freed. */ - redirectee = (WORD_DESC *)alloca (sizeof (WORD_DESC)); - xbcopy ((char *)new_redirect->redirectee.filename, - (char *)redirectee, sizeof (WORD_DESC)); - - alloca_hack = (char *) - alloca (1 + strlen (new_redirect->redirectee.filename->word)); - redirectee->word = alloca_hack; - strcpy (redirectee->word, new_redirect->redirectee.filename->word); - } - else - /* It's guaranteed to be an integer, and shouldn't be freed. */ - redirectee = new_redirect->redirectee.filename; - - redir_fd = new_redirect->redirectee.dest; - redirector = new_redirect->redirector; - ri = new_redirect->instruction; - - /* Overwrite the flags element of the old redirect with the new value. */ - redirect->flags = new_redirect->flags; - dispose_redirects (new_redirect); - } - - switch (ri) - { - case r_output_direction: - case r_appending_to: - case r_input_direction: - case r_inputa_direction: - case r_err_and_out: /* command &>filename */ - case r_append_err_and_out: /* command &>> filename */ - case r_input_output: - case r_output_force: - if (posixly_correct && interactive_shell == 0) - { - oflags = redirectee->flags; - redirectee->flags |= W_NOGLOB; - } - redirectee_word = redirection_expand (redirectee); - if (posixly_correct && interactive_shell == 0) - redirectee->flags = oflags; - - if (redirectee_word == 0) - return (AMBIGUOUS_REDIRECT); - -#if defined (RESTRICTED_SHELL) - if (restricted && (WRITE_REDIRECT (ri))) - { - free (redirectee_word); - return (RESTRICTED_REDIRECT); - } -#endif /* RESTRICTED_SHELL */ - - fd = redir_open (redirectee_word, redirect->flags, 0666, ri); - free (redirectee_word); - - if (fd == NOCLOBBER_REDIRECT) - return (fd); - - if (fd < 0) - return (errno); - - if (flags & RX_ACTIVE) - { - if (flags & RX_UNDOABLE) - { - /* Only setup to undo it if the thing to undo is active. */ - if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1)) - add_undo_redirect (redirector, ri, -1); - else - add_undo_close_redirect (redirector); - } - -#if defined (BUFFERED_INPUT) - check_bash_input (redirector); -#endif - - /* Make sure there is no pending output before we change the state - of the underlying file descriptor, since the builtins use stdio - for output. */ - if (redirector == 1 && fileno (stdout) == redirector) - { - fflush (stdout); - fpurge (stdout); - } - else if (redirector == 2 && fileno (stderr) == redirector) - { - fflush (stderr); - fpurge (stderr); - } - - if ((fd != redirector) && (dup2 (fd, redirector) < 0)) - return (errno); - -#if defined (BUFFERED_INPUT) - /* Do not change the buffered stream for an implicit redirection - of /dev/null to fd 0 for asynchronous commands without job - control (r_inputa_direction). */ - if (ri == r_input_direction || ri == r_input_output) - duplicate_buffered_stream (fd, redirector); -#endif /* BUFFERED_INPUT */ - - /* - * If we're remembering, then this is the result of a while, for - * or until loop with a loop redirection, or a function/builtin - * executing in the parent shell with a redirection. In the - * function/builtin case, we want to set all file descriptors > 2 - * to be close-on-exec to duplicate the effect of the old - * for i = 3 to NOFILE close(i) loop. In the case of the loops, - * both sh and ksh leave the file descriptors open across execs. - * The Posix standard mentions only the exec builtin. - */ - if ((flags & RX_CLEXEC) && (redirector > 2)) - SET_CLOSE_ON_EXEC (redirector); - } - - if (fd != redirector) - { -#if defined (BUFFERED_INPUT) - if (INPUT_REDIRECT (ri)) - close_buffered_fd (fd); - else -#endif /* !BUFFERED_INPUT */ - close (fd); /* Don't close what we just opened! */ - } - - /* If we are hacking both stdout and stderr, do the stderr - redirection here. */ - if (ri == r_err_and_out || ri == r_append_err_and_out) - { - if (flags & RX_ACTIVE) - { - if (flags & RX_UNDOABLE) - add_undo_redirect (2, ri, -1); - if (dup2 (1, 2) < 0) - return (errno); - } - } - break; - - case r_reading_until: - case r_deblank_reading_until: - case r_reading_string: - /* REDIRECTEE is a pointer to a WORD_DESC containing the text of - the new input. Place it in a temporary file. */ - if (redirectee) - { - fd = here_document_to_fd (redirectee, ri); - - if (fd < 0) - { - heredoc_errno = errno; - return (HEREDOC_REDIRECT); - } - - if (flags & RX_ACTIVE) - { - if (flags & RX_UNDOABLE) - { - /* Only setup to undo it if the thing to undo is active. */ - if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1)) - add_undo_redirect (redirector, ri, -1); - else - add_undo_close_redirect (redirector); - } - -#if defined (BUFFERED_INPUT) - check_bash_input (redirector); -#endif - if (fd != redirector && dup2 (fd, redirector) < 0) - { - r = errno; - close (fd); - return (r); - } - -#if defined (BUFFERED_INPUT) - duplicate_buffered_stream (fd, redirector); -#endif - - if ((flags & RX_CLEXEC) && (redirector > 2)) - SET_CLOSE_ON_EXEC (redirector); - } - - if (fd != redirector) -#if defined (BUFFERED_INPUT) - close_buffered_fd (fd); -#else - close (fd); -#endif - } - break; - - case r_duplicating_input: - case r_duplicating_output: - case r_move_input: - case r_move_output: - if ((flags & RX_ACTIVE) && (redir_fd != redirector)) - { - if (flags & RX_UNDOABLE) - { - /* Only setup to undo it if the thing to undo is active. */ - if (fcntl (redirector, F_GETFD, 0) != -1) - add_undo_redirect (redirector, ri, redir_fd); - else - add_undo_close_redirect (redirector); - } -#if defined (BUFFERED_INPUT) - check_bash_input (redirector); -#endif - /* This is correct. 2>&1 means dup2 (1, 2); */ - if (dup2 (redir_fd, redirector) < 0) - return (errno); - -#if defined (BUFFERED_INPUT) - if (ri == r_duplicating_input || ri == r_move_input) - duplicate_buffered_stream (redir_fd, redirector); -#endif /* BUFFERED_INPUT */ - - /* First duplicate the close-on-exec state of redirectee. dup2 - leaves the flag unset on the new descriptor, which means it - stays open. Only set the close-on-exec bit for file descriptors - greater than 2 in any case, since 0-2 should always be open - unless closed by something like `exec 2<&-'. It should always - be safe to set fds > 2 to close-on-exec if they're being used to - save file descriptors < 2, since we don't need to preserve the - state of the close-on-exec flag for those fds -- they should - always be open. */ - /* if ((already_set || set_unconditionally) && (ok_to_set)) - set_it () */ -#if 0 - if (((fcntl (redir_fd, F_GETFD, 0) == 1) || redir_fd < 2 || (flags & RX_CLEXEC)) && - (redirector > 2)) -#else - if (((fcntl (redir_fd, F_GETFD, 0) == 1) || (redir_fd < 2 && (flags & RX_INTERNAL)) || (flags & RX_CLEXEC)) && - (redirector > 2)) -#endif - SET_CLOSE_ON_EXEC (redirector); - - /* When undoing saving of non-standard file descriptors (>=3) using - file descriptors >= SHELL_FD_BASE, we set the saving fd to be - close-on-exec and use a flag to decide how to set close-on-exec - when the fd is restored. */ - if ((redirect->flags & RX_INTERNAL) && (redirect->flags & RX_SAVCLEXEC) && redirector >= 3 && redir_fd >= SHELL_FD_BASE) - SET_OPEN_ON_EXEC (redirector); - - /* dup-and-close redirection */ - if (ri == r_move_input || ri == r_move_output) - { - close (redir_fd); -#if defined (COPROCESS_SUPPORT) - coproc_fdchk (redir_fd); /* XXX - loses coproc fds */ -#endif - } - } - break; - - case r_close_this: - if (flags & RX_ACTIVE) - { - if ((flags & RX_UNDOABLE) && (fcntl (redirector, F_GETFD, 0) != -1)) - add_undo_redirect (redirector, ri, -1); - -#if defined (COPROCESS_SUPPORT) - coproc_fdchk (redirector); -#endif - -#if defined (BUFFERED_INPUT) - check_bash_input (redirector); - close_buffered_fd (redirector); -#else /* !BUFFERED_INPUT */ - close (redirector); -#endif /* !BUFFERED_INPUT */ - } - break; - - case r_duplicating_input_word: - case r_duplicating_output_word: - break; - } - return (0); -} - -/* Remember the file descriptor associated with the slot FD, - on REDIRECTION_UNDO_LIST. Note that the list will be reversed - before it is executed. Any redirections that need to be undone - even if REDIRECTION_UNDO_LIST is discarded by the exec builtin - are also saved on EXEC_REDIRECTION_UNDO_LIST. FDBASE says where to - start the duplicating. If it's less than SHELL_FD_BASE, we're ok, - and can use SHELL_FD_BASE (-1 == don't care). If it's >= SHELL_FD_BASE, - we have to make sure we don't use fdbase to save a file descriptor, - since we're going to use it later (e.g., make sure we don't save fd 0 - to fd 10 if we have a redirection like 0<&10). If the value of fdbase - puts the process over its fd limit, causing fcntl to fail, we try - again with SHELL_FD_BASE. */ -static int -add_undo_redirect (fd, ri, fdbase) - int fd; - enum r_instruction ri; - int fdbase; -{ - int new_fd, clexec_flag; - REDIRECT *new_redirect, *closer, *dummy_redirect; - - new_fd = fcntl (fd, F_DUPFD, (fdbase < SHELL_FD_BASE) ? SHELL_FD_BASE : fdbase+1); - if (new_fd < 0) - new_fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE); - - if (new_fd < 0) - { - sys_error (_("redirection error: cannot duplicate fd")); - return (-1); - } - - clexec_flag = fcntl (fd, F_GETFD, 0); -itrace("add_undo_redirect: saving copy of fd %d in fd %d clexec = %d", fd, new_fd, clexec_flag); - - rd.dest = 0; - closer = make_redirection (new_fd, r_close_this, rd); - closer->flags |= RX_INTERNAL; - dummy_redirect = copy_redirects (closer); - - rd.dest = new_fd; - if (fd == 0) - new_redirect = make_redirection (fd, r_duplicating_input, rd); - else - new_redirect = make_redirection (fd, r_duplicating_output, rd); - new_redirect->flags |= RX_INTERNAL; - if (clexec_flag == 0 && fd >= 3 && new_fd >= SHELL_FD_BASE) -{ -itrace("add_undo_redirect: setting RX_SAVCLEXEC"); - new_redirect->flags |= RX_SAVCLEXEC; -} - new_redirect->next = closer; - - closer->next = redirection_undo_list; - redirection_undo_list = new_redirect; - - /* Save redirections that need to be undone even if the undo list - is thrown away by the `exec' builtin. */ - add_exec_redirect (dummy_redirect); - - /* experimental: if we're saving a redirection to undo for a file descriptor - above SHELL_FD_BASE, add a redirection to be undone if the exec builtin - causes redirections to be discarded. There needs to be a difference - between fds that are used to save other fds and then are the target of - user redirctions and fds that are just the target of user redirections. - We use the close-on-exec flag to tell the difference; fds > SHELL_FD_BASE - that have the close-on-exec flag set are assumed to be fds used internally - to save others. */ - if (fd >= SHELL_FD_BASE && ri != r_close_this && clexec_flag) - { - rd.dest = new_fd; - new_redirect = make_redirection (fd, r_duplicating_output, rd); - new_redirect->flags |= RX_INTERNAL; - - add_exec_redirect (new_redirect); - } - - /* File descriptors used only for saving others should always be - marked close-on-exec. Unfortunately, we have to preserve the - close-on-exec state of the file descriptor we are saving, since - fcntl (F_DUPFD) sets the new file descriptor to remain open - across execs. If, however, the file descriptor whose state we - are saving is <= 2, we can just set the close-on-exec flag, - because file descriptors 0-2 should always be open-on-exec, - and the restore above in do_redirection() will take care of it. */ - if (clexec_flag || fd < 3) - SET_CLOSE_ON_EXEC (new_fd); - else if (redirection_undo_list->flags & RX_SAVCLEXEC) - SET_CLOSE_ON_EXEC (new_fd); - - return (0); -} - -/* Set up to close FD when we are finished with the current command - and its redirections. */ -static void -add_undo_close_redirect (fd) - int fd; -{ - REDIRECT *closer; - - rd.dest = 0; - closer = make_redirection (fd, r_close_this, rd); - closer->flags |= RX_INTERNAL; - closer->next = redirection_undo_list; - redirection_undo_list = closer; -} - -static void -add_exec_redirect (dummy_redirect) - REDIRECT *dummy_redirect; -{ - dummy_redirect->next = exec_redirection_undo_list; - exec_redirection_undo_list = dummy_redirect; -} - -/* Return 1 if the redirection specified by RI and REDIRECTOR alters the - standard input. */ -static int -stdin_redirection (ri, redirector) - enum r_instruction ri; - int redirector; -{ - switch (ri) - { - case r_input_direction: - case r_inputa_direction: - case r_input_output: - case r_reading_until: - case r_deblank_reading_until: - case r_reading_string: - return (1); - case r_duplicating_input: - case r_duplicating_input_word: - case r_close_this: - return (redirector == 0); - case r_output_direction: - case r_appending_to: - case r_duplicating_output: - case r_err_and_out: - case r_append_err_and_out: - case r_output_force: - case r_duplicating_output_word: - return (0); - } - return (0); -} - -/* Return non-zero if any of the redirections in REDIRS alter the standard - input. */ -int -stdin_redirects (redirs) - REDIRECT *redirs; -{ - REDIRECT *rp; - int n; - - for (n = 0, rp = redirs; rp; rp = rp->next) - n += stdin_redirection (rp->instruction, rp->redirector); - return n; -} diff --git a/shell.c~ b/shell.c~ deleted file mode 100644 index e6bfe362d..000000000 --- a/shell.c~ +++ /dev/null @@ -1,1839 +0,0 @@ -/* shell.c -- GNU's idea of the POSIX shell specification. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -/* - 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 - -#if defined (READLINE) -# include "bashline.h" -#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 int expand_aliases; -extern int array_needs_making; -extern int gnu_error_format; -extern char *primary_prompt, *secondary_prompt; -extern char *this_command_name; - -/* Non-zero means that this shell has already been run; i.e. you should - call shell_reinitialize () if you need to start afresh. */ -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; - -/* Non-zero means to list status of running and stopped jobs at shell exit */ -int check_jobs_at_exit = 0; - -/* Non-zero means to change to a directory name supplied as a command name */ -int autocd = 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; - -/* Do we have /dev/fd? */ -#ifdef HAVE_DEV_FD -int have_devfd = HAVE_DEV_FD; -#else -int have_devfd = 0; -#endif - -/* 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 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 */ - -#if defined (STRICT_POSIX) -int posixly_correct = 1; /* Non-zero means posix.2 superset. */ -#else -int posixly_correct = 0; /* Non-zero means posix.2 superset. */ -#endif - - -/* Some long-winded argument names. These are obviously new. */ -#define Int 1 -#define Charp 2 -static const struct { - const 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 init_interactive_script __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) sleep (3); - - 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; - if (arg_index > argc) - arg_index = argc; - 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 error 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 (stderr)))) /* error 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", 0); - 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_lang (); - set_default_locale_vars (); - - /* - * M-x term -> TERM=eterm EMACS=22.1 (term:0.96) (eterm) - * M-x shell -> TERM=dumb EMACS=t (no line editing) - * M-x terminal -> TERM=emacs-em7955 EMACS= (line editing) - */ - if (interactive_shell) - { - char *term, *emacs; - - term = get_string_value ("TERM"); - emacs = get_string_value ("EMACS"); - - /* Not sure any emacs terminal emulator sets TERM=emacs any more */ - no_line_editing |= term && (STREQ (term, "emacs")); - no_line_editing |= emacs && emacs[0] == 't' && emacs[1] == '\0' && STREQ (term, "dumb"); - - /* running_under_emacs == 2 for `eterm' */ - running_under_emacs = (emacs != 0) || (term && STREQN (term, "emacs", 5)); - running_under_emacs += term && STREQN (term, "eterm", 5) && strstr (emacs, "term"); - - if (running_under_emacs) - gnu_error_format = 1; - } - - 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", 0); - 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. */ - reset_mail_timer (); - init_mail_dates (); - -#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 (COPROCESS_SUPPORT) - coproc_flush (); -#endif - -#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); - if (*temp == '-') - temp++; - 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|W_NOPROCSUB; - 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, 1, -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_interactive_script (); - - 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 (); -#if defined (BUFFERED_INPUT) - else if (interactive == 0) - with_input_from_buffered_stream (default_buffered_input, dollar_vars[0]); -#endif /* BUFFERED_INPUT */ - else - with_input_from_stream (default_input, dollar_vars[0]); -} - -/* 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; - bash_input.type = st_none; - } -#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 = argv0 ? base_pathname (argv0) : PROGRAM; - - if (argv0 && *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 ? argv0 : PROGRAM; - 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 () -{ - expand_aliases = interactive_shell = startup_state = 1; - interactive = 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 */ -} - -static void -init_interactive_script () -{ - init_noninteractive (); - expand_aliases = interactive_shell = startup_state = 1; -} - -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); - - reinit_special_variables (); - -#if defined (READLINE) - bashline_reinitialize (); -#endif - - 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/shell.h~ b/shell.h~ deleted file mode 100644 index ec086885e..000000000 --- a/shell.h~ +++ /dev/null @@ -1,163 +0,0 @@ -/* shell.h -- The data structures used by the shell */ - -/* 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. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "bashjmp.h" - -#include "command.h" -#include "syntax.h" -#include "general.h" -#include "error.h" -#include "variables.h" -#include "arrayfunc.h" -#include "quit.h" -#include "maxpath.h" -#include "unwind_prot.h" -#include "dispose_cmd.h" -#include "make_cmd.h" -#include "ocache.h" -#include "subst.h" -#include "sig.h" -#include "pathnames.h" -#include "externs.h" - -extern int EOF_Reached; - -#define NO_PIPE -1 -#define REDIRECT_BOTH -2 - -#define NO_VARIABLE -1 - -/* Values that can be returned by execute_command (). */ -#define EXECUTION_FAILURE 1 -#define EXECUTION_SUCCESS 0 - -/* Usage messages by builtins result in a return status of 2. */ -#define EX_BADUSAGE 2 - -/* Special exit statuses used by the shell, internally and externally. */ -#define EX_BINARY_FILE 126 -#define EX_NOEXEC 126 -#define EX_NOINPUT 126 -#define EX_NOTFOUND 127 - -#define EX_SHERRBASE 256 /* all special error values are > this. */ - -#define EX_BADSYNTAX 257 /* shell syntax error */ -#define EX_USAGE 258 /* syntax error in usage */ -#define EX_REDIRFAIL 259 /* redirection failed */ -#define EX_BADASSIGN 260 /* variable assignment error */ -#define EX_EXPFAIL 261 /* word expansion failed */ - -/* Flag values that control parameter pattern substitution. */ -#define MATCH_ANY 0x000 -#define MATCH_BEG 0x001 -#define MATCH_END 0x002 - -#define MATCH_TYPEMASK 0x003 - -#define MATCH_GLOBREP 0x010 -#define MATCH_QUOTED 0x020 -#define MATCH_STARSUB 0x040 - -/* Some needed external declarations. */ -extern char **shell_environment; -extern WORD_LIST *rest_of_args; - -/* Generalized global variables. */ -extern int debugging_mode; -extern int executing, login_shell; -extern int interactive, interactive_shell; -extern int startup_state; - -/* Structure to pass around that holds a bitmap of file descriptors - to close, and the size of that structure. Used in execute_cmd.c. */ -struct fd_bitmap { - int size; - char *bitmap; -}; - -#define FD_BITMAP_SIZE 32 - -#define CTLESC '\001' -#define CTLNUL '\177' - -/* Information about the current user. */ -struct user_info { - uid_t uid, euid; - gid_t gid, egid; - char *user_name; - char *shell; /* shell from the password file */ - char *home_dir; -}; - -extern struct user_info current_user; - -/* Force gcc to not clobber X on a longjmp(). Old versions of gcc mangle - this badly. */ -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ > 8) -# define USE_VAR(x) ((void) &(x)) -#else -# define USE_VAR(x) -#endif - -/* Structure in which to save partial parsing state when doing things like - PROMPT_COMMAND and bash_execute_unix_command execution. */ - -typedef struct _sh_parser_state_t { - - /* parsing state */ - int parser_state; - int *token_state; - - /* input line state -- line number saved elsewhere */ - int input_line_terminator; - int eof_encountered; - -#if defined (HANDLE_MULTIBYTE) - /* Nothing right now for multibyte state, but might want something later. */ -#endif - - /* history state affecting or modified by the parser */ - int current_command_line_count; -#if defined (HISTORY) - int remember_on_history; - int history_expansion_inhibited; -#endif - - /* execution state possibly modified by the parser */ - int last_command_exit_value; -#if defined (ARRAY_VARS) - ARRAY *pipestatus; -#endif - sh_builtin_func_t *last_shell_builtin, *this_shell_builtin; - - /* flags state affecting the parser */ - int expand_aliases; - int echo_input_at_read; - -} sh_parser_state_t; - -/* Let's try declaring these here. */ -extern sh_parser_state_t *save_parser_state __P((sh_parser_state_t *)); -extern void restore_parser_state __P((sh_parser_state_t *)); diff --git a/sig.c~ b/sig.c~ deleted file mode 100644 index e6d6b4eb7..000000000 --- a/sig.c~ +++ /dev/null @@ -1,615 +0,0 @@ -/* sig.c - interface for shell signal handlers and signal initialization. */ - -/* Copyright (C) 1994-2007 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -#include "config.h" - -#include "bashtypes.h" - -#if defined (HAVE_UNISTD_H) -# ifdef _MINIX -# include -# endif -# include -#endif - -#include -#include - -#include "bashintl.h" - -#include "shell.h" -#if defined (JOB_CONTROL) -#include "jobs.h" -#endif /* JOB_CONTROL */ -#include "siglist.h" -#include "sig.h" -#include "trap.h" - -#include "builtins/common.h" - -#if defined (READLINE) -# include "bashline.h" -#endif - -#if defined (HISTORY) -# include "bashhist.h" -#endif - -extern int last_command_exit_value; -extern int last_command_exit_signal; -extern int return_catch_flag; -extern int loop_level, continuing, breaking; -extern int parse_and_execute_level, shell_initialized; - -/* Non-zero after SIGINT. */ -volatile int interrupt_state = 0; - -/* Non-zero after SIGWINCH */ -volatile int sigwinch_received = 0; - -/* Set to the value of any terminating signal received. */ -volatile int terminating_signal = 0; - -/* The environment at the top-level R-E loop. We use this in - the case of error return. */ -procenv_t top_level; - -#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) -/* The signal masks that this shell runs with. */ -sigset_t top_level_mask; -#endif /* JOB_CONTROL */ - -/* When non-zero, we throw_to_top_level (). */ -int interrupt_immediately = 0; - -/* When non-zero, we call the terminating signal handler immediately. */ -int terminate_immediately = 0; - -#if defined (SIGWINCH) -static SigHandler *old_winch = (SigHandler *)SIG_DFL; -#endif - -static void initialize_shell_signals __P((void)); - -void -initialize_signals (reinit) - int reinit; -{ - initialize_shell_signals (); - initialize_job_signals (); -#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL) - if (reinit == 0) - initialize_siglist (); -#endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */ -} - -/* A structure describing a signal that terminates the shell if not - caught. The orig_handler member is present so children can reset - these signals back to their original handlers. */ -struct termsig { - int signum; - SigHandler *orig_handler; - int orig_flags; -}; - -#define NULL_HANDLER (SigHandler *)SIG_DFL - -/* The list of signals that would terminate the shell if not caught. - We catch them, but just so that we can write the history file, - and so forth. */ -static struct termsig terminating_signals[] = { -#ifdef SIGHUP -{ SIGHUP, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGINT -{ SIGINT, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGILL -{ SIGILL, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGTRAP -{ SIGTRAP, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGIOT -{ SIGIOT, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGDANGER -{ SIGDANGER, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGEMT -{ SIGEMT, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGFPE -{ SIGFPE, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGBUS -{ SIGBUS, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGSEGV -{ SIGSEGV, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGSYS -{ SIGSYS, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGPIPE -{ SIGPIPE, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGALRM -{ SIGALRM, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGTERM -{ SIGTERM, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGXCPU -{ SIGXCPU, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGXFSZ -{ SIGXFSZ, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGVTALRM -{ SIGVTALRM, NULL_HANDLER, 0 }, -#endif - -#if 0 -#ifdef SIGPROF -{ SIGPROF, NULL_HANDLER, 0 }, -#endif -#endif - -#ifdef SIGLOST -{ SIGLOST, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGUSR1 -{ SIGUSR1, NULL_HANDLER, 0 }, -#endif - -#ifdef SIGUSR2 -{ SIGUSR2, NULL_HANDLER, 0 }, -#endif -}; - -#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig)) - -#define XSIG(x) (terminating_signals[x].signum) -#define XHANDLER(x) (terminating_signals[x].orig_handler) -#define XSAFLAGS(x) (terminating_signals[x].orig_flags) - -static int termsigs_initialized = 0; - -/* Initialize signals that will terminate the shell to do some - unwind protection. For non-interactive shells, we only call - this when a trap is defined for EXIT (0). */ -void -initialize_terminating_signals () -{ - register int i; -#if defined (HAVE_POSIX_SIGNALS) - struct sigaction act, oact; -#endif - - if (termsigs_initialized) - return; - - /* The following code is to avoid an expensive call to - set_signal_handler () for each terminating_signals. Fortunately, - this is possible in Posix. Unfortunately, we have to call signal () - on non-Posix systems for each signal in terminating_signals. */ -#if defined (HAVE_POSIX_SIGNALS) - act.sa_handler = termsig_sighandler; - act.sa_flags = 0; - sigemptyset (&act.sa_mask); - sigemptyset (&oact.sa_mask); - for (i = 0; i < TERMSIGS_LENGTH; i++) - sigaddset (&act.sa_mask, XSIG (i)); - for (i = 0; i < TERMSIGS_LENGTH; i++) - { - /* If we've already trapped it, don't do anything. */ - if (signal_is_trapped (XSIG (i))) - continue; - - sigaction (XSIG (i), &act, &oact); - XHANDLER(i) = oact.sa_handler; - XSAFLAGS(i) = oact.sa_flags; - /* Don't do anything with signals that are ignored at shell entry - if the shell is not interactive. */ - if (!interactive_shell && XHANDLER (i) == SIG_IGN) - { - sigaction (XSIG (i), &oact, &act); - set_signal_ignored (XSIG (i)); - } -#if defined (SIGPROF) && !defined (_MINIX) - if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN) - sigaction (XSIG (i), &oact, (struct sigaction *)NULL); -#endif /* SIGPROF && !_MINIX */ - } - -#else /* !HAVE_POSIX_SIGNALS */ - - for (i = 0; i < TERMSIGS_LENGTH; i++) - { - /* If we've already trapped it, don't do anything. */ - if (signal_is_trapped (XSIG (i))) - continue; - - XHANDLER(i) = signal (XSIG (i), termsig_sighandler); - XSAFLAGS(i) = 0; - /* Don't do anything with signals that are ignored at shell entry - if the shell is not interactive. */ - if (!interactive_shell && XHANDLER (i) == SIG_IGN) - { - signal (XSIG (i), SIG_IGN); - set_signal_ignored (XSIG (i)); - } -#ifdef SIGPROF - if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN) - signal (XSIG (i), XHANDLER (i)); -#endif - } - -#endif /* !HAVE_POSIX_SIGNALS */ - - termsigs_initialized = 1; -} - -static void -initialize_shell_signals () -{ - if (interactive) - initialize_terminating_signals (); - -#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) - /* All shells use the signal mask they inherit, and pass it along - to child processes. Children will never block SIGCHLD, though. */ - sigemptyset (&top_level_mask); - sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask); -# if defined (SIGCHLD) - sigdelset (&top_level_mask, SIGCHLD); -# endif -#endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */ - - /* And, some signals that are specifically ignored by the shell. */ - set_signal_handler (SIGQUIT, SIG_IGN); - - if (interactive) - { - set_signal_handler (SIGINT, sigint_sighandler); - set_signal_handler (SIGTERM, SIG_IGN); - set_sigwinch_handler (); - } -} - -void -reset_terminating_signals () -{ - register int i; -#if defined (HAVE_POSIX_SIGNALS) - struct sigaction act; -#endif - - if (termsigs_initialized == 0) - return; - -#if defined (HAVE_POSIX_SIGNALS) - act.sa_flags = 0; - sigemptyset (&act.sa_mask); - for (i = 0; i < TERMSIGS_LENGTH; i++) - { - /* Skip a signal if it's trapped or handled specially, because the - trap code will restore the correct value. */ - if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i))) - continue; - - act.sa_handler = XHANDLER (i); - act.sa_flags = XSAFLAGS (i); - sigaction (XSIG (i), &act, (struct sigaction *) NULL); - } -#else /* !HAVE_POSIX_SIGNALS */ - for (i = 0; i < TERMSIGS_LENGTH; i++) - { - if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i))) - continue; - - signal (XSIG (i), XHANDLER (i)); - } -#endif /* !HAVE_POSIX_SIGNALS */ -} -#undef XSIG -#undef XHANDLER - -/* Run some of the cleanups that should be performed when we run - jump_to_top_level from a builtin command context. XXX - might want to - also call reset_parser here. */ -void -top_level_cleanup () -{ - /* Clean up string parser environment. */ - while (parse_and_execute_level) - parse_and_execute_cleanup (); - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - run_unwind_protects (); - loop_level = continuing = breaking = 0; - return_catch_flag = 0; -} - -/* What to do when we've been interrupted, and it is safe to handle it. */ -void -throw_to_top_level () -{ - int print_newline = 0; - - if (interrupt_state) - { - print_newline = 1; - DELINTERRUPT; - } - - if (interrupt_state) - return; - - last_command_exit_signal = (last_command_exit_value > 128) ? - (last_command_exit_value - 128) : 0; - last_command_exit_value |= 128; - - /* Run any traps set on SIGINT. */ - run_interrupt_trap (); - - /* Clean up string parser environment. */ - while (parse_and_execute_level) - parse_and_execute_cleanup (); - -#if defined (JOB_CONTROL) - give_terminal_to (shell_pgrp, 0); -#endif /* JOB_CONTROL */ - -#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) - /* This should not be necessary on systems using sigsetjmp/siglongjmp. */ - sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); -#endif - - reset_parser (); - -#if defined (READLINE) - if (interactive) - bashline_reset (); -#endif /* READLINE */ - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - run_unwind_protects (); - loop_level = continuing = breaking = 0; - return_catch_flag = 0; - - if (interactive && print_newline) - { - fflush (stdout); - fprintf (stderr, "\n"); - fflush (stderr); - } - - /* An interrupted `wait' command in a script does not exit the script. */ - if (interactive || (interactive_shell && !shell_initialized) || - (print_newline && signal_is_trapped (SIGINT))) - jump_to_top_level (DISCARD); - else - jump_to_top_level (EXITPROG); -} - -/* This is just here to isolate the longjmp calls. */ -void -jump_to_top_level (value) - int value; -{ - longjmp (top_level, value); -} - -sighandler -termsig_sighandler (sig) - int sig; -{ - terminating_signal = sig; - - if (terminate_immediately) - { - terminate_immediately = 0; - termsig_handler (sig); - } - - SIGRETURN (0); -} - -void -termsig_handler (sig) - int sig; -{ - static int handling_termsig = 0; - - /* Simple semaphore to keep this function from being executed multiple - times. Since we no longer are running as a signal handler, we don't - block multiple occurrences of the terminating signals while running. */ - if (handling_termsig) - return; - handling_termsig = 1; - terminating_signal = 0; /* keep macro from re-testing true. */ - - /* I don't believe this condition ever tests true. */ - if (sig == SIGINT && signal_is_trapped (SIGINT)) - run_interrupt_trap (); - -#if defined (HISTORY) - if (interactive_shell && sig != SIGABRT) - maybe_save_shell_history (); -#endif /* HISTORY */ - -#if defined (JOB_CONTROL) - if (interactive && sig == SIGHUP) - hangup_all_jobs (); - end_job_control (); -#endif /* JOB_CONTROL */ - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - -itrace("received terminating signal %d", terminating_signal); - run_exit_trap (); - set_signal_handler (sig, SIG_DFL); - kill (getpid (), sig); -} - -/* What we really do when SIGINT occurs. */ -sighandler -sigint_sighandler (sig) - int sig; -{ -#if defined (MUST_REINSTALL_SIGHANDLERS) - signal (sig, sigint_sighandler); -#endif - - /* interrupt_state needs to be set for the stack of interrupts to work - right. Should it be set unconditionally? */ - if (interrupt_state == 0) - ADDINTERRUPT; - - if (interrupt_immediately) - { - interrupt_immediately = 0; - throw_to_top_level (); - } - - SIGRETURN (0); -} - -#if defined (SIGWINCH) -sighandler -sigwinch_sighandler (sig) - int sig; -{ -#if defined (MUST_REINSTALL_SIGHANDLERS) - set_signal_handler (SIGWINCH, sigwinch_sighandler); -#endif /* MUST_REINSTALL_SIGHANDLERS */ - sigwinch_received = 1; - SIGRETURN (0); -} -#endif /* SIGWINCH */ - -void -set_sigwinch_handler () -{ -#if defined (SIGWINCH) - old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler); -#endif -} - -void -unset_sigwinch_handler () -{ -#if defined (SIGWINCH) - set_signal_handler (SIGWINCH, old_winch); -#endif -} - -/* Signal functions used by the rest of the code. */ -#if !defined (HAVE_POSIX_SIGNALS) - -#if defined (JOB_CONTROL) -/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */ -sigprocmask (operation, newset, oldset) - int operation, *newset, *oldset; -{ - int old, new; - - if (newset) - new = *newset; - else - new = 0; - - switch (operation) - { - case SIG_BLOCK: - old = sigblock (new); - break; - - case SIG_SETMASK: - sigsetmask (new); - break; - - default: - internal_error (_("sigprocmask: %d: invalid operation"), operation); - } - - if (oldset) - *oldset = old; -} -#endif /* JOB_CONTROL */ - -#else - -#if !defined (SA_INTERRUPT) -# define SA_INTERRUPT 0 -#endif - -#if !defined (SA_RESTART) -# define SA_RESTART 0 -#endif - -SigHandler * -set_signal_handler (sig, handler) - int sig; - SigHandler *handler; -{ - struct sigaction act, oact; - - act.sa_handler = handler; - act.sa_flags = 0; -#if 0 - if (sig == SIGALRM) - act.sa_flags |= SA_INTERRUPT; /* XXX */ - else - act.sa_flags |= SA_RESTART; /* XXX */ -#endif - sigemptyset (&act.sa_mask); - sigemptyset (&oact.sa_mask); - sigaction (sig, &act, &oact); - return (oact.sa_handler); -} -#endif /* HAVE_POSIX_SIGNALS */ diff --git a/sig.h~ b/sig.h~ deleted file mode 100644 index a23f94c59..000000000 --- a/sig.h~ +++ /dev/null @@ -1,136 +0,0 @@ -/* sig.h -- header file for signal handler definitions. */ - -/* Copyright (C) 1994-2006 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - Bash is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License along - with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ - -/* Make sure that this is included *after* config.h! */ - -#if !defined (_SIG_H_) -# define _SIG_H_ - -#include "stdc.h" - -#if !defined (SIGABRT) && defined (SIGIOT) -# define SIGABRT SIGIOT -#endif - -#define sighandler RETSIGTYPE -typedef RETSIGTYPE SigHandler __P((int)); - -#if defined (VOID_SIGHANDLER) -# define SIGRETURN(n) return -#else -# define SIGRETURN(n) return(n) -#endif /* !VOID_SIGHANDLER */ - -/* Here is a definition for set_signal_handler () which simply expands to - a call to signal () for non-Posix systems. The code for set_signal_handler - in the Posix case resides in general.c. */ -#if !defined (HAVE_POSIX_SIGNALS) -# define set_signal_handler(sig, handler) (SigHandler *)signal (sig, handler) -#else -extern SigHandler *set_signal_handler __P((int, SigHandler *)); /* in sig.c */ -#endif /* _POSIX_VERSION */ - -/* Definitions used by the job control code. */ -#if defined (JOB_CONTROL) - -#if !defined (SIGCHLD) && defined (SIGCLD) -# define SIGCHLD SIGCLD -#endif - -#if !defined (HAVE_POSIX_SIGNALS) && !defined (sigmask) -# define sigmask(x) (1 << ((x)-1)) -#endif /* !HAVE_POSIX_SIGNALS && !sigmask */ - -#if !defined (HAVE_POSIX_SIGNALS) -# if !defined (SIG_BLOCK) -# define SIG_BLOCK 2 -# define SIG_SETMASK 3 -# endif /* SIG_BLOCK */ - -/* sigset_t defined in config.h */ - -/* Make sure there is nothing inside the signal set. */ -# define sigemptyset(set) (*(set) = 0) - -/* Initialize the signal set to hold all signals. */ -# define sigfillset(set) (*set) = sigmask (NSIG) - 1 - -/* Add SIG to the contents of SET. */ -# define sigaddset(set, sig) *(set) |= sigmask (sig) - -/* Delete SIG from signal set SET. */ -# define sigdelset(set, sig) *(set) &= ~sigmask (sig) - -/* Is SIG a member of the signal set SET? */ -# define sigismember(set, sig) ((*(set) & sigmask (sig)) != 0) - -/* Suspend the process until the reception of one of the signals - not present in SET. */ -# define sigsuspend(set) sigpause (*(set)) -#endif /* !HAVE_POSIX_SIGNALS */ - -/* These definitions are used both in POSIX and non-POSIX implementations. */ - -#define BLOCK_SIGNAL(sig, nvar, ovar) \ -do { \ - sigemptyset (&nvar); \ - sigaddset (&nvar, sig); \ - sigemptyset (&ovar); \ - sigprocmask (SIG_BLOCK, &nvar, &ovar); \ -} while (0) - -#if defined (HAVE_POSIX_SIGNALS) -# define BLOCK_CHILD(nvar, ovar) \ - BLOCK_SIGNAL (SIGCHLD, nvar, ovar) -# define UNBLOCK_CHILD(ovar) \ - sigprocmask (SIG_SETMASK, &ovar, (sigset_t *) NULL) -#else /* !HAVE_POSIX_SIGNALS */ -# define BLOCK_CHILD(nvar, ovar) ovar = sigblock (sigmask (SIGCHLD)) -# define UNBLOCK_CHILD(ovar) sigsetmask (ovar) -#endif /* !HAVE_POSIX_SIGNALS */ - -#endif /* JOB_CONTROL */ - -/* Extern variables */ -extern volatile int sigwinch_received; - -extern int interrupt_immediately; -extern int terminate_immediately; - -/* Functions from sig.c. */ -extern sighandler termsig_sighandler __P((int)); -extern void termsig_handler __P((int)); -extern sighandler sigint_sighandler __P((int)); -extern void initialize_signals __P((int)); -extern void initialize_terminating_signals __P((void)); -extern void reset_terminating_signals __P((void)); -extern void throw_to_top_level __P((void)); -extern void jump_to_top_level __P((int)) __attribute__((__noreturn__)); - -extern sighandler sigwinch_sighandler __P((int)); -extern void set_sigwinch_handler __P((void)); -extern void unset_sigwinch_handler __P((void)); - -/* Functions defined in trap.c. */ -extern SigHandler *set_sigint_handler __P((void)); -extern SigHandler *trap_to_sighandler __P((int)); -extern sighandler trap_handler __P((int)); - -#endif /* _SIG_H_ */ diff --git a/siglist.c~ b/siglist.c~ deleted file mode 100644 index 127facf6a..000000000 --- a/siglist.c~ +++ /dev/null @@ -1,228 +0,0 @@ -/* siglist.c -- signal list for those machines that don't have one. */ - -/* Copyright (C) 1989 Free Software Foundation, Inc. - -This file is part of GNU Bash, the Bourne Again SHell. - -Bash is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 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 (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL) - -#include -#include "bashtypes.h" -#include - -#include "siglist.h" - -#if !defined (NSIG) -# include "trap.h" -#endif - -#include "xmalloc.h" - -char *sys_siglist[NSIG]; - -void -initialize_siglist () -{ - register int i; - - for (i = 0; i < NSIG; i++) - sys_siglist[i] = (char *)0x0; - - sys_siglist[0] = "Bogus signal"; - -#if defined (SIGHUP) - sys_siglist[SIGHUP] = "Hangup"; -#endif - -#if defined (SIGINT) - sys_siglist[SIGINT] = "Interrupt"; -#endif - -#if defined (SIGQUIT) - sys_siglist[SIGQUIT] = "Quit"; -#endif - -#if defined (SIGILL) - sys_siglist[SIGILL] = "Illegal instruction"; -#endif - -#if defined (SIGTRAP) - sys_siglist[SIGTRAP] = "BPT trace/trap"; -#endif - -#if defined (SIGIOT) && !defined (SIGABRT) -#define SIGABRT SIGIOT -#endif - -#if defined (SIGABRT) - sys_siglist[SIGABRT] = "ABORT instruction"; -#endif - -#if defined (SIGEMT) - sys_siglist[SIGEMT] = "EMT instruction"; -#endif - -#if defined (SIGFPE) - sys_siglist[SIGFPE] = "Floating point exception"; -#endif - -#if defined (SIGKILL) - sys_siglist[SIGKILL] = "Killed"; -#endif - -#if defined (SIGBUS) - sys_siglist[SIGBUS] = "Bus error"; -#endif - -#if defined (SIGSEGV) - sys_siglist[SIGSEGV] = "Segmentation fault"; -#endif - -#if defined (SIGSYS) - sys_siglist[SIGSYS] = "Bad system call"; -#endif - -#if defined (SIGPIPE) - sys_siglist[SIGPIPE] = "Broken pipe"; -#endif - -#if defined (SIGALRM) - sys_siglist[SIGALRM] = "Alarm clock"; -#endif - -#if defined (SIGTERM) - sys_siglist[SIGTERM] = "Terminated"; -#endif - -#if defined (SIGURG) - sys_siglist[SIGURG] = "Urgent IO condition"; -#endif - -#if defined (SIGSTOP) - sys_siglist[SIGSTOP] = "Stopped (signal)"; -#endif - -#if defined (SIGTSTP) - sys_siglist[SIGTSTP] = "Stopped"; -#endif - -#if defined (SIGCONT) - sys_siglist[SIGCONT] = "Continue"; -#endif - -#if !defined (SIGCHLD) && defined (SIGCLD) -#define SIGCHLD SIGCLD -#endif - -#if defined (SIGCHLD) - sys_siglist[SIGCHLD] = "Child death or stop"; -#endif - -#if defined (SIGTTIN) - sys_siglist[SIGTTIN] = "Stopped (tty input)"; -#endif - -#if defined (SIGTTOU) - sys_siglist[SIGTTOU] = "Stopped (tty output)"; -#endif - -#if defined (SIGIO) - sys_siglist[SIGIO] = "I/O ready"; -#endif - -#if defined (SIGXCPU) - sys_siglist[SIGXCPU] = "CPU limit"; -#endif - -#if defined (SIGXFSZ) - sys_siglist[SIGXFSZ] = "File limit"; -#endif - -#if defined (SIGVTALRM) - sys_siglist[SIGVTALRM] = "Alarm (virtual)"; -#endif - -#if defined (SIGPROF) - sys_siglist[SIGPROF] = "Alarm (profile)"; -#endif - -#if defined (SIGWINCH) - sys_siglist[SIGWINCH] = "Window changed"; -#endif - -#if defined (SIGLOST) - sys_siglist[SIGLOST] = "Record lock"; -#endif - -#if defined (SIGUSR1) - sys_siglist[SIGUSR1] = "User signal 1"; -#endif - -#if defined (SIGUSR2) - sys_siglist[SIGUSR2] = "User signal 2"; -#endif - -#if defined (SIGMSG) - sys_siglist[SIGMSG] = "HFT input data pending"; -#endif - -#if defined (SIGPWR) - sys_siglist[SIGPWR] = "power failure imminent"; -#endif - -#if defined (SIGDANGER) - sys_siglist[SIGDANGER] = "system crash imminent"; -#endif - -#if defined (SIGMIGRATE) - sys_siglist[SIGMIGRATE] = "migrate process to another CPU"; -#endif - -#if defined (SIGPRE) - sys_siglist[SIGPRE] = "programming error"; -#endif - -#if defined (SIGGRANT) - sys_siglist[SIGGRANT] = "HFT monitor mode granted"; -#endif - -#if defined (SIGRETRACT) - sys_siglist[SIGRETRACT] = "HFT monitor mode retracted"; -#endif - -#if defined (SIGSOUND) - sys_siglist[SIGSOUND] = "HFT sound sequence has completed"; -#endif - -#if defined (SIGINFO) - sys_siglist[SIGINFO] = "Information request"; -#endif - - for (i = 0; i < NSIG; i++) - { - if (!sys_siglist[i]) - { - sys_siglist[i] = - (char *)xmalloc (10 + strlen ("Unknown Signal #")); - - sprintf (sys_siglist[i], "Unknown Signal #%d", i); - } - } -} -#endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */ diff --git a/stringlib.c~ b/stringlib.c~ deleted file mode 100644 index 626ddbe25..000000000 --- a/stringlib.c~ +++ /dev/null @@ -1,289 +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 0 - if (replen) - RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2)); -#else - RESIZE_MALLOCED_BUFFER (temp, templen, replen ? replen : 1, tempsize, replen ? (replen * 2) : 16); -#endif - - 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++]; - } - } - if (temp) - 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.orig b/subst.c.orig deleted file mode 100644 index 1110021c0..000000000 --- a/subst.c.orig +++ /dev/null @@ -1,8207 +0,0 @@ -/* subst.c -- The part of the shell that does parameter, command, arithmetic, - 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-2007 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 () */ -#define EX_REQMATCH 0x04 /* closing/matching delimiter required */ -#define EX_COMMAND 0x08 /* extracting a shell script/command */ - -/* 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]; - -#if defined (HANDLE_MULTIBYTE) -unsigned char ifs_firstc[MB_LEN_MAX]; -size_t ifs_firstc_len; -#else -unsigned char ifs_firstc; -#endif - -/* 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; -extern int tempenv_assign_error; - -#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE) -extern wchar_t *wcsdup __P((const wchar_t *)); -#endif - -/* 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 WORD_DESC expand_wdesc_error, expand_wdesc_fatal; -static char expand_param_error, expand_param_fatal; -static char extract_string_error, extract_string_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 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 *)); - -#if defined (ARRAY_VARS) -static SHELL_VAR *do_compound_assignment __P((char *, char *, int)); -#endif -static int do_assignment_internal __P((const WORD_DESC *, int)); - -static char *string_extract_verbatim __P((char *, size_t, int *, char *, int)); -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((const 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 *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, 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 int chk_arithsub __P((const char *, int)); - -static WORD_DESC *parameter_brace_expand_word __P((char *, int, int)); -static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *)); -static WORD_DESC *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 WORD_DESC *parameter_brace_expand __P((char *, int *, int, int *, int *)); -static WORD_DESC *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. If (flags & EX_REQMATCH) is non-zero, the string must - contain a closing character from CHARLIST. */ -static char * -string_extract (string, sindex, charlist, flags) - char *string; - int *sindex; - char *charlist; - int flags; -{ - register int c, i; - int found; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; - i = *sindex; - found = 0; - 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)) - { - found = 1; - break; - } - - ADVANCE_CHAR (string, slen, i); - } - - /* If we had to have a matching delimiter and didn't find one, return an - error and let the caller deal with it. */ - if ((flags & EX_REQMATCH) && found == 0) - { - *sindex = i; - return (&extract_string_error); - } - - 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, "$(", "(", ")", EX_COMMAND); /*)*/ - 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|EX_COMMAND); /* ) */ - 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; - - /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; - 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) - const 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, slen, sindex, charlist, flags) - char *string; - size_t slen; - int *sindex; - char *charlist; - int flags; -{ - register int i = *sindex; -#if defined (HANDLE_MULTIBYTE) - size_t clen; - wchar_t *wcharlist; -#endif - int c; - char *temp; - DECLARE_MBSTATE; - - if (charlist[0] == '\'' && charlist[1] == '\0') - { - temp = string_extract_single_quoted (string, sindex); - --*sindex; /* leave *sindex at separator character */ - return temp; - } - - i = *sindex; -#if 0 - /* See how the MBLEN and ADVANCE_CHAR macros work to understand why we need - this only if MB_CUR_MAX > 1. */ - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 1; -#endif -#if defined (HANDLE_MULTIBYTE) - clen = strlen (charlist); - wcharlist = 0; -#endif - while (c = string[i]) - { -#if defined (HANDLE_MULTIBYTE) - size_t mblength; -#endif - if (c == CTLESC) - { - i += 2; - continue; - } - -#if defined (HANDLE_MULTIBYTE) - mblength = MBLEN (string + i, slen - i); - if (mblength > 1) - { - wchar_t wc; - mblength = mbtowc (&wc, string + i, slen - i); - if (MB_INVALIDCH (mblength)) - { - if (MEMBER (c, charlist)) - break; - } - else - { - if (wcharlist == 0) - { - size_t len; - len = mbstowcs (wcharlist, charlist, 0); - if (len == -1) - len = 0; - wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1)); - mbstowcs (wcharlist, charlist, len + 1); - } - - if (wcschr (wcharlist, wc)) - break; - } - } - else -#endif - if (MEMBER (c, charlist)) - break; - - ADVANCE_CHAR (string, slen, i); - } - -#if defined (HANDLE_MULTIBYTE) - FREE (wcharlist); -#endif - - 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, "$(", "(", ")", EX_COMMAND)); /*)*/ -} - -/* 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) -/* This can be fooled by unquoted right parens in the passed string. If - each caller verifies that the last character in STRING is a right paren, - we don't even need to call extract_delimited_string. */ -char * -extract_array_assignment_list (string, sindex) - char *string; - int *sindex; -{ - int slen; - char *ret; - - slen = strlen (string); /* ( */ - if (string[slen - 1] == ')') - { - ret = substring (string, *sindex, slen - 1); - *sindex = slen - 1; - return ret; - } - return 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, in_comment; - 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 = in_comment = 0; - - nesting_level = 1; - i = *sindex; - - while (nesting_level) - { - c = string[i]; - - if (c == 0) - break; - - if (in_comment) - { - if (c == '\n') - in_comment = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - if (pass_character) /* previous char was backslash */ - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - /* Not exactly right yet; should handle shell metacharacters and - multibyte characters, too. */ - if ((flags & EX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || whitespace (string[i - 1]))) - { - in_comment = 1; - 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|EX_COMMAND); /*)*/ - 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|EX_COMMAND); /* ) */ - 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) - { - size_t slength; -#if defined (HANDLE_MULTIBYTE) - size_t mblength = 1; -#endif - DECLARE_MBSTATE; - - slength = strlen (delims); - d2 = (char *)xmalloc (slength + 1); - i = ts = 0; - while (delims[i]) - { -#if defined (HANDLE_MULTIBYTE) - mbstate_t state_bak; - state_bak = state; - mblength = MBRLEN (delims + i, slength, &state); - if (MB_INVALIDCH (mblength)) - state = state_bak; - else if (mblength > 1) - { - memcpy (d2 + ts, delims + i, mblength); - ts += mblength; - i += mblength; - slength -= mblength; - continue; - } -#endif - if (whitespace (delims[i]) == 0) - d2[ts++] = delims[i]; - - i++; - slength--; - } - 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 *ret; -#if defined (HANDLE_MULTIBYTE) -# if defined (__GNUC__) - char sep[MB_CUR_MAX + 1]; -# else - char *sep = 0; -# endif -#else - char sep[2]; -#endif - -#if defined (HANDLE_MULTIBYTE) -# if !defined (__GNUC__) - sep = (char *)xmalloc (MB_CUR_MAX + 1); -# endif /* !__GNUC__ */ - if (ifs_firstc_len == 1) - { - sep[0] = ifs_firstc[0]; - sep[1] = '\0'; - } - else - { - memcpy (sep, ifs_firstc, ifs_firstc_len); - sep[ifs_firstc_len] = '\0'; - } -#else - sep[0] = ifs_firstc; - sep[1] = '\0'; -#endif - - ret = string_list_internal (list, sep); -#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) - free (sep); -#endif - return ret; -} - -/* 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, *ret; -#if defined (HANDLE_MULTIBYTE) -# if defined (__GNUC__) - char sep[MB_CUR_MAX + 1]; -# else - char *sep = 0; -# endif /* !__GNUC__ */ -#else - char sep[2]; -#endif - WORD_LIST *tlist; - - /* XXX this could just be ifs = ifs_value; */ - ifs = ifs_var ? value_cell (ifs_var) : (char *)0; - -#if defined (HANDLE_MULTIBYTE) -# if !defined (__GNUC__) - sep = (char *)xmalloc (MB_CUR_MAX + 1); -# endif /* !__GNUC__ */ - if (ifs && *ifs) - { - if (ifs_firstc_len == 1) - { - sep[0] = ifs_firstc[0]; - sep[1] = '\0'; - } - else - { - memcpy (sep, ifs_firstc, ifs_firstc_len); - sep[ifs_firstc_len] = '\0'; - } - } - else - { - sep[0] = ' '; - sep[1] = '\0'; - } -#else - sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs; - sep[1] = '\0'; -#endif - - /* XXX -- why call quote_list if ifs == 0? we can get away without doing - it now that quote_escapes quotes spaces */ -#if 0 - tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0)) -#else - tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) -#endif - ? quote_list (list) - : list_quote_escapes (list); - - ret = string_list_internal (tlist, sep); -#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) - free (sep); -#endif - return ret; -} - -/* 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; - size_t slen; - - if (!string || !*string) - return ((WORD_LIST *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - - slen = 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. */ - slen = (MB_CUR_MAX > 1) ? strlen (string) : 1; - for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) - { - /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim - unless multibyte chars are possible. */ - current_word = string_extract_verbatim (string, slen, &sindex, separators, 0); - 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 = alloc_word_desc (); - t->word = make_quoted_char ('\0'); - t->flags |= W_QUOTED|W_HASQUOTEDNULL; - 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); - result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */ - 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 = alloc_word_desc (); - t->word = make_quoted_char ('\0'); - t->flags |= W_QUOTED|W_HASQUOTEDNULL; - 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]) - { - DECLARE_MBSTATE; - ADVANCE_CHAR (string, slen, 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++; - /* An IFS character that is not IFS white space, along with any - adjacent IFS white space, shall delimit a field. (SUSv3) */ - while (string[sindex] && spctabnl (string[sindex]) && isifs (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; - size_t slen; - - if (!stringp || !*stringp || !**stringp) - return ((char *)NULL); - - s = *stringp; - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - - slen = 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; - /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim - unless multibyte chars are possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (s) : 1; - current_word = string_extract_verbatim (s, slen, &sindex, separators, 0); - - /* 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]) - { - DECLARE_MBSTATE; - ADVANCE_CHAR (s, slen, 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++; - /* An IFS character that is not IFS white space, along with any adjacent - IFS white space, shall delimit a field. */ - while (s[sindex] && spctabnl (s[sindex]) && isifs (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 */ -/* */ -/********************************************************/ - -#if defined (ARRAY_VARS) -static SHELL_VAR * -do_compound_assignment (name, value, flags) - char *name, *value; - int flags; -{ - SHELL_VAR *v; - int mklocal; - WORD_LIST *list; - - mklocal = flags & ASS_MKLOCAL; - - if (mklocal && variable_context) - { - list = expand_compound_array_assignment (value, flags); - v = find_variable (name); - if (v == 0 || array_p (v) == 0 || v->context != variable_context) - v = make_local_array_variable (name); - assign_compound_array_list (v, list, flags); - } - else - v = assign_array_from_string (name, value, flags); - - return (v); -} -#endif - -/* 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 (word, expand) - const WORD_DESC *word; - int expand; -{ - int offset, tlen, appendop, assign_list, aflags; - char *name, *value; - SHELL_VAR *entry; -#if defined (ARRAY_VARS) - char *t; - int ni; -#endif - const char *string; - - if (word == 0 || word->word == 0) - return 0; - - appendop = assign_list = aflags = 0; - string = word->word; - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - char *temp; - - if (name[offset - 1] == '+') - { - appendop = 1; - name[offset - 1] = '\0'; - } - - name[offset] = 0; /* might need this set later */ - temp = name + offset + 1; - tlen = STRLEN (temp); - -#if defined (ARRAY_VARS) - if (expand && (word->flags & W_COMPASSIGN)) - { - assign_list = ni = 1; - value = extract_array_assignment_list (temp, &ni); - } - else -#endif - - if (expand && temp[0]) - value = expand_string_if_necessary (temp, 0, expand_string_assignment); - else - value = savestring (temp); - } - - if (value == 0) - { - value = (char *)xmalloc (1); - value[0] = '\0'; - } - - if (echo_command_at_execute) - { - if (appendop) - name[offset - 1] = '+'; - xtrace_print_assignment (name, value, assign_list, 1); - if (appendop) - name[offset - 1] = '\0'; - } - -#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) - - if (appendop) - aflags |= ASS_APPEND; - -#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, aflags); - if (entry == 0) - ASSIGN_RETURN (0); - } - else if (assign_list) - { - if (word->flags & W_ASSIGNARG) - aflags |= ASS_MKLOCAL; - entry = do_compound_assignment (name, value, aflags); - } - else -#endif /* ARRAY_VARS */ - entry = bind_variable (name, value, aflags); - - 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 tilde, command and parameter expansion. */ -int -do_assignment (string) - char *string; -{ - WORD_DESC td; - - td.flags = W_ASSIGNMENT; - td.word = string; - - return do_assignment_internal (&td, 1); -} - -int -do_word_assignment (word) - WORD_DESC *word; -{ - return do_assignment_internal (word, 1); -} - -/* Given STRING, an assignment string, get the value of the right side - of the `=', and bind it to the left side. Do not perform any word - expansions on the right hand side. */ -int -do_assignment_no_expand (string) - char *string; -{ - WORD_DESC td; - - td.flags = W_ASSIGNMENT; - td.word = string; - - return (do_assignment_internal (&td, 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); - - if (start == 0) /* handle ${@:0[:x]} specially */ - { - t = make_word_list (make_word (dollar_vars[0]), params); - save = params = t; - } - - 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 (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); - } - 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 || s == '~') -#else -#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~') -#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; - - /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (string) : 0; - 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)); -} - -char * -expand_assignment_string_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string_assignment)); -} - -char * -expand_arith_string (string, quoted) - char *string; -{ - return (expand_string_if_necessary (string, quoted, expand_string)); -} - -#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 1, 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. If - SPECIAL is 2, this is an rhs argument for the =~ operator, and should - be quoted appropriately for regcomp/regexec. The caller is responsible - for removing the backslashes if the unquoted word is needed later. */ -char * -cond_expand_word (w, special) - WORD_DESC *w; - int special; -{ - char *r, *p; - WORD_LIST *l; - int qflags; - - if (w->word == 0 || w->word[0] == '\0') - return ((char *)NULL); - - 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 - { - qflags = QGLOB_CVTNULL; - if (special == 2) - qflags |= QGLOB_REGEXP; - p = string_list (l); - r = quote_string_for_globbing (p, qflags); - 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); - value->word->flags &= ~W_HASQUOTEDNULL; - } - dequote_list (value); - } - return (value); -} - -/* Expand the rhs of an assignment statement */ -WORD_LIST * -expand_string_assignment (string, quoted) - char *string; - int quoted; -{ - WORD_DESC td; - WORD_LIST *value; - - if (string == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - expand_no_split_dollar_star = 1; - - td.flags = W_ASSIGNRHS; - td.word = savestring (string); - value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - FREE (td.word); - - expand_no_split_dollar_star = 0; - - if (value) - { - if (value->word) - { - remove_quoted_nulls (value->word->word); - value->word->flags &= ~W_HASQUOTEDNULL; - } - 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); - value->word->flags &= ~W_HASQUOTEDNULL; - } - 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 (word splitting - and filename generation). If IFS is null, we quote spaces as well, just - in case we split on spaces later (in the case of unquoted $@, we will - eventually attempt to split the entire word on spaces). Corresponding - code exists in dequote_escapes. Even if we don't end up splitting on - spaces, quoting spaces is not a problem. This should never be called on - a string that is quoted with single or double quotes or part of a here - document (effectively double-quoted). */ -char * -quote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - int quote_spaces; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - quote_spaces = (ifs_value && *ifs_value == 0); - - t = result = (char *)xmalloc ((slen * 2) + 1); - s = string; - - while (*s) - { - if (*s == CTLESC || *s == CTLNUL || (quote_spaces && *s == ' ')) - *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, *s1; - size_t slen; - char *result, *send; - int quote_spaces; - DECLARE_MBSTATE; - - if (string == 0) - return string; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc (slen + 1); - - if (strchr (string, CTLESC) == 0) - return (strcpy (result, string)); - - quote_spaces = (ifs_value && *ifs_value == 0); - - s = string; - while (*s) - { - if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' '))) - { - 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. - This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be - set in any resultant WORD_DESC where this value is the word. */ -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, returning a new string. This turns "" into QUOTED_NULL, so - the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where - this value is the word. */ -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-quote 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; - /* XXX - turn on W_HAVEQUOTEDNULL here? */ - } - return list; -} - -/* De-quote quoted characters in each word in LIST. */ -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; - /* XXX - turn off W_HAVEQUOTEDNULL here? */ - } - 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); - t->word->flags &= ~W_HASQUOTEDNULL; - } -} - -/* **************************************************************** */ -/* */ -/* 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 * -remove_wpattern (wparam, wstrlen, wpattern, op) - wchar_t *wparam; - size_t wstrlen; - wchar_t *wpattern; - int op; -{ - wchar_t wc, *ret; - int n; - - 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 = (char *)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, *npat; - char *end; - - /* If the pattern doesn't match anywhere in the string, go ahead and - short-circuit right away. A minor optimization, saves a bunch of - unnecessary calls to strmatch (up to N calls for a string of N - characters) if the match is unsuccessful. To preserve the semantics - of the substring matches below, we make sure that the pattern has - `*' as first and last character, making a new pattern if necessary. */ - /* XXX - check this later if I ever implement `**' with special meaning, - since this will potentially result in `**' at the beginning or end */ - len = STRLEN (pat); - if (pat[0] != '*' || pat[len - 1] != '*') - { - p = npat = (char *)xmalloc (len + 3); - p1 = pat; - if (*p1 != '*') - *p++ = '*'; - while (*p1) - *p++ = *p1++; - if (p1[-1] != '*' || p[-2] == '\\') - *p++ = '*'; - *p = '\0'; - } - else - npat = pat; - c = strmatch (npat, string, FNMATCH_EXTFLAG); - if (npat != pat) - free (npat); - if (c == FNM_NOMATCH) - return (0); - - 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, *wp, *nwpat, *wp1; - int len; -#if 0 - size_t n, n1; /* Apple's gcc seems to miscompile this badly */ -#else - int n, n1; -#endif - - /* If the pattern doesn't match anywhere in the string, go ahead and - short-circuit right away. A minor optimization, saves a bunch of - unnecessary calls to strmatch (up to N calls for a string of N - characters) if the match is unsuccessful. To preserve the semantics - of the substring matches below, we make sure that the pattern has - `*' as first and last character, making a new pattern if necessary. */ - /* XXX - check this later if I ever implement `**' with special meaning, - since this will potentially result in `**' at the beginning or end */ - len = wcslen (wpat); - if (wpat[0] != L'*' || wpat[len - 1] != L'*') - { - wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t)); - wp1 = wpat; - if (*wp1 != L'*') - *wp++ = L'*'; - while (*wp1 != L'\0') - *wp++ = *wp1++; - if (wp1[-1] != L'*' || wp1[-2] == L'\\') - *wp++ = L'*'; - *wp = '\0'; - } - else - nwpat = wpat; - len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG); - if (nwpat != wpat) - free (nwpat); - if (len == FNM_NOMATCH) - return (0); - - 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; -#if 0 - int i; -#endif - - /* 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 = *value ? expand_string_for_rhs (value, - (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, - (int *)NULL, (int *)NULL) - : (WORD_LIST *)0; - 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 = alloc_word_desc (); - w->word = tword ? tword : savestring (""); - new = make_word_list (w, new); - } - - l = REVERSE_LIST (new, WORD_LIST *); - if (itype == '*') - tword = (quoted & 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 = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - ? quote_string (temp1) - : 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; -} - -int -fifos_pending () -{ - return nfifo; -} - -static char * -make_named_pipe () -{ - char *tname; - - tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR); - 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++; -} - -int -fifos_pending () -{ - return 0; /* used for cleanup; not needed with /dev/fd */ -} - -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|SUBSHELL_PROCSUB; - } - -#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 (_("cannot 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, rflag) - int fd, quoted; - int *rflag; -{ - char *istring, buf[128], *bufp; - int istring_index, istring_size, c, tflag; - ssize_t bufn; - - istring = (char *)NULL; - istring_index = istring_size = bufn = tflag = 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. This may need to be - changed to understand multibyte characters in the future. */ - 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); - - /* This is essentially quote_string inline */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */) - istring[istring_index++] = CTLESC; - /* Escape CTLESC and CTLNUL in the output to protect those characters - from the rest of the word expansions (word splitting and globbing.) - This is essentially quote_escapes inline. */ - else if (c == CTLESC) - { - tflag |= W_HASCTLESC; - istring[istring_index++] = CTLESC; - } - else if (c == CTLNUL || (c == ' ' && (ifs_value && *ifs_value == 0))) - 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); - if (rflag) - *rflag = tflag; - 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); - - if (rflag) - *rflag = tflag; - return istring; -} - -/* Perform command substitution on STRING. This returns a WORD_DESC * with the - contained string possibly quoted. */ -WORD_DESC * -command_substitute (string, quoted) - char *string; - int quoted; -{ - pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid; - char *istring; - int result, fildes[2], function_value, pflags, rc, tflag; - WORD_DESC *ret; - - 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 ((WORD_DESC *)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 /* JOB_CONTROL */ - - old_async_pid = last_asynchronous_pid; - pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC); - last_asynchronous_pid = old_async_pid; - - 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 ((WORD_DESC *)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 (); -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif - exit (rc); - } - else - { -#if defined (JOB_CONTROL) && defined (PGRP_PIPE) - close_pgrp_pipe (); -#endif /* JOB_CONTROL && PGRP_PIPE */ - - close (fildes[1]); - - tflag = 0; - istring = read_comsub (fildes[0], quoted, &tflag); - - 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 */ - - ret = alloc_word_desc (); - ret->word = istring; - ret->flags = tflag; - - return ret; - } -} - -/******************************************************** - * * - * 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 WORD_DESC * -parameter_brace_expand_word (name, var_is_special, quoted) - char *name; - int var_is_special, quoted; -{ - WORD_DESC *ret; - char *temp, *tt; - intmax_t arg_index; - SHELL_VAR *var; - int atype; - - ret = 0; - temp = 0; - - /* 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); - - ret = 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; - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->word = temp; - } - return ret; -} - -/* Expand an indirect reference to a variable: ${!NAME} expands to the - value of the variable whose name is the value of NAME. */ -static WORD_DESC * -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; - WORD_DESC *w; - - w = parameter_brace_expand_word (name, var_is_special, quoted); - t = w->word; - /* 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; - } - dispose_word_desc (w); - - chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at); - if (t == 0) - return (WORD_DESC *)NULL; - - w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted); - free (t); - - return w; -} - -/* 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 WORD_DESC * -parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) - char *name, *value; - int c, quoted, *qdollaratp, *hasdollarat; -{ - WORD_DESC *w; - WORD_LIST *l; - char *t, *t1, *temp; - int hasdol; - - /* 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 (for sh backwards compatibility). */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value) - { - hasdol = 0; - temp = string_extract_double_quoted (value, &hasdol, 1); - } - else - temp = value; - - w = alloc_word_desc (); - 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); - if (temp != value) - 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 = make_quoted_char ('\0'); - w->flags |= W_HASQUOTEDNULL; - } - else - temp = (char *)NULL; - - if (c == '-' || c == '+') - { - w->word = temp; - return w; - } - - /* 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, 0); - else -#endif /* ARRAY_VARS */ - bind_variable (name, t1, 0); - free (t1); - - w->word = temp; - return w; -} - -/* 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) - { - l = expand_string (value, 0); - temp = string_list (l); - report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ - FREE (temp); - dispose_words (l); - } - else - 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} */ -} - -#if defined (HANDLE_MULTIBYTE) -size_t -mbstrlen (s) - const char *s; -{ - size_t clen, nc; - mbstate_t mbs, mbsbak; - - nc = 0; - memset (&mbs, 0, sizeof (mbs)); - mbsbak = mbs; - while ((clen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0) - { - if (MB_INVALIDCH(clen)) - { - clen = 1; /* assume single byte */ - mbs = mbsbak; - } - - s += clen; - nc++; - mbsbak = mbs; - } - return nc; -} -#endif - - -/* 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 = MB_STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && array_p (var)) - { - t = array_reference (array_cell (var), 0); - number = MB_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 = MB_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_arith_string (substr, Q_DOUBLE_QUOTES); - *e1p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - - len = -1; /* paranoia */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - len = MB_STRLEN (value); - break; - case VT_POSPARMS: - len = number_of_args () + 1; - if (*e1p == 0) - len++; /* add one arg if counting from $0 */ - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - a = (ARRAY *)value; - /* For arrays, the first value deals with array indices. Negative - offsets count from one past the array's maximum index. */ - len = array_max_index (a) + (*e1p < 0); /* 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_arith_string (temp2, Q_DOUBLE_QUOTES); - 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 if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')) - { - vtype = VT_VARIABLE; - *varp = v; - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - *valp = dequote_string (value); - else - *valp = dequote_escapes (value); - } - else - return -1; - } - else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && array_p (v)) - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = array_reference (array_cell (v), 0); - } - else -#endif - { - 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; - } - - 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; - /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0; - - 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, *oname; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - oname = this_command_name; - this_command_name = varname; - - vtype = get_var_and_type (varname, value, quoted, &v, &val); - if (vtype == -1) - { - this_command_name = oname; - return ((char *)NULL); - } - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - r = verify_substring_values (val, substr, vtype, &e1, &e2); - this_command_name = oname; - 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). */ - temp = array_subrange (array_cell (v), e1, e2, starsub, quoted); - /* array_subrange now calls array_quote_escapes as appropriate, so the - caller no longer needs to. */ - 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; - - 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 = alloc_word_desc (); - w->word = ret ? ret : savestring (""); - dispose_word (params->word); - params->word = w; - } - - 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 && *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 the pattern starts with a `/', make sure we skip over it when looking - for the replacement delimiter. */ - if (rep = quoted_strchr ((*patsub == '/') ? lpatsub+1 : lpatsub, '/', ST_BACKSL)) - *rep++ = '\0'; - else - rep = (char *)NULL; - - if (rep && *rep == '\0') - rep = (char *)NULL; - - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. */ - pat = getpattern (lpatsub, quoted, 1); - - 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); - } - - /* ksh93 doesn't allow the match specifier to be a part of the expanded - pattern. This is an extension. Make sure we don't anchor the pattern - at the beginning or end of the string if we're doing global replacement, - though. */ - p = pat; - if (mflags & MATCH_GLOBREP) - mflags |= MATCH_ANY; - else 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 = (mflags & MATCH_QUOTED) ? quote_string (temp) : 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); - /* Don't call quote_escapes anymore; array_patsub calls - array_quote_escapes as appropriate before adding the - space separators. */ - break; -#endif - } - - FREE (pat); - FREE (rep); - free (lpatsub); - - return temp; -} - -/* Check for unbalanced parens in S, which is the contents of $(( ... )). If - any occur, this must be a nested command substitution, so return 0. - Otherwise, return 1. A valid arithmetic expression must always have a - ( before a matching ), so any cases where there are more right parens - means that this must not be an arithmetic expression, though the parser - will not accept it without a balanced total number of parens. */ -static int -chk_arithsub (s, len) - const char *s; - int len; -{ - int i, count; - DECLARE_MBSTATE; - - i = count = 0; - while (i < len) - { - if (s[i] == '(') - count++; - else if (s[i] == ')') - { - count--; - if (count < 0) - return 0; - } - - switch (s[i]) - { - default: - ADVANCE_CHAR (s, len, i); - break; - - case '\\': - i++; - if (s[i]) - ADVANCE_CHAR (s, len, i); - break; - - case '\'': - i = skip_single_quoted (s, len, ++i); - break; - - case '"': - i = skip_double_quoted ((char *)s, len, ++i); - break; - } - } - - return (count == 0); -} - -/****************************************************************/ -/* */ -/* Functions to perform parameter expansion on a string */ -/* */ -/****************************************************************/ - -/* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */ -static WORD_DESC * -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; - WORD_DESC *tdesc, *ret; - int t_index, sindex, c, tflag; - 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; - /* ${#var} doesn't have any of the other parameter expansions on it. */ - if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */ - name = string_extract (string, &t_index, "}", EX_VARNAME); - else - name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME); - - ret = 0; - tflag = 0; - - /* 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; - if (number < 0) - return (&expand_wdesc_error); - else - { - ret = alloc_word_desc (); - ret->word = itos (number); - return ret; - } - } - - /* ${@} 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; - - ret = alloc_word_desc (); - ret->word = temp; - return ret; - } - -#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; - - ret = alloc_word_desc (); - ret->word = temp; - return ret; - } - - 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) - tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at); - else - tdesc = parameter_brace_expand_word (name, var_is_special, quoted); - - if (tdesc) - { - temp = tdesc->word; - tflag = tdesc->flags; - dispose_word_desc (tdesc); - } - else - temp = (char *)0; - -#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); - - if (temp1 == &expand_param_error) - return (&expand_wdesc_error); - else if (temp1 == &expand_param_fatal) - return (&expand_wdesc_fatal); - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - return ret; - } - else if (want_patsub) - { - temp1 = parameter_brace_patsub (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - - if (temp1 == &expand_param_error) - return (&expand_wdesc_error); - else if (temp1 == &expand_param_fatal) - return (&expand_wdesc_fatal); - - ret = alloc_word_desc (); - ret->word = temp1; - return ret; - } - - /* 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_wdesc_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_wdesc_error : &expand_wdesc_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) - { - ret = parameter_brace_expand_rhs (name, value, c, - quoted, - quoted_dollar_atp, - contains_dollar_at); - /* XXX - fix up later, esp. noting presence of - W_HASQUOTEDNULL in ret->flags */ - 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_wdesc_error; - } - else if (c == '?') - { - parameter_brace_expand_error (name, value); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_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; - - ret = parameter_brace_expand_rhs (name, value, c, quoted, - quoted_dollar_atp, - contains_dollar_at); - /* XXX - fix up later, esp. noting presence of - W_HASQUOTEDNULL in tdesc->flags */ - } - free (value); - } - - break; - } - free (name); - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->flags = tflag; - ret->word = temp; - } - return (ret); -} - -/* 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 WORD_DESC * -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; - WORD_DESC *tdesc, *ret; - int tflag; - - zindex = *sindex; - c = string[++zindex]; - - temp = (char *)NULL; - ret = tdesc = (WORD_DESC *)NULL; - tflag = 0; - - /* 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_wdesc_error : &expand_wdesc_fatal); - } - if (temp1) - temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp1) - : quote_escapes (temp1); - else - temp = (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_wdesc_error : &expand_wdesc_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 = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (list) : string_list (list); - temp1 = quote_string (temp); - if (*temp == 0) - tflag |= W_HASQUOTEDNULL; - free (temp); - temp = temp1; - } - else - { - /* We check whether or not we're eventually going to split $* here, - for example when IFS is empty and we are processing the rhs of - an assignment statement. In that case, we don't separate the - arguments at all. Otherwise, if the $* is not quoted it is - identical to $@ */ -#if 1 -# if defined (HANDLE_MULTIBYTE) - if (expand_no_split_dollar_star && ifs_firstc[0] == 0) -# else - if (expand_no_split_dollar_star && ifs_firstc == 0) -# endif - temp = string_list_dollar_star (list); - else - temp = string_list_dollar_at (list, quoted); -#else - temp = string_list_dollar_at (list, quoted); -#endif - 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: - tdesc = parameter_brace_expand (string, &zindex, quoted, - quoted_dollar_at_p, - contains_dollar_at); - - if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) - return (tdesc); - temp = tdesc ? tdesc->word : (char *)0; - - /* 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 (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp)) - { - if (had_quoted_null_p) - *had_quoted_null_p = 1; - if (*quoted_dollar_at_p == 0) - { - free (temp); - tdesc->word = temp = (char *)NULL; - } - - } - - ret = tdesc; - 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'; - - if (chk_arithsub (temp2, t_index) == 0) - { - free (temp2); - goto comsub; - } - - /* Expand variables found inside the expression. */ - temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES); - 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_wdesc_fatal); - } - else - return (&expand_wdesc_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 - { - tdesc = command_substitute (temp, quoted); - temp1 = tdesc ? tdesc->word : (char *)NULL; - dispose_word_desc (tdesc); - } - 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_arith_string (temp, Q_DOUBLE_QUOTES); - - 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_wdesc_fatal - : &expand_wdesc_error); - } - - if (string[zindex]) - zindex++; - -return0: - *sindex = zindex; - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->flags = tflag; /* XXX */ - ret->word = temp; - } - return ret; -} - -/* 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; - - /* State flags */ - int had_quoted_null; - int has_dollar_at; - int tflag; - - int assignoff; /* If assignment, offset of `=' */ - - 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; - /* Don't need the string length for the SADD... and COPY_ macros unless - multibyte characters are possible. */ - string_size = (MB_CUR_MAX > 1) ? strlen (string) : 1; - - if (contains_dollar_at) - *contains_dollar_at = 0; - - assignoff = -1; - - /* 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)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)) || 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 '=': - /* 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 (word->flags & (W_ASSIGNRHS|W_NOTILDE)) - goto add_character; - /* If we're not in posix mode or forcing assignment-statement tilde - expansion, note where the `=' appears in the word and prepare to - do tilde expansion following the first `='. */ - if ((word->flags & W_ASSIGNMENT) && - (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && - assignoff == -1 && sindex > 0) - assignoff = sindex; - if (sindex == assignoff && string[sindex+1] == '~') /* XXX */ - word->flags |= W_ITILDE; -#if 0 - else if ((word->flags & W_ASSIGNMENT) && - (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && - string[sindex+1] == '~') - word->flags |= W_ITILDE; -#endif - goto add_character; - - case ':': - if (word->flags & W_NOTILDE) - goto add_character; - - if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS|W_TILDEEXP)) && - string[sindex+1] == '~') - word->flags |= W_ITILDE; - goto add_character; - - case '~': - /* If the word isn't supposed to be tilde expanded, or we're not - at the start of a word or after an unquoted : or = in an - assignment statement, we don't do tilde expansion. */ - if ((word->flags & (W_NOTILDE|W_DQUOTE)) || - (sindex > 0 && ((word->flags & W_ITILDE) == 0)) || - (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - { - word->flags &= ~W_ITILDE; - goto add_character; - } - - if (word->flags & W_ASSIGNRHS) - tflag = 2; - else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP)) - tflag = 1; - else - tflag = 0; - - temp = bash_tilde_find_word (string + sindex, tflag, &t_index); - - word->flags &= ~W_ITILDE; - - if (temp && *temp && t_index > 0) - { - temp1 = bash_tilde_expand (temp, tflag); - if (temp1 && *temp1 == '~' && STREQ (temp, temp1)) - { - FREE (temp); - FREE (temp1); - goto add_character; /* tilde expansion failed */ - } - free (temp); - temp = temp1; - sindex += t_index; - goto add_string; - } - else - { - FREE (temp); - goto add_character; - } - - case '$': - if (expanded_something) - *expanded_something = 1; - - has_dollar_at = 0; - tword = param_expand (string, &sindex, quoted, expanded_something, - &has_dollar_at, "ed_dollar_at, - &had_quoted_null, - (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0); - - if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal) - { - free (string); - free (istring); - return ((tword == &expand_wdesc_error) ? &expand_word_error - : &expand_word_fatal); - } - if (contains_dollar_at && has_dollar_at) - *contains_dollar_at = 1; - - if (tword && (tword->flags & W_HASQUOTEDNULL)) - had_quoted_null = 1; - - temp = tword->word; - dispose_word_desc (tword); - - goto add_string; - break; - - case '`': /* Backquoted command substitution. */ - { - t_index = sindex++; - - temp = string_extract (string, &sindex, "`", EX_REQMATCH); - /* The test of sindex against t_index is to allow bare instances of - ` to pass through, for backwards compatibility. */ - if (temp == &extract_string_error || temp == &extract_string_fatal) - { - if (sindex - 1 == t_index) - { - sindex = t_index; - goto add_character; - } - report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index); - free (string); - free (istring); - return ((temp == &extract_string_error) ? &expand_word_error - : &expand_word_fatal); - } - - if (expanded_something) - *expanded_something = 1; - - if (word->flags & W_NOCOMSUB) - /* sindex + 1 because string[sindex] == '`' */ - temp1 = substring (string, t_index, sindex + 1); - else - { - de_backslash (temp); - tword = command_substitute (temp, quoted); - temp1 = tword ? tword->word : (char *)NULL; - dispose_word_desc (tword); - } - 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)) || (word->flags & W_DQUOTE)) -#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 = alloc_word_desc (); - tword->word = temp; - - temp = (char *)NULL; - - has_dollar_at = 0; - /* Need to get W_HASQUOTEDNULL flag through this function. */ - 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 (list && list->word && (list->word->flags & W_HASQUOTEDNULL)) - had_quoted_null = 1; - - 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); - tflag = list->word->flags; - dispose_words (list); - - /* 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. */ - /* We use the W_HASQUOTEDNULL flag to differentiate the - cases: a quoted null character as above and when - CTLNUL is contained in the (non-null) expansion - of some variable. We use the had_quoted_null flag to - pass the value through this function to its caller. */ - if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0) - remove_quoted_nulls (temp); /* XXX */ - } - } - 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)) || (word->flags & W_DQUOTE)) -#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); - tword->flags |= W_HASQUOTEDNULL; /* XXX */ - 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); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - list = make_word_list (tword, (WORD_LIST *)NULL); - } -#else - else - list = (WORD_LIST *)NULL; -#endif - } - else if (word->flags & W_NOSPLIT) - { - tword = make_bare_word (istring); - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; /* XXX */ - if (word->flags & W_COMPASSIGN) - tword->flags |= W_COMPASSIGN; /* XXX */ - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; /* XXX */ - if (word->flags & W_NOEXPAND) - tword->flags |= W_NOEXPAND; /* XXX */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - if (had_quoted_null) - tword->flags |= W_HASQUOTEDNULL; - list = make_word_list (tword, (WORD_LIST *)NULL); - } - 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); - 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_COMPASSIGN) - tword->flags |= W_COMPASSIGN; - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; - if (word->flags & W_NOEXPAND) - tword->flags |= W_NOEXPAND; - if (had_quoted_null) - tword->flags |= W_HASQUOTEDNULL; /* XXX */ - list = make_word_list (tword, (WORD_LIST *)NULL); - } - } - - 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 = alloc_word_desc (); - w->word = t ? t : savestring (""); - 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, *e; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); -#if 0 - result = (WORD_LIST *) list_append (result, tresult); -#else - if (result == 0) - result = e = tresult; - else - { - e->next = tresult; - while (e->next) - e = e->next; - } -#endif - } - 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)) ? value_cell (v) : " \t\n"; - - /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet - handle multibyte chars in IFS */ - memset (ifs_cmap, '\0', sizeof (ifs_cmap)); - for (t = ifs_value ; t && *t; t++) - { - uc = *t; - ifs_cmap[uc] = 1; - } - -#if defined (HANDLE_MULTIBYTE) - if (ifs_value == 0) - { - ifs_firstc[0] = '\0'; - ifs_firstc_len = 1; - } - else - { - size_t ifs_len; - ifs_len = strnlen (ifs_value, MB_CUR_MAX); - ifs_firstc_len = MBLEN (ifs_value, ifs_len); - if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len)) - { - ifs_firstc[0] = ifs_value[0]; - ifs_firstc[1] = '\0'; - ifs_firstc_len = 1; - } - else - memcpy (ifs_firstc, ifs_value, ifs_firstc_len); - } -#else - ifs_firstc = ifs_value ? *ifs_value : 0; -#endif -} - -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, *e; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = word_split (t->word, ifs_value); - if (result == 0) - result = e = tresult; - else - { - e->next = tresult; - while (e->next) - e = e->next; - } - } - 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; - -#if defined (ARRAY_VARS) - /* If this is a compound array assignment to a builtin that accepts - such assignments (e.g., `declare'), take the assignment and perform - it separately, handling the semantics of declarations inside shell - functions. This avoids the double-evaluation of such arguments, - because `declare' does some evaluation of compound assignments on - its own. */ - if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) - { - int t; - - t = do_word_assignment (tlist->word); - if (t == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - - /* Now transform the word as ksh93 appears to do and go on */ - t = assignment (tlist->word->word, 0); - tlist->word->word[t] = '\0'; - tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG); - } -#endif - - 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_word_assignment (temp_list->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_wassign_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_word_assignment; - tempenv_assign_error = 0; - - for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; - tint = (*assign_func) (temp_list->word); - /* Variable assignment errors in non-interactive shells running - in Posix.2 mode cause the shell to exit. */ - if (tint == 0) - { - if (assign_func == do_word_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); - } - else - tempenv_assign_error++; - } - } - - 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 75734570e..000000000 --- a/subst.c.save1 +++ /dev/null @@ -1,8367 +0,0 @@ -/* subst.c -- The part of the shell that does parameter, command, arithmetic, - 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-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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_ASSOCVAR 4 - -#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 `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]; - -#if defined (HANDLE_MULTIBYTE) -unsigned char ifs_firstc[MB_LEN_MAX]; -size_t ifs_firstc_len; -#else -unsigned char ifs_firstc; -#endif - -int assigning_in_environment; - -/* 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; -extern int tempenv_assign_error; - -#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE) -extern wchar_t *wcsdup __P((const wchar_t *)); -#endif - -/* 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 WORD_DESC expand_wdesc_error, expand_wdesc_fatal; -static char expand_param_error, expand_param_fatal; -static char extract_string_error, extract_string_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 char *remove_quoted_nulls __P((char *)); - -static int unquoted_substring __P((char *, char *)); -static int unquoted_member __P((int, char *)); - -#if defined (ARRAY_VARS) -static SHELL_VAR *do_compound_assignment __P((char *, char *, int)); -#endif -static int do_assignment_internal __P((const WORD_DESC *, int)); - -static char *string_extract_verbatim __P((char *, size_t, int *, char *, int)); -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((const 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 *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, 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 int chk_arithsub __P((const char *, int)); - -static WORD_DESC *parameter_brace_expand_word __P((char *, int, int)); -static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *)); -static WORD_DESC *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 WORD_DESC *parameter_brace_expand __P((char *, int *, int, int *, int *)); -static WORD_DESC *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 & SX_VARNAME) - is non-zero, and array variables have been compiled into the shell, - everything between a `[' and a corresponding `]' is skipped over. - If (flags & SX_NOALLOC) is non-zero, don't return the substring, just - update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must - contain a closing character from CHARLIST. */ -static char * -string_extract (string, sindex, charlist, flags) - char *string; - int *sindex; - char *charlist; - int flags; -{ - register int c, i; - int found; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; - i = *sindex; - found = 0; - while (c = string[i]) - { - if (c == '\\') - { - if (string[i + 1]) - i++; - else - break; - } -#if defined (ARRAY_VARS) - else if ((flags & SX_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)) - { - found = 1; - break; - } - - ADVANCE_CHAR (string, slen, i); - } - - /* If we had to have a matching delimiter and didn't find one, return an - error and let the caller deal with it. */ - if ((flags & SX_REQMATCH) && found == 0) - { - *sindex = i; - return (&extract_string_error); - } - - temp = (flags & SX_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_command_subst (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_command_subst (string, &si, SX_NOALLOC); - else - ret = extract_dollar_brace_string (string, &si, 0, SX_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; - - /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; - 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) - const 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, slen, sindex, charlist, flags) - char *string; - size_t slen; - int *sindex; - char *charlist; - int flags; -{ - register int i = *sindex; -#if defined (HANDLE_MULTIBYTE) - size_t clen; - wchar_t *wcharlist; -#endif - int c; - char *temp; - DECLARE_MBSTATE; - - if (charlist[0] == '\'' && charlist[1] == '\0') - { - temp = string_extract_single_quoted (string, sindex); - --*sindex; /* leave *sindex at separator character */ - return temp; - } - - i = *sindex; -#if 0 - /* See how the MBLEN and ADVANCE_CHAR macros work to understand why we need - this only if MB_CUR_MAX > 1. */ - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 1; -#endif -#if defined (HANDLE_MULTIBYTE) - clen = strlen (charlist); - wcharlist = 0; -#endif - while (c = string[i]) - { -#if defined (HANDLE_MULTIBYTE) - size_t mblength; -#endif - if ((flags & SX_NOCTLESC) == 0 && c == CTLESC) - { - i += 2; - continue; - } - /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL - through, to protect the CTLNULs from later calls to - remove_quoted_nulls. */ - else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL) - { - i += 2; - continue; - } - -#if defined (HANDLE_MULTIBYTE) - mblength = MBLEN (string + i, slen - i); - if (mblength > 1) - { - wchar_t wc; - mblength = mbtowc (&wc, string + i, slen - i); - if (MB_INVALIDCH (mblength)) - { - if (MEMBER (c, charlist)) - break; - } - else - { - if (wcharlist == 0) - { - size_t len; - len = mbstowcs (wcharlist, charlist, 0); - if (len == -1) - len = 0; - wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1)); - mbstowcs (wcharlist, charlist, len + 1); - } - - if (wcschr (wcharlist, wc)) - break; - } - } - else -#endif - if (MEMBER (c, charlist)) - break; - - ADVANCE_CHAR (string, slen, i); - } - -#if defined (HANDLE_MULTIBYTE) - FREE (wcharlist); -#endif - - 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 ")". ) - XFLAGS is additional flags to pass to other extraction functions, */ -char * -extract_command_subst (string, sindex, xflags) - char *string; - int *sindex; - int xflags; -{ - if (string[*sindex] == '(') /*)*/ - return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/ - else - { - xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0); - return (xparse_dolparen (string, string+*sindex, sindex, xflags)); - } -} - -/* 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) -/* This can be fooled by unquoted right parens in the passed string. If - each caller verifies that the last character in STRING is a right paren, - we don't even need to call extract_delimited_string. */ -char * -extract_array_assignment_list (string, sindex) - char *string; - int *sindex; -{ - int slen; - char *ret; - - slen = strlen (string); /* ( */ - if (string[slen - 1] == ')') - { - ret = substring (string, *sindex, slen - 1); - *sindex = slen - 1; - return ret; - } - return 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, in_comment; - 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 = in_comment = 0; - - nesting_level = 1; - i = *sindex; - - while (nesting_level) - { - c = string[i]; - - if (c == 0) - break; - - if (in_comment) - { - if (c == '\n') - in_comment = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - if (pass_character) /* previous char was backslash */ - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - /* Not exactly right yet; should handle shell metacharacters and - multibyte characters, too. */ - if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1]))) - { - in_comment = 1; - 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|SX_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|SX_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|SX_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 & SX_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|SX_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_command_subst (string, &si, flags|SX_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 & SX_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 - -#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0) - -/* 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, flags) - char *string; - int start; - char *delims; - int flags; -{ - int i, pass_next, backq, si, c; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = strlen (string + start) + start; - if (flags & SD_NOJMP) - 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, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ - else - temp = extract_dollar_brace_string (string, &si, 0, SX_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); -} - -#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. */ - -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); -} - -/* 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) - { - size_t slength; -#if defined (HANDLE_MULTIBYTE) - size_t mblength = 1; -#endif - DECLARE_MBSTATE; - - slength = strlen (delims); - d2 = (char *)xmalloc (slength + 1); - i = ts = 0; - while (delims[i]) - { -#if defined (HANDLE_MULTIBYTE) - mbstate_t state_bak; - state_bak = state; - mblength = MBRLEN (delims + i, slength, &state); - if (MB_INVALIDCH (mblength)) - state = state_bak; - else if (mblength > 1) - { - memcpy (d2 + ts, delims + i, mblength); - ts += mblength; - i += mblength; - slength -= mblength; - continue; - } -#endif - if (whitespace (delims[i]) == 0) - d2[ts++] = delims[i]; - - i++; - slength--; - } - 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, SD_NOJMP); - - /* 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, " ")); -} - -/* An external interface that can be used by the rest of the shell to - obtain a string containing the first character in $IFS. Handles all - the multibyte complications. If LENP is non-null, it is set to the - length of the returned string. */ -char * -ifs_firstchar (lenp) - int *lenp; -{ - char *ret; - int len; - - ret = xmalloc (MB_LEN_MAX + 1); -#if defined (HANDLE_MULTIBYTE) - if (ifs_firstc_len == 1) - { - ret[0] = ifs_firstc[0]; - ret[1] = '\0'; - len = ret[0] ? 1 : 0; - } - else - { - memcpy (ret, ifs_firstc, ifs_firstc_len); - ret[len = ifs_firstc_len] = '\0'; - } -#else - ret[0] = ifs_firstc; - ret[1] = '\0'; - len = ret[0] ? 0 : 1; -#endif - - if (lenp) - *lenp = len; - - return ret; -} - -/* 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 *ret; -#if defined (HANDLE_MULTIBYTE) -# if defined (__GNUC__) - char sep[MB_CUR_MAX + 1]; -# else - char *sep = 0; -# endif -#else - char sep[2]; -#endif - -#if defined (HANDLE_MULTIBYTE) -# if !defined (__GNUC__) - sep = (char *)xmalloc (MB_CUR_MAX + 1); -# endif /* !__GNUC__ */ - if (ifs_firstc_len == 1) - { - sep[0] = ifs_firstc[0]; - sep[1] = '\0'; - } - else - { - memcpy (sep, ifs_firstc, ifs_firstc_len); - sep[ifs_firstc_len] = '\0'; - } -#else - sep[0] = ifs_firstc; - sep[1] = '\0'; -#endif - - ret = string_list_internal (list, sep); -#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) - free (sep); -#endif - return ret; -} - -/* 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, *ret; -#if defined (HANDLE_MULTIBYTE) -# if defined (__GNUC__) - char sep[MB_CUR_MAX + 1]; -# else - char *sep = 0; -# endif /* !__GNUC__ */ -#else - char sep[2]; -#endif - WORD_LIST *tlist; - - /* XXX this could just be ifs = ifs_value; */ - ifs = ifs_var ? value_cell (ifs_var) : (char *)0; - -#if defined (HANDLE_MULTIBYTE) -# if !defined (__GNUC__) - sep = (char *)xmalloc (MB_CUR_MAX + 1); -# endif /* !__GNUC__ */ - if (ifs && *ifs) - { - if (ifs_firstc_len == 1) - { - sep[0] = ifs_firstc[0]; - sep[1] = '\0'; - } - else - { - memcpy (sep, ifs_firstc, ifs_firstc_len); - sep[ifs_firstc_len] = '\0'; - } - } - else - { - sep[0] = ' '; - sep[1] = '\0'; - } -#else - sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs; - sep[1] = '\0'; -#endif - - /* XXX -- why call quote_list if ifs == 0? we can get away without doing - it now that quote_escapes quotes spaces */ -#if 0 - tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0)) -#else - tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) -#endif - ? quote_list (list) - : list_quote_escapes (list); - - ret = string_list_internal (tlist, sep); -#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) - free (sep); -#endif - return ret; -} - -/* Turn the positional paramters into a string, understanding quoting and - the various subtleties of using the first character of $IFS as the - separator. Calls string_list_dollar_at, string_list_dollar_star, and - string_list as appropriate. */ -char * -string_list_pos_params (pchar, list, quoted) - int pchar; - WORD_LIST *list; - int quoted; -{ - char *ret; - - if (pchar == '*') - { - if (quoted & Q_DOUBLE_QUOTES) - ret = string_list_dollar_star (quote_list (list)); - else if (quoted & Q_HERE_DOCUMENT) - ret = string_list (quote_list (list)); - else - /* Even when unquoted, string_list_dollar_star does the right thing - making sure that the first character of $IFS is used as the - separator. */ - ret = string_list_dollar_star (list); - } - else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - /* We use string_list_dollar_at, but only if the string is quoted, since - that quotes the escapes if it's not, which we don't want. We could - use string_list (the old code did), but that doesn't do the right - thing if the first character of $IFS is not a space. We use - string_list_dollar_star if the string is unquoted so we make sure that - the elements of $@ are separated by the first character of $IFS for - later splitting. */ - ret = string_list_dollar_at (list, quoted); - else - ret = string_list_dollar_star (list); - - return ret; -} - -/* 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, xflags; - size_t slen; - - if (!string || !*string) - return ((WORD_LIST *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - for (xflags = 0, s = ifs_value; s && *s; s++) - { - if (*s == CTLESC) xflags |= SX_NOCTLESC; - else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; - } - - slen = 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. */ - slen = (MB_CUR_MAX > 1) ? strlen (string) : 1; - for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) - { - /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim - unless multibyte chars are possible. */ - current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags); - 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 = alloc_word_desc (); - t->word = make_quoted_char ('\0'); - t->flags |= W_QUOTED|W_HASQUOTEDNULL; - 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); - result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */ - 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 = alloc_word_desc (); - t->word = make_quoted_char ('\0'); - t->flags |= W_QUOTED|W_HASQUOTEDNULL; - 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]) - { - DECLARE_MBSTATE; - ADVANCE_CHAR (string, slen, 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++; - /* An IFS character that is not IFS white space, along with any - adjacent IFS white space, shall delimit a field. (SUSv3) */ - while (string[sindex] && spctabnl (string[sindex]) && isifs (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, xflags; - size_t slen; - - if (!stringp || !*stringp || !**stringp) - return ((char *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - for (xflags = 0, s = ifs_value; s && *s; s++) - { - if (*s == CTLESC) xflags |= SX_NOCTLESC; - if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; - } - - s = *stringp; - slen = 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; - /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim - unless multibyte chars are possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (s) : 1; - current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags); - - /* 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]) - { - DECLARE_MBSTATE; - ADVANCE_CHAR (s, slen, 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++; - /* An IFS character that is not IFS white space, along with any adjacent - IFS white space, shall delimit a field. */ - while (s[sindex] && spctabnl (s[sindex]) && isifs (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 */ -/* */ -/********************************************************/ - -#if defined (ARRAY_VARS) -static SHELL_VAR * -do_compound_assignment (name, value, flags) - char *name, *value; - int flags; -{ - SHELL_VAR *v; - int mklocal; - WORD_LIST *list; - - mklocal = flags & ASS_MKLOCAL; - - if (mklocal && variable_context) - { - list = expand_compound_array_assignment (value, flags); - v = find_variable (name); - if (v == 0 || array_p (v) == 0 || v->context != variable_context) - v = make_local_array_variable (name); - assign_compound_array_list (v, list, flags); - } - else - v = assign_array_from_string (name, value, flags); - - return (v); -} -#endif - -/* 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 (word, expand) - const WORD_DESC *word; - int expand; -{ - int offset, tlen, appendop, assign_list, aflags, retval; - char *name, *value; - SHELL_VAR *entry; -#if defined (ARRAY_VARS) - char *t; - int ni; -#endif - const char *string; - - if (word == 0 || word->word == 0) - return 0; - - appendop = assign_list = aflags = 0; - string = word->word; - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - char *temp; - - if (name[offset - 1] == '+') - { - appendop = 1; - name[offset - 1] = '\0'; - } - - name[offset] = 0; /* might need this set later */ - temp = name + offset + 1; - tlen = STRLEN (temp); - -#if defined (ARRAY_VARS) - if (expand && (word->flags & W_COMPASSIGN)) - { - assign_list = ni = 1; - value = extract_array_assignment_list (temp, &ni); - } - else -#endif - - if (expand && temp[0]) - value = expand_string_if_necessary (temp, 0, expand_string_assignment); - else - value = savestring (temp); - } - - if (value == 0) - { - value = (char *)xmalloc (1); - value[0] = '\0'; - } - - if (echo_command_at_execute) - { - if (appendop) - name[offset - 1] = '+'; - xtrace_print_assignment (name, value, assign_list, 1); - if (appendop) - name[offset - 1] = '\0'; - } - -#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) - - if (appendop) - aflags |= ASS_APPEND; - -#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, aflags); - if (entry == 0) - ASSIGN_RETURN (0); - } - else if (assign_list) - { - if (word->flags & W_ASSIGNARG) - aflags |= ASS_MKLOCAL; - entry = do_compound_assignment (name, value, aflags); - } - else -#endif /* ARRAY_VARS */ - entry = bind_variable (name, value, aflags); - - stupidly_hack_special_variables (name); - -#if 1 - /* Return 1 if the assignment seems to have been performed correctly. */ - if (entry == 0 || readonly_p (entry)) - retval = 0; /* assignment failure */ - else if (noassign_p (entry)) - { - last_command_exit_value = EXECUTION_FAILURE; - retval = 1; /* error status, but not assignment failure */ - } - else - retval = 1; - ASSIGN_RETURN (retval); - - if (entry && retval != 0) - VUNSETATTR (entry, att_invisible); -#else - if (entry) - VUNSETATTR (entry, att_invisible); - - ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0); -#endif -} - -/* Perform the assignment statement in STRING, and expand the - right side by doing tilde, command and parameter expansion. */ -int -do_assignment (string) - char *string; -{ - WORD_DESC td; - - td.flags = W_ASSIGNMENT; - td.word = string; - - return do_assignment_internal (&td, 1); -} - -int -do_word_assignment (word) - WORD_DESC *word; -{ - return do_assignment_internal (word, 1); -} - -/* Given STRING, an assignment string, get the value of the right side - of the `=', and bind it to the left side. Do not perform any word - expansions on the right hand side. */ -int -do_assignment_no_expand (string) - char *string; -{ - WORD_DESC td; - - td.flags = W_ASSIGNMENT; - td.word = string; - - return (do_assignment_internal (&td, 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); - - if (start == 0) /* handle ${@:0[:x]} specially */ - { - t = make_word_list (make_word (dollar_vars[0]), params); - save = params = t; - } - - 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; - - ret = string_list_pos_params (string[0], h, quoted); - - 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 || s == '~') -#else -#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~') -#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; - - /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (string) : 0; - 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)); -} - -char * -expand_assignment_string_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string_assignment)); -} - -char * -expand_arith_string (string, quoted) - char *string; -{ - return (expand_string_if_necessary (string, quoted, expand_string)); -} - -#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 1, 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. If - SPECIAL is 2, this is an rhs argument for the =~ operator, and should - be quoted appropriately for regcomp/regexec. The caller is responsible - for removing the backslashes if the unquoted word is needed later. */ -char * -cond_expand_word (w, special) - WORD_DESC *w; - int special; -{ - char *r, *p; - WORD_LIST *l; - int qflags; - - if (w->word == 0 || w->word[0] == '\0') - return ((char *)NULL); - - 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 - { - qflags = QGLOB_CVTNULL; - if (special == 2) - qflags |= QGLOB_REGEXP; - p = string_list (l); - r = quote_string_for_globbing (p, qflags); - 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); - value->word->flags &= ~W_HASQUOTEDNULL; - } - dequote_list (value); - } - return (value); -} - -/* Expand the rhs of an assignment statement */ -WORD_LIST * -expand_string_assignment (string, quoted) - char *string; - int quoted; -{ - WORD_DESC td; - WORD_LIST *value; - - if (string == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - expand_no_split_dollar_star = 1; - - td.flags = W_ASSIGNRHS; - td.word = savestring (string); - value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - FREE (td.word); - - expand_no_split_dollar_star = 0; - - if (value) - { - if (value->word) - { - remove_quoted_nulls (value->word->word); - value->word->flags &= ~W_HASQUOTEDNULL; - } - 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, wflags) - char *string; - int quoted; - int wflags; -{ - WORD_LIST *value; - WORD_DESC td; - - if (string == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = wflags; - 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); - value->word->flags &= ~W_HASQUOTEDNULL; - } - 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 (word splitting - and filename generation). If IFS is null, we quote spaces as well, just - in case we split on spaces later (in the case of unquoted $@, we will - eventually attempt to split the entire word on spaces). Corresponding - code exists in dequote_escapes. Even if we don't end up splitting on - spaces, quoting spaces is not a problem. This should never be called on - a string that is quoted with single or double quotes or part of a here - document (effectively double-quoted). */ -char * -quote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - int quote_spaces, skip_ctlesc, skip_ctlnul; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - quote_spaces = (ifs_value && *ifs_value == 0); - - for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++) - skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL; - - t = result = (char *)xmalloc ((slen * 2) + 1); - s = string; - - while (*s) - { - if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' ')) - *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, *s1; - size_t slen; - char *result, *send; - int quote_spaces; - DECLARE_MBSTATE; - - if (string == 0) - return string; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc (slen + 1); - - if (strchr (string, CTLESC) == 0) - return (strcpy (result, string)); - - quote_spaces = (ifs_value && *ifs_value == 0); - - s = string; - while (*s) - { - if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' '))) - { - 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. - This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be - set in any resultant WORD_DESC where this value is the word. */ -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, returning a new string. This turns "" into QUOTED_NULL, so - the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where - this value is the word. */ -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-quote 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; - /* XXX - turn on W_HAVEQUOTEDNULL here? */ - } - return list; -} - -/* De-quote quoted characters in each word in LIST. */ -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; - /* XXX - turn off W_HAVEQUOTEDNULL here? */ - } - return list; -} - -/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed - string. */ -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); - t->word->flags &= ~W_HASQUOTEDNULL; - } -} - -/* **************************************************************** */ -/* */ -/* 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 * -remove_wpattern (wparam, wstrlen, wpattern, op) - wchar_t *wparam; - size_t wstrlen; - wchar_t *wpattern; - int op; -{ - wchar_t wc, *ret; - int n; - - 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 = (char *)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, *npat; - char *end; - - /* If the pattern doesn't match anywhere in the string, go ahead and - short-circuit right away. A minor optimization, saves a bunch of - unnecessary calls to strmatch (up to N calls for a string of N - characters) if the match is unsuccessful. To preserve the semantics - of the substring matches below, we make sure that the pattern has - `*' as first and last character, making a new pattern if necessary. */ - /* XXX - check this later if I ever implement `**' with special meaning, - since this will potentially result in `**' at the beginning or end */ - len = STRLEN (pat); - if (pat[0] != '*' || pat[len - 1] != '*') - { - p = npat = (char *)xmalloc (len + 3); - p1 = pat; - if (*p1 != '*') - *p++ = '*'; - while (*p1) - *p++ = *p1++; - if (p1[-1] != '*' || p[-2] == '\\') - *p++ = '*'; - *p = '\0'; - } - else - npat = pat; - c = strmatch (npat, string, FNMATCH_EXTFLAG); - if (npat != pat) - free (npat); - if (c == FNM_NOMATCH) - return (0); - - 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, *wp, *nwpat, *wp1; - int len; -#if 0 - size_t n, n1; /* Apple's gcc seems to miscompile this badly */ -#else - int n, n1; -#endif - - /* If the pattern doesn't match anywhere in the string, go ahead and - short-circuit right away. A minor optimization, saves a bunch of - unnecessary calls to strmatch (up to N calls for a string of N - characters) if the match is unsuccessful. To preserve the semantics - of the substring matches below, we make sure that the pattern has - `*' as first and last character, making a new pattern if necessary. */ - /* XXX - check this later if I ever implement `**' with special meaning, - since this will potentially result in `**' at the beginning or end */ - len = wcslen (wpat); - if (wpat[0] != L'*' || wpat[len - 1] != L'*') - { - wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t)); - wp1 = wpat; - if (*wp1 != L'*') - *wp++ = L'*'; - while (*wp1 != L'\0') - *wp++ = *wp1++; - if (wp1[-1] != L'*' || wp1[-2] == L'\\') - *wp++ = L'*'; - *wp = '\0'; - } - else - nwpat = wpat; - len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG); - if (nwpat != wpat) - free (nwpat); - if (len == FNM_NOMATCH) - return (0); - - 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; -#if 0 - int i; -#endif - - /* 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 = *value ? expand_string_for_rhs (value, - (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, - (int *)NULL, (int *)NULL) - : (WORD_LIST *)0; - 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 = alloc_word_desc (); - w->word = tword ? tword : savestring (""); - new = make_word_list (w, new); - } - - l = REVERSE_LIST (new, WORD_LIST *); - if (itype == '*') - tword = (quoted & 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++; - - /* Need to pass getpattern newly-allocated memory in case of expansion -- - the expansion code will free the passed string on an error. */ - temp1 = savestring (patstr); - pattern = getpattern (temp1, quoted, 1); - free (temp1); - - 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 = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - ? quote_string (temp1) - : 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; -} - -int -fifos_pending () -{ - return nfifo; -} - -static char * -make_named_pipe () -{ - char *tname; - - tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR); - 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++; -} - -int -fifos_pending () -{ - return 0; /* used for cleanup; not needed with /dev/fd */ -} - -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|SUBSHELL_PROCSUB; - } - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - /* XXX - should we only do this in the parent? (as in command subst) */ - 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 (_("cannot 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, rflag) - int fd, quoted; - int *rflag; -{ - char *istring, buf[128], *bufp, *s; - int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul; - ssize_t bufn; - - istring = (char *)NULL; - istring_index = istring_size = bufn = tflag = 0; - - for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++) - skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL; - -#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. This may need to be - changed to understand multibyte characters in the future. */ - 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); - - /* This is essentially quote_string inline */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */) - istring[istring_index++] = CTLESC; - /* Escape CTLESC and CTLNUL in the output to protect those characters - from the rest of the word expansions (word splitting and globbing.) - This is essentially quote_escapes inline. */ - else if (skip_ctlesc == 0 && c == CTLESC) - { - tflag |= W_HASCTLESC; - istring[istring_index++] = CTLESC; - } - else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0))) - 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); - if (rflag) - *rflag = tflag; - 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); - - if (rflag) - *rflag = tflag; - return istring; -} - -/* Perform command substitution on STRING. This returns a WORD_DESC * with the - contained string possibly quoted. */ -WORD_DESC * -command_substitute (string, quoted) - char *string; - int quoted; -{ - pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid; - char *istring; - int result, fildes[2], function_value, pflags, rc, tflag; - WORD_DESC *ret; - - 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 ((WORD_DESC *)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 /* JOB_CONTROL */ - - old_async_pid = last_asynchronous_pid; - pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC); - last_asynchronous_pid = old_async_pid; - - if (pid == 0) - /* Reset the signal handlers in the child, but don't free the - trap strings. */ - reset_signal_handlers (); - -#if defined (JOB_CONTROL) - /* XXX DO THIS ONLY IN PARENT ? XXX */ - set_sigchld_handler (); - stop_making_children (); - if (pid != 0) - 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 ((WORD_DESC *)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 (); -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif - exit (rc); - } - else - { -#if defined (JOB_CONTROL) && defined (PGRP_PIPE) - close_pgrp_pipe (); -#endif /* JOB_CONTROL && PGRP_PIPE */ - - close (fildes[1]); - - tflag = 0; - istring = read_comsub (fildes[0], quoted, &tflag); - - 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 */ - - ret = alloc_word_desc (); - ret->word = istring; - ret->flags = tflag; - - return ret; - } -} - -/******************************************************** - * * - * 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 WORD_DESC * -parameter_brace_expand_word (name, var_is_special, quoted) - char *name; - int var_is_special, quoted; -{ - WORD_DESC *ret; - char *temp, *tt; - intmax_t arg_index; - SHELL_VAR *var; - int atype, rflags; - - ret = 0; - temp = 0; - rflags = 0; - - /* 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); - - ret = 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); - else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - rflags |= W_HASQUOTEDNULL; - } -#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; - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->word = temp; - ret->flags |= rflags; - } - return ret; -} - -/* Expand an indirect reference to a variable: ${!NAME} expands to the - value of the variable whose name is the value of NAME. */ -static WORD_DESC * -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; - WORD_DESC *w; - - w = parameter_brace_expand_word (name, var_is_special, quoted); - t = w->word; - /* 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; - } - dispose_word_desc (w); - - chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at); - if (t == 0) - return (WORD_DESC *)NULL; - - w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted); - free (t); - - return w; -} - -/* 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 WORD_DESC * -parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) - char *name, *value; - int c, quoted, *qdollaratp, *hasdollarat; -{ - WORD_DESC *w; - WORD_LIST *l; - char *t, *t1, *temp; - int hasdol; - - /* 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 (for sh backwards compatibility). */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value) - { - hasdol = 0; - temp = string_extract_double_quoted (value, &hasdol, 1); - } - else - temp = value; - - w = alloc_word_desc (); - 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); - if (temp != value) - 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 = make_quoted_char ('\0'); - w->flags |= W_HASQUOTEDNULL; - } - else - temp = (char *)NULL; - - if (c == '-' || c == '+') - { - w->word = temp; - return w; - } - - /* 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, 0); - else -#endif /* ARRAY_VARS */ - bind_variable (name, t1, 0); - free (t1); - - w->word = temp; - return w; -} - -/* 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) - { - l = expand_string (value, 0); - temp = string_list (l); - report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ - FREE (temp); - dispose_words (l); - } - else - 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} */ -} - -#if defined (HANDLE_MULTIBYTE) -size_t -mbstrlen (s) - const char *s; -{ - size_t clen, nc; - mbstate_t mbs, mbsbak; - - nc = 0; - memset (&mbs, 0, sizeof (mbs)); - mbsbak = mbs; - while ((clen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0) - { - if (MB_INVALIDCH(clen)) - { - clen = 1; /* assume single byte */ - mbs = mbsbak; - } - - s += clen; - nc++; - mbsbak = mbs; - } - return nc; -} -#endif - - -/* 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 = MB_STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && array_p (var)) - { - t = array_reference (array_cell (var), 0); - number = MB_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 = MB_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_arith_string (substr, Q_DOUBLE_QUOTES); - *e1p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - - len = -1; /* paranoia */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - len = MB_STRLEN (value); - break; - case VT_POSPARMS: - len = number_of_args () + 1; - if (*e1p == 0) - len++; /* add one arg if counting from $0 */ - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - a = (ARRAY *)value; - /* For arrays, the first value deals with array indices. Negative - offsets count from one past the array's maximum index. */ - len = array_max_index (a) + (*e1p < 0); /* 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_arith_string (temp2, Q_DOUBLE_QUOTES); - 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 if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')) - { - vtype = VT_VARIABLE; - *varp = v; - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - *valp = dequote_string (value); - else - *valp = dequote_escapes (value); - } - else - return -1; - } - else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && array_p (v)) - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = array_reference (array_cell (v), 0); - } - else -#endif - { - 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; - } - - 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; - /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0; - - 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, *oname; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - oname = this_command_name; - this_command_name = varname; - - vtype = get_var_and_type (varname, value, quoted, &v, &val); - if (vtype == -1) - { - this_command_name = oname; - return ((char *)NULL); - } - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - r = verify_substring_values (val, substr, vtype, &e1, &e2); - this_command_name = oname; - 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). */ - temp = array_subrange (array_cell (v), e1, e2, starsub, quoted); - /* array_subrange now calls array_quote_escapes as appropriate, so the - caller no longer needs to. */ - 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; - - 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 = alloc_word_desc (); - w->word = ret ? ret : savestring (""); - dispose_word (params->word); - params->word = w; - } - - if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB)) - ret = string_list_dollar_star (quote_list (save)); - else -#if 0 - ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save); -#else - if ((mflags & MATCH_QUOTED) == MATCH_QUOTED) - ret = string_list_dollar_star (quote_list (save)); - else - ret = string_list (save); -#endif - 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, delim; - 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 && *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 the pattern starts with a `/', make sure we skip over it when looking - for the replacement delimiter. */ -#if 0 - if (rep = quoted_strchr ((*patsub == '/') ? lpatsub+1 : lpatsub, '/', ST_BACKSL)) - *rep++ = '\0'; - else - rep = (char *)NULL; -#else - delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0); - if (lpatsub[delim] == '/') - { - lpatsub[delim] = 0; - rep = lpatsub + delim + 1; - } - else - rep = (char *)NULL; -#endif - - if (rep && *rep == '\0') - rep = (char *)NULL; - - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. */ - pat = getpattern (lpatsub, quoted, 1); - - 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); - } - - /* ksh93 doesn't allow the match specifier to be a part of the expanded - pattern. This is an extension. Make sure we don't anchor the pattern - at the beginning or end of the string if we're doing global replacement, - though. */ - p = pat; - if (mflags & MATCH_GLOBREP) - mflags |= MATCH_ANY; - else 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 = (mflags & MATCH_QUOTED) ? quote_string (temp) : 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); - /* Don't call quote_escapes anymore; array_patsub calls - array_quote_escapes as appropriate before adding the - space separators. */ - break; -#endif - } - - FREE (pat); - FREE (rep); - free (lpatsub); - - return temp; -} - -/* Check for unbalanced parens in S, which is the contents of $(( ... )). If - any occur, this must be a nested command substitution, so return 0. - Otherwise, return 1. A valid arithmetic expression must always have a - ( before a matching ), so any cases where there are more right parens - means that this must not be an arithmetic expression, though the parser - will not accept it without a balanced total number of parens. */ -static int -chk_arithsub (s, len) - const char *s; - int len; -{ - int i, count; - DECLARE_MBSTATE; - - i = count = 0; - while (i < len) - { - if (s[i] == '(') - count++; - else if (s[i] == ')') - { - count--; - if (count < 0) - return 0; - } - - switch (s[i]) - { - default: - ADVANCE_CHAR (s, len, i); - break; - - case '\\': - i++; - if (s[i]) - ADVANCE_CHAR (s, len, i); - break; - - case '\'': - i = skip_single_quoted (s, len, ++i); - break; - - case '"': - i = skip_double_quoted ((char *)s, len, ++i); - break; - } - } - - return (count == 0); -} - -/****************************************************************/ -/* */ -/* Functions to perform parameter expansion on a string */ -/* */ -/****************************************************************/ - -/* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */ -static WORD_DESC * -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; - WORD_DESC *tdesc, *ret; - int t_index, sindex, c, tflag; - intmax_t number; - - temp = temp1 = 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; - /* ${#var} doesn't have any of the other parameter expansions on it. */ - if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */ - name = string_extract (string, &t_index, "}", SX_VARNAME); - else - name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME); - - ret = 0; - tflag = 0; - - /* 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; - if (number < 0) - return (&expand_wdesc_error); - else - { - ret = alloc_word_desc (); - ret->word = itos (number); - return ret; - } - } - - /* ${@} 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; - - ret = alloc_word_desc (); - ret->word = temp; - return ret; - } - -#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; - - ret = alloc_word_desc (); - ret->word = temp; - return ret; - } - - 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) - tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at); - else - tdesc = parameter_brace_expand_word (name, var_is_special, quoted); - - if (tdesc) - { - temp = tdesc->word; - tflag = tdesc->flags; - dispose_word_desc (tdesc); - } - else - temp = (char *)0; - -#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); - - if (temp1 == &expand_param_error) - return (&expand_wdesc_error); - else if (temp1 == &expand_param_fatal) - return (&expand_wdesc_fatal); - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - return ret; - } - else if (want_patsub) - { - temp1 = parameter_brace_patsub (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - - if (temp1 == &expand_param_error) - return (&expand_wdesc_error); - else if (temp1 == &expand_param_fatal) - return (&expand_wdesc_fatal); - - ret = alloc_word_desc (); - ret->word = temp1; - return ret; - } - - /* 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_wdesc_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_wdesc_error : &expand_wdesc_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) - { - ret = parameter_brace_expand_rhs (name, value, c, - quoted, - quoted_dollar_atp, - contains_dollar_at); - /* XXX - fix up later, esp. noting presence of - W_HASQUOTEDNULL in ret->flags */ - 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_wdesc_error; - } - else if (c == '?') - { - parameter_brace_expand_error (name, value); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_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; - - ret = parameter_brace_expand_rhs (name, value, c, quoted, - quoted_dollar_atp, - contains_dollar_at); - /* XXX - fix up later, esp. noting presence of - W_HASQUOTEDNULL in tdesc->flags */ - } - free (value); - } - - break; - } - free (name); - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->flags = tflag; - ret->word = temp; - } - return (ret); -} - -/* 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 WORD_DESC * -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; - WORD_DESC *tdesc, *ret; - int tflag; - - zindex = *sindex; - c = string[++zindex]; - - temp = (char *)NULL; - ret = tdesc = (WORD_DESC *)NULL; - tflag = 0; - - /* 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_wdesc_error : &expand_wdesc_fatal); - } - if (temp1) - temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp1) - : quote_escapes (temp1); - else - temp = (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_wdesc_error : &expand_wdesc_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 = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (list) : string_list (list); - temp1 = quote_string (temp); - if (*temp == 0) - tflag |= W_HASQUOTEDNULL; - free (temp); - temp = temp1; - } - else - { - /* We check whether or not we're eventually going to split $* here, - for example when IFS is empty and we are processing the rhs of - an assignment statement. In that case, we don't separate the - arguments at all. Otherwise, if the $* is not quoted it is - identical to $@ */ -#if 1 -# if defined (HANDLE_MULTIBYTE) - if (expand_no_split_dollar_star && ifs_firstc[0] == 0) -# else - if (expand_no_split_dollar_star && ifs_firstc == 0) -# endif - temp = string_list_dollar_star (list); - else - temp = string_list_dollar_at (list, quoted); -#else - temp = string_list_dollar_at (list, quoted); -#endif - 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: - tdesc = parameter_brace_expand (string, &zindex, quoted, - quoted_dollar_at_p, - contains_dollar_at); - - if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) - return (tdesc); - temp = tdesc ? tdesc->word : (char *)0; - - /* 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 (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp)) - { - if (had_quoted_null_p) - *had_quoted_null_p = 1; - if (*quoted_dollar_at_p == 0) - { - free (temp); - tdesc->word = temp = (char *)NULL; - } - - } - - ret = tdesc; - 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, 0); - 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'; - - if (chk_arithsub (temp2, t_index) == 0) - { - free (temp2); - goto comsub; - } - - /* Expand variables found inside the expression. */ - temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES); - 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_wdesc_fatal); - } - else - return (&expand_wdesc_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 - { - tdesc = command_substitute (temp, quoted); - temp1 = tdesc ? tdesc->word : (char *)NULL; - if (tdesc) - dispose_word_desc (tdesc); - } - 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; - if (temp == 0) - { - temp = savestring (string); - if (expanded_something) - *expanded_something = 0; - goto return0; - } - - /* Do initial variable expansion. */ - temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES); - - 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_wdesc_fatal - : &expand_wdesc_error); - } - - if (string[zindex]) - zindex++; - -return0: - *sindex = zindex; - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->flags = tflag; /* XXX */ - ret->word = temp; - } - return ret; -} - -/* 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; - - /* State flags */ - int had_quoted_null; - int has_dollar_at; - int tflag; - - int assignoff; /* If assignment, offset of `=' */ - - 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; - /* Don't need the string length for the SADD... and COPY_ macros unless - multibyte characters are possible. */ - string_size = (MB_CUR_MAX > 1) ? strlen (string) : 1; - - if (contains_dollar_at) - *contains_dollar_at = 0; - - assignoff = -1; - - /* 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)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)) || 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 '=': - /* 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 (word->flags & (W_ASSIGNRHS|W_NOTILDE)) - goto add_character; - /* If we're not in posix mode or forcing assignment-statement tilde - expansion, note where the `=' appears in the word and prepare to - do tilde expansion following the first `='. */ - if ((word->flags & W_ASSIGNMENT) && - (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && - assignoff == -1 && sindex > 0) - assignoff = sindex; - if (sindex == assignoff && string[sindex+1] == '~') /* XXX */ - word->flags |= W_ITILDE; -#if 0 - else if ((word->flags & W_ASSIGNMENT) && - (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && - string[sindex+1] == '~') - word->flags |= W_ITILDE; -#endif - goto add_character; - - case ':': - if (word->flags & W_NOTILDE) - goto add_character; - - if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS|W_TILDEEXP)) && - string[sindex+1] == '~') - word->flags |= W_ITILDE; - goto add_character; - - case '~': - /* If the word isn't supposed to be tilde expanded, or we're not - at the start of a word or after an unquoted : or = in an - assignment statement, we don't do tilde expansion. */ - if ((word->flags & (W_NOTILDE|W_DQUOTE)) || - (sindex > 0 && ((word->flags & W_ITILDE) == 0)) || - (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - { - word->flags &= ~W_ITILDE; - goto add_character; - } - - if (word->flags & W_ASSIGNRHS) - tflag = 2; - else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP)) - tflag = 1; - else - tflag = 0; - - temp = bash_tilde_find_word (string + sindex, tflag, &t_index); - - word->flags &= ~W_ITILDE; - - if (temp && *temp && t_index > 0) - { - temp1 = bash_tilde_expand (temp, tflag); - if (temp1 && *temp1 == '~' && STREQ (temp, temp1)) - { - FREE (temp); - FREE (temp1); - goto add_character; /* tilde expansion failed */ - } - free (temp); - temp = temp1; - sindex += t_index; - goto add_quoted_string; /* XXX was add_string */ - } - else - { - FREE (temp); - goto add_character; - } - - case '$': - if (expanded_something) - *expanded_something = 1; - - has_dollar_at = 0; - tword = param_expand (string, &sindex, quoted, expanded_something, - &has_dollar_at, "ed_dollar_at, - &had_quoted_null, - (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0); - - if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal) - { - free (string); - free (istring); - return ((tword == &expand_wdesc_error) ? &expand_word_error - : &expand_word_fatal); - } - if (contains_dollar_at && has_dollar_at) - *contains_dollar_at = 1; - - if (tword && (tword->flags & W_HASQUOTEDNULL)) - had_quoted_null = 1; - - temp = tword->word; - dispose_word_desc (tword); - - goto add_string; - break; - - case '`': /* Backquoted command substitution. */ - { - t_index = sindex++; - - temp = string_extract (string, &sindex, "`", SX_REQMATCH); - /* The test of sindex against t_index is to allow bare instances of - ` to pass through, for backwards compatibility. */ - if (temp == &extract_string_error || temp == &extract_string_fatal) - { - if (sindex - 1 == t_index) - { - sindex = t_index; - goto add_character; - } - report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index); - free (string); - free (istring); - return ((temp == &extract_string_error) ? &expand_word_error - : &expand_word_fatal); - } - - if (expanded_something) - *expanded_something = 1; - - if (word->flags & W_NOCOMSUB) - /* sindex + 1 because string[sindex] == '`' */ - temp1 = substring (string, t_index, sindex + 1); - else - { - de_backslash (temp); - tword = command_substitute (temp, quoted); - temp1 = tword ? tword->word : (char *)NULL; - if (tword) - dispose_word_desc (tword); - } - 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)) || (word->flags & W_DQUOTE)) -#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 = alloc_word_desc (); - tword->word = temp; - - temp = (char *)NULL; - - has_dollar_at = 0; - /* Need to get W_HASQUOTEDNULL flag through this function. */ - 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 (list && list->word && (list->word->flags & W_HASQUOTEDNULL)) - had_quoted_null = 1; - - 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); - tflag = list->word->flags; - dispose_words (list); - - /* 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. */ - /* We use the W_HASQUOTEDNULL flag to differentiate the - cases: a quoted null character as above and when - CTLNUL is contained in the (non-null) expansion - of some variable. We use the had_quoted_null flag to - pass the value through this function to its caller. */ - if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0) - remove_quoted_nulls (temp); /* XXX */ - } - } - 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)) || (word->flags & W_DQUOTE)) -#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); - tword->flags |= W_HASQUOTEDNULL; /* XXX */ - 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); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - list = make_word_list (tword, (WORD_LIST *)NULL); - } -#else - else - list = (WORD_LIST *)NULL; -#endif - } - else if (word->flags & W_NOSPLIT) - { - tword = make_bare_word (istring); - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; /* XXX */ - if (word->flags & W_COMPASSIGN) - tword->flags |= W_COMPASSIGN; /* XXX */ - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; /* XXX */ - if (word->flags & W_NOEXPAND) - tword->flags |= W_NOEXPAND; /* XXX */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - if (had_quoted_null) - tword->flags |= W_HASQUOTEDNULL; - list = make_word_list (tword, (WORD_LIST *)NULL); - } - 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); - 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_COMPASSIGN) - tword->flags |= W_COMPASSIGN; - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; - if (word->flags & W_NOEXPAND) - tword->flags |= W_NOEXPAND; - if (had_quoted_null) - tword->flags |= W_HASQUOTEDNULL; /* XXX */ - list = make_word_list (tword, (WORD_LIST *)NULL); - } - } - - 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 (c == 0) - { - *r++ = '\\'; - break; - } - 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 = alloc_word_desc (); - w->word = t ? t : savestring (""); - 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, *e; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); -#if 0 - result = (WORD_LIST *) list_append (result, tresult); -#else - if (result == 0) - result = e = tresult; - else - { - e->next = tresult; - while (e->next) - e = e->next; - } -#endif - } - 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)) ? value_cell (v) : " \t\n"; - - /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet - handle multibyte chars in IFS */ - memset (ifs_cmap, '\0', sizeof (ifs_cmap)); - for (t = ifs_value ; t && *t; t++) - { - uc = *t; - ifs_cmap[uc] = 1; - } - -#if defined (HANDLE_MULTIBYTE) - if (ifs_value == 0) - { - ifs_firstc[0] = '\0'; - ifs_firstc_len = 1; - } - else - { - size_t ifs_len; - ifs_len = strnlen (ifs_value, MB_CUR_MAX); - ifs_firstc_len = MBLEN (ifs_value, ifs_len); - if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len)) - { - ifs_firstc[0] = ifs_value[0]; - ifs_firstc[1] = '\0'; - ifs_firstc_len = 1; - } - else - memcpy (ifs_firstc, ifs_value, ifs_firstc_len); - } -#else - ifs_firstc = ifs_value ? *ifs_value : 0; -#endif -} - -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, *e; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = word_split (t->word, ifs_value); - if (result == 0) - result = e = tresult; - else - { - e->next = tresult; - while (e->next) - e = e->next; - } - } - 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; - assigning_in_environment = 0; - - top_level_cleanup (); /* from sig.c */ - 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); - exp_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; - -#if defined (ARRAY_VARS) - /* If this is a compound array assignment to a builtin that accepts - such assignments (e.g., `declare'), take the assignment and perform - it separately, handling the semantics of declarations inside shell - functions. This avoids the double-evaluation of such arguments, - because `declare' does some evaluation of compound assignments on - its own. */ - if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) - { - int t; - - t = do_word_assignment (tlist->word); - if (t == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - - /* Now transform the word as ksh93 appears to do and go on */ - t = assignment (tlist->word->word, 0); - tlist->word->word[t] = '\0'; - tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG); - } -#endif - - 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_word_assignment (temp_list->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_wassign_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_word_assignment; - tempenv_assign_error = 0; - - for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; - assigning_in_environment = (assign_func == assign_in_env); - tint = (*assign_func) (temp_list->word); - assigning_in_environment = 0; - /* Variable assignment errors in non-interactive shells running - in Posix.2 mode cause the shell to exit. */ - if (tint == 0) - { - if (assign_func == do_word_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); - } - else - tempenv_assign_error++; - } - } - - 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 080da0f86..000000000 --- a/subst.c.save2 +++ /dev/null @@ -1,8363 +0,0 @@ -/* subst.c -- The part of the shell that does parameter, command, arithmetic, - 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-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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_ASSOCVAR 4 - -#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 `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]; - -#if defined (HANDLE_MULTIBYTE) -unsigned char ifs_firstc[MB_LEN_MAX]; -size_t ifs_firstc_len; -#else -unsigned char ifs_firstc; -#endif - -int assigning_in_environment; - -/* 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; -extern int tempenv_assign_error; - -#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE) -extern wchar_t *wcsdup __P((const wchar_t *)); -#endif - -/* 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 WORD_DESC expand_wdesc_error, expand_wdesc_fatal; -static char expand_param_error, expand_param_fatal; -static char extract_string_error, extract_string_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 char *remove_quoted_nulls __P((char *)); - -static int unquoted_substring __P((char *, char *)); -static int unquoted_member __P((int, char *)); - -#if defined (ARRAY_VARS) -static SHELL_VAR *do_compound_assignment __P((char *, char *, int)); -#endif -static int do_assignment_internal __P((const WORD_DESC *, int)); - -static char *string_extract_verbatim __P((char *, size_t, int *, char *, int)); -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((const 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 *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, 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 int chk_arithsub __P((const char *, int)); - -static WORD_DESC *parameter_brace_expand_word __P((char *, int, int)); -static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *)); -static WORD_DESC *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 WORD_DESC *parameter_brace_expand __P((char *, int *, int, int *, int *)); -static WORD_DESC *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 & SX_VARNAME) - is non-zero, and array variables have been compiled into the shell, - everything between a `[' and a corresponding `]' is skipped over. - If (flags & SX_NOALLOC) is non-zero, don't return the substring, just - update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must - contain a closing character from CHARLIST. */ -static char * -string_extract (string, sindex, charlist, flags) - char *string; - int *sindex; - char *charlist; - int flags; -{ - register int c, i; - int found; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; - i = *sindex; - found = 0; - while (c = string[i]) - { - if (c == '\\') - { - if (string[i + 1]) - i++; - else - break; - } -#if defined (ARRAY_VARS) - else if ((flags & SX_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)) - { - found = 1; - break; - } - - ADVANCE_CHAR (string, slen, i); - } - - /* If we had to have a matching delimiter and didn't find one, return an - error and let the caller deal with it. */ - if ((flags & SX_REQMATCH) && found == 0) - { - *sindex = i; - return (&extract_string_error); - } - - temp = (flags & SX_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_command_subst (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_command_subst (string, &si, SX_NOALLOC); - else - ret = extract_dollar_brace_string (string, &si, 0, SX_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; - - /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; - 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) - const 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, slen, sindex, charlist, flags) - char *string; - size_t slen; - int *sindex; - char *charlist; - int flags; -{ - register int i = *sindex; -#if defined (HANDLE_MULTIBYTE) - size_t clen; - wchar_t *wcharlist; -#endif - int c; - char *temp; - DECLARE_MBSTATE; - - if (charlist[0] == '\'' && charlist[1] == '\0') - { - temp = string_extract_single_quoted (string, sindex); - --*sindex; /* leave *sindex at separator character */ - return temp; - } - - i = *sindex; -#if 0 - /* See how the MBLEN and ADVANCE_CHAR macros work to understand why we need - this only if MB_CUR_MAX > 1. */ - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 1; -#endif -#if defined (HANDLE_MULTIBYTE) - clen = strlen (charlist); - wcharlist = 0; -#endif - while (c = string[i]) - { -#if defined (HANDLE_MULTIBYTE) - size_t mblength; -#endif - if ((flags & SX_NOCTLESC) == 0 && c == CTLESC) - { - i += 2; - continue; - } - /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL - through, to protect the CTLNULs from later calls to - remove_quoted_nulls. */ - else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL) - { - i += 2; - continue; - } - -#if defined (HANDLE_MULTIBYTE) - mblength = MBLEN (string + i, slen - i); - if (mblength > 1) - { - wchar_t wc; - mblength = mbtowc (&wc, string + i, slen - i); - if (MB_INVALIDCH (mblength)) - { - if (MEMBER (c, charlist)) - break; - } - else - { - if (wcharlist == 0) - { - size_t len; - len = mbstowcs (wcharlist, charlist, 0); - if (len == -1) - len = 0; - wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1)); - mbstowcs (wcharlist, charlist, len + 1); - } - - if (wcschr (wcharlist, wc)) - break; - } - } - else -#endif - if (MEMBER (c, charlist)) - break; - - ADVANCE_CHAR (string, slen, i); - } - -#if defined (HANDLE_MULTIBYTE) - FREE (wcharlist); -#endif - - 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 ")". ) - XFLAGS is additional flags to pass to other extraction functions, */ -char * -extract_command_subst (string, sindex, xflags) - char *string; - int *sindex; - int xflags; -{ - if (string[*sindex] == '(') /*)*/ - return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/ - else - { - xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0); - return (xparse_dolparen (string, string+*sindex, sindex, xflags)); - } -} - -/* 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) -/* This can be fooled by unquoted right parens in the passed string. If - each caller verifies that the last character in STRING is a right paren, - we don't even need to call extract_delimited_string. */ -char * -extract_array_assignment_list (string, sindex) - char *string; - int *sindex; -{ - int slen; - char *ret; - - slen = strlen (string); /* ( */ - if (string[slen - 1] == ')') - { - ret = substring (string, *sindex, slen - 1); - *sindex = slen - 1; - return ret; - } - return 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, in_comment; - 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 = in_comment = 0; - - nesting_level = 1; - i = *sindex; - - while (nesting_level) - { - c = string[i]; - - if (c == 0) - break; - - if (in_comment) - { - if (c == '\n') - in_comment = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - if (pass_character) /* previous char was backslash */ - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - /* Not exactly right yet; should handle shell metacharacters and - multibyte characters, too. */ - if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1]))) - { - in_comment = 1; - 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|SX_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|SX_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|SX_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 & SX_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|SX_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_command_subst (string, &si, flags|SX_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 & SX_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 - -#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0) - -/* 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, flags) - char *string; - int start; - char *delims; - int flags; -{ - int i, pass_next, backq, si, c; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = strlen (string + start) + start; - if (flags & SD_NOJMP) - 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, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ - else - temp = extract_dollar_brace_string (string, &si, 0, SX_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); -} - -#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. */ - -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); -} - -/* 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) - { - size_t slength; -#if defined (HANDLE_MULTIBYTE) - size_t mblength = 1; -#endif - DECLARE_MBSTATE; - - slength = strlen (delims); - d2 = (char *)xmalloc (slength + 1); - i = ts = 0; - while (delims[i]) - { -#if defined (HANDLE_MULTIBYTE) - mbstate_t state_bak; - state_bak = state; - mblength = MBRLEN (delims + i, slength, &state); - if (MB_INVALIDCH (mblength)) - state = state_bak; - else if (mblength > 1) - { - memcpy (d2 + ts, delims + i, mblength); - ts += mblength; - i += mblength; - slength -= mblength; - continue; - } -#endif - if (whitespace (delims[i]) == 0) - d2[ts++] = delims[i]; - - i++; - slength--; - } - 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, SD_NOJMP); - - /* 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, " ")); -} - -/* An external interface that can be used by the rest of the shell to - obtain a string containing the first character in $IFS. Handles all - the multibyte complications. If LENP is non-null, it is set to the - length of the returned string. */ -char * -ifs_firstchar (lenp) - int *lenp; -{ - char *ret; - int len; - - ret = xmalloc (MB_LEN_MAX + 1); -#if defined (HANDLE_MULTIBYTE) - if (ifs_firstc_len == 1) - { - ret[0] = ifs_firstc[0]; - ret[1] = '\0'; - len = ret[0] ? 1 : 0; - } - else - { - memcpy (ret, ifs_firstc, ifs_firstc_len); - ret[len = ifs_firstc_len] = '\0'; - } -#else - ret[0] = ifs_firstc; - ret[1] = '\0'; - len = ret[0] ? 0 : 1; -#endif - - if (lenp) - *lenp = len; - - return ret; -} - -/* 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 *ret; -#if defined (HANDLE_MULTIBYTE) -# if defined (__GNUC__) - char sep[MB_CUR_MAX + 1]; -# else - char *sep = 0; -# endif -#else - char sep[2]; -#endif - -#if defined (HANDLE_MULTIBYTE) -# if !defined (__GNUC__) - sep = (char *)xmalloc (MB_CUR_MAX + 1); -# endif /* !__GNUC__ */ - if (ifs_firstc_len == 1) - { - sep[0] = ifs_firstc[0]; - sep[1] = '\0'; - } - else - { - memcpy (sep, ifs_firstc, ifs_firstc_len); - sep[ifs_firstc_len] = '\0'; - } -#else - sep[0] = ifs_firstc; - sep[1] = '\0'; -#endif - - ret = string_list_internal (list, sep); -#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) - free (sep); -#endif - return ret; -} - -/* 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, *ret; -#if defined (HANDLE_MULTIBYTE) -# if defined (__GNUC__) - char sep[MB_CUR_MAX + 1]; -# else - char *sep = 0; -# endif /* !__GNUC__ */ -#else - char sep[2]; -#endif - WORD_LIST *tlist; - - /* XXX this could just be ifs = ifs_value; */ - ifs = ifs_var ? value_cell (ifs_var) : (char *)0; - -#if defined (HANDLE_MULTIBYTE) -# if !defined (__GNUC__) - sep = (char *)xmalloc (MB_CUR_MAX + 1); -# endif /* !__GNUC__ */ - if (ifs && *ifs) - { - if (ifs_firstc_len == 1) - { - sep[0] = ifs_firstc[0]; - sep[1] = '\0'; - } - else - { - memcpy (sep, ifs_firstc, ifs_firstc_len); - sep[ifs_firstc_len] = '\0'; - } - } - else - { - sep[0] = ' '; - sep[1] = '\0'; - } -#else - sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs; - sep[1] = '\0'; -#endif - - /* XXX -- why call quote_list if ifs == 0? we can get away without doing - it now that quote_escapes quotes spaces */ -#if 0 - tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0)) -#else - tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) -#endif - ? quote_list (list) - : list_quote_escapes (list); - - ret = string_list_internal (tlist, sep); -#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) - free (sep); -#endif - return ret; -} - -/* Turn the positional paramters into a string, understanding quoting and - the various subtleties of using the first character of $IFS as the - separator. Calls string_list_dollar_at, string_list_dollar_star, and - string_list as appropriate. */ -char * -string_list_pos_params (pchar, list, quoted) - int pchar; - WORD_LIST *list; - int quoted; -{ - char *ret; - - if (pchar == '*') - { - if (quoted & Q_DOUBLE_QUOTES) - ret = string_list_dollar_star (quote_list (list)); - else if (quoted & Q_HERE_DOCUMENT) - ret = string_list (quote_list (list)); - else - /* Even when unquoted, string_list_dollar_star does the right thing - making sure that the first character of $IFS is used as the - separator. */ - ret = string_list_dollar_star (list); - } - else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - /* We use string_list_dollar_at, but only if the string is quoted, since - that quotes the escapes if it's not, which we don't want. We could - use string_list (the old code did), but that doesn't do the right - thing if the first character of $IFS is not a space. We use - string_list_dollar_star if the string is unquoted so we make sure that - the elements of $@ are separated by the first character of $IFS for - later splitting. */ - ret = string_list_dollar_at (list, quoted); - else if (pchar == '@') - ret = string_list_dollar_star (list); - else - ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list); - - return ret; -} - -/* 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, xflags; - size_t slen; - - if (!string || !*string) - return ((WORD_LIST *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - for (xflags = 0, s = ifs_value; s && *s; s++) - { - if (*s == CTLESC) xflags |= SX_NOCTLESC; - else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; - } - - slen = 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. */ - slen = (MB_CUR_MAX > 1) ? strlen (string) : 1; - for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) - { - /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim - unless multibyte chars are possible. */ - current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags); - 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 = alloc_word_desc (); - t->word = make_quoted_char ('\0'); - t->flags |= W_QUOTED|W_HASQUOTEDNULL; - 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); - result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */ - 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 = alloc_word_desc (); - t->word = make_quoted_char ('\0'); - t->flags |= W_QUOTED|W_HASQUOTEDNULL; - 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]) - { - DECLARE_MBSTATE; - ADVANCE_CHAR (string, slen, 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++; - /* An IFS character that is not IFS white space, along with any - adjacent IFS white space, shall delimit a field. (SUSv3) */ - while (string[sindex] && spctabnl (string[sindex]) && isifs (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, xflags; - size_t slen; - - if (!stringp || !*stringp || !**stringp) - return ((char *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - for (xflags = 0, s = ifs_value; s && *s; s++) - { - if (*s == CTLESC) xflags |= SX_NOCTLESC; - if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; - } - - s = *stringp; - slen = 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; - /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim - unless multibyte chars are possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (s) : 1; - current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags); - - /* 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]) - { - DECLARE_MBSTATE; - ADVANCE_CHAR (s, slen, 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++; - /* An IFS character that is not IFS white space, along with any adjacent - IFS white space, shall delimit a field. */ - while (s[sindex] && spctabnl (s[sindex]) && isifs (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 */ -/* */ -/********************************************************/ - -#if defined (ARRAY_VARS) -static SHELL_VAR * -do_compound_assignment (name, value, flags) - char *name, *value; - int flags; -{ - SHELL_VAR *v; - int mklocal; - WORD_LIST *list; - - mklocal = flags & ASS_MKLOCAL; - - if (mklocal && variable_context) - { - list = expand_compound_array_assignment (value, flags); - v = find_variable (name); - if (v == 0 || array_p (v) == 0 || v->context != variable_context) - v = make_local_array_variable (name); - assign_compound_array_list (v, list, flags); - } - else - v = assign_array_from_string (name, value, flags); - - return (v); -} -#endif - -/* 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 (word, expand) - const WORD_DESC *word; - int expand; -{ - int offset, tlen, appendop, assign_list, aflags, retval; - char *name, *value; - SHELL_VAR *entry; -#if defined (ARRAY_VARS) - char *t; - int ni; -#endif - const char *string; - - if (word == 0 || word->word == 0) - return 0; - - appendop = assign_list = aflags = 0; - string = word->word; - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - char *temp; - - if (name[offset - 1] == '+') - { - appendop = 1; - name[offset - 1] = '\0'; - } - - name[offset] = 0; /* might need this set later */ - temp = name + offset + 1; - tlen = STRLEN (temp); - -#if defined (ARRAY_VARS) - if (expand && (word->flags & W_COMPASSIGN)) - { - assign_list = ni = 1; - value = extract_array_assignment_list (temp, &ni); - } - else -#endif - - if (expand && temp[0]) - value = expand_string_if_necessary (temp, 0, expand_string_assignment); - else - value = savestring (temp); - } - - if (value == 0) - { - value = (char *)xmalloc (1); - value[0] = '\0'; - } - - if (echo_command_at_execute) - { - if (appendop) - name[offset - 1] = '+'; - xtrace_print_assignment (name, value, assign_list, 1); - if (appendop) - name[offset - 1] = '\0'; - } - -#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) - - if (appendop) - aflags |= ASS_APPEND; - -#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, aflags); - if (entry == 0) - ASSIGN_RETURN (0); - } - else if (assign_list) - { - if (word->flags & W_ASSIGNARG) - aflags |= ASS_MKLOCAL; - entry = do_compound_assignment (name, value, aflags); - } - else -#endif /* ARRAY_VARS */ - entry = bind_variable (name, value, aflags); - - stupidly_hack_special_variables (name); - -#if 1 - /* Return 1 if the assignment seems to have been performed correctly. */ - if (entry == 0 || readonly_p (entry)) - retval = 0; /* assignment failure */ - else if (noassign_p (entry)) - { - last_command_exit_value = EXECUTION_FAILURE; - retval = 1; /* error status, but not assignment failure */ - } - else - retval = 1; - ASSIGN_RETURN (retval); - - if (entry && retval != 0) - VUNSETATTR (entry, att_invisible); -#else - if (entry) - VUNSETATTR (entry, att_invisible); - - ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0); -#endif -} - -/* Perform the assignment statement in STRING, and expand the - right side by doing tilde, command and parameter expansion. */ -int -do_assignment (string) - char *string; -{ - WORD_DESC td; - - td.flags = W_ASSIGNMENT; - td.word = string; - - return do_assignment_internal (&td, 1); -} - -int -do_word_assignment (word) - WORD_DESC *word; -{ - return do_assignment_internal (word, 1); -} - -/* Given STRING, an assignment string, get the value of the right side - of the `=', and bind it to the left side. Do not perform any word - expansions on the right hand side. */ -int -do_assignment_no_expand (string) - char *string; -{ - WORD_DESC td; - - td.flags = W_ASSIGNMENT; - td.word = string; - - return (do_assignment_internal (&td, 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); - - if (start == 0) /* handle ${@:0[:x]} specially */ - { - t = make_word_list (make_word (dollar_vars[0]), params); - save = params = t; - } - - 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; - - ret = string_list_pos_params (string[0], h, quoted); - - 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 || s == '~') -#else -#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~') -#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; - - /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (string) : 0; - 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)); -} - -char * -expand_assignment_string_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string_assignment)); -} - -char * -expand_arith_string (string, quoted) - char *string; -{ - return (expand_string_if_necessary (string, quoted, expand_string)); -} - -#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 1, 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. If - SPECIAL is 2, this is an rhs argument for the =~ operator, and should - be quoted appropriately for regcomp/regexec. The caller is responsible - for removing the backslashes if the unquoted word is needed later. */ -char * -cond_expand_word (w, special) - WORD_DESC *w; - int special; -{ - char *r, *p; - WORD_LIST *l; - int qflags; - - if (w->word == 0 || w->word[0] == '\0') - return ((char *)NULL); - - 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 - { - qflags = QGLOB_CVTNULL; - if (special == 2) - qflags |= QGLOB_REGEXP; - p = string_list (l); - r = quote_string_for_globbing (p, qflags); - 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); - value->word->flags &= ~W_HASQUOTEDNULL; - } - dequote_list (value); - } - return (value); -} - -/* Expand the rhs of an assignment statement */ -WORD_LIST * -expand_string_assignment (string, quoted) - char *string; - int quoted; -{ - WORD_DESC td; - WORD_LIST *value; - - if (string == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - expand_no_split_dollar_star = 1; - - td.flags = W_ASSIGNRHS; - td.word = savestring (string); - value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - FREE (td.word); - - expand_no_split_dollar_star = 0; - - if (value) - { - if (value->word) - { - remove_quoted_nulls (value->word->word); - value->word->flags &= ~W_HASQUOTEDNULL; - } - 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, wflags) - char *string; - int quoted; - int wflags; -{ - WORD_LIST *value; - WORD_DESC td; - - if (string == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = wflags; - 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); - value->word->flags &= ~W_HASQUOTEDNULL; - } - 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 (word splitting - and filename generation). If IFS is null, we quote spaces as well, just - in case we split on spaces later (in the case of unquoted $@, we will - eventually attempt to split the entire word on spaces). Corresponding - code exists in dequote_escapes. Even if we don't end up splitting on - spaces, quoting spaces is not a problem. This should never be called on - a string that is quoted with single or double quotes or part of a here - document (effectively double-quoted). */ -char * -quote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - int quote_spaces, skip_ctlesc, skip_ctlnul; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - quote_spaces = (ifs_value && *ifs_value == 0); - - for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++) - skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL; - - t = result = (char *)xmalloc ((slen * 2) + 1); - s = string; - - while (*s) - { - if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' ')) - *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, *s1; - size_t slen; - char *result, *send; - int quote_spaces; - DECLARE_MBSTATE; - - if (string == 0) - return string; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc (slen + 1); - - if (strchr (string, CTLESC) == 0) - return (strcpy (result, string)); - - quote_spaces = (ifs_value && *ifs_value == 0); - - s = string; - while (*s) - { - if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' '))) - { - 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. - This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be - set in any resultant WORD_DESC where this value is the word. */ -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, returning a new string. This turns "" into QUOTED_NULL, so - the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where - this value is the word. */ -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-quote 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; - /* XXX - turn on W_HAVEQUOTEDNULL here? */ - } - return list; -} - -/* De-quote quoted characters in each word in LIST. */ -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; - /* XXX - turn off W_HAVEQUOTEDNULL here? */ - } - return list; -} - -/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed - string. */ -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); - t->word->flags &= ~W_HASQUOTEDNULL; - } -} - -/* **************************************************************** */ -/* */ -/* 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 * -remove_wpattern (wparam, wstrlen, wpattern, op) - wchar_t *wparam; - size_t wstrlen; - wchar_t *wpattern; - int op; -{ - wchar_t wc, *ret; - int n; - - 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 = (char *)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, *npat; - char *end; - - /* If the pattern doesn't match anywhere in the string, go ahead and - short-circuit right away. A minor optimization, saves a bunch of - unnecessary calls to strmatch (up to N calls for a string of N - characters) if the match is unsuccessful. To preserve the semantics - of the substring matches below, we make sure that the pattern has - `*' as first and last character, making a new pattern if necessary. */ - /* XXX - check this later if I ever implement `**' with special meaning, - since this will potentially result in `**' at the beginning or end */ - len = STRLEN (pat); - if (pat[0] != '*' || pat[len - 1] != '*') - { - p = npat = (char *)xmalloc (len + 3); - p1 = pat; - if (*p1 != '*') - *p++ = '*'; - while (*p1) - *p++ = *p1++; - if (p1[-1] != '*' || p[-2] == '\\') - *p++ = '*'; - *p = '\0'; - } - else - npat = pat; - c = strmatch (npat, string, FNMATCH_EXTFLAG); - if (npat != pat) - free (npat); - if (c == FNM_NOMATCH) - return (0); - - 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, *wp, *nwpat, *wp1; - int len; -#if 0 - size_t n, n1; /* Apple's gcc seems to miscompile this badly */ -#else - int n, n1; -#endif - - /* If the pattern doesn't match anywhere in the string, go ahead and - short-circuit right away. A minor optimization, saves a bunch of - unnecessary calls to strmatch (up to N calls for a string of N - characters) if the match is unsuccessful. To preserve the semantics - of the substring matches below, we make sure that the pattern has - `*' as first and last character, making a new pattern if necessary. */ - /* XXX - check this later if I ever implement `**' with special meaning, - since this will potentially result in `**' at the beginning or end */ - len = wcslen (wpat); - if (wpat[0] != L'*' || wpat[len - 1] != L'*') - { - wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t)); - wp1 = wpat; - if (*wp1 != L'*') - *wp++ = L'*'; - while (*wp1 != L'\0') - *wp++ = *wp1++; - if (wp1[-1] != L'*' || wp1[-2] == L'\\') - *wp++ = L'*'; - *wp = '\0'; - } - else - nwpat = wpat; - len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG); - if (nwpat != wpat) - free (nwpat); - if (len == FNM_NOMATCH) - return (0); - - 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; -#if 0 - int i; -#endif - - /* 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 = *value ? expand_string_for_rhs (value, - (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, - (int *)NULL, (int *)NULL) - : (WORD_LIST *)0; - 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 = alloc_word_desc (); - w->word = tword ? tword : savestring (""); - new = make_word_list (w, new); - } - - l = REVERSE_LIST (new, WORD_LIST *); - tword = string_list_pos_params (itype, l, quoted); - 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++; - - /* Need to pass getpattern newly-allocated memory in case of expansion -- - the expansion code will free the passed string on an error. */ - temp1 = savestring (patstr); - pattern = getpattern (temp1, quoted, 1); - free (temp1); - - 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 = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - ? quote_string (temp1) - : 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; -} - -int -fifos_pending () -{ - return nfifo; -} - -static char * -make_named_pipe () -{ - char *tname; - - tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR); - 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++; -} - -int -fifos_pending () -{ - return 0; /* used for cleanup; not needed with /dev/fd */ -} - -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|SUBSHELL_PROCSUB; - } - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - /* XXX - should we only do this in the parent? (as in command subst) */ - 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 (_("cannot 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, rflag) - int fd, quoted; - int *rflag; -{ - char *istring, buf[128], *bufp, *s; - int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul; - ssize_t bufn; - - istring = (char *)NULL; - istring_index = istring_size = bufn = tflag = 0; - - for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++) - skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL; - -#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. This may need to be - changed to understand multibyte characters in the future. */ - 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); - - /* This is essentially quote_string inline */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */) - istring[istring_index++] = CTLESC; - /* Escape CTLESC and CTLNUL in the output to protect those characters - from the rest of the word expansions (word splitting and globbing.) - This is essentially quote_escapes inline. */ - else if (skip_ctlesc == 0 && c == CTLESC) - { - tflag |= W_HASCTLESC; - istring[istring_index++] = CTLESC; - } - else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0))) - 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); - if (rflag) - *rflag = tflag; - 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); - - if (rflag) - *rflag = tflag; - return istring; -} - -/* Perform command substitution on STRING. This returns a WORD_DESC * with the - contained string possibly quoted. */ -WORD_DESC * -command_substitute (string, quoted) - char *string; - int quoted; -{ - pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid; - char *istring; - int result, fildes[2], function_value, pflags, rc, tflag; - WORD_DESC *ret; - - 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 ((WORD_DESC *)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 /* JOB_CONTROL */ - - old_async_pid = last_asynchronous_pid; - pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC); - last_asynchronous_pid = old_async_pid; - - if (pid == 0) - /* Reset the signal handlers in the child, but don't free the - trap strings. */ - reset_signal_handlers (); - -#if defined (JOB_CONTROL) - /* XXX DO THIS ONLY IN PARENT ? XXX */ - set_sigchld_handler (); - stop_making_children (); - if (pid != 0) - 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 ((WORD_DESC *)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 (); -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif - exit (rc); - } - else - { -#if defined (JOB_CONTROL) && defined (PGRP_PIPE) - close_pgrp_pipe (); -#endif /* JOB_CONTROL && PGRP_PIPE */ - - close (fildes[1]); - - tflag = 0; - istring = read_comsub (fildes[0], quoted, &tflag); - - 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 */ - - ret = alloc_word_desc (); - ret->word = istring; - ret->flags = tflag; - - return ret; - } -} - -/******************************************************** - * * - * 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 WORD_DESC * -parameter_brace_expand_word (name, var_is_special, quoted) - char *name; - int var_is_special, quoted; -{ - WORD_DESC *ret; - char *temp, *tt; - intmax_t arg_index; - SHELL_VAR *var; - int atype, rflags; - - ret = 0; - temp = 0; - rflags = 0; - - /* 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); - - ret = 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); - else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - rflags |= W_HASQUOTEDNULL; - } -#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; - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->word = temp; - ret->flags |= rflags; - } - return ret; -} - -/* Expand an indirect reference to a variable: ${!NAME} expands to the - value of the variable whose name is the value of NAME. */ -static WORD_DESC * -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; - WORD_DESC *w; - - w = parameter_brace_expand_word (name, var_is_special, quoted); - t = w->word; - /* 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; - } - dispose_word_desc (w); - - chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at); - if (t == 0) - return (WORD_DESC *)NULL; - - w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted); - free (t); - - return w; -} - -/* 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 WORD_DESC * -parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) - char *name, *value; - int c, quoted, *qdollaratp, *hasdollarat; -{ - WORD_DESC *w; - WORD_LIST *l; - char *t, *t1, *temp; - int hasdol; - - /* 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 (for sh backwards compatibility). */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value) - { - hasdol = 0; - temp = string_extract_double_quoted (value, &hasdol, 1); - } - else - temp = value; - - w = alloc_word_desc (); - 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); - if (temp != value) - 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 = make_quoted_char ('\0'); - w->flags |= W_HASQUOTEDNULL; - } - else - temp = (char *)NULL; - - if (c == '-' || c == '+') - { - w->word = temp; - return w; - } - - /* 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, 0); - else -#endif /* ARRAY_VARS */ - bind_variable (name, t1, 0); - free (t1); - - w->word = temp; - return w; -} - -/* 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) - { - l = expand_string (value, 0); - temp = string_list (l); - report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ - FREE (temp); - dispose_words (l); - } - else - 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} */ -} - -#if defined (HANDLE_MULTIBYTE) -size_t -mbstrlen (s) - const char *s; -{ - size_t clen, nc; - mbstate_t mbs, mbsbak; - - nc = 0; - memset (&mbs, 0, sizeof (mbs)); - mbsbak = mbs; - while ((clen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0) - { - if (MB_INVALIDCH(clen)) - { - clen = 1; /* assume single byte */ - mbs = mbsbak; - } - - s += clen; - nc++; - mbsbak = mbs; - } - return nc; -} -#endif - - -/* 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 = MB_STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && array_p (var)) - { - t = array_reference (array_cell (var), 0); - number = MB_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 = MB_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_arith_string (substr, Q_DOUBLE_QUOTES); - *e1p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - - len = -1; /* paranoia */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - len = MB_STRLEN (value); - break; - case VT_POSPARMS: - len = number_of_args () + 1; - if (*e1p == 0) - len++; /* add one arg if counting from $0 */ - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - a = (ARRAY *)value; - /* For arrays, the first value deals with array indices. Negative - offsets count from one past the array's maximum index. */ - len = array_max_index (a) + (*e1p < 0); /* 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_arith_string (temp2, Q_DOUBLE_QUOTES); - 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 if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')) - { - vtype = VT_VARIABLE; - *varp = v; - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - *valp = dequote_string (value); - else - *valp = dequote_escapes (value); - } - else - return -1; - } - else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && array_p (v)) - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = array_reference (array_cell (v), 0); - } - else -#endif - { - 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; - } - - 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; - /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0; - - 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, *oname; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - oname = this_command_name; - this_command_name = varname; - - vtype = get_var_and_type (varname, value, quoted, &v, &val); - if (vtype == -1) - { - this_command_name = oname; - return ((char *)NULL); - } - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - r = verify_substring_values (val, substr, vtype, &e1, &e2); - this_command_name = oname; - 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). */ - temp = array_subrange (array_cell (v), e1, e2, starsub, quoted); - /* array_subrange now calls array_quote_escapes as appropriate, so the - caller no longer needs to. */ - 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; - int pchar; - - 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 = alloc_word_desc (); - w->word = ret ? ret : savestring (""); - dispose_word (params->word); - params->word = w; - } - - if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB)) - ret = string_list_dollar_star (quote_list (save)); - else if ((mflags & MATCH_QUOTED) == MATCH_QUOTED) - ret = string_list_dollar_star (quote_list (save)); - else - ret = string_list_dollar_star (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, delim; - 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 && *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 the pattern starts with a `/', make sure we skip over it when looking - for the replacement delimiter. */ -#if 0 - if (rep = quoted_strchr ((*patsub == '/') ? lpatsub+1 : lpatsub, '/', ST_BACKSL)) - *rep++ = '\0'; - else - rep = (char *)NULL; -#else - delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0); - if (lpatsub[delim] == '/') - { - lpatsub[delim] = 0; - rep = lpatsub + delim + 1; - } - else - rep = (char *)NULL; -#endif - - if (rep && *rep == '\0') - rep = (char *)NULL; - - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. */ - pat = getpattern (lpatsub, quoted, 1); - - 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); - } - - /* ksh93 doesn't allow the match specifier to be a part of the expanded - pattern. This is an extension. Make sure we don't anchor the pattern - at the beginning or end of the string if we're doing global replacement, - though. */ - p = pat; - if (mflags & MATCH_GLOBREP) - mflags |= MATCH_ANY; - else 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 = (mflags & MATCH_QUOTED) ? quote_string (temp) : 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); - /* Don't call quote_escapes anymore; array_patsub calls - array_quote_escapes as appropriate before adding the - space separators. */ - break; -#endif - } - - FREE (pat); - FREE (rep); - free (lpatsub); - - return temp; -} - -/* Check for unbalanced parens in S, which is the contents of $(( ... )). If - any occur, this must be a nested command substitution, so return 0. - Otherwise, return 1. A valid arithmetic expression must always have a - ( before a matching ), so any cases where there are more right parens - means that this must not be an arithmetic expression, though the parser - will not accept it without a balanced total number of parens. */ -static int -chk_arithsub (s, len) - const char *s; - int len; -{ - int i, count; - DECLARE_MBSTATE; - - i = count = 0; - while (i < len) - { - if (s[i] == '(') - count++; - else if (s[i] == ')') - { - count--; - if (count < 0) - return 0; - } - - switch (s[i]) - { - default: - ADVANCE_CHAR (s, len, i); - break; - - case '\\': - i++; - if (s[i]) - ADVANCE_CHAR (s, len, i); - break; - - case '\'': - i = skip_single_quoted (s, len, ++i); - break; - - case '"': - i = skip_double_quoted ((char *)s, len, ++i); - break; - } - } - - return (count == 0); -} - -/****************************************************************/ -/* */ -/* Functions to perform parameter expansion on a string */ -/* */ -/****************************************************************/ - -/* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */ -static WORD_DESC * -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; - WORD_DESC *tdesc, *ret; - int t_index, sindex, c, tflag; - intmax_t number; - - temp = temp1 = 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; - /* ${#var} doesn't have any of the other parameter expansions on it. */ - if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */ - name = string_extract (string, &t_index, "}", SX_VARNAME); - else - name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME); - - ret = 0; - tflag = 0; - - /* 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; - if (number < 0) - return (&expand_wdesc_error); - else - { - ret = alloc_word_desc (); - ret->word = itos (number); - return ret; - } - } - - /* ${@} 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; - - ret = alloc_word_desc (); - ret->word = temp; - return ret; - } - -#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; - - ret = alloc_word_desc (); - ret->word = temp; - return ret; - } - - 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) - tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at); - else - tdesc = parameter_brace_expand_word (name, var_is_special, quoted); - - if (tdesc) - { - temp = tdesc->word; - tflag = tdesc->flags; - dispose_word_desc (tdesc); - } - else - temp = (char *)0; - -#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); - - if (temp1 == &expand_param_error) - return (&expand_wdesc_error); - else if (temp1 == &expand_param_fatal) - return (&expand_wdesc_fatal); - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - return ret; - } - else if (want_patsub) - { - temp1 = parameter_brace_patsub (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - - if (temp1 == &expand_param_error) - return (&expand_wdesc_error); - else if (temp1 == &expand_param_fatal) - return (&expand_wdesc_fatal); - - ret = alloc_word_desc (); - ret->word = temp1; - return ret; - } - - /* 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_wdesc_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_wdesc_error : &expand_wdesc_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) - { - ret = parameter_brace_expand_rhs (name, value, c, - quoted, - quoted_dollar_atp, - contains_dollar_at); - /* XXX - fix up later, esp. noting presence of - W_HASQUOTEDNULL in ret->flags */ - 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_wdesc_error; - } - else if (c == '?') - { - parameter_brace_expand_error (name, value); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_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; - - ret = parameter_brace_expand_rhs (name, value, c, quoted, - quoted_dollar_atp, - contains_dollar_at); - /* XXX - fix up later, esp. noting presence of - W_HASQUOTEDNULL in tdesc->flags */ - } - free (value); - } - - break; - } - free (name); - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->flags = tflag; - ret->word = temp; - } - return (ret); -} - -/* 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 WORD_DESC * -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; - WORD_DESC *tdesc, *ret; - int tflag; - - zindex = *sindex; - c = string[++zindex]; - - temp = (char *)NULL; - ret = tdesc = (WORD_DESC *)NULL; - tflag = 0; - - /* 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_wdesc_error : &expand_wdesc_fatal); - } - if (temp1) - temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp1) - : quote_escapes (temp1); - else - temp = (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_wdesc_error : &expand_wdesc_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 = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (list) : string_list (list); - temp1 = quote_string (temp); - if (*temp == 0) - tflag |= W_HASQUOTEDNULL; - free (temp); - temp = temp1; - } - else - { - /* We check whether or not we're eventually going to split $* here, - for example when IFS is empty and we are processing the rhs of - an assignment statement. In that case, we don't separate the - arguments at all. Otherwise, if the $* is not quoted it is - identical to $@ */ -#if 1 -# if defined (HANDLE_MULTIBYTE) - if (expand_no_split_dollar_star && ifs_firstc[0] == 0) -# else - if (expand_no_split_dollar_star && ifs_firstc == 0) -# endif - temp = string_list_dollar_star (list); - else - temp = string_list_dollar_at (list, quoted); -#else - temp = string_list_dollar_at (list, quoted); -#endif - 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: - tdesc = parameter_brace_expand (string, &zindex, quoted, - quoted_dollar_at_p, - contains_dollar_at); - - if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) - return (tdesc); - temp = tdesc ? tdesc->word : (char *)0; - - /* 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 (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp)) - { - if (had_quoted_null_p) - *had_quoted_null_p = 1; - if (*quoted_dollar_at_p == 0) - { - free (temp); - tdesc->word = temp = (char *)NULL; - } - - } - - ret = tdesc; - 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, 0); - 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'; - - if (chk_arithsub (temp2, t_index) == 0) - { - free (temp2); - goto comsub; - } - - /* Expand variables found inside the expression. */ - temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES); - 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_wdesc_fatal); - } - else - return (&expand_wdesc_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 - { - tdesc = command_substitute (temp, quoted); - temp1 = tdesc ? tdesc->word : (char *)NULL; - if (tdesc) - dispose_word_desc (tdesc); - } - 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; - if (temp == 0) - { - temp = savestring (string); - if (expanded_something) - *expanded_something = 0; - goto return0; - } - - /* Do initial variable expansion. */ - temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES); - - 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_wdesc_fatal - : &expand_wdesc_error); - } - - if (string[zindex]) - zindex++; - -return0: - *sindex = zindex; - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->flags = tflag; /* XXX */ - ret->word = temp; - } - return ret; -} - -/* 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; - - /* State flags */ - int had_quoted_null; - int has_dollar_at; - int tflag; - - int assignoff; /* If assignment, offset of `=' */ - - 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; - /* Don't need the string length for the SADD... and COPY_ macros unless - multibyte characters are possible. */ - string_size = (MB_CUR_MAX > 1) ? strlen (string) : 1; - - if (contains_dollar_at) - *contains_dollar_at = 0; - - assignoff = -1; - - /* 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)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)) || 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 '=': - /* 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 (word->flags & (W_ASSIGNRHS|W_NOTILDE)) - goto add_character; - /* If we're not in posix mode or forcing assignment-statement tilde - expansion, note where the `=' appears in the word and prepare to - do tilde expansion following the first `='. */ - if ((word->flags & W_ASSIGNMENT) && - (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && - assignoff == -1 && sindex > 0) - assignoff = sindex; - if (sindex == assignoff && string[sindex+1] == '~') /* XXX */ - word->flags |= W_ITILDE; -#if 0 - else if ((word->flags & W_ASSIGNMENT) && - (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && - string[sindex+1] == '~') - word->flags |= W_ITILDE; -#endif - goto add_character; - - case ':': - if (word->flags & W_NOTILDE) - goto add_character; - - if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS|W_TILDEEXP)) && - string[sindex+1] == '~') - word->flags |= W_ITILDE; - goto add_character; - - case '~': - /* If the word isn't supposed to be tilde expanded, or we're not - at the start of a word or after an unquoted : or = in an - assignment statement, we don't do tilde expansion. */ - if ((word->flags & (W_NOTILDE|W_DQUOTE)) || - (sindex > 0 && ((word->flags & W_ITILDE) == 0)) || - (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - { - word->flags &= ~W_ITILDE; - goto add_character; - } - - if (word->flags & W_ASSIGNRHS) - tflag = 2; - else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP)) - tflag = 1; - else - tflag = 0; - - temp = bash_tilde_find_word (string + sindex, tflag, &t_index); - - word->flags &= ~W_ITILDE; - - if (temp && *temp && t_index > 0) - { - temp1 = bash_tilde_expand (temp, tflag); - if (temp1 && *temp1 == '~' && STREQ (temp, temp1)) - { - FREE (temp); - FREE (temp1); - goto add_character; /* tilde expansion failed */ - } - free (temp); - temp = temp1; - sindex += t_index; - goto add_quoted_string; /* XXX was add_string */ - } - else - { - FREE (temp); - goto add_character; - } - - case '$': - if (expanded_something) - *expanded_something = 1; - - has_dollar_at = 0; - tword = param_expand (string, &sindex, quoted, expanded_something, - &has_dollar_at, "ed_dollar_at, - &had_quoted_null, - (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0); - - if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal) - { - free (string); - free (istring); - return ((tword == &expand_wdesc_error) ? &expand_word_error - : &expand_word_fatal); - } - if (contains_dollar_at && has_dollar_at) - *contains_dollar_at = 1; - - if (tword && (tword->flags & W_HASQUOTEDNULL)) - had_quoted_null = 1; - - temp = tword->word; - dispose_word_desc (tword); - - goto add_string; - break; - - case '`': /* Backquoted command substitution. */ - { - t_index = sindex++; - - temp = string_extract (string, &sindex, "`", SX_REQMATCH); - /* The test of sindex against t_index is to allow bare instances of - ` to pass through, for backwards compatibility. */ - if (temp == &extract_string_error || temp == &extract_string_fatal) - { - if (sindex - 1 == t_index) - { - sindex = t_index; - goto add_character; - } - report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index); - free (string); - free (istring); - return ((temp == &extract_string_error) ? &expand_word_error - : &expand_word_fatal); - } - - if (expanded_something) - *expanded_something = 1; - - if (word->flags & W_NOCOMSUB) - /* sindex + 1 because string[sindex] == '`' */ - temp1 = substring (string, t_index, sindex + 1); - else - { - de_backslash (temp); - tword = command_substitute (temp, quoted); - temp1 = tword ? tword->word : (char *)NULL; - if (tword) - dispose_word_desc (tword); - } - 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)) || (word->flags & W_DQUOTE)) -#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 = alloc_word_desc (); - tword->word = temp; - - temp = (char *)NULL; - - has_dollar_at = 0; - /* Need to get W_HASQUOTEDNULL flag through this function. */ - 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 (list && list->word && (list->word->flags & W_HASQUOTEDNULL)) - had_quoted_null = 1; - - 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); - tflag = list->word->flags; - dispose_words (list); - - /* 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. */ - /* We use the W_HASQUOTEDNULL flag to differentiate the - cases: a quoted null character as above and when - CTLNUL is contained in the (non-null) expansion - of some variable. We use the had_quoted_null flag to - pass the value through this function to its caller. */ - if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0) - remove_quoted_nulls (temp); /* XXX */ - } - } - 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)) || (word->flags & W_DQUOTE)) -#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); - tword->flags |= W_HASQUOTEDNULL; /* XXX */ - 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); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - list = make_word_list (tword, (WORD_LIST *)NULL); - } -#else - else - list = (WORD_LIST *)NULL; -#endif - } - else if (word->flags & W_NOSPLIT) - { - tword = make_bare_word (istring); - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; /* XXX */ - if (word->flags & W_COMPASSIGN) - tword->flags |= W_COMPASSIGN; /* XXX */ - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; /* XXX */ - if (word->flags & W_NOEXPAND) - tword->flags |= W_NOEXPAND; /* XXX */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - if (had_quoted_null) - tword->flags |= W_HASQUOTEDNULL; - list = make_word_list (tword, (WORD_LIST *)NULL); - } - 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); - 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_COMPASSIGN) - tword->flags |= W_COMPASSIGN; - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; - if (word->flags & W_NOEXPAND) - tword->flags |= W_NOEXPAND; - if (had_quoted_null) - tword->flags |= W_HASQUOTEDNULL; /* XXX */ - list = make_word_list (tword, (WORD_LIST *)NULL); - } - } - - 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 (c == 0) - { - *r++ = '\\'; - break; - } - 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 = alloc_word_desc (); - w->word = t ? t : savestring (""); - 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, *e; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); -#if 0 - result = (WORD_LIST *) list_append (result, tresult); -#else - if (result == 0) - result = e = tresult; - else - { - e->next = tresult; - while (e->next) - e = e->next; - } -#endif - } - 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)) ? value_cell (v) : " \t\n"; - - /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet - handle multibyte chars in IFS */ - memset (ifs_cmap, '\0', sizeof (ifs_cmap)); - for (t = ifs_value ; t && *t; t++) - { - uc = *t; - ifs_cmap[uc] = 1; - } - -#if defined (HANDLE_MULTIBYTE) - if (ifs_value == 0) - { - ifs_firstc[0] = '\0'; - ifs_firstc_len = 1; - } - else - { - size_t ifs_len; - ifs_len = strnlen (ifs_value, MB_CUR_MAX); - ifs_firstc_len = MBLEN (ifs_value, ifs_len); - if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len)) - { - ifs_firstc[0] = ifs_value[0]; - ifs_firstc[1] = '\0'; - ifs_firstc_len = 1; - } - else - memcpy (ifs_firstc, ifs_value, ifs_firstc_len); - } -#else - ifs_firstc = ifs_value ? *ifs_value : 0; -#endif -} - -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, *e; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = word_split (t->word, ifs_value); - if (result == 0) - result = e = tresult; - else - { - e->next = tresult; - while (e->next) - e = e->next; - } - } - 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; - assigning_in_environment = 0; - - top_level_cleanup (); /* from sig.c */ - 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); - exp_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; - -#if defined (ARRAY_VARS) - /* If this is a compound array assignment to a builtin that accepts - such assignments (e.g., `declare'), take the assignment and perform - it separately, handling the semantics of declarations inside shell - functions. This avoids the double-evaluation of such arguments, - because `declare' does some evaluation of compound assignments on - its own. */ - if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) - { - int t; - - t = do_word_assignment (tlist->word); - if (t == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - - /* Now transform the word as ksh93 appears to do and go on */ - t = assignment (tlist->word->word, 0); - tlist->word->word[t] = '\0'; - tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG); - } -#endif - - 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_word_assignment (temp_list->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_wassign_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_word_assignment; - tempenv_assign_error = 0; - - for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; - assigning_in_environment = (assign_func == assign_in_env); - tint = (*assign_func) (temp_list->word); - assigning_in_environment = 0; - /* Variable assignment errors in non-interactive shells running - in Posix.2 mode cause the shell to exit. */ - if (tint == 0) - { - if (assign_func == do_word_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); - } - else - tempenv_assign_error++; - } - } - - 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 4d1db1f56..000000000 --- a/subst.c~ +++ /dev/null @@ -1,8687 +0,0 @@ -/* subst.c -- The part of the shell that does parameter, command, arithmetic, - 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-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include "config.h" - -#include "bashtypes.h" -#include -#include "chartypes.h" -#if defined (HAVE_PWD_H) -# include -#endif -#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 "builtins/builtext.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_ASSOCVAR 4 - -#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 `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]; - -#if defined (HANDLE_MULTIBYTE) -unsigned char ifs_firstc[MB_LEN_MAX]; -size_t ifs_firstc_len; -#else -unsigned char ifs_firstc; -#endif - -int assigning_in_environment; - -/* 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, parse_and_execute_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; -extern int tempenv_assign_error; - -#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE) -extern wchar_t *wcsdup __P((const wchar_t *)); -#endif - -/* 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 WORD_DESC expand_wdesc_error, expand_wdesc_fatal; -static char expand_param_error, expand_param_fatal; -static char extract_string_error, extract_string_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 *make_quoted_char __P((int)); -static WORD_LIST *quote_list __P((WORD_LIST *)); - -static int unquoted_substring __P((char *, char *)); -static int unquoted_member __P((int, char *)); - -#if defined (ARRAY_VARS) -static SHELL_VAR *do_compound_assignment __P((char *, char *, int)); -#endif -static int do_assignment_internal __P((const WORD_DESC *, int)); - -static char *string_extract_verbatim __P((char *, size_t, int *, char *, int)); -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((const 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 *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((SHELL_VAR *, 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, 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 int chk_arithsub __P((const char *, int)); - -static WORD_DESC *parameter_brace_expand_word __P((char *, int, int)); -static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *)); -static WORD_DESC *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((SHELL_VAR *, 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 *pos_params_casemod __P((char *, char *, int, int)); -static char *parameter_brace_casemod __P((char *, char *, int, char *, int)); - -static WORD_DESC *parameter_brace_expand __P((char *, int *, int, int *, int *)); -static WORD_DESC *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 -#if defined (ARRAY_VARS) -static int make_internal_declare __P((char *, char *)); -#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 & SX_VARNAME) - is non-zero, and array variables have been compiled into the shell, - everything between a `[' and a corresponding `]' is skipped over. - If (flags & SX_NOALLOC) is non-zero, don't return the substring, just - update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must - contain a closing character from CHARLIST. */ -static char * -string_extract (string, sindex, charlist, flags) - char *string; - int *sindex; - char *charlist; - int flags; -{ - register int c, i; - int found; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; - i = *sindex; - found = 0; - while (c = string[i]) - { - if (c == '\\') - { - if (string[i + 1]) - i++; - else - break; - } -#if defined (ARRAY_VARS) - else if ((flags & SX_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)) - { - found = 1; - break; - } - - ADVANCE_CHAR (string, slen, i); - } - - /* If we had to have a matching delimiter and didn't find one, return an - error and let the caller deal with it. */ - if ((flags & SX_REQMATCH) && found == 0) - { - *sindex = i; - return (&extract_string_error); - } - - temp = (flags & SX_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_command_subst (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_command_subst (string, &si, SX_NOALLOC); - else - ret = extract_dollar_brace_string (string, &si, 1, SX_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; - - /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0; - 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) - const 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, slen, sindex, charlist, flags) - char *string; - size_t slen; - int *sindex; - char *charlist; - int flags; -{ - register int i = *sindex; -#if defined (HANDLE_MULTIBYTE) - size_t clen; - wchar_t *wcharlist; -#endif - int c; - char *temp; - DECLARE_MBSTATE; - - if (charlist[0] == '\'' && charlist[1] == '\0') - { - temp = string_extract_single_quoted (string, sindex); - --*sindex; /* leave *sindex at separator character */ - return temp; - } - - i = *sindex; -#if 0 - /* See how the MBLEN and ADVANCE_CHAR macros work to understand why we need - this only if MB_CUR_MAX > 1. */ - slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 1; -#endif -#if defined (HANDLE_MULTIBYTE) - clen = strlen (charlist); - wcharlist = 0; -#endif - while (c = string[i]) - { -#if defined (HANDLE_MULTIBYTE) - size_t mblength; -#endif - if ((flags & SX_NOCTLESC) == 0 && c == CTLESC) - { - i += 2; - continue; - } - /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL - through, to protect the CTLNULs from later calls to - remove_quoted_nulls. */ - else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL) - { - i += 2; - continue; - } - -#if defined (HANDLE_MULTIBYTE) - mblength = MBLEN (string + i, slen - i); - if (mblength > 1) - { - wchar_t wc; - mblength = mbtowc (&wc, string + i, slen - i); - if (MB_INVALIDCH (mblength)) - { - if (MEMBER (c, charlist)) - break; - } - else - { - if (wcharlist == 0) - { - size_t len; - len = mbstowcs (wcharlist, charlist, 0); - if (len == -1) - len = 0; - wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1)); - mbstowcs (wcharlist, charlist, len + 1); - } - - if (wcschr (wcharlist, wc)) - break; - } - } - else -#endif - if (MEMBER (c, charlist)) - break; - - ADVANCE_CHAR (string, slen, i); - } - -#if defined (HANDLE_MULTIBYTE) - FREE (wcharlist); -#endif - - 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 ")". ) - XFLAGS is additional flags to pass to other extraction functions, */ -char * -extract_command_subst (string, sindex, xflags) - char *string; - int *sindex; - int xflags; -{ - if (string[*sindex] == '(') /*)*/ - return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/ - else - { - xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0); - return (xparse_dolparen (string, string+*sindex, sindex, xflags)); - } -} - -/* 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) -/* This can be fooled by unquoted right parens in the passed string. If - each caller verifies that the last character in STRING is a right paren, - we don't even need to call extract_delimited_string. */ -char * -extract_array_assignment_list (string, sindex) - char *string; - int *sindex; -{ - int slen; - char *ret; - - slen = strlen (string); /* ( */ - if (string[slen - 1] == ')') - { - ret = substring (string, *sindex, slen - 1); - *sindex = slen - 1; - return ret; - } - return 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, in_comment; - 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 = in_comment = 0; - - nesting_level = 1; - i = *sindex; - - while (nesting_level) - { - c = string[i]; - - if (c == 0) - break; - - if (in_comment) - { - if (c == '\n') - in_comment = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - if (pass_character) /* previous char was backslash */ - { - pass_character = 0; - ADVANCE_CHAR (string, slen, i); - continue; - } - - /* Not exactly right yet; should handle shell metacharacters and - multibyte characters, too. */ - if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1]))) - { - in_comment = 1; - 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|SX_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|SX_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|SX_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 & SX_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|SX_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_command_subst (string, &si, flags|SX_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 & SX_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 - -#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0) - -/* 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, flags) - char *string; - int start; - char *delims; - int flags; -{ - int i, pass_next, backq, si, c, invert; - size_t slen; - char *temp; - DECLARE_MBSTATE; - - slen = strlen (string + start) + start; - if (flags & SD_NOJMP) - no_longjmp_on_fatal_error = 1; - invert = (flags & SD_INVERT); - - 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 (invert == 0 && member (c, delims)) - break; - 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, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */ - else - temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC); - i = si; - if (string[i] == '\0') /* don't increment i past EOS in loop */ - break; - i++; - continue; - } - else if (invert && (member (c, delims) == 0)) - break; - else - ADVANCE_CHAR (string, slen, i); - } - - CQ_RETURN(i); -} - -#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. */ - -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); -} - -/* 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) - { - size_t slength; -#if defined (HANDLE_MULTIBYTE) - size_t mblength = 1; -#endif - DECLARE_MBSTATE; - - slength = strlen (delims); - d2 = (char *)xmalloc (slength + 1); - i = ts = 0; - while (delims[i]) - { -#if defined (HANDLE_MULTIBYTE) - mbstate_t state_bak; - state_bak = state; - mblength = MBRLEN (delims + i, slength, &state); - if (MB_INVALIDCH (mblength)) - state = state_bak; - else if (mblength > 1) - { - memcpy (d2 + ts, delims + i, mblength); - ts += mblength; - i += mblength; - slength -= mblength; - continue; - } -#endif - if (whitespace (delims[i]) == 0) - d2[ts++] = delims[i]; - - i++; - slength--; - } - 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, SD_NOJMP); - - /* 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, " ")); -} - -/* An external interface that can be used by the rest of the shell to - obtain a string containing the first character in $IFS. Handles all - the multibyte complications. If LENP is non-null, it is set to the - length of the returned string. */ -char * -ifs_firstchar (lenp) - int *lenp; -{ - char *ret; - int len; - - ret = xmalloc (MB_LEN_MAX + 1); -#if defined (HANDLE_MULTIBYTE) - if (ifs_firstc_len == 1) - { - ret[0] = ifs_firstc[0]; - ret[1] = '\0'; - len = ret[0] ? 1 : 0; - } - else - { - memcpy (ret, ifs_firstc, ifs_firstc_len); - ret[len = ifs_firstc_len] = '\0'; - } -#else - ret[0] = ifs_firstc; - ret[1] = '\0'; - len = ret[0] ? 0 : 1; -#endif - - if (lenp) - *lenp = len; - - return ret; -} - -/* 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 *ret; -#if defined (HANDLE_MULTIBYTE) -# if defined (__GNUC__) - char sep[MB_CUR_MAX + 1]; -# else - char *sep = 0; -# endif -#else - char sep[2]; -#endif - -#if defined (HANDLE_MULTIBYTE) -# if !defined (__GNUC__) - sep = (char *)xmalloc (MB_CUR_MAX + 1); -# endif /* !__GNUC__ */ - if (ifs_firstc_len == 1) - { - sep[0] = ifs_firstc[0]; - sep[1] = '\0'; - } - else - { - memcpy (sep, ifs_firstc, ifs_firstc_len); - sep[ifs_firstc_len] = '\0'; - } -#else - sep[0] = ifs_firstc; - sep[1] = '\0'; -#endif - - ret = string_list_internal (list, sep); -#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) - free (sep); -#endif - return ret; -} - -/* 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, *ret; -#if defined (HANDLE_MULTIBYTE) -# if defined (__GNUC__) - char sep[MB_CUR_MAX + 1]; -# else - char *sep = 0; -# endif /* !__GNUC__ */ -#else - char sep[2]; -#endif - WORD_LIST *tlist; - - /* XXX this could just be ifs = ifs_value; */ - ifs = ifs_var ? value_cell (ifs_var) : (char *)0; - -#if defined (HANDLE_MULTIBYTE) -# if !defined (__GNUC__) - sep = (char *)xmalloc (MB_CUR_MAX + 1); -# endif /* !__GNUC__ */ - if (ifs && *ifs) - { - if (ifs_firstc_len == 1) - { - sep[0] = ifs_firstc[0]; - sep[1] = '\0'; - } - else - { - memcpy (sep, ifs_firstc, ifs_firstc_len); - sep[ifs_firstc_len] = '\0'; - } - } - else - { - sep[0] = ' '; - sep[1] = '\0'; - } -#else - sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs; - sep[1] = '\0'; -#endif - - /* XXX -- why call quote_list if ifs == 0? we can get away without doing - it now that quote_escapes quotes spaces */ -#if 0 - tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0)) -#else - tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) -#endif - ? quote_list (list) - : list_quote_escapes (list); - - ret = string_list_internal (tlist, sep); -#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) - free (sep); -#endif - return ret; -} - -/* Turn the positional paramters into a string, understanding quoting and - the various subtleties of using the first character of $IFS as the - separator. Calls string_list_dollar_at, string_list_dollar_star, and - string_list as appropriate. */ -char * -string_list_pos_params (pchar, list, quoted) - int pchar; - WORD_LIST *list; - int quoted; -{ - char *ret; - WORD_LIST *tlist; - - if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES)) - { - tlist = quote_list (list); - word_list_remove_quoted_nulls (tlist); - ret = string_list_dollar_star (tlist); - } - else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT)) - { - tlist = quote_list (list); - word_list_remove_quoted_nulls (tlist); - ret = string_list (tlist); - } - else if (pchar == '*') - { - /* Even when unquoted, string_list_dollar_star does the right thing - making sure that the first character of $IFS is used as the - separator. */ - ret = string_list_dollar_star (list); - } - else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - /* We use string_list_dollar_at, but only if the string is quoted, since - that quotes the escapes if it's not, which we don't want. We could - use string_list (the old code did), but that doesn't do the right - thing if the first character of $IFS is not a space. We use - string_list_dollar_star if the string is unquoted so we make sure that - the elements of $@ are separated by the first character of $IFS for - later splitting. */ - ret = string_list_dollar_at (list, quoted); - else if (pchar == '@') - ret = string_list_dollar_star (list); - else - ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list); - - return ret; -} - -/* 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, xflags; - size_t slen; - - if (!string || !*string) - return ((WORD_LIST *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - for (xflags = 0, s = ifs_value; s && *s; s++) - { - if (*s == CTLESC) xflags |= SX_NOCTLESC; - else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; - } - - slen = 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. */ - slen = (MB_CUR_MAX > 1) ? strlen (string) : 1; - for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; ) - { - /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim - unless multibyte chars are possible. */ - current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags); - 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 = alloc_word_desc (); - t->word = make_quoted_char ('\0'); - t->flags |= W_QUOTED|W_HASQUOTEDNULL; - 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); - result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */ - 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 = alloc_word_desc (); - t->word = make_quoted_char ('\0'); - t->flags |= W_QUOTED|W_HASQUOTEDNULL; - 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]) - { - DECLARE_MBSTATE; - ADVANCE_CHAR (string, slen, 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++; - /* An IFS character that is not IFS white space, along with any - adjacent IFS white space, shall delimit a field. (SUSv3) */ - while (string[sindex] && spctabnl (string[sindex]) && isifs (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, xflags; - size_t slen; - - if (!stringp || !*stringp || !**stringp) - return ((char *)NULL); - - sh_style_split = separators && separators[0] == ' ' && - separators[1] == '\t' && - separators[2] == '\n' && - separators[3] == '\0'; - for (xflags = 0, s = ifs_value; s && *s; s++) - { - if (*s == CTLESC) xflags |= SX_NOCTLESC; - if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; - } - - s = *stringp; - slen = 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; - /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim - unless multibyte chars are possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (s) : 1; - current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags); - - /* 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]) - { - DECLARE_MBSTATE; - ADVANCE_CHAR (s, slen, 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++; - /* An IFS character that is not IFS white space, along with any adjacent - IFS white space, shall delimit a field. */ - while (s[sindex] && spctabnl (s[sindex]) && isifs (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 */ -/* */ -/********************************************************/ - -#if defined (ARRAY_VARS) -static SHELL_VAR * -do_compound_assignment (name, value, flags) - char *name, *value; - int flags; -{ - SHELL_VAR *v; - int mklocal, mkassoc; - WORD_LIST *list; - - mklocal = flags & ASS_MKLOCAL; - mkassoc = flags & ASS_MKASSOC; - - if (mklocal && variable_context) - { - v = find_variable (name); - list = expand_compound_array_assignment (v, value, flags); - if (mkassoc) - v = make_local_assoc_variable (name); - else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context) - v = make_local_array_variable (name); - assign_compound_array_list (v, list, flags); - } - else - v = assign_array_from_string (name, value, flags); - - return (v); -} -#endif - -/* 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 (word, expand) - const WORD_DESC *word; - int expand; -{ - int offset, tlen, appendop, assign_list, aflags, retval; - char *name, *value; - SHELL_VAR *entry; -#if defined (ARRAY_VARS) - char *t; - int ni; -#endif - const char *string; - - if (word == 0 || word->word == 0) - return 0; - - appendop = assign_list = aflags = 0; - string = word->word; - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - char *temp; - - if (name[offset - 1] == '+') - { - appendop = 1; - name[offset - 1] = '\0'; - } - - name[offset] = 0; /* might need this set later */ - temp = name + offset + 1; - tlen = STRLEN (temp); - -#if defined (ARRAY_VARS) - if (expand && (word->flags & W_COMPASSIGN)) - { - assign_list = ni = 1; - value = extract_array_assignment_list (temp, &ni); - } - else -#endif - - if (expand && temp[0]) - value = expand_string_if_necessary (temp, 0, expand_string_assignment); - else - value = savestring (temp); - } - - if (value == 0) - { - value = (char *)xmalloc (1); - value[0] = '\0'; - } - - if (echo_command_at_execute) - { - if (appendop) - name[offset - 1] = '+'; - xtrace_print_assignment (name, value, assign_list, 1); - if (appendop) - name[offset - 1] = '\0'; - } - -#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0) - - if (appendop) - aflags |= ASS_APPEND; - -#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, aflags); - if (entry == 0) - ASSIGN_RETURN (0); - } - else if (assign_list) - { - if (word->flags & W_ASSIGNARG) - aflags |= ASS_MKLOCAL; - if (word->flags & W_ASSIGNASSOC) - aflags |= ASS_MKASSOC; - entry = do_compound_assignment (name, value, aflags); - } - else -#endif /* ARRAY_VARS */ - entry = bind_variable (name, value, aflags); - - stupidly_hack_special_variables (name); - -#if 1 - /* Return 1 if the assignment seems to have been performed correctly. */ - if (entry == 0 || readonly_p (entry)) - retval = 0; /* assignment failure */ - else if (noassign_p (entry)) - { - last_command_exit_value = EXECUTION_FAILURE; - retval = 1; /* error status, but not assignment failure */ - } - else - retval = 1; - - if (entry && retval != 0 && noassign_p (entry) == 0) - VUNSETATTR (entry, att_invisible); - - ASSIGN_RETURN (retval); -#else - if (entry) - VUNSETATTR (entry, att_invisible); - - ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0); -#endif -} - -/* Perform the assignment statement in STRING, and expand the - right side by doing tilde, command and parameter expansion. */ -int -do_assignment (string) - char *string; -{ - WORD_DESC td; - - td.flags = W_ASSIGNMENT; - td.word = string; - - return do_assignment_internal (&td, 1); -} - -int -do_word_assignment (word) - WORD_DESC *word; -{ - return do_assignment_internal (word, 1); -} - -/* Given STRING, an assignment string, get the value of the right side - of the `=', and bind it to the left side. Do not perform any word - expansions on the right hand side. */ -int -do_assignment_no_expand (string) - char *string; -{ - WORD_DESC td; - - td.flags = W_ASSIGNMENT; - td.word = string; - - return (do_assignment_internal (&td, 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); - - if (start == 0) /* handle ${@:0[:x]} specially */ - { - t = make_word_list (make_word (dollar_vars[0]), params); - save = params = t; - } - - 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; - - ret = string_list_pos_params (string[0], h, quoted); - - 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 || s == '~') -#else -#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~') -#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; - - /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? strlen (string) : 0; - 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)); -} - -char * -expand_assignment_string_to_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_to_string_internal (string, quoted, expand_string_assignment)); -} - -char * -expand_arith_string (string, quoted) - char *string; - int quoted; -{ - return (expand_string_if_necessary (string, quoted, expand_string)); -} - -#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 1, 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. If - SPECIAL is 2, this is an rhs argument for the =~ operator, and should - be quoted appropriately for regcomp/regexec. The caller is responsible - for removing the backslashes if the unquoted word is needed later. */ -char * -cond_expand_word (w, special) - WORD_DESC *w; - int special; -{ - char *r, *p; - WORD_LIST *l; - int qflags; - - if (w->word == 0 || w->word[0] == '\0') - return ((char *)NULL); - - 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 - { - qflags = QGLOB_CVTNULL; - if (special == 2) - qflags |= QGLOB_REGEXP; - p = string_list (l); - r = quote_string_for_globbing (p, qflags); - 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); - value->word->flags &= ~W_HASQUOTEDNULL; - } - dequote_list (value); - } - return (value); -} - -/* Expand the rhs of an assignment statement */ -WORD_LIST * -expand_string_assignment (string, quoted) - char *string; - int quoted; -{ - WORD_DESC td; - WORD_LIST *value; - - if (string == 0 || *string == '\0') - return ((WORD_LIST *)NULL); - - expand_no_split_dollar_star = 1; - - td.flags = W_ASSIGNRHS; - td.word = savestring (string); - value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL); - FREE (td.word); - - expand_no_split_dollar_star = 0; - - if (value) - { - if (value->word) - { - remove_quoted_nulls (value->word->word); - value->word->flags &= ~W_HASQUOTEDNULL; - } - 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, wflags) - char *string; - int quoted; - int wflags; -{ - WORD_LIST *value; - WORD_DESC td; - - if (string == 0 || *string == 0) - return ((WORD_LIST *)NULL); - - td.flags = wflags; - 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); - value->word->flags &= ~W_HASQUOTEDNULL; - } - 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 (word splitting - and filename generation). If IFS is null, we quote spaces as well, just - in case we split on spaces later (in the case of unquoted $@, we will - eventually attempt to split the entire word on spaces). Corresponding - code exists in dequote_escapes. Even if we don't end up splitting on - spaces, quoting spaces is not a problem. This should never be called on - a string that is quoted with single or double quotes or part of a here - document (effectively double-quoted). */ -char * -quote_escapes (string) - char *string; -{ - register char *s, *t; - size_t slen; - char *result, *send; - int quote_spaces, skip_ctlesc, skip_ctlnul; - DECLARE_MBSTATE; - - slen = strlen (string); - send = string + slen; - - quote_spaces = (ifs_value && *ifs_value == 0); - - for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++) - skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL; - - t = result = (char *)xmalloc ((slen * 2) + 1); - s = string; - - while (*s) - { - if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' ')) - *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. */ -char * -dequote_escapes (string) - char *string; -{ - register char *s, *t, *s1; - size_t slen; - char *result, *send; - int quote_spaces; - DECLARE_MBSTATE; - - if (string == 0) - return string; - - slen = strlen (string); - send = string + slen; - - t = result = (char *)xmalloc (slen + 1); - - if (strchr (string, CTLESC) == 0) - return (strcpy (result, string)); - - quote_spaces = (ifs_value && *ifs_value == 0); - - s = string; - while (*s) - { - if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' '))) - { - 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. - This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be - set in any resultant WORD_DESC where this value is the word. */ -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, returning a new string. This turns "" into QUOTED_NULL, so - the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where - this value is the word. */ -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-quote 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); - if (*t == 0) - w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */ - w->word->flags |= W_QUOTED; - free (t); - } - return list; -} - -/* De-quote quoted characters in each word in LIST. */ -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); - if (QUOTED_NULL (tlist->word->word)) - tlist->word->flags &= ~W_HASQUOTEDNULL; - free (tlist->word->word); - tlist->word->word = s; - } - return list; -} - -/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed - string. */ -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. */ -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); - t->word->flags &= ~W_HASQUOTEDNULL; - } -} - -/* **************************************************************** */ -/* */ -/* 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 * -remove_wpattern (wparam, wstrlen, wpattern, op) - wchar_t *wparam; - size_t wstrlen; - wchar_t *wpattern; - int op; -{ - wchar_t wc, *ret; - int n; - - 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 = (char *)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, *npat; - char *end; - - /* If the pattern doesn't match anywhere in the string, go ahead and - short-circuit right away. A minor optimization, saves a bunch of - unnecessary calls to strmatch (up to N calls for a string of N - characters) if the match is unsuccessful. To preserve the semantics - of the substring matches below, we make sure that the pattern has - `*' as first and last character, making a new pattern if necessary. */ - /* XXX - check this later if I ever implement `**' with special meaning, - since this will potentially result in `**' at the beginning or end */ - len = STRLEN (pat); - if (pat[0] != '*' || pat[len - 1] != '*') - { - p = npat = (char *)xmalloc (len + 3); - p1 = pat; - if (*p1 != '*') - *p++ = '*'; - while (*p1) - *p++ = *p1++; - if (p1[-1] != '*' || p[-2] == '\\') - *p++ = '*'; - *p = '\0'; - } - else - npat = pat; - c = strmatch (npat, string, FNMATCH_EXTFLAG); - if (npat != pat) - free (npat); - if (c == FNM_NOMATCH) - return (0); - - 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, *wp, *nwpat, *wp1; - int len; -#if 0 - size_t n, n1; /* Apple's gcc seems to miscompile this badly */ -#else - int n, n1; -#endif - - /* If the pattern doesn't match anywhere in the string, go ahead and - short-circuit right away. A minor optimization, saves a bunch of - unnecessary calls to strmatch (up to N calls for a string of N - characters) if the match is unsuccessful. To preserve the semantics - of the substring matches below, we make sure that the pattern has - `*' as first and last character, making a new pattern if necessary. */ - /* XXX - check this later if I ever implement `**' with special meaning, - since this will potentially result in `**' at the beginning or end */ - len = wcslen (wpat); - if (wpat[0] != L'*' || wpat[len - 1] != L'*') - { - wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t)); - wp1 = wpat; - if (*wp1 != L'*') - *wp++ = L'*'; - while (*wp1 != L'\0') - *wp++ = *wp1++; - if (wp1[-1] != L'*' || wp1[-2] == L'\\') - *wp++ = L'*'; - *wp = '\0'; - } - else - nwpat = wpat; - len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG); - if (nwpat != wpat) - free (nwpat); - if (len == FNM_NOMATCH) - return (0); - - 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; -#if 0 - int i; -#endif - /* 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 = *value ? expand_string_for_rhs (value, - (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted, - (int *)NULL, (int *)NULL) - : (WORD_LIST *)0; - 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 = alloc_word_desc (); - w->word = tword ? tword : savestring (""); - new = make_word_list (w, new); - } - - l = REVERSE_LIST (new, WORD_LIST *); - tword = string_list_pos_params (itype, l, quoted); - 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 (var, pattern, patspec, varname, quoted) - SHELL_VAR *var; - char *pattern; - int patspec; - char *varname; /* so we can figure out how it's indexed */ - int quoted; -{ - ARRAY *a; - HASH_TABLE *h; - 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]; - - a = (v && array_p (v)) ? array_cell (v) : 0; - h = (v && assoc_p (v)) ? assoc_cell (v) : 0; - - list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0); - 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++; - - /* Need to pass getpattern newly-allocated memory in case of expansion -- - the expansion code will free the passed string on an error. */ - temp1 = savestring (patstr); - pattern = getpattern (temp1, quoted, 1); - free (temp1); - - 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 = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - ? quote_string (temp1) - : quote_escapes (temp1); - free (temp1); - temp1 = val; - } - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp1 = array_remove_pattern (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; -} - -int -fifos_pending () -{ - return nfifo; -} - -static char * -make_named_pipe () -{ - char *tname; - - tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR); - 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++; -} - -int -fifos_pending () -{ - return 0; /* used for cleanup; not needed with /dev/fd */ -} - -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 == 0) - { - 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|SUBSHELL_PROCSUB; - } - -#if defined (JOB_CONTROL) - set_sigchld_handler (); - stop_making_children (); - /* XXX - should we only do this in the parent? (as in command subst) */ - 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 (_("cannot 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, rflag) - int fd, quoted; - int *rflag; -{ - char *istring, buf[128], *bufp, *s; - int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul; - ssize_t bufn; - - istring = (char *)NULL; - istring_index = istring_size = bufn = tflag = 0; - - for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++) - skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL; - -#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. This may need to be - changed to understand multibyte characters in the future. */ - 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); - - /* This is essentially quote_string inline */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */) - istring[istring_index++] = CTLESC; - /* Escape CTLESC and CTLNUL in the output to protect those characters - from the rest of the word expansions (word splitting and globbing.) - This is essentially quote_escapes inline. */ - else if (skip_ctlesc == 0 && c == CTLESC) - { - tflag |= W_HASCTLESC; - istring[istring_index++] = CTLESC; - } - else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0))) - 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); - if (rflag) - *rflag = tflag; - 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); - - if (rflag) - *rflag = tflag; - return istring; -} - -/* Perform command substitution on STRING. This returns a WORD_DESC * with the - contained string possibly quoted. */ -WORD_DESC * -command_substitute (string, quoted) - char *string; - int quoted; -{ - pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid; - char *istring; - int result, fildes[2], function_value, pflags, rc, tflag; - WORD_DESC *ret; - - 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 ((WORD_DESC *)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 /* JOB_CONTROL */ - - old_async_pid = last_asynchronous_pid; - pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC); - last_asynchronous_pid = old_async_pid; - - if (pid == 0) - /* Reset the signal handlers in the child, but don't free the - trap strings. */ - reset_signal_handlers (); - -#if defined (JOB_CONTROL) - /* XXX DO THIS ONLY IN PARENT ? XXX */ - set_sigchld_handler (); - stop_making_children (); - if (pid != 0) - 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 ((WORD_DESC *)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 (); -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif - exit (rc); - } - else - { -#if defined (JOB_CONTROL) && defined (PGRP_PIPE) - close_pgrp_pipe (); -#endif /* JOB_CONTROL && PGRP_PIPE */ - - close (fildes[1]); - - tflag = 0; - istring = read_comsub (fildes[0], quoted, &tflag); - - 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 */ - - ret = alloc_word_desc (); - ret->word = istring; - ret->flags = tflag; - - return ret; - } -} - -/******************************************************** - * * - * Utility functions for parameter expansion * - * * - ********************************************************/ - -#if defined (ARRAY_VARS) - -static arrayind_t -array_length_reference (s) - char *s; -{ - int len; - arrayind_t ind; - char *akey; - 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 || (assoc_p (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] == ']') - { - if (assoc_p (var)) - return (assoc_num_elements (assoc_cell (var))); - else if (array_p (var)) - return (array_num_elements (array)); - else - return 1; - } - - if (assoc_p (var)) - { - t[len - 1] = '\0'; - akey = expand_assignment_string_to_string (t, 0); /* [ */ - t[len - 1] = ']'; - if (akey == 0 || *akey == 0) - { - err_badarraysub (t); - return (-1); - } - t = assoc_reference (assoc_cell (var), akey); - } - else - { - 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 = MB_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 WORD_DESC * -parameter_brace_expand_word (name, var_is_special, quoted) - char *name; - int var_is_special, quoted; -{ - WORD_DESC *ret; - char *temp, *tt; - intmax_t arg_index; - SHELL_VAR *var; - int atype, rflags; - - ret = 0; - temp = 0; - rflags = 0; - - /* 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); - - ret = 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); - else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - rflags |= W_HASQUOTEDNULL; - } -#endif - else if (var = find_variable (name)) - { - if (var_isset (var) && invisible_p (var) == 0) - { -#if defined (ARRAY_VARS) - if (assoc_p (var)) - temp = assoc_reference (assoc_cell (var), "0"); - else if (array_p (var)) - temp = array_reference (array_cell (var), 0); - else - temp = 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; - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->word = temp; - ret->flags |= rflags; - } - return ret; -} - -/* Expand an indirect reference to a variable: ${!NAME} expands to the - value of the variable whose name is the value of NAME. */ -static WORD_DESC * -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; - WORD_DESC *w; - - w = parameter_brace_expand_word (name, var_is_special, quoted); - t = w->word; - /* 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; - } - dispose_word_desc (w); - - chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at); - if (t == 0) - return (WORD_DESC *)NULL; - - w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted); - free (t); - - return w; -} - -/* 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 WORD_DESC * -parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) - char *name, *value; - int c, quoted, *qdollaratp, *hasdollarat; -{ - WORD_DESC *w; - WORD_LIST *l; - char *t, *t1, *temp; - int hasdol; - - /* 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 (for sh backwards compatibility). */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value) - { - hasdol = 0; - temp = string_extract_double_quoted (value, &hasdol, 1); - } - else - temp = value; - - w = alloc_word_desc (); - 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); - if (temp != value) - 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 = make_quoted_char ('\0'); - w->flags |= W_HASQUOTEDNULL; - } - else - temp = (char *)NULL; - - if (c == '-' || c == '+') - { - w->word = temp; - return w; - } - - /* 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, 0); - else -#endif /* ARRAY_VARS */ - bind_variable (name, t1, 0); - free (t1); - - w->word = temp; - return w; -} - -/* 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) - { - l = expand_string (value, 0); - temp = string_list (l); - report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */ - FREE (temp); - dispose_words (l); - } - else - 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} */ -} - -#if defined (HANDLE_MULTIBYTE) -size_t -mbstrlen (s) - const char *s; -{ - size_t clen, nc; - mbstate_t mbs, mbsbak; - - nc = 0; - memset (&mbs, 0, sizeof (mbs)); - mbsbak = mbs; - while ((clen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0) - { - if (MB_INVALIDCH(clen)) - { - clen = 1; /* assume single byte */ - mbs = mbsbak; - } - - s += clen; - nc++; - mbsbak = mbs; - } - return nc; -} -#endif - - -/* 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 = MB_STRLEN (t); - FREE (t); - } -#if defined (ARRAY_VARS) - else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var))) - { - if (assoc_p (var)) - t = assoc_reference (assoc_cell (var), "0"); - else - t = array_reference (array_cell (var), 0); - number = MB_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 = MB_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 (v, value, substr, vtype, e1p, e2p) - SHELL_VAR *v; - char *value, *substr; - int vtype; - intmax_t *e1p, *e2p; -{ - char *t, *temp1, *temp2; - arrayind_t len; - int expok; -#if defined (ARRAY_VARS) - ARRAY *a; - HASH_TABLE *h; -#endif - - /* duplicate behavior of strchr(3) */ - t = skiparith (substr, ':'); - if (*t && *t == ':') - *t = '\0'; - else - t = (char *)0; - - temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES); - *e1p = evalexp (temp1, &expok); - free (temp1); - if (expok == 0) - return (0); - - len = -1; /* paranoia */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - len = MB_STRLEN (value); - break; - case VT_POSPARMS: - len = number_of_args () + 1; - if (*e1p == 0) - len++; /* add one arg if counting from $0 */ - break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - /* For arrays, the first value deals with array indices. Negative - offsets count from one past the array's maximum index. Associative - arrays treat the number of elements as the maximum index. */ - if (assoc_p (v)) - { - h = assoc_cell (v); - len = assoc_num_elements (h) + (*e1p < 0); - } - else - { - a = (ARRAY *)value; - len = array_max_index (a) + (*e1p < 0); /* 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 = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a); -#endif - - if (t) - { - t++; - temp2 = savestring (t); - temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES); - 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) || assoc_p (v))) - { /* [ */ - if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']') - { - /* Callers have to differentiate betwen indexed and associative */ - vtype = VT_ARRAYVAR; - if (temp[0] == '*') - vtype |= VT_STARSUB; - *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v); - } - else - { - vtype = VT_ARRAYMEMBER; - *valp = array_value (varname, 1, (int *)NULL); - } - *varp = v; - } - else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')) - { - vtype = VT_VARIABLE; - *varp = v; - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - *valp = dequote_string (value); - else - *valp = dequote_escapes (value); - } - else - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = array_value (varname, 1, (int *)NULL); - } - } - else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v))) - { - vtype = VT_ARRAYMEMBER; - *varp = v; - *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0); - } - else -#endif - { - 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; - } - - 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; - /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */ - slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0; - - 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, *oname; - SHELL_VAR *v; - - if (value == 0) - return ((char *)NULL); - - oname = this_command_name; - this_command_name = varname; - - vtype = get_var_and_type (varname, value, quoted, &v, &val); - if (vtype == -1) - { - this_command_name = oname; - return ((char *)NULL); - } - - starsub = vtype & VT_STARSUB; - vtype &= ~VT_STARSUB; - - r = verify_substring_values (v, val, substr, vtype, &e1, &e2); - this_command_name = oname; - 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: - if (assoc_p (v)) - /* we convert to list and take first e2 elements starting at e1th - element -- officially undefined for now */ - temp = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted); - else - /* 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). */ - temp = array_subrange (array_cell (v), e1, e2, starsub, quoted); - /* array_subrange now calls array_quote_escapes as appropriate, so the - caller no longer needs to. */ - 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; - int pchar, qflags; - - 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 = alloc_word_desc (); - w->word = ret ? ret : savestring (""); - dispose_word (params->word); - params->word = w; - } - - pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; - qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; - -#if 0 - if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB)) - ret = string_list_dollar_star (quote_list (save)); - else if ((mflags & MATCH_STARSUB) == MATCH_STARSUB) - ret = string_list_dollar_star (save); - else if ((mflags & MATCH_QUOTED) == MATCH_QUOTED) - ret = string_list_dollar_at (save, qflags); - else - ret = string_list_dollar_star (save); -#else - ret = string_list_pos_params (pchar, save, qflags); -#endif - - 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, delim; - 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 && *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 the pattern starts with a `/', make sure we skip over it when looking - for the replacement delimiter. */ -#if 0 - if (rep = quoted_strchr ((*patsub == '/') ? lpatsub+1 : lpatsub, '/', ST_BACKSL)) - *rep++ = '\0'; - else - rep = (char *)NULL; -#else - delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0); - if (lpatsub[delim] == '/') - { - lpatsub[delim] = 0; - rep = lpatsub + delim + 1; - } - else - rep = (char *)NULL; -#endif - - if (rep && *rep == '\0') - rep = (char *)NULL; - - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. */ - pat = getpattern (lpatsub, quoted, 1); - - 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); - } - - /* ksh93 doesn't allow the match specifier to be a part of the expanded - pattern. This is an extension. Make sure we don't anchor the pattern - at the beginning or end of the string if we're doing global replacement, - though. */ - p = pat; - if (mflags & MATCH_GLOBREP) - mflags |= MATCH_ANY; - else 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 = (mflags & MATCH_QUOTED) ? quote_string (temp) : 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 = assoc_p (v) ? assoc_patsub (assoc_cell (v), p, rep, mflags) - : array_patsub (array_cell (v), p, rep, mflags); - /* Don't call quote_escapes anymore; array_patsub calls - array_quote_escapes as appropriate before adding the - space separators; ditto for assoc_patsub. */ - break; -#endif - } - - FREE (pat); - FREE (rep); - free (lpatsub); - - return temp; -} - -/****************************************************************/ -/* */ -/* Functions to perform case modification on variable values */ -/* */ -/****************************************************************/ - -/* Do case modification on the positional parameters. */ - -static char * -pos_params_modcase (string, pat, modop, mflags) - char *string, *pat; - int modop; - int mflags; -{ - WORD_LIST *save, *params; - WORD_DESC *w; - char *ret; - int pchar, qflags; - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for ( ; params; params = params->next) - { - ret = sh_modcase (params->word->word, pat, modop); - w = alloc_word_desc (); - w->word = ret ? ret : savestring (""); - dispose_word (params->word); - params->word = w; - } - - pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; - qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; - - ret = string_list_pos_params (pchar, save, qflags); - dispose_words (save); - - return (ret); -} - -/* Perform case modification on VALUE, which is the expansion of - VARNAME. MODSPEC is an expression supplying the type of modification - to perform. QUOTED is a flags word containing the type of quoting - currently in effect. */ -static char * -parameter_brace_casemod (varname, value, modspec, patspec, quoted) - char *varname, *value; - int modspec; - char *patspec; - int quoted; -{ - int vtype, starsub, modop, mflags, x; - char *val, *temp, *pat, *p, *lpat, *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; - - modop = 0; - mflags = 0; - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - mflags |= MATCH_QUOTED; - if (starsub) - mflags |= MATCH_STARSUB; - - p = patspec; - if (modspec == '^') - { - x = p && p[0] == modspec; - modop = x ? CASE_UPPER : CASE_CAPITALIZE; - p += x; - } - else if (modspec == ',') - { - x = p && p[0] == modspec; - modop = x ? CASE_LOWER : CASE_UNCAP; - p += x; - } - else if (modspec == '~') - { - x = p && p[0] == modspec; - modop = x ? CASE_TOGGLEALL : CASE_TOGGLE; - p += x; - } - - lpat = p ? savestring (p) : 0; - /* Perform the same expansions on the pattern as performed by the - pattern removal expansions. FOR LATER */ - pat = lpat ? getpattern (lpat, quoted, 1) : 0; - - /* OK, now we do the case modification. */ - switch (vtype) - { - case VT_VARIABLE: - case VT_ARRAYMEMBER: - temp = sh_modcase (val, pat, modop); - if (vtype == VT_VARIABLE) - FREE (val); - if (temp) - { - tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp); - free (temp); - temp = tt; - } - break; - - case VT_POSPARMS: - temp = pos_params_modcase (val, pat, modop, mflags); - if (temp && (mflags & MATCH_QUOTED) == 0) - { - tt = quote_escapes (temp); - free (temp); - temp = tt; - } - break; - -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags) - : array_modcase (array_cell (v), pat, modop, mflags); - /* Don't call quote_escapes; array_modcase calls array_quote_escapes - as appropriate before adding the space separators; ditto for - assoc_modcase. */ - break; -#endif - } - - FREE (pat); - free (lpat); - - return temp; -} - -/* Check for unbalanced parens in S, which is the contents of $(( ... )). If - any occur, this must be a nested command substitution, so return 0. - Otherwise, return 1. A valid arithmetic expression must always have a - ( before a matching ), so any cases where there are more right parens - means that this must not be an arithmetic expression, though the parser - will not accept it without a balanced total number of parens. */ -static int -chk_arithsub (s, len) - const char *s; - int len; -{ - int i, count; - DECLARE_MBSTATE; - - i = count = 0; - while (i < len) - { - if (s[i] == '(') - count++; - else if (s[i] == ')') - { - count--; - if (count < 0) - return 0; - } - - switch (s[i]) - { - default: - ADVANCE_CHAR (s, len, i); - break; - - case '\\': - i++; - if (s[i]) - ADVANCE_CHAR (s, len, i); - break; - - case '\'': - i = skip_single_quoted (s, len, ++i); - break; - - case '"': - i = skip_double_quoted ((char *)s, len, ++i); - break; - } - } - - return (count == 0); -} - -/****************************************************************/ -/* */ -/* Functions to perform parameter expansion on a string */ -/* */ -/****************************************************************/ - -/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */ -static WORD_DESC * -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, want_casemod; - char *name, *value, *temp, *temp1; - WORD_DESC *tdesc, *ret; - int t_index, sindex, c, tflag, modspec; - intmax_t number; - - temp = temp1 = value = (char *)NULL; - var_is_set = var_is_null = var_is_special = check_nullness = 0; - want_substring = want_indir = want_patsub = want_casemod = 0; - - sindex = *indexp; - t_index = ++sindex; - /* ${#var} doesn't have any of the other parameter expansions on it. */ - if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */ - name = string_extract (string, &t_index, "}", SX_VARNAME); - else -#if defined (CASEMOD_EXPANSIONS) - /* To enable case-toggling expansions using the `~' operator character - change the 1 to 0. */ -# if defined (CASEMOD_CAPCASE) - name = string_extract (string, &t_index, "#%^,~:-=?+/}", SX_VARNAME); -# else - name = string_extract (string, &t_index, "#%^,:-=?+/}", SX_VARNAME); -# endif /* CASEMOD_CAPCASE */ -#else - name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME); -#endif /* CASEMOD_EXPANSIONS */ - - ret = 0; - tflag = 0; - - /* 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; -#if defined (CASEMOD_EXPANSIONS) - else if (c == '^' || c == ',' || c == '~') - { - modspec = c; - want_casemod = 1; - } -#endif - - /* 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; - if (number < 0) - return (&expand_wdesc_error); - else - { - ret = alloc_word_desc (); - ret->word = itos (number); - return ret; - } - } - - /* ${@} 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; - - ret = alloc_word_desc (); - ret->word = temp; - return ret; - } - -#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); /* handles assoc vars too */ - 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; - - ret = alloc_word_desc (); - ret->word = temp; - return ret; - } - - 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) - tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at); - else - tdesc = parameter_brace_expand_word (name, var_is_special, quoted); - - if (tdesc) - { - temp = tdesc->word; - tflag = tdesc->flags; - dispose_word_desc (tdesc); - } - else - temp = (char *)0; - -#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); - - if (temp1 == &expand_param_error) - return (&expand_wdesc_error); - else if (temp1 == &expand_param_fatal) - return (&expand_wdesc_fatal); - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - return ret; - } - else if (want_patsub) - { - temp1 = parameter_brace_patsub (name, temp, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - - if (temp1 == &expand_param_error) - return (&expand_wdesc_error); - else if (temp1 == &expand_param_fatal) - return (&expand_wdesc_fatal); - - ret = alloc_word_desc (); - ret->word = temp1; - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - return ret; - } -#if defined (CASEMOD_EXPANSIONS) - else if (want_casemod) - { - temp1 = parameter_brace_casemod (name, temp, modspec, value, quoted); - FREE (name); - FREE (value); - FREE (temp); - - if (temp1 == &expand_param_error) - return (&expand_wdesc_error); - else if (temp1 == &expand_param_fatal) - return (&expand_wdesc_fatal); - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - return ret; - } -#endif - - /* 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_wdesc_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_wdesc_error : &expand_wdesc_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); - - ret = alloc_word_desc (); - ret->word = temp1; - if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ret->flags |= W_QUOTED|W_HASQUOTEDNULL; - return ret; - - 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) - { - ret = parameter_brace_expand_rhs (name, value, c, - quoted, - quoted_dollar_atp, - contains_dollar_at); - /* XXX - fix up later, esp. noting presence of - W_HASQUOTEDNULL in ret->flags */ - 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_wdesc_error; - } - else if (c == '?') - { - parameter_brace_expand_error (name, value); - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_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; - - ret = parameter_brace_expand_rhs (name, value, c, quoted, - quoted_dollar_atp, - contains_dollar_at); - /* XXX - fix up later, esp. noting presence of - W_HASQUOTEDNULL in tdesc->flags */ - } - free (value); - } - - break; - } - free (name); - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->flags = tflag; - ret->word = temp; - } - return (ret); -} - -/* 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 WORD_DESC * -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; - WORD_DESC *tdesc, *ret; - int tflag; - - zindex = *sindex; - c = string[++zindex]; - - temp = (char *)NULL; - ret = tdesc = (WORD_DESC *)NULL; - tflag = 0; - - /* 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_wdesc_error : &expand_wdesc_fatal); - } - if (temp1) - temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) - ? quote_string (temp1) - : quote_escapes (temp1); - else - temp = (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_wdesc_error : &expand_wdesc_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 (list == 0 && unbound_vars_is_error) - { - uerror[0] = '$'; - uerror[1] = '*'; - uerror[2] = '\0'; - err_unboundvar (uerror); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal); - } - - /* 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 = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (list) : string_list (list); - temp1 = quote_string (temp); - if (*temp == 0) - tflag |= W_HASQUOTEDNULL; - free (temp); - temp = temp1; - } - else - { - /* We check whether or not we're eventually going to split $* here, - for example when IFS is empty and we are processing the rhs of - an assignment statement. In that case, we don't separate the - arguments at all. Otherwise, if the $* is not quoted it is - identical to $@ */ -#if 1 -# if defined (HANDLE_MULTIBYTE) - if (expand_no_split_dollar_star && ifs_firstc[0] == 0) -# else - if (expand_no_split_dollar_star && ifs_firstc == 0) -# endif - temp = string_list_dollar_star (list); - else - temp = string_list_dollar_at (list, quoted); -#else - temp = string_list_dollar_at (list, quoted); -#endif - 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: - tdesc = parameter_brace_expand (string, &zindex, quoted, - quoted_dollar_at_p, - contains_dollar_at); - - if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) - return (tdesc); - temp = tdesc ? tdesc->word : (char *)0; - - /* 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 (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp)) - { - if (had_quoted_null_p) - *had_quoted_null_p = 1; - if (*quoted_dollar_at_p == 0) - { - free (temp); - tdesc->word = temp = (char *)NULL; - } - - } - - ret = tdesc; - 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, 0); - 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'; - - if (chk_arithsub (temp2, t_index) == 0) - { - free (temp2); - goto comsub; - } - - /* Expand variables found inside the expression. */ - temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES); - 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_wdesc_fatal); - } - else - return (&expand_wdesc_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 - { - tdesc = command_substitute (temp, quoted); - temp1 = tdesc ? tdesc->word : (char *)NULL; - if (tdesc) - dispose_word_desc (tdesc); - } - 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; - if (temp == 0) - { - temp = savestring (string); - if (expanded_something) - *expanded_something = 0; - goto return0; - } - - /* Do initial variable expansion. */ - temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES); - - 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 (assoc_p (var) || array_p (var)) - { - temp = array_p (var) ? array_reference (array_cell (var), 0) - : assoc_reference (assoc_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_wdesc_fatal - : &expand_wdesc_error); - } - - if (string[zindex]) - zindex++; - -return0: - *sindex = zindex; - - if (ret == 0) - { - ret = alloc_word_desc (); - ret->flags = tflag; /* XXX */ - ret->word = temp; - } - return ret; -} - -/* 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; - - /* State flags */ - int had_quoted_null; - int has_dollar_at; - int tflag; - - int assignoff; /* If assignment, offset of `=' */ - - 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; - /* Don't need the string length for the SADD... and COPY_ macros unless - multibyte characters are possible. */ - string_size = (MB_CUR_MAX > 1) ? strlen (string) : 1; - - if (contains_dollar_at) - *contains_dollar_at = 0; - - assignoff = -1; - - /* 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)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)) || 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 '=': - /* 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 (word->flags & (W_ASSIGNRHS|W_NOTILDE)) - goto add_character; - /* If we're not in posix mode or forcing assignment-statement tilde - expansion, note where the `=' appears in the word and prepare to - do tilde expansion following the first `='. */ - if ((word->flags & W_ASSIGNMENT) && - (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && - assignoff == -1 && sindex > 0) - assignoff = sindex; - if (sindex == assignoff && string[sindex+1] == '~') /* XXX */ - word->flags |= W_ITILDE; -#if 0 - else if ((word->flags & W_ASSIGNMENT) && - (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && - string[sindex+1] == '~') - word->flags |= W_ITILDE; -#endif - goto add_character; - - case ':': - if (word->flags & W_NOTILDE) - goto add_character; - - if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS|W_TILDEEXP)) && - string[sindex+1] == '~') - word->flags |= W_ITILDE; - goto add_character; - - case '~': - /* If the word isn't supposed to be tilde expanded, or we're not - at the start of a word or after an unquoted : or = in an - assignment statement, we don't do tilde expansion. */ - if ((word->flags & (W_NOTILDE|W_DQUOTE)) || - (sindex > 0 && ((word->flags & W_ITILDE) == 0)) || - (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) - { - word->flags &= ~W_ITILDE; - goto add_character; - } - - if (word->flags & W_ASSIGNRHS) - tflag = 2; - else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP)) - tflag = 1; - else - tflag = 0; - - temp = bash_tilde_find_word (string + sindex, tflag, &t_index); - - word->flags &= ~W_ITILDE; - - if (temp && *temp && t_index > 0) - { - temp1 = bash_tilde_expand (temp, tflag); - if (temp1 && *temp1 == '~' && STREQ (temp, temp1)) - { - FREE (temp); - FREE (temp1); - goto add_character; /* tilde expansion failed */ - } - free (temp); - temp = temp1; - sindex += t_index; - goto add_quoted_string; /* XXX was add_string */ - } - else - { - FREE (temp); - goto add_character; - } - - case '$': - if (expanded_something) - *expanded_something = 1; - - has_dollar_at = 0; - tword = param_expand (string, &sindex, quoted, expanded_something, - &has_dollar_at, "ed_dollar_at, - &had_quoted_null, - (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0); - - if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal) - { - free (string); - free (istring); - return ((tword == &expand_wdesc_error) ? &expand_word_error - : &expand_word_fatal); - } - if (contains_dollar_at && has_dollar_at) - *contains_dollar_at = 1; - - if (tword && (tword->flags & W_HASQUOTEDNULL)) - had_quoted_null = 1; - - temp = tword->word; - dispose_word_desc (tword); - - goto add_string; - break; - - case '`': /* Backquoted command substitution. */ - { - t_index = sindex++; - - temp = string_extract (string, &sindex, "`", SX_REQMATCH); - /* The test of sindex against t_index is to allow bare instances of - ` to pass through, for backwards compatibility. */ - if (temp == &extract_string_error || temp == &extract_string_fatal) - { - if (sindex - 1 == t_index) - { - sindex = t_index; - goto add_character; - } - report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index); - free (string); - free (istring); - return ((temp == &extract_string_error) ? &expand_word_error - : &expand_word_fatal); - } - - if (expanded_something) - *expanded_something = 1; - - if (word->flags & W_NOCOMSUB) - /* sindex + 1 because string[sindex] == '`' */ - temp1 = substring (string, t_index, sindex + 1); - else - { - de_backslash (temp); - tword = command_substitute (temp, quoted); - temp1 = tword ? tword->word : (char *)NULL; - if (tword) - dispose_word_desc (tword); - } - 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)) || (word->flags & W_DQUOTE)) -#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 = alloc_word_desc (); - tword->word = temp; - - temp = (char *)NULL; - - has_dollar_at = 0; - /* Need to get W_HASQUOTEDNULL flag through this function. */ - 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 (list && list->word && (list->word->flags & W_HASQUOTEDNULL)) - had_quoted_null = 1; - - 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); - tflag = list->word->flags; - dispose_words (list); - - /* 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. */ - /* We use the W_HASQUOTEDNULL flag to differentiate the - cases: a quoted null character as above and when - CTLNUL is contained in the (non-null) expansion - of some variable. We use the had_quoted_null flag to - pass the value through this function to its caller. */ - if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0) - remove_quoted_nulls (temp); /* XXX */ - } - } - 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)) || (word->flags & W_DQUOTE)) -#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); - tword->flags |= W_HASQUOTEDNULL; /* XXX */ - 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); - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - list = make_word_list (tword, (WORD_LIST *)NULL); - } -#else - else - list = (WORD_LIST *)NULL; -#endif - } - else if (word->flags & W_NOSPLIT) - { - tword = make_bare_word (istring); - if (word->flags & W_ASSIGNMENT) - tword->flags |= W_ASSIGNMENT; /* XXX */ - if (word->flags & W_COMPASSIGN) - tword->flags |= W_COMPASSIGN; /* XXX */ - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; /* XXX */ - if (word->flags & W_NOEXPAND) - tword->flags |= W_NOEXPAND; /* XXX */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - tword->flags |= W_QUOTED; - if (had_quoted_null) - tword->flags |= W_HASQUOTEDNULL; - list = make_word_list (tword, (WORD_LIST *)NULL); - } - 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); - 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_COMPASSIGN) - tword->flags |= W_COMPASSIGN; - if (word->flags & W_NOGLOB) - tword->flags |= W_NOGLOB; - if (word->flags & W_NOEXPAND) - tword->flags |= W_NOEXPAND; - if (had_quoted_null) - tword->flags |= W_HASQUOTEDNULL; /* XXX */ - list = make_word_list (tword, (WORD_LIST *)NULL); - } - } - - 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 (c == 0) - { - *r++ = '\\'; - break; - } - 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 = alloc_word_desc (); - w->word = t ? t : savestring (""); - 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, *e; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL); -#if 0 - result = (WORD_LIST *) list_append (result, tresult); -#else - if (result == 0) - result = e = tresult; - else - { - e->next = tresult; - while (e->next) - e = e->next; - } -#endif - } - 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)) ? value_cell (v) : " \t\n"; - - /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet - handle multibyte chars in IFS */ - memset (ifs_cmap, '\0', sizeof (ifs_cmap)); - for (t = ifs_value ; t && *t; t++) - { - uc = *t; - ifs_cmap[uc] = 1; - } - -#if defined (HANDLE_MULTIBYTE) - if (ifs_value == 0) - { - ifs_firstc[0] = '\0'; - ifs_firstc_len = 1; - } - else - { - size_t ifs_len; - ifs_len = strnlen (ifs_value, MB_CUR_MAX); - ifs_firstc_len = MBLEN (ifs_value, ifs_len); - if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len)) - { - ifs_firstc[0] = ifs_value[0]; - ifs_firstc[1] = '\0'; - ifs_firstc_len = 1; - } - else - memcpy (ifs_firstc, ifs_value, ifs_firstc_len); - } -#else - ifs_firstc = ifs_value ? *ifs_value : 0; -#endif -} - -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, *e; - - for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) - { - tresult = word_split (t->word, ifs_value); - if (result == 0) - result = e = tresult; - else - { - e->next = tresult; - while (e->next) - e = e->next; - } - } - 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; -{ - set_pipestatus_from_exit (last_command_exit_value); - - /* Cleanup code goes here. */ - expand_no_split_dollar_star = 0; /* XXX */ - expanding_redir = 0; - assigning_in_environment = 0; - - if (parse_and_execute_level == 0) - top_level_cleanup (); /* from sig.c */ - - 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); - exp_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 - -#if defined (ARRAY_VARS) -/* Take WORD, a compound associative array assignment, and internally run - 'declare -A w', where W is the variable name portion of WORD. */ -static int -make_internal_declare (word, option) - char *word; - char *option; -{ - int t; - WORD_LIST *wl; - WORD_DESC *w; - - w = make_word (word); - - t = assignment (w->word, 0); - w->word[t] = '\0'; - - wl = make_word_list (w, (WORD_LIST *)NULL); - wl = make_word_list (make_word (option), wl); - - return (declare_builtin (wl)); -} -#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; - -#if defined (ARRAY_VARS) - /* If this is a compound array assignment to a builtin that accepts - such assignments (e.g., `declare'), take the assignment and perform - it separately, handling the semantics of declarations inside shell - functions. This avoids the double-evaluation of such arguments, - because `declare' does some evaluation of compound assignments on - its own. */ - if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) - { - int t; - - if (tlist->word->flags & W_ASSIGNASSOC) - make_internal_declare (tlist->word->word, "-A"); - - t = do_word_assignment (tlist->word); - if (t == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); - } - - /* Now transform the word as ksh93 appears to do and go on */ - t = assignment (tlist->word->word, 0); - tlist->word->word[t] = '\0'; - tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC); - } -#endif - - 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_word_assignment (temp_list->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_wassign_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_word_assignment; - tempenv_assign_error = 0; - - for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) - { - this_command_name = (char *)NULL; - assigning_in_environment = (assign_func == assign_in_env); - tint = (*assign_func) (temp_list->word); - assigning_in_environment = 0; - /* Variable assignment errors in non-interactive shells running - in Posix.2 mode cause the shell to exit. */ - if (tint == 0) - { - if (assign_func == do_word_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); - } - else - tempenv_assign_error++; - } - } - - 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.h~ b/subst.h~ deleted file mode 100644 index 1093ee258..000000000 --- a/subst.h~ +++ /dev/null @@ -1,285 +0,0 @@ -/* subst.h -- Names of externally visible functions in subst.c. */ - -/* Copyright (C) 1993-2007 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 (_SUBST_H_) -#define _SUBST_H_ - -#include "stdc.h" - -/* Constants which specify how to handle backslashes and quoting in - expand_word_internal (). Q_DOUBLE_QUOTES means to use the function - slashify_in_quotes () to decide whether the backslash should be - retained. Q_HERE_DOCUMENT means slashify_in_here_document () to - decide whether to retain the backslash. Q_KEEP_BACKSLASH means - to unconditionally retain the backslash. Q_PATQUOTE means that we're - expanding a pattern ${var%#[#%]pattern} in an expansion surrounded - by double quotes. */ -#define Q_DOUBLE_QUOTES 0x01 -#define Q_HERE_DOCUMENT 0x02 -#define Q_KEEP_BACKSLASH 0x04 -#define Q_PATQUOTE 0x08 -#define Q_QUOTED 0x10 -#define Q_ADDEDQUOTES 0x20 -#define Q_QUOTEDNULL 0x40 - -/* Flag values controlling how assignment statements are treated. */ -#define ASS_APPEND 0x01 -#define ASS_MKLOCAL 0x02 - -/* Flags for the string extraction functions. */ -#define SX_NOALLOC 0x01 /* just skip; don't return substring */ -#define SX_VARNAME 0x02 /* variable name; for string_extract () */ -#define SX_REQMATCH 0x04 /* closing/matching delimiter required */ -#define SX_COMMAND 0x08 /* extracting a shell script/command */ -#define SX_NOCTLESC 0x10 /* don't honor CTLESC quoting */ -#define SX_NOESCCTLNUL 0x20 /* don't let CTLESC quote CTLNUL */ -#define SX_NOLONGJMP 0x40 /* don't longjmp on fatal error */ - -/* Remove backslashes which are quoting backquotes from STRING. Modifies - STRING, and returns a pointer to it. */ -extern char * de_backslash __P((char *)); - -/* Replace instances of \! in a string with !. */ -extern void unquote_bang __P((char *)); - -/* Extract the $( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "$(". - Make (SINDEX) get the position just after the matching ")". - XFLAGS is additional flags to pass to other extraction functions, */ -extern char *extract_command_subst __P((char *, int *, int)); - -/* Extract the $[ construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "$[". - Make (SINDEX) get the position just after the matching "]". */ -extern char *extract_arithmetic_subst __P((char *, int *)); - -#if defined (PROCESS_SUBSTITUTION) -/* Extract the <( or >( construct in STRING, and return a new string. - Start extracting at (SINDEX) as if we had just seen "<(". - Make (SINDEX) get the position just after the matching ")". */ -extern char *extract_process_subst __P((char *, char *, int *)); -#endif /* PROCESS_SUBSTITUTION */ - -/* Extract the name of the variable to bind to from the assignment string. */ -extern char *assignment_name __P((char *)); - -/* Return a single string of all the words present in LIST, separating - each word with SEP. */ -extern char *string_list_internal __P((WORD_LIST *, char *)); - -/* Return a single string of all the words present in LIST, separating - each word with a space. */ -extern char *string_list __P((WORD_LIST *)); - -/* Turn $* into a single string, obeying POSIX rules. */ -extern char *string_list_dollar_star __P((WORD_LIST *)); - -/* Expand $@ into a single string, obeying POSIX rules. */ -extern char *string_list_dollar_at __P((WORD_LIST *, int)); - -/* Perform quoted null character removal on each element of LIST. - This modifies LIST. */ -extern void word_list_remove_quoted_nulls __P((WORD_LIST *)); - -/* This performs word splitting and quoted null character removal on - STRING. */ -extern WORD_LIST *list_string __P((char *, char *, int)); - -extern char *ifs_firstchar __P((int *)); -extern char *get_word_from_string __P((char **, char *, char **)); -extern char *strip_trailing_ifs_whitespace __P((char *, char *, int)); - -/* Given STRING, an assignment string, get the value of the right side - of the `=', and bind it to the left side. If EXPAND is true, then - perform tilde expansion, parameter expansion, command substitution, - and arithmetic expansion on the right-hand side. Do not perform word - splitting on the result of expansion. */ -extern int do_assignment __P((char *)); -extern int do_assignment_no_expand __P((char *)); -extern int do_word_assignment __P((WORD_DESC *)); - -/* Append SOURCE to TARGET at INDEX. SIZE is the current amount - of space allocated to TARGET. SOURCE can be NULL, in which - case nothing happens. Gets rid of SOURCE by free ()ing it. - Returns TARGET in case the location has changed. */ -extern char *sub_append_string __P((char *, char *, int *, int *)); - -/* Append the textual representation of NUMBER to TARGET. - INDEX and SIZE are as in SUB_APPEND_STRING. */ -extern char *sub_append_number __P((intmax_t, char *, int *, int *)); - -/* Return the word list that corresponds to `$*'. */ -extern WORD_LIST *list_rest_of_args __P((void)); - -/* Make a single large string out of the dollar digit variables, - and the rest_of_args. If DOLLAR_STAR is 1, then obey the special - case of "$*" with respect to IFS. */ -extern char *string_rest_of_args __P((int)); - -extern int number_of_args __P((void)); - -/* Expand STRING by performing parameter expansion, command substitution, - and arithmetic expansion. Dequote the resulting WORD_LIST before - returning it, but do not perform word splitting. The call to - remove_quoted_nulls () is made here because word splitting normally - takes care of quote removal. */ -extern WORD_LIST *expand_string_unsplit __P((char *, int)); - -/* Expand the rhs of an assignment statement. */ -extern WORD_LIST *expand_string_assignment __P((char *, int)); - -/* Expand a prompt string. */ -extern WORD_LIST *expand_prompt_string __P((char *, int, int)); - -/* Expand STRING just as if you were expanding a word. This also returns - a list of words. Note that filename globbing is *NOT* done for word - or string expansion, just when the shell is expanding a command. This - does parameter expansion, command substitution, arithmetic expansion, - and word splitting. Dequote the resultant WORD_LIST before returning. */ -extern WORD_LIST *expand_string __P((char *, int)); - -/* Convenience functions that expand strings to strings, taking care of - converting the WORD_LIST * returned by the expand_string* functions - to a string and deallocating the WORD_LIST *. */ -extern char *expand_string_to_string __P((char *, int)); -extern char *expand_string_unsplit_to_string __P((char *, int)); -extern char *expand_assignment_string_to_string __P((char *, int)); - -/* Expand an arithmetic expression string */ -extern char *expand_arith_string __P((char *, int)); - -/* De-quote quoted characters in STRING. */ -extern char *dequote_string __P((char *)); - -/* De-quote quoted characters in each word in LIST. */ -extern WORD_LIST *dequote_list __P((WORD_LIST *)); - -/* Expand WORD, performing word splitting on the result. This does - parameter expansion, command substitution, arithmetic expansion, - word splitting, and quote removal. */ -extern WORD_LIST *expand_word __P((WORD_DESC *, int)); - -/* Expand WORD, but do not perform word splitting on the result. This - does parameter expansion, command substitution, arithmetic expansion, - and quote removal. */ -extern WORD_LIST *expand_word_unsplit __P((WORD_DESC *, int)); -extern WORD_LIST *expand_word_leave_quoted __P((WORD_DESC *, int)); - -/* Return the value of a positional parameter. This handles values > 10. */ -extern char *get_dollar_var_value __P((intmax_t)); - -/* Quote a string to protect it from word splitting. */ -extern char *quote_string __P((char *)); - -/* Quote escape characters (characters special to interals of expansion) - in a string. */ -extern char *quote_escapes __P((char *)); - -/* And remove such quoted special characters. */ -extern char *remove_quoted_escapes __P((char *)); - -/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the - backslash quoting rules for within double quotes. */ -extern char *string_quote_removal __P((char *, int)); - -/* Perform quote removal on word WORD. This allocates and returns a new - WORD_DESC *. */ -extern WORD_DESC *word_quote_removal __P((WORD_DESC *, int)); - -/* Perform quote removal on all words in LIST. If QUOTED is non-zero, - the members of the list are treated as if they are surrounded by - double quotes. Return a new list, or NULL if LIST is NULL. */ -extern WORD_LIST *word_list_quote_removal __P((WORD_LIST *, int)); - -/* Called when IFS is changed to maintain some private variables. */ -extern void setifs __P((SHELL_VAR *)); - -/* Return the value of $IFS, or " \t\n" if IFS is unset. */ -extern char *getifs __P((void)); - -/* This splits a single word into a WORD LIST on $IFS, but only if the word - is not quoted. list_string () performs quote removal for us, even if we - don't do any splitting. */ -extern WORD_LIST *word_split __P((WORD_DESC *, char *)); - -/* Take the list of words in LIST and do the various substitutions. Return - a new list of words which is the expanded list, and without things like - variable assignments. */ -extern WORD_LIST *expand_words __P((WORD_LIST *)); - -/* Same as expand_words (), but doesn't hack variable or environment - variables. */ -extern WORD_LIST *expand_words_no_vars __P((WORD_LIST *)); - -/* Perform the `normal shell expansions' on a WORD_LIST. These are - brace expansion, tilde expansion, parameter and variable substitution, - command substitution, arithmetic expansion, and word splitting. */ -extern WORD_LIST *expand_words_shellexp __P((WORD_LIST *)); - -extern WORD_DESC *command_substitute __P((char *, int)); -extern char *pat_subst __P((char *, char *, char *, int)); - -extern int fifos_pending __P((void)); -extern void unlink_fifo_list __P((void)); - -extern WORD_LIST *list_string_with_quotes __P((char *)); - -#if defined (ARRAY_VARS) -extern char *extract_array_assignment_list __P((char *, int *)); -#endif - -#if defined (COND_COMMAND) -extern char *remove_backslashes __P((char *)); -extern char *cond_expand_word __P((WORD_DESC *, int)); -#endif - -/* Flags for skip_to_delim */ -#define SD_NOJMP 0x01 /* don't longjmp on fatal error. */ - -extern int skip_to_delim __P((char *, int, char *, int)); - -#if defined (READLINE) -extern int char_is_quoted __P((char *, int)); -extern int unclosed_pair __P((char *, int, char *)); -extern WORD_LIST *split_at_delims __P((char *, int, char *, int, int *, int *)); -#endif - -/* Variables used to keep track of the characters in IFS. */ -extern SHELL_VAR *ifs_var; -extern char *ifs_value; -extern unsigned char ifs_cmap[]; - -#if defined (HANDLE_MULTIBYTE) -extern unsigned char ifs_firstc[]; -extern size_t ifs_firstc_len; -#else -extern unsigned char ifs_firstc; -#endif - -/* Evaluates to 1 if C is a character in $IFS. */ -#define isifs(c) (ifs_cmap[(unsigned char)(c)] != 0) - -/* How to determine the quoted state of the character C. */ -#define QUOTED_CHAR(c) ((c) == CTLESC) - -/* Is the first character of STRING a quoted NULL character? */ -#define QUOTED_NULL(string) ((string)[0] == CTLNUL && (string)[1] == '\0') - -#endif /* !_SUBST_H_ */ diff --git a/support/Makefile.in~ b/support/Makefile.in~ deleted file mode 100644 index cf6cee732..000000000 --- a/support/Makefile.in~ +++ /dev/null @@ -1,87 +0,0 @@ -# -# Simple Makefile for the support programs. -# -# documentation support: man2html -# testing support: printenv recho zecho -# -# bashbug lives here but is created by the top-level makefile -# -# Currently only man2html is built -# -# Copyright (C) 1998-2008 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 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# -# Boilerplate -# -topdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = .:@srcdir@ -BUILD_DIR = @BUILD_DIR@ - -RM = rm -f -SHELL = @MAKE_SHELL@ -CC = @CC@ -CC_FOR_BUILD = @CC_FOR_BUILD@ - -EXEEXT = @EXEEXT@ - -# -# Compiler options: -# -PROFILE_FLAGS = @PROFILE_FLAGS@ - -CFLAGS = @CFLAGS@ -CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ -CPPFLAGS = @CPPFLAGS@ -CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ -LOCAL_CFLAGS = @LOCAL_CFLAGS@ -DEFS = @DEFS@ -LOCAL_DEFS = @LOCAL_DEFS@ - -LIBS = @LIBS@ -LIBS_FOR_BUILD = ${LIBS} # XXX - -LOCAL_LDFLAGS = @LOCAL_LDFLAGS@ -LDFLAGS = @LDFLAGS@ $(LOCAL_LDFLAGS) $(CFLAGS) -LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ $(LOCAL_LDFLAGS) $(CFLAGS_FOR_BUILD) - -INCLUDES = -I${BUILD_DIR} -I${topdir} - -BASE_CCFLAGS = ${PROFILE_FLAGS} $(DEFS) $(LOCAL_DEFS) $(SYSTEM_FLAGS) \ - ${INCLUDES} $(LOCAL_CFLAGS) - -CCFLAGS = $(BASE_CCFLAGS) $(CPPFLAGS) $(CFLAGS) -CCFLAGS_FOR_BUILD = $(BASE_CCFLAGS) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) - -SRC1 = man2html.c -OBJ1 = man2html.o - -.c.o: - $(RM) $@ - $(CC_FOR_BUILD) -c $(CCFLAGS_FOR_BUILD) $< - -all: man2html$(EXEEXT) - -man2html$(EXEEXT): $(OBJ1) - $(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) $(OBJ1) -o $@ ${LIBS_FOR_BUILD} - -clean: - $(RM) man2html$(EXEEXT) - -distclean maintainer-clean mostlyclean: clean - $(RM) $(OBJ1) - -man2html.o: man2html.c diff --git a/support/bashversion.c~ b/support/bashversion.c~ deleted file mode 100644 index e91c7a04e..000000000 --- a/support/bashversion.c~ +++ /dev/null @@ -1,147 +0,0 @@ -/* bashversion.c -- Display bash version information. */ - -/* Copyright (C) 2001 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include "config.h" - -#include "stdc.h" - -#include - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashansi.h" - -#include "version.h" -#include "conftypes.h" - -#define RFLAG 0x0001 -#define VFLAG 0x0002 -#define MFLAG 0x0004 -#define PFLAG 0x0008 -#define SFLAG 0x0010 -#define LFLAG 0x0020 -#define XFLAG 0x0040 - -extern int optind; -extern char *optarg; - -extern char *dist_version; -extern int patch_level; - -extern char *shell_version_string __P((void)); - -char *shell_name = "bash"; -char *progname; - -static void -usage() -{ - fprintf(stderr, "%s: usage: %s [-hrvpmlsx]\n", progname, progname); -} - -int -main (argc, argv) - int argc; - char **argv; -{ - int opt, oflags; - char dv[128], *rv; - - if (progname = strrchr (argv[0], '/')) - progname++; - else - progname = argv[0]; - - oflags = 0; - while ((opt = getopt(argc, argv, "hrvmpslx")) != EOF) - { - switch (opt) - { - case 'h': - usage (); - exit (0); - case 'r': - oflags |= RFLAG; /* release */ - break; - case 'v': - oflags |= VFLAG; /* version */ - break; - case 'm': - oflags |= MFLAG; /* machtype */ - break; - case 'p': - oflags |= PFLAG; /* patchlevel */ - break; - case 's': /* short version string */ - oflags |= SFLAG; - break; - case 'l': /* long version string */ - oflags |= LFLAG; - break; - case 'x': /* extended version information */ - oflags |= XFLAG; - break; - default: - usage (); - exit (2); - } - } - - argc -= optind; - argv += optind; - - if (argc > 0) - { - usage (); - exit (2); - } - - /* default behavior */ - if (oflags == 0) - oflags = SFLAG; - - if (oflags & (RFLAG|VFLAG)) - { - strcpy (dv, dist_version); - rv = strchr (dv, '.'); - if (rv) - *rv++ = '\0'; - else - rv = "00"; - } - if (oflags & RFLAG) - printf ("%s\n", dv); - else if (oflags & VFLAG) - printf ("%s\n", rv); - else if (oflags & MFLAG) - printf ("%s\n", MACHTYPE); - else if (oflags & PFLAG) - printf ("%d\n", patch_level); - else if (oflags & SFLAG) - printf ("%s\n", shell_version_string ()); - else if (oflags & LFLAG) - show_shell_version (0); - else if (oflags & XFLAG) - show_shell_version (1); - - exit (0); -} diff --git a/support/config.guess~ b/support/config.guess~ deleted file mode 100644 index a937dd5c8..000000000 --- a/support/config.guess~ +++ /dev/null @@ -1,1529 +0,0 @@ -#! /bin/sh -# Attempt to guess a canonical system name. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 -# Free Software Foundation, Inc. - -timestamp='2008-03-12' - -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - - -# Originally written by Per Bothner . -# Please send patches to . Submit a context -# diff and a properly formatted ChangeLog entry. -# -# This script attempts to guess a canonical system name similar to -# config.sub. If it succeeds, it prints the system name on stdout, and -# exits with 0. Otherwise, it exits with 1. -# -# The plan is that this can be called by configure scripts if you -# don't specify an explicit build system type. - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] - -Output the configuration name of the system \`$me' is run on. - -Operation modes: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.guess ($timestamp) - -Originally written by Per Bothner. -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, -2002, 2003, 2004, 2005, 2006, 2007, 2008,2009 Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" >&2 - exit 1 ;; - * ) - break ;; - esac -done - -if test $# != 0; then - echo "$me: too many arguments$help" >&2 - exit 1 -fi - -trap 'exit 1' 1 2 15 - -# CC_FOR_BUILD -- compiler used by this script. Note that the use of a -# compiler to aid in system detection is discouraged as it requires -# temporary files to be created and, as you can see below, it is a -# headache to deal with in a portable fashion. - -# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still -# use `HOST_CC' if defined, but it is deprecated. - -# Portable tmp directory creation inspired by the Autoconf team. - -set_cc_for_build=' -trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; -trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; -: ${TMPDIR=/tmp} ; - { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || - { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; -dummy=$tmp/dummy ; -tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > $dummy.c ; - for c in cc gcc c89 c99 ; do - if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then - CC_FOR_BUILD="$c"; break ; - fi ; - done ; - if test x"$CC_FOR_BUILD" = x ; then - CC_FOR_BUILD=no_compiler_found ; - fi - ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; -esac ; set_cc_for_build= ;' - -# This is needed to find uname on a Pyramid OSx when run in the BSD universe. -# (ghazi@noc.rutgers.edu 1994-08-24) -if (test -f /.attbin/uname) >/dev/null 2>&1 ; then - PATH=$PATH:/.attbin ; export PATH -fi - -UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown -UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown -UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown - -# Note: order is significant - the case branches are not exclusive. - -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - *:NetBSD:*:*) - # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, - # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently - # switched to ELF, *-*-netbsd* would select the old - # object file format. This provides both forward - # compatibility and a consistent mechanism for selecting the - # object file format. - # - # Note: NetBSD doesn't particularly care about the vendor - # portion of the name. We always set it to "unknown". - sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || echo unknown)` - case "${UNAME_MACHINE_ARCH}" in - armeb) machine=armeb-unknown ;; - arm*) machine=arm-unknown ;; - sh3el) machine=shl-unknown ;; - sh3eb) machine=sh-unknown ;; - sh5el) machine=sh5le-unknown ;; - *) machine=${UNAME_MACHINE_ARCH}-unknown ;; - esac - # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. - case "${UNAME_MACHINE_ARCH}" in - arm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval $set_cc_for_build - if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep __ELF__ >/dev/null - then - # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). - # Return netbsd for either. FIX? - os=netbsd - else - os=netbsdelf - fi - ;; - *) - os=netbsd - ;; - esac - # The OS release - # Debian GNU/NetBSD machines have a different userland, and - # thus, need a distinct triplet. However, they do not need - # kernel version information, so it can be replaced with a - # suitable tag, in the style of linux-gnu. - case "${UNAME_VERSION}" in - Debian*) - release='-gnu' - ;; - *) - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` - ;; - esac - # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: - # contains redundant information, the shorter form: - # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}" - exit ;; - *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} - exit ;; - *:ekkoBSD:*:*) - echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} - exit ;; - *:SolidBSD:*:*) - echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} - exit ;; - macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd${UNAME_RELEASE} - exit ;; - *:MirBSD:*:*) - echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} - exit ;; - alpha:OSF1:*:*) - case $UNAME_RELEASE in - *4.0) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` - ;; - *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` - ;; - esac - # According to Compaq, /usr/sbin/psrinfo has been available on - # OSF/1 and Tru64 systems produced since 1995. I hope that - # covers most systems running today. This code pipes the CPU - # types through head -n 1, so we only detect the type of CPU 0. - ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` - case "$ALPHA_CPU_TYPE" in - "EV4 (21064)") - UNAME_MACHINE="alpha" ;; - "EV4.5 (21064)") - UNAME_MACHINE="alpha" ;; - "LCA4 (21066/21068)") - UNAME_MACHINE="alpha" ;; - "EV5 (21164)") - UNAME_MACHINE="alphaev5" ;; - "EV5.6 (21164A)") - UNAME_MACHINE="alphaev56" ;; - "EV5.6 (21164PC)") - UNAME_MACHINE="alphapca56" ;; - "EV5.7 (21164PC)") - UNAME_MACHINE="alphapca57" ;; - "EV6 (21264)") - UNAME_MACHINE="alphaev6" ;; - "EV6.7 (21264A)") - UNAME_MACHINE="alphaev67" ;; - "EV6.8CB (21264C)") - UNAME_MACHINE="alphaev68" ;; - "EV6.8AL (21264B)") - UNAME_MACHINE="alphaev68" ;; - "EV6.8CX (21264D)") - UNAME_MACHINE="alphaev68" ;; - "EV6.9A (21264/EV69A)") - UNAME_MACHINE="alphaev69" ;; - "EV7 (21364)") - UNAME_MACHINE="alphaev7" ;; - "EV7.9 (21364A)") - UNAME_MACHINE="alphaev79" ;; - esac - # A Pn.n version is a patched version. - # A Vn.n version is a released version. - # A Tn.n version is a released field test version. - # A Xn.n version is an unreleased experimental baselevel. - # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - exit ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead - # of the specific Alpha model? - echo alpha-pc-interix - exit ;; - 21064:Windows_NT:50:3) - echo alpha-dec-winnt3.5 - exit ;; - Amiga*:UNIX_System_V:4.0:*) - echo m68k-unknown-sysv4 - exit ;; - *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos - exit ;; - *:[Mm]orph[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-morphos - exit ;; - *:OS/390:*:*) - echo i370-ibm-openedition - exit ;; - *:z/VM:*:*) - echo s390-ibm-zvmoe - exit ;; - *:OS400:*:*) - echo powerpc-ibm-os400 - exit ;; - arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} - exit ;; - arm:riscos:*:*|arm:RISCOS:*:*) - echo arm-unknown-riscos - exit ;; - SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit ;; - Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) - # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "`(/bin/universe) 2>/dev/null`" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit ;; - NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit ;; - DRS?6000:unix:4.0:6*) - echo sparc-icl-nx6 - exit ;; - DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) - case `/usr/bin/uname -p` in - sparc) echo sparc-icl-nx7; exit ;; - esac ;; - sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:6*:*) - # According to config.sub, this is the proper way to canonicalize - # SunOS6. Hard to guess exactly what SunOS6 will be like, but - # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:*:*) - case "`/usr/bin/arch -k`" in - Series*|S4*) - UNAME_RELEASE=`uname -v` - ;; - esac - # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` - exit ;; - sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} - exit ;; - sun*:*:4.2BSD:*) - UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 - case "`/bin/arch`" in - sun3) - echo m68k-sun-sunos${UNAME_RELEASE} - ;; - sun4) - echo sparc-sun-sunos${UNAME_RELEASE} - ;; - esac - exit ;; - aushp:SunOS:*:*) - echo sparc-auspex-sunos${UNAME_RELEASE} - exit ;; - # The situation for MiNT is a little confusing. The machine name - # can be virtually everything (everything which is not - # "atarist" or "atariste" at least should have a processor - # > m68000). The system name ranges from "MiNT" over "FreeMiNT" - # to the lowercase version "mint" (or "freemint"). Finally - # the system name "TOS" denotes a system which is actually not - # MiNT. But MiNT is downward compatible to TOS, so this should - # be no problem. - atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit ;; - hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit ;; - *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit ;; - m68k:machten:*:*) - echo m68k-apple-machten${UNAME_RELEASE} - exit ;; - powerpc:machten:*:*) - echo powerpc-apple-machten${UNAME_RELEASE} - exit ;; - RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit ;; - RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} - exit ;; - VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} - exit ;; - 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix${UNAME_RELEASE} - exit ;; - mips:*:*:UMIPS | mips:*:*:RISCos) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c -#ifdef __cplusplus -#include /* for printf() prototype */ - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif - #if defined (host_mips) && defined (MIPSEB) - #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); - #endif - #endif - exit (-1); - } -EOF - $CC_FOR_BUILD -o $dummy $dummy.c && - dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`$dummy $dummyarg` && - { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos${UNAME_RELEASE} - exit ;; - Motorola:PowerMAX_OS:*:*) - echo powerpc-motorola-powermax - exit ;; - Motorola:*:4.3:PL8-*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit ;; - m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit ;; - m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit ;; - m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit ;; - AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] - then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ - [ ${TARGET_BINARY_INTERFACE}x = x ] - then - echo m88k-dg-dgux${UNAME_RELEASE} - else - echo m88k-dg-dguxbcs${UNAME_RELEASE} - fi - else - echo i586-dg-dgux${UNAME_RELEASE} - fi - exit ;; - M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit ;; - M88*:*:R3*:*) - # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit ;; - XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit ;; - Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit ;; - *:IRIX*:*:*) - echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` - exit ;; - ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' - i*86:AIX:*:*) - echo i386-ibm-aix - exit ;; - ia64:AIX:*:*) - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} - fi - echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} - exit ;; - *:AIX:2:3) - if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include - - main() - { - if (!__power_pc()) - exit(1); - puts("powerpc-ibm-aix3.2.5"); - exit(0); - } -EOF - if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` - then - echo "$SYSTEM_NAME" - else - echo rs6000-ibm-aix3.2.5 - fi - elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 - else - echo rs6000-ibm-aix3.2 - fi - exit ;; - *:AIX:*:[456]) - IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then - IBM_ARCH=rs6000 - else - IBM_ARCH=powerpc - fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} - fi - echo ${IBM_ARCH}-ibm-aix${IBM_REV} - exit ;; - *:AIX:*:*) - echo rs6000-ibm-aix - exit ;; - ibmrt:4.4BSD:*|romp-ibm:BSD:*) - echo romp-ibm-bsd4.4 - exit ;; - ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to - exit ;; # report: romp-ibm BSD 4.3 - *:BOSX:*:*) - echo rs6000-bull-bosx - exit ;; - DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit ;; - 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit ;; - hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit ;; - 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; - 9000/[678][0-9][0-9]) - if [ -x /usr/bin/getconf ]; then - sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 - esac ;; - esac - fi - if [ "${HP_ARCH}" = "" ]; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - - #define _HPUX_SOURCE - #include - #include - - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); - - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } -EOF - (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` - test -z "$HP_ARCH" && HP_ARCH=hppa - fi ;; - esac - if [ ${HP_ARCH} = "hppa2.0w" ] - then - eval $set_cc_for_build - - # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating - # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler - # generating 64-bit code. GNU and HP use different nomenclature: - # - # $ CC_FOR_BUILD=cc ./config.guess - # => hppa2.0w-hp-hpux11.23 - # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess - # => hppa64-hp-hpux11.23 - - if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | - grep __LP64__ >/dev/null - then - HP_ARCH="hppa2.0w" - else - HP_ARCH="hppa64" - fi - fi - echo ${HP_ARCH}-hp-hpux${HPUX_REV} - exit ;; - ia64:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo ia64-hp-hpux${HPUX_REV} - exit ;; - 3050*:HI-UX:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include - int - main () - { - long cpu = sysconf (_SC_CPU_VERSION); - /* The order matters, because CPU_IS_HP_MC68K erroneously returns - true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct - results, however. */ - if (CPU_IS_PA_RISC (cpu)) - { - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; - case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; - default: puts ("hppa-hitachi-hiuxwe2"); break; - } - } - else if (CPU_IS_HP_MC68K (cpu)) - puts ("m68k-hitachi-hiuxwe2"); - else puts ("unknown-hitachi-hiuxwe2"); - exit (0); - } -EOF - $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - echo unknown-hitachi-hiuxwe2 - exit ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) - echo hppa1.1-hp-bsd - exit ;; - 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit ;; - *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) - echo hppa1.1-hp-osf - exit ;; - hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit ;; - i*86:OSF1:*:*) - if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk - else - echo ${UNAME_MACHINE}-unknown-osf1 - fi - exit ;; - parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit ;; - C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit ;; - C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit ;; - C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit ;; - C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit ;; - CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*[A-Z]90:*:*:*) - echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ - | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ - -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ - -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*TS:*:*:*) - echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*SV1:*:*:*) - echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} - exit ;; - sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} - exit ;; - *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} - exit ;; - *:FreeBSD:*:*) - case ${UNAME_MACHINE} in - pc98) - echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - amd64) - echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - *) - echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - esac - exit ;; - i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin - exit ;; - *:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 - exit ;; - i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 - exit ;; - i*:PW*:*) - echo ${UNAME_MACHINE}-pc-pw32 - exit ;; - *:Interix*:[3456]*) - case ${UNAME_MACHINE} in - x86) - echo i586-pc-interix${UNAME_RELEASE} - exit ;; - EM64T | authenticamd) - echo x86_64-unknown-interix${UNAME_RELEASE} - exit ;; - IA64) - echo ia64-unknown-interix${UNAME_RELEASE} - exit ;; - esac ;; - [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) - echo i${UNAME_MACHINE}-pc-mks - exit ;; - i*:Windows_NT*:* | Pentium*:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we - # UNAME_MACHINE based on the output of uname instead of i386? - echo i586-pc-interix - exit ;; - i*:UWIN*:*) - echo ${UNAME_MACHINE}-pc-uwin - exit ;; - amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-unknown-cygwin - exit ;; - p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin - exit ;; - prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - *:GNU:*:*) - # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` - exit ;; - *:GNU/*:*:*) - # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu - exit ;; - i*86:Minix:*:*) - echo ${UNAME_MACHINE}-pc-minix - exit ;; - arm*:Linux:*:*) - eval $set_cc_for_build - if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_EABI__ - then - echo ${UNAME_MACHINE}-unknown-linux-gnu - else - echo ${UNAME_MACHINE}-unknown-linux-gnueabi - fi - exit ;; - avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - cris:Linux:*:*) - echo cris-axis-linux-gnu - exit ;; - crisv32:Linux:*:*) - echo crisv32-axis-linux-gnu - exit ;; - frv:Linux:*:*) - echo frv-unknown-linux-gnu - exit ;; - ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - mips:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #undef CPU - #undef mips - #undef mipsel - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=mipsel - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=mips - #else - CPU= - #endif - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^CPU/{ - s: ::g - p - }'`" - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } - ;; - mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #undef CPU - #undef mips64 - #undef mips64el - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=mips64el - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=mips64 - #else - CPU= - #endif - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^CPU/{ - s: ::g - p - }'`" - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } - ;; - or32:Linux:*:*) - echo or32-unknown-linux-gnu - exit ;; - ppc:Linux:*:*) - echo powerpc-unknown-linux-gnu - exit ;; - ppc64:Linux:*:*) - echo powerpc64-unknown-linux-gnu - exit ;; - alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in - EV5) UNAME_MACHINE=alphaev5 ;; - EV56) UNAME_MACHINE=alphaev56 ;; - PCA56) UNAME_MACHINE=alphapca56 ;; - PCA57) UNAME_MACHINE=alphapca56 ;; - EV6) UNAME_MACHINE=alphaev6 ;; - EV67) UNAME_MACHINE=alphaev67 ;; - EV68*) UNAME_MACHINE=alphaev68 ;; - esac - objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null - if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi - echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} - exit ;; - parisc:Linux:*:* | hppa:Linux:*:*) - # Look for CPU level - case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-gnu ;; - PA8*) echo hppa2.0-unknown-linux-gnu ;; - *) echo hppa-unknown-linux-gnu ;; - esac - exit ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-gnu - exit ;; - s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux - exit ;; - sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-gnu - exit ;; - x86_64:Linux:*:*) - echo x86_64-unknown-linux-gnu - exit ;; - xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - i*86:Linux:*:*) - # The BFD linker knows what the default object file format is, so - # first see if it will tell us. cd to the root directory to prevent - # problems with other programs or directories called `ld' in the path. - # Set LC_ALL=C to ensure ld outputs messages in English. - ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ - | sed -ne '/supported targets:/!d - s/[ ][ ]*/ /g - s/.*supported targets: *// - s/ .*// - p'` - case "$ld_supported_targets" in - elf32-i386) - TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" - ;; - a.out-i386-linux) - echo "${UNAME_MACHINE}-pc-linux-gnuaout" - exit ;; - coff-i386) - echo "${UNAME_MACHINE}-pc-linux-gnucoff" - exit ;; - "") - # Either a pre-BFD a.out linker (linux-gnuoldld) or - # one that does not give us useful --help. - echo "${UNAME_MACHINE}-pc-linux-gnuoldld" - exit ;; - esac - # Determine whether the default compiler is a.out or elf - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include - #ifdef __ELF__ - # ifdef __GLIBC__ - # if __GLIBC__ >= 2 - LIBC=gnu - # else - LIBC=gnulibc1 - # endif - # else - LIBC=gnulibc1 - # endif - #else - #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) - LIBC=gnu - #else - LIBC=gnuaout - #endif - #endif - #ifdef __dietlibc__ - LIBC=dietlibc - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^LIBC/{ - s: ::g - p - }'`" - test x"${LIBC}" != x && { - echo "${UNAME_MACHINE}-pc-linux-${LIBC}" - exit - } - test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } - ;; - i*86:DYNIX/ptx:4*:*) - # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. - # earlier versions are messed up and put the nodename in both - # sysname and nodename. - echo i386-sequent-sysv4 - exit ;; - i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, - # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} - exit ;; - i*86:OS/2:*:*) - # If we were able to find `uname', then EMX Unix compatibility - # is probably installed. - echo ${UNAME_MACHINE}-pc-os2-emx - exit ;; - i*86:XTS-300:*:STOP) - echo ${UNAME_MACHINE}-unknown-stop - exit ;; - i*86:atheos:*:*) - echo ${UNAME_MACHINE}-unknown-atheos - exit ;; - i*86:syllable:*:*) - echo ${UNAME_MACHINE}-pc-syllable - exit ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} - exit ;; - i*86:*DOS:*:*) - echo ${UNAME_MACHINE}-pc-msdosdjgpp - exit ;; - i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) - UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` - if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} - else - echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} - fi - exit ;; - i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. - case `/bin/uname -X | grep "^Machine"` in - *486*) UNAME_MACHINE=i486 ;; - *Pentium) UNAME_MACHINE=i586 ;; - *Pent*|*Celeron) UNAME_MACHINE=i686 ;; - esac - echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} - exit ;; - i*86:*:3.2:*) - if test -f /usr/options/cb.name; then - UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then - UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` - (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 - (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ - && UNAME_MACHINE=i586 - (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ - && UNAME_MACHINE=i686 - (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ - && UNAME_MACHINE=i686 - echo ${UNAME_MACHINE}-pc-sco$UNAME_REL - else - echo ${UNAME_MACHINE}-pc-sysv32 - fi - exit ;; - pc:*:*:*) - # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i386. - echo i386-pc-msdosdjgpp - exit ;; - Intel:Mach:3*:*) - echo i386-pc-mach3 - exit ;; - paragon:*:*:*) - echo i860-intel-osf1 - exit ;; - i860:*:4.*:*) # i860-SVR4 - if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 - else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 - fi - exit ;; - mini*:CTIX:SYS*5:*) - # "miniframe" - echo m68010-convergent-sysv - exit ;; - mc68k:UNIX:SYSTEM5:3.51m) - echo m68k-convergent-sysv - exit ;; - M680?0:D-NIX:5.3:*) - echo m68k-diab-dnix - exit ;; - M68*:*:R3V[5678]*:*) - test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; - 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) - OS_REL='' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; - 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; - m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} - exit ;; - mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit ;; - TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} - exit ;; - rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} - exit ;; - PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) - echo powerpc-unknown-lynxos${UNAME_RELEASE} - exit ;; - SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv${UNAME_RELEASE} - exit ;; - RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - *:SINIX-*:*:*) - if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo ${UNAME_MACHINE}-sni-sysv4 - else - echo ns32k-sni-sysv - fi - exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says - echo i586-unisys-sysv4 - exit ;; - *:UNIX_System_V:4*:FTX*) - # From Gerald Hewes . - # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit ;; - *:*:*:FTX*) - # From seanf@swdc.stratus.com. - echo i860-stratus-sysv4 - exit ;; - i*86:VOS:*:*) - # From Paul.Green@stratus.com. - echo ${UNAME_MACHINE}-stratus-vos - exit ;; - *:VOS:*:*) - # From Paul.Green@stratus.com. - echo hppa1.1-stratus-vos - exit ;; - mc68*:A/UX:*:*) - echo m68k-apple-aux${UNAME_RELEASE} - exit ;; - news*:NEWS-OS:6*:*) - echo mips-sony-newsos6 - exit ;; - R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} - else - echo mips-unknown-sysv${UNAME_RELEASE} - fi - exit ;; - BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit ;; - BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit ;; - BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit ;; - BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - echo i586-pc-haiku - exit ;; - SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} - exit ;; - SX-5:SUPER-UX:*:*) - echo sx5-nec-superux${UNAME_RELEASE} - exit ;; - SX-6:SUPER-UX:*:*) - echo sx6-nec-superux${UNAME_RELEASE} - exit ;; - SX-7:SUPER-UX:*:*) - echo sx7-nec-superux${UNAME_RELEASE} - exit ;; - SX-8:SUPER-UX:*:*) - echo sx8-nec-superux${UNAME_RELEASE} - exit ;; - SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux${UNAME_RELEASE} - exit ;; - Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody${UNAME_RELEASE} - exit ;; - *:Rhapsody:*:*) - echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} - exit ;; - *:Darwin:*:*) - UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - case $UNAME_PROCESSOR in - unknown) UNAME_PROCESSOR=powerpc ;; - esac - echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} - exit ;; - *:procnto*:*:* | *:QNX:[0123456789]*:*) - UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = "x86"; then - UNAME_PROCESSOR=i386 - UNAME_MACHINE=pc - fi - echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} - exit ;; - *:QNX:*:4*) - echo i386-pc-qnx - exit ;; - NSE-?:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} - exit ;; - NSR-?:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk${UNAME_RELEASE} - exit ;; - *:NonStop-UX:*:*) - echo mips-compaq-nonstopux - exit ;; - BS2000:POSIX*:*:*) - echo bs2000-siemens-sysv - exit ;; - DS/*:UNIX_System_V:*:*) - echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} - exit ;; - *:Plan9:*:*) - # "uname -m" is not consistent, so use $cputype instead. 386 - # is converted to i386 for consistency with other x86 - # operating systems. - if test "$cputype" = "386"; then - UNAME_MACHINE=i386 - else - UNAME_MACHINE="$cputype" - fi - echo ${UNAME_MACHINE}-unknown-plan9 - exit ;; - *:TOPS-10:*:*) - echo pdp10-unknown-tops10 - exit ;; - *:TENEX:*:*) - echo pdp10-unknown-tenex - exit ;; - KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - echo pdp10-dec-tops20 - exit ;; - XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - echo pdp10-xkl-tops20 - exit ;; - *:TOPS-20:*:*) - echo pdp10-unknown-tops20 - exit ;; - *:ITS:*:*) - echo pdp10-unknown-its - exit ;; - SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} - exit ;; - *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` - exit ;; - *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "${UNAME_MACHINE}" in - A*) echo alpha-dec-vms ; exit ;; - I*) echo ia64-dec-vms ; exit ;; - V*) echo vax-dec-vms ; exit ;; - esac ;; - *:XENIX:*:SysV) - echo i386-pc-xenix - exit ;; - i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' - exit ;; - i*86:rdos:*:*) - echo ${UNAME_MACHINE}-pc-rdos - exit ;; -esac - -#echo '(No uname command or uname output not recognized.)' 1>&2 -#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 - -eval $set_cc_for_build -cat >$dummy.c < -# include -#endif -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (__arm) && defined (__acorn) && defined (__unix) - printf ("arm-acorn-riscix\n"); exit (0); -#endif - -#if defined (hp300) && !defined (hpux) - printf ("m68k-hp-bsd\n"); exit (0); -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); - -#endif - -#if defined (vax) -# if !defined (ultrix) -# include -# if defined (BSD) -# if BSD == 43 - printf ("vax-dec-bsd4.3\n"); exit (0); -# else -# if BSD == 199006 - printf ("vax-dec-bsd4.3reno\n"); exit (0); -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# endif -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# else - printf ("vax-dec-ultrix\n"); exit (0); -# endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - -# Apollos put the system type in the environment. - -test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } - -# Convex versions that predate uname can use getsysinfo(1) - -if [ -x /usr/convex/getsysinfo ] -then - case `getsysinfo -f cpu_type` in - c1*) - echo c1-convex-bsd - exit ;; - c2*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - c34*) - echo c34-convex-bsd - exit ;; - c38*) - echo c38-convex-bsd - exit ;; - c4*) - echo c4-convex-bsd - exit ;; - esac -fi - -cat >&2 < in order to provide the needed -information to handle your system. - -config.guess timestamp = $timestamp - -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null` - -hostinfo = `(hostinfo) 2>/dev/null` -/bin/universe = `(/bin/universe) 2>/dev/null` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` -/bin/arch = `(/bin/arch) 2>/dev/null` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` - -UNAME_MACHINE = ${UNAME_MACHINE} -UNAME_RELEASE = ${UNAME_RELEASE} -UNAME_SYSTEM = ${UNAME_SYSTEM} -UNAME_VERSION = ${UNAME_VERSION} -EOF - -exit 1 - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/support/config.sub~ b/support/config.sub~ deleted file mode 100644 index 4b25e0323..000000000 --- a/support/config.sub~ +++ /dev/null @@ -1,1662 +0,0 @@ -#! /bin/sh -# Configuration validation subroutine script. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 -# Free Software Foundation, Inc. - -timestamp='2008-03-26' - -# This file is (in principle) common to ALL GNU software. -# The presence of a machine in this file suggests that SOME GNU software -# can handle that machine. It does not imply ALL GNU software can. -# -# This file is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - - -# Please send patches to . Submit a context -# diff and a properly formatted ChangeLog entry. -# -# Configuration subroutine to validate and canonicalize a configuration type. -# Supply the specified configuration type as an argument. -# If it is invalid, we print an error message on stderr and exit with code 1. -# Otherwise, we print the canonical config type on stdout and succeed. - -# This file is supposed to be the same for all GNU packages -# and recognize all the CPU types, system types and aliases -# that are meaningful with *any* GNU software. -# Each package is responsible for reporting which valid configurations -# it does not support. The user should be able to distinguish -# a failure to support a valid configuration from a meaningless -# configuration. - -# The goal of this file is to map all the various variations of a given -# machine specification into a single specification in the form: -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or in some cases, the newer four-part form: -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -# It is wrong to echo any other type of specification. - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS - $0 [OPTION] ALIAS - -Canonicalize a configuration name. - -Operation modes: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.sub ($timestamp) - -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, -2002, 2003, 2004, 2005, 2006, 2007, 2008,2009 Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" - exit 1 ;; - - *local*) - # First pass through any local machine types. - echo $1 - exit ;; - - * ) - break ;; - esac -done - -case $# in - 0) echo "$me: missing argument$help" >&2 - exit 1;; - 1) ;; - *) echo "$me: too many arguments$help" >&2 - exit 1;; -esac - -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ - uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] - then os=`echo $1 | sed 's/.*-/-/'` - else os=; fi - ;; -esac - -### Let's recognize common machines as not being operating systems so -### that things like config.sub decstation-3100 work. We also -### recognize some manufacturers as not being operating systems, so we -### can provide default operating systems below. -case $os in - -sun*os*) - # Prevent following clause from handling this invalid input. - ;; - -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ - -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ - -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ - -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ - -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ - -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray) - os= - basic_machine=$1 - ;; - -sim | -cisco | -oki | -wec | -winbond) - os= - basic_machine=$1 - ;; - -scout) - ;; - -wrs) - os=-vxworks - basic_machine=$1 - ;; - -chorusos*) - os=-chorusos - basic_machine=$1 - ;; - -chorusrdb) - os=-chorusrdb - basic_machine=$1 - ;; - -hiux*) - os=-hiuxwe2 - ;; - -sco6) - os=-sco5v6 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5) - os=-sco3.2v5 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco4) - os=-sco3.2v4 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2.[4-9]*) - os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2v[4-9]*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5v6*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco*) - os=-sco3.2v2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -udk*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -isc) - os=-isc2.2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -clix*) - basic_machine=clipper-intergraph - ;; - -isc*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -lynx*) - os=-lynxos - ;; - -ptx*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` - ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` - ;; - -psos*) - os=-psos - ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; -esac - -# Decode aliases for certain CPU-COMPANY combinations. -case $basic_machine in - # Recognize the basic CPU types without company name. - # Some are omitted here because they have special meanings below. - 1750a | 580 \ - | a29k \ - | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ - | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ - | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ - | bfin \ - | c4x | clipper \ - | d10v | d30v | dlx | dsp16xx \ - | fido | fr30 | frv \ - | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ - | i370 | i860 | i960 | ia64 \ - | ip2k | iq2000 \ - | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | mcore | mep | metag \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64el \ - | mips64octeon | mips64octeonel \ - | mips64orion | mips64orionel \ - | mips64r5900 | mips64r5900el \ - | mips64vr | mips64vrel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipstx39 | mipstx39el \ - | mn10200 | mn10300 \ - | mt \ - | msp430 \ - | nios | nios2 \ - | ns16k | ns32k \ - | or32 \ - | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ - | pyramid \ - | score \ - | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ - | sh64 | sh64le \ - | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ - | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu | strongarm \ - | tahoe | thumb | tic4x | tic80 | tron \ - | v850 | v850e \ - | we32k \ - | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ - | z8k) - basic_machine=$basic_machine-unknown - ;; - m6811 | m68hc11 | m6812 | m68hc12) - # Motorola 68HC11/12. - basic_machine=$basic_machine-unknown - os=-none - ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) - ;; - ms1) - basic_machine=mt-unknown - ;; - - # We use `pc' rather than `unknown' - # because (1) that's what they normally are, and - # (2) the word "unknown" tends to confuse beginning users. - i*86 | x86_64) - basic_machine=$basic_machine-pc - ;; - # Object if more than one company name word. - *-*-*) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ - | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ - | avr-* | avr32-* \ - | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ - | clipper-* | craynv-* | cydra-* \ - | d10v-* | d30v-* | dlx-* \ - | elxsi-* \ - | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ - | h8300-* | h8500-* \ - | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ - | i*86-* | i860-* | i960-* | ia64-* \ - | ip2k-* | iq2000-* \ - | m32c-* | m32r-* | m32rle-* \ - | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ - | mips16-* \ - | mips64-* | mips64el-* \ - | mips64octeon-* | mips64octeonel-* \ - | mips64orion-* | mips64orionel-* \ - | mips64r5900-* | mips64r5900el-* \ - | mips64vr-* | mips64vrel-* \ - | mips64vr4100-* | mips64vr4100el-* \ - | mips64vr4300-* | mips64vr4300el-* \ - | mips64vr5000-* | mips64vr5000el-* \ - | mips64vr5900-* | mips64vr5900el-* \ - | mipsisa32-* | mipsisa32el-* \ - | mipsisa32r2-* | mipsisa32r2el-* \ - | mipsisa64-* | mipsisa64el-* \ - | mipsisa64r2-* | mipsisa64r2el-* \ - | mipsisa64sb1-* | mipsisa64sb1el-* \ - | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipstx39-* | mipstx39el-* \ - | mmix-* \ - | mt-* \ - | msp430-* \ - | nios-* | nios2-* \ - | none-* | np1-* | ns16k-* | ns32k-* \ - | orion-* \ - | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ - | pyramid-* \ - | romp-* | rs6000-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ - | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ - | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ - | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ - | tahoe-* | thumb-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ - | tron-* \ - | v850-* | v850e-* | vax-* \ - | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ - | xstormy16-* | xtensa*-* \ - | ymp-* \ - | z8k-*) - ;; - # Recognize the basic CPU types without company name, with glob match. - xtensa*) - basic_machine=$basic_machine-unknown - ;; - # Recognize the various machine names and aliases which stand - # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-unknown - os=-bsd - ;; - 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - basic_machine=m68000-att - ;; - 3b*) - basic_machine=we32k-att - ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; - abacus) - basic_machine=abacus-unknown - ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; - alliant | fx80) - basic_machine=fx80-alliant - ;; - altos | altos3068) - basic_machine=m68k-altos - ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; - amd64) - basic_machine=x86_64-pc - ;; - amd64-*) - basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv - ;; - amiga | amiga-*) - basic_machine=m68k-unknown - ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - blackfin) - basic_machine=bfin-unknown - os=-linux - ;; - blackfin-*) - basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - c90) - basic_machine=c90-cray - os=-unicos - ;; - convex-c1) - basic_machine=c1-convex - os=-bsd - ;; - convex-c2) - basic_machine=c2-convex - os=-bsd - ;; - convex-c32) - basic_machine=c32-convex - os=-bsd - ;; - convex-c34) - basic_machine=c34-convex - os=-bsd - ;; - convex-c38) - basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp - ;; - cr16) - basic_machine=cr16-unknown - os=-elf - ;; - crds | unos) - basic_machine=m68k-crds - ;; - crisv32 | crisv32-* | etraxfs*) - basic_machine=crisv32-axis - ;; - cris | cris-* | etrax*) - basic_machine=cris-axis - ;; - crx) - basic_machine=crx-unknown - os=-elf - ;; - da30 | da30-*) - basic_machine=m68k-da30 - ;; - decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) - basic_machine=mips-dec - ;; - decsystem10* | dec10*) - basic_machine=pdp10-dec - os=-tops10 - ;; - decsystem20* | dec20*) - basic_machine=pdp10-dec - os=-tops20 - ;; - delta | 3300 | motorola-3300 | motorola-delta \ - | 3300-motorola | delta-motorola) - basic_machine=m68k-motorola - ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; - dpx20 | dpx20-*) - basic_machine=rs6000-bull - os=-bosx - ;; - dpx2* | dpx2*-bull) - basic_machine=m68k-bull - os=-sysv3 - ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd - ;; - encore | umax | mmax) - basic_machine=ns32k-encore - ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose - ;; - fx2800) - basic_machine=i860-alliant - ;; - genix) - basic_machine=ns32k-ns - ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 - ;; - h3050r* | hiux*) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 - ;; - hp300-*) - basic_machine=m68k-hp - ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux - ;; - hp3k9[0-9][0-9] | hp9[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k2[0-9][0-9] | hp9k31[0-9]) - basic_machine=m68000-hp - ;; - hp9k3[2-9][0-9]) - basic_machine=m68k-hp - ;; - hp9k6[0-9][0-9] | hp6[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k7[0-79][0-9] | hp7[0-79][0-9]) - basic_machine=hppa1.1-hp - ;; - hp9k78[0-9] | hp78[0-9]) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][13679] | hp8[0-9][13679]) - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][0-9] | hp8[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hppa-next) - os=-nextstep3 - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; - i370-ibm* | ibm*) - basic_machine=i370-ibm - ;; -# I'm not sure what "Sysv32" means. Should this be sysv3.2? - i*86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 - ;; - i*86v4*) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv4 - ;; - i*86v) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv - ;; - i*86sol2) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-solaris2 - ;; - i386mach) - basic_machine=i386-mach - os=-mach - ;; - i386-vsta | vsta) - basic_machine=i386-unknown - os=-vsta - ;; - iris | iris4d) - basic_machine=mips-sgi - case $os in - -irix*) - ;; - *) - os=-irix4 - ;; - esac - ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; - m68knommu) - basic_machine=m68k-unknown - os=-linux - ;; - m68knommu-*) - basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - m88k-omron*) - basic_machine=m88k-omron - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv - ;; - mingw32) - basic_machine=i386-pc - os=-mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - os=-mingw32ce - ;; - miniframe) - basic_machine=m68000-convergent - ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; - mips3*-*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` - ;; - mips3*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - msdos) - basic_machine=i386-pc - os=-msdos - ;; - ms1-*) - basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos - ;; - news-3600 | risc-news) - basic_machine=mips-sony - os=-newsos - ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next ) - basic_machine=m68k-next - case $os in - -nextstep* ) - ;; - -ns2*) - os=-nextstep2 - ;; - *) - os=-nextstep3 - ;; - esac - ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; - np1) - basic_machine=np1-gould - ;; - nsr-tandem) - basic_machine=nsr-tandem - ;; - op50n-* | op60c-*) - basic_machine=hppa1.1-oki - os=-proelf - ;; - openrisc | openrisc-*) - basic_machine=or32-unknown - ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k - ;; - pa-hitachi) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - parisc) - basic_machine=hppa-unknown - os=-linux - ;; - parisc-*) - basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - pbd) - basic_machine=sparc-tti - ;; - pbb) - basic_machine=m68k-tti - ;; - pc532 | pc532-*) - basic_machine=ns32k-pc532 - ;; - pc98) - basic_machine=i386-pc - ;; - pc98-*) - basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium | p5 | k5 | k6 | nexgen | viac3) - basic_machine=i586-pc - ;; - pentiumpro | p6 | 6x86 | athlon | athlon_*) - basic_machine=i686-pc - ;; - pentiumii | pentium2 | pentiumiii | pentium3) - basic_machine=i686-pc - ;; - pentium4) - basic_machine=i786-pc - ;; - pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium4-*) - basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pn) - basic_machine=pn-gould - ;; - power) basic_machine=power-ibm - ;; - ppc) basic_machine=powerpc-unknown - ;; - ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppcle | powerpclittle | ppc-le | powerpc-little) - basic_machine=powerpcle-unknown - ;; - ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64) basic_machine=powerpc64-unknown - ;; - ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) - basic_machine=powerpc64le-unknown - ;; - ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ps2) - basic_machine=i386-ibm - ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff - ;; - rm[46]00) - basic_machine=mips-siemens - ;; - rtpc | rtpc-*) - basic_machine=romp-ibm - ;; - s390 | s390-*) - basic_machine=s390-ibm - ;; - s390x | s390x-*) - basic_machine=s390x-ibm - ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; - sb1) - basic_machine=mipsisa64sb1-unknown - ;; - sb1el) - basic_machine=mipsisa64sb1el-unknown - ;; - sde) - basic_machine=mipsisa32-sde - os=-elf - ;; - sei) - basic_machine=mips-sei - os=-seiux - ;; - sequent) - basic_machine=i386-sequent - ;; - sh) - basic_machine=sh-hitachi - os=-hms - ;; - sh5el) - basic_machine=sh5le-unknown - ;; - sh64) - basic_machine=sh64-unknown - ;; - sparclite-wrs | simso-wrs) - basic_machine=sparclite-wrs - os=-vxworks - ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 - ;; - spur) - basic_machine=spur-unknown - ;; - st2000) - basic_machine=m68k-tandem - ;; - stratus) - basic_machine=i860-stratus - os=-sysv4 - ;; - sun2) - basic_machine=m68000-sun - ;; - sun2os3) - basic_machine=m68000-sun - os=-sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - os=-sunos4 - ;; - sun3os3) - basic_machine=m68k-sun - os=-sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - os=-sunos4 - ;; - sun4os3) - basic_machine=sparc-sun - os=-sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - os=-sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - os=-solaris2 - ;; - sun3 | sun3-*) - basic_machine=m68k-sun - ;; - sun4) - basic_machine=sparc-sun - ;; - sun386 | sun386i | roadrunner) - basic_machine=i386-sun - ;; - sv1) - basic_machine=sv1-cray - os=-unicos - ;; - symmetry) - basic_machine=i386-sequent - os=-dynix - ;; - t3e) - basic_machine=alphaev5-cray - os=-unicos - ;; - t90) - basic_machine=t90-cray - os=-unicos - ;; - tic54x | c54x*) - basic_machine=tic54x-unknown - os=-coff - ;; - tic55x | c55x*) - basic_machine=tic55x-unknown - os=-coff - ;; - tic6x | c6x*) - basic_machine=tic6x-unknown - os=-coff - ;; - tile*) - basic_machine=tile-unknown - os=-linux-gnu - ;; - tx39) - basic_machine=mipstx39-unknown - ;; - tx39el) - basic_machine=mipstx39el-unknown - ;; - toad1) - basic_machine=pdp10-xkl - os=-tops20 - ;; - tower | tower-32) - basic_machine=m68k-ncr - ;; - tpf) - basic_machine=s390x-ibm - os=-tpf - ;; - udi29k) - basic_machine=a29k-amd - os=-udi - ;; - ultra3) - basic_machine=a29k-nyu - os=-sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - os=-none - ;; - vaxv) - basic_machine=vax-dec - os=-sysv - ;; - vms) - basic_machine=vax-dec - os=-vms - ;; - vpp*|vx|vx-*) - basic_machine=f301-fujitsu - ;; - vxworks960) - basic_machine=i960-wrs - os=-vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - os=-vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - os=-vxworks - ;; - w65*) - basic_machine=w65-wdc - os=-none - ;; - w89k-*) - basic_machine=hppa1.1-winbond - os=-proelf - ;; - xbox) - basic_machine=i686-pc - os=-mingw32 - ;; - xps | xps100) - basic_machine=xps100-honeywell - ;; - ymp) - basic_machine=ymp-cray - os=-unicos - ;; - z8k-*-coff) - basic_machine=z8k-unknown - os=-sim - ;; - none) - basic_machine=none-none - os=-none - ;; - -# Here we handle the default manufacturer of certain CPU types. It is in -# some cases the only manufacturer, in others, it is the most popular. - w89k) - basic_machine=hppa1.1-winbond - ;; - op50n) - basic_machine=hppa1.1-oki - ;; - op60c) - basic_machine=hppa1.1-oki - ;; - romp) - basic_machine=romp-ibm - ;; - mmix) - basic_machine=mmix-knuth - ;; - rs6000) - basic_machine=rs6000-ibm - ;; - vax) - basic_machine=vax-dec - ;; - pdp10) - # there are many clones, so DEC is not a safe bet - basic_machine=pdp10-unknown - ;; - pdp11) - basic_machine=pdp11-dec - ;; - we32k) - basic_machine=we32k-att - ;; - sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) - basic_machine=sh-unknown - ;; - sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) - basic_machine=sparc-sun - ;; - cydra) - basic_machine=cydra-cydrome - ;; - orion) - basic_machine=orion-highlevel - ;; - orion105) - basic_machine=clipper-highlevel - ;; - mac | mpw | mac-mpw) - basic_machine=m68k-apple - ;; - pmac | pmac-mpw) - basic_machine=powerpc-apple - ;; - *-unknown) - # Make sure to match an already-canonicalized machine name. - ;; - *) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; -esac - -# Here we canonicalize certain aliases for manufacturers. -case $basic_machine in - *-digital*) - basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` - ;; - *-commodore*) - basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` - ;; - *) - ;; -esac - -# Decode manufacturer-specific aliases for certain operating systems. - -if [ x"$os" != x"" ] -then -case $os in - # First match some system type aliases - # that might get confused with valid system types. - # -solaris* is a basic system type, with this one exception. - -solaris1 | -solaris1.*) - os=`echo $os | sed -e 's|solaris1|sunos4|'` - ;; - -solaris) - os=-solaris2 - ;; - -svr4*) - os=-sysv4 - ;; - -unixware*) - os=-sysv4.2uw - ;; - -gnu/linux*) - os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` - ;; - # First accept the basic system types. - # The portable systems comes first. - # Each alternative MUST END IN A *, to match a version number. - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -openbsd* | -solidbsd* \ - | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ - | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* \ - | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ - | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ - | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ - | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ - | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) - # Remember, each alternative MUST END IN *, to match a version number. - ;; - -qnx*) - case $basic_machine in - x86-* | i*86-*) - ;; - *) - os=-nto$os - ;; - esac - ;; - -nto-qnx*) - ;; - -nto*) - os=`echo $os | sed -e 's|nto|nto-qnx|'` - ;; - -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ - | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ - | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) - ;; - -mac*) - os=`echo $os | sed -e 's|mac|macos|'` - ;; - -linux-dietlibc) - os=-linux-dietlibc - ;; - -linux*) - os=`echo $os | sed -e 's|linux|linux-gnu|'` - ;; - -sunos5*) - os=`echo $os | sed -e 's|sunos5|solaris2|'` - ;; - -sunos6*) - os=`echo $os | sed -e 's|sunos6|solaris3|'` - ;; - -opened*) - os=-openedition - ;; - -os400*) - os=-os400 - ;; - -wince*) - os=-wince - ;; - -osfrose*) - os=-osfrose - ;; - -osf*) - os=-osf - ;; - -utek*) - os=-bsd - ;; - -dynix*) - os=-bsd - ;; - -acis*) - os=-aos - ;; - -atheos*) - os=-atheos - ;; - -syllable*) - os=-syllable - ;; - -386bsd) - os=-bsd - ;; - -ctix* | -uts*) - os=-sysv - ;; - -nova*) - os=-rtmk-nova - ;; - -ns2 ) - os=-nextstep2 - ;; - -nsk*) - os=-nsk - ;; - # Preserve the version number of sinix5. - -sinix5.*) - os=`echo $os | sed -e 's|sinix|sysv|'` - ;; - -sinix*) - os=-sysv4 - ;; - -tpf*) - os=-tpf - ;; - -triton*) - os=-sysv3 - ;; - -oss*) - os=-sysv3 - ;; - -svr4) - os=-sysv4 - ;; - -svr3) - os=-sysv3 - ;; - -sysvr4) - os=-sysv4 - ;; - # This must come after -sysvr4. - -sysv*) - ;; - -ose*) - os=-ose - ;; - -es1800*) - os=-ose - ;; - -xenix) - os=-xenix - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - os=-mint - ;; - -aros*) - os=-aros - ;; - -kaos*) - os=-kaos - ;; - -zvmoe) - os=-zvmoe - ;; - -none) - ;; - *) - # Get rid of the `-' at the beginning of $os. - os=`echo $os | sed 's/[^-]*-//'` - echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 - exit 1 - ;; -esac -else - -# Here we handle the default operating systems that come with various machines. -# The value should be what the vendor currently ships out the door with their -# machine or put another way, the most popular os provided with the machine. - -# Note that if you're going to try to match "-MANUFACTURER" here (say, -# "-sun"), then you have to tell the case statement up towards the top -# that MANUFACTURER isn't an operating system. Otherwise, code above -# will signal an error saying that MANUFACTURER isn't an operating -# system, and we'll never get to this point. - -case $basic_machine in - score-*) - os=-elf - ;; - spu-*) - os=-elf - ;; - *-acorn) - os=-riscix1.2 - ;; - arm*-rebel) - os=-linux - ;; - arm*-semi) - os=-aout - ;; - c4x-* | tic4x-*) - os=-coff - ;; - # This must come before the *-dec entry. - pdp10-*) - os=-tops20 - ;; - pdp11-*) - os=-none - ;; - *-dec | vax-*) - os=-ultrix4.2 - ;; - m68*-apollo) - os=-domain - ;; - i386-sun) - os=-sunos4.0.2 - ;; - m68000-sun) - os=-sunos3 - # This also exists in the configure program, but was not the - # default. - # os=-sunos4 - ;; - m68*-cisco) - os=-aout - ;; - mep-*) - os=-elf - ;; - mips*-cisco) - os=-elf - ;; - mips*-*) - os=-elf - ;; - or32-*) - os=-coff - ;; - *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 - ;; - sparc-* | *-sun) - os=-sunos4.1.1 - ;; - *-be) - os=-beos - ;; - *-haiku) - os=-haiku - ;; - *-ibm) - os=-aix - ;; - *-knuth) - os=-mmixware - ;; - *-wec) - os=-proelf - ;; - *-winbond) - os=-proelf - ;; - *-oki) - os=-proelf - ;; - *-hp) - os=-hpux - ;; - *-hitachi) - os=-hiux - ;; - i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv - ;; - *-cbm) - os=-amigaos - ;; - *-dg) - os=-dgux - ;; - *-dolphin) - os=-sysv3 - ;; - m68k-ccur) - os=-rtu - ;; - m88k-omron*) - os=-luna - ;; - *-next ) - os=-nextstep - ;; - *-sequent) - os=-ptx - ;; - *-crds) - os=-unos - ;; - *-ns) - os=-genix - ;; - i370-*) - os=-mvs - ;; - *-next) - os=-nextstep3 - ;; - *-gould) - os=-sysv - ;; - *-highlevel) - os=-bsd - ;; - *-encore) - os=-bsd - ;; - *-sgi) - os=-irix - ;; - *-siemens) - os=-sysv4 - ;; - *-masscomp) - os=-rtu - ;; - f30[01]-fujitsu | f700-fujitsu) - os=-uxpv - ;; - *-rom68k) - os=-coff - ;; - *-*bug) - os=-coff - ;; - *-apple) - os=-macos - ;; - *-atari*) - os=-mint - ;; - *) - os=-none - ;; -esac -fi - -# Here we handle the case where we know the os, and the CPU type, but not the -# manufacturer. We pick the logical manufacturer. -vendor=unknown -case $basic_machine in - *-unknown) - case $os in - -riscix*) - vendor=acorn - ;; - -sunos*) - vendor=sun - ;; - -aix*) - vendor=ibm - ;; - -beos*) - vendor=be - ;; - -hpux*) - vendor=hp - ;; - -mpeix*) - vendor=hp - ;; - -hiux*) - vendor=hitachi - ;; - -unos*) - vendor=crds - ;; - -dgux*) - vendor=dg - ;; - -luna*) - vendor=omron - ;; - -genix*) - vendor=ns - ;; - -mvs* | -opened*) - vendor=ibm - ;; - -os400*) - vendor=ibm - ;; - -ptx*) - vendor=sequent - ;; - -tpf*) - vendor=ibm - ;; - -vxsim* | -vxworks* | -windiss*) - vendor=wrs - ;; - -aux*) - vendor=apple - ;; - -hms*) - vendor=hitachi - ;; - -mpw* | -macos*) - vendor=apple - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - vendor=atari - ;; - -vos*) - vendor=stratus - ;; - esac - basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` - ;; -esac - -echo $basic_machine$os -exit - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/support/mail-shell~ b/support/mail-shell~ deleted file mode 100644 index 19400765c..000000000 --- a/support/mail-shell~ +++ /dev/null @@ -1,127 +0,0 @@ -#! /bin/bash -# -# mail-shell -- mail out the shell -# -# usage: mail-shell -t tarball recipient -# -# Chet Ramey -# chet@ins.CWRU.Edu -# - -# Copyright (C) 1995-2008 by Chester Ramey -# -# 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 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - - -PATH=/usr/ucb:/bin:/usr/bin:/usr/local/bin/gnu:/usr/local/bin:. - -trap 'rm -f x?? ${UUFILE}' 0 1 2 3 6 15 - -prog=`basename $0` - -TARFILE=bash.tar -VERS=2.05b - -while getopts t: opt -do - case $opt in - t) TARFILE=$OPTARG ;; - *) echo usage: $prog [ -t tarfile ] recipient 1>&2 - exit 1 - esac -done - -shift $(( $OPTIND - 1 )) - -case "$TARFILE" in -bash-*.tar) VERS=${TARFILE%%.tar} ; VERS=${VERS#bash-} ;; -esac - -GZFILE=${TARFILE}.gz -UUFILE=${GZFILE}.uu - -if [ $# -ne 1 ] ; then - echo usage: $0 recipient - exit 1 -fi - -recip=$1 -i=1 - -if [ ! -f ${TARFILE} ] && [ ! -f ${GZFILE} ]; then - echo "$prog: no file ${TARFILE}, aborting" - exit 1 -fi - -if [ ! -f ${GZFILE} ] ; then - echo "$prog: no gzipped tar file ${GZFILE}" - echo "$prog: gzipping ${TARFILE}" - gzip ${TARFILE} -fi - -if [ ! -f ${UUFILE} ] ; then - echo "$prog: no uuencoded tar file ${UUFILE}" - echo "$prog: uuencoding ${GZFILE}" - uuencode ${GZFILE} < ${GZFILE} > ${UUFILE} -fi - -files=$(echo x??) - -if [ "$files" = 'x??' ] ; then - echo "$prog: no split of ${UUFILE} exists" - echo "$prog: splitting ${UUFILE}" - split ${UUFILE} -fi - -count() -{ - echo $# -} - -parts=$(count x??) - -if [ -x /usr/ucb/mail ]; then - MAIL=/usr/ucb/mail -elif [ -x /usr/ucb/Mail ]; then - MAIL=/usr/ucb/Mail -elif [ -x /usr/bin/mailx ]; then - MAIL=/usr/bin/mailx -elif [ -x /usr/bin/mail ]; then - MAIL=/usr/bin/mail -else - MAIL=/bin/mail -fi - -$MAIL -s "bash-${VERS} shipment coming" $recip <&2 ; exit 2 ;; - esac -done - -# Required arguments -if [ -z "$dist_version" ]; then - echo "${PROGNAME}: required argument -d missing" >&2 - echo "$PROGNAME: usage: $USAGE" >&2 - exit 1 -fi - -#if [ -z "$patch_level" ]; then -# echo "${PROGNAME}: required argument -p missing" >&2 -# echo "$PROGNAME: usage: $USAGE" >&2 -# exit 1 -#fi - -# Defaults -if [ -z "$rel_status" ]; then - rel_status="release" -fi - -build_ver= -if [ -r .build ]; then - build_ver=`cat .build` -fi -if [ -z "$build_ver" ]; then - build_ver=0 -fi - -# increment the build version if that's what's required - -if [ -n "$inc_build" ]; then - build_ver=`expr 1 + $build_ver` -fi - -# what's the patch level? -if [ -z "$patch_level" ]; then - patchlevel_h=$source_dir/patchlevel.h - if [ -s $patchlevel_h ]; then - patch_level=`cat $patchlevel_h | grep '^#define[ ]*PATCHLEVEL' | awk '{print $NF}'` - fi -fi -if [ -z "$patch_level" ]; then - patch_level=0 -fi - -# If we have an output file specified, make it the standard output -if [ -n "$OUTFILE" ]; then - if exec >$OUTFILE; then - : - else - echo "${PROGNAME}: cannot redirect standard output to $OUTFILE" >&2 - exit 1 - fi -fi - -# Output the leading comment. -echo "/* Version control for the shell. This file gets changed when you say" -echo " \`make version.h' to the Makefile. It is created by mkversion. */" - -# Output the distribution version. Single numbers are converted to x.00. -# Allow, as a special case, `[:digit:].[:digit:][:alpha:]' for -# intermediate versions (e.g., `2.5a'). -# Any characters other than digits and `.' are invalid. -case "$dist_version" in -[0-9].[0-9][a-z]) ;; # special case -*[!0-9.]*) echo "mkversion.sh: ${dist_version}: bad distribution version" >&2 - exit 1 ;; -*.*) ;; -*) dist_version=${dist_version}.00 ;; -esac - -dist_major=`echo $dist_version | sed 's:\..*$::'` -[ -z "${dist_major}" ] && dist_major=0 - -dist_minor=`echo $dist_version | sed 's:^.*\.::'` -case "$dist_minor" in -"") dist_minor=0 ;; -[a-z]) dist_minor=0${dist_minor} ;; -?) dist_minor=${dist_minor} ;; -*) ;; -esac - -#float_dist=`echo $dist_version | awk '{printf "%.2f\n", $1}'` -float_dist=${dist_major}.${dist_minor} - -echo -echo "/* The distribution version number of this shell. */" -echo "#define DISTVERSION \"${float_dist}\"" - -# Output the patch level -#echo -#echo "/* The patch level of this version of the shell. */" -#echo "#define PATCHLEVEL ${patch_level}" - -# Output the build version -echo -echo "/* The last built version of this shell. */" -echo "#define BUILDVERSION ${build_ver}" - -# Output the release status -echo -echo "/* The release status of this shell. */" -echo "#define RELSTATUS \"${rel_status}\"" - -echo "#define DEFAULT_COMPAT_LEVEL ${dist_major}${dist_minor}" - -# Output the SCCS version string -sccs_string="${float_dist}.${patch_level}(${build_ver}) ${rel_status} GNU" -echo -echo "/* A version string for use by sccs and the what command. */" -echo "#define SCCSVERSION \"@(#)Bash version ${sccs_string}\"" - -# extern function declarations -#echo -#echo '/* Functions from version.c. */' -#echo 'extern char *shell_version_string __P((void));' -#echo 'extern void show_shell_version __P((int));' - -if [ -n "$inc_build" ]; then - # Make sure we can write to .build - if [ -f .build ] && [ ! -w .build ]; then - echo "$PROGNAME: cannot write to .build, not incrementing build version" >&2 - else - echo "$build_ver" > .build - fi -fi - -exit 0 diff --git a/support/shobj-conf~ b/support/shobj-conf~ deleted file mode 100755 index 6a6aae949..000000000 --- a/support/shobj-conf~ +++ /dev/null @@ -1,568 +0,0 @@ -#! /bin/sh -# -# shobj-conf -- output a series of variable assignments to be substituted -# into a Makefile by configure which specify system-dependent -# information for creating shared objects that may be loaded -# into bash with `enable -f' -# -# usage: shobj-conf [-C compiler] -c host_cpu -o host_os -v host_vendor -# -# Chet Ramey -# chet@po.cwru.edu - -# Copyright (C) 1996-2008 Free Software Foundation, Inc. -# -# This file is part of GNU Bash, the Bourne Again SHell. -# -# 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 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -# -# defaults -# -SHOBJ_STATUS=supported -SHLIB_STATUS=supported - -SHOBJ_CC=cc -SHOBJ_CFLAGS= -SHOBJ_LD= -SHOBJ_LDFLAGS= -SHOBJ_XLDFLAGS= -SHOBJ_LIBS= - -SHLIB_XLDFLAGS= -SHLIB_LIBS= - -SHLIB_DOT='.' -SHLIB_LIBPREF='lib' -SHLIB_LIBSUFF='so' - -SHLIB_LIBVERSION='$(SHLIB_LIBSUFF)' -SHLIB_DLLVERSION='$(SHLIB_MAJOR)' - -PROGNAME=`basename $0` -USAGE="$PROGNAME [-C compiler] -c host_cpu -o host_os -v host_vendor" - -while [ $# -gt 0 ]; do - case "$1" in - -C) shift; SHOBJ_CC="$1"; shift ;; - -c) shift; host_cpu="$1"; shift ;; - -o) shift; host_os="$1"; shift ;; - -v) shift; host_vendor="$1"; shift ;; - *) echo "$USAGE" >&2 ; exit 2;; - esac -done - -case "${host_os}-${SHOBJ_CC}" in -sunos4*-*gcc*) - SHOBJ_CFLAGS=-fpic - SHOBJ_LD=/usr/bin/ld - SHOBJ_LDFLAGS='-assert pure-text' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' - ;; - -sunos4*) - SHOBJ_CFLAGS=-pic - SHOBJ_LD=/usr/bin/ld - SHOBJ_LDFLAGS='-assert pure-text' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' - ;; - -sunos5*-*gcc*|solaris2*-*gcc*) - SHOBJ_LD='${CC}' - ld_used=`gcc -print-prog-name=ld` - if ${ld_used} -V 2>&1 | grep GNU >/dev/null 2>&1; then - # This line works for the GNU ld - SHOBJ_LDFLAGS='-shared -Wl,-h,$@' - # http://sourceware.org/ml/binutils/2001-08/msg00361.html - SHOBJ_CFLAGS=-fPIC - else - # This line works for the Solaris linker in /usr/ccs/bin/ld - SHOBJ_LDFLAGS='-shared -Wl,-i -Wl,-h,$@' - SHOBJ_CFLAGS=-fpic - fi - -# SHLIB_XLDFLAGS='-R $(libdir)' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -sunos5*|solaris2*) - SHOBJ_CFLAGS='-K pic' - SHOBJ_LD=/usr/ccs/bin/ld - SHOBJ_LDFLAGS='-G -dy -z text -i -h $@' - -# SHLIB_XLDFLAGS='-R $(libdir)' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -# All versions of Linux or the semi-mythical GNU Hurd. -linux*-*|gnu*-*|k*bsd*-gnu-*) - SHOBJ_CFLAGS=-fPIC - SHOBJ_LD='${CC}' - SHOBJ_LDFLAGS='-shared -Wl,-soname,$@' - - SHLIB_XLDFLAGS='-Wl,-rpath,$(libdir) -Wl,-soname,`basename $@ $(SHLIB_MINOR)`' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' - ;; - -freebsd2*) - SHOBJ_CFLAGS=-fpic - SHOBJ_LD=ld - SHOBJ_LDFLAGS='-x -Bshareable' - - SHLIB_XLDFLAGS='-R$(libdir)' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' - ;; - -# FreeBSD-3.x ELF -freebsd[3-9]*|freebsdelf[3-9]*|freebsdaout[3-9]*|dragonfly*) - SHOBJ_CFLAGS=-fPIC - SHOBJ_LD='${CC}' - - if [ -x /usr/bin/objformat ] && [ "`/usr/bin/objformat`" = "elf" ]; then - SHOBJ_LDFLAGS='-shared -Wl,-soname,$@' - - SHLIB_XLDFLAGS='-Wl,-rpath,$(libdir)' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - else - SHOBJ_LDFLAGS='-shared' - - SHLIB_XLDFLAGS='-R$(libdir)' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' - fi - ;; - -# Darwin/MacOS X -darwin[89]*) - SHOBJ_STATUS=supported - SHLIB_STATUS=supported - - SHOBJ_CFLAGS='-fno-common' - - SHOBJ_LD='MACOSX_DEPLOYMENT_TARGET=10.3 ${CC}' - - SHLIB_LIBVERSION='$(SHLIB_MAJOR)$(SHLIB_MINOR).$(SHLIB_LIBSUFF)' - SHLIB_LIBSUFF='dylib' - - SHOBJ_LDFLAGS='-dynamiclib -dynamic -undefined dynamic_lookup -arch_only `/usr/bin/arch`' - SHLIB_XLDFLAGS='-dynamiclib -arch_only `/usr/bin/arch` -install_name $(libdir)/$@ -current_version $(SHLIB_MAJOR)$(SHLIB_MINOR) -compatibility_version $(SHLIB_MAJOR) -v' - - SHLIB_LIBS='-lncurses' # see if -lcurses works on MacOS X 10.1 - ;; - -darwin*|macosx*) - SHOBJ_STATUS=unsupported - SHLIB_STATUS=supported - - SHOBJ_CFLAGS='-fno-common' - - SHOBJ_LD='${CC}' - - SHLIB_LIBVERSION='$(SHLIB_MAJOR)$(SHLIB_MINOR).$(SHLIB_LIBSUFF)' - SHLIB_LIBSUFF='dylib' - - case "${host_os}" in - darwin[789]*|darwin10*) SHOBJ_LDFLAGS='' - SHLIB_XLDFLAGS='-dynamiclib -arch_only `/usr/bin/arch` -install_name $(libdir)/$@ -current_version $(SHLIB_MAJOR)$(SHLIB_MINOR) -compatibility_version $(SHLIB_MAJOR) -v' - ;; - *) SHOBJ_LDFLAGS='-dynamic' - SHLIB_XLDFLAGS='-arch_only `/usr/bin/arch` -install_name $(libdir)/$@ -current_version $(SHLIB_MAJOR)$(SHLIB_MINOR) -compatibility_version $(SHLIB_MAJOR) -v' - ;; - esac - - SHLIB_LIBS='-lncurses' # see if -lcurses works on MacOS X 10.1 - ;; - -openbsd*|netbsd*) - SHOBJ_CFLAGS=-fPIC - SHOBJ_LD='${CC}' - SHOBJ_LDFLAGS='-shared' - - SHLIB_XLDFLAGS='-R$(libdir)' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' - ;; - -bsdi2*) - SHOBJ_CC=shlicc2 - SHOBJ_CFLAGS= - SHOBJ_LD=ld - SHOBJ_LDFLAGS=-r - SHOBJ_LIBS=-lc_s.2.1.0 - - # BSD/OS 2.x and 3.x `shared libraries' are too much of a pain in - # the ass -- they require changing {/usr/lib,etc}/shlib.map on - # each system, and the library creation process is byzantine - SHLIB_STATUS=unsupported - ;; - -bsdi3*) - SHOBJ_CC=shlicc2 - SHOBJ_CFLAGS= - SHOBJ_LD=ld - SHOBJ_LDFLAGS=-r - SHOBJ_LIBS=-lc_s.3.0.0 - - # BSD/OS 2.x and 3.x `shared libraries' are too much of a pain in - # the ass -- they require changing {/usr/lib,etc}/shlib.map on - # each system, and the library creation process is byzantine - SHLIB_STATUS=unsupported - ;; - -bsdi4*) - # BSD/OS 4.x now supports ELF and SunOS-style dynamically-linked - # shared libraries. gcc 2.x is the standard compiler, and the - # `normal' gcc options should work as they do in Linux. - - SHOBJ_CFLAGS=-fPIC - SHOBJ_LD='${CC}' - SHOBJ_LDFLAGS='-shared -Wl,-soname,$@' - - SHLIB_XLDFLAGS='-Wl,-soname,`basename $@ $(SHLIB_MINOR)`' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' - ;; - -osf*-*gcc*) - # Fix to use gcc linker driver from bfischer@TechFak.Uni-Bielefeld.DE - SHOBJ_LD='${CC}' - SHOBJ_LDFLAGS='-shared -Wl,-soname,$@' - - SHLIB_XLDFLAGS='-rpath $(libdir)' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -osf*) - SHOBJ_LD=ld - SHOBJ_LDFLAGS='-shared -soname $@ -expect_unresolved "*"' - - SHLIB_XLDFLAGS='-rpath $(libdir)' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -aix4.[2-9]*-*gcc*|aix[5-9].*-*gcc*) # lightly tested by jik@cisco.com - SHOBJ_CFLAGS=-fpic - SHOBJ_LD='ld' - SHOBJ_LDFLAGS='-bdynamic -bnoentry -bexpall' - SHOBJ_XLDFLAGS='-G' - - SHLIB_XLDFLAGS='-bM:SRE' - SHLIB_LIBS='-lcurses -lc' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -aix4.[2-9]*|aix[5-9].*) - SHOBJ_CFLAGS=-K - SHOBJ_LD='ld' - SHOBJ_LDFLAGS='-bdynamic -bnoentry -bexpall' - SHOBJ_XLDFLAGS='-G' - - SHLIB_XLDFLAGS='-bM:SRE' - SHLIB_LIBS='-lcurses -lc' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -# -# THE FOLLOWING ARE UNTESTED -- and some may not support the dlopen interface -# -irix[56]*-*gcc*) - SHOBJ_CFLAGS='-fpic' - SHOBJ_LD='${CC}' - SHOBJ_LDFLAGS='-shared -Wl,-soname,$@' - - SHLIB_XLDFLAGS='-Wl,-rpath,$(libdir)' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -irix[56]*) - SHOBJ_CFLAGS='-K PIC' - SHOBJ_LD=ld -# SHOBJ_LDFLAGS='-call_shared -hidden_symbol -no_unresolved -soname $@' -# Change from David Kaelbling . If you have problems, -# remove the `-no_unresolved' - SHOBJ_LDFLAGS='-shared -no_unresolved -soname $@' - - SHLIB_XLDFLAGS='-rpath $(libdir)' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -hpux9*-*gcc*) - # must use gcc; the bundled cc cannot compile PIC code - SHOBJ_CFLAGS='-fpic' - SHOBJ_LD='${CC}' - SHOBJ_LDFLAGS='-shared -Wl,-b -Wl,+s' - - SHLIB_XLDFLAGS='-Wl,+b,$(libdir)' - SHLIB_LIBSUFF='sl' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -hpux9*) - SHOBJ_STATUS=unsupported - SHLIB_STATUS=unsupported - - # If you are using the HP ANSI C compiler, you can uncomment and use - # this code (I have not tested it) -# SHOBJ_STATUS=supported -# SHLIB_STATUS=supported -# -# SHOBJ_CFLAGS='+z' -# SHOBJ_LD='ld' -# SHOBJ_LDFLAGS='-b +s' -# -# SHLIB_XLDFLAGS='+b $(libdir)' -# SHLIB_LIBSUFF='sl' -# SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - - ;; - -hpux10*-*gcc*) - # must use gcc; the bundled cc cannot compile PIC code - SHOBJ_CFLAGS='-fpic' - SHOBJ_LD='${CC}' - # if you have problems linking here, moving the `-Wl,+h,$@' from - # SHLIB_XLDFLAGS to SHOBJ_LDFLAGS has been reported to work - SHOBJ_LDFLAGS='-shared -fpic -Wl,-b -Wl,+s' - - SHLIB_XLDFLAGS='-Wl,+h,$@ -Wl,+b,$(libdir)' - SHLIB_LIBSUFF='sl' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -hpux10*) - SHOBJ_STATUS=unsupported - SHLIB_STATUS=unsupported - - # If you are using the HP ANSI C compiler, you can uncomment and use - # this code (I have not tested it) -# SHOBJ_STATUS=supported -# SHLIB_STATUS=supported -# -# SHOBJ_CFLAGS='+z' -# SHOBJ_LD='ld' -# SHOBJ_LDFLAGS='-b +s +h $@' -# -# SHLIB_XLDFLAGS='+b $(libdir)' -# SHLIB_LIBSUFF='sl' -# SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - - ;; - -hpux11*-*gcc*) - # must use gcc; the bundled cc cannot compile PIC code - SHOBJ_CFLAGS='-fpic' - SHOBJ_LD='${CC}' -# SHOBJ_LDFLAGS='-shared -Wl,-b -Wl,-B,symbolic -Wl,+s -Wl,+std -Wl,+h,$@' - SHOBJ_LDFLAGS='-shared -fpic -Wl,-b -Wl,+s -Wl,+h,$@' - - SHLIB_XLDFLAGS='-Wl,+b,$(libdir)' - SHLIB_LIBSUFF='sl' - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -hpux11*) - SHOBJ_STATUS=unsupported - SHLIB_STATUS=unsupported - - # If you are using the HP ANSI C compiler, you can uncomment and use - # this code (I have not tested it) -# SHOBJ_STATUS=supported -# SHLIB_STATUS=supported -# -# SHOBJ_CFLAGS='+z' -# SHOBJ_LD='ld' -# SHOBJ_LDFLAGS='-b +s +h $@' -# -# SHLIB_XLDFLAGS='+b $(libdir)' -# SHLIB_LIBSUFF='sl' -# SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - - ;; - -sysv4*-*gcc*) - SHOBJ_CFLAGS=-shared - SHOBJ_LDFLAGS='-shared -h $@' - SHOBJ_LD='${CC}' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -sysv4*) - SHOBJ_CFLAGS='-K PIC' - SHOBJ_LD=ld - SHOBJ_LDFLAGS='-dy -z text -G -h $@' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -sco3.2v5*-*gcc*) - SHOBJ_CFLAGS='-fpic' # DEFAULTS TO ELF - SHOBJ_LD='${CC}' - SHOBJ_LDFLAGS='-shared' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -sco3.2v5*) - SHOBJ_CFLAGS='-K pic -b elf' - SHOBJ_LD=ld - SHOBJ_LDFLAGS='-G -b elf -dy -z text -h $@' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -sysv5uw7*-*gcc*) - SHOBJ_CFLAGS='-fpic' - SHOBJ_LD='${CC}' - SHOBJ_LDFLAGS='-shared' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -sysv5uw7*) - SHOBJ_CFLAGS='-K PIC' - SHOBJ_LD=ld - SHOBJ_LDFLAGS='-G -dy -z text -h $@' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -sysv5UnixWare*-*gcc*) - SHOBJ_CFLAGS=-fpic - SHOBJ_LD='${CC}' - SHOBJ_LDFLAGS='-shared' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -sysv5UnixWare*) - SHOBJ_CFLAGS='-K PIC' - SHOBJ_LD=ld - SHOBJ_LDFLAGS='-G -dy -z text -h $@' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -sysv5OpenUNIX*-*gcc*) - SHOBJ_CFLAGS=-fpic - SHOBJ_LD='${CC}' - SHOBJ_LDFLAGS='-shared' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -sysv5OpenUNIX*) - SHOBJ_CFLAGS='-K PIC' - SHOBJ_LD=ld - SHOBJ_LDFLAGS='-G -dy -z text -h $@' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -dgux*-*gcc*) - SHOBJ_CFLAGS=-fpic - SHOBJ_LD='${CC}' - SHOBJ_LDFLAGS='-shared' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -dgux*) - SHOBJ_CFLAGS='-K pic' - SHOBJ_LD=ld - SHOBJ_LDFLAGS='-G -dy -h $@' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -msdos*) - SHOBJ_STATUS=unsupported - SHLIB_STATUS=unsupported - ;; - -cygwin*) - SHOBJ_LD='$(CC)' - SHOBJ_LDFLAGS='-shared -Wl,--enable-auto-import -Wl,--enable-auto-image-base -Wl,--export-all -Wl,--out-implib=$(@).a' - SHLIB_LIBPREF='cyg' - SHLIB_LIBSUFF='dll' - SHLIB_LIBVERSION='$(SHLIB_DLLVERSION).$(SHLIB_LIBSUFF)' - SHLIB_LIBS='$(TERMCAP_LIB)' - - SHLIB_DOT= - # For official cygwin releases, DLLVERSION will be defined in the - # environment of configure, and will be incremented any time the API - # changes in a non-backwards compatible manner. Otherwise, it is just - # SHLIB_MAJOR. - if [ -n "$DLLVERSION" ] ; then - SHLIB_DLLVERSION="$DLLVERSION" - fi - ;; - -mingw*) - SHOBJ_LD='$(CC)' - SHOBJ_LDFLAGS='-shared -Wl,--enable-auto-import -Wl,--enable-auto-image-base -Wl,--export-all -Wl,--out-implib=$(@).a' - SHLIB_LIBSUFF='dll' - SHLIB_LIBVERSION='$(SHLIB_DLLVERSION).$(SHLIB_LIBSUFF)' - SHLIB_LIBS='$(TERMCAP_LIB)' - - SHLIB_DOT= - # For official cygwin releases, DLLVERSION will be defined in the - # environment of configure, and will be incremented any time the API - # changes in a non-backwards compatible manner. Otherwise, it is just - # SHLIB_MAJOR. - if [ -n "$DLLVERSION" ] ; then - SHLIB_DLLVERSION="$DLLVERSION" - fi - ;; - -# -# Rely on correct gcc configuration for everything else -# -*-*gcc*) - SHOBJ_CFLAGS=-fpic - SHOBJ_LD='${CC}' - SHOBJ_LDFLAGS='-shared' - - SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' - ;; - -*) - SHOBJ_STATUS=unsupported - SHLIB_STATUS=unsupported - ;; - -esac - -echo SHOBJ_CC=\'"$SHOBJ_CC"\' -echo SHOBJ_CFLAGS=\'"$SHOBJ_CFLAGS"\' -echo SHOBJ_LD=\'"$SHOBJ_LD"\' -echo SHOBJ_LDFLAGS=\'"$SHOBJ_LDFLAGS"\' -echo SHOBJ_XLDFLAGS=\'"$SHOBJ_XLDFLAGS"\' -echo SHOBJ_LIBS=\'"$SHOBJ_LIBS"\' - -echo SHLIB_XLDFLAGS=\'"$SHLIB_XLDFLAGS"\' -echo SHLIB_LIBS=\'"$SHLIB_LIBS"\' - -echo SHLIB_DOT=\'"$SHLIB_DOT"\' - -echo SHLIB_LIBPREF=\'"$SHLIB_LIBPREF"\' -echo SHLIB_LIBSUFF=\'"$SHLIB_LIBSUFF"\' - -echo SHLIB_LIBVERSION=\'"$SHLIB_LIBVERSION"\' -echo SHLIB_DLLVERSION=\'"$SHLIB_DLLVERSION"\' - -echo SHOBJ_STATUS=\'"$SHOBJ_STATUS"\' -echo SHLIB_STATUS=\'"$SHLIB_STATUS"\' - -exit 0 diff --git a/support/xcase.c~ b/support/xcase.c~ deleted file mode 100644 index 7b465a30c..000000000 --- a/support/xcase.c~ +++ /dev/null @@ -1,92 +0,0 @@ -/* xcase - change uppercase characters to lowercase or vice versa. */ - -/* Copyright (C) 2008 Free Software Foundation, Inc. - - This file is part of GNU Bash. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#define HAVE_UNISTD_H 1 - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#if HAVE_UNISTD_H -#include -#endif -#include -#include - -#define LOWER 1 -#define UPPER 2 - -main(ac, av) -int ac; -char **av; -{ - int c, x; - int op; - FILE *inf; - - op = 0; - while ((c = getopt(ac, av, "lnu")) != EOF) { - switch (c) { - case 'n': - setbuf (stdout, (char *)NULL); - break; - case 'u': - op = UPPER; - break; - case 'l': - op = LOWER; - break; - default: - fprintf(stderr, "casemod: usage: casemod [-lnu] [file]\n"); - exit(2); - } - } - av += optind; - ac -= optind; - - if (av[0] && (av[0][0] != '-' || av[0][1])) { - inf = fopen(av[0], "r"); - if (inf == 0) { - fprintf(stderr, "casemod: %s: cannot open: %s\n", av[0], strerror(errno)); - exit(1); - } - } else - inf = stdin; - - while ((c = getc(inf)) != EOF) { - switch (op) { - case UPPER: - x = islower(c) ? toupper(c) : c; - break; - case LOWER: - x = isupper(c) ? tolower(c) : c; - break; - default: - x = c; - break; - } - putchar(x); - } - - exit(0); -} diff --git a/test.c~ b/test.c~ deleted file mode 100644 index b4639a891..000000000 --- a/test.c~ +++ /dev/null @@ -1,825 +0,0 @@ -/* test.c - GNU test program (ksb and mjb) */ - -/* Modified to run with the GNU shell Apr 25, 1988 by bfox. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -/* Define PATTERN_MATCHING to get the csh-like =~ and !~ pattern-matching - binary operators. */ -/* #define PATTERN_MATCHING */ - -#if defined (HAVE_CONFIG_H) -# include -#endif - -#include - -#include "bashtypes.h" - -#if !defined (HAVE_LIMITS_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#if !defined (errno) -extern int errno; -#endif /* !errno */ - -#if !defined (_POSIX_VERSION) && defined (HAVE_SYS_FILE_H) -# include -#endif /* !_POSIX_VERSION */ -#include "posixstat.h" -#include "filecntl.h" - -#include "bashintl.h" - -#include "shell.h" -#include "pathexp.h" -#include "test.h" -#include "builtins/common.h" - -#include - -#if !defined (STRLEN) -# define STRLEN(s) ((s)[0] ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0) -#endif - -#if !defined (STREQ) -# define STREQ(a, b) ((a)[0] == (b)[0] && strcmp (a, b) == 0) -#endif /* !STREQ */ - -#if !defined (R_OK) -#define R_OK 4 -#define W_OK 2 -#define X_OK 1 -#define F_OK 0 -#endif /* R_OK */ - -#define EQ 0 -#define NE 1 -#define LT 2 -#define GT 3 -#define LE 4 -#define GE 5 - -#define NT 0 -#define OT 1 -#define EF 2 - -/* The following few defines control the truth and false output of each stage. - TRUE and FALSE are what we use to compute the final output value. - SHELL_BOOLEAN is the form which returns truth or falseness in shell terms. - Default is TRUE = 1, FALSE = 0, SHELL_BOOLEAN = (!value). */ -#define TRUE 1 -#define FALSE 0 -#define SHELL_BOOLEAN(value) (!(value)) - -#define TEST_ERREXIT_STATUS 2 - -static procenv_t test_exit_buf; -static int test_error_return; -#define test_exit(val) \ - do { test_error_return = val; longjmp (test_exit_buf, 1); } while (0) - -extern int sh_stat __P((const char *, struct stat *)); - -static int pos; /* The offset of the current argument in ARGV. */ -static int argc; /* The number of arguments present in ARGV. */ -static char **argv; /* The argument list. */ -static int noeval; - -static void test_syntax_error __P((char *, char *)) __attribute__((__noreturn__)); -static void beyond __P((void)) __attribute__((__noreturn__)); -static void integer_expected_error __P((char *)) __attribute__((__noreturn__)); - -static int unary_operator __P((void)); -static int binary_operator __P((void)); -static int two_arguments __P((void)); -static int three_arguments __P((void)); -static int posixtest __P((void)); - -static int expr __P((void)); -static int term __P((void)); -static int and __P((void)); -static int or __P((void)); - -static int filecomp __P((char *, char *, int)); -static int arithcomp __P((char *, char *, int, int)); -static int patcomp __P((char *, char *, int)); - -static void -test_syntax_error (format, arg) - char *format, *arg; -{ - builtin_error (format, arg); - test_exit (TEST_ERREXIT_STATUS); -} - -/* - * beyond - call when we're beyond the end of the argument list (an - * error condition) - */ -static void -beyond () -{ - test_syntax_error (_("argument expected"), (char *)NULL); -} - -/* Syntax error for when an integer argument was expected, but - something else was found. */ -static void -integer_expected_error (pch) - char *pch; -{ - test_syntax_error (_("%s: integer expression expected"), pch); -} - -/* Increment our position in the argument list. Check that we're not - past the end of the argument list. This check is supressed if the - argument is FALSE. Made a macro for efficiency. */ -#define advance(f) do { ++pos; if (f && pos >= argc) beyond (); } while (0) -#define unary_advance() do { advance (1); ++pos; } while (0) - -/* - * expr: - * or - */ -static int -expr () -{ - if (pos >= argc) - beyond (); - - return (FALSE ^ or ()); /* Same with this. */ -} - -/* - * or: - * and - * and '-o' or - */ -static int -or () -{ - int value, v2; - - value = and (); - if (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'o' && !argv[pos][2]) - { - advance (0); - v2 = or (); - return (value || v2); - } - - return (value); -} - -/* - * and: - * term - * term '-a' and - */ -static int -and () -{ - int value, v2; - - value = term (); - if (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'a' && !argv[pos][2]) - { - advance (0); - v2 = and (); - return (value && v2); - } - return (value); -} - -/* - * term - parse a term and return 1 or 0 depending on whether the term - * evaluates to true or false, respectively. - * - * term ::= - * '-'('a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'k'|'p'|'r'|'s'|'u'|'w'|'x') filename - * '-'('G'|'L'|'O'|'S'|'N') filename - * '-t' [int] - * '-'('z'|'n') string - * '-o' option - * string - * string ('!='|'='|'==') string - * '-'(eq|ne|le|lt|ge|gt) - * file '-'(nt|ot|ef) file - * '(' ')' - * int ::= - * positive and negative integers - */ -static int -term () -{ - int value; - - if (pos >= argc) - beyond (); - - /* Deal with leading `not's. */ - if (argv[pos][0] == '!' && argv[pos][1] == '\0') - { - value = 0; - while (pos < argc && argv[pos][0] == '!' && argv[pos][1] == '\0') - { - advance (1); - value = 1 - value; - } - - return (value ? !term() : term()); - } - - /* A paren-bracketed argument. */ - if (argv[pos][0] == '(' && argv[pos][1] == '\0') /* ) */ - { - advance (1); - value = expr (); - if (argv[pos] == 0) /* ( */ - test_syntax_error (_("`)' expected"), (char *)NULL); - else if (argv[pos][0] != ')' || argv[pos][1]) /* ( */ - test_syntax_error (_("`)' expected, found %s"), argv[pos]); - advance (0); - return (value); - } - - /* are there enough arguments left that this could be dyadic? */ - if ((pos + 3 <= argc) && test_binop (argv[pos + 1])) - value = binary_operator (); - - /* Might be a switch type argument */ - else if (argv[pos][0] == '-' && argv[pos][2] == '\0') - { - if (test_unop (argv[pos])) - value = unary_operator (); - else - test_syntax_error (_("%s: unary operator expected"), argv[pos]); - } - else - { - value = argv[pos][0] != '\0'; - advance (0); - } - - return (value); -} - -static int -filecomp (s, t, op) - char *s, *t; - int op; -{ - struct stat st1, st2; - int r1, r2; - - if ((r1 = sh_stat (s, &st1)) < 0) - { - if (op == EF) - return (FALSE); - } - if ((r2 = sh_stat (t, &st2)) < 0) - { - if (op == EF) - return (FALSE); - } - - switch (op) - { - case OT: return (r1 < r2 || (r2 == 0 && st1.st_mtime < st2.st_mtime)); - case NT: return (r1 > r2 || (r1 == 0 && st1.st_mtime > st2.st_mtime)); - case EF: return (same_file (s, t, &st1, &st2); - } - return (FALSE); -} - -static int -arithcomp (s, t, op, flags) - char *s, *t; - int op, flags; -{ - intmax_t l, r; - int expok; - - if (flags & TEST_ARITHEXP) - { - l = evalexp (s, &expok); - if (expok == 0) - return (FALSE); /* should probably longjmp here */ - r = evalexp (t, &expok); - if (expok == 0) - return (FALSE); /* ditto */ - } - else - { - if (legal_number (s, &l) == 0) - integer_expected_error (s); - if (legal_number (t, &r) == 0) - integer_expected_error (t); - } - - switch (op) - { - case EQ: return (l == r); - case NE: return (l != r); - case LT: return (l < r); - case GT: return (l > r); - case LE: return (l <= r); - case GE: return (l >= r); - } - - return (FALSE); -} - -static int -patcomp (string, pat, op) - char *string, *pat; - int op; -{ - int m; - - m = strmatch (pat, string, FNMATCH_EXTFLAG|FNMATCH_IGNCASE); - return ((op == EQ) ? (m == 0) : (m != 0)); -} - -int -binary_test (op, arg1, arg2, flags) - char *op, *arg1, *arg2; - int flags; -{ - int patmatch; - - patmatch = (flags & TEST_PATMATCH); - - if (op[0] == '=' && (op[1] == '\0' || (op[1] == '=' && op[2] == '\0'))) - return (patmatch ? patcomp (arg1, arg2, EQ) : STREQ (arg1, arg2)); - - else if ((op[0] == '>' || op[0] == '<') && op[1] == '\0') - return ((op[0] == '>') ? (strcmp (arg1, arg2) > 0) : (strcmp (arg1, arg2) < 0)); - - else if (op[0] == '!' && op[1] == '=' && op[2] == '\0') - return (patmatch ? patcomp (arg1, arg2, NE) : (STREQ (arg1, arg2) == 0)); - - else if (op[2] == 't') - { - switch (op[1]) - { - case 'n': return (filecomp (arg1, arg2, NT)); /* -nt */ - case 'o': return (filecomp (arg1, arg2, OT)); /* -ot */ - case 'l': return (arithcomp (arg1, arg2, LT, flags)); /* -lt */ - case 'g': return (arithcomp (arg1, arg2, GT, flags)); /* -gt */ - } - } - else if (op[1] == 'e') - { - switch (op[2]) - { - case 'f': return (filecomp (arg1, arg2, EF)); /* -ef */ - case 'q': return (arithcomp (arg1, arg2, EQ, flags)); /* -eq */ - } - } - else if (op[2] == 'e') - { - switch (op[1]) - { - case 'n': return (arithcomp (arg1, arg2, NE, flags)); /* -ne */ - case 'g': return (arithcomp (arg1, arg2, GE, flags)); /* -ge */ - case 'l': return (arithcomp (arg1, arg2, LE, flags)); /* -le */ - } - } - - return (FALSE); /* should never get here */ -} - - -static int -binary_operator () -{ - int value; - char *w; - - w = argv[pos + 1]; - if ((w[0] == '=' && (w[1] == '\0' || (w[1] == '=' && w[2] == '\0'))) || /* =, == */ - ((w[0] == '>' || w[0] == '<') && w[1] == '\0') || /* <, > */ - (w[0] == '!' && w[1] == '=' && w[2] == '\0')) /* != */ - { - value = binary_test (w, argv[pos], argv[pos + 2], 0); - pos += 3; - return (value); - } - -#if defined (PATTERN_MATCHING) - if ((w[0] == '=' || w[0] == '!') && w[1] == '~' && w[2] == '\0') - { - value = patcomp (argv[pos], argv[pos + 2], w[0] == '=' ? EQ : NE); - pos += 3; - return (value); - } -#endif - - if ((w[0] != '-' || w[3] != '\0') || test_binop (w) == 0) - { - test_syntax_error (_("%s: binary operator expected"), w); - /* NOTREACHED */ - return (FALSE); - } - - value = binary_test (w, argv[pos], argv[pos + 2], 0); - pos += 3; - return value; -} - -static int -unary_operator () -{ - char *op; - intmax_t r; - - op = argv[pos]; - if (test_unop (op) == 0) - return (FALSE); - - /* the only tricky case is `-t', which may or may not take an argument. */ - if (op[1] == 't') - { - advance (0); - if (pos < argc) - { - if (legal_number (argv[pos], &r)) - { - advance (0); - return (unary_test (op, argv[pos - 1])); - } - else - return (FALSE); - } - else - return (unary_test (op, "1")); - } - - /* All of the unary operators take an argument, so we first call - unary_advance (), which checks to make sure that there is an - argument, and then advances pos right past it. This means that - pos - 1 is the location of the argument. */ - unary_advance (); - return (unary_test (op, argv[pos - 1])); -} - -int -unary_test (op, arg) - char *op, *arg; -{ - intmax_t r; - struct stat stat_buf; - - switch (op[1]) - { - case 'a': /* file exists in the file system? */ - case 'e': - return (sh_stat (arg, &stat_buf) == 0); - - case 'r': /* file is readable? */ - return (sh_eaccess (arg, R_OK) == 0); - - case 'w': /* File is writeable? */ - return (sh_eaccess (arg, W_OK) == 0); - - case 'x': /* File is executable? */ - return (sh_eaccess (arg, X_OK) == 0); - - case 'O': /* File is owned by you? */ - return (sh_stat (arg, &stat_buf) == 0 && - (uid_t) current_user.euid == (uid_t) stat_buf.st_uid); - - case 'G': /* File is owned by your group? */ - return (sh_stat (arg, &stat_buf) == 0 && - (gid_t) current_user.egid == (gid_t) stat_buf.st_gid); - - case 'N': - return (sh_stat (arg, &stat_buf) == 0 && - stat_buf.st_atime <= stat_buf.st_mtime); - - case 'f': /* File is a file? */ - if (sh_stat (arg, &stat_buf) < 0) - return (FALSE); - - /* -f is true if the given file exists and is a regular file. */ -#if defined (S_IFMT) - return (S_ISREG (stat_buf.st_mode) || (stat_buf.st_mode & S_IFMT) == 0); -#else - return (S_ISREG (stat_buf.st_mode)); -#endif /* !S_IFMT */ - - case 'd': /* File is a directory? */ - return (sh_stat (arg, &stat_buf) == 0 && (S_ISDIR (stat_buf.st_mode))); - - case 's': /* File has something in it? */ - return (sh_stat (arg, &stat_buf) == 0 && stat_buf.st_size > (off_t) 0); - - case 'S': /* File is a socket? */ -#if !defined (S_ISSOCK) - return (FALSE); -#else - return (sh_stat (arg, &stat_buf) == 0 && S_ISSOCK (stat_buf.st_mode)); -#endif /* S_ISSOCK */ - - case 'c': /* File is character special? */ - return (sh_stat (arg, &stat_buf) == 0 && S_ISCHR (stat_buf.st_mode)); - - case 'b': /* File is block special? */ - return (sh_stat (arg, &stat_buf) == 0 && S_ISBLK (stat_buf.st_mode)); - - case 'p': /* File is a named pipe? */ -#ifndef S_ISFIFO - return (FALSE); -#else - return (sh_stat (arg, &stat_buf) == 0 && S_ISFIFO (stat_buf.st_mode)); -#endif /* S_ISFIFO */ - - case 'L': /* Same as -h */ - case 'h': /* File is a symbolic link? */ -#if !defined (S_ISLNK) || !defined (HAVE_LSTAT) - return (FALSE); -#else - return ((arg[0] != '\0') && - (lstat (arg, &stat_buf) == 0) && S_ISLNK (stat_buf.st_mode)); -#endif /* S_IFLNK && HAVE_LSTAT */ - - case 'u': /* File is setuid? */ - return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISUID) != 0); - - case 'g': /* File is setgid? */ - return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISGID) != 0); - - case 'k': /* File has sticky bit set? */ -#if !defined (S_ISVTX) - /* This is not Posix, and is not defined on some Posix systems. */ - return (FALSE); -#else - return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISVTX) != 0); -#endif - - case 't': /* File fd is a terminal? */ - if (legal_number (arg, &r) == 0) - return (FALSE); - return ((r == (int)r) && isatty ((int)r)); - - case 'n': /* True if arg has some length. */ - return (arg[0] != '\0'); - - case 'z': /* True if arg has no length. */ - return (arg[0] == '\0'); - - case 'o': /* True if option `arg' is set. */ - return (minus_o_option_value (arg) == 1); - } - - /* We can't actually get here, but this shuts up gcc. */ - return (FALSE); -} - -/* Return TRUE if OP is one of the test command's binary operators. */ -int -test_binop (op) - char *op; -{ - if (op[0] == '=' && op[1] == '\0') - return (1); /* '=' */ - else if ((op[0] == '<' || op[0] == '>') && op[1] == '\0') /* string <, > */ - return (1); - else if ((op[0] == '=' || op[0] == '!') && op[1] == '=' && op[2] == '\0') - return (1); /* `==' and `!=' */ -#if defined (PATTERN_MATCHING) - else if (op[2] == '\0' && op[1] == '~' && (op[0] == '=' || op[0] == '!')) - return (1); -#endif - else if (op[0] != '-' || op[2] == '\0' || op[3] != '\0') - return (0); - else - { - if (op[2] == 't') - switch (op[1]) - { - case 'n': /* -nt */ - case 'o': /* -ot */ - case 'l': /* -lt */ - case 'g': /* -gt */ - return (1); - default: - return (0); - } - else if (op[1] == 'e') - switch (op[2]) - { - case 'q': /* -eq */ - case 'f': /* -ef */ - return (1); - default: - return (0); - } - else if (op[2] == 'e') - switch (op[1]) - { - case 'n': /* -ne */ - case 'g': /* -ge */ - case 'l': /* -le */ - return (1); - default: - return (0); - } - else - return (0); - } -} - -/* Return non-zero if OP is one of the test command's unary operators. */ -int -test_unop (op) - char *op; -{ - if (op[0] != '-' || op[2] != 0) - return (0); - - switch (op[1]) - { - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'k': case 'n': - case 'o': case 'p': case 'r': case 's': case 't': - case 'u': case 'w': case 'x': case 'z': - case 'G': case 'L': case 'O': case 'S': case 'N': - return (1); - } - - return (0); -} - -static int -two_arguments () -{ - if (argv[pos][0] == '!' && argv[pos][1] == '\0') - return (argv[pos + 1][0] == '\0'); - else if (argv[pos][0] == '-' && argv[pos][2] == '\0') - { - if (test_unop (argv[pos])) - return (unary_operator ()); - else - test_syntax_error (_("%s: unary operator expected"), argv[pos]); - } - else - test_syntax_error (_("%s: unary operator expected"), argv[pos]); - - return (0); -} - -#define ANDOR(s) (s[0] == '-' && !s[2] && (s[1] == 'a' || s[1] == 'o')) - -/* This could be augmented to handle `-t' as equivalent to `-t 1', but - POSIX requires that `-t' be given an argument. */ -#define ONE_ARG_TEST(s) ((s)[0] != '\0') - -static int -three_arguments () -{ - int value; - - if (test_binop (argv[pos+1])) - { - value = binary_operator (); - pos = argc; - } - else if (ANDOR (argv[pos+1])) - { - if (argv[pos+1][1] == 'a') - value = ONE_ARG_TEST(argv[pos]) && ONE_ARG_TEST(argv[pos+2]); - else - value = ONE_ARG_TEST(argv[pos]) || ONE_ARG_TEST(argv[pos+2]); - pos = argc; - } - else if (argv[pos][0] == '!' && argv[pos][1] == '\0') - { - advance (1); - value = !two_arguments (); - } - else if (argv[pos][0] == '(' && argv[pos+2][0] == ')') - { - value = ONE_ARG_TEST(argv[pos+1]); - pos = argc; - } - else - test_syntax_error (_("%s: binary operator expected"), argv[pos+1]); - - return (value); -} - -/* This is an implementation of a Posix.2 proposal by David Korn. */ -static int -posixtest () -{ - int value; - - switch (argc - 1) /* one extra passed in */ - { - case 0: - value = FALSE; - pos = argc; - break; - - case 1: - value = ONE_ARG_TEST(argv[1]); - pos = argc; - break; - - case 2: - value = two_arguments (); - pos = argc; - break; - - case 3: - value = three_arguments (); - break; - - case 4: - if (argv[pos][0] == '!' && argv[pos][1] == '\0') - { - advance (1); - value = !three_arguments (); - break; - } - /* FALLTHROUGH */ - default: - value = expr (); - } - - return (value); -} - -/* - * [: - * '[' expr ']' - * test: - * test expr - */ -int -test_command (margc, margv) - int margc; - char **margv; -{ - int value; - int code; - - USE_VAR(margc); - - code = setjmp (test_exit_buf); - - if (code) - return (test_error_return); - - argv = margv; - - if (margv[0] && margv[0][0] == '[' && margv[0][1] == '\0') - { - --margc; - - if (margv[margc] && (margv[margc][0] != ']' || margv[margc][1])) - test_syntax_error (_("missing `]'"), (char *)NULL); - - if (margc < 2) - test_exit (SHELL_BOOLEAN (FALSE)); - } - - argc = margc; - pos = 1; - - if (pos >= argc) - test_exit (SHELL_BOOLEAN (FALSE)); - - noeval = 0; - value = posixtest (); - - if (pos != argc) - test_syntax_error (_("too many arguments"), (char *)NULL); - - test_exit (SHELL_BOOLEAN (value)); -} diff --git a/tests/COPYRIGHT~ b/tests/COPYRIGHT~ deleted file mode 100644 index 986a7e734..000000000 --- a/tests/COPYRIGHT~ +++ /dev/null @@ -1,6 +0,0 @@ -Unless otherwise stated, all files in this directory are Copyright (C) -1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003, -2004,2005,2006,2007,2008 -Free Software Foundation, Inc. - -The file ifs-posix.tests is Copyright (C) 2005 Glen Fowler. 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 33622e76b..000000000 --- a/tests/arith.tests~ +++ /dev/null @@ -1,284 +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 )) - -${THIS_SH} ./arith1.sub -${THIS_SH} ./arith2.sub - -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/array.tests~ b/tests/array.tests~ deleted file mode 100644 index 3e3786a70..000000000 --- a/tests/array.tests~ +++ /dev/null @@ -1,384 +0,0 @@ -# this is needed so that the bad assignments (b[]=bcde, for example) do not -# cause fatal shell errors when in posix mode -set +o posix - -set +a -# The calls to egrep -v are to filter out builtin array variables that are -# automatically set and possibly contain values that vary. - -# first make sure we handle the basics -x=() -echo ${x[@]} -unset x - -# this should be an error -test=(first & second) -echo $? -unset test - -# make sure declare -a converts an existing variable to an array -unset a -a=abcde -declare -a a -echo ${a[0]} - -unset a -a=abcde -a[2]=bdef - -unset b -declare -a b[256] - -unset c[2] -unset c[*] - -a[1]= - -_ENV=/bin/true -x=${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]} - -declare -r c[100] - -echo ${a[0]} ${a[4]} -echo ${a[@]} - -echo ${a[*]} - -# this should print out values, too -declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)' - -unset a[7] -echo ${a[*]} - -unset a[4] -echo ${a[*]} - -echo ${a} -echo "${a}" -echo $a - -unset a[0] -echo ${a} - -echo ${a[@]} - -a[5]="hello world" -echo ${a[5]} -echo ${#a[5]} - -echo ${#a[@]} - -a[4+5/2]="test expression" -echo ${a[@]} - -readonly a[5] -readonly a -# these two lines should output `declare' commands -readonly -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)' -declare -ar | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)' -# this line should output `readonly' commands, even for arrays -set -o posix -readonly -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)' -set +o posix - -declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")' -d[9]="ninth element" - -declare -a e[10]=test # this works in post-bash-2.05 versions -declare -a e[10]='(test)' - -pass=/etc/passwd -declare -a f='("${d[@]}")' -b=([0]=this [1]=is [2]=a [3]=test [4]="$PS1" [5]=$pass) - -echo ${b[@]:2:3} - -declare -pa | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)' - -a[3]="this is a test" - -b[]=bcde -b[*]=aaa -echo ${b[ ]} - -c[-2]=4 -echo ${c[-4]} - -d[7]=(abdedfegeee) - -d=([]=abcde [1]="test test" [*]=last [-65]=negative ) - -unset d[12] -unset e[*] - -declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)' - -ps1='hello' -unset ps1[2] -unset ${ps1[2]} - -declare +a ps1 -declare +a c - -# the prompt should not print when using a here doc -read -p "array test: " -a rv <' [2]='<' [3]='>' [4]='!' ) -echo ${foo[@]} - -# numbers are just words when not in a redirection context -foo=( 12 14 16 18 20 ) -echo ${foo[@]} - -foo=( 4414758999202 ) -echo ${foo[@]} - -# this was a bug in all versions of bash 2.x up to and including bash-2.04 -declare -a ddd=(aaa -bbb) -echo ${ddd[@]} - -# errors until post-bash-2.05a; now reserved words are OK -foo=(a b c for case if then else) - -foo=(for case if then else) - -# errors -metas=( <> < > ! ) -metas=( [1]=<> [2]=< [3]=> [4]=! ) - -# various expansions that didn't really work right until post-bash-2.04 -foo='abc' -echo ${foo[0]} ${#foo[0]} -echo ${foo[1]} ${#foo[1]} -echo ${foo[@]} ${#foo[@]} -echo ${foo[*]} ${#foo[*]} - -foo='' -echo ${foo[0]} ${#foo[0]} -echo ${foo[1]} ${#foo[1]} -echo ${foo[@]} ${#foo[@]} -echo ${foo[*]} ${#foo[*]} - -# new expansions added after bash-2.05b -x[0]=zero -x[1]=one -x[4]=four -x[10]=ten - -recho ${!x[@]} -recho "${!x[@]}" -recho ${!x[*]} -recho "${!x[*]}" - -# sparse array tests for code fixed in bash-3.0 -unset av -av[1]='one' -av[2]='' - -av[3]=three -av[5]=five -av[7]=seven - -echo include null element -- expect one -echo ${av[@]:1:2} # what happens when we include a null element? -echo include unset element -- expect three five -echo ${av[@]:3:2} # what happens when we include an unset element? -echo start at unset element -- expect five seven -echo ${av[@]:4:2} # what happens when we start at an unset element? - -echo too many elements -- expect three five seven -echo ${av[@]:3:5} # how about too many elements? - -echo positive offset - expect five seven -echo ${av[@]:5:2} -echo negative offset to unset element - expect seven -echo ${av[@]: -2:2} - -echo positive offset 2 - expect seven -echo ${av[@]: 6:2} -echo negative offset 2 - expect seven -echo ${av[@]: -1:2} - -echo out-of-range offset -echo ${av[@]:12} - -# parsing problems and other inconsistencies not fixed until post bash-3.0 -unset x -declare -a x=(')' $$) -[ ${x[1]} -eq $$ ] || echo bad - -unset x -declare -a x=(a b c d e) -echo ${x[4]} - -z=([1]=one [4]=four [7]=seven [10]=ten) - -echo ${#z[@]} - -echo ${!z[@]} - -unset x -declare -a x=(a \'b c\') - -echo "${x[1]}" - -unset x -declare -a x=(a 'b c') - -echo "${x[1]}" - -unset x -declare -a x=($0) -[ "${x[@]}" = $0 ] || echo double expansion of \$0 -declare -a x=(\$0) -echo "${x[@]}" - -# tests for bash-3.1 problems -${THIS_SH} ./array5.sub - -# tests for post-bash-3.2 problems, most fixed in bash-3.2 patches -${THIS_SH} ./array6.sub -${THIS_SH} ./array7.sub - -${THIS_SH} ./array8.sub diff --git a/tests/array6.sub~ b/tests/array6.sub~ deleted file mode 100644 index 78d92e4c4..000000000 --- a/tests/array6.sub~ +++ /dev/null @@ -1,123 +0,0 @@ -# test cases for array quoting and escaping fixed post bash-3.2-release - -oIFS="$IFS" - -a=(a b c) -echo ${a[@]} - -a2=("${a[@]/#/"-iname '"}") -recho "${a2[@]}" - -echo "${dbg-"'hey'"}" -echo "${dbg-"hey"}" -echo "${dbg-'"'hey}" -echo "${dbg-'"hey'}" - -unset a a2 - -IFS= -a2=(${a[@]/#/"-iname '"}) -recho "${a2[@]}" - -IFS="$oIFS" -unset a a2 - -a=('a b' 'c d' 'e f') - -recho ${a[@]:1:2} -recho "${a[@]:1:2}" - -IFS= -recho ${a[@]:1:2} -recho "${a[@]:1:2}" - -IFS="$oIFS" -unset a a2 - -a=(abc def) - -# Prevent word splitting -#IFS= - -a2=("${a[@]/#/"-iname '"}") -recho "${a2[@]}" - -eval a2=("${a[@]/#/"-iname '"}") -recho "${a2[@]}" - -a2=("${a[@]/#/-iname \'}") -recho "${a2[@]}" - -eval a2=("${a[@]/#/-iname \'}") -recho "${a2[@]}" - -set -- abc def - -a2=("${@/#/"-iname '"}") -recho "${a2[@]}" - -eval a2=("${@/#/"-iname '"}") -recho "${a2[@]}" - -unset a a2 - -IFS= -pat=('*.*') -case $(ls ${pat[@]} 2>/dev/null) in -'') echo '*.* BAD' ;; -*) echo '*.* OK' ;; -esac - -IFS="$oIFS" -unset a a2 pat - -IFS= - -s='abc' - -set - ${s/b/1 2 3} -echo $# -echo "$1" - -IFS="$oIFS" -unset s - -set -- ab cd ef -foo="var with spaces" - -IFS= -recho $foo -recho "$foo" - -recho ${foo}"$@" -recho ${foo}$@ - -array=(ab cd ef) -recho ${foo}"${array[@]}" -recho ${foo}${array[@]} - -recho $(echo $foo)"$@" -recho $(echo $foo)$@ - -a=('word1 with spaces' 'word2 with spaces') -set - ${a[@]/word/element} -echo $# -recho "$@" -recho $@ - -IFS="$oIFS" -unset a a2 array foo - -a=$'ab\001cd\001ef' - -recho $a -recho "$a" - -recho $(echo $a) -recho $(echo "$a") - -# XXX - this doesn't work right until post-bash-3.2 -IFS=$'\001' -recho $a - -IFS=$'\001' recho "$a" diff --git a/tests/braces.tests~ b/tests/braces.tests~ deleted file mode 100644 index 5f15f5f3b..000000000 --- a/tests/braces.tests~ +++ /dev/null @@ -1,78 +0,0 @@ -echo ff{c,b,a} -echo f{d,e,f}g -echo {l,n,m}xyz -echo {abc\,def} -echo {abc} - -echo \{a,b,c,d,e} -echo {x,y,\{a,b,c}} -echo {x\,y,\{abc\},trie} - -echo /usr/{ucb/{ex,edit},lib/{ex,how_ex}} - -echo XXXX\{`echo a b c | tr ' ' ','`\} -eval echo XXXX\{`echo a b c | tr ' ' ','`\} - -echo {} -echo { } -echo } -echo { -echo abcd{efgh - -echo foo {1,2} bar -echo `zecho foo {1,2} bar` -echo $(zecho foo {1,2} bar) - -var=baz -varx=vx -vary=vy - -echo foo{bar,${var}.} -echo foo{bar,${var}} - -echo "${var}"{x,y} -echo $var{x,y} -echo ${var}{x,y} - -unset var varx vary - -# new sequence brace operators -echo {1..10} - -# this doesn't work yet -echo {0..10,braces} -# but this does -echo {{0..10},braces} -echo x{{0..10},braces}y - -echo {3..3} -echo x{3..3}y -echo {10..1} -echo {10..1}y -echo x{10..1}y - -echo {a..f} -echo {f..a} - -echo {a..A} -echo {A..a} - -echo {f..f} - -# mixes are incorrectly-formed brace expansions -echo {1..f} -echo {f..1} - -echo 0{1..9} {10..20} - -# do negative numbers work? -echo {-1..-10} -echo {-20..0} - -# weirdly-formed brace expansions -- fixed in post-bash-3.1 -echo a-{b{d,e}}-c - -echo a-{bdef-{g,i}-c - -echo {"klklkl"}{1,2,3} -echo {"x,x"} diff --git a/tests/builtins1.sub~ b/tests/builtins1.sub~ deleted file mode 100644 index 5b7971136..000000000 --- a/tests/builtins1.sub~ +++ /dev/null @@ -1,14 +0,0 @@ -unset CDPATH - -MYDIR=$(pwd -P) -FULLDIR=/tmp/bash-dir-a -DIR=${FULLDIR##*/} - -mkdir $FULLDIR -CDPATH=.:/tmp -cd $DIR -pwd -echo $PWD - -cd $MYDIR -rmdir $FULLDIR diff --git a/tests/casemod.tests~ b/tests/casemod.tests~ deleted file mode 100644 index 99907e9ce..000000000 --- a/tests/casemod.tests~ +++ /dev/null @@ -1,96 +0,0 @@ -S1=acknowledgement -S2=oenophile - -echo ${S1^} -echo ${S1^^} - -echo ${S2^[aeiou]} -echo ${S2^^[aeiou]} - -U1=${S1^^} -U2=${S2^^} - -echo ${U1,} -echo ${U1,,} - -echo ${U2,} -echo ${U2,[AEIOU]} -echo ${U2,,[AEIOU]} - -A1=( $S1 $S2 ) - -echo ${A1[@]^[aeiou]} -echo ${A1[@]^^[aeiou]} - -A2=( $U1 $U2 ) - -echo ${A2[@],[AEIOU]} -echo ${A2[@],,[AEIOU]} - -echo ${A2[@],?} -echo ${A2[@],,?} - -declare -A AA1 AA2 - -AA1[ack]=$S1 -AA1[oen]=$S2 - -echo ${AA1[@]^} -echo ${AA1[@]^^} - -echo ${AA1[@]^[aeiou]} -echo ${AA1[@]^^[aeiou]} - -AA2[ACK]=$U1 -AA2[OEN]=$U2 - -echo ${AA2[@],} -echo ${AA2[@],,} - -echo ${AA2[@],[AEIOU]} -echo ${AA2[@],,[AEIOU]} - -set -- $S1 $S2 - -echo ${@^} -echo ${@^^} - - -echo ${S1^[rstlne]} ${S2^[rstlne]} -echo ${S1^^[rstlne]} ${S2^^[rstlne]} - -echo ${@^[rstlne]} -echo ${@^^[rstlne]} - -echo ${S1,[rstlne]} ${S2,[rstlne]} -echo ${S1,,[rstlne]} ${S2,,[rstlne]} - -echo ${@,[rstlne]} -echo ${@,,[rstlne]} - -echo ${@^?} -echo ${@^^?} - -# make sure that multiple words in the string are handled as other expansions -TEXT="Be Conservative in what you send and Liberal in what you accept" -TEXT2="be conservative in what you send and liberal in what you accept" - -declare -u foo -foo=$TEXT -echo $foo - -declare -l bar -bar=$TEXT -echo $bar - -declare -c qux -qux=$TEXT -echo $qux -qux=$TEXT2 -echo $qux - -echo ${TEXT,} -echo ${TEXT,,} - -echo ${TEXT^} -echo ${TEXT^^} diff --git a/tests/comsub-eof0.sub~ b/tests/comsub-eof0.sub~ deleted file mode 100644 index 19d76b7c1..000000000 --- a/tests/comsub-eof0.sub~ +++ /dev/null @@ -1,10 +0,0 @@ -foo=$(cat < bar && $PWD -ef . ]] -echo returns: $? - -# [[ x ]] is equivalent to [[ -n x ]] -[[ x ]] -echo returns: $? - -# [[ ! x ]] is equivalent to [[ ! -n x ]] -[[ ! x ]] -echo returns: $? - -# ! binds tighter than test/[ -- it binds to a term, not an expression -[[ ! x || x ]] -echo returns: $? - -# parenthesized terms didn't work right until post-2.04 -[[ a ]] -echo returns: $? - -[[ (a) ]] -echo returns: $? - -[[ -n a ]] -echo returns: $? - -[[ (-n a) ]] -echo returns: $? - -# unset variables don't need to be quoted -[[ -n $UNSET ]] -echo returns: $? - -[[ -z $UNSET ]] -echo returns: $? - -# the ==/= and != operators do pattern matching -[[ $TDIR == /usr/homes/* ]] -echo returns: $? - -# ...but you can quote any part of the pattern to have it matched as a string -[[ $TDIR == /usr/homes/\* ]] -echo returns: $? - -[[ $TDIR == '/usr/homes/*' ]] -echo returns: $? - -# if the first part of && fails, the second is not executed -[[ -n $UNSET && $UNSET == foo ]] -echo returns: $? - -[[ -z $UNSET && $UNSET == foo ]] -echo returns: $? - -# if the first part of || succeeds, the second is not executed -[[ -z $UNSET || -d $PWD ]] -echo returns: $? - -# if the rhs were executed, it would be an error -[[ -n $TDIR || $HOME -ef ${H*} ]] -echo returns: $? - -[[ -n $TDIR && -z $UNSET || $HOME -ef ${H*} ]] -echo returns: $? - -# && has a higher parsing precedence than || -[[ -n $TDIR && -n $UNSET || $TDIR -ef . ]] -echo returns: $? - -# ...but expressions in parentheses may be used to override precedence rules -[[ -n $TDIR || -n $UNSET && $PWD -ef xyz ]] -echo returns: $? - -[[ ( -n $TDIR || -n $UNSET ) && $PWD -ef xyz ]] -echo returns: $? - -# some arithmetic tests for completeness -- see what happens with missing -# operands, bad expressions, makes sure arguments are evaluated as -# arithmetic expressions, etc. - -unset IVAR A -[[ 7 -gt $IVAR ]] -echo returns: $? - -[[ $IVAR -gt 7 ]] -echo returns: $? - -IVAR=4 -[[ $IVAR -gt 7 ]] -echo returns: $? - -[[ 7 -eq 4+3 ]] -echo returns: $? - -[[ 7 -eq 4+ ]] -echo returns: $? - -IVAR=4+3 -[[ $IVAR -eq 7 ]] -echo returns: $? - -A=7 -[[ $IVAR -eq A ]] -echo returns: $? - -unset IVAR A - -# more pattern matching tests - -[[ $filename == *.c ]] -echo returns: $? - -filename=patmatch.c - -[[ $filename == *.c ]] -echo returns: $? - -# the extended globbing features may be used when matching patterns -shopt -s extglob - -arg=-7 - -[[ $arg == -+([0-9]) ]] -echo returns: $? - -arg=-H - -[[ $arg == -+([0-9]) ]] -echo returns: $? - -arg=+4 -[[ $arg == ++([0-9]) ]] -echo returns: $? - -# make sure the null string is never matched if the string is not null -STR=file.c -PAT= - -if [[ $STR = $PAT ]]; then - echo oops -fi - -# but that if the string is null, a null pattern is matched correctly -STR= -PAT= - -if [[ $STR = $PAT ]]; then - echo ok -fi - -# test the regular expression conditional operator -[[ jbig2dec-0.9-i586-001.tgz =~ ([^-]+)-([^-]+)-([^-]+)-0*([1-9][0-9]*)\.tgz ]] -echo ${BASH_REMATCH[1]} - -LDD_BASH=" linux-gate.so.1 => (0xffffe000) - libreadline.so.5 => /lib/libreadline.so.5 (0xb7f91000) - libhistory.so.5 => /lib/libhistory.so.5 (0xb7f8a000) - libncurses.so.5 => /lib/libncurses.so.5 (0xb7f55000) - libdl.so.2 => /lib/libdl.so.2 (0xb7f51000) - libc.so.6 => /lib/libc.so.6 (0xb7e34000) - /lib/ld-linux.so.2 (0xb7fd0000)" - -[[ "$LDD_BASH" =~ "libc" ]] && echo "found 1" -echo ${BASH_REMATCH[@]} - -[[ "$LDD_BASH" =~ libc ]] && echo "found 2" -echo ${BASH_REMATCH[@]} - -# bug in all versions up to and including bash-2.05b -if [[ "123abc" == *?(a)bc ]]; then echo ok 42; else echo bad 42; fi -if [[ "123abc" == *?(a)bc ]]; then echo ok 43; else echo bad 43; fi - -${THIS_SH} ./cond-regexp.sub diff --git a/tests/coproc.tests~ b/tests/coproc.tests~ deleted file mode 100644 index eba69fdcf..000000000 --- a/tests/coproc.tests~ +++ /dev/null @@ -1,45 +0,0 @@ -coproc { echo a b c; sleep 2; } - -echo $COPROC_PID -echo ${COPROC[@]} - -read LINE <&${COPROC[0]} -echo $LINE - -wait $COPROC_PID - -coproc REFLECT { cat - ; } - -echo $REFLECT_PID -echo ${REFLECT[@]} - -echo flop >&${REFLECT[1]} -read LINE <&${REFLECT[0]} - -echo $LINE - -kill $REFLECT_PID -wait $REFLECT_PID - -coproc tr -u 'a-z' 'A-Z' - -echo $COPROC_PID -echo ${COPROC[@]} - -echo foo >&${COPROC[1]} -read <&${COPROC[0]} - -echo $REPLY -echo ${COPROC[@]} - -cat /etc/passwd | grep root | awk -F: '{print $1;}' - -exec 4<&${COPROC[0]}- -exec >&${COPROC[1]}- - -echo ${COPROC[@]} - -read foo <&4 -echo $foo >&2 - -exit 0 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/cprint.tests~ b/tests/cprint.tests~ deleted file mode 100644 index 08ff1ebc0..000000000 --- a/tests/cprint.tests~ +++ /dev/null @@ -1,67 +0,0 @@ -# -# a nonsense script and shell function to test out the command printing code -# -tf() -{ - # simple command with redir - echo this is ${0##*/} > /dev/null - - # pipeline - 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 - elif (( 7 > 40 )) ; then - echo oops - else - echo done - 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 \; \} - # when not in POSIX mode, we can have weirdly-named functions - eval fu\%nc'()' \{ echo abcde \; \} - type fu\%nc -} - -tf2() -{ - ( { time -p echo a | cat - > /dev/null ; } ) 2>&1 -} - -type tf -type tf2 - -tf diff --git a/tests/dstack.tests~ b/tests/dstack.tests~ deleted file mode 100644 index 6c4cef142..000000000 --- a/tests/dstack.tests~ +++ /dev/null @@ -1,87 +0,0 @@ -export LC_ALL=C -export LANG=C - -dirs -c -# error -- nonexistant directory -pushd /tmp/xxx-notthere - -# errors -- empty stack -pushd -popd - -# errors -- bad numeric arguments -- should not cause the script to exit -pushd -m -popd -m -dirs -m -dirs 7 - -MYDIR=$PWD -unalias cd 2>/dev/null - -unalias -a - -command cd -P / -command pwd -P # better be `/' - -case "$OLDPWD" in -$MYDIR) echo ok ;; -*) echo oops -- bad \$OLDPWD ;; -esac - -pushd /usr -echo $PWD $OLDPWD -dirs -echo ${DIRSTACK[@]} - -# this should not change the directory stack at all -pushd -n +0 -dirs - -popd -pushd /usr - -pushd /etc -dirs -dirs -l -dirs -v - -# two consecutive `pushd's should swap the top two stack elements, then -# swap them back, leaving the stack intact -pushd -pushd - -pushd /tmp -echo ${DIRSTACK[0]} ; dirs +0 -echo ${DIRSTACK[2]} ; dirs +2 - -# these should be errors, but not affect the directory stack -dirs +9; dirs -9 -pushd +9 ; pushd -9 -popd +9 ; popd -9 - -popd -n +2 -dirs -echo ${DIRSTACK[@]} - -pushd -n /usr -echo $PWD -dirs -echo ${DIRSTACK[@]} - -builtin pwd - -DIRSTACK[1]=/bin -dirs - -builtin pwd -popd +2 -builtin pwd -L -pushd -1 -dirs -echo ${DIRSTACK[0]} - -dirs -c -dirs - -# this is for the benefit of pure coverage -cd $MYDIR diff --git a/tests/exec.right~ b/tests/exec.right~ deleted file mode 100644 index 075912958..000000000 --- a/tests/exec.right~ +++ /dev/null @@ -1,56 +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 39: /: is a directory -126 -/: /: is a directory -126 -./execscript: line 46: .: /: 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 68: notthere: No such file or directory -127 -./execscript: line 71: notthere: No such file or directory -127 -./execscript: line 74: 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 -bash: no job control in this shell -expand_aliases on -after diff --git a/tests/exp.tests~ b/tests/exp.tests~ deleted file mode 100644 index ed23d0cbb..000000000 --- a/tests/exp.tests~ +++ /dev/null @@ -1,382 +0,0 @@ -# -# A suite of tests for bash word expansions -# -# This tests parameter and variable expansion, with an empahsis on -# proper quoting behavior. -# -# Chet Ramey - -# -# If you comment out the body of this function, you can do a diff against -# `expansion-tests.right' to see if the shell is behaving correctly -# -expect() -{ - echo expect "$@" -} - -# Test the substitution quoting characters (CTLESC and CTLNUL) in different -# combinations - -expect "<^A>" -recho `echo ''` -expect "<^A>" -recho `echo ""` -expect "<^B>" -recho `echo ''` -expect "<^B>" -recho `echo ""` -expect "<^A>" -recho `echo ` -expect "<^B>" -recho `echo ` - -# Test null strings without variable expansion -expect "" -recho abcd""efgh -expect "" -recho abcd''efgh -expect "" -recho ""abcdefgh -expect "" -recho ''abcdefgh -expect "" -recho abcd"" -expect "" -recho abcd'' - -# Test the quirky behavior of $@ in "" -expect nothing -recho "$@" -expect "< >" -recho " $@" -expect "<-->" -recho "-${@}-" - -# Test null strings with variable expansion that fails -expect '<>' -recho $xxx"" -expect '<>' -recho ""$xxx -expect '<>' -recho $xxx'' -expect '<>' -recho ''$xxx -expect '<>' -recho $xxx""$yyy -expect '<>' -recho $xxx''$yyy - -# Test null strings with variable expansion that succeeds -xxx=abc -yyy=def - -expect '' -recho $xxx"" -expect '' -recho ""$xxx -expect '' -recho $xxx'' -expect '' -recho ''$xxx -expect '' -recho $xxx""$yyy -expect '' -recho $xxx''$yyy - -unset xxx yyy - -# Test the unquoted special quoting characters -expect "<^A>" -recho  -expect "<^B>" -recho  -expect "<^A>" -recho "" -expect "<^B>" -recho "" -expect "<^A>" -recho '' -expect "<^B>" -recho '' - -# Test expansion of a variable that is unset -expect nothing -recho $xxx -expect '<>' -recho "$xxx" - -expect nothing -recho "$xxx${@}" - -# Test empty string expansion -expect '<>' -recho "" -expect '<>' -recho '' - -# Test command substitution with (disabled) history substitution -expect '' -# set +H -recho "`echo \"Hello world!\"`" - -# Test some shell special characters -expect '<`>' -recho "\`" -expect '<">' -recho "\"" -expect '<\^A>' -recho "\" - -expect '<\$>' -recho "\\$" - -expect '<\\>' -recho "\\\\" - -# This should give argv[1] = a argv[2] = b -expect ' ' -FOO=`echo 'a b' | tr ' ' '\012'` -recho $FOO - -# This should give argv[1] = ^A argv[2] = ^B -expect '<^A> <^B>' -FOO=`echo ' ' | tr ' ' '\012'` -recho $FOO - -# Test quoted and unquoted globbing characters -expect '<**>' -recho "*"* - -expect '<\.\./*/>' -recho "\.\./*/" - -# Test patterns that come up when the shell quotes funny character -# combinations -expect '<^A^B^A^B>' -recho '' -expect '<^A^A>' -recho '' -expect '<^A^B>' -recho '' -expect '<^A^A^B>' -recho '' - -# More tests of "$@" -set abc def ghi jkl -expect '< abc> ' -recho " $@ " -expect '< abc> ' -recho "${1+ $@ }" - -set abc def ghi jkl -expect '<--abc> ' -recho "--$@--" - -set "a b" cd ef gh -expect ' ' -recho ${1+"$@"} -expect ' ' -recho ${foo:-"$@"} -expect ' ' -recho "${@}" - -expect '< >' -recho " " -expect '< - >' -recho " - " - -# Test combinations of different types of quoting in a fully-quoted string -# (so the WHOLLY_QUOTED tests fail and it doesn't get set) -expect '' -recho "/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/" - -# Test the various Posix parameter expansions - -expect '' -recho "${x:-$(echo "foo bar")}" -expect ' ' -recho ${x:-$(echo "foo bar")} - -unset X -expect '' -recho ${X:=abc} -expect '' -recho $X - -set a b c -expect '' -recho ${3:+posix} - -POSIX=/usr/posix -expect '<10>' -recho ${#POSIX} - -# remove shortest trailing match -x=file.c -expect '' -recho ${x%.c}.o - -# remove longest trailing match -x=posix/src/std -expect '' -recho ${x%%/*} - -# remove shortest leading pattern -x=$HOME/src/cmd -expect '' -recho ${x#$HOME} - -# remove longest leading pattern -x=/one/two/three -expect '' -recho ${x##*/} - -# pattern removal of patterns that don't match -z=abcdef - -expect '' -recho ${z#xyz} -expect '' -recho ${z##xyz} - -expect '' -recho ${z%xyz} -expect '' -recho ${z%%xyz} - -# Command substitution and the quirky differences between `` and $() - -expect '<\$x>' -recho '\$x' - -expect '<$x>' -recho `echo '\$x'` - -expect '<\$x>' -recho $(echo '\$x') - -# The difference between $* "$*" and "$@" - -set "abc" "def ghi" "jkl" - -expect ' ' -recho $* - -expect '' -recho "$*" - -OIFS="$IFS" -IFS=":$IFS" - -# The special behavior of "$*", using the first character of $IFS as separator -expect '' -recho "$*" - -IFS="$OIFS" - -expect ' ' -recho "$@" - -expect ' ' -recho "xx$@yy" - -expect ' ' -recho "$@$@" - -foo=abc -bar=def - -expect '' -recho "$foo""$bar" - -unset foo -set $foo bar '' xyz "$foo" abc - -expect ' <> <> ' -recho "$@" - -# More tests of quoting and deferred evaluation - -foo=10 x=foo -y='$'$x -expect '<$foo>' -recho $y -eval y='$'$x -expect '<10>' -recho $y - -# case statements - -NL=' -' -x='ab -cd' - -expect '' -case "$x" in -*$NL*) recho "newline expected" ;; -esac - -expect '' -case \? in -*"?"*) recho "got it" ;; -esac - -expect '' -case \? in -*\?*) recho "got it" ;; -esac - -set one two three four five -expect ' ' -recho $1 $3 ${5} $8 ${9} - -# length tests on positional parameters and some special parameters - -expect '<5> <5>' -recho $# ${#} -expect '<3>' -recho ${#1} -expect '<1>' -recho ${##} -expect '<1>' -recho ${#?} -expect '<5>' -recho ${#@} -expect '<5>' -recho ${#*} -expect '<5>' -recho "${#@}" -expect '<5>' -recho "${#*}" - -expect '<42>' -recho $((28 + 14)) -expect '<26>' -recho $[ 13 * 2 ] - -expect '<\>' -recho `echo \\\\` - -expect '<~>' -recho '~' - -expect nothing -recho $! -expect nothing -recho ${!} - -# test word splitting of assignment statements not preceding a command -a="a b c d e" -declare b=$a -expect ' ' -recho $b - -a="a?b?c" - -echo ${a//\\?/ } - -echo ${a//\?/ } - -${THIS_SH} ./exp1.sub diff --git a/tests/extglob.tests~ b/tests/extglob.tests~ deleted file mode 100644 index 51e33ee73..000000000 --- a/tests/extglob.tests~ +++ /dev/null @@ -1,365 +0,0 @@ -# test the ksh-like extended globbing features: [!@*?+](patlist) - -shopt -s extglob - -expect() -{ - echo expect "$@" -} - -case "/dev/udp/129.22.8.102/45" in -/dev/@(tcp|udp)/*/*) echo ok 1;; -*) echo bad 1;; -esac - -# valid numbers -case 12 in -0|[1-9]*([0-9])) echo ok 2;; -*) echo bad 2;; -esac - -case 12abc in -0|[1-9]*([0-9])) echo bad 3;; -*) echo ok 3;; -esac - -case 1 in -0|[1-9]*([0-9])) echo ok 4;; -*) echo bad 4;; -esac - -# octal numbers -case 07 in -+([0-7])) echo ok 5;; -*) echo bad 5;; -esac - -case 0377 in -+([0-7])) echo ok 6;; -*) echo bad 6;; -esac - -case 09 in -+([0-7])) echo bad 7;; -*) echo ok 7;; -esac - -# stuff from korn's book -case paragraph in -para@(chute|graph)) echo ok 8;; -*) echo bad 8;; -esac - -case paramour in -para@(chute|graph)) echo bad 9;; -*) echo ok 9;; -esac - -case para991 in -para?([345]|99)1) echo ok 10;; -*) echo bad 10;; -esac - -case para381 in -para?([345]|99)1) echo bad 11;; -*) echo ok 11;; -esac - -case paragraph in -para*([0-9])) echo bad 12;; -*) echo ok 12;; -esac - -case para in -para*([0-9])) echo ok 13;; -*) echo bad 13;; -esac - -case para13829383746592 in -para*([0-9])) echo ok 14;; -*) echo bad 14;; -esac - -case paragraph in -para*([0-9])) echo bad 15;; -*) echo ok 15;; -esac - -case para in -para+([0-9])) echo bad 16;; -*) echo ok 16;; -esac - -case para987346523 in -para+([0-9])) echo ok 17;; -*) echo bad 17;; -esac - -case paragraph in -para!(*.[0-9])) echo ok 18;; -*) echo bad 18;; -esac - -case para.38 in -para!(*.[0-9])) echo ok 19;; -*) echo bad 19;; -esac - -case para.graph in -para!(*.[0-9])) echo ok 20;; -*) echo bad 20;; -esac - -case para39 in -para!(*.[0-9])) echo ok 21;; -*) echo bad 21;; -esac - -# tests derived from those in rosenblatt's korn shell book - -case "" in -*(0|1|3|5|7|9)) echo ok 22;; -*) echo bad 22; -esac - -case 137577991 in -*(0|1|3|5|7|9)) echo ok 23;; -*) echo bad 23; -esac - -case 2468 in -*(0|1|3|5|7|9)) echo bad 24;; -*) echo ok 24; -esac - -case file.c in -*.c?(c)) echo ok 25;; -*) echo bad 25;; -esac - -case file.C in -*.c?(c)) echo bad 26;; -*) echo ok 26;; -esac - -case file.cc in -*.c?(c)) echo ok 27;; -*) echo bad 27;; -esac - -case file.ccc in -*.c?(c)) echo bad 28;; -*) echo ok 28;; -esac - -case parse.y in -!(*.c|*.h|Makefile.in|config*|README)) echo ok 29;; -*) echo bad 29;; -esac - -case shell.c in -!(*.c|*.h|Makefile.in|config*|README)) echo bad 30;; -*) echo ok 30;; -esac - -case Makefile in -!(*.c|*.h|Makefile.in|config*|README)) echo ok 31;; -*) echo bad 31;; -esac - -case "VMS.FILE;1" in -*\;[1-9]*([0-9])) echo ok 32;; -*) echo bad 32;; -esac - -case "VMS.FILE;0" in -*\;[1-9]*([0-9])) echo bad 33;; -*) echo ok 33;; -esac -case "VMS.FILE;" in -*\;[1-9]*([0-9])) echo bad 34;; -*) echo ok 34;; -esac -case "VMS.FILE;139" in -*\;[1-9]*([0-9])) echo ok 35;; -*) echo bad 35;; -esac -case "VMS.FILE;1N" in -*\;[1-9]*([0-9])) echo bad 36;; -*) echo ok 36;; -esac - -# tests derived from the pd-ksh test suite - -MYDIR=$PWD # save where we are - -TESTDIR=/tmp/eglob-test-$$ -mkdir $TESTDIR -builtin cd $TESTDIR || { echo $0: cannot cd to $TESTDIR >&2 ; exit 1; } -rm -rf * - -touch abcx abcz bbc -expect '!([*)*' -echo !([*)* - -expect '+(a|b[)*' -echo +(a|b[)* - -expect '[a*(]*z' -echo [a*(]*)z - -rm -f abcx abcz bbc - -touch abc - -expect '+()c' -echo +()c -expect '+()x' -echo +()x -expect abc -echo +(*)c -expect '+(*)x' -echo +(*)x - -# extended globbing should not be performed on the output of substitutions -x='@(*)' -expect '@(*)' -echo $x - -expect 'no-file+(a|b)stuff' -echo no-file+(a|b)stuff -expect 'no-file+(a*(c)|b)stuff' -echo no-file+(a*(c)|b)stuff - -touch abd acd - -expect 'abd acd' -echo a+(b|c)d - -expect 'acd' -echo a!(@(b|B))d - -expect 'abd' -echo a[b*(foo|bar)]d - -# simple kleene star tests -expect no -case foo in *(a|b[)) echo yes;; *) echo no;; esac - -expect yes -case foo in *(a|b[)|f*) echo yes;; *) echo no;; esac - -# this doesn't work right yet; it is an incorrectly formed pattern -expect yes -case '*(a|b[)' in *(a|b[)) echo yes;; *) echo no;; esac - -# check extended globbing in pattern removal -- these don't work right yet -x=abcdef - -expect '1: bcdef' -echo 1: ${x#+(a|abc)} -expect '2: def' -echo 2: ${x##+(a|abc)} -expect '3: abcde' -echo 3: ${x%+(def|f)} -expect '4: abc' -echo 4: ${x%%+(f|def)} - -# these work ok - -expect '5: ef' -echo 5: ${x#*(a|b)cd} -expect '6: ef' -echo 6: "${x#*(a|b)cd}" -expect '7: abcdef' -echo 7: ${x#"*(a|b)cd"} - -# More tests derived from a bug report concerning extended glob patterns -# following a * -builtin cd $TESTDIR || { echo $0: cannot cd to $TESTDIR >&2 ; exit 1; } -rm -rf * - -touch ab abcdef abef abcfef - -expect 'ab abef' -echo ab*(e|f) - -expect 'abcfef abef' -echo ab?*(e|f) - -expect abcdef -echo ab*d+(e|f) - -expect 'ab abcdef abcfef abef' -echo ab**(e|f) - -expect 'abcdef abcfef abef' -echo ab*+(e|f) - -case 'abcfefg' in -ab**(e|f)) echo ok 37;; -*) echo bad 37;; -esac - -case 'abcfefg' in -ab**(e|f)g) echo ok 38;; -*a) echo bad 38;; -esac - -case ab in -ab*+(e|f)) echo bad 39;; -*) echo ok 39;; -esac - -case abef in -ab***ef) echo ok 40;; -*) echo bad 40;; -esac - -case abef in -ab**) echo ok 41;; -*) echo bad 41;; -esac - -# bug in all versions up to and including bash-2.05b -case "123abc" in -*?(a)bc) echo ok 42;; -*) echo bad 42;; -esac - -# clean up and do the next one - -builtin cd / -rm -rf $TESTDIR - -mkdir $TESTDIR -builtin cd $TESTDIR - -LC_COLLATE=C # have to set this; it affects the sorting -touch a.b a,b a:b a-b a\;b a\ b a_b - -echo a[^[:alnum:]]b -echo a[-.,:\;\ _]b - -echo a@([^[:alnum:]])b -echo a@([-.,:; _])b -echo a@([.])b -echo a@([^.])b -echo a@([^x])b -echo a+([^[:alnum:]])b - -echo a@(.|[^[:alnum:]])b - -builtin cd / -rm -rf $TESTDIR - -x=abcdef -recho "${x#*(a|b)cd}" - -# this is for the benefit of pure coverage, so it writes the pcv file -# in the right place -builtin cd $MYDIR - -${THIS_SH} ./extglob1.sub - -exit 0 diff --git a/tests/extglob1.sub~ b/tests/extglob1.sub~ deleted file mode 100644 index 3beec9e86..000000000 --- a/tests/extglob1.sub~ +++ /dev/null @@ -1,37 +0,0 @@ -MYDIR=$PWD - -: ${TMPDIR:=/tmp} -GDIR=$TMPDIR/gtest-$$ - -shopt -s extglob - -mkdir $GDIR || exit 1 -cd $GDIR || exit 1 - -touch a.c - -echo +([[:alpha:].]) -echo +([[:alpha:].])+([[:alpha:].]) -echo *([[:alpha:].]) -echo *([[:alpha:].])*([[:alpha:].]) - -echo ?([[:alpha:].])?([[:alpha:].])?([[:alpha:].]) -echo @([[:alpha:].])@([[:alpha:].])@([[:alpha:].]) - -case . in -!([[:alpha:].]) ) echo bad 1;; -*) echo ok 1;; -esac - -case . in -?([[:alpha:].]) ) echo ok 2;; -*) echo bad 2;; -esac - -case . in -@([[:alpha:].]) ) echo ok 3;; -*) echo bad 3;; -esac - -cd $MYDIR -rm -rf $GDIR 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/history.tests~ b/tests/history.tests~ deleted file mode 100644 index 16e6b26e2..000000000 --- a/tests/history.tests~ +++ /dev/null @@ -1,109 +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 - -unset HISTFILESIZE - -# 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 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 - -# these two blocks had better both result in the same output -echo aa -echo bb -echo cc -fc -e cat - -echo aa -echo bb -echo cc -fc -e cat -1 - -set +o history - -shopt -q -o history -echo $? diff --git a/tests/history1.sub~ b/tests/history1.sub~ deleted file mode 100644 index 9c73bccbe..000000000 --- a/tests/history1.sub~ +++ /dev/null @@ -1,11 +0,0 @@ -set -o history - -history -c -cat < $FILE - -mapfile -n 5 array < $FILE -echo ${array[@]} - -mapfile -n 5 -c 1 -C "echo foo" array < $FILE -mapfile -n 5 -c 1 -C "echo foo" array < /dev/null 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/new-exp.tests~ b/tests/new-exp.tests~ deleted file mode 100644 index 0fc265db8..000000000 --- a/tests/new-exp.tests~ +++ /dev/null @@ -1,562 +0,0 @@ -# must do this because posix mode causes process substitution to be disabled -# and flagged as a syntax error, which causes the shell to exit -set +o posix - -expect() -{ - echo expect "$@" -} - -HOME=/usr/homes/chet # to make the check against new-exp.right work -expect '' -recho "${undef-"foo bar"}" # should be foo bar -expect '' -recho "${und="foo"}" # should be foo - -expect "<$HOME>" -recho ${HOME-"}"} -expect "<$HOME>" -recho "${HOME-'}'}" -expect "<$HOME>" -recho "${HOME-"}"}" - -expect $0: 'HOME: }: syntax error: operand expected (error token is "}")' -recho "${HOME:`echo }`}" # should be a math error -- bad substring substitution - -expect unset -_ENV=oops -x=${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]} -echo ${x:-unset} - -expect "<$HOME>" -recho ${HOME} -expect "<$HOME>" -recho ${HOME:-`echo }`} -expect "<$HOME>" -recho ${HOME:-`echo "}"`} -expect "<$HOME>" -recho "${HOME:-`echo "}"`}" -expect "<$HOME>" -recho "$(echo "${HOME}")" -expect "<$HOME>" -recho "$(echo "$(echo ${HOME})")" -expect "<$HOME>" -recho "$(echo "$(echo "${HOME}")")" - -P=*@* -expect '<*@>' -recho "${P%"*"}" # -expect '<*@>' -recho "${P%'*'}" # -expect '<@*>' -recho "${P#\*}" # should be @* - -expect '<)>' -recho "$(echo ")")" # should be ) -expect '<")">' -recho "$(echo "\")\"")" # should be ")" - -foo='abcd ' -expect '<-abcd> <->' -recho -${foo}- # should be -abcd - -expect '<-abcd> <->' -recho -${foo% *}- # should be -abcd - -expect '<-abcd->' -recho -${foo%% *}- # should be -abcd- - -foo=bar -expect '' -echo -n $foo' ' ; echo foo - -expect '' -echo -n $foo" " ; echo foo - -expect '' -echo -n "$foo " ; echo foo - -expect '' -echo -e "$foo\c " ; echo foo - -expect '' -echo -e $foo"\c " ; echo foo - -# make sure backslashes are preserved in front of characters that are not -# valid backslash escapes -expect '<\x>' -echo -e '\x' - -# substring tests -z=abcdefghijklmnop -expect '' -recho ${z:0:4} - -expect ' ' -recho ${z:4:3} ${z:${#z}-3:3} - -expect ' ' -recho ${z:4:3} ${z: -3:3} - -expect '' -recho ${z:7:30} - -expect '' -recho ${z:0:100} - -expect '' -recho ${z:0:${#z}} - -set 'ab cd' 'ef' 'gh ij' 'kl mn' 'op' -expect ' ' -recho "${@:1:2}" - -expect ' ' -recho "${@:3:2}" - -expect ' ' -recho "${@:3:4}" - -expect ' ' -recho "${@:1:$#}" - -# code to ad-hoc parse arithmetic expressions in substring expansions was -# broken until post-2.04 -base=/home/chet/foo//bar -string1=$base/abcabcabc -x=1 j=4 - -expect '' -recho ${string1:0} - -expect '' -recho ${string1:1} - -expect '' -recho ${string1:(j?1:0):j} - -expect '' -recho ${string1:j?1:0:j} - -expect '' -recho ${string1:(j?(x?1:0):0):j} - -expect '' -recho ${string1:j?(x?1:0):0:j} - -unset base string1 x j - -# indirect variable references -expect '' -recho ${!9:-$z} - -ef=4 -expect '<4>' -recho ${!2} - -expect '' -recho ${!#} - -set a b c d e -a= -expect '' -recho ${a:-$z} -expect '' -recho ${!1:-$z} - -expect nothing -recho ${a-$z} -expect nothing -recho ${!1-$z} - -set -u -expect $0: ABX: unbound variable -( recho ${ABX} ) -set +u - -expect $0: '$6: cannot assign in this way' -recho ${6="arg6"} - -v=abcde - -# sed-like variable substitution -expect '' -recho ${v/a[a-z]/xx} -expect '' -recho ${v/a??/axx} -expect '' -recho ${v/c??/xyz} -expect '' -recho ${v/#a/ab} -expect '' -recho ${v/#d/ab} -expect '' -recho ${v/d/ab} -expect '' -recho ${v/%?/last} -expect '' -recho ${v/%x/last} - -av=(abcd efgh ijkl mnop qrst uvwx) - -expect '' -recho ${av/??/xx} -expect '' -recho ${av/%??/xx} -expect '' -recho ${av[1]/??/xx} -expect '' -recho ${av[1]/%ab/xx} -expect '' -recho ${av[1]/#?/xx} -expect '' -recho ${av[1]/??/za} -expect '' -recho ${av[1]//??/za} -expect '' -recho ${av[1]/#??/za} -expect '' -recho ${av[1]/%??/za} - -expect ' ' -recho ${av[@]/*/yyy} -expect ' ' -recho ${av[@]/#*/yyy} -expect ' ' -recho ${av[@]/%*/yyy} -expect ' ' -recho ${av[@]/a*/yyy} -expect ' ' -recho ${av[@]/%??/xx} - -set abcd efgh ijkl mnop qrst uvwx - -expect '' -recho ${1/??/xx} -expect ' ' -recho ${@/??/xx} -expect ' ' -recho ${@/%??/xx} -expect '' -recho ${3//??/za} -expect '' -recho ${3/%??/za} -expect ' ' -recho ${@//??/za} -expect ' ' -recho ${@/#??/za} -expect ' ' -recho ${@//*/yyy} -expect ' ' -recho ${@//a*/yyy} -expect ' ' -recho ${@/%x*/yyy} - -expect a newline -echo $abmcde - -# sneaky way to replace a newline in a variable value with something else -AVAR=$'This\nstring\nhas\nmultiple\nlines.' -echo "${AVAR}" - -eval BVAR=\"\${AVAR//$'\n'/-}\" -echo "$BVAR" - -unset AVAR BVAR - -# run process substitution tests in a subshell so that syntax errors -# caused by a shell not implementing process substitution (e.g., one -# built on a NeXT) will not cause the whole test to exit prematurely -${THIS_SH} ./new-exp1.sub - -# run the tests of $(' -recho ${#:-foo} -expect $0: '${#:}: bad substitution' -echo ${#:} - -expect "<'>" -recho "'" -expect '<">' -recho '"' -expect '<"hello">' -recho "\"hello\"" - -shift $# -unset foo -z=abcdef -z1='abc def' - -expect '<>' -recho ${foo:-""} -expect nothing -recho ${foo:-"$@"} -expect '<>' -recho "${foo:-$@}" - -# unset var -expect '<>' -recho ${foo:-"$zbcd"} -expect nothing -recho ${foo:-$zbcd} - -# set var -expect '' -recho ${foo:-"$z"} -expect '' -recho ${foo:-"$z1"} - -expect '' -recho ${foo:-$z} -expect ' ' -recho ${foo:-$z1} - -expect '' -recho "${foo:-$z}" -expect '' -recho "${foo:-$z1}" - -expect '' -recho "${foo:-"$z"}" -# this disagrees with sh and ksh, but I think it is right according -# to posix.2. -expect '' -recho "${foo:-"$z1"}" - -set ab cd ef gh -expect ' ' -recho ${foo:-"$@"} -expect ' ' -recho "${foo:-$@}" -expect ' ' -recho "${foo:-"$@"}" - -shift $# -expect nothing -recho $xxx"$@" -expect nothing -recho ${foo:-$xxx"$@"} -expect '<>' -recho "${foo:-$xxx$@}" -expect '<>' -recho "${foo:-$xxx"$@"}" - -expect nothing -recho $xxx"$@" -expect nothing -recho "$xxx$@" -expect nothing -recho "$@"$xxx - -expect '<>' -recho $xxx"" -expect '<>' -recho $xxx'' -expect '<>' -recho ''$xxx -expect '<>' -recho ""$xxx - -AB='abcdefghijklmnopqrstuvwxyz' - -recho ${AB:7:15} -recho ${AB:15:7} - -recho ${AB:20} - -recho ${AB:0} -recho ${AB:0:20} - -recho ${AB:10:7} -recho ${AB:10:3+4} -recho ${AB:20/2:3+4} - -set 1 2 3 4 5 6 -recho \""${*:2:2}"\" - -IFS=: -recho \""${*:2:2}"\" - -IFS=$' \t\n' - -z=123456 - -recho \""${z:2:2}"\" -recho \""${z:2}"\" -recho \""${z:2:4}"\" -recho \""${z:2:6}"\" - -set $'\1' $'\2' $'\177' - -recho $* -recho $@ - -recho ${*} -recho ${@} - -xx=one/two/two -recho ${xx%/*} -recho ${xx/\/two} - -yy=oneonetwo -recho ${yy//one} -recho ${yy/\/one} - -xx=oneonetwo - -recho ${xx/one} -recho ${xx//one} -recho ${xx/\/one} - -# out-of-range substrings -var=abc -c=${var:3} -expect nothing -recho $c -c=${var:4} -expect nothing -recho $c -expect '<./new-exp.tests: -2: substring expression < 0>' -c=${var:0:-2} - -var=abcdefghi -c=${var:3:12} -recho $c -c=${var:4:20} -recho $c - -# make sure null patterns work -xxx=endocrine -yyy=n -unset zzz - -recho ${xxx/$yyy/*} -recho ${xxx//$yyy/*} - -recho ${xxx/$zzz/*} -recho ${xxx//$zzz/*} - -recho ${xxx//%${zzz}/} -recho ${xxx//%${zzz}} -recho ${xxx//#${zzz}/} -recho ${xxx//#${zzz}} - -# another case that caused a core dump in bash-2.0 -XPATH=/usr/bin:/bin:/usr/local/bin:/usr/gnu/bin::/usr/bin/X11:/sbin:/usr/sbin - -recho ${XPATH//:/ } - -xx=(ar as at au av aw ax ay az) - -recho ${xx[@]/a/} -recho ${xx[@]//a/} - -recho ${xx[*]/a/} -recho ${xx[*]//a/} - -recho ${xx[@]%?} -recho ${xx[*]%?} - -recho ${xx[@]#?} -recho ${xx[*]#?} - -set -- ar as at au av aw ax ay az - -recho ${@/a/} -recho ${@//a/} - -recho ${*/a/} -recho ${*//a/} - -recho ${@%?} -recho ${*%?} - -recho ${@#?} -recho ${*#?} - -shift $# -set -u -( recho $9 ; echo after 1) -( recho ${9} ; echo after 2) -( recho $UNSET ; echo after 3) -( recho ${UNSET} ; echo after 4) -( recho "$UNSET" ; echo after 5) -( recho "${UNSET}" ; echo after 6) -( recho "${#UNSET}" ; echo after 7) -set +u - -RECEIVED="12345" -recho "${RECEIVED:$((${#RECEIVED}-1)):1}" -RECEIVED="12345#" -recho "${RECEIVED:$((${#RECEIVED}-1)):1}" -RECEIVED="#" -recho "${RECEIVED:$((${#RECEIVED}-1)):1}" -RECEIVED="" -recho "${RECEIVED:$((${#RECEIVED}-1)):1}" - -# tests of new prefix expansion ${!prefix*} -${THIS_SH} ./new-exp3.sub - -# bug with indirect expansion through bash-2.05b -${THIS_SH} ./new-exp4.sub - -# these caused errors and core dumps in versions before bash-2.04 -c="" -echo ${c//${$(($#-1))}/x/} - -set a b c d e f g -recho "$@" - -set -- ${@:1:$(($# - 2))} -recho "$@" - -set a b -recho ${@:1:$(($# - 2))} - -recho ${@:1:0} -recho ${@:1:1} -recho ${@:1:2} - -recho "${*:1:0}" - -# this is an error -- negative expression -set a -recho ${@:1:$(($# - 2))} - -XPATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:.:/sbin:/usr/sbin -set $( IFS=: ; echo $XPATH ) - -recho ${@##*/} -recho ${@%%[!/]*} - -recho ${@#/*} -recho ${@%*/} - -set /full/path/to/x16 /another/full/path - -recho ${1%/*} -recho ${1%%[!/]*} -recho ${1#*/} -recho ${1##*/} - -${THIS_SH} ./new-exp5.sub - -unset var -var=blah - -# these had better agree -echo ${var[@]:3} -echo ${var:3} -echo ${var[@]/#/--} -echo ${var/#/--} -echo ${var[@]##?} -echo ${var##?} - -${THIS_SH} ./new-exp6.sub - -${THIS_SH} ./new-exp7.sub - -# this must be last! -expect $0: 'ABXD: parameter unset' -recho ${ABXD:?"parameter unset"} diff --git a/tests/nquote3.tests~ b/tests/nquote3.tests~ deleted file mode 100644 index 6bb42daa4..000000000 --- a/tests/nquote3.tests~ +++ /dev/null @@ -1,94 +0,0 @@ -a=$'a\001b' - -set $a - -b=$a -c=$1 -d="$1" - -e=$'uv\001\001wx' -f=$'uv\001w\001xy' - -set $e $e - -recho ${e%%??} -recho "${e%%??}" - -recho ${e%%???} -recho "${e%%???}" - -recho ${a#?} -recho "${a#?}" - -# simple variables - -recho ${f##*$'\001'} -recho "${f##*$'\001'}" -recho ${f##*''} # literal ^A -recho "${f##*'^A'}" # two characters, `^' and `A' - -recho ${e%$'\001'*} -recho "${e%$'\001'*}" -recho ${e#*$'\001'} -recho "${e#*$'\001'}" - -# array members - -arr[0]=$e -arr[1]=$f - -recho ${arr[1]##*$'\001'} -recho "${arr[1]##*$'\001'}" -recho ${arr[1]##*''} # literal ^A -recho "${arr[1]##*'^A'}" # two characters, `^' and `A' - -recho ${arr[0]%$'\001'*} -recho "${arr[0]%$'\001'*}" -recho ${arr[0]#*$'\001'} -recho "${arr[0]#*$'\001'}" - -recho ${arr%$'\001'*} -recho "${arr%$'\001'*}" -recho ${arr#*$'\001'} -recho "${arr#*$'\001'}" - -# positional parameters - -set $e $f - -recho ${2##*$'\001'} -recho "${2##*$'\001'}" -recho ${2##*''} # literal ^A -recho "${2##*''}" # literal ^A -recho ${2##*'^A'} # two characters, `^' and `A' -recho "${2##*'^A'}" # two characters, `^' and `A' - -recho ${1%$'\001'*} -recho "${1%$'\001'*}" -recho ${1#*$'\001'} -recho "${1#*$'\001'}" - -recho ${@%$'\001'*} -recho "${@%$'\001'*}" -recho ${@#*$'\001'} -recho "${@#*$'\001'}" -recho ${@##*''} # literal ^A -recho "${@##*'^A'}" # two characters, `^' and `A' - -# arrays treated as a whole - -recho ${arr[@]%$'\001'*} -recho "${arr[@]%$'\001'*}" -recho ${arr[@]#*$'\001'} -recho "${arr[@]#*$'\001'}" -recho ${arr[@]##*''} # literal ^A -recho "${arr[@]##*'^A'}" # two characters, `^' and `A' - -# make sure command substitution works with CTLESC as well -a=$'ab\001cd\001ef' - -recho $a -recho "$a" - -recho $(echo $a) -recho $(echo "$a") diff --git a/tests/nquote5.tests~ b/tests/nquote5.tests~ deleted file mode 100644 index 8667783da..000000000 --- a/tests/nquote5.tests~ +++ /dev/null @@ -1,43 +0,0 @@ -a=$'ab\001cd\001ef' -IFS=$'\001' - -recho $a -recho ${a} -recho xx${a}yy -recho "$a" - -recho $(echo $a) -recho $(echo "$a") - -recho ${a%%??} -recho "${a%%??}" - -recho ${a/f/} -recho "${a/f/}" - -a1=("$a") -recho ${a1[0]} -recho ${a1} - -recho ${a:2:2} - -set -- $a -recho $1 -- $2 -- $3 - -set -- "$a" -recho $1 -recho ${1} - -echo "$a" | { IFS=$'\001' read x y z; recho $x -- $y -- $z ; } -unset x y z -b=$'uv\177wx\177yz' - -recho $b - -recho "ab${x}y${a}z" -recho ab${x}y${a}z - -recho "ab${b}y${a}z" -recho ab${b}y${a}z - -echo "ab${b}y${a}z" | { IFS=$'\001' read l m n o ; recho $l -- $m -- $n -- $o; } diff --git a/tests/printf.tests~ b/tests/printf.tests~ deleted file mode 100644 index 9b12f8d4c..000000000 --- a/tests/printf.tests~ +++ /dev/null @@ -1,309 +0,0 @@ -LC_ALL=C -LC_NUMERIC=C - -# these should output error messages -- the format is required -printf -printf -- - -# these should output nothing -printf "" -printf -- "" - -# in the future this may mean to put the output into VAR, but for -# now it is an error -# 2005-03-15 no longer an error -unset var -printf -v var "%10d" $RANDOM -echo ${#var} - -# this should expand escape sequences in the format string, nothing else -printf "\tone\n" - -# this should not cut off output after the \c -printf "one\ctwo\n" - -# and unrecognized backslash escapes should have the backslash preserverd -printf "4\.2\n" - -printf "no newline " ; printf "now newline\n" - -# %% -> % -printf "%%\n" - -# this was a bug caused by pre-processing the string for backslash escapes -# before doing the `%' format processing -- all versions before bash-2.04 -printf "\045" ; echo -printf "\045d\n" - -# simple character output -printf "%c\n" ABCD - -# test simple string output -printf "%s\n" unquoted - -# test quoted string output -printf "%s %q\n" unquoted quoted -printf "%s%10q\n" unquoted quoted - -printf "%q\n" 'this&that' - -# make sure the format string is reused to use up arguments -printf "%d " 1 2 3 4 5; printf "\n" - -# make sure that extra format characters get null arguments -printf "%s %d %d %d\n" onestring - -printf "%s %d %u %4.2f\n" onestring - -printf -- "--%s %s--\n" 4.2 '' -printf -- "--%s %s--\n" 4.2 - -# test %b escapes - -# 8 is a non-octal digit, so the `81' should be output -printf -- "--%b--\n" '\n\081' - -printf -- "--%b--\n" '\t\0101' -printf -- "--%b--\n" '\t\101' - -# these should all display `A7' -echo -e "\01017" -echo -e "\x417" - -printf "%b\n" '\01017' -printf "%b\n" '\1017' -printf "%b\n" '\x417' - -printf -- "--%b--\n" '\"abcd\"' -printf -- "--%b--\n" "\'abcd\'" - -printf -- "--%b--\n" 'a\\x' - -printf -- "--%b--\n" '\x' - -Z1=$(printf -- "%b\n" '\a\b\e\f\r\v') -Z2=$'\a\b\e\f\r\v' - -if [ "$Z1" != "$Z2" ]; then - echo "whoops: printf %b and $'' differ" >&2 -fi -unset Z1 Z2 - -printf -- "--%b--\n" '' -printf -- "--%b--\n" - -# the stuff following the \c should be ignored, as well as the rest -# of the format string -printf -- "--%b--\n" '4.2\c5.4\n'; printf "\n" - -# unrecognized escape sequences should by displayed unchanged -printf -- "--%b--\n" '4\.2' - -# a bare \ should not be processed as an escape sequence -printf -- "--%b--\n" '\' - -# make sure extra arguments are ignored if the format string doesn't -# actually use them -printf "\n" 4.4 BSD -printf " " 4.4 BSD ; printf "\n" - -# make sure that a fieldwidth and precision of `*' are handled right -printf "%10.8s\n" 4.4BSD -printf "%*.*s\n" 10 8 4.4BSD - -printf "%10.8q\n" 4.4BSD -printf "%*.*q\n" 10 8 4.4BSD - -printf "%6b\n" 4.4BSD -printf "%*b\n" 6 4.4BSD - -# we handle this crap with homemade code in printf.def -printf "%10b\n" 4.4BSD -printf -- "--%-10b--\n" 4.4BSD -printf "%4.2b\n" 4.4BSD -printf "%.3b\n" 4.4BSD -printf -- "--%-8b--\n" 4.4BSD - -# test numeric conversions -- these four lines should echo identically -printf "%d %u %i 0%o 0x%x 0x%X\n" 255 255 255 255 255 255 -printf "%d %u %i %#o %#x %#X\n" 255 255 255 255 255 255 - -printf "%ld %lu %li 0%o 0x%x 0x%X\n" 255 255 255 255 255 255 -printf "%ld %lu %li %#o %#x %#X\n" 255 255 255 255 255 255 - -printf "%10d\n" 42 -printf "%10d\n" -42 - -printf "%*d\n" 10 42 -printf "%*d\n" 10 -42 - -# test some simple floating point formats -printf "%4.2f\n" 4.2 -printf "%#4.2f\n" 4.2 -printf "%#4.1f\n" 4.2 - -printf "%*.*f\n" 4 2 4.2 -printf "%#*.*f\n" 4 2 4.2 -printf "%#*.*f\n" 4 1 4.2 - -printf "%E\n" 4.2 -printf "%e\n" 4.2 -printf "%6.1E\n" 4.2 -printf "%6.1e\n" 4.2 - -printf "%G\n" 4.2 -printf "%g\n" 4.2 -printf "%6.2G\n" 4.2 -printf "%6.2g\n" 4.2 - -# test some of the more esoteric features of POSIX.1 printf -printf "%d\n" "'string'" -printf "%d\n" '"string"' - -printf "%#o\n" "'string'" -printf "%#o\n" '"string"' - -printf "%#x\n" "'string'" -printf "%#X\n" '"string"' - -printf "%6.2f\n" "'string'" -printf "%6.2f\n" '"string"' - -# output from these two lines had better be the same -printf -- "--%6.4s--\n" abcdefghijklmnopqrstuvwxyz -printf -- "--%6.4b--\n" abcdefghijklmnopqrstuvwxyz - -# and these two also -printf -- "--%12.10s--\n" abcdefghijklmnopqrstuvwxyz -printf -- "--%12.10b--\n" abcdefghijklmnopqrstuvwxyz - -# tests for translating \' to ' and \\ to \ -# printf translates \' to ' in the format string... -printf "\'abcd\'\n" - -# but not when the %b format specification is used -printf "%b\n" \\\'abcd\\\' - -# but both translate \\ to \ -printf '\\abcd\\\n' -printf "%b\n" '\\abcd\\' - -# this was reported as a bug in bash-2.03 -# these three lines should all echo `26' -printf "%d\n" 0x1a -printf "%d\n" 032 -printf "%d\n" 26 - -# error messages - -# this should be an overflow, but error messages vary between systems -# printf "%lu\n" 4294967296 - -# ...but we cannot use this because some systems (SunOS4, for example), -# happily ignore overflow conditions in strtol(3) -#printf "%ld\n" 4294967296 - -printf "%10" -printf "ab%Mcd\n" - -# this caused an infinite loop in older versions of printf -printf "%y" 0 - -# these should print a warning and `0', according to POSIX.2 -printf "%d\n" GNU -printf "%o\n" GNU - -# failures in all bash versions through bash-2.05 -printf "%.0s" foo -printf "%.*s" 0 foo - -printf '%.0b-%.0s\n' foo bar -printf '(%*b)(%*s)\n' -4 foo -4 bar - -format='%'`printf '%0100384d' 0`'d\n' -printf $format 0 - -# failures in all bash versions through bash-3.0 - undercounted characters -unset vv -printf " %s %s %s \n%n" ab cd ef vv -echo "$vv" - -# this doesn't work with printf(3) on all systems -#printf "%'s\n" foo - -# test cases from an austin-group list discussion -# prints ^G as an extension -printf '%b\n' '\7' - -# prints ^G -printf '%b\n' '\0007' - -# prints NUL then 7 -printf '\0007\n' - -# prints no more than two hex digits -printf '\x07e\n' - -# additional backslash escapes -printf '\"\?\n' - -# failures with decimal precisions until after bash-3.1 -printf '%0.5d\n' 1 - -printf '%05d\n' 1 -printf '%5d\n' 1 -printf '%0d\n' 1 - -# failures with various floating point formats and 0 after bash-3.2 - -printf "%G\n" 0 -printf "%g\n" 0 -printf "%4.2G\n" 0 -printf "%4.2g\n" 0 - -printf "%G\n" 4 -printf "%g\n" 4 -printf "%4.2G\n" 4 -printf "%4.2g\n" 4 - -printf "%F\n" 0 -printf "%f\n" 0 -printf "%4.2F\n" 0 -printf "%4.2f\n" 0 - -printf "%F\n" 4 -printf "%f\n" 4 -printf "%4.2F\n" 4 -printf "%4.2f\n" 4 - -printf "%E\n" 0 -printf "%e\n" 0 -printf "%4.2E\n" 0 -printf "%4.2e\n" 0 - -printf "%E\n" 4 -printf "%e\n" 4 -printf "%4.2E\n" 4 -printf "%4.2e\n" 4 - -printf "%08X\n" 2604292517 - -# make sure these format specifiers all output '' for empty string arguments -echo q -printf "%q\n" "" -printf "%q\n" - -echo s -printf "%s\n" '' -printf "%s\n" - -echo b -printf "%b\n" '' -printf "%b\n" - -# bug in bash versions up to and including bash-3.2 -v-=yyy -printf -v var "%s" '/current/working/directory/*.@(m3|i3|ig|mg)' -shopt -s nullglob extglob -echo "x$(printf "%b" @(hugo))x" -printf -v var "%b" @(hugo); echo "x${var}x" diff --git a/tests/read.tests~ b/tests/read.tests~ deleted file mode 100644 index f9c78c5a9..000000000 --- a/tests/read.tests~ +++ /dev/null @@ -1,95 +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 - -# test behavior when IFS is not the default -- bug through bash-2.05b -${THIS_SH} ./read5.sub diff --git a/tests/read6.sub~ b/tests/read6.sub~ deleted file mode 100644 index 5f5e1027f..000000000 --- a/tests/read6.sub~ +++ /dev/null @@ -1,12 +0,0 @@ -# test read with a timeout of 0 -- input polling - -echo abcde | read -t 0 -echo $? - -read -t 0 < bash -echo $? - -read -t 0 -echo $? - - diff --git a/tests/redir.tests~ b/tests/redir.tests~ deleted file mode 100644 index 5d88357c2..000000000 --- a/tests/redir.tests~ +++ /dev/null @@ -1,189 +0,0 @@ -: ${TMPDIR:=/tmp} - -export LC_ALL=C -export LANG=C - -# catch-all for remaining untested redirection stuff -set +o posix - -echo abc > /tmp/redir-test -cat /tmp/redir-test - -set -o noclobber - -#this should be an error -echo def > /tmp/redir-test -cat /tmp/redir-test - -# but this should succeed -echo def > /tmp/redir-test-2 -cat /tmp/redir-test-2 - -# and so should this -echo def >| /tmp/redir-test -cat /tmp/redir-test - -set +o noclobber -rm /tmp/redir-test /tmp/redir-test-2 - -# this should be an error -z="a b" -cat < $z - -echo "Point 1" - -exec 3$TMPDIR/bash-a -exec 5>$TMPDIR/bash-b -echo "Point 2" - -echo to a 1>&4 -echo to b 1>&5 -cat $TMPDIR/bash-a -cat $TMPDIR/bash-b -exec 11&4 -echo to b 1>&5 -cat $TMPDIR/bash-a -cat $TMPDIR/bash-b - -exec 11<&- -echo "Point 4" - -exec 6<>$TMPDIR/bash-c -echo to c 1>&6 -cat $TMPDIR/bash-c -echo "Point 5" - -rm -f $TMPDIR/bash-a $TMPDIR/bash-b $TMPDIR/bash-c - -# -# Test the effect of input buffering on the shell's input -# -${THIS_SH} < redir1.sub - -# more open, close, duplicate file descriptors -${THIS_SH} ./redir3.sub < ./redir3.in1 - -# still more redirections -${THIS_SH} ./redir4.sub < redir4.in1 - -# various forms of null redirection -testf() -{ - if [ -f "$1" ]; then - rm -f "$1" - else - echo oops -- $1 not found - fi -} - -> $TMPDIR/null-redir-a -testf $TMPDIR/null-redir-a - -$EXIT > $TMPDIR/null-redir-b -testf $TMPDIR/null-redir-b - -( > $TMPDIR/null-redir-c ) -testf $TMPDIR/null-redir-c - -$EXIT > $TMPDIR/null-redir-d & -wait -testf $TMPDIR/null-redir-d - -exit 3 | $EXIT > $TMPDIR/null-redir-e -echo $? -- ${PIPESTATUS[@]} -testf $TMPDIR/null-redir-e - -exit 4 | > $TMPDIR/null-redir-f -echo $? -- ${PIPESTATUS[@]} -testf $TMPDIR/null-redir-f - -> $TMPDIR/null-redir-g & -wait -testf $TMPDIR/null-redir-g - -exec >$TMPDIR/null-redir-h & -wait -testf $TMPDIR/null-redir-h - -# make sure async commands don't get /dev/null as stdin when an explicit -# input redirection is supplied -for x in 1 2 3; do - { read line ; echo $line ; } & - wait - { read line ; echo $line ; } & - wait -done << EOF -ab -cd -ef -gh -ij -kl -EOF - -# make sure async commands get /dev/null as stdin in the absence of any -# input redirection -/bin/cat & -wait -echo $? - -# make sure that loops work OK with here documents and are not run in -# subshells -while read line; do - echo $line - l2=$line -done << EOF -ab -cd -EOF -echo $l2 - -# These should not echo anything -- bug in versions before 2.04 -( ( echo hello 1>&3 ) 3>&1 ) >/dev/null 2>&1 - -( ( echo hello 1>&3 ) 3>&1 ) >/dev/null 2>&1 | cat - -# in posix mode, non-interactive shells are not allowed to perform -# filename expansion on input redirections, even if they expand to -# a single filename -set -o posix -cat < redir1.* - -# test ksh93 dup-and-close (move fd) redirections -${THIS_SH} ./redir5.sub - -# test behavior after a write error with a builtin command -${THIS_SH} ./redir6.sub - -# problem with redirections using fds bash uses internally -: ${TMPDIR:=$TMPDIR} - -trap 'rm -f $TMPDIR/bash-redir-$$' 0 1 2 3 6 15 - -echo before block -{ - echo before redir - exec 10>&1 - echo after redir -} > $TMPDIR/bash-redir-$$ - -echo after block - -${THIS_SH} ./redir7.sub - -${THIS_SH} ./redir8.sub - -exec 9>&2 -command exec 2>$TMPDIR/foo -echo whatsis >&2 -echo cat $TMPDIR/foo -cat $TMPDIR/foo -rm -f $TMPDIR/foo -exec 2>&9 -exec 9>&- - -${THIS_SH} ./redir9.sub diff --git a/tests/redir8.sub~ b/tests/redir8.sub~ deleted file mode 100644 index da12cc766..000000000 --- a/tests/redir8.sub~ +++ /dev/null @@ -1,60 +0,0 @@ -rm -f u - -${THIS_SH} -c 'exec 10>&1; echo fd 10 >&10' 10>u -cat u -rm -f u - -${THIS_SH} -c 'exec 8>&1; echo fd 8 >&8' 8>u -cat u -rm -f u - -exec 10>u -exec 10>&1; echo 'fd 10' >&10 -cat u -rm -f u -exec 10>&- - -exec 8>u -exec 8>&1; echo 'fd 8' >&8 -cat u -rm -f u -exec 8>&- - -rm -f infile -cat > infile <&2 -} - -rm -f $TMPDIR/foo - -echo hey > $TMPDIR/foo -func &>> $TMPDIR/foo - -cat $TMPDIR/foo - -echo -func &> $TMPDIR/foo - -cat $TMPDIR/foo - -echo -func >$TMPDIR/foo -cat $TMPDIR/foo - -echo -echo hey > $TMPDIR/foo -func >> $TMPDIR/foo -cat $TMPDIR/foo - -rm -f $TMPDIR/foo - -logfunc() -{ - echo "$@" &>> $TMPDIR/log -} - -type logfunc diff --git a/tests/run-array~ b/tests/run-array~ deleted file mode 100644 index 44207d9cc..000000000 --- a/tests/run-array~ +++ /dev/null @@ -1,4 +0,0 @@ -echo "warning: all of these tests will fail if arrays have not" >&2 -echo "warning: been compiled into the shell" >&2 -${THIS_SH} ./array.tests > /tmp/xx 2>&1 -diff /tmp/xx array.right && rm -f /tmp/xx diff --git a/tests/run-assoc~ b/tests/run-assoc~ deleted file mode 100644 index 6fdbae494..000000000 --- a/tests/run-assoc~ +++ /dev/null @@ -1,6 +0,0 @@ -echo "warning: all of these tests will fail if arrays have not" >&2 -echo "warning: been compiled into the shell" >&2 -echo "warning: the BASH_ARGC and BASH_ARGV tests will fail if debugging support" >&2 -echo "warning: has not been compiled into the shell" >&2 -${THIS_SH} ./array.tests > /tmp/xx 2>&1 -diff /tmp/xx array.right && rm -f /tmp/xx diff --git a/tests/run-builtins~ b/tests/run-builtins~ deleted file mode 100644 index 545f0b889..000000000 --- a/tests/run-builtins~ +++ /dev/null @@ -1,6 +0,0 @@ -echo "warning: some of these tests may fail if process substitution has not" >&2 -echo "warning: been compiled into the shell or if the OS does not provide" >&2 -ecoh "warning: /dev/fd." >&2 - -${THIS_SH} ./builtins.tests > /tmp/xx 2>&1 -diff /tmp/xx builtins.right && rm -f /tmp/xx diff --git a/tests/run-case~ b/tests/run-case~ deleted file mode 100644 index 6fdbae494..000000000 --- a/tests/run-case~ +++ /dev/null @@ -1,6 +0,0 @@ -echo "warning: all of these tests will fail if arrays have not" >&2 -echo "warning: been compiled into the shell" >&2 -echo "warning: the BASH_ARGC and BASH_ARGV tests will fail if debugging support" >&2 -echo "warning: has not been compiled into the shell" >&2 -${THIS_SH} ./array.tests > /tmp/xx 2>&1 -diff /tmp/xx array.right && rm -f /tmp/xx diff --git a/tests/run-comsub-eof~ b/tests/run-comsub-eof~ deleted file mode 100644 index 0bbcad5e8..000000000 --- a/tests/run-comsub-eof~ +++ /dev/null @@ -1,2 +0,0 @@ -${THIS_SH} ./comsub.tests > /tmp/xx 2>&1 -diff /tmp/xx comsub.right && rm -f /tmp/xx diff --git a/tests/run-coproc~ b/tests/run-coproc~ deleted file mode 100644 index 6aa9915f5..000000000 --- a/tests/run-coproc~ +++ /dev/null @@ -1,2 +0,0 @@ -${THIS_SH} ./coproc.tests > /tmp/xx 2>&1 -diff /tmp/xx coproc.right && rm -f /tmp/xx diff --git a/tests/run-exp-tests~ b/tests/run-exp-tests~ deleted file mode 100644 index c55f7147b..000000000 --- a/tests/run-exp-tests~ +++ /dev/null @@ -1,2 +0,0 @@ -${THIS_SH} ./exp-tests | grep -v '^expect' > /tmp/xx -diff /tmp/xx exp.right && rm -f /tmp/xx diff --git a/tests/run-minimal~ b/tests/run-minimal~ deleted file mode 100644 index 5c5dcc498..000000000 --- a/tests/run-minimal~ +++ /dev/null @@ -1,36 +0,0 @@ -#! /bin/sh -# -# run-minimal - a version of run-all for shells configured with -# --enable-minimal-config -# -PATH=.:$PATH # just to get the right version of printenv -export PATH - -# unset BASH_ENV only if it is set -[ "${BASH_ENV+set}" = "set" ] && unset BASH_ENV -# ditto for SHELLOPTS -#[ "${SHELLOPTS+set}" = "set" ] && unset SHELLOPTS - -: ${THIS_SH:=../bash} -export THIS_SH - -${THIS_SH} ./version.mini - -rm -f /tmp/xx - -echo Testing ${THIS_SH} -echo Any output from any test, unless otherwise noted, indicates a possible anomaly -for x in run-* -do - case $x in - $0) ;; - *.orig|*~) ;; - run-dollars|run-execscript|run-func|run-getopts|run-heredoc) echo $x ; sh $x ;; - run-ifs-tests|run-input-test|run-invert|run-more-exp|run-nquote) echo $x ; sh $x ;; - run-ifs-0posix|run-posix2|run-posixpat) echo $x ; sh $x ;; - run-precedence|run-quote|run-read|run-rhs-exp|run-strip|run-tilde) echo $x ; sh $x ;; - *) ;; - esac -done - -exit 0 diff --git a/tests/run-nquote4~ b/tests/run-nquote4~ deleted file mode 100644 index f7d05bb29..000000000 --- a/tests/run-nquote4~ +++ /dev/null @@ -1,4 +0,0 @@ -echo warning: some of these tests will fail if you do not have UTF-8 >&2 -echo warning: locales installed on your system -${THIS_SH} ./nquote4.tests 2>&1 | grep -v '^expect' > /tmp/xx -diff /tmp/xx nquote4.right && rm -f /tmp/xx diff --git a/tests/run-nquote5~ b/tests/run-nquote5~ deleted file mode 100644 index f7d05bb29..000000000 --- a/tests/run-nquote5~ +++ /dev/null @@ -1,4 +0,0 @@ -echo warning: some of these tests will fail if you do not have UTF-8 >&2 -echo warning: locales installed on your system -${THIS_SH} ./nquote4.tests 2>&1 | grep -v '^expect' > /tmp/xx -diff /tmp/xx nquote4.right && rm -f /tmp/xx diff --git a/tests/set-e-test~ b/tests/set-e-test~ deleted file mode 100644 index fe1549c41..000000000 --- a/tests/set-e-test~ +++ /dev/null @@ -1,84 +0,0 @@ -if : ; then - set -e - N=95 - while :; do - # expr returns 1 if expression is null or 0 - set +e - N_MOD_100=`expr $N % 100` - set -e - echo $N_MOD_100 - N=`expr $N + 1` - if [ $N -eq 110 ]; then - break - fi - done - set +e -fi - -( -set -e -false -echo bad -) -echo $? - -x=$( -set -e -false -echo bad -) -echo $? $x - -# command subst should not inherit -e -set -e -echo $(false; echo ok) - -if set +e -then - false -fi -echo hi - -set -e - -# a failing command in the compound list following a while, until, or -# if should not cause the shell to exit - -while false; do - echo hi -done -echo while succeeded - -x=1 -until (( x == 4 )); do - x=4 -done -echo until succeeded: $x - -if false; then - echo oops -fi -echo if succeeded - -# failing commands that are part of an AND or OR list should not -# cause the shell to exit -false && echo AND list failed -echo AND list succeeded - -false || echo OR list succeeded - -! false -echo ! succeeded - -# make sure eval preserves the state of the -e flag and `!' reserved word -set -e -if eval false; then - echo oops -fi -echo eval succeeded - -! eval false -echo ! eval succeeded -- 1 - -! eval '(exit 5)' -echo ! eval succeeded -- 2 diff --git a/tests/set-e1.sub~ b/tests/set-e1.sub~ deleted file mode 100644 index 9422dcaf2..000000000 --- a/tests/set-e1.sub~ +++ /dev/null @@ -1,45 +0,0 @@ -# subshell failure should cause the shell to exit silently -${THIS_SH} -ce '(exit 17) ; echo "after (exit 17): $?"' - -# pipeline failure should cause shell to exit silently -${THIS_SH} -c 'set -e ; false | echo foo | while read x ; do ( exit 17 ) ; done; echo after pipeline subshell;' - -# should be silent in posix mode -${THIS_SH} -c 'set -o posix; set -e ; z=$(false;echo posix foo) ; echo $z' -# but echo foo in non-posix -${THIS_SH} -c 'set -e ; z=$(false;echo non-posix foo) ; echo $z' - -${THIS_SH} -ce 'x=$(false) ; echo "x=\$(false) does not exit"' - -${THIS_SH} -ce '{ false; echo false in brace group does not exit; }' -echo after brace group failure: $? - -set -e - -! false -echo after negation 1: $? - -! false | false -echo after negation 2: $? - -! true -echo after negation 3: $? - -! (false) -echo after negation 4: $? - -{ false ; echo foo; } | cat -echo after brace pipeline - -false | echo foo | cat -echo after failure 1 - -false | (echo foo; false) | true -echo after failure 2 - -false | echo foo | while read x ; do ( exit 17 ) ; done | true -echo after failure 3 - -# this pipeline failure should cause the shell to exit -false | echo foo | false -echo after failure 4 diff --git a/tests/trap.tests~ b/tests/trap.tests~ deleted file mode 100644 index 9aac72545..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/tests/type.tests~ b/tests/type.tests~ deleted file mode 100644 index 15106f0f3..000000000 --- a/tests/type.tests~ +++ /dev/null @@ -1,89 +0,0 @@ -set +o posix - -hash -r -unalias -a - -# this should echo nothing -type -# this should be a usage error -type -r ${THIS_SH} - -# these should behave identically -type notthere -command -v notthere - -alias m=more - -unset -f func 2>/dev/null -func() { echo this is func; } - -type -t func -type -t while -type -t builtin -type -t /bin/sh -type -t ${THIS_SH} -type -t mv - -type func -# the following two should produce identical output -type while -type -a while -type builtin -type /bin/sh - -command -v func -command -V func -command -v while -command -V while - -# the following two lines should produce the same output -# post-3.0 patch makes command -v silent, as posix specifies -# first test with alias expansion off (should all fail or produce no output) -type -t m -type m -command -v m -alias -p -alias m - -# then test with alias expansion on -shopt -s expand_aliases -type m -type -t m -command -v m -alias -p -alias m - -command -V m -shopt -u expand_aliases - -command -v builtin -command -V builtin -command -v /bin/sh -command -V /bin/sh - -unset -f func -type func -unalias m -type m - -hash -r - -hash -p /bin/sh sh -type -p sh - -SHBASE=${THIS_SH##*/} -hash -p /tmp/$SHBASE $SHBASE -type -p $SHBASE -type $SHBASE - -type -t $SHBASE - -# make sure the hash table looks right -hash - -# bug in versions of bash up to and including bash-3.2 -f() { - v=$'\001' - } - -type f | cat -v diff --git a/trap.c~ b/trap.c~ deleted file mode 100644 index c039d0466..000000000 --- a/trap.c~ +++ /dev/null @@ -1,1020 +0,0 @@ -/* trap.c -- Not the trap command, but useful functions for manipulating - those objects. The trap command is in builtins/trap.def. */ - -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include "config.h" - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include "bashtypes.h" -#include "bashansi.h" - -#include -#include - -#include "bashintl.h" - -#include "trap.h" - -#include "shell.h" -#include "flags.h" -#include "input.h" /* for save_token_state, restore_token_state */ -#include "jobs.h" -#include "signames.h" -#include "builtins.h" -#include "builtins/common.h" -#include "builtins/builtext.h" - -#ifndef errno -extern int errno; -#endif - -/* Flags which describe the current handling state of a signal. */ -#define SIG_INHERITED 0x0 /* Value inherited from parent. */ -#define SIG_TRAPPED 0x1 /* Currently trapped. */ -#define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */ -#define SIG_SPECIAL 0x4 /* Treat this signal specially. */ -#define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */ -#define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */ -#define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */ -#define SIG_IGNORED 0x40 /* The signal is currently being ignored. */ - -#define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP) - -/* An array of such flags, one for each signal, describing what the - shell will do with a signal. DEBUG_TRAP == NSIG; some code below - assumes this. */ -static int sigmodes[BASH_NSIG]; - -static void free_trap_command __P((int)); -static void change_signal __P((int, char *)); - -static void get_original_signal __P((int)); - -static int _run_trap_internal __P((int, char *)); - -static void reset_signal __P((int)); -static void restore_signal __P((int)); -static void reset_or_restore_signal_handlers __P((sh_resetsig_func_t *)); - -/* Variables used here but defined in other files. */ -extern int last_command_exit_value; -extern int line_number; - -extern char *this_command_name; -extern sh_builtin_func_t *this_shell_builtin; -extern procenv_t wait_intr_buf; -extern int return_catch_flag, return_catch_value; -extern int subshell_level; - -/* The list of things to do originally, before we started trapping. */ -SigHandler *original_signals[NSIG]; - -/* For each signal, a slot for a string, which is a command to be - executed when that signal is recieved. The slot can also contain - DEFAULT_SIG, which means do whatever you were going to do before - you were so rudely interrupted, or IGNORE_SIG, which says ignore - this signal. */ -char *trap_list[BASH_NSIG]; - -/* A bitmap of signals received for which we have trap handlers. */ -int pending_traps[NSIG]; - -/* Set to the number of the signal we're running the trap for + 1. - Used in execute_cmd.c and builtins/common.c to clean up when - parse_and_execute does not return normally after executing the - trap command (e.g., when `return' is executed in the trap command). */ -int running_trap; - -/* Set to last_command_exit_value before running a trap. */ -int trap_saved_exit_value; - -/* The (trapped) signal received while executing in the `wait' builtin */ -int wait_signal_received; - -/* A value which can never be the target of a trap handler. */ -#define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps - -#define GETORIGSIG(sig) \ - do { \ - original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \ - set_signal_handler (sig, original_signals[sig]); \ - if (original_signals[sig] == SIG_IGN) \ - sigmodes[sig] |= SIG_HARD_IGNORE; \ - } while (0) - -#define GET_ORIGINAL_SIGNAL(sig) \ - if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \ - GETORIGSIG(sig) - -void -initialize_traps () -{ - register int i; - - initialize_signames(); - - trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL; - sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = sigmodes[ERROR_TRAP] = sigmodes[RETURN_TRAP] = SIG_INHERITED; - original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER; - - for (i = 1; i < NSIG; i++) - { - pending_traps[i] = 0; - trap_list[i] = (char *)DEFAULT_SIG; - sigmodes[i] = SIG_INHERITED; - original_signals[i] = IMPOSSIBLE_TRAP_HANDLER; - } - - /* Show which signals are treated specially by the shell. */ -#if defined (SIGCHLD) - GETORIGSIG (SIGCHLD); - sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP); -#endif /* SIGCHLD */ - - GETORIGSIG (SIGINT); - sigmodes[SIGINT] |= SIG_SPECIAL; - -#if defined (__BEOS__) - /* BeOS sets SIGINT to SIG_IGN! */ - original_signals[SIGINT] = SIG_DFL; - sigmodes[SIGINT] &= ~SIG_HARD_IGNORE; -#endif - - GETORIGSIG (SIGQUIT); - sigmodes[SIGQUIT] |= SIG_SPECIAL; - - if (interactive) - { - GETORIGSIG (SIGTERM); - sigmodes[SIGTERM] |= SIG_SPECIAL; - } -} - -#ifdef INCLUDE_UNUSED -/* Return a printable representation of the trap handler for SIG. */ -static char * -trap_handler_string (sig) - int sig; -{ - if (trap_list[sig] == (char *)DEFAULT_SIG) - return "DEFAULT_SIG"; - else if (trap_list[sig] == (char *)IGNORE_SIG) - return "IGNORE_SIG"; - else if (trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER) - return "IMPOSSIBLE_TRAP_HANDLER"; - else if (trap_list[sig]) - return trap_list[sig]; - else - return "NULL"; -} -#endif - -/* Return the print name of this signal. */ -char * -signal_name (sig) - int sig; -{ - char *ret; - - /* on cygwin32, signal_names[sig] could be null */ - ret = (sig >= BASH_NSIG || sig < 0 || signal_names[sig] == NULL) - ? _("invalid signal number") - : signal_names[sig]; - - return ret; -} - -/* Turn a string into a signal number, or a number into - a signal number. If STRING is "2", "SIGINT", or "INT", - then (int)2 is returned. Return NO_SIG if STRING doesn't - contain a valid signal descriptor. */ -int -decode_signal (string, flags) - char *string; - int flags; -{ - intmax_t sig; - char *name; - - if (legal_number (string, &sig)) - return ((sig >= 0 && sig < NSIG) ? (int)sig : NO_SIG); - - /* A leading `SIG' may be omitted. */ - for (sig = 0; sig < BASH_NSIG; sig++) - { - name = signal_names[sig]; - if (name == 0 || name[0] == '\0') - continue; - - /* Check name without the SIG prefix first case sensitivly or - insensitively depending on whether flags includes DSIG_NOCASE */ - if (STREQN (name, "SIG", 3)) - { - name += 3; - - if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0) - return ((int)sig); - else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0) - return ((int)sig); - /* If we can't use the `SIG' prefix to match, punt on this - name now. */ - else if ((flags & DSIG_SIGPREFIX) == 0) - continue; - } - - /* Check name with SIG prefix case sensitively or insensitively - depending on whether flags includes DSIG_NOCASE */ - name = signal_names[sig]; - if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0) - return ((int)sig); - else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0) - return ((int)sig); - } - - return (NO_SIG); -} - -/* Non-zero when we catch a trapped signal. */ -static int catch_flag; - -void -run_pending_traps () -{ - register int sig; - int old_exit_value, *token_state; - - if (catch_flag == 0) /* simple optimization */ - return; - - catch_flag = 0; - - /* Preserve $? when running trap. */ - old_exit_value = last_command_exit_value; - - for (sig = 1; sig < NSIG; sig++) - { - /* XXX this could be made into a counter by using - while (pending_traps[sig]--) instead of the if statement. */ - if (pending_traps[sig]) - { -#if defined (HAVE_POSIX_SIGNALS) - sigset_t set, oset; - - sigemptyset (&set); - sigemptyset (&oset); - - sigaddset (&set, sig); - sigprocmask (SIG_BLOCK, &set, &oset); -#else -# if defined (HAVE_BSD_SIGNALS) - int oldmask = sigblock (sigmask (sig)); -# endif -#endif /* HAVE_POSIX_SIGNALS */ - - if (sig == SIGINT) - { - run_interrupt_trap (); - CLRINTERRUPT; - } -#if defined (JOB_CONTROL) && defined (SIGCHLD) - else if (sig == SIGCHLD && - trap_list[SIGCHLD] != (char *)IMPOSSIBLE_TRAP_HANDLER && - (sigmodes[SIGCHLD] & SIG_INPROGRESS) == 0) - { - run_sigchld_trap (pending_traps[sig]); /* use as counter */ - } -#endif - else if (trap_list[sig] == (char *)DEFAULT_SIG || - trap_list[sig] == (char *)IGNORE_SIG || - trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER) - { - /* This is possible due to a race condition. Say a bash - process has SIGTERM trapped. A subshell is spawned - using { list; } & and the parent does something and kills - the subshell with SIGTERM. It's possible for the subshell - to set pending_traps[SIGTERM] to 1 before the code in - execute_cmd.c eventually calls restore_original_signals - to reset the SIGTERM signal handler in the subshell. The - next time run_pending_traps is called, pending_traps[SIGTERM] - will be 1, but the trap handler in trap_list[SIGTERM] will - be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG). - Unless we catch this, the subshell will dump core when - trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is - usually 0x0. */ - internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"), - sig, trap_list[sig]); - if (trap_list[sig] == (char *)DEFAULT_SIG) - { - internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig, signal_name (sig)); - kill (getpid (), sig); - } - } - else - { - token_state = save_token_state (); - parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE); - restore_token_state (token_state); - free (token_state); - } - - pending_traps[sig] = 0; - -#if defined (HAVE_POSIX_SIGNALS) - sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); -#else -# if defined (HAVE_BSD_SIGNALS) - sigsetmask (oldmask); -# endif -#endif /* POSIX_VERSION */ - } - } - - last_command_exit_value = old_exit_value; -} - -sighandler -trap_handler (sig) - int sig; -{ - int oerrno; - - if ((sigmodes[sig] & SIG_TRAPPED) == 0) - { -#if defined (DEBUG) - internal_warning ("trap_handler: signal %d: signal not trapped", sig); -#endif - SIGRETURN (0); - } - - if ((sig >= NSIG) || - (trap_list[sig] == (char *)DEFAULT_SIG) || - (trap_list[sig] == (char *)IGNORE_SIG)) - programming_error (_("trap_handler: bad signal %d"), sig); - else - { - oerrno = errno; -#if defined (MUST_REINSTALL_SIGHANDLERS) -# if defined (JOB_CONTROL) && defined (SIGCHLD) - if (sig != SIGCHLD) -# endif /* JOB_CONTROL && SIGCHLD */ - set_signal_handler (sig, trap_handler); -#endif /* MUST_REINSTALL_SIGHANDLERS */ - - catch_flag = 1; - pending_traps[sig]++; - - if (interrupt_immediately && this_shell_builtin && (this_shell_builtin == wait_builtin)) - { - wait_signal_received = sig; - longjmp (wait_intr_buf, 1); - } - - if (interrupt_immediately) - run_pending_traps (); - - errno = oerrno; - } - - SIGRETURN (0); -} - -#if defined (JOB_CONTROL) && defined (SIGCHLD) - -#ifdef INCLUDE_UNUSED -/* Make COMMAND_STRING be executed when SIGCHLD is caught. */ -void -set_sigchld_trap (command_string) - char *command_string; -{ - set_signal (SIGCHLD, command_string); -} -#endif - -/* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD - is not already trapped. IMPOSSIBLE_TRAP_HANDLER is used as a sentinel - to make sure that a SIGCHLD trap handler run via run_sigchld_trap can - reset the disposition to the default and not have the original signal - accidentally restored, undoing the user's command. */ -void -maybe_set_sigchld_trap (command_string) - char *command_string; -{ - if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0 && trap_list[SIGCHLD] == (char *)IMPOSSIBLE_TRAP_HANDLER) - set_signal (SIGCHLD, command_string); -} - -/* Temporarily set the SIGCHLD trap string to IMPOSSIBLE_TRAP_HANDLER. Used - as a sentinel in run_sigchld_trap and maybe_set_sigchld_trap to see whether - or not a SIGCHLD trap handler reset SIGCHLD disposition to the default. */ -void -set_impossible_sigchld_trap () -{ - restore_default_signal (SIGCHLD); - change_signal (SIGCHLD, (char *)IMPOSSIBLE_TRAP_HANDLER); - sigmodes[SIGCHLD] &= ~SIG_TRAPPED; /* maybe_set_sigchld_trap checks this */ -} -#endif /* JOB_CONTROL && SIGCHLD */ - -void -set_debug_trap (command) - char *command; -{ - set_signal (DEBUG_TRAP, command); -} - -void -set_error_trap (command) - char *command; -{ - set_signal (ERROR_TRAP, command); -} - -void -set_return_trap (command) - char *command; -{ - set_signal (RETURN_TRAP, command); -} - -#ifdef INCLUDE_UNUSED -void -set_sigint_trap (command) - char *command; -{ - set_signal (SIGINT, command); -} -#endif - -/* Reset the SIGINT handler so that subshells that are doing `shellsy' - things, like waiting for command substitution or executing commands - in explicit subshells ( ( cmd ) ), can catch interrupts properly. */ -SigHandler * -set_sigint_handler () -{ - if (sigmodes[SIGINT] & SIG_HARD_IGNORE) - return ((SigHandler *)SIG_IGN); - - else if (sigmodes[SIGINT] & SIG_IGNORED) - return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */ - - else if (sigmodes[SIGINT] & SIG_TRAPPED) - return ((SigHandler *)set_signal_handler (SIGINT, trap_handler)); - - /* The signal is not trapped, so set the handler to the shell's special - interrupt handler. */ - else if (interactive) /* XXX - was interactive_shell */ - return (set_signal_handler (SIGINT, sigint_sighandler)); - else - return (set_signal_handler (SIGINT, termsig_sighandler)); -} - -/* Return the correct handler for signal SIG according to the values in - sigmodes[SIG]. */ -SigHandler * -trap_to_sighandler (sig) - int sig; -{ - if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE)) - return (SIG_IGN); - else if (sigmodes[sig] & SIG_TRAPPED) - return (trap_handler); - else - return (SIG_DFL); -} - -/* Set SIG to call STRING as a command. */ -void -set_signal (sig, string) - int sig; - char *string; -{ - if (SPECIAL_TRAP (sig)) - { - change_signal (sig, savestring (string)); - if (sig == EXIT_TRAP && interactive == 0) - initialize_terminating_signals (); - return; - } - - /* A signal ignored on entry to the shell cannot be trapped or reset, but - no error is reported when attempting to do so. -- Posix.2 */ - if (sigmodes[sig] & SIG_HARD_IGNORE) - return; - - /* Make sure we have original_signals[sig] if the signal has not yet - been trapped. */ - if ((sigmodes[sig] & SIG_TRAPPED) == 0) - { - /* If we aren't sure of the original value, check it. */ - if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) - GETORIGSIG (sig); - if (original_signals[sig] == SIG_IGN) - return; - } - - /* Only change the system signal handler if SIG_NO_TRAP is not set. - The trap command string is changed in either case. The shell signal - handlers for SIGINT and SIGCHLD run the user specified traps in an - environment in which it is safe to do so. */ - if ((sigmodes[sig] & SIG_NO_TRAP) == 0) - { - set_signal_handler (sig, SIG_IGN); - change_signal (sig, savestring (string)); - set_signal_handler (sig, trap_handler); - } - else - change_signal (sig, savestring (string)); -} - -static void -free_trap_command (sig) - int sig; -{ - if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] && - (trap_list[sig] != (char *)IGNORE_SIG) && - (trap_list[sig] != (char *)DEFAULT_SIG) && - (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER)) - free (trap_list[sig]); -} - -/* If SIG has a string assigned to it, get rid of it. Then give it - VALUE. */ -static void -change_signal (sig, value) - int sig; - char *value; -{ - if ((sigmodes[sig] & SIG_INPROGRESS) == 0) - free_trap_command (sig); - trap_list[sig] = value; - - sigmodes[sig] |= SIG_TRAPPED; - if (value == (char *)IGNORE_SIG) - sigmodes[sig] |= SIG_IGNORED; - else - sigmodes[sig] &= ~SIG_IGNORED; - if (sigmodes[sig] & SIG_INPROGRESS) - sigmodes[sig] |= SIG_CHANGED; -} - -static void -get_original_signal (sig) - int sig; -{ - /* If we aren't sure the of the original value, then get it. */ - if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER) - GETORIGSIG (sig); -} - -/* Restore the default action for SIG; i.e., the action the shell - would have taken before you used the trap command. This is called - from trap_builtin (), which takes care to restore the handlers for - the signals the shell treats specially. */ -void -restore_default_signal (sig) - int sig; -{ - if (SPECIAL_TRAP (sig)) - { - if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) || - (sigmodes[sig] & SIG_INPROGRESS) == 0) - free_trap_command (sig); - trap_list[sig] = (char *)NULL; - sigmodes[sig] &= ~SIG_TRAPPED; - if (sigmodes[sig] & SIG_INPROGRESS) - sigmodes[sig] |= SIG_CHANGED; - return; - } - - GET_ORIGINAL_SIGNAL (sig); - - /* A signal ignored on entry to the shell cannot be trapped or reset, but - no error is reported when attempting to do so. Thanks Posix.2. */ - if (sigmodes[sig] & SIG_HARD_IGNORE) - return; - - /* If we aren't trapping this signal, don't bother doing anything else. */ - if ((sigmodes[sig] & SIG_TRAPPED) == 0) - return; - - /* Only change the signal handler for SIG if it allows it. */ - if ((sigmodes[sig] & SIG_NO_TRAP) == 0) - set_signal_handler (sig, original_signals[sig]); - - /* Change the trap command in either case. */ - change_signal (sig, (char *)DEFAULT_SIG); - - /* Mark the signal as no longer trapped. */ - sigmodes[sig] &= ~SIG_TRAPPED; -} - -/* Make this signal be ignored. */ -void -ignore_signal (sig) - int sig; -{ - if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0)) - { - change_signal (sig, (char *)IGNORE_SIG); - return; - } - - GET_ORIGINAL_SIGNAL (sig); - - /* A signal ignored on entry to the shell cannot be trapped or reset. - No error is reported when the user attempts to do so. */ - if (sigmodes[sig] & SIG_HARD_IGNORE) - return; - - /* If already trapped and ignored, no change necessary. */ - if (sigmodes[sig] & SIG_IGNORED) - return; - - /* Only change the signal handler for SIG if it allows it. */ - if ((sigmodes[sig] & SIG_NO_TRAP) == 0) - set_signal_handler (sig, SIG_IGN); - - /* Change the trap command in either case. */ - change_signal (sig, (char *)IGNORE_SIG); -} - -/* Handle the calling of "trap 0". The only sticky situation is when - the command to be executed includes an "exit". This is why we have - to provide our own place for top_level to jump to. */ -int -run_exit_trap () -{ - char *trap_command; - int code, function_code, retval; - - trap_saved_exit_value = last_command_exit_value; - function_code = 0; - - /* Run the trap only if signal 0 is trapped and not ignored, and we are not - currently running in the trap handler (call to exit in the list of - commands given to trap 0). */ - if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) && - (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0) - { - trap_command = savestring (trap_list[EXIT_TRAP]); - sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; - sigmodes[EXIT_TRAP] |= SIG_INPROGRESS; - - retval = trap_saved_exit_value; - running_trap = 1; - - code = setjmp (top_level); - - /* If we're in a function, make sure return longjmps come here, too. */ - if (return_catch_flag) - function_code = setjmp (return_catch); - - if (code == 0 && function_code == 0) - { - reset_parser (); - parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE); - } - else if (code == ERREXIT) - retval = last_command_exit_value; - else if (code == EXITPROG) - retval = last_command_exit_value; - else if (function_code != 0) - retval = return_catch_value; - else - retval = trap_saved_exit_value; - - running_trap = 0; - return retval; - } - - return (trap_saved_exit_value); -} - -void -run_trap_cleanup (sig) - int sig; -{ - sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED); -} - -/* Run a trap command for SIG. SIG is one of the signals the shell treats - specially. Returns the exit status of the executed trap command list. */ -static int -_run_trap_internal (sig, tag) - int sig; - char *tag; -{ - char *trap_command, *old_trap; - int trap_exit_value, *token_state; - int save_return_catch_flag, function_code, flags; - procenv_t save_return_catch; - - trap_exit_value = function_code = 0; - /* Run the trap only if SIG is trapped and not ignored, and we are not - currently executing in the trap handler. */ - if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) && - (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) && - ((sigmodes[sig] & SIG_INPROGRESS) == 0)) - { - old_trap = trap_list[sig]; - sigmodes[sig] |= SIG_INPROGRESS; - sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */ - trap_command = savestring (old_trap); - - running_trap = sig + 1; - trap_saved_exit_value = last_command_exit_value; - - token_state = save_token_state (); - - /* If we're in a function, make sure return longjmps come here, too. */ - save_return_catch_flag = return_catch_flag; - if (return_catch_flag) - { - COPY_PROCENV (return_catch, save_return_catch); - function_code = setjmp (return_catch); - } - - flags = SEVAL_NONINT|SEVAL_NOHIST; - if (sig != DEBUG_TRAP) - flags |= SEVAL_RESETLINE; - if (function_code == 0) - parse_and_execute (trap_command, tag, flags); - - restore_token_state (token_state); - free (token_state); - - trap_exit_value = last_command_exit_value; - last_command_exit_value = trap_saved_exit_value; - running_trap = 0; - - sigmodes[sig] &= ~SIG_INPROGRESS; - - if (sigmodes[sig] & SIG_CHANGED) - { -#if 0 - /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in - the places where they can be changed using unwind-protects. For - example, look at execute_cmd.c:execute_function(). */ - if (SPECIAL_TRAP (sig) == 0) -#endif - free (old_trap); - sigmodes[sig] &= ~SIG_CHANGED; - } - - if (save_return_catch_flag) - { - return_catch_flag = save_return_catch_flag; - return_catch_value = trap_exit_value; - COPY_PROCENV (save_return_catch, return_catch); - if (function_code) - longjmp (return_catch, 1); - } - } - - return trap_exit_value; -} - -int -run_debug_trap () -{ - int trap_exit_value; - - /* XXX - question: should the DEBUG trap inherit the RETURN trap? */ - trap_exit_value = 0; - if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0)) - { - trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap"); - -#if defined (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'. */ - if (debugging_mode && trap_exit_value == 2 && return_catch_flag) - { - return_catch_value = trap_exit_value; - longjmp (return_catch, 1); - } -#endif - } - return trap_exit_value; -} - -void -run_error_trap () -{ - if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0) - _run_trap_internal (ERROR_TRAP, "error trap"); -} - -void -run_return_trap () -{ - int old_exit_value; - -#if 0 - if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS)) - return; -#endif - - if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0) - { - old_exit_value = last_command_exit_value; - _run_trap_internal (RETURN_TRAP, "return trap"); - last_command_exit_value = old_exit_value; - } -} - -/* Run a trap set on SIGINT. This is called from throw_to_top_level (), and - declared here to localize the trap functions. */ -void -run_interrupt_trap () -{ - _run_trap_internal (SIGINT, "interrupt trap"); -} - -#ifdef INCLUDE_UNUSED -/* Free all the allocated strings in the list of traps and reset the trap - values to the default. */ -void -free_trap_strings () -{ - register int i; - - for (i = 0; i < BASH_NSIG; i++) - { - free_trap_command (i); - trap_list[i] = (char *)DEFAULT_SIG; - sigmodes[i] &= ~SIG_TRAPPED; - } - trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL; -} -#endif - -/* Reset the handler for SIG to the original value. */ -static void -reset_signal (sig) - int sig; -{ - set_signal_handler (sig, original_signals[sig]); - sigmodes[sig] &= ~SIG_TRAPPED; -} - -/* Set the handler signal SIG to the original and free any trap - command associated with it. */ -static void -restore_signal (sig) - int sig; -{ - set_signal_handler (sig, original_signals[sig]); - change_signal (sig, (char *)DEFAULT_SIG); - sigmodes[sig] &= ~SIG_TRAPPED; -} - -static void -reset_or_restore_signal_handlers (reset) - sh_resetsig_func_t *reset; -{ - register int i; - - /* Take care of the exit trap first */ - if (sigmodes[EXIT_TRAP] & SIG_TRAPPED) - { - sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; - if (reset != reset_signal) - { - free_trap_command (EXIT_TRAP); - trap_list[EXIT_TRAP] = (char *)NULL; - } - } - - for (i = 1; i < NSIG; i++) - { - if (sigmodes[i] & SIG_TRAPPED) - { - if (trap_list[i] == (char *)IGNORE_SIG) - set_signal_handler (i, SIG_IGN); - else - (*reset) (i); - } - else if (sigmodes[i] & SIG_SPECIAL) - (*reset) (i); - } - - /* Command substitution and other child processes don't inherit the - debug, error, or return traps. If we're in the debugger, and the - `functrace' or `errtrace' options have been set, then let command - substitutions inherit them. Let command substitution inherit the - RETURN trap if we're in the debugger and tracing functions. */ - if (function_trace_mode == 0) - { - sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED; - sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED; - } - if (error_trace_mode == 0) - sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED; -} - -/* Reset trapped signals to their original values, but don't free the - trap strings. Called by the command substitution code. */ -void -reset_signal_handlers () -{ - reset_or_restore_signal_handlers (reset_signal); -} - -/* Reset all trapped signals to their original values. Signals set to be - ignored with trap '' SIGNAL should be ignored, so we make sure that they - are. Called by child processes after they are forked. */ -void -restore_original_signals () -{ - reset_or_restore_signal_handlers (restore_signal); -} - -/* If a trap handler exists for signal SIG, then call it; otherwise just - return failure. */ -int -maybe_call_trap_handler (sig) - int sig; -{ - /* Call the trap handler for SIG if the signal is trapped and not ignored. */ - if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0)) - { - switch (sig) - { - case SIGINT: - run_interrupt_trap (); - break; - case EXIT_TRAP: - run_exit_trap (); - break; - case DEBUG_TRAP: - run_debug_trap (); - break; - case ERROR_TRAP: - run_error_trap (); - break; - default: - trap_handler (sig); - break; - } - return (1); - } - else - return (0); -} - -int -signal_is_trapped (sig) - int sig; -{ - return (sigmodes[sig] & SIG_TRAPPED); -} - -int -signal_is_special (sig) - int sig; -{ - return (sigmodes[sig] & SIG_SPECIAL); -} - -int -signal_is_ignored (sig) - int sig; -{ - return (sigmodes[sig] & SIG_IGNORED); -} - -void -set_signal_ignored (sig) - int sig; -{ - sigmodes[sig] |= SIG_HARD_IGNORE; - original_signals[sig] = SIG_IGN; -} - -int -signal_in_progress (sig) - int sig; -{ - return (sigmodes[sig] & SIG_INPROGRESS); -} diff --git a/variables.c~ b/variables.c~ deleted file mode 100644 index 3b3276cf3..000000000 --- a/variables.c~ +++ /dev/null @@ -1,4604 +0,0 @@ -/* variables.c -- Functions for hacking shell variables. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Bash is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Bash. If not, see . -*/ - -#include "config.h" - -#include "bashtypes.h" -#include "posixstat.h" -#include "posixtime.h" - -#if defined (__QNX__) -# if defined (__QNXNTO__) -# include -# else -# include -# endif /* !__QNXNTO__ */ -#endif /* __QNX__ */ - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#include -#include "chartypes.h" -#if defined (HAVE_PWD_H) -# include -#endif -#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 "alias.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') - -extern char **environ; - -/* 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; -extern int assigning_in_environment; -extern int executing_builtin; - -#if defined (READLINE) -extern int no_line_editing; -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_error; - -/* 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; - -/* 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; - -/* 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; - -#if defined (READLINE) -static int winsize_assignment; /* currently assigning to LINES or COLUMNS */ -static int winsize_assigned; /* assigned to LINES or COLUMNS */ -#endif - -/* Some forward declarations. */ -static void create_variable_tables __P((void)); - -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, char *)); -#if defined (ARRAY_VARS) -static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *)); -#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)); -static SHELL_VAR *init_dynamic_assoc_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, char *)); -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 void seedrand __P((void)); /* seed generator randomly */ -static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_random __P((SHELL_VAR *)); - -static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_lineno __P((SHELL_VAR *)); - -static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_subshell __P((SHELL_VAR *)); - -static SHELL_VAR *get_bashpid __P((SHELL_VAR *)); - -#if defined (HISTORY) -static SHELL_VAR *get_histcmd __P((SHELL_VAR *)); -#endif - -#if defined (READLINE) -static SHELL_VAR *get_comp_wordbreaks __P((SHELL_VAR *)); -static SHELL_VAR *assign_comp_wordbreaks __P((SHELL_VAR *, char *, arrayind_t, char *)); -#endif - -#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS) -static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *get_dirstack __P((SHELL_VAR *)); -#endif - -#if defined (ARRAY_VARS) -static SHELL_VAR *get_groupset __P((SHELL_VAR *)); - -static SHELL_VAR *build_hashcmd __P((SHELL_VAR *)); -static SHELL_VAR *get_hashcmd __P((SHELL_VAR *)); -static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *, char *, arrayind_t, char *)); -static SHELL_VAR *build_aliasvar __P((SHELL_VAR *)); -static SHELL_VAR *get_aliasvar __P((SHELL_VAR *)); -static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *, char *, arrayind_t, char *)); -#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, int)); - -static void dispose_variable_value __P((SHELL_VAR *)); -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 *)); - -static void -create_variable_tables () -{ - 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 -} - -/* 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; - - create_variable_tables (); - - 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] == '[' && string[strlen (string) - 1] == ')') - { - 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 if (legal_identifier (name)) - { - temp_var = bind_variable (name, string, 0); - 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 = set_if_not ("_", 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]; -# if defined (__QNXNTO__) - netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name)); -# else - qnx_nidtostr (getnid (), node_name, sizeof (node_name)); -# endif - temp_var = bind_variable ("NODE", node_name, 0); - 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", 0); - 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) - { - temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60"); - VSETATTR (temp_var, att_integer); - } - - /* Do some things with shell level. */ - initialize_shell_level (); - - set_ppid (); - - /* Initialize the `getopts' stuff. */ - temp_var = bind_variable ("OPTIND", "1", 0); - VSETATTR (temp_var, att_integer); - getopts_reset (0); - bind_variable ("OPTERR", "1", 0); - sh_opterr = 1; - - if (login_shell == 1 && posixly_correct == 0) - 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, 0); - 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 (), 0); -#if defined (ARRAY_VARS) - make_vers_array (); -#endif - - if (command_execution_string) - bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0); - - /* 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); - -#if 0 - set_if_not ("HISTSIZE", "500"); - sv_histsize ("HISTSIZE"); -#endif - } -#endif /* HISTORY */ - - /* Seed the random number generator. */ - seedrand (); - - /* 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"); - sv_histtimefmt ("HISTTIMEFORMAT"); - } -#endif /* HISTORY */ - -#if defined (READLINE) && defined (STRICT_POSIX) - /* POSIXLY_CORRECT will only be 1 here if the shell was compiled - -DSTRICT_POSIX */ - if (interactive_shell && posixly_correct && no_line_editing == 0) - rl_prefer_env_winsize = 1; -#endif /* READLINE && STRICT_POSIX */ - - /* - * 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 (), 0); -#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, 0); - } -#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, 0); - 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, 0); - set_auto_export (temp_var); - } - else - { - temp_string = get_working_directory ("shell-init"); - if (temp_string) - { - temp_var = bind_variable ("PWD", temp_string, 0); - 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, 0); - 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, 0); - 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, 0); - 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, 0); - 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; - -#if defined (READLINE) - /* If we are currently assigning to LINES or COLUMNS, don't do anything. */ - if (winsize_assignment) - return; -#endif - - v = inttostr (lines, val, sizeof (val)); - bind_variable ("LINES", v, 0); - - v = inttostr (cols, val, sizeof (val)); - bind_variable ("COLUMNS", v, 0); -} - -/* **************************************************************** */ -/* */ -/* 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); - else if (assoc_p (var)) - print_assoc_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; -{ - char *x; - - if (function_p (var) && var_isset (var)) - { - x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL); - printf ("%s", x); - } -} - -/* **************************************************************** */ -/* */ -/* 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), 0); \ - 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) - -#define INIT_DYNAMIC_ASSOC_VAR(var, gfunc, afunc) \ - do \ - { \ - v = make_new_assoc_variable (var); \ - v->dynamic_value = gfunc; \ - v->assign_func = afunc; \ - } \ - while (0) - -static SHELL_VAR * -null_assign (self, value, unused, key) - SHELL_VAR *self; - char *value; - arrayind_t unused; - char *key; -{ - return (self); -} - -#if defined (ARRAY_VARS) -static SHELL_VAR * -null_array_assign (self, value, ind, key) - SHELL_VAR *self; - char *value; - arrayind_t ind; - char *key; -{ - 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; -} - -static SHELL_VAR * -init_dynamic_assoc_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_ASSOC_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, key) - SHELL_VAR *self; - char *value; - arrayind_t unused; - char *key; -{ - 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; -static int seeded_subshell = 0; - -/* 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 () -{ -#if 0 - rseed = rseed * 1103515245 + 12345; - return ((unsigned int)((rseed >> 16) & 32767)); /* was % 32768 */ -#else - /* From "Random number generators: good ones are hard to find", - Park and Miller, Communications of the ACM, vol. 31, no. 10, - October 1988, p. 1195. filtered through FreeBSD */ - long h, l; - - if (rseed == 0) - seedrand (); - h = rseed / 127773; - l = rseed % 127773; - rseed = 16807 * l - 2836 * h; -#if 0 - if (rseed < 0) - rseed += 0x7fffffff; -#endif - return ((unsigned int)(rseed & 32767)); /* was % 32768 */ -#endif -} - -/* Set the random number generator seed to SEED. */ -static void -sbrand (seed) - unsigned long seed; -{ - rseed = seed; - last_random_value = 0; -} - -static void -seedrand () -{ - struct timeval tv; - - gettimeofday (&tv, NULL); - sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid ()); -} - -static SHELL_VAR * -assign_random (self, value, unused, key) - SHELL_VAR *self; - char *value; - arrayind_t unused; - char *key; -{ - sbrand (strtoul (value, (char **)NULL, 10)); - if (subshell_environment) - seeded_subshell = getpid (); - return (self); -} - -int -get_random_number () -{ - int rv, pid; - - /* Reset for command and process substitution. */ - pid = getpid (); - if (subshell_environment && seeded_subshell != pid) - { - seedrand (); - seeded_subshell = pid; - } - - 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, key) - SHELL_VAR *var; - char *value; - arrayind_t unused; - char *key; -{ - 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, key) - SHELL_VAR *var; - char *value; - arrayind_t unused; - char *key; -{ - 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_bashpid (var) - SHELL_VAR *var; -{ - int pid; - char *p; - - pid = getpid (); - p = itos (pid); - - FREE (value_cell (var)); - VSETATTR (var, att_integer|att_readonly); - var_setvalue (var, p); - return (var); -} - -static SHELL_VAR * -get_bash_command (var) - SHELL_VAR *var; -{ - char *p; - - if (the_printed_command_except_trap) - p = savestring (the_printed_command_except_trap); - else - { - p = (char *)xmalloc (1); - p[0] = '\0'; - } - 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; -{ - /* 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); - - var_setvalue (var, rl_completer_word_break_characters); - - return (var); -} - -/* When this function returns, rl_completer_word_break_characters points to - malloced memory. */ -static SHELL_VAR * -assign_comp_wordbreaks (self, value, unused, key) - SHELL_VAR *self; - char *value; - arrayind_t unused; - char *key; -{ - 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, key) - SHELL_VAR *self; - char *value; - arrayind_t ind; - char *key; -{ - 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 (0); - 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); -} - -static SHELL_VAR * -build_hashcmd (self) - SHELL_VAR *self; -{ - HASH_TABLE *h; - int i; - char *k, *v; - BUCKET_CONTENTS *item; - - h = assoc_cell (self); - if (h) - assoc_dispose (h); - - if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0) - { - var_setvalue (self, (char *)NULL); - return self; - } - - h = assoc_create (hashed_filenames->nbuckets); - for (i = 0; i < hashed_filenames->nbuckets; i++) - { - for (item = hash_items (i, hashed_filenames); item; item = item->next) - { - k = savestring (item->key); - v = pathdata(item)->path; - assoc_insert (h, k, v); - } - } - - var_setvalue (self, (char *)h); - return self; -} - -static SHELL_VAR * -get_hashcmd (self) - SHELL_VAR *self; -{ - build_hashcmd (self); - return (self); -} - -static SHELL_VAR * -assign_hashcmd (self, value, ind, key) - SHELL_VAR *self; - char *value; - arrayind_t ind; - char *key; -{ - phash_insert (key, value, 0, 0); - return (build_hashcmd (self)); -} - -static SHELL_VAR * -build_aliasvar (self) - SHELL_VAR *self; -{ - HASH_TABLE *h; - int i; - char *k, *v; - BUCKET_CONTENTS *item; - - h = assoc_cell (self); - if (h) - assoc_dispose (h); - - if (aliases == 0 || HASH_ENTRIES (aliases) == 0) - { - var_setvalue (self, (char *)NULL); - return self; - } - - h = assoc_create (aliases->nbuckets); - for (i = 0; i < aliases->nbuckets; i++) - { - for (item = hash_items (i, aliases); item; item = item->next) - { - k = savestring (item->key); - v = ((alias_t *)(item->data))->value; - assoc_insert (h, k, v); - } - } - - var_setvalue (self, (char *)h); - return self; -} - -static SHELL_VAR * -get_aliasvar (self) - SHELL_VAR *self; -{ - build_aliasvar (self); - return (self); -} - -static SHELL_VAR * -assign_aliasvar (self, value, ind, key) - SHELL_VAR *self; - char *value; - arrayind_t ind; - char *key; -{ - add_alias (key, value); - return (build_aliasvar (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); - VSETATTR (v, att_integer); - INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno); - VSETATTR (v, att_integer); - - INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign); - VSETATTR (v, att_integer|att_readonly); - -#if defined (HISTORY) - INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL); - VSETATTR (v, att_integer); -#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_noassign|att_nounset); - v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset); -# endif /* DEBUGGER */ - v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset); - v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset); - - v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree); - v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree); -#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 && (assigning_in_environment || executing_builtin)))); -} - -/* 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; -{ -#if defined (DEBUGGER) - return ((FUNCTION_DEF *)hash_lookup (name, shell_function_defs)); -#else - return ((FUNCTION_DEF *)0); -#endif -} - -/* 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)); - else if (assoc_p (var)) - return (assoc_reference (assoc_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; - - if (shell_variables == 0) - create_variable_tables (); - - v = find_variable (name); - if (v == 0) - v = bind_variable_internal (name, value, global_variables->table, HASH_NOSRCH, 0); - 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) - { - VUNSETATTR (old_var, att_invisible); - 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 = make_new_variable (name, vc->table); - 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); -} - -/* 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) - create_variable_tables (); - - 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; -} - -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 (); - - dispose_variable_value (var); - var_setarray (var, array); - VSETATTR (var, att_array); - return var; -} - -SHELL_VAR * -make_new_assoc_variable (name) - char *name; -{ - SHELL_VAR *entry; - HASH_TABLE *hash; - - entry = make_new_variable (name, global_variables->table); - hash = assoc_create (0); - - var_setassoc (entry, hash); - VSETATTR (entry, att_assoc); - return entry; -} - -SHELL_VAR * -make_local_assoc_variable (name) - char *name; -{ - SHELL_VAR *var; - HASH_TABLE *hash; - - var = make_local_variable (name); - if (var == 0 || assoc_p (var)) - return var; - - dispose_variable_value (var); - hash = assoc_create (0); - - var_setassoc (var, hash); - VSETATTR (var, att_assoc); - return var; -} -#endif - -char * -make_variable_value (var, value, flags) - SHELL_VAR *var; - char *value; - int flags; -{ - char *retval, *oval; - intmax_t lval, rval; - int expok, olen, op; - - /* 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)) - { - if (flags & ASS_APPEND) - { - oval = value_cell (var); - lval = evalexp (oval, &expok); /* ksh93 seems to do this */ - if (expok == 0) - { - top_level_cleanup (); - jump_to_top_level (DISCARD); - } - } - rval = evalexp (value, &expok); - if (expok == 0) - { - top_level_cleanup (); - jump_to_top_level (DISCARD); - } - if (flags & ASS_APPEND) - rval += lval; - retval = itos (rval); - } -#if defined (CASEMOD_ATTRS) - else if (capcase_p (var) || uppercase_p (var) || lowercase_p (var)) - { - if (flags & ASS_APPEND) - { - oval = get_variable_value (var); - if (oval == 0) /* paranoia */ - oval = ""; - olen = STRLEN (oval); - retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); - strcpy (retval, oval); - if (value) - strcpy (retval+olen, value); - } - else if (*value) - retval = savestring (value); - else - { - retval = (char *)xmalloc (1); - retval[0] = '\0'; - } - op = capcase_p (var) ? CASE_CAPITALIZE - : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER); - oval = sh_modcase (retval, (char *)0, op); - free (retval); - retval = oval; - } -#endif /* CASEMOD_ATTRS */ - else if (value) - { - if (flags & ASS_APPEND) - { - oval = get_variable_value (var); - if (oval == 0) /* paranoia */ - oval = ""; - olen = STRLEN (oval); - retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1); - strcpy (retval, oval); - if (value) - strcpy (retval+olen, value); - } - else 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, aflags) - const char *name; - char *value; - HASH_TABLE *table; - int hflags, aflags; -{ - 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, 0)); /* XXX */ - } - else if (entry->assign_func) /* array vars have assign functions now */ - { - INVALIDATE_EXPORTSTR (entry); - newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : value; - entry = (*(entry->assign_func)) (entry, newval, -1, 0); - if (newval != value) - free (newval); - return (entry); - } - 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, aflags); /* XXX */ - - /* 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 if (assoc_p (entry)) - { - assoc_insert (assoc_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, flags) - const char *name; - char *value; - int flags; -{ - SHELL_VAR *v; - VAR_CONTEXT *vc; - - if (shell_variables == 0) - create_variable_tables (); - - /* 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, flags)); - } - } - return (bind_variable_internal (name, value, global_variables->table, 0, flags)); -} - -/* 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, aflags) - SHELL_VAR *var; - char *value; - int aflags; -{ - char *t; - - VUNSETATTR (var, att_invisible); - - if (var->assign_func) - { - /* If we're appending, we need the old value, so use - make_variable_value */ - t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value; - (*(var->assign_func)) (var, t, -1, 0); - if (t != value && t) - free (t); - } - else - { - t = make_variable_value (var, value, aflags); - 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; - int isint, isarr; - - isint = isarr = 0; -#if defined (ARRAY_VARS) - if (valid_array_reference (lhs)) - { - 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, 0); - else -#endif - v = bind_variable (lhs, rhs, 0); - - 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); -} - -#if defined (DEBUGGER) -/* 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; - } -} -#endif /* DEBUGGER */ - -/* 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 (word) - WORD_DESC *word; -{ - int offset; - char *name, *temp, *value; - SHELL_VAR *var; - const char *string; - - string = word->word; - - offset = assignment (string, 0); - name = savestring (string); - value = (char *)NULL; - - if (name[offset] == '=') - { - name[offset] = 0; - - /* ignore the `+' when assigning temporary environment */ - if (name[offset - 1] == '+') - name[offset - 1] = '\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; - value = expand_assignment_string_to_string (temp, 0); - } - - 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, array_copy (array_cell (var))); - else if (assoc_p (var)) - var_setassoc (copy, assoc_copy (assoc_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. */ -static void -dispose_variable_value (var) - SHELL_VAR *var; -{ - if (function_p (var)) - dispose_command (function_cell (var)); -#if defined (ARRAY_VARS) - else if (array_p (var)) - array_dispose (array_cell (var)); - else if (assoc_p (var)) - assoc_dispose (assoc_cell (var)); -#endif - else - FREE (value_cell (var)); -} - -void -dispose_variable (var) - SHELL_VAR *var; -{ - if (var == 0) - return; - - if (nofree_p (var) == 0) - dispose_variable_value (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; -} - -#if defined (DEBUGGER) -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; -} -#endif /* DEBUGGER */ - -/* 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) - { - if (nofree_p (old_var)) - var_setvalue (old_var, (char *)NULL); -#if defined (ARRAY_VARS) - else if (array_p (old_var)) - array_dispose (array_cell (old_var)); - else if (assoc_p (old_var)) - assoc_dispose (assoc_cell (old_var)); -#endif - else - FREE (value_cell (old_var)); - /* 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); - 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, "", 0); \ - 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, 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); - maybe_make_export_env (); - } -} - -/* 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 - else if (assoc_p (var)) -# if 0 - value = assoc_to_assignment_string (assoc_cell (var)); -# else - continue; /* XXX associative 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) || assoc_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); \ - environ = export_env; \ - } \ - 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); - environ = export_env; - } - 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, 0); - if (shell_variables == global_variables) - var->attributes &= ~(att_tempvar|att_propagate); - else - shell_variables->flags |= VC_HASTMPVAR; - v->attributes |= var->attributes; - } - else - stupidly_hack_special_variables (var->name); /* XXX */ - - 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. */ - /* XXX - This isn't exactly right, because all tempenv variables have the - export attribute set. */ -#if 0 - if (exported_p (var) || (var->attributes & att_propagate)) -#else - if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate)) -#endif - { - var->attributes &= ~att_tempvar; /* XXX */ - v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); - if (shell_variables == global_variables) - var->attributes &= ~att_propagate; - v->attributes |= var->attributes; - } - else - stupidly_hack_special_variables (var->name); /* XXX */ - - 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 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[] = { -#if defined (READLINE) -# if defined (STRICT_POSIX) - { "COLUMNS", sv_winsize }, -# endif - { "COMP_WORDBREAKS", sv_comp_wordbreaks }, -#endif - - { "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 (__CYGWIN__) - { "HOME", sv_home }, -#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 }, - { "LC_TIME", sv_locale }, - -#if defined (READLINE) && defined (STRICT_POSIX) - { "LINES", sv_winsize }, -#endif - - { "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); -} - -/* Special variables that need hooks to be run when they are unset as part - of shell reinitialization should have their sv_ functions run here. */ -void -reinit_special_variables () -{ -#if defined (READLINE) - sv_comp_wordbreaks ("COMP_WORDBREAKS"); -#endif - sv_globignore ("GLOBIGNORE"); - sv_opterr ("OPTERR"); -} - -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; -{ - if (privileged_mode == 0) - setup_glob_ignore (name); -} - -#if defined (READLINE) -void -sv_comp_wordbreaks (name) - char *name; -{ - SHELL_VAR *sv; - - sv = find_variable (name); - if (sv == 0) - rl_completer_word_break_characters = (char *)NULL; -} - -/* 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; -} - -#if defined (STRICT_POSIX) -/* In strict posix mode, we allow assignments to LINES and COLUMNS (and values - found in the initial environment) to override the terminal size reported by - the kernel. */ -void -sv_winsize (name) - char *name; -{ - SHELL_VAR *v; - intmax_t xd; - int d; - - if (posixly_correct == 0 || interactive_shell == 0 || no_line_editing) - return; - - v = find_variable (name); - if (v == 0 || var_isnull (v)) - rl_reset_screen_size (); - else - { - if (legal_number (value_cell (v), &xd) == 0) - return; - winsize_assignment = winsize_assigned = 1; - d = xd; /* truncate */ - if (name[0] == 'L') /* LINES */ - rl_set_screen_size (d, -1); - else /* COLUMNS */ - rl_set_screen_size (-1, d); - winsize_assignment = 0; - } -} -#endif /* STRICT_POSIX */ -#endif /* READLINE */ - -/* Update the value of HOME in the export environment so tilde expansion will - work on cygwin. */ -#if defined (__CYGWIN__) -sv_home (name) - char *name; -{ - array_needs_making = 1; - maybe_make_export_env (); -} -#endif - -#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; - int hmax; - - temp = get_string_value (name); - - if (temp && *temp) - { - if (legal_number (temp, &num)) - { - hmax = num; - if (name[4] == 'S') - { - stifle_history (hmax); - hmax = where_history (); - if (history_lines_this_session > hmax) - history_lines_this_session = hmax; - } - else - { - history_truncate_file (get_string_value ("HISTFILE"), hmax); - if (hmax <= history_lines_in_file) - history_lines_in_file = hmax; - } - } - } - 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/variables.h~ b/variables.h~ deleted file mode 100644 index 036fe4955..000000000 --- a/variables.h~ +++ /dev/null @@ -1,385 +0,0 @@ -/* variables.h -- data structures for shell variables. */ - -/* Copyright (C) 1987-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 (_VARIABLES_H_) -#define _VARIABLES_H_ - -#include "stdc.h" -#include "array.h" -#include "assoc.h" - -/* Shell variables and functions are stored in hash tables. */ -#include "hashlib.h" - -#include "conftypes.h" - -/* A variable context. */ -typedef struct var_context { - char *name; /* empty or NULL means global context */ - int scope; /* 0 means global context */ - int flags; - struct var_context *up; /* previous function calls */ - struct var_context *down; /* down towards global context */ - HASH_TABLE *table; /* variables at this scope */ -} VAR_CONTEXT; - -/* Flags for var_context->flags */ -#define VC_HASLOCAL 0x01 -#define VC_HASTMPVAR 0x02 -#define VC_FUNCENV 0x04 /* also function if name != NULL */ -#define VC_BLTNENV 0x08 /* builtin_env */ -#define VC_TEMPENV 0x10 /* temporary_env */ - -#define VC_TEMPFLAGS (VC_FUNCENV|VC_BLTNENV|VC_TEMPENV) - -/* Accessing macros */ -#define vc_isfuncenv(vc) (((vc)->flags & VC_FUNCENV) != 0) -#define vc_isbltnenv(vc) (((vc)->flags & VC_BLTNENV) != 0) -#define vc_istempenv(vc) (((vc)->flags & (VC_TEMPFLAGS)) == VC_TEMPENV) - -#define vc_istempscope(vc) (((vc)->flags & (VC_TEMPENV|VC_BLTNENV)) != 0) - -#define vc_haslocals(vc) (((vc)->flags & VC_HASLOCAL) != 0) -#define vc_hastmpvars(vc) (((vc)->flags & VC_HASTMPVAR) != 0) - -/* What a shell variable looks like. */ - -typedef struct variable *sh_var_value_func_t __P((struct variable *)); -typedef struct variable *sh_var_assign_func_t __P((struct variable *, char *, arrayind_t, char *)); - -/* For the future */ -union _value { - char *s; /* string value */ - intmax_t i; /* int value */ - COMMAND *f; /* function */ - ARRAY *a; /* array */ - HASH_TABLE *h; /* associative array */ - double d; /* floating point number */ -#if defined (HAVE_LONG_DOUBLE) - long double ld; /* long double */ -#endif - struct variable *v; /* possible indirect variable use */ - void *opaque; /* opaque data for future use */ -}; - -typedef struct variable { - char *name; /* Symbol that the user types. */ - char *value; /* Value that is returned. */ - char *exportstr; /* String for the environment. */ - sh_var_value_func_t *dynamic_value; /* Function called to return a `dynamic' - value for a variable, like $SECONDS - or $RANDOM. */ - sh_var_assign_func_t *assign_func; /* Function called when this `special - variable' is assigned a value in - bind_variable. */ - int attributes; /* export, readonly, array, invisible... */ - int context; /* Which context this variable belongs to. */ -} SHELL_VAR; - -typedef struct _vlist { - SHELL_VAR **list; - int list_size; /* allocated size */ - int list_len; /* current number of entries */ -} VARLIST; - -/* The various attributes that a given variable can have. */ -/* First, the user-visible attributes */ -#define att_exported 0x0000001 /* export to environment */ -#define att_readonly 0x0000002 /* cannot change */ -#define att_array 0x0000004 /* value is an array */ -#define att_function 0x0000008 /* value is a function */ -#define att_integer 0x0000010 /* internal representation is int */ -#define att_local 0x0000020 /* variable is local to a function */ -#define att_assoc 0x0000040 /* variable is an associative array */ -#define att_trace 0x0000080 /* function is traced with DEBUG trap */ -#define att_uppercase 0x0000100 /* word converted to uppercase on assignment */ -#define att_lowercase 0x0000200 /* word converted to lowercase on assignment */ -#define att_capcase 0x0000400 /* word capitalized on assignment */ - -#define user_attrs (att_exported|att_readonly|att_integer|att_local|att_trace|att_uppercase|att_lowercase|att_capcase) - -#define attmask_user 0x0000fff - -/* Internal attributes used for bookkeeping */ -#define att_invisible 0x0001000 /* cannot see */ -#define att_nounset 0x0002000 /* cannot unset */ -#define att_noassign 0x0004000 /* assignment not allowed */ -#define att_imported 0x0008000 /* came from environment */ -#define att_special 0x0010000 /* requires special handling */ -#define att_nofree 0x0020000 /* do not free value on unset */ - -#define attmask_int 0x00ff000 - -/* Internal attributes used for variable scoping. */ -#define att_tempvar 0x0100000 /* variable came from the temp environment */ -#define att_propagate 0x0200000 /* propagate to previous scope */ - -#define attmask_scope 0x0f00000 - -#define exported_p(var) ((((var)->attributes) & (att_exported))) -#define readonly_p(var) ((((var)->attributes) & (att_readonly))) -#define array_p(var) ((((var)->attributes) & (att_array))) -#define function_p(var) ((((var)->attributes) & (att_function))) -#define integer_p(var) ((((var)->attributes) & (att_integer))) -#define local_p(var) ((((var)->attributes) & (att_local))) -#define assoc_p(var) ((((var)->attributes) & (att_assoc))) -#define trace_p(var) ((((var)->attributes) & (att_trace))) -#define uppercase_p(var) ((((var)->attributes) & (att_uppercase))) -#define lowercase_p(var) ((((var)->attributes) & (att_lowercase))) -#define capcase_p(var) ((((var)->attributes) & (att_capcase))) - -#define invisible_p(var) ((((var)->attributes) & (att_invisible))) -#define non_unsettable_p(var) ((((var)->attributes) & (att_nounset))) -#define noassign_p(var) ((((var)->attributes) & (att_noassign))) -#define imported_p(var) ((((var)->attributes) & (att_imported))) -#define specialvar_p(var) ((((var)->attributes) & (att_special))) -#define nofree_p(var) ((((var)->attributes) & (att_nofree))) - -#define tempvar_p(var) ((((var)->attributes) & (att_tempvar))) - -/* Acessing variable values: rvalues */ -#define value_cell(var) ((var)->value) -#define function_cell(var) (COMMAND *)((var)->value) -#define array_cell(var) (ARRAY *)((var)->value) -#define assoc_cell(var) (HASH_TABLE *)((var)->value) - -#define var_isnull(var) ((var)->value == 0) -#define var_isset(var) ((var)->value != 0) - -/* Assigning variable values: lvalues */ -#define var_setvalue(var, str) ((var)->value = (str)) -#define var_setfunc(var, func) ((var)->value = (char *)(func)) -#define var_setarray(var, arr) ((var)->value = (char *)(arr)) -#define var_setassoc(var, arr) ((var)->value = (char *)(arr)) - -/* Make VAR be auto-exported. */ -#define set_auto_export(var) \ - do { (var)->attributes |= att_exported; array_needs_making = 1; } while (0) - -#define SETVARATTR(var, attr, undo) \ - ((undo == 0) ? ((var)->attributes |= (attr)) \ - : ((var)->attributes &= ~(attr))) - -#define VSETATTR(var, attr) ((var)->attributes |= (attr)) -#define VUNSETATTR(var, attr) ((var)->attributes &= ~(attr)) - -#define VGETFLAGS(var) ((var)->attributes) - -#define VSETFLAGS(var, flags) ((var)->attributes = (flags)) -#define VCLRFLAGS(var) ((var)->attributes = 0) - -/* Macros to perform various operations on `exportstr' member of a SHELL_VAR. */ -#define CLEAR_EXPORTSTR(var) (var)->exportstr = (char *)NULL -#define COPY_EXPORTSTR(var) ((var)->exportstr) ? savestring ((var)->exportstr) : (char *)NULL -#define SET_EXPORTSTR(var, value) (var)->exportstr = (value) -#define SAVE_EXPORTSTR(var, value) (var)->exportstr = (value) ? savestring (value) : (char *)NULL - -#define FREE_EXPORTSTR(var) \ - do { if ((var)->exportstr) free ((var)->exportstr); } while (0) - -#define CACHE_IMPORTSTR(var, value) \ - (var)->exportstr = savestring (value) - -#define INVALIDATE_EXPORTSTR(var) \ - do { \ - if ((var)->exportstr) \ - { \ - free ((var)->exportstr); \ - (var)->exportstr = (char *)NULL; \ - } \ - } while (0) - -/* Stuff for hacking variables. */ -typedef int sh_var_map_func_t __P((SHELL_VAR *)); - -/* Where we keep the variables and functions */ -extern VAR_CONTEXT *global_variables; -extern VAR_CONTEXT *shell_variables; - -extern HASH_TABLE *shell_functions; -extern HASH_TABLE *temporary_env; - -extern int variable_context; -extern char *dollar_vars[]; -extern char **export_env; - -extern void initialize_shell_variables __P((char **, int)); -extern SHELL_VAR *set_if_not __P((char *, char *)); - -extern void sh_set_lines_and_columns __P((int, int)); -extern void set_pwd __P((void)); -extern void set_ppid __P((void)); -extern void make_funcname_visible __P((int)); - -extern SHELL_VAR *var_lookup __P((const char *, VAR_CONTEXT *)); - -extern SHELL_VAR *find_function __P((const char *)); -extern FUNCTION_DEF *find_function_def __P((const char *)); -extern SHELL_VAR *find_variable __P((const char *)); -extern SHELL_VAR *find_variable_internal __P((const char *, int)); -extern SHELL_VAR *find_tempenv_variable __P((const char *)); -extern SHELL_VAR *copy_variable __P((SHELL_VAR *)); -extern SHELL_VAR *make_local_variable __P((const char *)); -extern SHELL_VAR *bind_variable __P((const char *, char *, int)); -extern SHELL_VAR *bind_function __P((const char *, COMMAND *)); - -extern void bind_function_def __P((const char *, FUNCTION_DEF *)); - -extern SHELL_VAR **map_over __P((sh_var_map_func_t *, VAR_CONTEXT *)); -SHELL_VAR **map_over_funcs __P((sh_var_map_func_t *)); - -extern SHELL_VAR **all_shell_variables __P((void)); -extern SHELL_VAR **all_shell_functions __P((void)); -extern SHELL_VAR **all_visible_variables __P((void)); -extern SHELL_VAR **all_visible_functions __P((void)); -extern SHELL_VAR **all_exported_variables __P((void)); -extern SHELL_VAR **local_exported_variables __P((void)); -extern SHELL_VAR **all_local_variables __P((void)); -#if defined (ARRAY_VARS) -extern SHELL_VAR **all_array_variables __P((void)); -#endif -extern char **all_variables_matching_prefix __P((const char *)); - -extern char **make_var_array __P((HASH_TABLE *)); -extern char **add_or_supercede_exported_var __P((char *, int)); - -extern char *get_variable_value __P((SHELL_VAR *)); -extern char *get_string_value __P((const char *)); -extern char *sh_get_env_value __P((const char *)); -extern char *make_variable_value __P((SHELL_VAR *, char *, int)); - -extern SHELL_VAR *bind_variable_value __P((SHELL_VAR *, char *, int)); -extern SHELL_VAR *bind_int_variable __P((char *, char *)); -extern SHELL_VAR *bind_var_to_int __P((char *, intmax_t)); - -extern int assign_in_env __P((WORD_DESC *)); - -extern int unbind_variable __P((const char *)); -extern int unbind_func __P((const char *)); -extern int unbind_function_def __P((const char *)); -extern int makunbound __P((const char *, VAR_CONTEXT *)); -extern int kill_local_variable __P((const char *)); -extern void delete_all_variables __P((HASH_TABLE *)); -extern void delete_all_contexts __P((VAR_CONTEXT *)); - -extern VAR_CONTEXT *new_var_context __P((char *, int)); -extern void dispose_var_context __P((VAR_CONTEXT *)); -extern VAR_CONTEXT *push_var_context __P((char *, int, HASH_TABLE *)); -extern void pop_var_context __P((void)); -extern VAR_CONTEXT *push_scope __P((int, HASH_TABLE *)); -extern void pop_scope __P((int)); - -extern void push_context __P((char *, int, HASH_TABLE *)); -extern void pop_context __P((void)); -extern void push_dollar_vars __P((void)); -extern void pop_dollar_vars __P((void)); -extern void dispose_saved_dollar_vars __P((void)); - -extern void push_args __P((WORD_LIST *)); -extern void pop_args __P((void)); - -extern void adjust_shell_level __P((int)); -extern void non_unsettable __P((char *)); -extern void dispose_variable __P((SHELL_VAR *)); -extern void dispose_used_env_vars __P((void)); -extern void dispose_function_env __P((void)); -extern void dispose_builtin_env __P((void)); -extern void merge_temporary_env __P((void)); -extern void merge_builtin_env __P((void)); -extern void kill_all_local_variables __P((void)); - -extern void set_var_read_only __P((char *)); -extern void set_func_read_only __P((const char *)); -extern void set_var_auto_export __P((char *)); -extern void set_func_auto_export __P((const char *)); - -extern void sort_variables __P((SHELL_VAR **)); - -extern void maybe_make_export_env __P((void)); -extern void update_export_env_inplace __P((char *, int, char *)); -extern void put_command_name_into_env __P((char *)); -extern void put_gnu_argv_flags_into_env __P((intmax_t, char *)); - -extern void print_var_list __P((SHELL_VAR **)); -extern void print_func_list __P((SHELL_VAR **)); -extern void print_assignment __P((SHELL_VAR *)); -extern void print_var_value __P((SHELL_VAR *, int)); -extern void print_var_function __P((SHELL_VAR *)); - -#if defined (ARRAY_VARS) -extern SHELL_VAR *make_new_array_variable __P((char *)); -extern SHELL_VAR *make_local_array_variable __P((char *)); - -extern SHELL_VAR *make_new_assoc_variable __P((char *)); -extern SHELL_VAR *make_local_assoc_variable __P((char *)); - -extern void set_pipestatus_array __P((int *, int)); -#endif - -extern void set_pipestatus_from_exit __P((int)); - -/* The variable in NAME has just had its state changed. Check to see if it - is one of the special ones where something special happens. */ -extern void stupidly_hack_special_variables __P((char *)); - -/* Reinitialize some special variables that have external effects upon unset - when the shell reinitializes itself. */ -extern void reinit_special_variables __P((void)); - -extern int get_random_number __P((void)); - -/* The `special variable' functions that get called when a particular - variable is set. */ -extern void sv_ifs __P((char *)); -extern void sv_path __P((char *)); -extern void sv_mail __P((char *)); -extern void sv_globignore __P((char *)); -extern void sv_ignoreeof __P((char *)); -extern void sv_strict_posix __P((char *)); -extern void sv_optind __P((char *)); -extern void sv_opterr __P((char *)); -extern void sv_locale __P((char *)); - -#if defined (READLINE) -extern void sv_comp_wordbreaks __P((char *)); -extern void sv_terminal __P((char *)); -extern void sv_hostfile __P((char *)); -extern void sv_winsize __P((char *)); -#endif - -#if defined (__CYGWIN__) -extern void sv_home __P((char *)); -#endif - -#if defined (HISTORY) -extern void sv_histsize __P((char *)); -extern void sv_histignore __P((char *)); -extern void sv_history_control __P((char *)); -# if defined (BANG_HISTORY) -extern void sv_histchars __P((char *)); -# endif -extern void sv_histtimefmt __P((char *)); -#endif /* HISTORY */ - -#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) -extern void sv_tz __P((char *)); -#endif - -#endif /* !_VARIABLES_H_ */ diff --git a/version.c~ b/version.c~ deleted file mode 100644 index e8e6d2995..000000000 --- a/version.c~ +++ /dev/null @@ -1,86 +0,0 @@ -/* version.c -- distribution and version numbers. */ - -/* Copyright (C) 1989-2008 Free Software Foundation, Inc. - - This file is part of GNU Bash, the Bourne Again SHell. - - Bash is free software; you can 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 - -#include "stdc.h" - -#include "version.h" -#include "patchlevel.h" -#include "conftypes.h" - -#include "bashintl.h" - -extern char *shell_name; - -/* Defines from version.h */ -const char * const dist_version = DISTVERSION; -const int patch_level = PATCHLEVEL; -const int build_version = BUILDVERSION; -#ifdef RELSTATUS -const char * const release_status = RELSTATUS; -#else -const char * const release_status = (char *)0; -#endif -const char * const sccs_version = SCCSVERSION; - -/* If == 31, shell compatible with bash-3.1, = =32 with bash-3.2, and so on */ -int shell_compatibility_level = DEFAULT_COMPAT_LEVEL; - -/* Functions for getting, setting, and displaying the shell version. */ - -/* Forward declarations so we don't have to include externs.h */ -extern char *shell_version_string __P((void)); -extern void show_shell_version __P((int)); - -/* Give version information about this shell. */ -char * -shell_version_string () -{ - static char tt[32] = { '\0' }; - - if (tt[0] == '\0') - { - if (release_status) -#if defined (HAVE_SNPRINTF) - snprintf (tt, sizeof (tt), "%s.%d(%d)-%s", dist_version, patch_level, build_version, release_status); -#else - sprintf (tt, "%s.%d(%d)-%s", dist_version, patch_level, build_version, release_status); -#endif - else -#if defined (HAVE_SNPRINTF) - snprintf (tt, sizeof (tt), "%s.%d(%d)", dist_version, patch_level, build_version); -#else - sprintf (tt, "%s.%d(%d)", dist_version, patch_level, build_version); -#endif - } - return tt; -} - -void -show_shell_version (extended) - int extended; -{ - printf (_("GNU bash, version %s (%s)\n"), shell_version_string (), MACHTYPE); - if (extended) - printf (_("Copyright (C) 2008 Free Software Foundation, Inc.\n")); -}