diff options
-rw-r--r-- | CHANGES | 383 | ||||
-rw-r--r-- | COMPAT | 14 | ||||
-rw-r--r-- | COPYING | 2 | ||||
-rw-r--r-- | CWRU/PLATFORMS | 2 | ||||
-rw-r--r-- | CWRU/POSIX.NOTES | 39 | ||||
-rw-r--r-- | CWRU/changelog | 2015 | ||||
-rw-r--r-- | INSTALL | 33 | ||||
-rw-r--r-- | MANIFEST | 201 | ||||
-rw-r--r-- | Makefile.in | 121 | ||||
-rw-r--r-- | NEWS | 119 | ||||
-rw-r--r-- | NOTES | 57 | ||||
-rw-r--r-- | aclocal.m4 | 317 | ||||
-rw-r--r-- | alias.c | 9 | ||||
-rw-r--r-- | array.c | 7 | ||||
-rw-r--r-- | bashhist.c | 19 | ||||
-rw-r--r-- | bashline.c | 141 | ||||
-rw-r--r-- | bracecomp.c | 3 | ||||
-rw-r--r-- | braces.c | 3 | ||||
-rw-r--r-- | builtins.h | 3 | ||||
-rw-r--r-- | builtins/Makefile.in | 62 | ||||
-rw-r--r-- | builtins/alias.def | 14 | ||||
-rw-r--r-- | builtins/bashgetopt.c | 2 | ||||
-rw-r--r-- | builtins/bind.def | 62 | ||||
-rw-r--r-- | builtins/break.def | 5 | ||||
-rw-r--r-- | builtins/builtin.def | 3 | ||||
-rw-r--r-- | builtins/cd.def | 37 | ||||
-rw-r--r-- | builtins/command.def | 18 | ||||
-rw-r--r-- | builtins/common.c | 28 | ||||
-rw-r--r-- | builtins/common.h | 98 | ||||
-rw-r--r-- | builtins/declare.def | 15 | ||||
-rw-r--r-- | builtins/enable.def | 3 | ||||
-rw-r--r-- | builtins/eval.def | 5 | ||||
-rw-r--r-- | builtins/evalfile.c | 20 | ||||
-rw-r--r-- | builtins/evalstring.c | 123 | ||||
-rw-r--r-- | builtins/exec.def | 1 | ||||
-rw-r--r-- | builtins/exit.def | 2 | ||||
-rw-r--r-- | builtins/fc.def | 8 | ||||
-rw-r--r-- | builtins/getopt.c | 3 | ||||
-rw-r--r-- | builtins/getopts.def | 3 | ||||
-rw-r--r-- | builtins/hash.def | 26 | ||||
-rw-r--r-- | builtins/help.def | 6 | ||||
-rw-r--r-- | builtins/history.def | 4 | ||||
-rw-r--r-- | builtins/jobs.def | 31 | ||||
-rw-r--r-- | builtins/kill.def | 22 | ||||
-rw-r--r-- | builtins/let.def | 3 | ||||
-rw-r--r-- | builtins/mkbuiltins.c | 38 | ||||
-rw-r--r-- | builtins/printf.def | 693 | ||||
-rw-r--r-- | builtins/psize.c | 5 | ||||
-rwxr-xr-x | builtins/psize.sh | 22 | ||||
-rw-r--r-- | builtins/pushd.def | 36 | ||||
-rw-r--r-- | builtins/read.def | 5 | ||||
-rw-r--r-- | builtins/return.def | 3 | ||||
-rw-r--r-- | builtins/set.def | 96 | ||||
-rw-r--r-- | builtins/setattr.def | 6 | ||||
-rw-r--r-- | builtins/shift.def | 3 | ||||
-rw-r--r-- | builtins/shopt.def | 82 | ||||
-rw-r--r-- | builtins/source.def | 6 | ||||
-rw-r--r-- | builtins/suspend.def | 3 | ||||
-rw-r--r-- | builtins/test.def | 14 | ||||
-rw-r--r-- | builtins/times.def | 5 | ||||
-rw-r--r-- | builtins/trap.def | 3 | ||||
-rw-r--r-- | builtins/type.def | 18 | ||||
-rw-r--r-- | builtins/ulimit.def | 13 | ||||
-rw-r--r-- | builtins/umask.def | 23 | ||||
-rw-r--r-- | builtins/wait.def | 6 | ||||
-rw-r--r-- | command.h | 39 | ||||
-rw-r--r-- | config.h.in | 66 | ||||
-rwxr-xr-x | configure | 1380 | ||||
-rw-r--r-- | configure.in | 132 | ||||
-rw-r--r-- | copy_cmd.c | 61 | ||||
-rw-r--r-- | cross-build/cygwin32.cache | 39 | ||||
-rw-r--r-- | cross-build/win32sig.h | 254 | ||||
-rw-r--r-- | dispose_cmd.c | 52 | ||||
-rw-r--r-- | dispose_cmd.h | 4 | ||||
-rw-r--r-- | doc/FAQ | 131 | ||||
-rw-r--r-- | doc/Makefile.in | 18 | ||||
-rw-r--r-- | doc/bash.1 | 1515 | ||||
-rw-r--r-- | doc/bashref.info | 4226 | ||||
-rw-r--r-- | doc/bashref.texi | 3391 | ||||
-rwxr-xr-x | doc/htmlpost.sh | 19 | ||||
-rw-r--r-- | doc/readline.3 | 127 | ||||
-rw-r--r-- | error.c | 35 | ||||
-rw-r--r-- | error.h | 3 | ||||
-rw-r--r-- | eval.c | 38 | ||||
-rw-r--r-- | examples/functions/basename2 | 43 | ||||
-rw-r--r-- | examples/functions/getoptx.bash | 302 | ||||
-rw-r--r-- | examples/functions/inetaddr | 44 | ||||
-rw-r--r-- | examples/functions/inpath | 5 | ||||
-rw-r--r-- | examples/functions/isnum.bash | 23 | ||||
-rw-r--r-- | examples/functions/isnum2 | 22 | ||||
-rw-r--r-- | examples/functions/jdate.bash | 78 | ||||
-rw-r--r-- | examples/functions/pathfuncs | 48 | ||||
-rw-r--r-- | examples/functions/shcat2 | 19 | ||||
-rw-r--r-- | examples/loadables/Makefile.in (renamed from examples/loadables/Makefile) | 91 | ||||
-rw-r--r-- | examples/loadables/getconf.c | 402 | ||||
-rw-r--r-- | examples/loadables/print.c | 416 | ||||
-rw-r--r-- | examples/loadables/printf.c | 460 | ||||
-rwxr-xr-x | examples/misc/aliasconv.bash (renamed from examples/misc/alias-conv.bash) | 0 | ||||
-rwxr-xr-x | examples/misc/aliasconv.sh (renamed from examples/misc/alias-conv.sh) | 0 | ||||
-rw-r--r-- | examples/scripts.v2/cal2day.bash | 49 | ||||
-rw-r--r-- | examples/scripts/fixfiles.bash | 92 | ||||
-rw-r--r-- | examples/scripts/hanoi.bash | 21 | ||||
-rwxr-xr-x | examples/scripts/krand.bash | 74 | ||||
-rw-r--r-- | examples/scripts/randomcard.bash | 18 | ||||
-rwxr-xr-x | examples/scripts/scrollbar | 10 | ||||
-rwxr-xr-x | examples/scripts/scrollbar2 | 24 | ||||
-rw-r--r-- | examples/scripts/showperm.bash | 53 | ||||
-rw-r--r-- | examples/scripts/timeout | 53 | ||||
-rw-r--r-- | examples/startup-files/Bashrc.bfox (renamed from examples/startup-files/Bashrc) | 0 | ||||
-rw-r--r-- | execute_cmd.c | 1663 | ||||
-rw-r--r-- | execute_cmd.h | 9 | ||||
-rw-r--r-- | expr.c | 41 | ||||
-rw-r--r-- | externs.h | 77 | ||||
-rw-r--r-- | findcmd.c | 580 | ||||
-rw-r--r-- | findcmd.h | 34 | ||||
-rw-r--r-- | flags.c | 13 | ||||
-rw-r--r-- | general.c | 182 | ||||
-rw-r--r-- | general.h | 16 | ||||
-rw-r--r-- | hashcmd.c | 14 | ||||
-rw-r--r-- | hashcmd.h | 2 | ||||
-rw-r--r-- | hashlib.c | 11 | ||||
-rw-r--r-- | input.c | 37 | ||||
-rw-r--r-- | input.h | 11 | ||||
-rw-r--r-- | jobs.c | 177 | ||||
-rw-r--r-- | jobs.h | 6 | ||||
-rw-r--r-- | lib/glob/collsyms.h | 129 | ||||
-rw-r--r-- | lib/glob/fnmatch.c | 816 | ||||
-rw-r--r-- | lib/glob/fnmatch.h | 22 | ||||
-rw-r--r-- | lib/glob/glob.c | 285 | ||||
-rw-r--r-- | lib/glob/glob.h | 1 | ||||
-rw-r--r-- | lib/malloc/getpagesize.h | 7 | ||||
-rw-r--r-- | lib/malloc/gmalloc.c | 1213 | ||||
-rw-r--r-- | lib/malloc/malloc.c | 957 | ||||
-rw-r--r-- | lib/malloc/ogmalloc.c | 1579 | ||||
-rw-r--r-- | lib/malloc/omalloc.c | 759 | ||||
-rw-r--r-- | lib/readline/Makefile.in | 2 | ||||
-rw-r--r-- | lib/readline/bind.c | 291 | ||||
-rw-r--r-- | lib/readline/callback.c | 8 | ||||
-rw-r--r-- | lib/readline/chardefs.h | 15 | ||||
-rw-r--r-- | lib/readline/complete.c | 824 | ||||
-rw-r--r-- | lib/readline/display.c | 4 | ||||
-rw-r--r-- | lib/readline/doc/hist.texinfo | 17 | ||||
-rw-r--r-- | lib/readline/doc/hsuser.texinfo | 122 | ||||
-rw-r--r-- | lib/readline/doc/rlman.texinfo | 17 | ||||
-rw-r--r-- | lib/readline/doc/rltech.texinfo | 10 | ||||
-rw-r--r-- | lib/readline/doc/rluser.texinfo | 247 | ||||
-rw-r--r-- | lib/readline/examples/rltest.c | 23 | ||||
-rw-r--r-- | lib/readline/funmap.c | 4 | ||||
-rw-r--r-- | lib/readline/histexpand.c | 46 | ||||
-rw-r--r-- | lib/readline/histfile.c | 49 | ||||
-rw-r--r-- | lib/readline/history.c | 3 | ||||
-rw-r--r-- | lib/readline/histsearch.c | 3 | ||||
-rw-r--r-- | lib/readline/isearch.c | 17 | ||||
-rw-r--r-- | lib/readline/keymaps.h | 4 | ||||
-rw-r--r-- | lib/readline/kill.c | 98 | ||||
-rw-r--r-- | lib/readline/nls.c | 3 | ||||
-rw-r--r-- | lib/readline/parens.c | 2 | ||||
-rw-r--r-- | lib/readline/readline.c | 18 | ||||
-rw-r--r-- | lib/readline/readline.h | 14 | ||||
-rw-r--r-- | lib/readline/rltty.h | 12 | ||||
-rw-r--r-- | lib/readline/rlwinsize.h | 58 | ||||
-rw-r--r-- | lib/readline/shell.c | 9 | ||||
-rw-r--r-- | lib/readline/terminal.c | 23 | ||||
-rw-r--r-- | lib/readline/tilde.c | 3 | ||||
-rw-r--r-- | lib/readline/util.c | 62 | ||||
-rw-r--r-- | lib/readline/vi_mode.c | 7 | ||||
-rw-r--r-- | lib/sh/Makefile.in | 164 | ||||
-rw-r--r-- | lib/sh/clktck.c | 55 | ||||
-rw-r--r-- | lib/sh/getcwd.c (renamed from getcwd.c) | 25 | ||||
-rw-r--r-- | lib/sh/getenv.c | 99 | ||||
-rw-r--r-- | lib/sh/itos.c | 64 | ||||
-rw-r--r-- | lib/sh/oslib.c (renamed from oslib.c) | 219 | ||||
-rw-r--r-- | lib/sh/setlinebuf.c | 41 | ||||
-rw-r--r-- | lib/sh/strcasecmp.c | 88 | ||||
-rw-r--r-- | lib/sh/strerror.c | 74 | ||||
-rw-r--r-- | lib/sh/strtod.c | 197 | ||||
-rw-r--r-- | lib/sh/strtol.c | 213 | ||||
-rw-r--r-- | lib/sh/strtoul.c | 26 | ||||
-rw-r--r-- | lib/sh/vprint.c (renamed from vprint.c) | 2 | ||||
-rw-r--r-- | lib/termcap/termcap.c | 6 | ||||
-rw-r--r-- | lib/tilde/tilde.c | 3 | ||||
-rw-r--r-- | list.c | 5 | ||||
-rw-r--r-- | mailcheck.c | 13 | ||||
-rw-r--r-- | make_cmd.c | 74 | ||||
-rw-r--r-- | make_cmd.h | 7 | ||||
-rw-r--r-- | nojobs.c | 9 | ||||
-rw-r--r-- | parse.y | 400 | ||||
-rw-r--r-- | parser-built | 43 | ||||
-rw-r--r-- | pathexp.c | 58 | ||||
-rw-r--r-- | pathexp.h | 24 | ||||
-rw-r--r-- | print_cmd.c | 140 | ||||
-rw-r--r-- | redir.c | 828 | ||||
-rw-r--r-- | redir.h | 31 | ||||
-rw-r--r-- | shell.c | 266 | ||||
-rw-r--r-- | sig.c | 9 | ||||
-rw-r--r-- | stringlib.c | 40 | ||||
-rw-r--r-- | subst.c | 3196 | ||||
-rw-r--r-- | subst.h | 35 | ||||
-rw-r--r-- | support/Makefile.in | 58 | ||||
-rw-r--r-- | support/bashbug.sh | 11 | ||||
-rwxr-xr-x | support/config.guess | 260 | ||||
-rwxr-xr-x | support/config.sub | 5 | ||||
-rw-r--r-- | support/man2html.c | 4018 | ||||
-rwxr-xr-x | support/texi2html | 2 | ||||
-rw-r--r-- | test.c | 530 | ||||
-rw-r--r-- | test.h | 40 | ||||
-rw-r--r-- | tests/arith.right | 5 | ||||
-rw-r--r-- | tests/arith.tests | 7 | ||||
-rwxr-xr-x | tests/array-at-star | 120 | ||||
-rw-r--r-- | tests/array.right | 6 | ||||
-rw-r--r-- | tests/array.tests | 21 | ||||
-rw-r--r-- | tests/array2.right | 74 | ||||
-rw-r--r-- | tests/builtins.right | 14 | ||||
-rw-r--r-- | tests/builtins.tests | 80 | ||||
-rw-r--r-- | tests/cond.right | 31 | ||||
-rwxr-xr-x | tests/cond.tests | 142 | ||||
-rw-r--r-- | tests/dirstack.right | 51 | ||||
-rwxr-xr-x | tests/dollar-at-star | 119 | ||||
-rwxr-xr-x | tests/dollar-at.sh | 1 | ||||
-rwxr-xr-x | tests/dollar-star.sh | 9 | ||||
-rw-r--r-- | tests/dollar.right | 68 | ||||
-rw-r--r-- | tests/dstack.right | 55 | ||||
-rw-r--r-- | tests/dstack.tests (renamed from tests/dirstack.tests) | 8 | ||||
-rw-r--r-- | tests/dstack2.right | 24 | ||||
-rw-r--r-- | tests/dstack2.tests | 33 | ||||
-rw-r--r-- | tests/errors.right | 32 | ||||
-rw-r--r-- | tests/errors.tests | 61 | ||||
-rw-r--r-- | tests/exec.right (renamed from tests/execscript.right) | 15 | ||||
-rwxr-xr-x | tests/exec1.sub (renamed from tests/execscript.sub) | 0 | ||||
-rw-r--r-- | tests/exec2.sub (renamed from tests/execscript.sub2) | 0 | ||||
-rw-r--r-- | tests/exec3.sub (renamed from tests/execscript.sub3) | 0 | ||||
-rw-r--r-- | tests/exec4.sub (renamed from tests/execscript.sub4) | 0 | ||||
-rw-r--r-- | tests/exec5.sub | 9 | ||||
-rw-r--r-- | tests/execscript | 21 | ||||
-rw-r--r-- | tests/extglob.right | 59 | ||||
-rw-r--r-- | tests/extglob.tests | 286 | ||||
-rw-r--r-- | tests/getopts.right | 20 | ||||
-rw-r--r-- | tests/getopts.tests | 30 | ||||
-rw-r--r-- | tests/getopts1.sub (renamed from tests/getopts.sub1) | 0 | ||||
-rw-r--r-- | tests/getopts2.sub (renamed from tests/getopts.sub2) | 0 | ||||
-rw-r--r-- | tests/getopts3.sub (renamed from tests/getopts.sub3) | 0 | ||||
-rw-r--r-- | tests/getopts4.sub (renamed from tests/getopts.sub4) | 0 | ||||
-rw-r--r-- | tests/getopts5.sub (renamed from tests/getopts.sub5) | 0 | ||||
-rw-r--r-- | tests/getopts6.sub (renamed from tests/getopts.sub6) | 0 | ||||
-rw-r--r-- | tests/getopts7.sub (renamed from tests/getopts.sub7) | 0 | ||||
-rw-r--r-- | tests/glob-test | 20 | ||||
-rw-r--r-- | tests/glob.right | 36 | ||||
-rw-r--r-- | tests/glob1.sub | 14 | ||||
-rw-r--r-- | tests/histexp.right (renamed from tests/histexpand.right) | 2 | ||||
-rw-r--r-- | tests/histexp.tests (renamed from tests/histexpand.tests) | 10 | ||||
-rw-r--r-- | tests/history.right | 8 | ||||
-rw-r--r-- | tests/history.tests | 14 | ||||
-rw-r--r-- | tests/ifs-1.right (renamed from tests/ifs.1.right) | 0 | ||||
-rw-r--r-- | tests/ifs-1.test (renamed from tests/ifs-test-1.sh) | 0 | ||||
-rw-r--r-- | tests/ifs-2.right (renamed from tests/ifs.2.right) | 0 | ||||
-rw-r--r-- | tests/ifs-2.test (renamed from tests/ifs-test-2.sh) | 0 | ||||
-rw-r--r-- | tests/ifs-3.right (renamed from tests/ifs.3.right) | 0 | ||||
-rw-r--r-- | tests/ifs-3.test (renamed from tests/ifs-test-3.sh) | 0 | ||||
-rw-r--r-- | tests/jobs.right | 44 | ||||
-rw-r--r-- | tests/jobs.tests | 36 | ||||
-rw-r--r-- | tests/jobs1.sub | 17 | ||||
-rw-r--r-- | tests/jobs2.sub | 13 | ||||
-rw-r--r-- | tests/misc/perftest (renamed from tests/misc/haertel.perftest) | 1 | ||||
-rw-r--r-- | tests/misc/redir-t2.sh (renamed from tests/misc/redir.t2.sh) | 0 | ||||
-rwxr-xr-x | tests/misc/run-r2.sh | 1 | ||||
-rwxr-xr-x | tests/misc/run.r2.sh | 1 | ||||
-rwxr-xr-x | tests/misc/sigint-1.sh (renamed from tests/misc/sigint.t1.sh) | 0 | ||||
-rwxr-xr-x | tests/misc/sigint-2.sh (renamed from tests/misc/sigint.t2.sh) | 0 | ||||
-rwxr-xr-x | tests/misc/sigint-3.sh (renamed from tests/misc/sigint.t3.sh) | 0 | ||||
-rwxr-xr-x | tests/misc/sigint-4.sh (renamed from tests/misc/sigint.t4.sh) | 0 | ||||
-rw-r--r-- | tests/more-exp.right | 48 | ||||
-rw-r--r-- | tests/more-exp.tests | 133 | ||||
-rw-r--r-- | tests/new-exp.right | 10 | ||||
-rw-r--r-- | tests/new-exp.tests | 28 | ||||
-rw-r--r-- | tests/new-exp1.sub (renamed from tests/new-exp.sub1) | 0 | ||||
-rw-r--r-- | tests/new-exp2.sub | 36 | ||||
-rw-r--r-- | tests/posix2.tests | 29 | ||||
-rw-r--r-- | tests/posixpat.right | 42 | ||||
-rw-r--r-- | tests/posixpat.tests | 233 | ||||
-rw-r--r-- | tests/printf.right | bin | 0 -> 1179 bytes | |||
-rw-r--r-- | tests/printf.tests | 176 | ||||
-rw-r--r-- | tests/read.right | 5 | ||||
-rw-r--r-- | tests/read.tests | 13 | ||||
-rw-r--r-- | tests/rsh.right | 1 | ||||
-rw-r--r-- | tests/rsh.tests | 1 | ||||
-rw-r--r-- | tests/run-array | 2 | ||||
-rw-r--r-- | tests/run-array2 | 4 | ||||
-rw-r--r-- | tests/run-cond | 7 | ||||
-rw-r--r-- | tests/run-dirstack | 7 | ||||
-rw-r--r-- | tests/run-dollars | 3 | ||||
-rw-r--r-- | tests/run-execscript | 2 | ||||
-rw-r--r-- | tests/run-extglob | 4 | ||||
-rw-r--r-- | tests/run-histexpand | 4 | ||||
-rw-r--r-- | tests/run-ifs-tests | 12 | ||||
-rw-r--r-- | tests/run-minimal | 1 | ||||
-rw-r--r-- | tests/run-new-exp | 5 | ||||
-rw-r--r-- | tests/run-posixpat | 2 | ||||
-rw-r--r-- | tests/run-printf | 2 | ||||
-rw-r--r-- | tests/run-set-e (renamed from tests/run-set-e-test) | 0 | ||||
-rw-r--r-- | tests/run-shopt | 2 | ||||
-rw-r--r-- | tests/run-trap | 4 | ||||
-rw-r--r-- | tests/shopt.right | 189 | ||||
-rw-r--r-- | tests/shopt.tests | 93 | ||||
-rw-r--r-- | tests/source1.sub (renamed from tests/source.sub1) | 0 | ||||
-rw-r--r-- | tests/source2.sub (renamed from tests/source.sub2) | 0 | ||||
-rw-r--r-- | tests/source3.sub (renamed from tests/source.sub3) | 0 | ||||
-rw-r--r-- | tests/source4.sub (renamed from tests/source.sub4) | 0 | ||||
-rw-r--r-- | tests/source5.sub | 19 | ||||
-rw-r--r-- | tests/test-tests | 10 | ||||
-rw-r--r-- | tests/test.right | 4 | ||||
-rw-r--r-- | tests/trap.right | 4 | ||||
-rw-r--r-- | tests/trap.tests | 8 | ||||
-rwxr-xr-x | tests/trap1.sub (renamed from tests/trap.sub1) | 0 | ||||
-rw-r--r-- | tests/type.right | 5 | ||||
-rw-r--r-- | tests/type.tests | 8 | ||||
-rw-r--r-- | tests/varenv.right | 1 | ||||
-rw-r--r-- | tests/varenv.sh | 17 | ||||
-rw-r--r-- | trap.c | 28 | ||||
-rw-r--r-- | variables.c | 492 | ||||
-rw-r--r-- | variables.h | 49 | ||||
-rw-r--r-- | version.c | 2 | ||||
-rw-r--r-- | y.tab.c | 1370 | ||||
-rw-r--r-- | y.tab.h | 43 |
323 files changed, 33727 insertions, 12132 deletions
@@ -1,3 +1,386 @@ +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. 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. @@ -101,3 +101,17 @@ encountered by a significant number of users. 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. @@ -2,7 +2,7 @@ Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. diff --git a/CWRU/PLATFORMS b/CWRU/PLATFORMS index 4d2b4844..f05caff5 100644 --- a/CWRU/PLATFORMS +++ b/CWRU/PLATFORMS @@ -6,7 +6,7 @@ By chet: SunOS 4.1.4 SunOS 5.5 BSDI BSD/OS 2.1 -FreeBSD 2.1.7 +FreeBSD 2.2 NetBSD 1.2 AIX 4.2 AIX 4.1.4 diff --git a/CWRU/POSIX.NOTES b/CWRU/POSIX.NOTES index af3acbcc..f33d1e60 100644 --- a/CWRU/POSIX.NOTES +++ b/CWRU/POSIX.NOTES @@ -21,8 +21,8 @@ The following list is what's changed when `POSIX mode' is in effect: 5. The POSIX.2 `PS1' and `PS2' expansions of `!' to the history number and `!!' to `!' are enabled, and parameter expansion is - performed on the value regardless of the setting of the - `promptvars' option. + performed on the values of `PS1' and `PS2' regardless of the + setting of the `promptvars' option. 6. Interactive comments are enabled by default. (Note that Bash has them on by default anyway.) @@ -42,42 +42,51 @@ The following list is what's changed when `POSIX mode' is in effect: 11. Non-interactive shells exit if FILENAME in `.' FILENAME is not found. - 12. Redirection operators do not perform filename expansion on the word + 12. Non-interactive shells exit if a syntax error in an arithmetic + expansion results in an invalid expression. + + 13. Redirection operators do not perform filename expansion on the word in the redirection unless the shell is interactive. - 13. Function names must be valid shell `name's. That is, they may not + 14. Function names must be valid shell `name's. That is, they may not contain characters other than letters, digits, and underscores, and - may not start with a digit. Declaring a function with an illegal + may not start with a digit. Declaring a function with an invalid name causes a fatal syntax error in non-interactive shells. - 14. POSIX.2 `special' builtins are found before shell functions during + 15. POSIX.2 `special' builtins are found before shell functions during command lookup. - 15. If a POSIX.2 special builtin returns an error status, a + 16. If a POSIX.2 special builtin returns an error status, a non-interactive shell exits. The fatal errors are those listed in the POSIX.2 standard, and include things like passing incorrect options, redirection errors, variable assignment errors for assignments preceding the command name, and so on. - 16. If the `cd' builtin finds a directory to change to using + 17. If the `cd' builtin finds a directory to change to using `$CDPATH', the value it assigns to the `PWD' variable does not contain any symbolic links, as if `cd -P' had been executed. - 17. A non-interactive shell exits with an error status if a variable + 18. If `$CDPATH' is set, the `cd' builtin will not implicitly append + the current directory to it. This means that `cd' will fail if no + valid directory name can be constructed from any of the entries in + `$CDPATH', even if the a directory with the same name as the name + given as an argument to `cd' exists in the current directory. + + 19. 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. + trying to assign a value to a readonly variable. - 18. A non-interactive shell exits with an error status if the iteration + 20. 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. + `select' statement is a readonly variable. - 19. Process substitution is not available. + 21. Process substitution is not available. - 20. Assignment statements preceding POSIX.2 `special' builtins persist + 22. Assignment statements preceding POSIX.2 special builtins persist in the shell environment after the builtin completes. - 21. The `export' and `readonly' builtin commands display their output + 23. The `export' and `readonly' builtin commands display their output in the format required by POSIX.2. diff --git a/CWRU/changelog b/CWRU/changelog index 331c9e60..460f6e63 100644 --- a/CWRU/changelog +++ b/CWRU/changelog @@ -1717,3 +1717,2018 @@ builtins/type.def - free the value returned by find_hashed_filename [bash-2.01-release frozen] + + 6/6 + --- +configure.in + - force shlicc2 and libc malloc for BSD/OS 3.0 + + 6/9 + --- +doc/Makefile.in + - don't create ${man3dir}, since we're not installing the readline + manual page + +lib/readline/readline.h + - rl_dispatching should be declared `extern' + [in bash-2.01.1] + + 6/10 + ---- +lib/malloc/Makefile.in + - make sure ${ALLOCA_SOURCE} is preceded by ${srcdir} so that things + work when building in a directory other than the source directory + [in bash-2.01.1] + + 6/30 + ---- +lib/readline/examples/rltest.c + - don't free the value returned by history_list() + +lib/readline/histfile.c + - open the history file for writing with mode 0600 for better + security + [in bash-2.01.1] + +execute_cmd.c + - select_query now uses legal_number to decide whether the user's + selection is a valid number, and just executes the loop again if + invalid input is entered + [in bash-2.01.1] + + 7/1 + --- +builtins/evalstring.c + - fix to parse_and_execute so `bash -c 'time [-p] zzz'' works right + [in bash-2.01.1] + +execute_cmd.c + - fix to execute_command_internal so that `bash -c time [-p] (zzz)'' + works right + [in bash-2.01.1] + - print_formatted_time should pass a long as the fourth parameter + to mkfmt + [in bash-2.01.1] + +externs.h, shell.c + - `exit_shell' is now a void function + +hashlib.c + - print_table_stats is now a void function + +mailcheck.c + - made add_mail_file check for the filename in the mail file list + using the expanded filename, since that is what it puts into + the list + [in bash-2.01.1] + +variables.c + - for the time being, PWD will be auto-exported, since some systems + seem to expect it + +doc/bashref.texi, lib/readline/doc/{hist,rlman}.texinfo + - added necessary `dircategory' and `direntry' commands to make + `install-info' work correctly + +Makefile.in + - move $(LDFLAGS) after $(BUILTINS_LDFLAGS) and $(LIBRARY_LDFLAGS) on + the line that links bash + +doc/texinfo.tex + - upgraded to version 2.185 from the texinfo-3.9 distribution + +lib/tilde/tilde.c + - fixed a bug in tilde_expand so that enough space is allocated for + the string and terminating null byte if a `~' does not appear. + This was masked before by the bash malloc() + [in bash-2.01.1] + + 7/3 + --- +aclocal.m4 + - new test, BASH_TYPE_INT32_T, to check which builtin C type is + 32 bits wide + - new test, BASH_TYPE_PTRDIFF_T, to check which builtin C type is + appropriate for pointer arithmetic + +configure.in + - check sizes of int and long, and for the existence of an int32_t + basic system type. Call BASH_TYPE_INT32_T if int32_t is not + defined anywhere in the system header files + - check size of (char *), and for the existence of a ptrdiff_t + basic system type. Call BASH_TYPE_PTRDIFF_T if ptrdiff_t is not + defined anywhere in the system header files + - added a check for <stddef.h> + +config.h.in + - add lines for SIZEOF_INT, SIZEOF_LONG, SIZEOF_CHAR_P, int32_t, + u_int32_t, and ptrdiff_t + - added line for HAVE_STDDEF_H + +lib/malloc/malloc.c + - new version, with many changes and much better memory usage; old + (bash-2.01) version is lib/malloc/omalloc.c + +lib/malloc/gmalloc.c + - new version, with a number of changes and range checking included + by default; old (bash-2.01) version is lib/malloc/ogmalloc.c + +execute_cmd.c + - applied patch from 5/27 to make execute_simple_command fork early + if it's part of a pipeline. This keeps assignment statements or + other commands that don't require a builtin, function, or disk + command to be executed from modifying the shell's environment + +tests/exec?.sub + - renamed from tests/execscript.sub? because those filenames are + too long for System V 14-char filename systems + +tests/source?.sub + - renamed from tests/source.sub? because those filenames are bad + for DOS/Windows + +tests/getopts?.sub + - renamed from tests/getopts.sub? because those filenames are bad + for DOS/Windows + +tests/histexp.{tests,right} + - renamed from histexpand.{tests,right} because those filenames are + too long for System V 14-char filename systems + +tests/trap1.sub + - renamed from trap.sub1 because that filename was bad for DOS/Windows + +tests/ifs-[123].right + - renamed from ifs.[123].right because those filenames were bad for + DOS/Windows + +tests/ifs-[123].test + - renamed from ifs-test-[123].sh because those filenames were bad + for DOS/Windows + +examples/startup-files/Bashrc.bfox + - renamed from examples/startup-files/Bashrc because that filename + conflicts with examples/startup-files/bashrc on case-insensitive + file systems + +tests/exec.right + - renamed from execscript.right because that filename is too long + for System V 14-char filename systems + +tests/run-set-e + - renamed from run-set-e-test + +tests/misc/perftest + - renamed from tests/misc/haertel.perftest because that filename is + too long for System V 14-char filename systems + +lib/glob/fnmatch.c + - new version with full POSIX.2 BRE matching (character classes, + collating symbols, equivalence classes), full support for + strcoll(3), and case-insensitive pattern matching + +lib/glob/fnmatch.h + - new version, with necessary symbols for the new fnmatch.c + +tests/posixpat.{tests,right}, tests/run-posixpat + - test suite for the POSIX.2 BRE pattern matching code + +variables.c + - make sure that array assignment using the compound syntax empties + the array before doing the assignment + [in bash-2.01.1] + +trap.c + - new function, trap_to_sighandler(sig), which returns the correct + trap handler for SIG depending on the information in sigmodes[sig] + [in bash-2.01.1] + +sig.h + - extern declarations for trap_handler and trap_to_sighandler + [in bash-2.01.1] + +jobs.c + - if we get an interrupt while waiting for a command to complete, + and there was a trap set on SIGINT that resets the handler to + SIG_DFL, the value that waitchld uses for old_trap_handler will + be wrong (it will be trap_handler, but trap_handler no longer + knows anything about SIGINT). If old_signal_handler is trap_handler, + but signal_is_trapped(SIGINT) returns 0, we need to call + trap_to_sighandler to decide what to do + [in bash-2.01.1] + + 7/7 + --- +locale.c + - fix to set_locale_var to handle an assignment to LC_ALL (e.g., as + the result of `unset LANG') when default_locale is null + [in bash-2.01.1] + + 7/8 + --- +builtins/umask.def, doc/{bash.{1,html},bashref.texi} + - added `-p' option for umask to print output in a reusable form + + 7/9 + --- +doc/{bash.{1,html},bashref.texi} + - removed descriptions of `-type', `-path', and `-all' options to + the `type' builtin in preparation for removing them in the next + release + +builtins/type.def + - removed mention of `-type', `-path', and `-all' options from the + long help description + +error.c, error.h + - new function: internal_warning, for warning messages + +variables.c + - changed a call to internal_error to use internal_warning + - modified change of 7/3 so that arrays are not emptied until + just before the shell is about to assign the new values, so + the old value can be used to generate the rhs of the assignment, + if necessary. This is how `normal' shell variables work + [in bash-2.01.1] + +jobs.c, jobs.h + - delete_job now takes a second int argument and prints a warning + message when deleting a stopped job if the second argument is + non-zero + +jobs.c, builtins/jobs.def + - changed all calls to delete_job to provide a proper second arg + +lib/readline/bind.c + - broke rl_read_init_file into an `upper' and `lower' half in + preparation for adding file inclusion capability to inputrc + parsing + - handle_parser_directive now displays an error message if an + unknown directive is encountered + - parser_endif now prints an error message if an $endif without + a matching $if is found + - added `$include' parser directive to read bindings and commands + from another file at that point + +lib/readline/doc/rluser.texinfo, doc/{bash.{1,html},readline.3} + - documented new readline `$include' parser directive + +shell.c, parse.y + - added a new invocation option, --dump-po-strings, and code to + make it dump translatable strings ($"...") in GNU gettext + `po' format + +doc/{bash.{1,html},bashref.texi} + - documented new `--dump-po-strings' invocation option + +lib/readline/{{kill,funmap}.c,readline.h} + - added `rl_paste_from_clipboard()', bound to `paste-from-clipboard' + for CYGWIN32 users + +lib/readline/kill.c + - incorporated bfox's patches for `iterative' yank-last-arg handling. + This means that one can keep pressing M-. and move backwards in + the history, yanking the last argument of successive history lines + +lib/readline/rlwinsize.h + - new file, encapsulates various locations of the definition for + `struct winsize' + +aclocal.m4 + - augmented BASH_STRUCT_WINSIZE to look in termios.h as well as + sys/ioctl.h for definition of `struct winsize' + +lib/readline/rltty.h + - include "rlwinsize.h" after including tty-driver-specific header + file + + 7/10 + ---- +support/config.guess + - add better support for SunOS on M68K (old Sun3 machines) + +parse.y + - check for compound array assignment in read_token_word only if + there are characters before the `=' (which would make it a legal + assignment statement). This fixes the problem with defining a + function named `=' with `=() { echo foo; }' + [in bash-2.01.1] + +jobs.c, jobs.h + - nohup_all_jobs and delete_all_jobs now take a parameter which + says whether or not to restrict their operation to only running + jobs + +jobs.c + - changed all calls to delete_all_jobs + +builtins/jobs.def + - added `-a' (all jobs) and `-r' (running jobs only) options to + `disown' + +doc/{bash.{1,html},bashref.texi} + - documented new `-a' and `-r' options to `disown' + +findcmd.c, findcmd.h + - new files with command searching code from execute_cmd.c and + function declarations from execute_cmd.h + +Makefile.in, builtins/Makefile.in + - updated dependencies to account for new findcmd.[ch] + - updated dependencies to account for new redir.[ch] + +redir.c, redir.h + - new files with code that sets up lists and performs redirections + from execute_cmd.c and execute_cmd.h + +execute_cmd.c + - include new findcmd.h, redir.h + + 7/11 + ---- +Makefile.in, configure.in + - PROFILE_FLAGS is now substituted into the Makefile by configure + + 7/14 + ---- +print_cmd.c + - make sure single_quote is called from xtrace_print_word_list + to correctly quote each word of trace output, especially those + with embedded quotes + [in bash-2.01.1] + +aclocal.m4 + - extended BASH_CHECK_GETPW_FUNCS so that it checks that getpwuid + and getpwnam can also be declared, as well as getpwent + [in bash-2.01.1] + - in BASH_FUNC_PRINTF, cast printf to type `_bashfunc' before trying + to assign it to `pf' to avoid any prototype problems in the + declaration + [in bash-2.01.1] + +trap.c + - include <unistd.h> before any of the bash-specific header files, + but after config.h + [in bash-2.01.1] + +test.c + - include <errno.h> and declare `extern int errno' before including + any of the bash-specific include files, but after <unistd.h> + [in bash-2.01.1] + +builtins/Makefile.in + - PROFILE_FLAGS is now substituted into the Makefile by configure + +configure.in + - new options, --enable-profiling and --enable-static-link, to turn + on profiling with gprof and link bash statically (if using gcc) + for use as a root shell. The former implies the latter. If + we're linking statically, dynamic loading of new builtins is not + available + +doc/bashref.texi + - documented new --enable-profiling and --enable-static-link + options in installation section; regenerated INSTALL + +lib/glob/glob.[ch] + - new global variable, glob_ignore_case, turns on case-insensitive + filename matching in fnmatch() using the FNM_CASEFOLD flag + +doc/{bash.{1,html},bashref.texi} + - documented new shopt `nocaseglob' option + + 7/15 + ---- +bashline.c + - when glob_complete_word is called with state == 0, make sure we + set rl_filename_completion_desired so that proper quoting of + the resultant filenames is performed + [in bash-2.01.1] + + 7/16 + ---- +externs.h, oslib.c + - strcasecmp and strncasecmp replacements should have `const char *' + as the first two arguments, to match OS definitions + [in bash-2.01.1] + + 7/17 + ---- +(many files) + - changes for minix-2.0, mostly just adding #ifndef _MINIX around + include files that minix doesn't provide, like <sys/param.h> and + <sys/file.h> + +lib/readline/terminal.c + - removed `outchar' function; use _rl_output_character_function in + its place + +support/config.guess + - changes to recognize HP_ARCH of `hppa2.0' + +test.c + - new `-N' option: `test -N file' returns true if FILE exists and + has been modified since it was last accessed + +doc/{bash.{1,html},bashref.texi} + - documented new `test -N' option + + 7/22 + ---- +aclocal.m4 + - prefer /var/spool/mail to /usr/spool/mail in BASH_DEFAULT_MAIL_DIR + [in bash-2.01.1] + +lib/readline/{complete,bind}.c + - new readline variable, print-completions-horizontally, which causes + matches to be printed across the screen (like `ls -x') rather than + up-and-down (like `ls') + - new readline variable, completion-ignore-case, which causes filename + completion and matching to be performed case-insensitively + +doc/{bash.{1,html},readline.3}, lib/readline/doc/rluser.texinfo + - documented new print-completions-horizontally variable + - documented new completion-ignore-case variable + +_distribution, Makefile.in + - bumped the version number up to 2.02-alpha1 + +bracecomp.c + - fixes so that the braces are not quoted by the filename quoting + function when complete-into-braces is executed with M-{. The + brace completion functions do filename quoting themselves + [in bash-2.01.1] + +pathexp.c + - changed quote_string_for_globbing so that it takes a flags word + as its second argument + +pathexp.h + - defines for flags passed to quote_string_for_globbing + +subst.c,execute_cmd.c + - changed calls to quote_string_for_globbing to pass the correct + flag arguments + +expr.c + - added a `**' binary operator to do exponentiation (2**16 == 65536). + precedence is lower than arithmetic operators, higher than unary + operators (2**16-1 == 65535) + +doc/{bash.{1,html},bashref.texi} + - documented new `**' arithmetic binary operator + + 7/24 + ---- +shell.c + - added new (currently undocumented) `--wordexp' option to do the + job required by POSIX.2 wordexp(). If -n is supplied along with + --wordexp, command substitution is disallowed and the shell + exits with a status of 125 if one is attempted. If there is an + expansion error, the shell exits with a status of 127. If there + is a shell parsing error, the shell exits with a status of 126. + Otherwise, the exit status is 0. The current output is + + number of words\n + number of bytes\n + expanded words, one per line, separated by newlines + + This will have to be changed when an interface to glibc is coded + + 7/28 + ---- +hashcmd.h + - reduced the default size of the filename hash table from 631 + to 107 + +sig.c + - don't call initialize_siglist if HAVE_UNDER_SYS_SIGLIST is defined + [in bash-2.01.1] + +siglist.c + - don't compile this file if HAVE_UNDER_SYS_SIGLIST is defined + [in bash-2.01.1] + +variables.c + - fix to make $RANDOM work better in subshells + [in bash-2.01.1] + +aclocal.m4 + - new macro, BASH_DECL_UNDER_SYS_SIGLIST, looks for _sys_siglist in + <signal.h> and <unistd.h>, defines UNDER_SYS_SIGLIST_DECLARED if + found + [in bash-2.01.1] + - change BASH_UNDER_SYS_SIGLIST to require BASH_DECL_UNDER_SYS_SIGLIST, + like BASH_SYS_SIGLIST requires AC_DECL_SYS_SIGLIST + [in bash-2.01.1] + +config.h.in + - add a line for UNDER_SYS_SIGLIST_DECLARED + [in bash-2.01.1] + +configure.in + - make sure that SVR4_2 is defined for machines that have $host_os + sysv4.2* (e.g., sysv4.2MP) as well as $host == sysv4.2 + [in bash-2.01.1] + + 7/29 + ---- +command.h + - new command type, ARITH_COM, used to create and execute a ((...)) + command without translating it into let "..." + +parse.y + - changes to the grammar and lexer so that ((...)) is parsed as a + command of type ARITH_CMD. An ARITH_CMD is a WORD_LIST, for + future expansion, even though only the first word is used + +make_cmd.c, make_cmd.h + - definition and declaration of a function to build an arithmetic + command + +dispose_cmd.c + - added code to dispose of arithmetic commands + +print_cmd.c + - added code to print arithmetic commands, both `regularly' and + when they're being traced with `set -x' + +externs.h + - extern declaration for xtrace_print_arith_cmd + +copy_cmd.c + - added code to copy arithmetic commands + +execute_cmd.c + - added code to directly execute arithmetic commands -- they are + a shell_control_structure, so just about everything like + redirections and piping is taken care of by the boilerplate code. + All that's needed is to expand the expression (which is within + double quotes -- added by parse.y:parse_arith_cmd()), print it + if tracing is enabled, call the expression evaluator, and return + an appropriate result + + 7/30 + ---- +input.c + - new function, set_buffered_stream(fd, bp), sets the buffered stream + associated with FD to BP and returns the old buffered stream + +input.h + - extern declaration for set_buffered_stream + +parse.y + - call set_buffered_stream rather than manipulating the BUFFERS array + directly + +shell.c + - unset_bash_input now takes an argument, CHECK_ZERO. This tells it + whether to check whether default_buffered_input is >= 0 or just > 0 + +externs.h + - changed extern declaration for unset_bash_input + +execute_cmd.c, jobs.c, nojobs.c + - changed calls to unset_bash_input to add appropriate argument + +input.h + - #undef B_* before defining them as flag values for b_flags. Some + systems, like SVR4, have a B_ERROR define in a file included by + jobs.c and nojobs.c, and it causes a warning + + 7/31 + ---- +fnmatch.c + - rewrote most of fnmatch(), so that it now implements ksh-88 style + pattern matching (`[@+*?!](patlist)') if the FNM_EXTMATCH flag + is set + +fnmatch.h + - added a define for FNM_EXTMATCH + + 8/4 + --- +lib/readline/display.c + - fixed _rl_redisplay_after_sigwinch () so that it really redisplays + only the portion after the final newline of a multi-line prompt + [in bash-2.01.1] + +bashline.c + - attempt_shell_completion no longer returns matches if a glob pattern + matches more than one filename -- it caused too many problems + [in bash-2.01.1] + + 8/5 + --- +lib/glob/glob.c + - updated glob_pattern_p so that the extended matching operators + are recognized + +pathexp.c + - udpated unquoted_glob_pattern_p so that the extended matching + operators are recognized + - udpated quote_globbing_chars so that the extended matching + operators are recognized and quoted appropriately + +subst.c + - updated match_pattern_char so that the extended matching operators + are recognized + +parse.y + - updated read_token_word so that it parses an extended matching + pattern as a single word + +jobs.c + - if a job is suspended with SIGTSTP, and the user has set + checkwinsize with `shopt', update the window size + [in bash-2.01.1] + +pathexp.c, pathexp.h + - new global variable, extended_glob, controls whether the extended + pattern matching features are enabled + +pathexp.h + - new define, FNMATCH_EXTFLAG, to be OR'd with other values for + flags argument to fnmatch to enable the extended pattern matching + features if extended_glob is set + +{pathexp,execute_cmd,bashhist,subst,test}.c, builtins/help.def + - changed calls to fnmatch to add FNMATCH_EXTFLAG to the flags arg if + extended_glob is non-zero + +lib/glob/glob.c + - changed flags arg passed to fnmatch to include FNM_EXTMATCH if + extended_glob is non-zero (#ifdef SHELL) + + 8/6 + --- +builtins/shopt.def + - added a new `extglob' shell option, controls the value of + extended_glob + + 8/7 + --- +doc/{bash.{1,html},bashref.texi} + - documented new extended pattern matching operators and the `extglob' + shell option + +tests/{extglob.{tests,right},run-extglob} + - test suite for the new extended globbing features + + 8/8 + --- +parse.y, pathexp.h, lib/glob/fnmatch.c + - made the extended globbing code #ifdef EXTENDED_GLOB + +config.h.in + - added a line for EXTENDED_GLOB, controlled by configure + +configure.in + - new option, --enable-extended-glob, controls defining of + EXTENDED_GLOB (on by default) + +doc/bashref.texi + - documented new `configure' `--enable-extended-glob' option + + 8/11 + ---- +builtins/printf.def + - new `printf' builtin, implemented according to POSIX.2 spec + for printf(1) + +Makefile.in,builtins/Makefile.in + - added necessary stuff for new printf builtin + + 8/12 + ---- +lib/readline/isearch.c + - change to make ^G interrupt the incremental search correctly + [in bash-2.01.1] + +configure.in, config.h.in + - configure now checks for the availability of strtoul(3) + +builtins/printf.def + - use strtoul for the `%o', `%u', `%x', and `%X' formats if it + is available + + 8/13 + ---- +tests/{printf.{right,tests},run-printf} + - extensive test suite for the new `printf' builtin + +builtins/Makefile.in + - change so that `builtext.h' is not recreated every time the source + file for a builtin is changed if the contents are the same. This + keeps many files from being recompiled + + 8/14 + ---- +subst.c + - changed verify_substring_values so that it returns -1 for substring + range errors, 0 for expression errors, and 1 for success + [in bash-2.01.1] + - changed parameter_brace_substring to return an error if + verify_substring_values returns 0, and a null string if it returns + -1. This matches the ksh93 behavior + [in bash-2.01.1] + +trap.c + - changed decode_signal so that it makes sure the first three + characters of a signal name are `SIG' before allowing the `SIG' + prefix to be omitted. This is so a signal spec of `T' does not + match `EXIT', for instance + [in bash-2.01.1] + +builtins/trap.def + - make sure that showtrap() displays traps for signals with unknown + names using the signal number + [in bash-2.01.1] +shell.c + - make sure that `bash -r' doesn't turn on the restricted mode until + after the startup files are executed + [in bash-2.01.1] + +doc/{bash.{1,html},bashref.texi} + - documented printf builtin + + 8/15 + ---- +general.c + - added \xNNN escape to ansicstr -- NNN are up to three hex digits. + This affects $'...', `echo -e', and printf + +builtins/printf.def + - added \xNNN escape to bexpand -- NNN are up to three hex digits. + This affects printf's `%b' conversion specifier + +doc/{bash.{1,html},bashref.texi} + - documented new \xNNN escape sequence for echo, $'...', and printf + +builtins/setattr.def + - make sure that a variable found in the temp environment does not + cause a null string to be assigned by bind_variable (e.g., + foo="" export foo + ) + [in bash-2.01.1] + + 8/18 + ---- +subst.c + - fixed a bug that sometimes caused bad memory (pointer into an + allocated block) to be passed to free when doing arithmetic + substitution. Bug report from stevet@myofb.org + [in bash-2.01.1] + + 8/19 + ---- +subst.c + - considerable changes: moved the code that expands a single + $... parameter expansion into a separate function: param_expand() + This function returns a string, which may contain characters + quoted with CTLESC or CTLNUL without doing word splitting + - changed expand_word_internal to not remove the expansion of "$*" + if the number of positional parameters is > 0 + - changed the '"' case of expand_word_internal to remove quoted + nulls from the resultant word if the expansion was not "$@", and + the word is not a quoted null string ([] == CTLNUL, [1] == '\0') + +subst.c, variables.c + - moved the code that handles special variables from subst.c to + variables.c + + 8/20 + ---- +subst.c + - rearranged the source a bit to group functions with similar + operation together + - fixed parameter_brace_expand so that it no longer allows + indirect expansion of `special' variables + - fixed parameter_brace_expand so taking the length of some of + the shell's special parameters works again + - moved all of the code that computes the length of a shell + parameter (the ${#xxx} expansion) into parameter_brace_expand_length. + Previously, the code that handled the lengths of the shell's + special parameters was in parameter_brace_expand_word + - valid indirect expansions are now only variable names or positional + parameters + + 8/21 + ---- +subst.c + - fixed param_expand to raise an expansion error if $! is being + expanded and no asynchronous processes have been created + - an expression error in a $((...)) arithmetic expansion now causes + a non-interactive shell running in POSIX mode to exit + - relaxed change of 8/20 to allow indirect references to $#, $@, $* + +builtins/bashref.texi + - documented new posix-mode exit on invalid expressions in $((...)) + +lib/readline/complete.c + - don't call rl_strpbrk unless rl_filename_quote_characters is not + NULL -- strpbrk requires non-NULL arguments + [in bash-2.01.1] + + 8/22 + ---- +bashline.c + - don't make `history-expand-line' a bindable command unless + BANG_HISTORY is defined, and don't compile the code for that + command in unless BANG_HISTORY is defined + - make history_expand_line(), tcsh_magic_space(), alias_expand_line(), + and history_and_alias_expand_line() int-returning functions that + return 0 for success and non-zero on error. This allows + tcsh_magic_space() to just call history_expand_line() and insert + a space if that returns successfully + - `magic-space' is now a bindable readline command + +doc/bash.{1,html}, lib/readline/doc/rluser.texinfo + - documented new `magic-space' bindable readline command + + 8/25 + ---- +parse.y + - fixed decode_prompt_string so that values of $PWD longer than + PATH_MAX don't cause buffer overruns (char t_string[PATH_MAX]) + [in bash-2.01.1] + +general.c + - fixed polite_directory_format so that values of $HOME longer + than PATH_MAX don't cause buffer overruns (char tdir[PATH_MAX]) + [in bash-2.01.1] + +subst.c + - fix to expansion of $* so that the positional parameters are + separated by the first character of $IFS, even when the expansion + is not within double quotes, so the correct split is still + performed even when IFS does not contain a space. Works for + ${*}, too + - fix to expansion of $@ so that the positional parameters are + separated by the first character of $IFS, even when the expansion + is not within double quotes, so the correct split is still + performed even when IFS does not contain a space. Works for + ${@}, too + - new function, string_list_dollar_at(), which is to $@ as + string_list_dollar_star is to $* + - fixed expansion of $@ so that splitting is still done even if + IFS is unset or NULL, as POSIX.2 specifies (section 3.5.2) + - fixed expansion of $* so that it expands to multiple words if there + is more than one positional parameter, just like $@, even if + IFS is unset or NULL + - new function list_quote_escapes, quotes (with CTLESC) all + CTLESC and CTLNUL characters in each member of the list + +tests/dollar-{at,star}.sh + - combined into dollar-at-star, changed run-dollars accordingly + + 8/26 + ---- +Makefile.in + - make the `tests' target use $(SHELL) instead of hardcoding `sh' + + 8/29 + ---- +subst.c + - expand_word_list_internal now takes a flags word as the second + argument, telling which expansions to perform on the WORD_LIST + - broke expand_word_list_internal into several functions: one + each to do brace expansion, glob expansion, and the `normal' + shell expansions + - new extern function: expand_words_shellexp() to perform the + `normal' shell expansions on a WORD_LIST + +subst.h + - extern declaration for expand_words_shellexp + +bashline.c + - fixed a problem with attempt_shell_completion where it attempted + to refer to rl_line_buffer[-1] (completion at the start of the + line, which means that ti == -1, which means that the test for + rl_line_buffer[ti] at line 715 was an array bounds error + [in bash-2.01.1] + +eval.c + - new function, parse_string_to_word_list(), which takes a string + and runs it through the parser, returning the resultant word + list + +externs.h + - new extern declaration for parse_string_to_word_list() + +variables.c + - change assign_array_var_from_string to first split the string + between the parens on whitespace, then expand the resultant + list of words with all the shell expansions before doing the + assignment + + 9/4 + --- +redir.c, redir.h + - redirection_error is no longer a static function + +builtins/evalstring.c + - changes to handle $( < filename ) (equivalent to $(cat filename)) + as in ksh + +lib/readline/bind.c + - added two new functions: rl_unbind_function_in_map(func, map), + which unbinds all keys that execute FUNC in MAP; and + rl_unbind_command_in_map(command, map), which unbinds all keys + bound to COMMAND in MAP + +lib/readline/readline.h + - extern declarations for rl_unbind_{function,command}_in_map + +lib/readline/doc/rltech.texi + - documented rl_unbind_{function,command}_in_map + +builtins/bind.def + - added a new option, -u FUNCNAME, which unbinds all key sequences + bound to FUNCNAME in the specified (or current) keymap + +doc/{bash.{1,html},bashref.texi} + - documented new $( < filename ) command substitution + - documented new bind -u FUNCNAME option + + 9/5 + --- +shell.c + - send SIGHUP to all jobs when an interactive login shell exits if + the variable `hup_on_exit' is non-zero + - modified run_startup_files so that if `NON_INTERACTIVE_LOGIN_SHELLS' + is #define'd (perhaps in config.h.top, though there is nothing there + for it), all login shells (interactive and non-interactive) run + /etc/profile and one of the per-user login shell startup files + +builtins/shopt.def + - new shopt option `huponexit' to control the value of hup_on_exit + +doc/{bash.{1,html},bashref.texi} + - documented new `huponexit' shell option + + 9/8 + --- +builtins/common.c + - changed contains_shell_metas to return 1 if a tilde appears at the + start of a string or after a `=' or `:' + - changed backslash_quote to quote a tilde if it appears at the start + of a string or after a `=' or `:' + +lib/readline/complete.c + - moved rl_tilde_expand to util.c; it doesn't really have anything + to do with completion + - moved insert_text to readline.c, renamed it _rl_replace_text (since + that's really what it does), changed callers + - moved code that postprocesses the list of completion matches into + a new function: postprocess_matches + - new implementation of tcsh-like menu completion in a single new + function: rl_menu_complete + +lib/readline/{funmap.c,readline.h} + - necessary declarations for binding rl_menu_complete to the + new `menu-complete' command + +doc/{bash.{1,html},readline.3}, lib/readline/doc/rluser.texinfo + - documented new `menu-complete' bindable readline command + + 9/9 + --- +jobs.c + - delete_job should print a warning only if subshell_environment + is 0, so we don't print bogus warnings when shell scripts without + a leading #! are executed + + 9/10 + ---- +builtins/read.def + - fixed the code so that the `read' is automatically restarted when + it returns -1 with errno == EINTR. SIGINT is handled by the + interrupt handler, since interrupt_immediately is set to 1, so + this handles things like SIGCHLD + [in bash-2.01.1] + + 9/11 + ---- +test.c + - reorganized the code slightly to make it easier to add the ksh-like + [[...]] compound command + +test.h + - new file, with extern declarations for functions available in test.c + +externs.h + - moved declaration of test_command to test.h + +builtins/test.def + - include `test.h' + + 9/16 + ---- +{command,make_cmd,dispose_cmd,externs,subst}.h +parse.y, subst.c +{make,dispose,copy,print,execute}_cmd.c + - changes to add the new ksh-93 compatible [[...]] conditional command + +configure.in + - new enable option, --enable-cond-command, to compile in the [[...]] + command code + +config.h.in + - new #define, COND_COMMAND, to compile in the [[...]] command code + +tests/{run-cond,cond.{tests,right}} + - test suite for the new [[...]] command + +{builtins,lib/{readline,glob,tilde}}/Makefile.in + - explicit dependencies for .o files on .c files for losing makes + like Solaris + +doc/{bash.{1,html},bashref.texi} + - documented the new `[[' compound command + - documented the test/[ builtin behavior based on the number of + arguments in the description of the builtin + - made a new section for conditional expressions that just lists + the available primaries -- the connectives and other operators + are listed in the description of the [[ command and the test/[ + builtin + + 9/18 + ---- +builtins/set.def + - minus_o_option_commands is now a global function so the shopt + code can use it + - minus_o_option_commands now takes an argument telling it which + options to print, just like list_minus_o_options + - new function, print_minus_o_option, which prints the value of + a `set -o' option either in the traditional format or in the + format used by `set +o' + - changed list_minus_o_opts and minus_o_option_commands to call + print_minus_o_option + +builtins/shopt.def + - `shopt -p' now causes output to be printed in a format reusable + as input (the format is a series of shopt commands, like the + output of `set +o') + - fixed a bug that made `shopt -so' and `shopt -uo' not work + - fixed list_shopt_o_options so that `shopt -op' acts like `set +o' + - fixed list_shopt_o_options to that `shopt -op optname' prints the + value of optname in a reusable format + - fixed list_some_o_options so that `shopt -ops' and `shopt -opu' + work and display output in a reusable format + + 9/19 + ---- +doc/{bash.{1,html},bashref.texi} + - documented new `shopt -p' behavior + +shell.c + - made `bash +o' display the same output as `set +o' and then + start an interactive shell (previously `bash -o' and `bash +o' + displayed the same thing) + +builtins/common.h + - added prototypes to the extern function declarations + + 9/22 + ---- +builtins/evalstring.c + - fixed the DISCARD case of the jump_to_top_level so that it + doesn't try to call dispose_command(command) after the + `pe_dispose' unwind frame gets run, since that disposes the + command + + 9/23 + ---- +test.[ch] + - test_eaccess is now a global function so that globbing code can + use it + +lib/glob/glob.c + - rewrote glob_vector to be slightly more efficient and to not + read the directory if the filename pattern does not contain + any globbing chars. This satisfies the POSIX requirement that + read permission is not required for a directory when the + pathname component does not contain a pattern character (bug + reported by jsm28@cam.ac.uk) + +subst.c + - fixed parameter_brace_expand so that ${array[@]} and ${array[*]} + behave correctly when IFS is unset or set to something that does + not contain a space (they should result in separate words, just + like $@ and $*) + +tests/{run-array2,array-at-star,array2.right} + - tests for the expansions of ${array[@]} and ${array[*]}, derived + from the tests in dollar-at-star + + 9/24 + ---- +jobs.c + - fixed cleanup_dead_jobs so that it doesn't remove the job + containing last_asynchronous_pid from the job table. This + fixes the POSIX.2 `wait' requirement problem + + 9/25 + ---- +parse.y + - added `\r' escape sequence to the prompt expansion code + +lib/readline/chardefs.h + - added defines for ISOCTAL, OCTVALUE, isxdigit (if not defined), + and HEXVALUE + +lib/readline/bind.c + - added `normal' echo/printf-like backslash escapes to the + key sequence translation code, with the addition that \d + expands to RUBOUT. This means that key sequence definitions + (before the `:') and macro values may contain these special + backslash-escape sequences + - now that we can translate octal escape sequences in key bindings, + change _rl_get_keyname so that it turns characters with values + 128-159 inclusive into octal escape sequences (\200-\237), since + those characters are not ASCII or ISO Latin 1 + +doc/{bash.{1,html},readline.3}, lib/readline/doc/rluser.texinfo + - documented new backslash escapes for readline key sequence and + macro translation + +builtins/pushd.def + - new function, get_dirstack_from_string(char *string), returns an + element from the directory stack or null, treating the argument + exactly as `dirs string' would, with the exception that if + the first character of `string' is not `+' or `-', a `+' is + assumed + +builtins/common.h + - new extern declaration for get_dirstack_from_string + +general.c + - added code to bash_special_tilde_expansions to get the expansion + using get_dirstack_from_string() if the first character of the + tilde-prefix is a digit or the first character is a `+' or `-' + and the second is a digit + +tests/dstack.{tests,right} + - renamed from dirstack.{tests,right} + +tests/dtack2.{tests,right} + - new tests for the directory stack tilde expansion code + +tests/run-dirstack + - now runs both dstack and dstack2 + + 10/3 + ---- +trap.c + - reordered header file inclusion for irix 4 + +execute_cmd.c + - fixed select_query so that a reply that is not a number is treated + the same as a numeric reply that is out of range + +lib/readline/util.c + - added a backwards-compatibility definition of _rl_savestring() + +builtins/set.def + - initialize_shell_options now takes an argument saying whether or + not we should parse $SHELLOPTS from the environment. The shell + does not parse the value if it's restricted, running setuid, or + running in `privileged mode' + +shell.c + - change call to initialize_shell_options to add the correct argument + +builtins/common.h + - changed extern declaration for initialize_shell_options + +doc/{bash.{1,html},bashref.texi} + - added note that the shell ignores $SHELLOPTS in the environment at + startup if running in privileged mode + - added note that the restricted shell does not parse $SHELLOPTS from + the environment at startup + + 10/6 + ---- +aclocal.m4 + - change BASH_RLIMIT_TYPE so that it looks for rlim_t in + <sys/resource.h> as well as <sys/types.h>, for Solaris 2.6 + - new macro, BASH_LARGE_FILE_SUPPORT, to enable special compilation + options for large files on Solaris 2.6 (from eggert@twinsun.com) + +mailcheck.c + - the `file_size' member of the FILEINFO struct should be of + type `off_t' + - the `size' variable in file_has_grown should be of type `off_t' + - the RESET_MAIL_FILE macro should initialize file_size to 0, not 0L + +builtins/Makefile.in + - LDFLAGS and LOCAL_LDFLAGS are now set by configure + - `mkbuiltins' is now created from `mkbuiltins.o' instead of directly + from the source to the executable + +builtins/evalfile.c + - fixed _evalfile so that it handles large files correctly on + systems where the st_size member of `struct stat' will not fit + into an `int' + +builtins/mkbuiltins.c + - don't assume that st_size fits into an int + +input.[ch] + - the `b_size' member of a struct BSTREAM is now of type `size_t' + - changed third argument to make_buffered_stream to size_t; changed + caller + - changed `size' variable in fd_to_buffered_stream to type `size_t' + +general.h + - include <sys/resource.h> if HAVE_SYS_RESOURCE_H and RLIMTYPE are + both defined, for possible necessary definition of RLIMTYPE + (e.g., on Solaris 2.6) + +{execute_cmd,jobs}.c, builtins/times.def + - don't include <sys/resource.h> explicitly if RLIMTYPE is defined, + since general.h will include it in that case + +lib/readline/bind.c + - new function, char *_rl_read_file(filename, sizep), which reads + FILENAME into a malloced buffer, returning the buffer and the + size of the buffer in *SIZEP + +lib/readline/histfile.c + - changed read_history_range and history_truncate_file to handle + large files + +hashcmd.c + - find_hashed_filename should not add `./' to the front of a pathname + that already begins with `./' + + 10/8 + ---- +support/config.sub + - recognize `hppa2.0' as a valid machine architecture + +aclocal.m4 + - changed BASH_CHECK_LIB_TERMCAP so that `gnutermcap' is not chosen + if `$prefer_curses' is set to something + +bashhist.c + - don't use HISTCONTROL or HISTIGNORE to remove lines from the + second and subsequent lines of a multi-line command + (current_command_line_count > 1). Old code did this only when + command-oriented-history was enabled + +doc/{bash.{1,html},bashref.texi} + - changed descriptions of HISTCONTROL and HISTIGNORE to state that + these variables are not applied to the second and subsequent + lines of a multi-line command + +builtins/hash.def, {copy,dispose}_cmd.c + - include "bashtypes.h" -- cray machines need it because of their + oddball definition of `word' + +configure.in + - changed check of ${host_cpu} to check for `*cray*' and `*Cray*' + when deciding whether to include the GNU malloc, since it + seems that ${host_cpu} gets set to `CrayYMP' + + 10/9 + ---- +configure.in + - look for strtod and strtol in libc + - make lib/sh directory in build directory if not there + - create lib/sh/Makefile + +config.h.in + - added HAVE_STRTOD and HAVE_STRTOL + +Makefile.in + - changes for lib/sh/libsh.a (shell library) + +builtins/printf.def + - took out the `#ifdef STRTOUL' code, since strtoul is in libsh.a, + and will be resolved from there if it's not in libc + +variables.c + - call strtol() instead of string_to_long() + +general.c, general.h + - removed string_to_long + - changed legal_number to use strtol so it correctly sets errno + to ERANGE on overflow + - moved bash_getcwd_errstr here from lib/sh/oslib.c + +externs.h + - moved extern declarations for functions defined in libsh to a + separate section of the file, added extern declarations for + other functions in libsh + +builtins/ulimit.def + - changed macro definition for string_to_rlimtype to call strtol + directly instead of string_to_long + +lib/sh/clktck.c + - moved get_clock_tck to its own file, since it's compiled in + unconditionally + + 10/10 + ----- +lib/sh/getenv.c + - moved getenv() and __getenv() here from lib/sh/oslib.c + +lib/sh/{setlinebuf,strerror,strcasecmp}.c + - moved {setlinebuf,strerror,strcasecmp}() from oslib.c to + individual files + +lib/sh/Makefile.in, Makefile.in + - changes for new files in lib/sh + +aclocal.m4 + - new macro BASH_SYS_RESTARTABLE_SYSCALLS, which does what + AC_SYS_RESTARTABLE_SYSCALLS does, but using posix sigaction() + +configure.in + - call BASH_SYS_RESTARTABLE_SYSCALLS if ac_cv_sys_restartable_syscalls + is `no' + + 10/13 + ----- +builtins/jobs.def + - catch out-of-range jobs better in disown_builtin + +configure.in + - don't build with GNU malloc on cygwin32 + +trap.c + - change signal_name to handle the case where signal_names[sig] is + NULL, which can happen on cygwin32 + +execute_cmd.c + - changes to do_piping to make pipes text mode (O_TEXT) on cygwin32 + +cross-build + - new directory with cache files and other stuff for cross-compiling + bash (currently only for building for cygwin32 on a Unix machine) + +cross-build/cygwin32.cache + - new file containing configuration variable assignments for + cygwin32 that would otherwise require a default case for AC_TRY_RUN + +configure.in + - source ${srcdir}/cross-build/cygwin32.cache on CYGWIN32 systems + if we're cross-compiling on a unix machine + - set $CC_FOR_BUILD for cygwin32 cross-compiling environment + +Makefile.in + - CC_FOR_BUILD is now a variable set by configure + +builtins/mkbuiltins.c + - only check for read(2) returning <= 0 in extract_info() (error + and exit on < 0, warning and return on == 0) + +builtins/evalfile.c + - only check for read(2) returning <= 0 in _evalfile() (error and + and failure return on < 0, success on == 0 while short-circuting + rest of operation) + + 10/14 + ----- + +vprint.c + - moved to lib/sh/vprint.c + +lib/sh/Makefile.in + - added entries for vprint.[co] in the appropriate places + +cross-build/win32sig.h + - a version of signames.h for cross-compiling for the CYGWIN32 + environment on a Unix machine (from noer@cygnus.com) + +aclocal.m4 + - made all cases of AC_TRY_RUN and AC_TRY_COMPILE have reasonable + default cases for cross-compiling, and tell the user what they are + +Makefile.in + - removed vprint.c from shell sources and vprint.o from shell + objects + - added a level of indirection for signames.h -- the variable + SIGNAMES_H is set by configure to either `lsignames.h' or + a file for a cross-compilation environment (currently only + the cygwin32 stuff is supported). Then that file is copied + to `signames.h'. `lsignames.h' is created by `mksignames' as + was previously used to create signames.h directly + +configure.in + - set SIGNAMES_H to either `$(srcdir)/cross-build/win32sig.h' or + `lsignames.h' as appropriate, substitute into Makefile + + 10/15 + ----- +builtins/Makefile.in + - CC_FOR_BUILD is now set by configure and used to build mkbuiltins + and psize.aux + +variables.h + - new variable attribute `att_tempvar', set if the SHELL_VAR * was + constructed on the fly from the temporary environment + +variables.c + - find_name_in_env_array now sets the `att_tempvar' attribute on + the SHELL_VAR it creates + +findcmd.c + - search_for_command now disposes the SHELL_VAR created by searching + the temporary environment for $PATH, if it is found there + - _find_user_command_internal also disposes of the SHELL_VAR if it + has the `att_tempvar' attribute set + +builtins/setattr.c + - show_name_attributes looks in the temporary environemnt, so it needs + to dispose the SHELL_VAR if it has the att_tempvar attribute set + +subst.c + - parameter_brace_expand_word now disposes of the SHELL_VAR returned + by find_variable if it has the att_tempvar attribute set + - ditto for param_expand and word_split + +builtins/kill.def + - disallow null pid arguments instead of treating them as 0 + - display a usage message and return failure if no pid or job + arguments are supplied + + 10/16 + ----- +builtins/declare.def + - make `var=value declare -x var' behave the same as + `var=value export var' and `var=value declare -r var' behave the + same as `var=value readonly var', now that we have the `tempvar' + attribute + + 10/22 + ----- +jobs.c + - non-interactive shells shouldn't report jobs killed by a SIGINT, + even if the standard output is to a terminal + - pretty_print_job should add a CR at the end of its output if the + shell is interactive and asynchronous notification is being + performed. This fixes the problem with extra CRs in the output + of $(jobs) + +general.c + - changed canonicalize_pathname to change `//' into `/', but leave + other pathnames starting with two consecutive slashes alone + + 10/27 + ----- + +lib/readline/histexpand.c + - fixed history_expand so that the appearance of the history + comment character at the beginning of a word inhibits history + expansion for the rest of the line + + 10/29 + ----- +jobs.c,variables.c + - moved set_pipestatus_array to variables.c + +variables.c + - new function, set_pipestatus_from_exit(int), which sets the + PIPESTATUS variable from a command's exit status + +variables.h + - extern declarations for set_pipestatus_from_exit and + set_pipestatus_array + +execute_cmd.c + - fixed execute_simple_command to call set_pipestatus_from_exit + if a foreground builtin or function, or a foreground null + command is executed + + 10/31 + ----- +shell.c + - fixed run_startup_files to detect being run by sshd, and treat + that case as equivalent to being run by rshd + + 11/3 + ---- +builtins/set.def + - make sure `set -a' doesn't cause SHELLOPTS to be exported when + a change is made to one of the shell options + + 11/4 + ---- +pathexp.c + - fix to shell_glob_filename in the code that uses a POSIX glob + library + + 11/5 + ---- +jobs.c + - fix cleanup_dead_jobs to hang onto the job corresponding to + last_asynchronous_pid only if the shell is not interactive + (this still has the problem that until a new async process + is started, the job will stay in the jobs table) + +configure.in,aclocal.m4 + - added a new macro, BASH_TYPE_U_INT32_T, to check for u_int32_t + separately from int32_t, since there are systems (HP-UX 10.20) + that have a define for the latter but not the former + + 11/6 + ---- +jobs.c + - cleanup_dead_jobs no longer checks whether the job it is deleting + corresponds to last_asynchronous_pid + - notify_of_job_status and mark_dead_jobs_as_notified now will not + mark the job corresponding to last_asynchronous_pid as notified + if the shell is not interactive + - wait_for_single_pid, if told to wait for last_asynchronous_pid, + or the job of which it is a member, will take care of marking + the job as notified after calling wait_for and collecting the + status. This means that two successive `wait' calls for $! will + succeed the first time and fail the second, as POSIX.2 specifies + (take this code out if it causes problems) + + 11/7 + ---- +jobs.c + - wait_for_job, if told to wait for the job corresponding to the + last async pid, will mark the job as notified after waiting for + it and collecting the status + +general.h + - fixed MEMBER macro to avoid reading past end of S (it used to + test s[1] before s[0], which is an error if s == "") + +subst.c + - expand_word_internal should free ISTRING before returning if + param_expand returns an error + - parameter_brace_expand_word should free the memory it allocates + and passes to param_expand + +execute_cmd.c + - execute_arith_command should call dispose_words on the list + returned by expand_words + +parse.y + - after calling parse_arith_command, read_token needs to free the + string value that parse_arith_command fills in, since make_word + makes a copy of the string it's passed + + 11/10 + ----- +subst.c + - cond_expand_word needs to free the value returned by string_list + after it is run through quote_string_for_globbing + +parse.y + - make sure cond_term frees yylval.word if it is just a `!' and + it's parsed as a term negation operator + +variables.c + - assign_array_var_from_string needs to free the word list returned + by parse_string_to_word_list after calling expand_words_shellexp + on it + +execute_cmd.c + - changed execute_simple_command to avoid saving the_printed_command + into command_line until just before it's needed. This should save + time and prevent memory leaks on errors, but it must be watched + closely to make sure that the_printed_command doesn't change out + from under execute_simple_command before we copy it + + 11/12 + ----- +builtins/alias.def + - alias and unalias should print error messages when passed an + argument that is not an alias for printing or deletion, + respectively, even if the shell is not interactive + +builtins/exit.def + - `logout' will no longer exit a non-login non-interactive shell + + 11/17 + ----- +lib/readline/nls.c + - add `koi8-r' as a legal LANG value + +builtins/alias.def + - if `alias' or `alias -p' is executed when no aliases are defined, + the return status should be 0, according to POSIX.2 + + 11/18 + ----- +subst.c + - changed a couple of calls to make_word_list (make_word(z), ...) + to add_string_to_list (z, ...) + +execute_cmd.c + - execute_cond_command now sets this_command_name to `[[' + + 11/21 + ----- +variables.c + - all_visible_{function,variable}s and the functions they call + should be compiled in only if READLINE is defined + + 11/24 + ----- +aclocal.m4 + - remove some leading whitespace before preprocessor statements in + BASH_KERNEL_RLIMIT_CHECK + +general.[ch] + - fix declarations for group_member so the extern declaration in + general.h agrees with the definition in general.c (fix from + Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>) + +builtins/cd.def + - print the new working directory if the shell is interactive + and `cd -' succeeds + - don't print the new working directory if it's found in $CDPATH + if the shell is not interactive + + 11/25 + ----- +builtins/cd.def + - fixes to bindpwd so that it copes with get_working_directory + returning NULL (bug from schwab@issan.informatik.uni-dortmund.de) + + 12/2 + ---- +support/config.guess + - add support for new OS name for SINIX SVR4 systems + + 12/3 + ---- + +builtins/set.def + - `unset' should check that a function it's trying to unset is a + legal identifier only when in POSIX mode + +redir.c + - changed here_document_to_fd to try and make sure the filename + used for the here document is `more unique', since the old + version would fail if two here documents were created in less + than a second + + 12/4 + ---- +builtins/cd.def + - POSIX.2 says that if CDPATH is used to find the new directory, + and it's not relative to the current directory, the new directory + name should be displayed on stdout even if the shell is not + interactive + + 12/5 + ---- +parse.y + - changes so that `time' is recognized as a reserved word only at + the beginning of a pipeline (the last read token is one of 0, + `;', `\n', `&&', `||', or `&'): + + o add clause to special_case_tokens that does the check + and returns TIME if the conditions are met + o take check for `TIME' out of CHECK_FOR_RESERVED_WORD, but + leave it in the word_token_alist so that `type' still + reports it as a `keyword' + o new function, time_command_acceptable(), encapsulates the + necessary conditions for `time' to be returned as a + reserved word + +[bash-2.02-alpha1 frozen] + + 1/6/98 + ------ +lib/glob/fnmatch.c + - fix define for isgraph so that it does not return success for space + - fix strcompare() so that the call to strcoll is surrounded by + #ifdef HAVE_STRCOLL + + 1/7 + --- +lib/glob/fnmatch.c + - the `test' argument to brackmatch() should be of type `unsigned char' + + 1/11 + ---- +execute_cmd.c + - make sure execute_arith_command sets this_command_name to `((' + + 1/29 + ---- +parse.y + - make sure the code for pushing and popping strings is compiled in + if either ALIAS or DPAREN_ARITHMETIC is defined, because the (( + code uses push_string in the case of a nested subshell + - fix cond_skip_newlines so it resets the prompt to $PS2 while + parsing an unfinished conditional command + +dispose_cmd.c, copy_cmd.c, builtins/hash.def + - fixes to not use `word' as a variable name or the name of a + function parameter to get around stuff in the Cray Unix include + files + +builtins/printf.def + - return failure immediately if an illegal format character is + encountered + +redir.c + - make the code that creates here-documents behave better if the + file it's trying to create already exists for some reason + +lib/readline/complete.c + - changed print_filename to return the number of characters it + outputs; changed callers to use that value. This makes columns + line up when printing completion listings with filenames + containing control characters + +doc/bash.{1,html} + - fixed a typo in the quote removal section + + 1/30 + ---- +parse.y + - free_string_list() needs to check that t->expander is not NULL + before trying to dereference it + - reset_parser() doesn't need to set pushed_string_list to NULL + after calling free_string_list(), since free_string_list does it + +configure.in,cross-build/cygwin32.cache + - fixes from Geoff Noer for better cygwin32 cross-compilation + +tests/printf.{tests,right} + - removed test for integer overflow, since error messages differ + across systems + +pathexp.c + - fixed a problem with unquoted_glob_pattern_p that made things + like `x+*' not expand correctly + +lib/glob/glob.c + - fixed a problem with glob_pattern_p that made things like `x+*' + not expand correctly + +builtins/cd.def + - if `cd -P' is executed, or `set -o physical' has been executed, + the value of $PWD after a successful cd will not contain any + symlinks, regardless of whether or not the shell is in posix mode + + 2/3 + --- +lib/readline/shell.c + - include <string.h> or <strings.h> as appropriate + + 2/4 + --- +builtins/common.c + - take out the code in backslash_quote() that looks for tildes to + quote, for the time being + - if getcwd() fails, get_working_directory now prints the error + message corresponding to errno in addition to the rest of the + information -- TENTATIVE CHANGE + +lib/sh/getcwd.c + - fix from Paul Smith to make getcwd() behave better in the presence + of lstat(2) failures + +stringlib.c + - when copying the replacement string into the output string being + constructed, strsub() needs to make sure enough space for the + replacement string is allocated, not the length of the pattern + (use REPLEN, not PATLEN) + +mailcheck.c + - make sure make_default_mailpath() has a valid current_user struct + before trying to construct the default mailpath + + 2/5 + --- +execute_cmd.c + - execute_builtin needs to call run_unwind_frame if the builtin is + `source' or `eval' and we're not in a subshell rather than just + calling dispose_builtin_env, because not all invocations copy + the temporary_env to builtin_env, and nested calls to `.' require + that the temporary env given to the first persist until that first + call to `.' finishes + +parse.y + - fix to history_delimiting_chars so that function definitions like + + function xyz + { + echo a + } + + are saved to the history correctly when command_oriented_history + is enabled, but literal_history is not + +bashhist.c + - when calling internal_error from pre_process_line, use "%s" as + the format with history_value as the argument to avoid the + problem with the failed history event containing printf escape + sequences + + 2/13 + ---- +shell.c + - if shell_initialized is non-zero, don't line-buffer stderr and + stdout in shell_initialize on SunOS5 -- see if this fixes the + crashing problems for scripts without a leading `#! /bin/sh' + + 2/17 + ---- +bashline.c + - added diffs to _ignore_completion_names from Andreas Schwab to + complete names that would otherwise be ignored with FIGNORE if + they are the only possible completions. Define NO_FORCE_FIGNORE + if you want this; it is not defined by default + + 2/19 + ---- +support/bashbug.sh + - changed the bug-bash address to bug-bash@gnu.org + +examples/loadables/Makefile.in + - converted from `Makefile' with some boilerplate configure variables + to find the source and build directories -- still requires some + hand-editing to get the right CFLAGS and LDFLAGS for shared object + creation + +Makefile.in + - create examples/loadables/Makefile with `make makefiles' + +configure.in + - create examples/loadables directory so `make makefiles' can write a + makefile there + +general.c + - make sure initialize_groups_array always sets things up so that + ${GROUPS[0]} is the user's primary group (current_user.gid) + + 2/20 + ---- +lib/readline/parens.c + - change the time delay when showing matching parens from 1.5 sec to + 0.5 sec + + 2/23 + ---- +shell.c + - isnetconn() should call getpeername(fd,...) instead of using 0 + (though fileno(stdin) should always be 0) + +support/config.guess + - updates from master FSF copy + + 2/24 + ---- +support/man2html.c + - modified version of man2html to convert bash.1 into bash.html + +support/Makefile.in + - simple Makefile to create man2html + +configure.in + - make sure support/Makefile is created + +Makefile.in + - make sure support/Makefile is created and cleaned + +doc/Makefile.in + - changes to suffix rules to say how to make .html from .1 + - `bash.html' is now a makefile target, created by man2html from + bash.1 rather than being hand-modified + +lib/sh/itos.c, general.c + - new file, itos() from general.c. This is here because the + implementation of strerror in lib/sh/strerror.c uses itos() + +Makefile.in, lib/sh/Makefile.in + - changes to add itos.c in libsh.a + +externs.h, general.h + - moved extern declaration of itos() from general.h to externs.h + +aclocal.m4 + - changes to BASH_LARGE_FILE_SUPPORT for the LFS64_* variables in + Solaris 2.6 + +Makefile.in + - make sure configure sets CPPFLAGS in this file + + 2/27 + ---- + +builtins/command.def + - make sure get_standard_path returns the value of + STANDARD_UTILS_PATH if _CS_PATH is defined, but confstr(3) + returns 0, indicating that _CS_PATH does not have a defined + value + +bashhist.c + - fixed bash_history_inhibit_expansion() so that extended globbing + expressions like *.!(c) are not history expanded if extended_glob + is non-zero (shopt -s extglob has been executed) + + 3/2 + --- +Makefile.in + - changed release status to `beta1' + +[bash-2.02-beta1 frozen] + + 3/17 + ---- +lib/readline/vi_mode.c + - make sure _rl_vi_save_insert() gets a non-null UNDO_LIST pointer + before trying to do anything with it + +jobs.c + - add a call to internal_warning from wait_for_job if the job is + stopped + - changed notify_of_job_status to not report pipelines exiting due to + SIGPIPE in non-interactive shells if the shell is compiled with + -DDONT_REPORT_SIGPIPE + +builtins/psize.sh + - some fixes to try to avoid /tmp file races and surreptitious + substitutions + +version.c + - changed the extended version info to show 1998 as the copyright year + +parse.y + - fixes from Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de> + for compilation errors when the shell is configured --disable-alias + but with dparen arithmetic enabled + +eval.c + - fixes from Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de> to + make sure the input stream is popped correctly when performing an + array assignment in the command argument to `bash -c', e.g., + `bash -c 'A=()'' + +builtins/kill.def + - make `kill' with no arguments print a usage message and return a + failure status + +alias.c + - fix so that rd_token doesn't dump core when trying to do alias + expansion on a line containing an unclosed single quote (fix from + Vasco Pedro <vp@di.fct.unl.pt>) + +builtins/cd.def + - fix so that using a non-empty directory from CDPATH to construct + the name of the directory to change to results in an absolute + pathname of the new current working directory being displayed, + as POSIX.2 specifies + +support/bashbug.sh + - a couple of small fixes to minimize /tmp file races -- the script + is still raceable, the window is just smaller + + 3/24 + ---- +variables.c + - make sure assign_in_env passes a malloc'd string to + expand_string_unsplit, because some of the error code assumes that + it is malloc'd and frees it (bug reported by Marko.Makela@HUT.FI) + + 3/25 + ---- +doc/bashref.texi + - changed the email addresses to use the @email texinfo tag + +trap.c + - call reset_parser from the exit trap code before calling + parse_and_execute, so reserved words are parsed correctly + +subst.c + - make sure parameter_brace_patsub expands the pattern string as if + the expression were not in double quotes, even if the entire + expansion is enclosed in double quotes, so that quote removal + on embedded double quotes is performed correctly (bug report from + schwab@issan.informatik.uni-dortmund.de) + + 3/27 + ---- +support/config.guess + - changes to allow Power PCs running Apple's Rhapsody to configure + + 3/31 + ---- + +Makefile.in + - changed release status to `beta2' + +[bash-2.02-beta2 frozen] + + 4/6 + --- +subst.c + - make sure command_substitute does not try to set the terminal's + process group to a background job + +[bash-2.02 frozen] @@ -197,17 +197,20 @@ the Bash `configure' recognizes. `--with-glibc-malloc' Use the GNU libc version of `malloc' in `lib/malloc/gmalloc.c'. - This is somewhat slower than the default `malloc', but wastes - considerably less space. + This is not the version of `malloc' that appears in glibc version + 2, but a modified version of the `malloc' from glibc version 1. + This is somewhat slower than the default `malloc', but wastes less + space on a per-allocation basis, and will return memory to the + operating system under some circumstances. `--with-gnu-malloc' Use the GNU version of `malloc' in `lib/malloc/malloc.c'. This is not the same `malloc' that appears in GNU libc, but an older version derived from the 4.2 BSD `malloc'. This `malloc' is very - fast, but wastes a lot of space. This option is enabled by - default. The `NOTES' file contains a list of systems for which - this should be turned off, and `configure' disables this option - automatically for a number of systems. + fast, but wastes some space on each allocation. This option is + enabled by default. The `NOTES' file contains a list of systems + for which this should be turned off, and `configure' disables this + option automatically for a number of systems. `--with-purify' Define this to use the Purify memory allocation checker from Pure @@ -217,6 +220,17 @@ the Bash `configure' recognizes. This produces a shell with minimal features, close to the historical Bourne shell. +There are several `--enable-' options that alter how Bash is compiled +and linked, rather than changing run-time features. + +`--enable-profiling' + This builds a Bash binary that produces profiling information to be + processed by `gprof' each time it is executed. + +`--enable-static-link' + This causes Bash to be linked statically, if `gcc' is being used. + This could be used to build a version to use as root's shell. + The `minimal-config' option can be used to disable all of the following options, but it is processed first, so individual options may be enabled using `enable-FEATURE'. @@ -244,6 +258,9 @@ does not provide the necessary support. This allows pipelines as well as shell builtins and functions to be timed. +`--enable-cond-command' + Include support for the `[[' conditional command. + `--enable-directory-stack' Include support for a `csh'-like directory stack and the `pushd', `popd', and `dirs' builtins. @@ -257,6 +274,10 @@ does not provide the necessary support. `--enable-dparen-arithmetic' Include support for the `ksh' `((...))' command. +`--enable-extended-glob' + Include support for the extended pattern matching features + described above under *Note Pattern Matching::. + `--enable-help-builtin' Include the `help' builtin, which displays help on shell builtins and variables. @@ -7,6 +7,7 @@ CWRU d CWRU/misc d builtins d +cross-build d doc d examples d examples/bashdb d @@ -25,6 +26,7 @@ lib/posixheaders d lib/readline d lib/readline/doc d lib/readline/examples d +lib/sh d lib/termcap d lib/termcap/grot d lib/tilde d @@ -55,13 +57,11 @@ general.c f list.c f locale.c f stringlib.c f -oslib.c f variables.c f make_cmd.c f copy_cmd.c f unwind_prot.c f dispose_cmd.c f -getcwd.c f bashhist.c f hashcmd.c f hashlib.c f @@ -81,11 +81,12 @@ 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 -vprint.c f error.c f xmalloc.c f alias.h f @@ -97,6 +98,7 @@ array.h f jobs.h f maxpath.h f filecntl.h f +findcmd.h f hashlib.h f quit.h f flags.h f @@ -104,6 +106,7 @@ shell.h f pathexp.h f parser.h f sig.h f +test.h f trap.h f general.h f unwind_prot.h f @@ -121,6 +124,7 @@ bashjmp.h f bashintl.h f make_cmd.h f execute_cmd.h f +redir.h f bashtypes.h f mailcheck.h f pathnames.h f @@ -165,6 +169,7 @@ builtins/history.def f builtins/jobs.def f builtins/kill.def f builtins/mkbuiltins.c f +builtins/printf.def f builtins/pushd.def f builtins/read.def f builtins/reserved.def f @@ -188,12 +193,15 @@ builtins/inlib.def f builtins/bashgetopt.c f builtins/common.h f builtins/bashgetopt.h f +cross-build/cygwin32.cache f +cross-build/win32sig.h f lib/glob/ChangeLog f lib/glob/Makefile.in f lib/glob/fnmatch.c f lib/glob/fnmatch.h f lib/glob/glob.c f lib/glob/glob.h f +lib/glob/collsyms.h f lib/glob/doc/Makefile f lib/glob/doc/glob.texi f lib/glob/ndir.h f @@ -203,6 +211,8 @@ lib/malloc/alloca.c f lib/malloc/malloc.c f lib/malloc/gmalloc.c f lib/malloc/xmalloc.c f +lib/malloc/ogmalloc.c f +lib/malloc/omalloc.c f lib/malloc/stub.c f lib/malloc/i386-alloca.s f lib/malloc/x386-alloca.s f @@ -251,6 +261,7 @@ lib/readline/tilde.h f lib/readline/rldefs.h f lib/readline/rlconf.h f lib/readline/rltty.h f +lib/readline/rlwinsize.h f lib/readline/readline.h f lib/readline/tcap.h f lib/readline/keymaps.h f @@ -275,6 +286,19 @@ lib/readline/examples/histexamp.c f lib/readline/examples/rltest.c f lib/readline/examples/rl.c f lib/readline/examples/Inputrc f +lib/sh/Makefile.in f +lib/sh/clktck.c f +lib/sh/getcwd.c f +lib/sh/getenv.c f +lib/sh/itos.c f +lib/sh/oslib.c f +lib/sh/setlinebuf.c f +lib/sh/strcasecmp.c f +lib/sh/strerror.c f +lib/sh/strtod.c f +lib/sh/strtol.c f +lib/sh/strtoul.c f +lib/sh/vprint.c f lib/termcap/Makefile.in f lib/termcap/termcap.c f lib/termcap/termcap.h f @@ -324,6 +348,8 @@ doc/bashref.texi f doc/bashref.info f doc/builtins.1 f doc/article.ms f +doc/htmlpost.sh f 755 +support/Makefile.in f support/config.guess f support/config.sub f support/printenv.sh f 755 @@ -335,6 +361,7 @@ support/mkdirs f 755 support/mkversion.sh f 755 support/mksignames.c f support/bashbug.sh f +support/man2html.c f support/recho.c f support/zecho.c f support/SYMLINKS f @@ -349,10 +376,9 @@ examples/bashdb/bashdb f examples/bashdb/bashdb.fns f examples/bashdb/bashdb.pre f examples/loadables/README f -examples/loadables/Makefile f +examples/loadables/Makefile.in f examples/loadables/necho.c f examples/loadables/hello.c f -examples/loadables/printf.c f examples/loadables/print.c f examples/loadables/sprintf.c f examples/loadables/sleep.c f @@ -369,127 +395,159 @@ examples/loadables/pathchk.c f examples/loadables/tee.c f examples/loadables/rmdir.c f examples/loadables/head.c f -examples/functions/substr f -examples/functions/kshenv f examples/functions/autoload f examples/functions/autoload.v2 f +examples/functions/basename f +examples/functions/basename2 f examples/functions/csh-compat f -examples/functions/shcat f -examples/functions/substr2 f -examples/functions/term f -examples/functions/whatis f -examples/functions/whence f -examples/functions/func f -examples/functions/dirname f examples/functions/dirfuncs f -examples/functions/basename f +examples/functions/dirname f examples/functions/exitstat f examples/functions/external f examples/functions/fact f -examples/functions/manpage f examples/functions/fstty f -examples/functions/jj.bash f -examples/functions/notify.bash f +examples/functions/func f +examples/functions/getoptx.bash f +examples/functions/inetaddr f examples/functions/inpath f -examples/functions/login f +examples/functions/isnum.bash f +examples/functions/isnum2 f +examples/functions/jdate.bash f +examples/functions/jj.bash f examples/functions/keep f -examples/functions/seq 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/repeat2 f -examples/functions/lowercase f +examples/functions/seq f +examples/functions/shcat f +examples/functions/shcat2 f +examples/functions/substr f +examples/functions/substr2 f +examples/functions/term f +examples/functions/whatis f +examples/functions/whence f examples/functions/xalias.bash f -examples/scripts/shprompt f examples/scripts/adventure.sh f -examples/scripts/precedence f examples/scripts/bcsh.sh f +examples/scripts/fixfiles.bash f +examples/scripts/hanoi.bash f examples/scripts/inpath f +examples/scripts/krand.bash f examples/scripts/nohup.bash f -examples/scripts/vtree2 f -examples/scripts/vtree3 f +examples/scripts/precedence f +examples/scripts/randomcard.bash f examples/scripts/scrollbar f +examples/scripts/scrollbar2 f +examples/scripts/showperm.bash f +examples/scripts/shprompt f examples/scripts/spin.bash f +examples/scripts/timeout f +examples/scripts/vtree2 f +examples/scripts/vtree3 f examples/scripts/zprintf f examples/startup-files/README f -examples/startup-files/Bashrc 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/misc/suncmd.termcap f -examples/misc/alias-conv.sh f -examples/misc/alias-conv.bash f +examples/misc/aliasconv.sh f +examples/misc/aliasconv.bash f examples/misc/cshtobash f tests/README f tests/arith.tests f tests/arith.right f tests/array.tests f tests/array.right f +tests/array-at-star f +tests/array2.right f tests/braces-tests f tests/braces.right f tests/builtins.tests f tests/builtins.right f tests/builtins.sub1 f -tests/source.sub1 f -tests/source.sub2 f -tests/source.sub3 f -tests/source.sub4 f -tests/dirstack.tests f -tests/dirstack.right f -tests/dollar-at.sh f -tests/dollar-star.sh f +tests/source1.sub f +tests/source2.sub f +tests/source3.sub f +tests/source4.sub f +tests/source5.sub f +tests/cond.tests f +tests/cond.right f +tests/dollar-at-star 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/execscript.right f -tests/execscript.sub f 755 -tests/execscript.sub2 f -tests/execscript.sub3 f -tests/execscript.sub4 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/exp-tests f tests/exp.right f +tests/extglob.tests f +tests/extglob.right f tests/func.tests f tests/func.right f tests/getopts.tests f tests/getopts.right f -tests/getopts.sub1 f -tests/getopts.sub2 f -tests/getopts.sub3 f -tests/getopts.sub4 f -tests/getopts.sub5 f -tests/getopts.sub6 f -tests/getopts.sub7 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/histexpand.tests f -tests/histexpand.right f +tests/histexp.tests f +tests/histexp.right f tests/history.tests f tests/history.right f tests/history.list f -tests/ifs-test-1.sh f -tests/ifs-test-2.sh f -tests/ifs-test-3.sh f -tests/ifs.1.right f -tests/ifs.2.right f -tests/ifs.3.right f +tests/ifs-1.test f +tests/ifs-2.test f +tests/ifs-3.test f +tests/ifs-1.right f +tests/ifs-2.right f +tests/ifs-3.right f tests/input-line.sh f tests/input-line.sub f tests/input.right f tests/jobs.tests f +tests/jobs1.sub f +tests/jobs2.sub f tests/jobs.right f tests/more-exp.tests f tests/more-exp.right f tests/new-exp.tests f -tests/new-exp.sub1 f +tests/new-exp1.sub f +tests/new-exp2.sub f tests/new-exp.right f tests/nquote.tests f tests/nquote.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 @@ -511,13 +569,16 @@ tests/run-all f tests/run-minimal f tests/run-arith f tests/run-array f +tests/run-array2 f tests/run-braces f tests/run-builtins f +tests/run-cond f tests/run-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-func f tests/run-getopts f tests/run-glob-test f @@ -531,13 +592,16 @@ tests/run-more-exp f tests/run-new-exp f tests/run-nquote 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-test f +tests/run-set-e f +tests/run-shopt f tests/run-strip f tests/run-test f tests/run-tilde f @@ -546,6 +610,8 @@ tests/run-type f tests/run-varenv f tests/set-e-test f tests/set-e.right f +tests/shopt.tests f +tests/shopt.right f tests/strip.tests f tests/strip.right f tests/test-tests f @@ -554,27 +620,28 @@ tests/tilde-tests f tests/tilde.right f tests/trap.tests f tests/trap.right f -tests/trap.sub1 f 755 +tests/trap1.sub f 755 tests/type.tests f tests/type.right f tests/varenv.right f tests/varenv.sh f tests/version f tests/version.mini f -tests/misc/haertel.perftest f -tests/misc/perf-script f -tests/misc/redir.t2.sh f -tests/misc/run.r2.sh f -tests/misc/sigint.t1.sh f -tests/misc/sigint.t2.sh f -tests/misc/sigint.t3.sh f -tests/misc/sigint.t4.sh f +tests/misc/perftest f +tests/misc/perf-script 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 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 diff --git a/Makefile.in b/Makefile.in index 86596f59..5462426e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# Makefile for bash-2.01, version 2.32 +# Makefile for bash-2.02, version 2.84 # # Make sure the first target in the makefile is the right one all: .made @@ -27,6 +27,7 @@ VPATH = .:@srcdir@ @SET_MAKE@ CC = @CC@ +CC_FOR_BUILD = @CC_FOR_BUILD@ YACC = @YACC@ SHELL=/bin/sh CP = cp @@ -68,12 +69,13 @@ 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= @PROFILE_FLAGS@ # The GNU coding standards don't recognize the possibility that # other information besides optimization and debugging might be # passed to cc. A different name should have been used. CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ LOCAL_CFLAGS = @LOCAL_CFLAGS@ DEFS = @DEFS@ LOCAL_DEFS = @LOCAL_DEFS@ @@ -105,6 +107,27 @@ LIBSRC = $(srcdir)/$(LIBSUBDIR) SUBDIR_INCLUDES = -I. -I$(topdir) -I$(topdir)/$(LIBSUBDIR) -I$(includedir) +# 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 + +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 @@ -240,13 +263,13 @@ BASHPOSIX_SUPPORT = $(BASHPOSIX_LIB)/posixstat.h $(BASHPOSIX_LIB)/ansi_stdlib.h $(BASHPOSIX_LIB)/memalloc.h $(BASHPOSIX_LIB)/stdc.h LIBRARIES = $(READLINE_LIB) $(HISTORY_LIB) $(TERMCAP_LIB) $(GLOB_LIB) \ - $(TILDE_LIB) $(MALLOC_LIB) $(LOCAL_LIBS) + $(TILDE_LIB) $(MALLOC_LIB) $(SHLIB_LIB) $(LOCAL_LIBS) LIBDEP = $(READLINE_DEP) $(TERMCAP_DEP) $(GLOB_DEP) $(HISTORY_DEP) \ - $(TILDE_DEP) $(MALLOC_DEP) + $(TILDE_DEP) $(MALLOC_DEP) $(SHLIB_DEP) LIBRARY_LDFLAGS = $(READLINE_LDFLAGS) $(HISTORY_LDFLAGS) $(TILDE_LDFLAGS) \ - $(GLOB_LDFLAGS) $(MALLOC_LDFLAGS) + $(GLOB_LDFLAGS) $(MALLOC_LDFLAGS) $(SHLIB_LDFLAGS) # # The shell itself @@ -257,9 +280,9 @@ 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 \ - vprint.c input.c bashhist.c array.c sig.c pathexp.c oslib.c \ - unwind_prot.c siglist.c getcwd.c bashline.c bracecomp.c error.c \ - list.c stringlib.c locale.c xmalloc.c + input.c bashhist.c array.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 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 maxpath.h \ @@ -272,6 +295,9 @@ HSOURCES = shell.h flags.h trap.h hashcmd.h hashlib.h jobs.h builtins.h \ 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@ @@ -281,8 +307,7 @@ OBJECTS = shell.o eval.o y.tab.o general.o make_cmd.o print_cmd.o $(GLOBO) \ 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 braces.o bracecomp.o bashhist.o bashline.o \ - getcwd.o siglist.o vprint.o oslib.o list.o stringlib.o \ - locale.o xmalloc.o + siglist.o list.o stringlib.o locale.o findcmd.o redir.o xmalloc.o # Where the source code of the shell builtins resides. BUILTIN_SRCDIR=$(srcdir)/builtins @@ -303,7 +328,7 @@ BUILTIN_DEFS = $(DEFSRC)/alias.def $(DEFSRC)/bind.def $(DEFSRC)/break.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)/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) @@ -317,7 +342,7 @@ BUILTIN_OBJS = $(DEFDIR)/alias.o $(DEFDIR)/bind.o $(DEFDIR)/break.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)/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 \ @@ -342,13 +367,14 @@ SDIR = $(dot)/support/ TESTS_SUPPORT = recho zecho printenv CREATED_SUPPORT = signames.h recho zecho printenv tests/recho tests/zecho \ - tests/printenv mksignames + tests/printenv mksignames lsignames.h CREATED_CONFIGURE = config.h config.cache config.status config.log \ stamp-h CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \ lib/readline/Makefile lib/glob/Makefile \ - lib/tilde/Makefile lib/malloc/Makefile \ - lib/termcap/Makefile + lib/sh/Makefile lib/tilde/Makefile lib/malloc/Makefile \ + lib/termcap/Makefile examples/loadables/Makefile \ + support/Makefile # Keep GNU Make from exporting the entire environment for small machines. .NOEXPORT: @@ -358,7 +384,7 @@ CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \ $(Program): .build $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP) $(RM) $@ - $(PURIFY) $(CC) $(LDFLAGS) $(BUILTINS_LDFLAGS) $(LIBRARY_LDFLAGS) -o $(Program) $(OBJECTS) $(LIBS) + $(PURIFY) $(CC) $(BUILTINS_LDFLAGS) $(LIBRARY_LDFLAGS) $(LDFLAGS) -o $(Program) $(OBJECTS) $(LIBS) ls -l $(Program) size $(Program) @@ -432,13 +458,24 @@ $(TERMCAP_LIBRARY): config.h ${TERMCAP_SOURCE} @(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) ${SHLIB_LIBNAME}) || exit 1 + mksignames: $(SUPPORT_SRC)mksignames.c $(CC) $(CCFLAGS) $(CPPFLAGS) -o $@ $(SUPPORT_SRC)mksignames.c -signames.h: mksignames +# make a list of signals for the local system -- this is done when we're +# *not* cross-compiling +lsignames.h: mksignames $(RM) $@ ./mksignames $@ +# copy the correct signames header file to signames.h +signames.h: $(SIGNAMES_H) + -if cmp -s $(SIGNAMES_H) $@ ; then :; else $(RM) $@ ; $(CP) $(SIGNAMES_H) $@ ; fi + $(BUILTINS_LIBRARY): $(BUILTIN_DEFS) $(BUILTIN_C_SRC) config.h memalloc.h @(cd $(DEFDIR) && $(MAKE) $(MFLAGS) libbuiltins.a ) || exit 1 @@ -587,7 +624,7 @@ test tests check: force $(Program) $(TESTS_SUPPORT) @-test -d tests || mkdir tests @cp $(TESTS_SUPPORT) tests @( cd $(srcdir)/tests && \ - PATH=$$PATH:$(BUILD_DIR)/tests THIS_SH=$(THIS_SH) sh ${TESTSCRIPT} ) + PATH=$$PATH:$(BUILD_DIR)/tests THIS_SH=$(THIS_SH) $(SHELL) ${TESTSCRIPT} ) symlinks: $(SHELL) $(SUPPORT_SRC)fixlinks -s $(srcdir) @@ -633,8 +670,6 @@ dispose_cmd.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h dispose_cmd.o: error.h general.h bashtypes.h variables.h array.h hashlib.h dispose_cmd.o: quit.h maxpath.h unwind_prot.h dispose_cmd.h dispose_cmd.o: make_cmd.h subst.h sig.h pathnames.h externs.h -getcwd.o: config.h bashtypes.h bashansi.h -getcwd.o: maxpath.h posixstat.h posixdir.h memalloc.h error.o: config.h bashtypes.h bashansi.h ansi_stdlib.h flags.h stdc.h error.h error.o: command.h general.h externs.h input.h bashhist.h eval.o: config.h bashansi.h ansi_stdlib.h trap.h flags.h ${DEFSRC}/common.h @@ -649,13 +684,18 @@ execute_cmd.o: general.h bashtypes.h variables.h array.h hashlib.h execute_cmd.o: quit.h 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: memalloc.h ${GRAM_H} flags.h builtins.h jobs.h quit.h siglist.h -execute_cmd.o: execute_cmd.h trap.h pathexp.h $(DEFSRC)/common.h -execute_cmd.o: ${DEFDIR}/builtext.h ${GLOB_LIBSRC}/fnmatch.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}/fnmatch.h expr.o: config.h bashansi.h ansi_stdlib.h expr.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h error.h expr.o: general.h bashtypes.h variables.h array.h hashlib.h expr.o: quit.h maxpath.h unwind_prot.h dispose_cmd.h expr.o: make_cmd.h subst.h sig.h pathnames.h externs.h +findcmd.o: config.h bashtypes.h filecntl.h posixstat.h bashansi.h +findcmd.o: ansi_stdlib.h memalloc.h shell.h bashjmp.h posixjmp.h command.h +findcmd.o: stdc.h error.h general.h variables.h quit.h 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 flags.o: config.h flags.h flags.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h error.h flags.o: general.h bashtypes.h variables.h array.h hashlib.h @@ -670,7 +710,7 @@ general.o: maxpath.h hashcmd.o: config.h posixstat.h bashtypes.h bashansi.h ansi_stdlib.h hashcmd.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h error.h hashcmd.o: general.h bashtypes.h variables.h array.h hashcmd.h -hashcmd.o: execute_cmd.h stdc.h +hashcmd.o: execute_cmd.h findcmd.h stdc.h hashlib.o: config.h bashansi.h ansi_stdlib.h hashlib.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h error.h hashlib.o: general.h bashtypes.h variables.h array.h hashlib.h @@ -697,11 +737,6 @@ make_cmd.o: config.h bashtypes.h filecntl.h bashansi.h make_cmd.o: command.h stdc.h general.h error.h flags.h make_cmd.h make_cmd.o: variables.h array.h hashlib.h subst.h input.h externs.h make_cmd.o: jobs.h quit.h siglist.h -oslib.o: config.h bashtypes.h posixstat.h filecntl.h bashansi.h maxpath.h -oslib.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h error.h -oslib.o: general.h bashtypes.h variables.h array.h hashlib.h -oslib.o: quit.h maxpath.h unwind_prot.h dispose_cmd.h -oslib.o: make_cmd.h subst.h sig.h pathnames.h externs.h y.tab.o: config.h bashtypes.h bashansi.h ansi_stdlib.h memalloc.h y.tab.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h error.h y.tab.o: general.h bashtypes.h variables.h array.h hashlib.h @@ -722,13 +757,18 @@ print_cmd.o: general.h bashtypes.h variables.h array.h hashlib.h print_cmd.o: quit.h 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 posixstat.h bashansi.h ansi_stdlib.h filecntl.h +redir.o: memalloc.h shell.h bashjmp.h posixjmp.h command.h stdc.h error.h +redir.o: general.h variables.h array.h hashlib.h quit.h 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 posixstat.h bashansi.h ansi_stdlib.h filecntl.h shell.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h error.h shell.o: general.h bashtypes.h variables.h array.h hashlib.h shell.o: quit.h 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 bashhist.h +shell.o: jobs.h siglist.h input.h execute_cmd.h findcmd.h bashhist.h shell.o: ${GLOB_LIBSRC}/fnmatch.h sig.o: config.h bashtypes.h sig.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h error.h @@ -754,7 +794,7 @@ test.o: bashtypes.h posixstat.h filecntl.h test.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h error.h test.o: general.h bashtypes.h variables.h array.h hashlib.h test.o: quit.h maxpath.h unwind_prot.h dispose_cmd.h -test.o: make_cmd.h subst.h sig.h pathnames.h externs.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 ansi_stdlib.h trap.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h error.h @@ -769,10 +809,9 @@ variables.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h error.h variables.o: general.h bashtypes.h variables.h array.h hashlib.h variables.o: quit.h maxpath.h unwind_prot.h dispose_cmd.h variables.o: make_cmd.h subst.h sig.h pathnames.h externs.h -varibales.o: flags.h execute_cmd.h mailcheck.h input.h $(DEFSRC)/common.h -variables.o: bashhist.h +variables.o: flags.h execute_cmd.h mailcheck.h input.h $(DEFSRC)/common.h +variables.o: findcmd.h bashhist.h version.o: version.h .build -vprint.o: config.h xmalloc.o: config.h bashtypes.h ansi_stdlib.h error.h # job control @@ -819,7 +858,7 @@ bashline.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h error.h bashline.o: general.h bashtypes.h variables.h array.h hashlib.h bashline.o: quit.h 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 pathexp.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 bracecomp.o: config.h bashansi.h ansi_stdlib.h bracecomp.o: shell.h config.h bashjmp.h posixjmp.h command.h stdc.h error.h @@ -929,7 +968,7 @@ builtins/exec.o: bashtypes.h builtins/exec.o: command.h config.h memalloc.h error.h general.h maxpath.h builtins/exec.o: shell.h bashjmp.h posixjmp.h sig.h unwind_prot.h variables.h builtins/exec.o: dispose_cmd.h make_cmd.h subst.h externs.h execute_cmd.h -builtins/exec.o: flags.h quit.h $(DEFSRC)/common.h stdc.h +builtins/exec.o: findcmd.h flags.h quit.h $(DEFSRC)/common.h stdc.h builtins/exit.o: bashtypes.h builtins/exit.o: command.h config.h memalloc.h error.h general.h maxpath.h builtins/exit.o: shell.h bashjmp.h posixjmp.h sig.h unwind_prot.h variables.h quit.h @@ -948,7 +987,7 @@ builtins/getopts.o: command.h config.h memalloc.h error.h general.h maxpath.h builtins/getopts.o: shell.h bashjmp.h posixjmp.h sig.h unwind_prot.h variables.h quit.h builtins/getopts.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h builtins/hash.o: bashtypes.h -builtins/hash.o: builtins.h command.h execute_cmd.h stdc.h $(DEFSRC)/common.h +builtins/hash.o: builtins.h command.h findcmd.h stdc.h $(DEFSRC)/common.h builtins/hash.o: command.h config.h memalloc.h error.h general.h maxpath.h builtins/hash.o: shell.h bashjmp.h posixjmp.h sig.h unwind_prot.h variables.h quit.h builtins/help.o: command.h config.h memalloc.h error.h general.h maxpath.h @@ -973,6 +1012,10 @@ builtins/kill.o: shell.h bashjmp.h posixjmp.h sig.h trap.h unwind_prot.h variabl builtins/let.o: command.h config.h memalloc.h error.h general.h maxpath.h builtins/let.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h builtins/let.o: shell.h bashjmp.h posixjmp.h sig.h unwind_prot.h variables.h +builtins/printf.o: config.h memalloc.h bashjmp.h command.h error.h +builtins/printf.o: general.h quit.h dispose_cmd.h make_cmd.h subst.h +builtins/printf.o: externs.h sig.h pathnames.h shell.h unwind_prot.h +builtins/printf.o: variables.h stdc.h $(DEFSRC)/bashgetopt.h builtins/pushd.o: command.h config.h memalloc.h error.h general.h maxpath.h builtins/pushd.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h builtins/pushd.o: shell.h bashjmp.h posixjmp.h sig.h unwind_prot.h variables.h @@ -1000,13 +1043,15 @@ builtins/shopt.o: shell.h bashjmp.h posixjmp.h unwind_prot.h variables.h maxpath builtins/shopt.o: $(DEFSRC)/common.h $(DEFSRC)/bashgetopt.h builtins/source.o: command.h config.h memalloc.h error.h general.h maxpath.h builtins/source.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h -builtins/source.o: shell.h bashjmp.h posixjmp.h sig.h unwind_prot.h variables.h +builtins/source.o: shell.h bashjmp.h posixjmp.h sig.h unwind_prot.h variables.h +builtins/source.o: findcmd.h builtins/suspend.o: command.h config.h memalloc.h error.h general.h maxpath.h builtins/suspend.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h builtins/suspend.o: shell.h bashjmp.h posixjmp.h sig.h unwind_prot.h variables.h builtins/test.o: command.h config.h memalloc.h error.h general.h maxpath.h builtins/test.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h builtins/test.o: shell.h bashjmp.h posixjmp.h sig.h unwind_prot.h variables.h +builtins/test.o: test.h builtins/times.o: command.h config.h memalloc.h error.h general.h maxpath.h builtins/times.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h stdc.h builtins/times.o: shell.h bashjmp.h posixjmp.h sig.h unwind_prot.h variables.h @@ -1015,7 +1060,7 @@ builtins/trap.o: quit.h $(DEFSRC)/common.h builtins/trap.o: shell.h bashjmp.h posixjmp.h sig.h unwind_prot.h variables.h builtins/trap.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h builtins/type.o: command.h config.h memalloc.h error.h general.h maxpath.h -builtins/type.o: quit.h $(DEFSRC)/common.h execute_cmd.h +builtins/type.o: quit.h $(DEFSRC)/common.h findcmd.h builtins/type.o: shell.h bashjmp.h posixjmp.h sig.h unwind_prot.h variables.h builtins/type.o: dispose_cmd.h make_cmd.h subst.h externs.h stdc.h builtins/ulimit.o: command.h config.h memalloc.h error.h general.h maxpath.h @@ -1,3 +1,122 @@ +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. @@ -137,3 +137,60 @@ being built and linked against, but there is only a stub file in the archive.) /* 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, + <tmc@barnyard.syr.edu>) + + 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 <sys/types.h>, 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. @@ -26,7 +26,8 @@ main() exit(fl != 1); } ], bash_cv_dup2_broken=yes, bash_cv_dup2_broken=no, - AC_MSG_ERROR(cannot check dup2 if cross compiling)) + [AC_MSG_ERROR(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 @@ -128,7 +129,8 @@ main() exit(ok ? 0 : 5); } ], bash_cv_pgrp_pipe=no,bash_cv_pgrp_pipe=yes, - AC_MSG_ERROR(cannot check pgrp synchronization if cross compiling)) + [AC_MSG_ERROR(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 @@ -169,7 +171,8 @@ dnl AC_DEFUN(BASH_RLIMIT_TYPE, [AC_MSG_CHECKING(for size and type of struct rlimit fields) AC_CACHE_VAL(bash_cv_type_rlimit, -[AC_TRY_COMPILE([#include <sys/types.h>], +[AC_TRY_COMPILE([#include <sys/types.h> +#include <sys/resource.h>], [rlim_t xxx;], bash_cv_type_rlimit=rlim_t,[ AC_TRY_RUN([ #include <sys/types.h> @@ -184,7 +187,8 @@ main() #endif exit(1); }], bash_cv_type_rlimit=quad_t, bash_cv_type_rlimit=long, - AC_MSG_ERROR(cannot check quad_t if cross compiling))]) + [AC_MSG_ERROR(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 @@ -207,7 +211,7 @@ AC_CACHE_VAL(bash_cv_decl_under_sys_siglist, #include <unistd.h> #endif], [ char *msg = _sys_siglist[2]; ], bash_cv_decl_under_sys_siglist=yes, bash_cv_decl_under_sys_siglist=no, -AC_MSG_ERROR(cannot check for _sys_siglist[] if cross compiling))])dnl + [AC_MSG_ERROR(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) @@ -232,8 +236,9 @@ main() char *msg = (char *)_sys_siglist[2]; exit(msg == 0); }], -bash_cv_under_sys_siglist=yes, bash_cv_under_sys_siglist=no, -AC_MSG_ERROR(cannot check for _sys_siglist[] if cross compiling))])dnl + bash_cv_under_sys_siglist=yes, bash_cv_under_sys_siglist=no, + [AC_MSG_ERROR(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) @@ -258,8 +263,9 @@ main() char *msg = sys_siglist[2]; exit(msg == 0); }], -bash_cv_sys_siglist=yes, bash_cv_sys_siglist=no, -AC_MSG_ERROR(cannot check for sys_siglist if cross compiling))])dnl + bash_cv_sys_siglist=yes, bash_cv_sys_siglist=no, + [AC_MSG_ERROR(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) @@ -319,7 +325,9 @@ dir = opendir("/tmp/not_a_directory"); unlink("/tmp/not_a_directory"); exit (dir == 0); }], bash_cv_opendir_not_robust=yes,bash_cv_opendir_not_robust=no, - AC_MSG_ERROR(cannot check opendir if cross compiling))]) + [AC_MSG_ERROR(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) @@ -346,8 +354,116 @@ AC_DEFINE(VOID_SIGHANDLER) fi ]) +AC_DEFUN(BASH_TYPE_INT32_T, +[ +if test "X$bash_cv_type_int32_t" = "X"; then +_bash_needmsg=yes +else +AC_MSG_CHECKING(which builtin C type is 32 bits wide) +_bash_needmsg= +fi +AC_CACHE_VAL(bash_cv_type_int32_t, +[AC_TRY_RUN([ +main() +{ +#if SIZEOF_INT == 4 +exit (0); +#else +# if SIZEOF_LONG == 4 +exit (1); +# else +# error cannot find 32 bit type... +# endif +#endif +}], bash_cv_type_int32_t=int, bash_cv_type_int32_t=long, + [AC_MSG_ERROR(cannot check type sizes if cross-compiling -- defaulting to int) + bash_cv_type_int32_t=int] +)]) +if test "X$_bash_needmsg" = "Xyes"; then +AC_MSG_CHECKING(which builtin C type is 32 bits wide) +fi +AC_MSG_RESULT($bash_cv_type_int32_t); +if test "$bash_cv_type_int32_t" = "int"; then +AC_DEFINE(int32_t, int) +else +AC_DEFINE(int32_t, long) +fi +]) + +AC_DEFUN(BASH_TYPE_U_INT32_T, +[ +if test "X$bash_cv_type_u_int32_t" = "X"; then +_bash_needmsg=yes +else +AC_MSG_CHECKING(which unsigned builtin C type is 32 bits wide) +_bash_needmsg= +fi +AC_CACHE_VAL(bash_cv_type_u_int32_t, +[AC_TRY_RUN([ +main() +{ +#if SIZEOF_INT == 4 +exit (0); +#else +# if SIZEOF_LONG == 4 +exit (1); +# else +# error cannot find 32 bit type... +# endif +#endif +}], bash_cv_type_u_int32_t=int, bash_cv_type_u_int32_t=long, + [AC_MSG_ERROR(cannot check type sizes if cross-compiling -- defaulting to int) + bash_cv_type_u_int32_t=int] +)]) +if test "X$_bash_needmsg" = "Xyes"; then +AC_MSG_CHECKING(which unsigned builtin C type is 32 bits wide) +fi +AC_MSG_RESULT($bash_cv_type_u_int32_t); +if test "$bash_cv_type_u_int32_t" = "int"; then +AC_DEFINE(u_int32_t, unsigned int) +else +AC_DEFINE(u_int32_t, unsigned long) +fi +]) + +AC_DEFUN(BASH_TYPE_PTRDIFF_T, +[ +if test "X$bash_cv_type_ptrdiff_t" = "X"; then +_bash_needmsg=yes +else +AC_MSG_CHECKING(which builtin C type is correct for ptrdiff_t) +_bash_needmsg= +fi +AC_CACHE_VAL(bash_cv_type_ptrdiff_t, +[AC_TRY_RUN([ +main() +{ +#if SIZEOF_CHAR_P == SIZEOF_INT +exit (0); +#else +# if SIZEOF_CHAR_P == SIZEOF_LONG +exit (1); +# else +# error cannot find type for pointer arithmetic... +# endif +#endif +}], bash_cv_type_ptrdiff_t=int, bash_cv_type_ptrdiff_t=long, + [AC_MSG_ERROR(cannot check type sizes if cross-compiling -- defaulting to int) + bash_cv_type_ptrdiff_t=int] +)]) +if test "X$_bash_needmsg" = "Xyes"; then +AC_MSG_CHECKING(which builtin C type is correct for ptrdiff_t) +fi +AC_MSG_RESULT($bash_cv_type_ptrdiff_t); +if test "$bash_cv_type_ptrdiff_t" = "int"; then +AC_DEFINE(ptrdiff_t, int) +else +AC_DEFINE(ptrdiff_t, long) +fi +]) + AC_DEFUN(BASH_FUNC_STRSIGNAL, -[AC_MSG_CHECKING([for the existance of strsignal]) +[AC_MSG_CHECKING([for the existence of strsignal]) AC_CACHE_VAL(bash_cv_have_strsignal, [AC_TRY_LINK([#include <sys/types.h> #include <signal.h>], @@ -366,7 +482,7 @@ AC_CACHE_CHECK([for lstat], bash_cv_func_lstat, [AC_TRY_LINK([ #include <sys/types.h> #include <sys/stat.h> -],[ lstat("",(struct stat *)0); ], +],[ 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) @@ -432,7 +548,9 @@ s = getenv("ABCDE"); exit(s == 0); /* force optimizer to leave getenv in */ } ], bash_cv_getenv_redef=yes, bash_cv_getenv_redef=no, -AC_MSG_ERROR(cannot check getenv redefinition if cross compiling))]) + [AC_MSG_ERROR(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) @@ -455,8 +573,10 @@ _bashfunc pf; pf = (_bashfunc) printf; exit(pf == 0); } -],bash_cv_printf_declared=yes, bash_cv_printf_declared=no, -AC_MSG_ERROR(cannot check printf declaration if cross compiling))]) +], bash_cv_printf_declared=yes, bash_cv_printf_declared=no, + [AC_MSG_ERROR(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) @@ -472,8 +592,10 @@ main() long maxfds = ulimit(4, 0L); exit (maxfds == -1L); } -],bash_cv_ulimit_maxfds=yes, bash_cv_ulimit_maxfds=no, -AC_MSG_ERROR(cannot check ulimit if cross compiling))]) +], bash_cv_ulimit_maxfds=yes, bash_cv_ulimit_maxfds=no, + [AC_MSG_ERROR(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) @@ -497,7 +619,7 @@ if test "X$_bash_needmsg" = "Xyes"; then AC_MSG_CHECKING(which library has the termcap functions) fi AC_MSG_RESULT(using $bash_cv_termcap_lib) -if test $bash_cv_termcap_lib = gnutermcap; then +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" @@ -568,7 +690,9 @@ main() exit (popen_called); } ], bash_cv_getcwd_calls_popen=no, bash_cv_getcwd_calls_popen=yes, -AC_MSG_ERROR(cannot check whether getcwd calls popen if cross compiling))]) + [AC_MSG_ERROR(cannot check whether getcwd calls popen if cross compiling -- defaulting to no) + bash_cv_getcwd_calls_popen=no] +)]) AC_MSG_RESULT($bash_cv_getcwd_calls_popen) if test $bash_cv_getcwd_calls_popen = yes; then AC_DEFINE(GETCWD_BROKEN) @@ -690,7 +814,9 @@ main() exit(nsigint != 2); } ], bash_cv_must_reinstall_sighandlers=no, bash_cv_must_reinstall_sighandlers=yes, -AC_MSG_ERROR(cannot check signal handling if cross compiling))]) + [AC_MSG_ERROR(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) @@ -756,9 +882,10 @@ exit(1); #endif exit(0); -}],bash_cv_job_control_missing=present, bash_cv_job_control_missing=missing, - AC_MSG_ERROR(cannot check job control if cross-compiling)) -]) +}], bash_cv_job_control_missing=present, bash_cv_job_control_missing=missing, + [AC_MSG_ERROR(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) @@ -800,9 +927,10 @@ if (fd == -1) close(fd); unlink ("/tmp/sh-np-autoconf"); exit(0); -}],bash_cv_sys_named_pipes=present, bash_cv_sys_named_pipes=missing, - AC_MSG_ERROR(cannot check for named pipes if cross-compiling)) -]) +}], bash_cv_sys_named_pipes=present, bash_cv_sys_named_pipes=missing, + [AC_MSG_ERROR(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) @@ -850,9 +978,10 @@ sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL); siglongjmp(xx, 10); exit(1); #endif -}],bash_cv_func_sigsetjmp=present, bash_cv_func_sigsetjmp=missing, - AC_MSG_ERROR(cannot check for sigsetjmp/siglongjmp if cross-compiling)) -]) +}], bash_cv_func_sigsetjmp=present, bash_cv_func_sigsetjmp=missing, + [AC_MSG_ERROR(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) @@ -872,14 +1001,23 @@ fi ]) AC_DEFUN(BASH_STRUCT_WINSIZE, -[AC_MSG_CHECKING(for struct winsize in sys/ioctl.h) -AC_CACHE_VAL(bash_cv_struct_winsize_in_ioctl, +[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 <sys/types.h> #include <sys/ioctl.h>], [struct winsize x;], - bash_cv_struct_winsize_in_ioctl=yes,bash_cv_struct_winsize_in_ioctl=no)]) -AC_MSG_RESULT($bash_cv_struct_winsize_in_ioctl) -if test $bash_cv_struct_winsize_in_ioctl = yes; then -AC_DEFINE(STRUCT_WINSIZE_IN_SYS_IOCTL) + bash_cv_struct_winsize_header=ioctl_h, + [AC_TRY_COMPILE([#include <sys/types.h> +#include <termios.h>], [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 ]) @@ -1051,16 +1189,16 @@ AC_CACHE_VAL(bash_cv_kernel_rlimit, int f; f = RLIMIT_DATA; ], bash_cv_kernel_rlimit=no, - [AC_TRY_COMPILE([ - #include <sys/types.h> - #define _KERNEL - #include <sys/resource.h> - #undef _KERNEL - ], - [ +[AC_TRY_COMPILE([ +#include <sys/types.h> +#define _KERNEL +#include <sys/resource.h> +#undef _KERNEL +], +[ int f; f = RLIMIT_DATA; - ], bash_cv_kernel_rlimit=yes, bash_cv_kernel_rlimit=no)] +], 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 @@ -1108,10 +1246,99 @@ char *v[]; exit (r1 > 0 && r2 > 0); } ], bash_cv_func_strcoll_broken=yes, bash_cv_func_strcoll_broken=no, - AC_MSG_ERROR(cannot check strcoll if cross compiling)) -]) + [AC_MSG_ERROR(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 ]) + +dnl +dnl If available, use support for large files unless the user specified +dnl one of the CPPFLAGS, LDFLAGS, or LIBS variables (<eggert@twinsun.com> +dnl via GNU patch 2.5) +dnl +AC_DEFUN(BASH_LARGE_FILE_SUPPORT, +[AC_MSG_CHECKING(whether large file support needs explicit enabling) +ac_getconfs='' +ac_result=yes +ac_set='' +ac_shellvars='CPPFLAGS LDFLAGS LIBS' +for ac_shellvar in $ac_shellvars; do + case $ac_shellvar in + CPPFLAGS) ac_lfsvar=LFS_CFLAGS ac_lfs64var=LFS64_CFLAGS ;; + *) ac_lfsvar=LFS_$ac_shellvar ac_lfs64var=LFS64_$ac_shellvar ;; + esac + eval test '"${'$ac_shellvar'+set}"' = set && ac_set=$ac_shellvar + (getconf $ac_lfsvar) >/dev/null 2>&1 || { ac_result=no; break; } + ac_getconf=`getconf $ac_lfsvar` + ac_getconf64=`getconf $ac_lfs64var` + ac_getconfs=$ac_getconfs$ac_getconf\ $ac_getconf64 + eval ac_test_$ac_shellvar="\$ac_getconf\ \$ac_getconf64" +done +case "$ac_result$ac_getconfs" in +yes) ac_result=no ;; +esac +case "$ac_result$ac_set" in +yes?*) ac_result="yes, but $ac_set is already set, so use its settings" +esac +AC_MSG_RESULT($ac_result) +case $ac_result in +yes) + for ac_shellvar in $ac_shellvars; do + eval $ac_shellvar=\$ac_test_$ac_shellvar + done ;; +esac +]) + +dnl +dnl AC_SYS_RESTARTABLE_SYSCALLS tests only for restarted system calls +dnl after a signal handler has been installed with signal(). Since +dnl Bash uses sigaction() if it is available, we need to check whether +dnl or not a signal handler installed with sigaction and SA_RESTART +dnl causes system calls to be restarted after the signal is caught +dnl +AC_DEFUN(BASH_SYS_RESTARTABLE_SYSCALLS, +[AC_REQUIRE([BASH_SIGNAL_CHECK]) +AC_CACHE_CHECK(for restartable system calls with posix sigaction, +bash_cv_sys_restartable_syscalls, +[AC_TRY_RUN( +[/* Exit 0 (true) if wait returns something other than -1, + i.e. the pid of the child, which means that wait was restarted + after getting the signal. */ +#include <sys/types.h> +#include <signal.h> +static int caught = 0; +void ucatch (isig) int isig; { caught = 1; } +main () +{ +#if !defined (_POSIX_VERSION) || !defined (HAVE_POSIX_SIGNALS) + exit (1); +#else + struct sigaction act, oact; + int i, status; + + act.sa_handler = ucatch; + /* Might want to add SA_RESTART here, but bash's set_signal_handler + does not. */ + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + sigemptyset(&oact.sa_mask); + i = fork (); + /* A possible race condition here, but in practice it never happens. */ + if (i == 0) { sleep (3); kill (getppid (), SIGINT); sleep (3); exit (0); } + sigaction(SIGINT, &act, &oact); + status = wait(&i); + if (status == -1) wait(&i); + exit (status == -1); +#endif +} +], bash_cv_sys_restartable_syscalls=yes, bash_cv_sys_restartable_syscalls=no, + AC_MSG_ERROR(cannot check restartable syscalls if cross compiling)) +]) +if test $bash_cv_sys_restartable_syscalls = yes; then + AC_DEFINE(HAVE_RESTARTABLE_SYSCALLS) +fi +]) @@ -24,6 +24,9 @@ #if defined (ALIAS) #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -411,6 +414,12 @@ rd_token (string, start) 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; @@ -13,6 +13,9 @@ #if defined (ARRAY_VARS) #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -151,6 +154,7 @@ ARRAY_ELEMENT *s, *e; } #endif +#ifdef INCLUDE_UNUSED ARRAY_ELEMENT * copy_array_element(ae) ARRAY_ELEMENT *ae; @@ -158,6 +162,7 @@ ARRAY_ELEMENT *ae; return(ae ? new_array_element(element_index(ae), element_value(ae)) : (ARRAY_ELEMENT *) NULL); } +#endif /* * Add a new element with index I and value V to array A (a[i] = v). @@ -248,6 +253,7 @@ arrayind_t i; return((char *) NULL); } +#ifdef TEST_ARRAY /* * Walk the array, calling FUNC once for each element, with the array * element as the argument. @@ -264,6 +270,7 @@ Function *func; for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) (*func)(ae); } +#endif /* * Return a string that is the concatenation of all the elements in A, @@ -23,6 +23,9 @@ #if defined (HISTORY) #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -174,6 +177,10 @@ bash_history_inhibit_expansion (string, i) 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); } @@ -399,7 +406,7 @@ pre_process_line (line, print_changes, addit) if (print_changes) { if (expanded < 0) - internal_error (history_value); + internal_error ("%s", history_value); #if defined (READLINE) else if (hist_verify == 0) #else @@ -461,9 +468,13 @@ maybe_add_history (line) should_add = 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 when - command_oriented_history is enabled. */ + and subsequent lines of a multi-line command (old code did + this only when command_oriented_history is enabled). */ +#if 0 if (command_oriented_history && current_command_line_count > 1) +#else + if (current_command_line_count > 1) +#endif { bash_add_history (line); return; @@ -693,7 +704,7 @@ history_should_ignore (line) else npat = histignore.ignores[i].val; - match = fnmatch (npat, line, 0) != FNM_NOMATCH; + match = fnmatch (npat, line, FNMATCH_EXTFLAG) != FNM_NOMATCH; if (histignore.ignores[i].flags & HIGN_EXPAND) free (npat); @@ -36,6 +36,7 @@ #include "bashhist.h" #include "bashline.h" #include "execute_cmd.h" +#include "findcmd.h" #include "pathexp.h" #include "builtins/common.h" #include <readline/rlconf.h> @@ -55,12 +56,19 @@ extern void bash_brace_completion (); /* Functions bound to keys in Readline for Bash users. */ static void shell_expand_line (); static void display_shell_version (), operate_and_get_next (); -static void history_expand_line (), bash_ignore_filenames (); +static void bash_ignore_filenames (); +static void cleanup_expansion_error (), set_up_new_line (); + +#if defined (BANG_HISTORY) +static int history_expand_line (); +static int tcsh_magic_space (); +#endif /* BANG_HISTORY */ #ifdef ALIAS -static void alias_expand_line (); +static int alias_expand_line (); +#endif +#if defined (BANG_HISTORY) && defined (ALIAS) +static int history_and_alias_expand_line (); #endif -static void history_and_alias_expand_line (); -static void cleanup_expansion_error (), set_up_new_line (); /* Helper functions for Readline. */ static int bash_directory_completion_hook (); @@ -196,9 +204,13 @@ initialize_readline () rl_bind_key_in_map (CTRL('E'), (Function *)shell_expand_line, emacs_meta_keymap); /* Bind up our special shell functions. */ +#ifdef BANG_HISTORY rl_add_defun ("history-expand-line", (Function *)history_expand_line, -1); rl_bind_key_in_map ('^', (Function *)history_expand_line, emacs_meta_keymap); + rl_add_defun ("magic-space", (Function *)tcsh_magic_space, -1); +#endif + #ifdef ALIAS rl_add_defun ("alias-expand-line", (Function *)alias_expand_line, -1); rl_add_defun ("history-and-alias-expand-line", (Function *)history_and_alias_expand_line, -1); @@ -1030,7 +1042,7 @@ command_subst_completion_function (text, state) orig_start = text; if (*text == '`') text++; - else if (*text == '$' && text[1] == '(') + else if (*text == '$' && text[1] == '(') /* ) */ text += 2; start_len = text - orig_start; filename_text = savestring (text); @@ -1173,7 +1185,12 @@ hostname_completion_function (text, state) return ((char *)NULL); } -/* History and alias expand the line. */ +/* 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; @@ -1183,22 +1200,6 @@ history_expand_line_internal (line) new_line = pre_process_line (line, 0, 0); return (new_line == line) ? savestring (line) : new_line; } - -#if defined (ALIAS) -/* Expand aliases in the current readline line. */ -static void -alias_expand_line (ignore) - int ignore; -{ - char *new_line; - - new_line = alias_expand (rl_line_buffer); - - if (new_line) - set_up_new_line (new_line); - else - cleanup_expansion_error (); -} #endif /* There was an error in expansion. Let the preprocessor print @@ -1259,8 +1260,32 @@ set_up_new_line (new_line) } } +#if defined (ALIAS) +/* Expand aliases in the current readline line. */ +static int +alias_expand_line (ignore) + int 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 void +static int history_expand_line (ignore) int ignore; { @@ -1269,13 +1294,35 @@ history_expand_line (ignore) new_line = history_expand_line_internal (rl_line_buffer); if (new_line) - set_up_new_line (new_line); + { + set_up_new_line (new_line); + return (0); + } else - cleanup_expansion_error (); + { + cleanup_expansion_error (); + return (1); + } +} + +/* Expand history substitutions in the current line and then insert a + space wherever set_up_new_line decided to put rl_point. */ +static int +tcsh_magic_space (ignore) + int ignore; +{ + if (history_expand_line (ignore) == 0) + { + rl_insert (1, ' '); + return (0); + } + else + return (1); } +#endif /* History and alias expand the line. */ -static void +static int history_and_alias_expand_line (ignore) int ignore; { @@ -1297,13 +1344,21 @@ history_and_alias_expand_line (ignore) #endif /* ALIAS */ if (new_line) - set_up_new_line (new_line); + { + set_up_new_line (new_line); + return (0); + } else - cleanup_expansion_error (); + { + cleanup_expansion_error (); + return (1); + } } /* History and alias expand the line, then perform the shell word - expansions by calling expand_string. */ + 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 void shell_expand_line (ignore) int ignore; @@ -1369,6 +1424,10 @@ shell_expand_line (ignore) cleanup_expansion_error (); } +/* Define NO_FORCE_FIGNORE if you want to match filenames that would + otherwise be ignored if they are the only possible matches. */ +/* #define NO_FORCE_FIGNORE */ + /* 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 @@ -1393,6 +1452,10 @@ _ignore_completion_names (names, name_func) { char **newnames; int idx, nidx; +#ifdef NO_FORCE_FIGNORE + char **oldnames; + int oidx; +#endif /* 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 @@ -1400,11 +1463,13 @@ _ignore_completion_names (names, name_func) if there is only one completion; it is the completion itself. */ if (names[1] == (char *)0) { +#ifndef NO_FORCE_FIGNORE if ((*name_func) (names[0]) == 0) { free (names[0]); names[0] = (char *)NULL; } +#endif return; } @@ -1413,6 +1478,10 @@ _ignore_completion_names (names, name_func) for (nidx = 1; names[nidx]; nidx++) ; newnames = (char **)xmalloc ((nidx + 1) * (sizeof (char *))); +#ifdef NO_FORCE_FIGNORE + oldnames = (char **)xmalloc ((nidx - 1) * (sizeof (char *))); + oidx = 0; +#endif newnames[0] = names[0]; for (idx = nidx = 1; names[idx]; idx++) @@ -1420,7 +1489,11 @@ _ignore_completion_names (names, name_func) if ((*name_func) (names[idx])) newnames[nidx++] = names[idx]; else +#ifndef NO_FORCE_FIGNORE free (names[idx]); +#else + oldnames[oidx++] = names[idx]; +#endif } newnames[nidx] = (char *)NULL; @@ -1428,12 +1501,22 @@ _ignore_completion_names (names, name_func) /* If none are acceptable then let the completer handle it. */ if (nidx == 1) { +#ifndef NO_FORCE_FIGNORE free (names[0]); names[0] = (char *)NULL; +#else + free (oldnames); +#endif free (newnames); return; } +#ifdef NO_FORCE_FIGNORE + while (oidx) + free (oldnames[--oidx]); + free (oldnames); +#endif + /* If only one is acceptable, copy it to names[0] and return. */ if (nidx == 2) { diff --git a/bracecomp.c b/bracecomp.c index cca8d6ca..f28570f7 100644 --- a/bracecomp.c +++ b/bracecomp.c @@ -28,6 +28,9 @@ #include <stdio.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -25,6 +25,9 @@ #if defined (BRACE_EXPANSION) #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -21,6 +21,9 @@ #include "config.h" #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif diff --git a/builtins/Makefile.in b/builtins/Makefile.in index 73e719d9..2cf5d682 100644 --- a/builtins/Makefile.in +++ b/builtins/Makefile.in @@ -3,6 +3,7 @@ SHELL = /bin/sh RANLIB = @RANLIB@ CC = @CC@ +CC_FOR_BUILD = @CC_FOR_BUILD@ AR = @AR@ RM = rm -f CP = cp @@ -11,13 +12,16 @@ srcdir = @srcdir@ VPATH = .:@srcdir@ topdir = @top_srcdir@ includedir = @includedir@ +BUILD_DIR = @BUILD_DIR@ -PROFILE_FLAGS = +PROFILE_FLAGS = @PROFILE_FLAGS@ CFLAGS = @CFLAGS@ LOCAL_CFLAGS = @LOCAL_CFLAGS@ CPPFLAGS = @CPPFLAGS@ DEFS = @DEFS@ LOCAL_DEFS = @LOCAL_DEFS@ +LDFLAGS = @LDFLAGS@ $(LOCAL_LDFLAGS) $(CFLAGS) +LOCAL_LDFLAGS = @LOCAL_LDFLAGS@ LIBS = @LIBS@ INCLUDES = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(srcdir) @@ -62,7 +66,8 @@ DEFSRC = $(srcdir)/alias.def $(srcdir)/bind.def $(srcdir)/break.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)/reserved.def $(srcdir)/pushd.def $(srcdir)/shopt.def \ + $(srcdir)/printf.def STATIC_SOURCE = common.c evalstring.c evalfile.c getopt.c bashgetopt.c \ getopt.h @@ -74,40 +79,57 @@ OFILES = builtins.o \ exit.o fc.o fg_bg.o hash.o help.o history.o jobs.o kill.o let.o \ pushd.o read.o return.o set.o setattr.o shift.o source.o \ suspend.o test.o times.o trap.o type.o ulimit.o umask.o \ - wait.o getopts.o shopt.o getopt.o bashgetopt.o + wait.o getopts.o shopt.o printf.o getopt.o bashgetopt.o CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h all: $(MKBUILTINS) libbuiltins.a -libbuiltins.a: $(MKBUILTINS) $(OFILES) +libbuiltins.a: $(MKBUILTINS) $(OFILES) builtins.o $(RM) $@ $(AR) cr $@ $(OFILES) -$(RANLIB) $@ builtext.h builtins.c: $(MKBUILTINS) $(DEFSRC) - $(RM) builtext.h builtins.c + @-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) $(DEFSRC) + -noproduction $(DIRECTDEFINE) $(DEFSRC) + @-if cmp -s old-builtext.h builtext.h; then \ + mv old-builtext.h builtext.h; \ + else \ + $(RM) old-builtext.h; \ + fi + @-if cmp -s old-builtins.c builtins.c; then \ + mv old-builtins.c builtins.c; \ + else \ + $(RM) old-builtins.c; \ + fi -mkbuiltins: $(srcdir)/mkbuiltins.c ../config.h - $(CC) $(CCFLAGS) -o $(MKBUILTINS) $(srcdir)/mkbuiltins.c $(LIBS) +mkbuiltins.o: ../config.h +mkbuiltins.o: mkbuiltins.c + $(RM) $@ + $(CC_FOR_BUILD) -c $(CCFLAGS) $< + +mkbuiltins: mkbuiltins.o + $(CC_FOR_BUILD) $(LDFLAGS) -o $(MKBUILTINS) mkbuiltins.o $(LIBS) # 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 +evalstring.o: evalstring.c +evalfile.o: evalfile.c -ulimit.o: ulimit.def ulimit.o: pipesize.h pipesize.h: psize.aux $(SHELL) $(srcdir)/psize.sh > pipesize.h psize.aux: psize.c - $(CC) $(CCFLAGS) -o $@ $(srcdir)/psize.c + $(CC_FOR_BUILD) $(CCFLAGS) -o $@ $(srcdir)/psize.c documentation: builtins.texi @@ -146,6 +168,7 @@ history.o: history.def jobs.o: jobs.def kill.o: kill.def let.o: let.def +printf.o: printf.def pushd.o: pushd.def read.o: read.def return.o: return.def @@ -159,6 +182,7 @@ 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 @@ -274,6 +298,7 @@ exec.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h exec.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/flags.h exec.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h exec.o: $(srcdir)/common.h $(topdir)/execute_cmd.h $(topdir)/maxpath.h +exec.o: $(topdir)/findcmd.h exit.o: $(topdir)/bashtypes.h exit.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h exit.o: $(topdir)/error.h $(topdir)/general.h @@ -302,7 +327,7 @@ getopts.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h getopts.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h getopts.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h hash.o: $(topdir)/builtins.h $(topdir)/command.h $(topdir)/quit.h -hash.o: $(topdir)/execute_cmd.h $(topdir)/hashlib.h +hash.o: $(topdir)/findcmd.h $(topdir)/hashlib.h hash.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h hash.o: $(topdir)/error.h $(topdir)/general.h hash.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h @@ -339,6 +364,12 @@ let.o: $(topdir)/error.h $(topdir)/general.h let.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h let.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h let.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +printf.o: ../config.h $(topdir)/memalloc.h $(topdir)/bashjmp.h +printf.o: $(topdir)/command.h $(topdir)/error.h $(topdir)/general.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: $(topdir)/pathnames.h $(topdir)/shell.h $(topdir)/unwind_prot.h +printf.o: $(topdir)/variables.h $(topdir)/stdc.h $(srcdir)/bashgetopt.h pushd.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h pushd.o: $(topdir)/error.h $(topdir)/general.h pushd.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h @@ -372,7 +403,7 @@ shift.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h shift.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h shift.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h source.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h -source.o: $(topdir)/error.h $(topdir)/general.h +source.o: $(topdir)/error.h $(topdir)/general.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 $(topdir)/maxpath.h source.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h @@ -386,6 +417,7 @@ test.o: $(topdir)/error.h $(topdir)/general.h test.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h test.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/maxpath.h test.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h +test.o: $(topdir)/test.h times.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h times.o: $(topdir)/error.h $(topdir)/general.h times.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h @@ -396,7 +428,7 @@ trap.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/externs.h trap.o: $(topdir)/quit.h $(srcdir)/common.h $(topdir)/maxpath.h trap.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h trap.o: $(topdir)/shell.h $(topdir)/unwind_prot.h $(topdir)/variables.h -trap.o: $(topdir)/execute_cmd.h +trap.o: $(topdir)/findcmd.h type.o: $(topdir)/command.h ../config.h $(topdir)/memalloc.h type.o: $(topdir)/error.h $(topdir)/general.h type.o: $(topdir)/quit.h $(srcdir)/common.h $(topdir)/maxpath.h diff --git a/builtins/alias.def b/builtins/alias.def index 044b44dc..dec72f64 100644 --- a/builtins/alias.def +++ b/builtins/alias.def @@ -37,6 +37,9 @@ $END #if defined (ALIAS) #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -80,12 +83,12 @@ alias_builtin (list) if (list == 0 || pflag) { if (aliases == 0) - return (EXECUTION_FAILURE); + return (EXECUTION_SUCCESS); alias_list = all_aliases (); if (alias_list == 0) - return (EXECUTION_FAILURE); + return (EXECUTION_SUCCESS); for (offset = 0; alias_list[offset]; offset++) print_alias (alias_list[offset]); @@ -118,8 +121,7 @@ alias_builtin (list) print_alias (t); else { - if (interactive) - builtin_error ("`%s' not found", name); + builtin_error ("`%s' not found", name); any_failed++; } } @@ -179,9 +181,7 @@ unalias_builtin (list) remove_alias (alias->name); else { - if (interactive) - builtin_error ("`%s': not an alias", list->word->word); - + builtin_error ("`%s': not an alias", list->word->word); aflag++; } diff --git a/builtins/bashgetopt.c b/builtins/bashgetopt.c index 72ac900a..65b8d087 100644 --- a/builtins/bashgetopt.c +++ b/builtins/bashgetopt.c @@ -161,6 +161,7 @@ reset_internal_getopt () sp = 1; } +#ifdef INCLUDE_UNUSED void report_bad_option () { @@ -171,3 +172,4 @@ report_bad_option () s[2] = '\0'; bad_option (s); } +#endif diff --git a/builtins/bind.def b/builtins/bind.def index 908803a1..6b8ac56b 100644 --- a/builtins/bind.def +++ b/builtins/bind.def @@ -26,7 +26,7 @@ $PRODUCES bind.c $BUILTIN bind $DEPENDS_ON READLINE $FUNCTION bind_builtin -$SHORT_DOC bind [-lpvsPVS] [-m keymap] [-f filename] [-q name] [-r keyseq] [keyseq:readline-function] +$SHORT_DOC bind [-lpvsPVS] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [keyseq:readline-function] Bind a key sequence to a Readline function, or to a macro. The syntax is equivalent to that found in ~/.inputrc, but must be passed as a single argument: bind '"\C-x\C-r": re-read-init-file'. @@ -42,6 +42,7 @@ Arguments we accept: -r keyseq Remove the binding for KEYSEQ. -f filename Read key bindings from FILENAME. -q function-name Query about which keys invoke the named function. + -u function-name Unbind all keys which are bound to the named function. -V List variable names and values -v List variable names and values in a form that can be reused as input. @@ -53,6 +54,9 @@ $END #if defined (READLINE) #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -71,22 +75,24 @@ extern int errno; #include "common.h" static int query_bindings (); +static int unbind_command (); extern int no_line_editing; #define BIND_RETURN(x) do { return_code = x; goto bind_exit; } while (0) -#define LFLAG 0x01 -#define PFLAG 0x02 -#define FFLAG 0x04 -#define VFLAG 0x08 -#define QFLAG 0x10 -#define MFLAG 0x20 -#define RFLAG 0x40 -#define PPFLAG 0x80 -#define VVFLAG 0x100 -#define SFLAG 0x200 -#define SSFLAG 0x400 +#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 int bind_builtin (list) @@ -96,14 +102,14 @@ bind_builtin (list) FILE *old_rl_outstream; Keymap kmap, saved_keymap; int flags, opt; - char *initfile, *map_name, *fun_name, *remove_seq; + char *initfile, *map_name, *fun_name, *unbind_name, *remove_seq; if (no_line_editing) return (EXECUTION_FAILURE); kmap = saved_keymap = (Keymap) NULL; flags = 0; - initfile = map_name = fun_name = remove_seq = (char *)NULL; + initfile = map_name = fun_name = unbind_name = remove_seq = (char *)NULL; return_code = EXECUTION_SUCCESS; if (!bash_readline_initialized) @@ -116,7 +122,7 @@ bind_builtin (list) rl_outstream = stdout; reset_internal_getopt (); - while ((opt = internal_getopt (list, "lvpVPsSf:q:m:r:")) != EOF) + while ((opt = internal_getopt (list, "lvpVPsSf:q:u:m:r:")) != EOF) { switch (opt) { @@ -141,6 +147,10 @@ bind_builtin (list) flags |= QFLAG; fun_name = list_optarg; break; + case 'u': + flags |= UFLAG; + unbind_name = list_optarg; + break; case 'r': flags |= RFLAG; remove_seq = list_optarg; @@ -220,6 +230,9 @@ bind_builtin (list) 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, (Function *)NULL, rl_get_keymap ()) != 0) @@ -253,7 +266,7 @@ query_bindings (name) int j; function = rl_named_function (name); - if (!function) + if (function == 0) { builtin_error ("unknown function name `%s'", name); return EXECUTION_FAILURE; @@ -275,4 +288,21 @@ query_bindings (name) free_array (keyseqs); return EXECUTION_SUCCESS; } + +static int +unbind_command (name) + char *name; +{ + Function *function; + + function = rl_named_function (name); + if (function == 0) + { + builtin_error ("unknown function name `%s'", 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 index 5354ef6f..e99d136a 100644 --- a/builtins/break.def +++ b/builtins/break.def @@ -30,7 +30,10 @@ $END #include <config.h> #if defined (HAVE_UNISTD_H) -#include <unistd.h> +# ifdef _MINIX +# include <sys/types.h> +# endif +# include <unistd.h> #endif #include "../shell.h" diff --git a/builtins/builtin.def b/builtins/builtin.def index 75d25a09..b18960c9 100644 --- a/builtins/builtin.def +++ b/builtins/builtin.def @@ -31,6 +31,9 @@ $END #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif diff --git a/builtins/cd.def b/builtins/cd.def index 4bbad7e1..ef8d8051 100644 --- a/builtins/cd.def +++ b/builtins/cd.def @@ -23,13 +23,18 @@ $PRODUCES cd.c #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif #include "../bashtypes.h" #include "../posixdir.h" #include "../posixstat.h" +#ifndef _MINIX #include <sys/param.h> +#endif #include <stdio.h> @@ -66,11 +71,11 @@ $BUILTIN cd $FUNCTION cd_builtin $SHORT_DOC cd [-PL] [dir] Change the current directory to DIR. The variable $HOME is the -default DIR. The variable $CDPATH defines the search path for +default DIR. The variable CDPATH defines the search path for the directory containing DIR. Alternative directory names in CDPATH are separated by a colon (:). A null directory name is the same as the current directory, i.e. `.'. If DIR begins with a slash (/), -then $CDPATH is not used. If the directory is not found, and the +then CDPATH is not used. If the directory is not found, and the shell option `cdable_vars' is set, then try the word as a variable name. If that variable has a value, then cd to the value of that variable. The -P option says to use the physical directory structure @@ -146,9 +151,10 @@ bindpwd (no_symlinks) needing a remake. */ if (old_anm == 0 && array_needs_making && exported_p (tvar)) { - pwdvar = xmalloc (strlen (dirname) + 5); /* 5 = "PWD" + '=' + '\0' */ + pwdvar = xmalloc (STRLEN (dirname) + 5); /* 5 = "PWD" + '=' + '\0' */ strcpy (pwdvar, "PWD="); - strcpy (pwdvar + 4, dirname); + if (dirname) + strcpy (pwdvar + 4, dirname); add_or_supercede_exported_var (pwdvar, 0); array_needs_making = 0; } @@ -226,6 +232,8 @@ cd_builtin (list) builtin_error ("%s: %s", dirname, strerror (errno)); return (EXECUTION_FAILURE); } + if (interactive) + printf ("%s\n", dirname); } else { @@ -237,6 +245,8 @@ cd_builtin (list) 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 = mkpath (path, dirname, 1); free (path); @@ -248,17 +258,30 @@ cd_builtin (list) if (change_to_directory (temp, no_symlinks)) { - if (temp[0] != '.' || temp[1] != '/') - printf ("%s\n", temp); + /* 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) + printf ("%s\n", the_current_working_directory); free (temp); /* Posix.2 says that after using CDPATH, the resultant value of $PWD will not contain symlinks. */ - return (bindpwd (posixly_correct)); + return (bindpwd (posixly_correct || no_symlinks)); } else free (temp); } + + /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't + try the current directory, so we just punt now with an error + message if POSIXLY_CORRECT is non-zero. */ + if (posixly_correct) + { + builtin_error ("%s: %s", dirname, strerror (ENOENT)); + return (EXECUTION_FAILURE); + } } if (change_to_directory (dirname, no_symlinks)) diff --git a/builtins/command.def b/builtins/command.def index 6e6e5f60..415b6d15 100644 --- a/builtins/command.def +++ b/builtins/command.def @@ -35,6 +35,9 @@ $END #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -179,11 +182,16 @@ get_standard_path () size_t len; len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0); - p = xmalloc ((int)len + 2); - *p = '\0'; - confstr (_CS_PATH, p, len); - return (p); -#else /* !_CSPATH || !HAVE_CONFSTR */ + if (len > 0) + { + p = xmalloc ((int)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 diff --git a/builtins/common.c b/builtins/common.c index 1b820326..696901e0 100644 --- a/builtins/common.c +++ b/builtins/common.c @@ -19,6 +19,9 @@ #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -27,6 +30,8 @@ #include "../posixstat.h" #include <signal.h> +#include <errno.h> + #if defined (PREFER_STDARG) # include <stdarg.h> #else @@ -54,6 +59,10 @@ # include "../bashhist.h" #endif +#if !defined (errno) +extern int errno; +#endif /* !errno */ + extern int no_symbolic_links, interactive, interactive_shell; extern int indirection_level, startup_state, subshell_environment; extern int line_number; @@ -399,11 +408,12 @@ get_working_directory (for_whom) directory = getcwd (the_current_working_directory, PATH_MAX); if (directory == 0) { - fprintf (stderr, "%s: could not get current directory: %s\n", + fprintf (stderr, "%s: could not get current directory: %s: %s\n", (for_whom && *for_whom) ? for_whom : get_name_for_error (), the_current_working_directory[0] ? the_current_working_directory - : bash_getcwd_errstr); + : bash_getcwd_errstr, + strerror (errno)); free (the_current_working_directory); the_current_working_directory = (char *)NULL; @@ -691,8 +701,13 @@ shell_builtin_compare (sbp1, sbp2) void initialize_shell_builtins () { +#ifdef _MINIX + qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin), + (int (*)(const void *, const void *))shell_builtin_compare); +#else qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin), shell_builtin_compare); +#endif } /* **************************************************************** */ @@ -791,10 +806,14 @@ backslash_quote (string) *r++ = '\\'; *r++ = c; break; - case '#': /* comment char */ #if 0 case '~': /* tilde expansion */ + if (s == string || s[-1] == '=' || s[-1] == ':') + *r++ = '\\'; + *r++ = c; + break; #endif + case '#': /* comment char */ if (s == string) *r++ = '\\'; /* FALLTHROUGH */ @@ -827,6 +846,9 @@ contains_shell_metas (string) case '^': case '$': case '`': /* expansion chars */ return (1); + case '~': /* tilde expansion */ + if (s == string || s[-1] == '=' || s[-1] == ':') + return (1); case '#': if (s == string) /* comment char */ return (1); diff --git a/builtins/common.h b/builtins/common.h index eec5444e..f6fa101d 100644 --- a/builtins/common.h +++ b/builtins/common.h @@ -30,77 +30,79 @@ #define SEVAL_INTERACT 0x02 #define SEVAL_NOHIST 0x04 +/* Functions from common.c */ extern void builtin_error __P((const char *, ...)); -extern void builtin_usage (); -extern void bad_option (); - -extern char **make_builtin_argv (); - -extern int get_numeric_arg (); -extern void remember_args (); -extern void no_args (); -extern int no_options (); - -extern int read_octal (); - -extern void push_context (), pop_context (); -extern void push_dollar_vars (), pop_dollar_vars (); -extern void dispose_saved_dollar_vars (); -extern int dollar_vars_changed (); -extern void set_dollar_vars_unchanged (), set_dollar_vars_changed (); +extern void builtin_usage __P((void)); +extern void no_args __P((WORD_LIST *)); +extern void bad_option __P((char *)); +extern int no_options __P((WORD_LIST *)); + +extern char **make_builtin_argv __P((WORD_LIST *, int *)); +extern void remember_args __P((WORD_LIST *, int)); + +extern void push_context __P((void)); +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 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)); +extern int read_octal __P((char *)); /* Keeps track of the current working directory. */ extern char *the_current_working_directory; -extern char *get_working_directory (); -extern void set_working_directory (); +extern char *get_working_directory __P((char *)); +extern void set_working_directory __P((char *)); #if defined (JOB_CONTROL) -extern int get_job_spec (); +extern int get_job_spec __P((WORD_LIST *)); #endif - -extern int display_signal_list (); +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 (); -extern Function *find_shell_builtin (); -extern Function *builtin_address (); -extern Function *find_special_builtin (); - -extern void initialize_shell_builtins (); +extern struct builtin *builtin_address_internal __P((char *, int)); +extern Function *find_shell_builtin __P((char *)); +extern Function *builtin_address __P((char *)); +extern Function *find_special_builtin __P((char *)); +extern void initialize_shell_builtins __P((void)); -extern char *single_quote (); -extern char *double_quote (); -extern char *backslash_quote (); -extern int contains_shell_metas (); +extern char *single_quote __P((char *)); +extern char *double_quote __P((char *)); +extern char *backslash_quote __P((char *)); +extern int contains_shell_metas __P((char *)); /* Functions from set.def */ -extern void initialize_shell_options (); -extern void list_minus_o_opts (); -extern int set_minus_o_option (); -extern int minus_o_option_value (); -extern void reset_shell_options (); +extern void initialize_shell_options __P((int)); +extern void list_minus_o_opts __P((int, int)); +extern int set_minus_o_option __P((int, char *)); +extern int minus_o_option_value __P((char *)); +extern void reset_shell_options __P((void)); /* Functions from shopt.def */ -extern void reset_shopt_options (); +extern void reset_shopt_options __P((void)); /* Functions from type.def */ -extern int describe_command (); +extern int describe_command __P((char *, int, int)); /* Functions from setattr.def */ -extern int set_or_show_attributes (); -extern int show_var_attributes (); -extern int show_name_attributes (); -extern void set_var_attribute (); +extern int set_or_show_attributes __P((WORD_LIST *, int, int)); +extern int show_var_attributes __P((SHELL_VAR *, int, int)); +extern int show_name_attributes __P((char *, int)); +extern void set_var_attribute __P((char *, int, int)); /* Functions from pushd.def */ -extern char *get_dirstack_element (); -extern void set_dirstack_element (); -extern WORD_LIST *get_directory_stack (); +extern char *get_dirstack_from_string __P((char *)); +extern char *get_dirstack_element __P((int, int)); +extern void set_dirstack_element __P((int, int, char *)); +extern WORD_LIST *get_directory_stack __P((void)); /* Functions from evalstring.c */ -extern int parse_and_execute (); -extern void parse_and_execute_cleanup (); +extern int parse_and_execute __P((char *, char *, int)); +extern void parse_and_execute_cleanup __P((void)); /* Functions from evalfile.c */ extern int maybe_execute_file __P((char *, int)); diff --git a/builtins/declare.def b/builtins/declare.def index ae49b66b..3bdca64c 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -57,6 +57,9 @@ $END #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -377,6 +380,18 @@ declare_internal (list, local_var) FREE (var->value); var->value = t; } + + /* 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. */ + if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var)) + { + SHELL_VAR *tv; + tv = bind_variable (var->name, var->value ? var->value : ""); + tv->attributes = var->attributes & ~att_tempvar; + dispose_variable (var); + } } stupidly_hack_special_variables (name); diff --git a/builtins/enable.def b/builtins/enable.def index 049a7f02..61ea1095 100644 --- a/builtins/enable.def +++ b/builtins/enable.def @@ -42,6 +42,9 @@ $END #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif diff --git a/builtins/eval.def b/builtins/eval.def index 62db7127..c37b99a4 100644 --- a/builtins/eval.def +++ b/builtins/eval.def @@ -29,7 +29,10 @@ $END #include <config.h> #if defined (HAVE_UNISTD_H) -#include <unistd.h> +# ifdef _MINIX +# include <sys/types.h> +# endif +# include <unistd.h> #endif #include "../shell.h" diff --git a/builtins/evalfile.c b/builtins/evalfile.c index 3ffccbe4..bb3217d3 100644 --- a/builtins/evalfile.c +++ b/builtins/evalfile.c @@ -75,6 +75,7 @@ _evalfile (filename, flags) int return_val, fd, result, pflags; char *string; struct stat finfo; + size_t file_size; VFunction *errfunc; fd = open (filename, O_RDONLY); @@ -108,20 +109,33 @@ file_error_and_exit: return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); } - string = xmalloc (1 + (int)finfo.st_size); - result = read (fd, string, finfo.st_size); + 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); + } + string = xmalloc (1 + file_size); + result = read (fd, string, file_size); string[result] = '\0'; return_val = errno; close (fd); errno = return_val; - if (result != (int)finfo.st_size) + if (result < 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 (check_binary_file ((unsigned char *)string, (result > 80) ? 80 : result)) { free (string); diff --git a/builtins/evalstring.c b/builtins/evalstring.c index 1a22887d..0063b711 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -19,12 +19,18 @@ #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif #include <stdio.h> #include <signal.h> +#include <errno.h> + +#include "../filecntl.h" #include "../bashansi.h" #include "../shell.h" @@ -33,6 +39,7 @@ #include "../flags.h" #include "../input.h" #include "../execute_cmd.h" +#include "../redir.h" #if defined (HISTORY) # include "../bashhist.h" @@ -40,6 +47,10 @@ #include "common.h" +#if !defined (errno) +extern int errno; +#endif + extern void run_trap_cleanup (); extern int interactive, interactive_shell; @@ -47,10 +58,13 @@ extern int indirection_level, startup_state, subshell_environment; extern int line_number; extern int last_command_exit_value; extern int running_trap; +extern int posixly_correct; extern COMMAND *global_command; int parse_and_execute_level = 0; +static int cat_file (); + /* How to force parse_and_execute () to clean up after itself. */ void parse_and_execute_cleanup () @@ -202,7 +216,23 @@ parse_and_execute (string, from_file, flags) } #endif /* ONESHOT */ - last_result = execute_command_internal + /* See if this is a candidate for $( <file ). */ + if (startup_state == 2 && + subshell_environment == SUBSHELL_COMSUB && + *bash_input.location.string == '\0' && + command->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); @@ -238,3 +268,94 @@ parse_and_execute (string, from_file, flags) return (last_result); } + +/* Write NB bytes from BUF to file descriptor FD, retrying the write if + it is interrupted. We retry three times if we get a zero-length + write. Any other signal causes this function to return prematurely. */ +static int +zwrite (fd, buf, nb) + int fd; + unsigned char *buf; + int nb; +{ + int n, i, nt; + + for (n = nb, nt = 0;;) + { + i = write (fd, buf, n); + if (i > 0) + { + n -= i; + if (n <= 0) + return nb; + } + else if (i == 0) + { + if (++nt > 3) + return (nb - n); + } + else if (errno != EINTR) + return -1; + } +} + +/* 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 lbuf[128], *fn; + int nr, 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 = 0; + while (1) + { + /* Retry the reads on EINTR. Any other error causes a break from the + loop. */ + while ((nr = read (fd, lbuf, sizeof(lbuf))) < 0 && errno == EINTR) + ; + if (nr == 0) + break; + else if (nr < 0) + { + rval = -1; + break; + } + if (zwrite (1, lbuf, nr) < 0) + { + rval = -1; + break; + } + } + + free (fn); + close (fd); + + return (0); +} diff --git a/builtins/exec.def b/builtins/exec.def index cc7f5a90..4e1394de 100644 --- a/builtins/exec.def +++ b/builtins/exec.def @@ -49,6 +49,7 @@ $END #include "../shell.h" #include "../execute_cmd.h" +#include "../findcmd.h" #if defined (JOB_CONTROL) # include "../jobs.h" #endif diff --git a/builtins/exit.def b/builtins/exit.def index ee02b38d..37f1d7bf 100644 --- a/builtins/exit.def +++ b/builtins/exit.def @@ -75,7 +75,7 @@ int logout_builtin (list) WORD_LIST *list; { - if (login_shell == 0 && interactive) + if (login_shell == 0 /* && interactive */) { builtin_error ("not login shell: use `exit'"); return (EXECUTION_FAILURE); diff --git a/builtins/fc.def b/builtins/fc.def index e88ba122..587d7edd 100644 --- a/builtins/fc.def +++ b/builtins/fc.def @@ -49,10 +49,14 @@ $END #include <config.h> #if defined (HISTORY) -#include <sys/param.h> +#ifndef _MINIX +# include <sys/param.h> +#endif #include "../bashtypes.h" #include "../posixstat.h" -#include <sys/file.h> +#ifndef _MINIX +# include <sys/file.h> +#endif #if defined (HAVE_UNISTD_H) # include <unistd.h> diff --git a/builtins/getopt.c b/builtins/getopt.c index b5f8bc4b..2fbcac73 100644 --- a/builtins/getopt.c +++ b/builtins/getopt.c @@ -20,6 +20,9 @@ #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif diff --git a/builtins/getopts.def b/builtins/getopts.def index a9c5116e..533775af 100644 --- a/builtins/getopts.def +++ b/builtins/getopts.def @@ -61,6 +61,9 @@ $END #include <stdio.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif diff --git a/builtins/hash.def b/builtins/hash.def index 813cb035..f601c10d 100644 --- a/builtins/hash.def +++ b/builtins/hash.def @@ -35,6 +35,8 @@ $END #include <stdio.h> +#include "../bashtypes.h" + #if defined (HAVE_UNISTD_H) # include <unistd.h> #endif @@ -43,8 +45,8 @@ $END #include "../shell.h" #include "../builtins.h" -#include "../execute_cmd.h" #include "../flags.h" +#include "../findcmd.h" #include "../hashcmd.h" #include "common.h" #include "bashgetopt.h" @@ -63,7 +65,7 @@ hash_builtin (list) WORD_LIST *list; { int expunge_hash_table, opt; - char *word, *pathname; + char *w, *pathname; if (hashing_enabled == 0) { @@ -107,12 +109,12 @@ hash_builtin (list) for (opt = EXECUTION_SUCCESS; list; list = list->next) { /* Add or rehash the specified commands. */ - word = list->word->word; + w = list->word->word; if (pathname) - remember_filename (word, pathname, 0, 0); - else if (absolute_program (word)) + remember_filename (w, pathname, 0, 0); + else if (absolute_program (w)) continue; - else if (add_hashed_command (word, 0)) + else if (add_hashed_command (w, 0)) opt = EXECUTION_FAILURE; } @@ -121,23 +123,23 @@ hash_builtin (list) } static int -add_hashed_command (word, quiet) - char *word; +add_hashed_command (w, quiet) + char *w; int quiet; { int rv; char *full_path; rv = 0; - if (find_function (word) == 0 && find_shell_builtin (word) == 0) + if (find_function (w) == 0 && find_shell_builtin (w) == 0) { - full_path = find_user_command (word); + full_path = find_user_command (w); if (full_path && executable_file (full_path)) - remember_filename (word, full_path, dot_found_in_search, 0); + remember_filename (w, full_path, dot_found_in_search, 0); else { if (quiet == 0) - builtin_error ("%s: not found", word); + builtin_error ("%s: not found", w); rv++; } if (full_path) diff --git a/builtins/help.def b/builtins/help.def index 9c479103..cd59d3c3 100644 --- a/builtins/help.def +++ b/builtins/help.def @@ -36,11 +36,15 @@ $END #include <stdio.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif #include "../shell.h" #include "../builtins.h" +#include "../pathexp.h" #include "bashgetopt.h" #include <glob/fnmatch.h> @@ -100,7 +104,7 @@ help_builtin (list) { QUIT; if ((strncmp (pattern, name, plen) == 0) || - (fnmatch (pattern, name, 0) != FNM_NOMATCH)) + (fnmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH)) { printf ("%s: %s\n", name, shell_builtins[i].short_doc); diff --git a/builtins/history.def b/builtins/history.def index b1e3ab39..92094d68 100644 --- a/builtins/history.def +++ b/builtins/history.def @@ -46,7 +46,9 @@ $END #if defined (HISTORY) #include "../bashtypes.h" -#include <sys/file.h> +#ifndef _MINIX +# include <sys/file.h> +#endif #include "../posixstat.h" #include "../filecntl.h" #include <errno.h> diff --git a/builtins/jobs.def b/builtins/jobs.def index 2c818af5..4cc9b77b 100644 --- a/builtins/jobs.def +++ b/builtins/jobs.def @@ -205,11 +205,12 @@ execute_list_with_replacements (list) $BUILTIN disown $FUNCTION disown_builtin $DEPENDS_ON JOB_CONTROL -$SHORT_DOC disown [-h] [jobspec ...] +$SHORT_DOC disown [-h] [-ar] [jobspec ...] By default, removes each JOBSPEC argument from the table of active jobs. If the -h option is given, the job is not removed from the table, but is marked so that SIGHUP is not sent to the job if the shell receives a -SIGHUP. +SIGHUP. The -a option, when JOBSPEC is not supplied, means to remove all +jobs from the job table; the -r option means to remove only running jobs. $END #if defined (JOB_CONTROL) @@ -217,18 +218,24 @@ int disown_builtin (list) WORD_LIST *list; { - int opt, job, retval, nohup_only; + int opt, job, retval, nohup_only, running_jobs, all_jobs; sigset_t set, oset; - nohup_only = 0; + nohup_only = running_jobs = all_jobs = 0; reset_internal_getopt (); - while ((opt = internal_getopt (list, "h")) != -1) + 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); @@ -237,17 +244,15 @@ disown_builtin (list) list = loptend; retval = EXECUTION_SUCCESS; -#if 0 - /* For the future `disown -a' */ - if (list == 0) + /* `disown -a' or `disown -r' */ + if (list == 0 && (all_jobs || running_jobs)) { if (nohup_only) - nohup_all_jobs (); + nohup_all_jobs (running_jobs); else - delete_all_jobs (); + delete_all_jobs (running_jobs); return (EXECUTION_SUCCESS); } -#endif do { @@ -256,7 +261,7 @@ disown_builtin (list) ? get_job_by_pid (atoi(list->word->word), 0) : get_job_spec (list); - if (job == NO_JOB || jobs == 0 || jobs[job] == 0) + if (job == NO_JOB || jobs == 0 || job < 0 || job >= job_slots || jobs[job] == 0) { builtin_error ("%s: no such job", list ? list->word->word : "current"); retval = EXECUTION_FAILURE; @@ -264,7 +269,7 @@ disown_builtin (list) else if (nohup_only) nohup_job (job); else - delete_job (job); + delete_job (job, 1); UNBLOCK_CHILD (oset); if (list) diff --git a/builtins/kill.def b/builtins/kill.def index ea78bd52..6efb37b3 100644 --- a/builtins/kill.def +++ b/builtins/kill.def @@ -39,6 +39,9 @@ $END #include <stdio.h> #include <errno.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -77,7 +80,10 @@ kill_builtin (list) pid_t pid; if (list == 0) - return (EXECUTION_SUCCESS); + { + builtin_usage (); + return (EXECUTION_FAILURE); + } any_succeeded = listing = saw_signal = 0; signal = SIGTERM; @@ -145,6 +151,12 @@ kill_builtin (list) return (EXECUTION_FAILURE); } + if (list == 0) + { + builtin_usage (); + return (EXECUTION_FAILURE); + } + while (list) { word = list->word->word; @@ -152,7 +164,7 @@ kill_builtin (list) if (*word == '-') word++; - if (all_digits (word)) + if (*word && all_digits (word)) { /* Use the entire argument in case of minus sign presence. */ pid = (pid_t) atoi (list->word->word); @@ -162,12 +174,12 @@ kill_builtin (list) else any_succeeded++; } - else if (*list->word->word != '%') + else if (*list->word->word && *list->word->word != '%') { builtin_error ("%s: no such pid", list->word->word); CONTINUE_OR_FAIL; } - else if (interactive || job_control) + else if (*word && (interactive || job_control)) /* Posix.2 says you can kill without job control active (4.32.4) */ { /* Must be a job spec. Check it out. */ int job; @@ -208,7 +220,7 @@ kill_builtin (list) } else { - builtin_error ("`%s' is not a pid or valid job spec", list->word->word); + builtin_error ("`%s': not a pid or valid job spec", list->word->word); CONTINUE_OR_FAIL; } continue_killing: diff --git a/builtins/let.def b/builtins/let.def index b7479623..fd037cd9 100644 --- a/builtins/let.def +++ b/builtins/let.def @@ -63,6 +63,9 @@ $END #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif diff --git a/builtins/mkbuiltins.c b/builtins/mkbuiltins.c index 983bada8..8cd27039 100644 --- a/builtins/mkbuiltins.c +++ b/builtins/mkbuiltins.c @@ -22,18 +22,20 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif +#ifndef _MINIX #include "../bashtypes.h" #include <sys/file.h> +#endif + #include "../posixstat.h" #include "../filecntl.h" -#if defined (HAVE_UNISTD_H) -# include <unistd.h> -#endif /* HAVE_UNISTD_H */ - #include "../bashansi.h" #include <stdio.h> @@ -437,8 +439,9 @@ extract_info (filename, structfile, externfile) register int i; DEF_FILE *defs; struct stat finfo; + size_t file_size; char *buffer, *line; - int fd; + int fd, nr; if (stat (filename, &finfo) == -1) file_error (filename); @@ -448,13 +451,20 @@ extract_info (filename, structfile, externfile) if (fd == -1) file_error (filename); - buffer = xmalloc (1 + (int)finfo.st_size); + file_size = (size_t)finfo.st_size; + buffer = xmalloc (1 + file_size); - if (read (fd, buffer, finfo.st_size) != finfo.st_size) + if ((nr = read (fd, buffer, file_size)) < 0) file_error (filename); 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; @@ -466,11 +476,11 @@ extract_info (filename, structfile, externfile) /* Build the array of lines. */ i = 0; - while (i < finfo.st_size) + while (i < file_size) { array_add (&buffer[i], defs->lines); - while (buffer[i] != '\n' && i < finfo.st_size) + while (buffer[i] != '\n' && i < file_size) i++; buffer[i++] = '\0'; } @@ -676,7 +686,10 @@ current_builtin (directive, defs) DEF_FILE *defs; { must_be_building (directive, defs); - return ((BUILTIN_DESC *)defs->builtins->array[defs->builtins->sindex - 1]); + 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. @@ -756,6 +769,11 @@ function_handler (self, defs, arg) 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); diff --git a/builtins/printf.def b/builtins/printf.def new file mode 100644 index 00000000..43ccb56e --- /dev/null +++ b/builtins/printf.def @@ -0,0 +1,693 @@ +This file is printf.def, from which is created printf.c. +It implements the builtin "printf" in Bash. + +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 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + +$PRODUCES printf.c + +$BUILTIN printf +$FUNCTION printf_builtin +$SHORT_DOC printf format [arguments] +printf formats and prints ARGUMENTS under control of the FORMAT. FORMAT +is a character string which contains three types of objects: plain +characters, which are simply copied to standard output, character escape +sequences which are converted and copied to the standard output, and +format specifications, each of which causes printing of the next successive +argument. In addition to the standard printf(1) formats, %b means to +expand backslash escape sequences in the corresponding argument, and %q +means to quote the argument in a way that can be reused as shell input. +$END + +#include <config.h> + +#include "../bashtypes.h" + +#include <errno.h> +#if defined (HAVE_LIMITS_H) +# include <limits.h> +#else + /* Assume 32-bit ints and longs. */ +# define LONG_MAX 2147483647L +# define LONG_MIN (-2147483647L-1) +# define INT_MAX 2147483647 +# define INT_MIN (-2147483647-1) +#endif + +#include <stdio.h> +#include <ctype.h> + +#include "../bashansi.h" +#include "../shell.h" +#include "../stdc.h" +#include "bashgetopt.h" + +#if !defined (errno) +extern int errno; +#endif + +#define PF(f, func) \ + do { \ + if (fieldwidth && precision) \ + (void)printf(f, fieldwidth, precision, func); \ + else if (fieldwidth && precision == 0) \ + (void)printf(f, fieldwidth, func); \ + else if (precision) \ + (void)printf(f, precision, func); \ + else \ + (void)printf(f, func); \ + } while (0) + +#define PRETURN(value) \ + do { free (format); fflush (stdout); return (value); } while (0) + +#define SKIP1 "#-+ 0" +#define SKIP2 "*0123456789" + +static void printstr __P((char *, char *, int, int, int)); +static char *bexpand __P((char *, int, int *, int *)); +static char *mklong __P((char *, int)); +static int getchr __P((void)); +static char *getstr __P((void)); +static int getint __P((void)); +static int getlong __P((long *)); +static int getulong __P((unsigned long *)); +static double getdouble __P((void)); +static int asciicode __P((void)); + +static WORD_LIST *garglist; +static int retval; + +extern char *backslash_quote (); + +int +printf_builtin (list) + WORD_LIST *list; +{ + int ch, end, fieldwidth, precision, foundmod; + char convch, nextch, *format, *fmt, *start; + + retval = EXECUTION_SUCCESS; + reset_internal_getopt (); + while ((ch = internal_getopt (list, "")) != -1) + { + switch (ch) + { + case '?': + default: + builtin_usage(); + return (EX_USAGE); + } + } + list = loptend; + + if (list == 0) + { + builtin_usage (); + return (EX_USAGE); + } + + if (list->word->word == 0 || list->word->word[0] == '\0') + return (EXECUTION_SUCCESS); + + format = ansicstr (list->word->word, strlen (list->word->word), (int *)NULL, (int *)NULL); + + garglist = list->next; + + /* 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 + { + /* find next format specification */ + for (fmt = format; *fmt; fmt++) + { + precision = fieldwidth = foundmod = 0; + + if (*fmt != '%') + { + putchar (*fmt); + continue; + } + + /* ASSERT(*fmt == '%') */ + start = fmt++; + + if (*fmt == '%') /* %% prints a % */ + { + putchar ('%'); + continue; + } + + /* found format specification, skip to field width */ + for (; *fmt && strchr(SKIP1, *fmt); ++fmt) + ; + fieldwidth = (*fmt == '*') ? getint () : 0; + + /* skip to possible '.', get following precision */ + for (; *fmt && strchr(SKIP2, *fmt); ++fmt) + ; + if (*fmt == '.') + { + ++fmt; + precision = (*fmt == '*') ? getint () : 0; + } + + /* skip to conversion char */ + for (; *fmt && strchr(SKIP2, *fmt); ++fmt) + ; + if (*fmt == 0) + { + builtin_error ("`%s': missing format character", start); + PRETURN (EXECUTION_FAILURE); + } + + /* skip possible format modifiers */ + if (*fmt == 'l' || *fmt == 'L' || *fmt == 'h') + { + fmt++; + foundmod = 1; + } + + convch = *fmt; + nextch = fmt[1]; + fmt[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 'b': /* expand escapes in argument */ + { + char *p, *xp; + int rlen; + + p = getstr (); + ch = rlen = 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. */ + printstr (start, xp, rlen, fieldwidth, precision); + free (xp); + } + + if (ch) + PRETURN (retval); + break; + } + + case 'q': /* print with shell quoting */ + { + char *p, *xp; + + p = getstr (); + xp = backslash_quote (p); + if (xp) + { + /* Use printstr to get fieldwidth and precision right. */ + printstr (start, xp, strlen (xp), fieldwidth, precision); + free (xp); + } + break; + } + + case 'd': + case 'i': + { + long p; + char *f; + + if (foundmod == 0 && ((f = mklong (start, convch)) == NULL)) + PRETURN (EXECUTION_FAILURE); + else + f = start; + if (getlong (&p)) + PRETURN (EXECUTION_FAILURE); + PF(f, p); + break; + } + + case 'o': + case 'u': + case 'x': + case 'X': + { + unsigned long p; + char *f; + + if (foundmod == 0 && ((f = mklong (start, convch)) == NULL)) + PRETURN (EXECUTION_FAILURE); + else + f = start; + if (getulong (&p)) + PRETURN (EXECUTION_FAILURE); + PF (f, p); + break; + } + + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + { + double p; + + p = getdouble (); + PF(start, p); + break; + } + + /* We output unrecognized format characters, but we print a + warning message and return a failure exit status. */ + default: + builtin_error ("`%c': illegal format character", convch); + PRETURN (EXECUTION_FAILURE); + } + + fmt[1] = nextch; + } + } + while (garglist); + + PRETURN (retval); +} + +/* We duplicate a lot of what printf(3) does here. */ +static void +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 (string == 0 || *string == '\0') + return; + +#if 0 + s = fmt; +#endif + if (*fmt == '%') + fmt++; + + ljust = fw = pr = 0; + + /* skip flags */ + while (*fmt == '#' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '0') + { + if (*fmt == '-') + ljust = 1; + fmt++; + } + + /* get fieldwidth, if present */ + if (*fmt == '*') + { + fmt++; + fw = fieldwidth; + } + else if (isdigit (*fmt)) + { + fw = *fmt++ - '0'; + while (isdigit (*fmt)) + fw = (fw * 10) + (*fmt++ - '0'); + } + + /* get precision, if present */ + if (*fmt == '.') + { + fmt++; + if (*fmt == '*') + { + fmt++; + pr = precision; + } + else if (isdigit (*fmt)) + { + pr = *fmt++ - '0'; + while (isdigit (*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--) + putchar (' '); + + /* output NC characters from STRING */ + for (i = 0; i < nc; i++) + putchar (string[i]); + + /* output any necessary trailing padding */ + for (; padlen < 0; padlen++) + putchar (' '); +} + +/* Convert STRING by expanding the escape sequences specified by the + POSIX standard for printf's `%b' format string. If SAWC is non-null, + recognize `\c' and use that as a string terminator. If we see \c, set + *SAWC to 1 before returning. LEN is the length of STRING. */ + +#ifdef isoctal +#undef isoctal +#endif + +#define isoctal(c) ((c) >= '0' && (c) <= '7') + +#define OCTVALUE(c) ((c) - '0') + +#ifndef isxdigit +# define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) +#endif + +#define HEXVALUE(c) \ + ((c) >= 'a' && (c) <= 'f' ? (c)-'a'+10 : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0') + +static char * +bexpand (string, len, sawc, lenp) + char *string; + int len, *sawc, *lenp; +{ + int c, temp; + char *ret, *r, *s; + + if (string == 0 || *string == '\0') + { + if (sawc) + *sawc = 0; + if (lenp) + *lenp = 0; + return ((char *)NULL); + } + + ret = xmalloc (len + 1); + for (r = ret, s = string; s && *s; ) + { + c = *s++; + if (c != '\\' || *s == '\0') + { + *r++ = c; + continue; + } + + switch (c = *s++) + { +#if defined (__STDC__) + case 'a': c = '\a'; break; +#else + case 'a': c = '\007'; break; +#endif + + case 'b': c = '\b'; break; + + case 'e': c = '\033'; break; /* ESC -- non-ANSI */ + + case 'f': c = '\f'; break; + + case 'n': c = '\n'; break; + + case 'r': c = '\r'; break; + + case 't': c = '\t'; break; + + case 'v': c = '\v'; break; + + /* %b octal constants are `\0' followed by one, two, or three + octal digits... */ + case '0': + for (temp = 3, c = 0; isoctal (*s) && temp--; s++) + c = (c * 8) + OCTVALUE (*s); + break; + + /* but, as an extension, the other echo-like octal escape + sequences are supported as well. */ + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + for (temp = 2, c -= '0'; isoctal (*s) && temp--; s++) + c = (c * 8) + OCTVALUE (*s); + break; + + /* And, as another extension, we allow \xNNN, where each N is a + hex digit. */ + case 'x': + for (temp = 3, c = 0; isxdigit (*s) && temp--; s++) + c = (c * 16) + HEXVALUE (*s); + if (temp == 3) + { + builtin_error ("missing hex digit for \\x"); + *r++ = '\\'; + c = 'x'; + } + break; + + case '\\': +#if 0 + case '\'': /* XXX */ + case '"': /* XXX */ +#endif + break; + + case 'c': + if (sawc) + *sawc = 1; + *r = '\0'; + if (lenp) + *lenp = r - ret; + return ret; + + /* other backslash escapes are passed through unaltered */ + default: *r++ = '\\'; break; + } + + *r++ = c; + } + + *r = '\0'; + if (lenp) + *lenp = r - ret; + return ret; +} + +static char * +mklong (str, ch) + char *str; + int ch; +{ + static char copy[64]; + int len; + + len = strlen (str) + 2; + FASTCOPY (str, copy, len - 3); + copy[len - 3] = 'l'; + copy[len - 2] = ch; + copy[len - 1] = '\0'; + return (copy); +} + +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 () +{ + long ret; + + if (getlong (&ret)) + return (0); + + if (ret > INT_MAX) + { + builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE)); + return (0); + } + + return ((int)ret); +} + +static int +getlong (lp) + long *lp; +{ + long ret; + + if (garglist == 0) + { + *lp = 0L; + return (0); + } + + if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') + { + *lp = (long)asciicode (); + return (0); + } + + errno = 0; + /* legal_number does not currently detect overflow, but it should. + Someday it will. */ + if (legal_number (garglist->word->word, &ret) == 0) + { + builtin_error ("%s: illegal number", garglist->word->word); + return (1); + } + else if (errno == ERANGE) + { + builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE)); + return (1); + } + + *lp = ret; + garglist = garglist->next; + return (0); +} + +static int +getulong (ulp) + unsigned long *ulp; +{ + unsigned long ret; + char *ep; + + if (garglist == 0) + { + *ulp = (unsigned long)0; + return (0); + } + + if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') + { + *ulp = (unsigned long)asciicode (); + return (0); + } + + errno = 0; + ret = strtoul (garglist->word->word, &ep, 0); + + if (*ep) + { + builtin_error ("%s: illegal number", garglist->word->word); + return (1); + } + else if (errno == ERANGE) + { + builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE)); + return (1); + } + + *ulp = ret; + garglist = garglist->next; + return (0); +} + +static double +getdouble () +{ + double ret; + + if (garglist == 0) + return ((double)0); + + if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') + return ((double)asciicode ()); + + /* This should use strtod if it is available. */ + ret = atof (garglist->word->word); + garglist = garglist->next; + return (ret); +} + +/* NO check is needed for garglist here. */ +static int +asciicode () +{ + register int ch; + + ch = garglist->word->word[1]; + garglist = garglist->next; + return (ch); +} diff --git a/builtins/psize.c b/builtins/psize.c index 6037d7af..596f97fd 100644 --- a/builtins/psize.c +++ b/builtins/psize.c @@ -24,11 +24,16 @@ #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif #include <stdio.h> +#ifndef _MINIX #include "../bashtypes.h" +#endif #include <signal.h> #include <errno.h> diff --git a/builtins/psize.sh b/builtins/psize.sh index 961becd3..84f1f2a4 100755 --- a/builtins/psize.sh +++ b/builtins/psize.sh @@ -3,6 +3,12 @@ # psize.sh -- determine this system's pipe size, and write a define to # pipesize.h so ulimit.c can use it. +TMPDIR=/tmp +TMPNAME=pipsize.$$ +TMPFILE=$TMPDIR/$TMPNAME + +trap 'rm -f $TMPFILE' 0 1 2 3 6 15 + echo "/*" echo " * pipesize.h" echo " *" @@ -11,14 +17,20 @@ echo " * Do not edit!" echo " */" echo "" -./psize.aux 2>/tmp/pipesize | sleep 3 +# +# Try to avoid tempfile races. We can't really check for the file's +# existance before we run psize.aux, because `test -e' is not portable, +# `test -h' (test for symlinks) is not portable, and `test -f' only +# checks for regular files +# +rm -f $TMPFILE + +./psize.aux 2>$TMPFILE | sleep 3 -if [ -s /tmp/pipesize ]; then - echo "#define PIPESIZE `cat /tmp/pipesize`" +if [ -s $TMPFILE ]; then + echo "#define PIPESIZE `cat $TMPFILE`" else echo "#define PIPESIZE 512" fi -rm -f /tmp/pipesize - exit 0 diff --git a/builtins/pushd.def b/builtins/pushd.def index 87300dca..7226ab20 100644 --- a/builtins/pushd.def +++ b/builtins/pushd.def @@ -95,9 +95,14 @@ $END #if defined (PUSHD_AND_POPD) #include <stdio.h> -#include <sys/param.h> +#ifndef _MINIX +# include <sys/param.h> +#endif #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -547,6 +552,34 @@ get_dirstack_index (ind, sign, indexp) return (sign > 0 ? directory_list_offset - ind : ind); } +/* Used by the tilde expansion code. */ +char * +get_dirstack_from_string (string) + char *string; +{ + int ind, sign, index_flag; + long 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) int ind, sign; @@ -557,6 +590,7 @@ get_dirstack_element (ind, sign) return (i < 0 || i > directory_list_offset) ? (char *)NULL : pushd_directory_list[i]; } +#endif void set_dirstack_element (ind, sign, value) diff --git a/builtins/read.def b/builtins/read.def index e1e63541..6d161f63 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -43,6 +43,9 @@ $END #include <stdio.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -395,11 +398,13 @@ bind_read_variable (name, value) #if defined (ARRAY_VARS) if (valid_array_reference (name) == 0) { +#if 0 if (legal_identifier (name) == 0) { builtin_error ("`%s': not a valid identifier", name); return ((SHELL_VAR *)NULL); } +#endif return (bind_variable (name, value)); } else diff --git a/builtins/return.def b/builtins/return.def index da5b76b1..e88808c8 100644 --- a/builtins/return.def +++ b/builtins/return.def @@ -32,6 +32,9 @@ $END #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif diff --git a/builtins/set.def b/builtins/set.def index 74f2e5cd..b5ac83b4 100644 --- a/builtins/set.def +++ b/builtins/set.def @@ -24,6 +24,9 @@ $PRODUCES set.c #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -229,31 +232,20 @@ minus_o_option_value (name) #define MINUS_O_FORMAT "%-15s\t%s\n" -void -list_minus_o_opts (mode) - int mode; +static void +print_minus_o_option (name, value, pflag) + char *name; + int value, pflag; { - register int i; - int *on_or_off, value; - - for (value = i = 0; o_options[i].name; i++) - { - on_or_off = find_flag (o_options[i].letter); - if (on_or_off == FLAG_UNKNOWN) - on_or_off = &value; - if (mode == -1 || mode == *on_or_off) - printf (MINUS_O_FORMAT, o_options[i].name, *on_or_off ? on : off); - } - for (i = 0; binary_o_options[i].name; i++) - { - value = GET_BINARY_O_OPTION_VALUE (i, binary_o_options[i].name); - if (mode == -1 || mode == value) - printf (MINUS_O_FORMAT, binary_o_options[i].name, value ? on : off); - } + if (pflag == 0) + printf (MINUS_O_FORMAT, name, value ? on : off); + else + printf ("set %co %s\n", value ? '-' : '+', name); } -static void -minus_o_option_commands () +void +list_minus_o_opts (mode, reusable) + int mode, reusable; { register int i; int *on_or_off, value; @@ -263,12 +255,14 @@ minus_o_option_commands () on_or_off = find_flag (o_options[i].letter); if (on_or_off == FLAG_UNKNOWN) on_or_off = &value; - printf ("set %co %s\n", *on_or_off ? '-' : '+', o_options[i].name); + if (mode == -1 || mode == *on_or_off) + print_minus_o_option (o_options[i].name, *on_or_off, reusable); } for (i = 0; binary_o_options[i].name; i++) { value = GET_BINARY_O_OPTION_VALUE (i, binary_o_options[i].name); - printf ("set %co %s\n", value ? '-' : '+', binary_o_options[i].name); + if (mode == -1 || mode == value) + print_minus_o_option (binary_o_options[i].name, value, reusable); } } @@ -421,7 +415,7 @@ void set_shellopts () { char *value; - int vsize, i, vptr, *ip; + int vsize, i, vptr, *ip, exported; SHELL_VAR *v; for (vsize = i = 0; o_options[i].name; i++) @@ -458,10 +452,25 @@ set_shellopts () 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) - v->attributes &= ~att_readonly; + { + v->attributes &= ~att_readonly; + exported = exported_p (v); + } + else + exported = 0; + v = bind_variable ("SHELLOPTS", value); + + /* 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. */ v->attributes |= att_readonly; + if (mark_modified_vars && exported == 0 && exported_p (v)) + v->attributes &= ~att_exported; free (value); } @@ -482,20 +491,24 @@ parse_shellopts (value) } void -initialize_shell_options () +initialize_shell_options (no_shellopts) + int no_shellopts; { char *temp; SHELL_VAR *var; - var = find_variable ("SHELLOPTS"); - /* set up any shell options we may have inherited. */ - if (var && imported_p (var)) + if (no_shellopts == 0) { - temp = (array_p (var)) ? (char *)NULL : savestring (value_cell (var)); - if (temp) + var = find_variable ("SHELLOPTS"); + /* set up any shell options we may have inherited. */ + if (var && imported_p (var)) { - parse_shellopts (temp); - free (temp); + temp = (array_p (var)) ? (char *)NULL : savestring (value_cell (var)); + if (temp) + { + parse_shellopts (temp); + free (temp); + } } } @@ -607,10 +620,7 @@ set_builtin (list) if (opt == 0) { - if (on_or_off == '-') - list_minus_o_opts (-1); - else - minus_o_option_commands (); + list_minus_o_opts (-1, (on_or_off == '+')); continue; } @@ -619,10 +629,7 @@ set_builtin (list) if (option_name == 0 || *option_name == '\0' || *option_name == '-' || *option_name == '+') { - if (on_or_off == '-') - list_minus_o_opts (-1); - else - minus_o_option_commands (); + list_minus_o_opts (-1, (on_or_off == '+')); continue; } list = list->next; /* Skip over option name. */ @@ -730,7 +737,10 @@ unset_builtin (list) } #endif - if (legal_identifier (name) == 0) + /* 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) { builtin_error ("`%s': not a valid identifier", name); NEXT_VARIABLE (); diff --git a/builtins/setattr.def b/builtins/setattr.def index d4068a33..1fadee65 100644 --- a/builtins/setattr.def +++ b/builtins/setattr.def @@ -24,6 +24,9 @@ $PRODUCES setattr.c #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -339,6 +342,7 @@ show_name_attributes (name, nodefs) int nodefs; { SHELL_VAR *var; + int ret; var = find_tempenv_variable (name); if (var == 0) @@ -347,6 +351,8 @@ show_name_attributes (name, nodefs) if (var && invisible_p (var) == 0) { show_var_attributes (var, READONLY_OR_EXPORT, nodefs); + if (tempvar_p (var)) + dispose_variable (var); return (0); } else diff --git a/builtins/shift.def b/builtins/shift.def index 293c31b3..cc2a4f2b 100644 --- a/builtins/shift.def +++ b/builtins/shift.def @@ -24,6 +24,9 @@ $PRODUCES shift.c #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif diff --git a/builtins/shopt.def b/builtins/shopt.def index bc26a96a..762bb420 100644 --- a/builtins/shopt.def +++ b/builtins/shopt.def @@ -38,6 +38,9 @@ $END #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -59,6 +62,12 @@ extern int no_exit_on_failed_exec, print_shift_error; extern int check_hashed_filenames, promptvars, interactive_comments; extern int cdspelling, expand_aliases; extern int check_window_size; +extern int glob_ignore_case; +extern int hup_on_exit; + +#if defined (EXTENDED_GLOB) +extern int extended_glob; +#endif #if defined (HISTORY) extern int literal_history, command_oriented_history; @@ -89,6 +98,9 @@ static struct { { "dotglob", &glob_dot_filenames, (Function *)NULL }, { "execfail", &no_exit_on_failed_exec, (Function *)NULL }, { "expand_aliases", &expand_aliases, (Function *)NULL }, +#if defined (EXTENDED_GLOB) + { "extglob", &extended_glob, (Function *)NULL }, +#endif #if defined (READLINE) { "histreedit", &history_reediting, (Function *)NULL }, #endif @@ -99,11 +111,13 @@ static struct { { "histverify", &hist_verify, (Function *)NULL }, { "hostcomplete", &perform_hostname_completion, (Function *)enable_hostname_completion }, #endif + { "huponexit", &hup_on_exit, (Function *)NULL }, { "interactive_comments", &interactive_comments, set_interactive_comments }, #if defined (HISTORY) { "lithist", &literal_history, (Function *)NULL }, #endif { "mailwarn", &mail_warning, (Function *)NULL }, + { "nocaseglob", &glob_ignore_case, (Function *)NULL }, { "nullglob", &allow_null_glob_expansion, (Function *)NULL }, { "promptvars", &promptvars, (Function *)NULL }, { "shift_verbose", &print_shift_error, (Function *)NULL }, @@ -166,17 +180,17 @@ shopt_builtin (list) rval = EXECUTION_SUCCESS; if ((flags & OFLAG) && ((flags & (SFLAG|UFLAG)) == 0)) /* shopt -o */ - rval = list_shopt_o_options (list, flags & QFLAG); + 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) ? FLAG_ON : FLAG_OFF, flags & QFLAG); + 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 & QFLAG); + rval = list_shopts (list, flags); else /* shopt -su */ - rval = list_some_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, flags & QFLAG); + rval = list_some_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, flags); return (rval); } @@ -192,6 +206,10 @@ reset_shopt_options () 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; @@ -244,12 +262,23 @@ toggle_shopts (mode, list, quiet) return (rval); } +static int +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, quiet) +list_shopts (list, flags) WORD_LIST *list; - int quiet; + int flags; { WORD_LIST *l; int i, val, rval; @@ -259,8 +288,8 @@ list_shopts (list, quiet) for (i = 0; shopt_vars[i].name; i++) { val = *shopt_vars[i].value; - if (quiet == 0) - printf (OPTFMT, shopt_vars[i].name, val ? on : off); + if ((flags & QFLAG) == 0) + print_shopt (shopt_vars[i].name, val, flags); } return (EXECUTION_SUCCESS); } @@ -277,39 +306,39 @@ list_shopts (list, quiet) val = *shopt_vars[i].value; if (val == 0) rval = EXECUTION_FAILURE; - if (quiet == 0) - printf (OPTFMT, l->word->word, val ? on : off); + if ((flags & QFLAG) == 0) + print_shopt (l->word->word, val, flags); } return (rval); } static int -list_some_shopts (mode, quiet) - int mode, quiet; +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 (quiet == 0 && mode == val) - printf (OPTFMT, shopt_vars[i].name, val ? on : off); + if (((flags & QFLAG) == 0) && mode == val) + print_shopt (shopt_vars[i].name, val, flags); } return (EXECUTION_SUCCESS); } static int -list_shopt_o_options (list, quiet) +list_shopt_o_options (list, flags) WORD_LIST *list; - int quiet; + int flags; { WORD_LIST *l; int val, rval; if (list == 0) { - if (quiet == 0) - list_minus_o_opts (-1); + if ((flags & QFLAG) == 0) + list_minus_o_opts (-1, (flags & PFLAG)); return (EXECUTION_SUCCESS); } @@ -324,18 +353,23 @@ list_shopt_o_options (list, quiet) } if (val == 0) rval = EXECUTION_FAILURE; - if (quiet == 0) - printf (OPTFMT, l->word->word, val ? "on" : "off"); + 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 (rval); } static int -list_some_o_options (mode, quiet) - int mode, quiet; +list_some_o_options (mode, flags) + int mode, flags; { - if (quiet == 0) - list_minus_o_opts (mode); + if ((flags & QFLAG) == 0) + list_minus_o_opts (mode, (flags & PFLAG)); return (EXECUTION_SUCCESS); } diff --git a/builtins/source.def b/builtins/source.def index 1bb3e731..8979f0b1 100644 --- a/builtins/source.def +++ b/builtins/source.def @@ -41,7 +41,9 @@ $END #include "../bashtypes.h" #include "../posixstat.h" #include "../filecntl.h" -#include <sys/file.h> +#ifndef _MINIX +# include <sys/file.h> +#endif #include <errno.h> #if defined (HAVE_UNISTD_H) @@ -51,7 +53,7 @@ $END #include "../bashansi.h" #include "../shell.h" -#include "../execute_cmd.h" +#include "../findcmd.h" #include "common.h" #if !defined (errno) diff --git a/builtins/suspend.def b/builtins/suspend.def index 82ec71ba..3e949baf 100644 --- a/builtins/suspend.def +++ b/builtins/suspend.def @@ -34,6 +34,9 @@ $END #if defined (JOB_CONTROL) #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif diff --git a/builtins/test.def b/builtins/test.def index 03de47d8..eded0fae 100644 --- a/builtins/test.def +++ b/builtins/test.def @@ -50,9 +50,10 @@ File operators: -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 (according to - modification date) file2. + FILE1 -nt FILE2 True if file1 is newer than file2 (according to + modification date). FILE1 -ot FILE2 True if file1 is older than file2. @@ -70,12 +71,13 @@ String operators: STRING1 != STRING2 True if the strings are not equal. STRING1 < STRING2 - True if STRING1 sorts before STRING2 lexicographically + True if STRING1 sorts before STRING2 lexicographically. STRING1 > STRING2 - True if STRING1 sorts after STRING2 lexicographically + 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. @@ -99,12 +101,16 @@ $END #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif #include "../bashansi.h" #include "../shell.h" +#include "../test.h" #include "common.h" extern char *this_command_name; diff --git a/builtins/times.def b/builtins/times.def index 216abcbe..630642c5 100644 --- a/builtins/times.def +++ b/builtins/times.def @@ -31,6 +31,9 @@ $END #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -53,7 +56,7 @@ $END # include <sys/times.h> #endif /* HAVE_SYS_TIMES_H */ -#if defined (HAVE_SYS_RESOURCE_H) +#if defined (HAVE_SYS_RESOURCE_H) && !defined (RLIMTYPE) # include <sys/resource.h> #endif diff --git a/builtins/trap.def b/builtins/trap.def index 252a1dbe..522e2a46 100644 --- a/builtins/trap.def +++ b/builtins/trap.def @@ -42,6 +42,9 @@ $END #include <config.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif diff --git a/builtins/type.def b/builtins/type.def index 3af018f7..93c8ff80 100644 --- a/builtins/type.def +++ b/builtins/type.def @@ -27,20 +27,18 @@ $SHORT_DOC type [-apt] name [name ...] For each NAME, indicate how it would be interpreted if used as a command name. -If the -t option is used, returns a single word which is one of +If the -t option is used, `type' outputs a single word which is one of `alias', `keyword', `function', `builtin', `file' or `', if NAME is an alias, shell reserved word, shell function, shell builtin, disk file, or unfound, respectively. -If the -p flag is used, either returns the name of the disk file -that would be executed, or nothing if -t would not return `file'. +If the -p flag is used, `type' either returns the name of the disk +file that would be executed, or nothing if `type -t NAME' would not +return `file'. -If the -a flag is used, displays all of the places that contain an -executable named `file'. This includes aliases and functions, if and -only if the -p flag is not also used. - -Type accepts -all, -path, and -type in place of -a, -p, and -t, -respectively. +If the -a flag is used, `type' displays all of the places that contain +an executable named `file'. This includes aliases and functions, if +and only if the -p flag is not also used. $END #include <config.h> @@ -56,7 +54,7 @@ $END #include "../bashansi.h" #include "../shell.h" -#include "../execute_cmd.h" +#include "../findcmd.h" #include "../hashcmd.h" #if defined (ALIAS) diff --git a/builtins/ulimit.def b/builtins/ulimit.def index 3cdf26ab..bbeb7c92 100644 --- a/builtins/ulimit.def +++ b/builtins/ulimit.def @@ -23,7 +23,7 @@ $PRODUCES ulimit.c $BUILTIN ulimit $FUNCTION ulimit_builtin -$DEPENDS_ON !MINIX +$DEPENDS_ON !_MINIX $SHORT_DOC ulimit [-SHacdflmnpstuv] [limit] Ulimit provides control over the resources available to processes started by the shell, on systems that allow such control. If an @@ -52,10 +52,14 @@ increments of 512 bytes, and -u, which is an unscaled number of processes. $END +#if !defined (_MINIX) + #include <config.h> #include "../bashtypes.h" -#include <sys/param.h> +#ifndef _MINIX +# include <sys/param.h> +#endif #if defined (HAVE_UNISTD_H) # include <unistd.h> @@ -101,7 +105,7 @@ extern int errno; #if !defined (RLIMTYPE) # define RLIMTYPE long -# define string_to_rlimtype string_to_long +# define string_to_rlimtype(s) strtol(s, (char **)NULL, 10) # define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "") #endif @@ -597,7 +601,8 @@ printone (limind, curlim, pdesc) if (curlim == RLIM_INFINITY) puts ("unlimited"); else if (curlim == RLIM_INVALID) - printf ("cannot get limit: %s\n", strerror (errno)); + builtin_error ("cannot get limit: %s\n", strerror (errno)); else print_rlimtype ((curlim / limits[limind].block_factor), 1); } +#endif /* !_MINIX */ diff --git a/builtins/umask.def b/builtins/umask.def index 85bf220b..f7341130 100644 --- a/builtins/umask.def +++ b/builtins/umask.def @@ -23,19 +23,23 @@ $PRODUCES umask.c $BUILTIN umask $FUNCTION umask_builtin -$SHORT_DOC umask [-S] [mode] +$SHORT_DOC umask [-p] [-S] [mode] The user file-creation mask is set to MODE. If MODE is omitted, or if `-S' is supplied, the current value of the mask is printed. The `-S' option makes the output symbolic; otherwise an octal number is output. -If 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). +If `-p' is supplied, and MODE is omitted, the output is in a form +that may be used as input. If MODE begins with a digit, it is +interpreted as an octal number, otherwise it is a symbolic mode string +like that accepted by chmod(1). $END #include <config.h> #include "../bashtypes.h" #include "../filecntl.h" -#include <sys/file.h> +#ifndef _MINIX +# include <sys/file.h> +#endif #if defined (HAVE_UNISTD_H) #include <unistd.h> @@ -63,18 +67,21 @@ int umask_builtin (list) WORD_LIST *list; { - int print_symbolically, opt, umask_value; + int print_symbolically, opt, umask_value, pflag; mode_t umask_arg; - print_symbolically = 0; + print_symbolically = pflag = 0; reset_internal_getopt (); - while ((opt = internal_getopt (list, "S")) != -1) + while ((opt = internal_getopt (list, "Sp")) != -1) { switch (opt) { case 'S': print_symbolically++; break; + case 'p': + pflag++; + break; default: builtin_usage (); return (EX_USAGE); @@ -116,6 +123,8 @@ umask_builtin (list) umask_arg = umask (022); umask (umask_arg); + if (pflag) + printf ("umask%s ", (print_symbolically ? " -S" : "")); if (print_symbolically) print_symbolic_umask (umask_arg); else diff --git a/builtins/wait.def b/builtins/wait.def index 741ff5c9..11fe85a9 100644 --- a/builtins/wait.def +++ b/builtins/wait.def @@ -136,6 +136,12 @@ wait_builtin (list) UNBLOCK_CHILD (oset); status = wait_for_job (job); } + else if (job_control == 0 && *w == '%') + { + /* can't use jobspecs as arguments if job control is not active. */ + builtin_error ("job control not enabled"); + status = EXECUTION_FAILURE; + } #endif /* JOB_CONTROL */ else { @@ -54,7 +54,8 @@ enum r_instruction { /* 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_connection, cm_function_def, cm_until, cm_group, + cm_arith, cm_cond }; /* Possible values for the `flags' field of a WORD_DESC. */ #define W_HASDOLLAR 0x01 /* Dollar sign present. */ @@ -143,6 +144,12 @@ typedef struct command { #if defined (SELECT_COMMAND) struct select_com *Select; #endif +#if defined (DPAREN_ARITHMETIC) + struct arith_com *Arith; +#endif +#if defined (COND_COMMAND) + struct cond_com *Cond; +#endif } value; } COMMAND; @@ -207,6 +214,34 @@ typedef struct while_com { COMMAND *action; /* Thing to do while test is non-zero. */ } WHILE_COM; +#if defined (DPAREN_ARITHMETIC) +/* The arithmetic evaluation command, ((...)). Just a set of flags and + a WORD_LIST, of which the first element is the only one used, for the + time being. */ +typedef struct arith_com { + int flags; + WORD_LIST *exp; + int line; +} ARITH_COM; +#endif /* DPAREN_ARITHMETIC */ + +/* The conditional command, [[...]]. This is a binary tree -- we slippped + a recursive-descent parser into the YACC grammar to parse it. */ +#define COND_AND 1 +#define COND_OR 2 +#define COND_UNARY 3 +#define COND_BINARY 4 +#define COND_TERM 5 +#define COND_EXPR 6 + +typedef struct cond_com { + int flags; + int line; + int type; + WORD_DESC *op; + struct cond_com *left, *right; +} COND_COM; + /* The "simple" command. Just a collection of words and redirects. */ typedef struct simple_com { int flags; /* See description of CMD flags. */ @@ -218,7 +253,7 @@ typedef struct simple_com { /* The "function definition" command. */ typedef struct function_def { - int ignore; /* See description of CMD flags. */ + int flags; /* See description of CMD flags. */ WORD_DESC *name; /* The name of the function. */ COMMAND *command; /* The parsed execution tree. */ int line; /* Line number the function def starts on. */ diff --git a/config.h.in b/config.h.in index cd1ef954..39bcbd58 100644 --- a/config.h.in +++ b/config.h.in @@ -110,6 +110,14 @@ 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 AFS if you are using Transarc's AFS. */ #undef AFS @@ -170,6 +178,15 @@ /* Define if on MINIX. */ #undef _MINIX +/* 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 + /* Define to `long' if <sys/types.h> doesn't define. */ #undef off_t @@ -182,6 +199,27 @@ /* Define to `int' if <sys/types.h> doesn't define. */ #undef pid_t +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef int32_t + +/* Define to `unsigned int' if <sys/types.h> doesn't define. */ +#undef u_int32_t + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef ptrdiff_t + +/* Define to `unsigned' if <sys/types.h> doesn't define. */ +#undef size_t + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef uid_t + +/* Define to `long' if <sys/types.h> doesn't define. */ +#undef clock_t + +/* Define to `long' if <sys/types.h> doesn't define. */ +#undef time_t + /* Define if the system does not provide POSIX.1 features except with this defined. */ #undef _POSIX_1_SOURCE @@ -197,9 +235,6 @@ before release 3. */ #undef SETVBUF_REVERSED -/* Define to `unsigned' if <sys/types.h> doesn't define. */ -#undef size_t - /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. @@ -212,21 +247,12 @@ /* Define if you have the ANSI C header files. */ #undef STDC_HEADERS -/* Define if `sys_siglist' is declared by <signal.h>. */ +/* Define if `sys_siglist' is declared by <signal.h> or <unistd.h>. */ #undef SYS_SIGLIST_DECLARED /* Define if `_sys_siglist' is declared by <signal.h> or <unistd.h>. */ #undef UNDER_SYS_SIGLIST_DECLARED -/* Define to `int' if <sys/types.h> doesn't define. */ -#undef uid_t - -/* Define to `long' if <sys/types.h> doesn't define. */ -#undef clock_t - -/* Define to `long' if <sys/types.h> doesn't define. */ -#undef time_t - #undef DUP2_BROKEN #undef HAVE_GETRLIMIT @@ -307,6 +333,8 @@ #undef STRUCT_WINSIZE_IN_SYS_IOCTL +#undef STRUCT_WINSIZE_IN_TERMIOS + #undef SPEED_T_IN_SYS_TYPES #undef CAN_REDEFINE_GETENV @@ -395,6 +423,15 @@ /* Define if you have the strerror function. */ #undef HAVE_STRERROR +/* Define if you have the strtod function. */ +#undef HAVE_STRTOD + +/* Define if you have the strtol function. */ +#undef HAVE_STRTOL + +/* Define if you have the strtoul function. */ +#undef HAVE_STRTOUL + /* Define if you have the tcgetattr function. */ #undef HAVE_TCGETATTR @@ -496,6 +533,9 @@ /* Define if you have the <libintl.h> header file. */ #undef HAVE_LIBINTL_H +/* Define if you have the <stddef.h> header file. */ +#undef HAVE_STDDEF_H + #undef HAVE_LIBDL #undef HAVE_LIBSUN @@ -1,6 +1,16 @@ #! /bin/sh -# From configure.in for Bash 2.01, version 1.28, from autoconf version 2.12 +# From configure.in for Bash 2.02, version 2.19, from autoconf version 2.12 + + + + + + + + + + @@ -112,12 +122,16 @@ ac_help="$ac_help ac_help="$ac_help --enable-command-timing enable the time reserved word and command timing" ac_help="$ac_help +--enable-cond-command enable the conditional command" +ac_help="$ac_help --enable-directory-stack enable builtins pushd/popd/dirs" ac_help="$ac_help --enable-disabled-builtins allow disabled builtins to still be invoked" ac_help="$ac_help --enable-dparen-arithmetic include ((...)) command" ac_help="$ac_help +--enable-extended-glob include ksh-style extended pattern matching" +ac_help="$ac_help --enable-help-builtin include the help builtin" ac_help="$ac_help --enable-history turn on command history" @@ -135,6 +149,10 @@ ac_help="$ac_help --enable-select include select command" ac_help="$ac_help --enable-usg-echo-default make the echo builtin expand escape sequences by default" +ac_help="$ac_help +--enable-profiling allow profiling with gprof" +ac_help="$ac_help +--enable-static-link link bash statically, for use as a root shell" # Initialize some variables set by options. # The variables have the same names as the options, with @@ -673,7 +691,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } fi echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:677: checking host system type" >&5 +echo "configure:695: checking host system type" >&5 host_alias=$host case "$host_alias" in @@ -703,19 +721,20 @@ opt_curses=no case "${host_cpu}-${host_os}" in alpha-*) opt_gnu_malloc=no ;; # alpha running osf/1 or linux -*cray*-*) opt_gnu_malloc=no ;; # Crays +*Ccray*-*) opt_gnu_malloc=no ;; # Crays *-osf1*) opt_gnu_malloc=no ;; # other osf/1 machines sparc-svr4*) opt_gnu_malloc=no ;; # sparc SVR4, SVR4.2 sparc-netbsd*) opt_gnu_malloc=no ;; # needs 8-byte alignment sgi-irix6*) opt_gnu_malloc=no ;; # needs 8-byte alignment sparc-linux*) opt_gnu_malloc=no ;; # sparc running linux; requires ELF -*-freebsd*) opt_gnu_malloc=no ;; # they claim it's better +#*-freebsd*) opt_gnu_malloc=no ;; # they claim it's better *-aix*) opt_gnu_malloc=no ;; # AIX machines *-nextstep*) opt_gnu_malloc=no ;; # NeXT machines running NeXTstep *-dgux*) opt_gnu_malloc=no ;; # DG/UX machines *-qnx*) opt_gnu_malloc=no ;; # QNX 4.2 *-machten4) opt_gnu_malloc=no ;; # MachTen 4.x -*-bsdi2.1|*-bsdi3.0) opt_gnu_malloc=no ; : ${CC:=shlicc2} ;; # for loadable builtins +*-bsdi2.1|*-bsdi3.?) opt_gnu_malloc=no ; : ${CC:=shlicc2} ;; # for loadable builtins +*-cygwin32*) opt_gnu_malloc=no ;; # Cygnus's CYGWIN32 environment esac # Check whether --with-afs or --without-afs was given. @@ -802,10 +821,15 @@ 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_usg_echo=no +opt_cond_command=yes + +opt_static_link=no +opt_profiling=no # Check whether --enable-minimal-config or --disable-minimal-config was given. if test "${enable_minimal_config+set}" = set; then @@ -820,6 +844,7 @@ if test $opt_minimal_config = yes; then 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 fi # Check whether --enable-alias or --disable-alias was given. @@ -852,6 +877,12 @@ if test "${enable_command_timing+set}" = set; then opt_command_timing=$enableval fi +# Check whether --enable-cond-command or --disable-cond-command was given. +if test "${enable_cond_command+set}" = set; then + enableval="$enable_cond_command" + opt_cond_command=$enableval +fi + # Check whether --enable-directory-stack or --disable-directory-stack was given. if test "${enable_directory_stack+set}" = set; then enableval="$enable_directory_stack" @@ -870,6 +901,12 @@ if test "${enable_dparen_arithmetic+set}" = set; then opt_dparen_arith=$enableval fi +# Check whether --enable-extended-glob or --disable-extended-glob was given. +if test "${enable_extended_glob+set}" = set; then + enableval="$enable_extended_glob" + opt_extended_glob=$enableval +fi + # Check whether --enable-help-builtin or --disable-help-builtin was given. if test "${enable_help_builtin+set}" = set; then enableval="$enable_help_builtin" @@ -925,6 +962,19 @@ if test "${enable_usg_echo_default+set}" = set; then fi +# Check whether --enable-profiling or --disable-profiling was given. +if test "${enable_profiling+set}" = set; then + enableval="$enable_profiling" + opt_profiling=$enableval +fi + +# Check whether --enable-static-link or --disable-static-link was given. +if test "${enable_static_link+set}" = set; then + enableval="$enable_static_link" + opt_static_link=$enableval +fi + + if test $opt_alias = yes; then cat >> confdefs.h <<\EOF @@ -1034,6 +1084,18 @@ cat >> confdefs.h <<\EOF EOF fi +if test $opt_extended_glob = yes ; then +cat >> confdefs.h <<\EOF +#define EXTENDED_GLOB 1 +EOF + +fi +if test $opt_cond_command = yes ; then +cat >> confdefs.h <<\EOF +#define COND_COMMAND 1 +EOF + +fi if test "$opt_minimal_config" = yes; then TESTSCRIPT=run-minimal @@ -1050,15 +1112,15 @@ fi -BASHVERS=2.01 -BASHPATCH=1 +BASHVERS=2.02 +BASHPATCH=0 -echo "Beginning configuration for bash-$BASHVERS" +echo "Beginning configuration for bash-$BASHVERS for ${host_cpu}-${host_vendor}-${host_os}" # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1062: checking for $ac_word" >&5 +echo "configure:1124: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1087,7 +1149,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1091: checking for $ac_word" >&5 +echo "configure:1153: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1135,7 +1197,7 @@ fi fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:1139: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 +echo "configure:1201: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. @@ -1145,11 +1207,11 @@ ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext <<EOF -#line 1149 "configure" +#line 1211 "configure" #include "confdefs.h" main(){return(0);} EOF -if { (eval echo configure:1153: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1215: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -1169,12 +1231,12 @@ if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:1173: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:1235: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:1178: checking whether we are using GNU C" >&5 +echo "configure:1240: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1183,7 +1245,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1187: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1249: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -1198,7 +1260,7 @@ if test $ac_cv_prog_gcc = yes; then ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:1202: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:1264: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1225,8 +1287,40 @@ else test "${CFLAGS+set}" = set || CFLAGS="-g" fi +echo $ac_n "checking whether large file support needs explicit enabling""... $ac_c" 1>&6 +echo "configure:1292: checking whether large file support needs explicit enabling" >&5 +ac_getconfs='' +ac_result=yes +ac_set='' +ac_shellvars='CPPFLAGS LDFLAGS LIBS' +for ac_shellvar in $ac_shellvars; do + case $ac_shellvar in + CPPFLAGS) ac_lfsvar=LFS_CFLAGS ac_lfs64var=LFS64_CFLAGS ;; + *) ac_lfsvar=LFS_$ac_shellvar ac_lfs64var=LFS64_$ac_shellvar ;; + esac + eval test '"${'$ac_shellvar'+set}"' = set && ac_set=$ac_shellvar + (getconf $ac_lfsvar) >/dev/null 2>&1 || { ac_result=no; break; } + ac_getconf=`getconf $ac_lfsvar` + ac_getconf64=`getconf $ac_lfs64var` + ac_getconfs=$ac_getconfs$ac_getconf\ $ac_getconf64 + eval ac_test_$ac_shellvar="\$ac_getconf\ \$ac_getconf64" +done +case "$ac_result$ac_getconfs" in +yes) ac_result=no ;; +esac +case "$ac_result$ac_set" in +yes?*) ac_result="yes, but $ac_set is already set, so use its settings" +esac +echo "$ac_t""$ac_result" 1>&6 +case $ac_result in +yes) + for ac_shellvar in $ac_shellvars; do + eval $ac_shellvar=\$ac_test_$ac_shellvar + done ;; +esac + echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6 -echo "configure:1230: checking for POSIXized ISC" >&5 +echo "configure:1324: checking for POSIXized ISC" >&5 if test -d /etc/conf/kconfig.d && grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1 then @@ -1247,7 +1341,7 @@ else fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:1251: checking how to run the C preprocessor" >&5 +echo "configure:1345: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= @@ -1262,13 +1356,13 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext <<EOF -#line 1266 "configure" +#line 1360 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1272: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1366: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : @@ -1279,13 +1373,13 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext <<EOF -#line 1283 "configure" +#line 1377 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1289: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1383: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : @@ -1309,17 +1403,17 @@ echo "$ac_t""$CPP" 1>&6 ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6 -echo "configure:1313: checking for minix/config.h" >&5 +echo "configure:1407: checking for minix/config.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1318 "configure" +#line 1412 "configure" #include "confdefs.h" #include <minix/config.h> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1323: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1417: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* @@ -1357,23 +1451,68 @@ EOF fi + +if test "x$cross_compiling" = "xyes"; then + case "${host}" in + *-cygwin32*) + cross_cache=${srcdir}/cross-build/cygwin32.cache + if test -r "${cross_cache}"; then + echo "loading cross-build cache file ${cross_cache}" + . ${cross_cache} + fi + unset cross_cache + ;; + *) echo "configure: cross-compiling for a non-cygwin32 target is not supported" >&2 + ;; + esac +fi + +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 + + +if test "x$cross_compiling" = "xno"; then + SIGNAMES_H=lsignames.h +else + SIGNAMES_H='$(srcdir)/cross-build/win32sig.h' +fi + + + test -z "$CFLAGS" && CFLAGS=-g auto_cflags=1 test -n "$GCC" && test -n "$auto_cflags" && CFLAGS="$CFLAGS -O2" +if test "$opt_profiling" = "yes"; then + PROFILE_FLAGS=-pg + opt_static_link=yes +fi + +if test "$opt_static_link" = yes; then + # if we're using gcc, add `-static' to LDFLAGS + if test -n "$GCC" || test "$ac_cv_prog_gcc" = "yes"; then + LDFLAGS="$LDFLAGS -static" + fi +fi + if test $ac_cv_prog_gcc = yes; then echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 -echo "configure:1371: checking whether ${CC-cc} needs -traditional" >&5 +echo "configure:1510: checking whether ${CC-cc} needs -traditional" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_pattern="Autoconf.*'x'" cat > conftest.$ac_ext <<EOF -#line 1377 "configure" +#line 1516 "configure" #include "confdefs.h" #include <sgtty.h> Autoconf TIOCGETP @@ -1391,7 +1530,7 @@ rm -f conftest* if test $ac_cv_prog_gcc_traditional = no; then cat > conftest.$ac_ext <<EOF -#line 1395 "configure" +#line 1534 "configure" #include "confdefs.h" #include <termio.h> Autoconf TCGETA @@ -1424,7 +1563,7 @@ fi # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:1428: checking for a BSD compatible install" >&5 +echo "configure:1567: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1476,7 +1615,7 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1480: checking for $ac_word" >&5 +echo "configure:1619: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1504,7 +1643,7 @@ fi # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1508: checking for $ac_word" >&5 +echo "configure:1647: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1535,7 +1674,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1539: checking for $ac_word" >&5 +echo "configure:1678: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1565,7 +1704,7 @@ done test -n "$YACC" || YACC="yacc" echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 -echo "configure:1569: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo "configure:1708: checking whether ${MAKE-make} sets \${MAKE}" >&5 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1595,19 +1734,19 @@ fi # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 -echo "configure:1599: checking for working alloca.h" >&5 +echo "configure:1738: checking for working alloca.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1604 "configure" +#line 1743 "configure" #include "confdefs.h" #include <alloca.h> int main() { char *p = alloca(2 * sizeof(int)); ; return 0; } EOF -if { (eval echo configure:1611: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1750: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* ac_cv_header_alloca_h=yes else @@ -1628,12 +1767,12 @@ EOF fi echo $ac_n "checking for alloca""... $ac_c" 1>&6 -echo "configure:1632: checking for alloca" >&5 +echo "configure:1771: checking for alloca" >&5 if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1637 "configure" +#line 1776 "configure" #include "confdefs.h" #ifdef __GNUC__ @@ -1656,7 +1795,7 @@ int main() { char *p = (char *) alloca(1); ; return 0; } EOF -if { (eval echo configure:1660: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1799: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* ac_cv_func_alloca_works=yes else @@ -1688,12 +1827,12 @@ EOF echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 -echo "configure:1692: checking whether alloca needs Cray hooks" >&5 +echo "configure:1831: checking whether alloca needs Cray hooks" >&5 if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1697 "configure" +#line 1836 "configure" #include "confdefs.h" #if defined(CRAY) && ! defined(CRAY2) webecray @@ -1718,12 +1857,12 @@ echo "$ac_t""$ac_cv_os_cray" 1>&6 if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:1722: checking for $ac_func" >&5 +echo "configure:1861: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1727 "configure" +#line 1866 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -1746,7 +1885,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:1750: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1889: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -1773,7 +1912,7 @@ done fi echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 -echo "configure:1777: checking stack direction for C alloca" >&5 +echo "configure:1916: checking stack direction for C alloca" >&5 if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1781,7 +1920,7 @@ else ac_cv_c_stack_direction=0 else cat > conftest.$ac_ext <<EOF -#line 1785 "configure" +#line 1924 "configure" #include "confdefs.h" find_stack_direction () { @@ -1800,7 +1939,7 @@ main () exit (find_stack_direction() < 0); } EOF -if { (eval echo configure:1804: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:1943: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then ac_cv_c_stack_direction=1 else @@ -1822,7 +1961,7 @@ EOF fi echo $ac_n "checking whether getpgrp takes no argument""... $ac_c" 1>&6 -echo "configure:1826: checking whether getpgrp takes no argument" >&5 +echo "configure:1965: checking whether getpgrp takes no argument" >&5 if eval "test \"`echo '$''{'ac_cv_func_getpgrp_void'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1830,7 +1969,7 @@ else { echo "configure: error: cannot check getpgrp if cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <<EOF -#line 1834 "configure" +#line 1973 "configure" #include "confdefs.h" /* @@ -1885,7 +2024,7 @@ main() } EOF -if { (eval echo configure:1889: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:2028: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then ac_cv_func_getpgrp_void=yes else @@ -1909,7 +2048,7 @@ EOF fi echo $ac_n "checking whether setvbuf arguments are reversed""... $ac_c" 1>&6 -echo "configure:1913: checking whether setvbuf arguments are reversed" >&5 +echo "configure:2052: checking whether setvbuf arguments are reversed" >&5 if eval "test \"`echo '$''{'ac_cv_func_setvbuf_reversed'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1917,7 +2056,7 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <<EOF -#line 1921 "configure" +#line 2060 "configure" #include "confdefs.h" #include <stdio.h> /* If setvbuf has the reversed format, exit 0. */ @@ -1931,7 +2070,7 @@ main () { exit(0); /* Non-reversed systems segv here. */ } EOF -if { (eval echo configure:1935: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:2074: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then ac_cv_func_setvbuf_reversed=yes else @@ -1955,12 +2094,12 @@ EOF fi echo $ac_n "checking for vprintf""... $ac_c" 1>&6 -echo "configure:1959: checking for vprintf" >&5 +echo "configure:2098: checking for vprintf" >&5 if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1964 "configure" +#line 2103 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char vprintf(); below. */ @@ -1983,7 +2122,7 @@ vprintf(); ; return 0; } EOF -if { (eval echo configure:1987: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2126: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_vprintf=yes" else @@ -2007,12 +2146,12 @@ fi if test "$ac_cv_func_vprintf" != yes; then echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 -echo "configure:2011: checking for _doprnt" >&5 +echo "configure:2150: checking for _doprnt" >&5 if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2016 "configure" +#line 2155 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char _doprnt(); below. */ @@ -2035,7 +2174,7 @@ _doprnt(); ; return 0; } EOF -if { (eval echo configure:2039: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2178: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func__doprnt=yes" else @@ -2060,7 +2199,7 @@ fi fi echo $ac_n "checking for wait3 that fills in rusage""... $ac_c" 1>&6 -echo "configure:2064: checking for wait3 that fills in rusage" >&5 +echo "configure:2203: checking for wait3 that fills in rusage" >&5 if eval "test \"`echo '$''{'ac_cv_func_wait3_rusage'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2068,7 +2207,7 @@ else ac_cv_func_wait3_rusage=no else cat > conftest.$ac_ext <<EOF -#line 2072 "configure" +#line 2211 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/time.h> @@ -2099,7 +2238,7 @@ main() { } } EOF -if { (eval echo configure:2103: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:2242: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then ac_cv_func_wait3_rusage=yes else @@ -2122,7 +2261,7 @@ EOF fi echo $ac_n "checking for working strcoll""... $ac_c" 1>&6 -echo "configure:2126: checking for working strcoll" >&5 +echo "configure:2265: checking for working strcoll" >&5 if eval "test \"`echo '$''{'ac_cv_func_strcoll_works'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2130,7 +2269,7 @@ else ac_cv_func_strcoll_works=no else cat > conftest.$ac_ext <<EOF -#line 2134 "configure" +#line 2273 "configure" #include "confdefs.h" #include <string.h> main () @@ -2140,7 +2279,7 @@ main () strcoll ("123", "456") >= 0); } EOF -if { (eval echo configure:2144: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:2283: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then ac_cv_func_strcoll_works=yes else @@ -2165,9 +2304,9 @@ fi if test "$ac_cv_func_vprintf" = no; then echo $ac_n "checking for declaration of vprintf in stdio.h""... $ac_c" 1>&6 -echo "configure:2169: checking for declaration of vprintf in stdio.h" >&5 +echo "configure:2308: checking for declaration of vprintf in stdio.h" >&5 cat > conftest.$ac_ext <<EOF -#line 2171 "configure" +#line 2310 "configure" #include "confdefs.h" #include <stdio.h> EOF @@ -2188,12 +2327,12 @@ EOF fi echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 -echo "configure:2192: checking return type of signal handlers" >&5 +echo "configure:2331: checking return type of signal handlers" >&5 if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2197 "configure" +#line 2336 "configure" #include "confdefs.h" #include <sys/types.h> #include <signal.h> @@ -2210,7 +2349,7 @@ int main() { int i; ; return 0; } EOF -if { (eval echo configure:2214: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2353: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_type_signal=void else @@ -2230,12 +2369,12 @@ EOF echo $ac_n "checking for __setostype""... $ac_c" 1>&6 -echo "configure:2234: checking for __setostype" >&5 +echo "configure:2373: checking for __setostype" >&5 if eval "test \"`echo '$''{'ac_cv_func___setostype'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2239 "configure" +#line 2378 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char __setostype(); below. */ @@ -2258,7 +2397,7 @@ __setostype(); ; return 0; } EOF -if { (eval echo configure:2262: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2401: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func___setostype=yes" else @@ -2281,12 +2420,12 @@ else fi echo $ac_n "checking for wait3""... $ac_c" 1>&6 -echo "configure:2285: checking for wait3" >&5 +echo "configure:2424: checking for wait3" >&5 if eval "test \"`echo '$''{'ac_cv_func_wait3'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2290 "configure" +#line 2429 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char wait3(); below. */ @@ -2309,7 +2448,7 @@ wait3(); ; return 0; } EOF -if { (eval echo configure:2313: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2452: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_wait3=yes" else @@ -2333,12 +2472,12 @@ fi echo $ac_n "checking for mkfifo""... $ac_c" 1>&6 -echo "configure:2337: checking for mkfifo" >&5 +echo "configure:2476: checking for mkfifo" >&5 if eval "test \"`echo '$''{'ac_cv_func_mkfifo'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2342 "configure" +#line 2481 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char mkfifo(); below. */ @@ -2361,7 +2500,7 @@ mkfifo(); ; return 0; } EOF -if { (eval echo configure:2365: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2504: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_mkfifo=yes" else @@ -2393,12 +2532,12 @@ for ac_func in dup2 select getdtablesize getgroups gethostname \ getrlimit getrusage gettimeofday waitpid tcgetpgrp do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2397: checking for $ac_func" >&5 +echo "configure:2536: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2402 "configure" +#line 2541 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -2421,7 +2560,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2425: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2564: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2447,16 +2586,17 @@ done for ac_func in bcopy bzero confstr getcwd strcasecmp setenv putenv \ - setlinebuf setlocale strchr strerror tcgetattr uname \ - sysconf ulimit times tzset siginterrupt memmove + setlinebuf setlocale strchr strerror strtod strtol \ + strtoul tcgetattr uname sysconf ulimit times tzset \ + siginterrupt memmove do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2455: checking for $ac_func" >&5 +echo "configure:2595: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2460 "configure" +#line 2600 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -2479,7 +2619,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2483: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2623: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2508,17 +2648,17 @@ for ac_hdr in libintl.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:2512: checking for $ac_hdr" >&5 +echo "configure:2652: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2517 "configure" +#line 2657 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2522: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2662: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* @@ -2547,12 +2687,12 @@ done for ac_func in gettext textdomain bindtextdomain do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2551: checking for $ac_func" >&5 +echo "configure:2691: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2556 "configure" +#line 2696 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -2575,7 +2715,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2579: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2719: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2602,7 +2742,7 @@ done if test "$ac_cv_func_bindtextdomain" = "no"; then echo $ac_n "checking for bindtextdomain in -lintl""... $ac_c" 1>&6 -echo "configure:2606: checking for bindtextdomain in -lintl" >&5 +echo "configure:2746: checking for bindtextdomain in -lintl" >&5 ac_lib_var=`echo intl'_'bindtextdomain | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -2610,7 +2750,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lintl $LIBS" cat > conftest.$ac_ext <<EOF -#line 2614 "configure" +#line 2754 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -2621,7 +2761,7 @@ int main() { bindtextdomain() ; return 0; } EOF -if { (eval echo configure:2625: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2765: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -2652,12 +2792,12 @@ fi for ac_func in gettext textdomain bindtextdomain do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2656: checking for $ac_func" >&5 +echo "configure:2796: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2661 "configure" +#line 2801 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -2680,7 +2820,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2684: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2824: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2707,8 +2847,9 @@ done fi fi +if test "$opt_static_link" != yes; then echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 -echo "configure:2712: checking for dlopen in -ldl" >&5 +echo "configure:2853: checking for dlopen in -ldl" >&5 ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -2716,7 +2857,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldl $LIBS" cat > conftest.$ac_ext <<EOF -#line 2720 "configure" +#line 2861 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -2727,7 +2868,7 @@ int main() { dlopen() ; return 0; } EOF -if { (eval echo configure:2731: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2872: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -2757,12 +2898,12 @@ fi for ac_func in dlopen dlclose dlsym do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2761: checking for $ac_func" >&5 +echo "configure:2902: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2766 "configure" +#line 2907 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -2785,7 +2926,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2789: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2930: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2809,14 +2950,15 @@ else fi done +fi echo $ac_n "checking for sys_siglist declaration in signal.h or unistd.h""... $ac_c" 1>&6 -echo "configure:2815: checking for sys_siglist declaration in signal.h or unistd.h" >&5 +echo "configure:2957: checking for sys_siglist declaration in signal.h or unistd.h" >&5 if eval "test \"`echo '$''{'ac_cv_decl_sys_siglist'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2820 "configure" +#line 2962 "configure" #include "confdefs.h" #include <sys/types.h> #include <signal.h> @@ -2828,7 +2970,7 @@ int main() { char *msg = *(sys_siglist + 1); ; return 0; } EOF -if { (eval echo configure:2832: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2974: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_decl_sys_siglist=yes else @@ -2854,12 +2996,12 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 -echo "configure:2858: checking for $ac_hdr that defines DIR" >&5 +echo "configure:3000: checking for $ac_hdr that defines DIR" >&5 if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2863 "configure" +#line 3005 "configure" #include "confdefs.h" #include <sys/types.h> #include <$ac_hdr> @@ -2867,7 +3009,7 @@ int main() { DIR *dirp = 0; ; return 0; } EOF -if { (eval echo configure:2871: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3013: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* eval "ac_cv_header_dirent_$ac_safe=yes" else @@ -2892,7 +3034,7 @@ done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 -echo "configure:2896: checking for opendir in -ldir" >&5 +echo "configure:3038: checking for opendir in -ldir" >&5 ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -2900,7 +3042,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldir $LIBS" cat > conftest.$ac_ext <<EOF -#line 2904 "configure" +#line 3046 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -2911,7 +3053,7 @@ int main() { opendir() ; return 0; } EOF -if { (eval echo configure:2915: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:3057: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -2933,7 +3075,7 @@ fi else echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 -echo "configure:2937: checking for opendir in -lx" >&5 +echo "configure:3079: checking for opendir in -lx" >&5 ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -2941,7 +3083,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lx $LIBS" cat > conftest.$ac_ext <<EOF -#line 2945 "configure" +#line 3087 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -2952,7 +3094,7 @@ int main() { opendir() ; return 0; } EOF -if { (eval echo configure:2956: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:3098: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -2975,12 +3117,12 @@ fi fi echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 -echo "configure:2979: checking whether time.h and sys/time.h may both be included" >&5 +echo "configure:3121: checking whether time.h and sys/time.h may both be included" >&5 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2984 "configure" +#line 3126 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/time.h> @@ -2989,7 +3131,7 @@ int main() { struct tm *tp; ; return 0; } EOF -if { (eval echo configure:2993: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3135: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time=yes else @@ -3011,21 +3153,22 @@ fi for ac_hdr in unistd.h stdlib.h stdarg.h varargs.h limits.h string.h \ - memory.h locale.h termcap.h termio.h termios.h dlfcn.h + memory.h locale.h termcap.h termio.h termios.h dlfcn.h \ + stddef.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:3019: checking for $ac_hdr" >&5 +echo "configure:3162: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3024 "configure" +#line 3167 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3029: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3172: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* @@ -3057,17 +3200,17 @@ for ac_hdr in sys/ptem.h sys/pte.h sys/stream.h sys/select.h sys/file.h \ do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:3061: checking for $ac_hdr" >&5 +echo "configure:3204: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3066 "configure" +#line 3209 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3071: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3214: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* @@ -3100,14 +3243,14 @@ if test "X$bash_cv_have_socklib" = "X"; then _bash_needmsg= else echo $ac_n "checking for socket library""... $ac_c" 1>&6 -echo "configure:3104: checking for socket library" >&5 +echo "configure:3247: checking for socket library" >&5 _bash_needmsg=yes fi if eval "test \"`echo '$''{'bash_cv_have_socklib'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo $ac_n "checking for getpeername in -lsocket""... $ac_c" 1>&6 -echo "configure:3111: checking for getpeername in -lsocket" >&5 +echo "configure:3254: checking for getpeername in -lsocket" >&5 ac_lib_var=`echo socket'_'getpeername | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -3115,7 +3258,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lsocket -lnsl $LIBS" cat > conftest.$ac_ext <<EOF -#line 3119 "configure" +#line 3262 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -3126,7 +3269,7 @@ int main() { getpeername() ; return 0; } EOF -if { (eval echo configure:3130: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:3273: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -3159,14 +3302,14 @@ if test $bash_cv_have_socklib = yes; then _bash_needmsg= else echo $ac_n "checking for libnsl""... $ac_c" 1>&6 -echo "configure:3163: checking for libnsl" >&5 +echo "configure:3306: checking for libnsl" >&5 _bash_needmsg=yes fi if eval "test \"`echo '$''{'bash_cv_have_libnsl'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo $ac_n "checking for t_open in -lnsl""... $ac_c" 1>&6 -echo "configure:3170: checking for t_open in -lnsl" >&5 +echo "configure:3313: checking for t_open in -lnsl" >&5 ac_lib_var=`echo nsl'_'t_open | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -3174,7 +3317,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext <<EOF -#line 3178 "configure" +#line 3321 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -3185,7 +3328,7 @@ int main() { t_open() ; return 0; } EOF -if { (eval echo configure:3189: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:3332: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -3230,12 +3373,12 @@ fi fi echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 -echo "configure:3234: checking for uid_t in sys/types.h" >&5 +echo "configure:3377: checking for uid_t in sys/types.h" >&5 if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3239 "configure" +#line 3382 "configure" #include "confdefs.h" #include <sys/types.h> EOF @@ -3264,7 +3407,7 @@ EOF fi echo $ac_n "checking type of array argument to getgroups""... $ac_c" 1>&6 -echo "configure:3268: checking type of array argument to getgroups" >&5 +echo "configure:3411: checking type of array argument to getgroups" >&5 if eval "test \"`echo '$''{'ac_cv_type_getgroups'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3272,7 +3415,7 @@ else ac_cv_type_getgroups=cross else cat > conftest.$ac_ext <<EOF -#line 3276 "configure" +#line 3419 "configure" #include "confdefs.h" /* Thanks to Mike Rendell for this test. */ @@ -3297,7 +3440,7 @@ main() } EOF -if { (eval echo configure:3301: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:3444: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then ac_cv_type_getgroups=gid_t else @@ -3311,7 +3454,7 @@ fi if test $ac_cv_type_getgroups = cross; then cat > conftest.$ac_ext <<EOF -#line 3315 "configure" +#line 3458 "configure" #include "confdefs.h" #include <unistd.h> EOF @@ -3335,12 +3478,12 @@ EOF echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 -echo "configure:3339: checking for ANSI C header files" >&5 +echo "configure:3482: checking for ANSI C header files" >&5 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3344 "configure" +#line 3487 "configure" #include "confdefs.h" #include <stdlib.h> #include <stdarg.h> @@ -3348,7 +3491,7 @@ else #include <float.h> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3352: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3495: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* @@ -3365,7 +3508,7 @@ rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext <<EOF -#line 3369 "configure" +#line 3512 "configure" #include "confdefs.h" #include <string.h> EOF @@ -3383,7 +3526,7 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext <<EOF -#line 3387 "configure" +#line 3530 "configure" #include "confdefs.h" #include <stdlib.h> EOF @@ -3404,7 +3547,7 @@ if test "$cross_compiling" = yes; then : else cat > conftest.$ac_ext <<EOF -#line 3408 "configure" +#line 3551 "configure" #include "confdefs.h" #include <ctype.h> #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') @@ -3415,7 +3558,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF -if { (eval echo configure:3419: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:3562: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then : else @@ -3439,12 +3582,12 @@ EOF fi echo $ac_n "checking for off_t""... $ac_c" 1>&6 -echo "configure:3443: checking for off_t" >&5 +echo "configure:3586: checking for off_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3448 "configure" +#line 3591 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -3472,12 +3615,12 @@ EOF fi echo $ac_n "checking for mode_t""... $ac_c" 1>&6 -echo "configure:3476: checking for mode_t" >&5 +echo "configure:3619: checking for mode_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3481 "configure" +#line 3624 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -3505,12 +3648,12 @@ EOF fi echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 -echo "configure:3509: checking for uid_t in sys/types.h" >&5 +echo "configure:3652: checking for uid_t in sys/types.h" >&5 if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3514 "configure" +#line 3657 "configure" #include "confdefs.h" #include <sys/types.h> EOF @@ -3539,12 +3682,12 @@ EOF fi echo $ac_n "checking for pid_t""... $ac_c" 1>&6 -echo "configure:3543: checking for pid_t" >&5 +echo "configure:3686: checking for pid_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3548 "configure" +#line 3691 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -3572,12 +3715,12 @@ EOF fi echo $ac_n "checking for size_t""... $ac_c" 1>&6 -echo "configure:3576: checking for size_t" >&5 +echo "configure:3719: checking for size_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3581 "configure" +#line 3724 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -3605,12 +3748,12 @@ EOF fi echo $ac_n "checking for time_t""... $ac_c" 1>&6 -echo "configure:3609: checking for time_t" >&5 +echo "configure:3752: checking for time_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_time_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3614 "configure" +#line 3757 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -3639,12 +3782,12 @@ fi echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 -echo "configure:3643: checking return type of signal handlers" >&5 +echo "configure:3786: checking return type of signal handlers" >&5 if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3648 "configure" +#line 3791 "configure" #include "confdefs.h" #include <sys/types.h> #include <signal.h> @@ -3661,7 +3804,7 @@ int main() { int i; ; return 0; } EOF -if { (eval echo configure:3665: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3808: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_type_signal=void else @@ -3680,13 +3823,430 @@ EOF +echo $ac_n "checking size of int""... $ac_c" 1>&6 +echo "configure:3828: checking size of int" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 3836 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(int)); + exit(0); +} +EOF +if { (eval echo configure:3847: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_int=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_int=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_int" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_INT $ac_cv_sizeof_int +EOF + + +echo $ac_n "checking size of long""... $ac_c" 1>&6 +echo "configure:3867: checking size of long" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 3875 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(long)); + exit(0); +} +EOF +if { (eval echo configure:3886: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_long=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_long=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_long" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_LONG $ac_cv_sizeof_long +EOF + + +echo $ac_n "checking size of char *""... $ac_c" 1>&6 +echo "configure:3906: checking size of char *" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_char_p'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 3914 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(char *)); + exit(0); +} +EOF +if { (eval echo configure:3925: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_char_p=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_char_p=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_char_p" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_CHAR_P $ac_cv_sizeof_char_p +EOF + + + +echo $ac_n "checking for int32_t""... $ac_c" 1>&6 +echo "configure:3946: checking for int32_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_int32_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 3951 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_int32_t=yes +else + rm -rf conftest* + ac_cv_type_int32_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_int32_t" 1>&6 +if test $ac_cv_type_int32_t = no; then + cat >> confdefs.h <<\EOF +#define int32_t +EOF + +fi + +if test "$ac_cv_type_int32_t" = "no"; then + +if test "X$bash_cv_type_int32_t" = "X"; then +_bash_needmsg=yes +else +echo $ac_n "checking which builtin C type is 32 bits wide""... $ac_c" 1>&6 +echo "configure:3984: checking which builtin C type is 32 bits wide" >&5 +_bash_needmsg= +fi +if eval "test \"`echo '$''{'bash_cv_type_int32_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check type sizes if cross-compiling -- defaulting to int" 1>&2; exit 1; } + bash_cv_type_int32_t=int + +else + cat > conftest.$ac_ext <<EOF +#line 3996 "configure" +#include "confdefs.h" + +main() +{ +#if SIZEOF_INT == 4 +exit (0); +#else +# if SIZEOF_LONG == 4 +exit (1); +# else +# error cannot find 32 bit type... +# endif +#endif +} +EOF +if { (eval echo configure:4012: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_type_int32_t=int +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_type_int32_t=long +fi +rm -fr conftest* +fi + +fi + +if test "X$_bash_needmsg" = "Xyes"; then +echo $ac_n "checking which builtin C type is 32 bits wide""... $ac_c" 1>&6 +echo "configure:4028: checking which builtin C type is 32 bits wide" >&5 +fi +echo "$ac_t""$bash_cv_type_int32_t" 1>&6; +if test "$bash_cv_type_int32_t" = "int"; then +cat >> confdefs.h <<\EOF +#define int32_t int +EOF + +else +cat >> confdefs.h <<\EOF +#define int32_t long +EOF + +fi + +fi +echo $ac_n "checking for u_int32_t""... $ac_c" 1>&6 +echo "configure:4045: checking for u_int32_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_u_int32_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 4050 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "u_int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_u_int32_t=yes +else + rm -rf conftest* + ac_cv_type_u_int32_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_u_int32_t" 1>&6 +if test $ac_cv_type_u_int32_t = no; then + cat >> confdefs.h <<\EOF +#define u_int32_t +EOF + +fi + +if test "$ac_cv_type_u_int32_t" = "no"; then + +if test "X$bash_cv_type_u_int32_t" = "X"; then +_bash_needmsg=yes +else +echo $ac_n "checking which unsigned builtin C type is 32 bits wide""... $ac_c" 1>&6 +echo "configure:4083: checking which unsigned builtin C type is 32 bits wide" >&5 +_bash_needmsg= +fi +if eval "test \"`echo '$''{'bash_cv_type_u_int32_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check type sizes if cross-compiling -- defaulting to int" 1>&2; exit 1; } + bash_cv_type_u_int32_t=int + +else + cat > conftest.$ac_ext <<EOF +#line 4095 "configure" +#include "confdefs.h" + +main() +{ +#if SIZEOF_INT == 4 +exit (0); +#else +# if SIZEOF_LONG == 4 +exit (1); +# else +# error cannot find 32 bit type... +# endif +#endif +} +EOF +if { (eval echo configure:4111: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_type_u_int32_t=int +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_type_u_int32_t=long +fi +rm -fr conftest* +fi + +fi + +if test "X$_bash_needmsg" = "Xyes"; then +echo $ac_n "checking which unsigned builtin C type is 32 bits wide""... $ac_c" 1>&6 +echo "configure:4127: checking which unsigned builtin C type is 32 bits wide" >&5 +fi +echo "$ac_t""$bash_cv_type_u_int32_t" 1>&6; +if test "$bash_cv_type_u_int32_t" = "int"; then +cat >> confdefs.h <<\EOF +#define u_int32_t unsigned int +EOF + +else +cat >> confdefs.h <<\EOF +#define u_int32_t unsigned long +EOF + +fi + +fi + +echo $ac_n "checking for ptrdiff_t""... $ac_c" 1>&6 +echo "configure:4145: checking for ptrdiff_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_ptrdiff_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 4150 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ptrdiff_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_ptrdiff_t=yes +else + rm -rf conftest* + ac_cv_type_ptrdiff_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_ptrdiff_t" 1>&6 +if test $ac_cv_type_ptrdiff_t = no; then + cat >> confdefs.h <<\EOF +#define ptrdiff_t +EOF + +fi + +if test "$ac_cv_type_ptrdiff_t" = "no"; then + +if test "X$bash_cv_type_ptrdiff_t" = "X"; then +_bash_needmsg=yes +else +echo $ac_n "checking which builtin C type is correct for ptrdiff_t""... $ac_c" 1>&6 +echo "configure:4183: checking which builtin C type is correct for ptrdiff_t" >&5 +_bash_needmsg= +fi +if eval "test \"`echo '$''{'bash_cv_type_ptrdiff_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check type sizes if cross-compiling -- defaulting to int" 1>&2; exit 1; } + bash_cv_type_ptrdiff_t=int + +else + cat > conftest.$ac_ext <<EOF +#line 4195 "configure" +#include "confdefs.h" + +main() +{ +#if SIZEOF_CHAR_P == SIZEOF_INT +exit (0); +#else +# if SIZEOF_CHAR_P == SIZEOF_LONG +exit (1); +# else +# error cannot find type for pointer arithmetic... +# endif +#endif +} +EOF +if { (eval echo configure:4211: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_type_ptrdiff_t=int +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_type_ptrdiff_t=long +fi +rm -fr conftest* +fi + +fi + +if test "X$_bash_needmsg" = "Xyes"; then +echo $ac_n "checking which builtin C type is correct for ptrdiff_t""... $ac_c" 1>&6 +echo "configure:4227: checking which builtin C type is correct for ptrdiff_t" >&5 +fi +echo "$ac_t""$bash_cv_type_ptrdiff_t" 1>&6; +if test "$bash_cv_type_ptrdiff_t" = "int"; then +cat >> confdefs.h <<\EOF +#define ptrdiff_t int +EOF + +else +cat >> confdefs.h <<\EOF +#define ptrdiff_t long +EOF + +fi + +fi + echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&6 -echo "configure:3685: checking whether stat file-mode macros are broken" >&5 +echo "configure:4245: checking whether stat file-mode macros are broken" >&5 if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3690 "configure" +#line 4250 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/stat.h> @@ -3737,7 +4297,7 @@ EOF fi cat > conftest.$ac_ext <<EOF -#line 3741 "configure" +#line 4301 "configure" #include "confdefs.h" #include <sys/time.h> EOF @@ -3750,7 +4310,7 @@ rm -f conftest* if test -z "$bash_cv_struct_timeval"; then cat > conftest.$ac_ext <<EOF -#line 3754 "configure" +#line 4314 "configure" #include "confdefs.h" #include <time.h> EOF @@ -3773,14 +4333,14 @@ EOF fi echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 -echo "configure:3777: checking whether byte ordering is bigendian" >&5 +echo "configure:4337: checking whether byte ordering is bigendian" >&5 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. cat > conftest.$ac_ext <<EOF -#line 3784 "configure" +#line 4344 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/param.h> @@ -3791,11 +4351,11 @@ int main() { #endif ; return 0; } EOF -if { (eval echo configure:3795: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4355: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext <<EOF -#line 3799 "configure" +#line 4359 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/param.h> @@ -3806,7 +4366,7 @@ int main() { #endif ; return 0; } EOF -if { (eval echo configure:3810: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4370: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_bigendian=yes else @@ -3826,7 +4386,7 @@ if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <<EOF -#line 3830 "configure" +#line 4390 "configure" #include "confdefs.h" main () { /* Are we little or big endian? From Harbison&Steele. */ @@ -3839,7 +4399,7 @@ main () { exit (u.c[sizeof (long) - 1] == 1); } EOF -if { (eval echo configure:3843: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4403: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then ac_cv_c_bigendian=no else @@ -3866,7 +4426,7 @@ fi # Pull the hash mark out of the macro call to avoid m4 problems. ac_msg="whether #! works in shell scripts" echo $ac_n "checking $ac_msg""... $ac_c" 1>&6 -echo "configure:3870: checking $ac_msg" >&5 +echo "configure:4430: checking $ac_msg" >&5 if eval "test \"`echo '$''{'ac_cv_sys_interpreter'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3892,7 +4452,7 @@ EOF fi echo $ac_n "checking for restartable system calls""... $ac_c" 1>&6 -echo "configure:3896: checking for restartable system calls" >&5 +echo "configure:4456: checking for restartable system calls" >&5 if eval "test \"`echo '$''{'ac_cv_sys_restartable_syscalls'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3900,7 +4460,7 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <<EOF -#line 3904 "configure" +#line 4464 "configure" #include "confdefs.h" /* Exit 0 (true) if wait returns something other than -1, i.e. the pid of the child, which means that wait was restarted @@ -3918,7 +4478,7 @@ main () { } EOF -if { (eval echo configure:3922: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4482: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then ac_cv_sys_restartable_syscalls=yes else @@ -3943,22 +4503,22 @@ fi if test "$ac_cv_func_lstat" = "no"; then echo $ac_n "checking for lstat""... $ac_c" 1>&6 -echo "configure:3947: checking for lstat" >&5 +echo "configure:4507: checking for lstat" >&5 if eval "test \"`echo '$''{'bash_cv_func_lstat'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3952 "configure" +#line 4512 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/stat.h> int main() { - lstat("",(struct stat *)0); + lstat(".",(struct stat *)0); ; return 0; } EOF -if { (eval echo configure:3962: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:4522: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* bash_cv_func_lstat=yes else @@ -3981,15 +4541,16 @@ fi fi echo $ac_n "checking if dup2 fails to clear the close-on-exec flag""... $ac_c" 1>&6 -echo "configure:3985: checking if dup2 fails to clear the close-on-exec flag" >&5 +echo "configure:4545: checking if dup2 fails to clear the close-on-exec flag" >&5 if eval "test \"`echo '$''{'bash_cv_dup2_broken'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check dup2 if cross compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check dup2 if cross compiling -- defaulting to no" 1>&2; exit 1; } + bash_cv_dup2_broken=no else cat > conftest.$ac_ext <<EOF -#line 3993 "configure" +#line 4554 "configure" #include "confdefs.h" #include <sys/types.h> @@ -4009,7 +4570,7 @@ main() } EOF -if { (eval echo configure:4013: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4574: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_dup2_broken=yes else @@ -4034,15 +4595,16 @@ fi echo $ac_n "checking whether pgrps need synchronization""... $ac_c" 1>&6 -echo "configure:4038: checking whether pgrps need synchronization" >&5 +echo "configure:4599: checking whether pgrps need synchronization" >&5 if eval "test \"`echo '$''{'bash_cv_pgrp_pipe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check pgrp synchronization if cross compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check pgrp synchronization if cross compiling -- defaulting to no" 1>&2; exit 1; } + bash_cv_pgrp_pipe=no else cat > conftest.$ac_ext <<EOF -#line 4046 "configure" +#line 4608 "configure" #include "confdefs.h" #ifdef HAVE_UNISTD_H @@ -4094,7 +4656,7 @@ main() } EOF -if { (eval echo configure:4098: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4660: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_pgrp_pipe=no else @@ -4119,13 +4681,13 @@ fi echo $ac_n "checking for type of signal functions""... $ac_c" 1>&6 -echo "configure:4123: checking for type of signal functions" >&5 +echo "configure:4685: checking for type of signal functions" >&5 if eval "test \"`echo '$''{'bash_cv_signal_vintage'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4129 "configure" +#line 4691 "configure" #include "confdefs.h" #include <signal.h> int main() { @@ -4138,7 +4700,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:4142: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:4704: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* bash_cv_signal_vintage=posix else @@ -4147,7 +4709,7 @@ else rm -rf conftest* cat > conftest.$ac_ext <<EOF -#line 4151 "configure" +#line 4713 "configure" #include "confdefs.h" #include <signal.h> int main() { @@ -4157,7 +4719,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:4161: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:4723: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* bash_cv_signal_vintage=4.2bsd else @@ -4166,7 +4728,7 @@ else rm -rf conftest* cat > conftest.$ac_ext <<EOF -#line 4170 "configure" +#line 4732 "configure" #include "confdefs.h" #include <signal.h> @@ -4179,7 +4741,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:4183: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:4745: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* bash_cv_signal_vintage=svr3 else @@ -4218,13 +4780,83 @@ EOF fi +if test "$ac_cv_sys_restartable_syscalls" = "no"; then + +echo $ac_n "checking for restartable system calls with posix sigaction""... $ac_c" 1>&6 +echo "configure:4787: checking for restartable system calls with posix sigaction" >&5 +if eval "test \"`echo '$''{'bash_cv_sys_restartable_syscalls'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check restartable syscalls if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 4795 "configure" +#include "confdefs.h" +/* Exit 0 (true) if wait returns something other than -1, + i.e. the pid of the child, which means that wait was restarted + after getting the signal. */ +#include <sys/types.h> +#include <signal.h> +static int caught = 0; +void ucatch (isig) int isig; { caught = 1; } +main () +{ +#if !defined (_POSIX_VERSION) || !defined (HAVE_POSIX_SIGNALS) + exit (1); +#else + struct sigaction act, oact; + int i, status; + + act.sa_handler = ucatch; + /* Might want to add SA_RESTART here, but bash's set_signal_handler + does not. */ + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + sigemptyset(&oact.sa_mask); + i = fork (); + /* A possible race condition here, but in practice it never happens. */ + if (i == 0) { sleep (3); kill (getppid (), SIGINT); sleep (3); exit (0); } + sigaction(SIGINT, &act, &oact); + status = wait(&i); + if (status == -1) wait(&i); + exit (status == -1); +#endif +} + +EOF +if { (eval echo configure:4829: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + bash_cv_sys_restartable_syscalls=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + bash_cv_sys_restartable_syscalls=no +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$bash_cv_sys_restartable_syscalls" 1>&6 +if test $bash_cv_sys_restartable_syscalls = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_RESTARTABLE_SYSCALLS 1 +EOF + +fi + +fi + echo $ac_n "checking for sys_errlist and sys_nerr""... $ac_c" 1>&6 -echo "configure:4223: checking for sys_errlist and sys_nerr" >&5 +echo "configure:4855: checking for sys_errlist and sys_nerr" >&5 if eval "test \"`echo '$''{'bash_cv_sys_errlist'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4228 "configure" +#line 4860 "configure" #include "confdefs.h" #include <errno.h> int main() { @@ -4233,7 +4865,7 @@ extern char *sys_errlist[]; char *msg = sys_errlist[sys_nerr - 1]; ; return 0; } EOF -if { (eval echo configure:4237: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:4869: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* bash_cv_sys_errlist=yes else @@ -4254,15 +4886,16 @@ fi echo $ac_n "checking for sys_siglist in system C library""... $ac_c" 1>&6 -echo "configure:4258: checking for sys_siglist in system C library" >&5 +echo "configure:4890: checking for sys_siglist in system C library" >&5 if eval "test \"`echo '$''{'bash_cv_sys_siglist'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check for sys_siglist if cross compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check for sys_siglist if cross compiling -- defaulting to no" 1>&2; exit 1; } + bash_cv_sys_siglist=no else cat > conftest.$ac_ext <<EOF -#line 4266 "configure" +#line 4899 "configure" #include "confdefs.h" #include <sys/types.h> @@ -4279,7 +4912,7 @@ char *msg = sys_siglist[2]; exit(msg == 0); } EOF -if { (eval echo configure:4283: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4916: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_sys_siglist=yes else @@ -4292,6 +4925,7 @@ rm -fr conftest* fi fi + echo "$ac_t""$bash_cv_sys_siglist" 1>&6 if test $bash_cv_sys_siglist = yes; then cat >> confdefs.h <<\EOF @@ -4301,12 +4935,12 @@ EOF fi echo $ac_n "checking for _sys_siglist in signal.h or unistd.h""... $ac_c" 1>&6 -echo "configure:4305: checking for _sys_siglist in signal.h or unistd.h" >&5 +echo "configure:4939: checking for _sys_siglist in signal.h or unistd.h" >&5 if eval "test \"`echo '$''{'bash_cv_decl_under_sys_siglist'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4310 "configure" +#line 4944 "configure" #include "confdefs.h" #include <sys/types.h> @@ -4318,7 +4952,7 @@ int main() { char *msg = _sys_siglist[2]; ; return 0; } EOF -if { (eval echo configure:4322: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4956: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_decl_under_sys_siglist=yes else @@ -4339,15 +4973,16 @@ fi echo $ac_n "checking for _sys_siglist in system C library""... $ac_c" 1>&6 -echo "configure:4343: checking for _sys_siglist in system C library" >&5 +echo "configure:4977: checking for _sys_siglist in system C library" >&5 if eval "test \"`echo '$''{'bash_cv_under_sys_siglist'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check for _sys_siglist if cross compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check for _sys_siglist if cross compiling -- defaulting to no" 1>&2; exit 1; } + bash_cv_under_sys_siglist=no else cat > conftest.$ac_ext <<EOF -#line 4351 "configure" +#line 4986 "configure" #include "confdefs.h" #include <sys/types.h> @@ -4364,7 +4999,7 @@ char *msg = (char *)_sys_siglist[2]; exit(msg == 0); } EOF -if { (eval echo configure:4368: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:5003: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_under_sys_siglist=yes else @@ -4377,6 +5012,7 @@ rm -fr conftest* fi fi + echo "$ac_t""$bash_cv_under_sys_siglist" 1>&6 if test $bash_cv_under_sys_siglist = yes; then cat >> confdefs.h <<\EOF @@ -4387,12 +5023,12 @@ fi echo $ac_n "checking whether signal handlers are of type void""... $ac_c" 1>&6 -echo "configure:4391: checking whether signal handlers are of type void" >&5 +echo "configure:5027: checking whether signal handlers are of type void" >&5 if eval "test \"`echo '$''{'bash_cv_void_sighandler'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4396 "configure" +#line 5032 "configure" #include "confdefs.h" #include <sys/types.h> #include <signal.h> @@ -4407,7 +5043,7 @@ int main() { int i; ; return 0; } EOF -if { (eval echo configure:4411: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5047: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_void_sighandler=yes else @@ -4427,12 +5063,12 @@ EOF fi echo $ac_n "checking for clock_t""... $ac_c" 1>&6 -echo "configure:4431: checking for clock_t" >&5 +echo "configure:5067: checking for clock_t" >&5 if eval "test \"`echo '$''{'bash_cv_type_clock_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4436 "configure" +#line 5072 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -4463,12 +5099,12 @@ EOF fi echo $ac_n "checking for sigset_t""... $ac_c" 1>&6 -echo "configure:4467: checking for sigset_t" >&5 +echo "configure:5103: checking for sigset_t" >&5 if eval "test \"`echo '$''{'bash_cv_type_sigset_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4472 "configure" +#line 5108 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -4499,12 +5135,12 @@ EOF fi echo $ac_n "checking for quad_t""... $ac_c" 1>&6 -echo "configure:4503: checking for quad_t" >&5 +echo "configure:5139: checking for quad_t" >&5 if eval "test \"`echo '$''{'bash_cv_type_quad_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4508 "configure" +#line 5144 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -4540,19 +5176,20 @@ EOF fi echo $ac_n "checking for size and type of struct rlimit fields""... $ac_c" 1>&6 -echo "configure:4544: checking for size and type of struct rlimit fields" >&5 +echo "configure:5180: checking for size and type of struct rlimit fields" >&5 if eval "test \"`echo '$''{'bash_cv_type_rlimit'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4549 "configure" +#line 5185 "configure" #include "confdefs.h" #include <sys/types.h> +#include <sys/resource.h> int main() { rlim_t xxx; ; return 0; } EOF -if { (eval echo configure:4556: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5193: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_type_rlimit=rlim_t else @@ -4561,10 +5198,11 @@ else rm -rf conftest* if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check quad_t if cross compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check quad_t if cross compiling -- defaulting to long" 1>&2; exit 1; } + bash_cv_type_rlimit=long else cat > conftest.$ac_ext <<EOF -#line 4568 "configure" +#line 5206 "configure" #include "confdefs.h" #include <sys/types.h> @@ -4580,7 +5218,7 @@ main() exit(1); } EOF -if { (eval echo configure:4584: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:5222: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_type_rlimit=quad_t else @@ -4612,12 +5250,12 @@ fi echo $ac_n "checking for a c_line member of struct termios""... $ac_c" 1>&6 -echo "configure:4616: checking for a c_line member of struct termios" >&5 +echo "configure:5254: checking for a c_line member of struct termios" >&5 if eval "test \"`echo '$''{'bash_cv_termios_ldisc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4621 "configure" +#line 5259 "configure" #include "confdefs.h" #include <sys/types.h> #include <termios.h> @@ -4625,7 +5263,7 @@ int main() { struct termios t; int i; i = t.c_line; ; return 0; } EOF -if { (eval echo configure:4629: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5267: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_termios_ldisc=yes else @@ -4645,12 +5283,12 @@ EOF fi echo $ac_n "checking for a c_line member of struct termio""... $ac_c" 1>&6 -echo "configure:4649: checking for a c_line member of struct termio" >&5 +echo "configure:5287: checking for a c_line member of struct termio" >&5 if eval "test \"`echo '$''{'bash_cv_termio_ldisc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4654 "configure" +#line 5292 "configure" #include "confdefs.h" #include <sys/types.h> #include <termio.h> @@ -4658,7 +5296,7 @@ int main() { struct termio t; int i; i = t.c_line; ; return 0; } EOF -if { (eval echo configure:4662: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5300: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_termio_ldisc=yes else @@ -4679,12 +5317,12 @@ fi echo $ac_n "checking if struct dirent has a d_ino member""... $ac_c" 1>&6 -echo "configure:4683: checking if struct dirent has a d_ino member" >&5 +echo "configure:5321: checking if struct dirent has a d_ino member" >&5 if eval "test \"`echo '$''{'bash_cv_dirent_has_dino'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4688 "configure" +#line 5326 "configure" #include "confdefs.h" #include <stdio.h> @@ -4713,7 +5351,7 @@ struct dirent d; int z; z = d.d_ino; ; return 0; } EOF -if { (eval echo configure:4717: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5355: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_dirent_has_dino=yes else @@ -4735,12 +5373,12 @@ fi echo $ac_n "checking if struct dirent has a d_fileno member""... $ac_c" 1>&6 -echo "configure:4739: checking if struct dirent has a d_fileno member" >&5 +echo "configure:5377: checking if struct dirent has a d_fileno member" >&5 if eval "test \"`echo '$''{'bash_cv_dirent_has_d_fileno'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4744 "configure" +#line 5382 "configure" #include "confdefs.h" #include <stdio.h> @@ -4769,7 +5407,7 @@ struct dirent d; int z; z = d.d_fileno; ; return 0; } EOF -if { (eval echo configure:4773: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5411: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_dirent_has_d_fileno=yes else @@ -4789,13 +5427,13 @@ EOF fi -echo $ac_n "checking for struct winsize in sys/ioctl.h""... $ac_c" 1>&6 -echo "configure:4794: checking for struct winsize in sys/ioctl.h" >&5 -if eval "test \"`echo '$''{'bash_cv_struct_winsize_in_ioctl'+set}'`\" = set"; then +echo $ac_n "checking for struct winsize in sys/ioctl.h and termios.h""... $ac_c" 1>&6 +echo "configure:5432: checking for struct winsize in sys/ioctl.h and termios.h" >&5 +if eval "test \"`echo '$''{'bash_cv_struct_winsize_header'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4799 "configure" +#line 5437 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/ioctl.h> @@ -4803,34 +5441,61 @@ int main() { struct winsize x; ; return 0; } EOF -if { (eval echo configure:4807: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5445: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bash_cv_struct_winsize_header=ioctl_h +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + cat > conftest.$ac_ext <<EOF +#line 5453 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <termios.h> +int main() { +struct winsize x; +; return 0; } +EOF +if { (eval echo configure:5461: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* - bash_cv_struct_winsize_in_ioctl=yes + bash_cv_struct_winsize_header=termios_h else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* - bash_cv_struct_winsize_in_ioctl=no + bash_cv_struct_winsize_header=other +fi +rm -f conftest* + fi rm -f conftest* fi -echo "$ac_t""$bash_cv_struct_winsize_in_ioctl" 1>&6 -if test $bash_cv_struct_winsize_in_ioctl = yes; then -cat >> confdefs.h <<\EOF +if test $bash_cv_struct_winsize_header = ioctl_h; then + echo "$ac_t""sys/ioctl.h" 1>&6 + cat >> confdefs.h <<\EOF #define STRUCT_WINSIZE_IN_SYS_IOCTL 1 EOF +elif test $bash_cv_struct_winsize_header = termios_h; then + echo "$ac_t""termios.h" 1>&6 + cat >> confdefs.h <<\EOF +#define STRUCT_WINSIZE_IN_TERMIOS 1 +EOF + +else + echo "$ac_t""not found" 1>&6 fi -echo $ac_n "checking for the existance of strsignal""... $ac_c" 1>&6 -echo "configure:4829: checking for the existance of strsignal" >&5 +echo $ac_n "checking for the existence of strsignal""... $ac_c" 1>&6 +echo "configure:5494: checking for the existence of strsignal" >&5 if eval "test \"`echo '$''{'bash_cv_have_strsignal'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4834 "configure" +#line 5499 "configure" #include "confdefs.h" #include <sys/types.h> #include <signal.h> @@ -4838,7 +5503,7 @@ int main() { char *s = (char *)strsignal(2); ; return 0; } EOF -if { (eval echo configure:4842: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:5507: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* bash_cv_have_strsignal=yes else @@ -4859,15 +5524,17 @@ EOF fi echo $ac_n "checking if opendir() opens non-directories""... $ac_c" 1>&6 -echo "configure:4863: checking if opendir() opens non-directories" >&5 +echo "configure:5528: checking if opendir() opens non-directories" >&5 if eval "test \"`echo '$''{'bash_cv_opendir_not_robust'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check opendir if cross compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check opendir if cross compiling -- defaulting to no" 1>&2; exit 1; } + bash_cv_opendir_not_robust=no + else cat > conftest.$ac_ext <<EOF -#line 4871 "configure" +#line 5538 "configure" #include "confdefs.h" #include <stdio.h> @@ -4903,7 +5570,7 @@ unlink("/tmp/not_a_directory"); exit (dir == 0); } EOF -if { (eval echo configure:4907: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:5574: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_opendir_not_robust=yes else @@ -4926,15 +5593,17 @@ EOF fi echo $ac_n "checking for declaration of printf in <stdio.h>""... $ac_c" 1>&6 -echo "configure:4930: checking for declaration of printf in <stdio.h>" >&5 +echo "configure:5597: checking for declaration of printf in <stdio.h>" >&5 if eval "test \"`echo '$''{'bash_cv_printf_declared'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check printf declaration if cross compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check printf declaration if cross compiling -- defaulting to yes" 1>&2; exit 1; } + bash_cv_printf_declared=yes + else cat > conftest.$ac_ext <<EOF -#line 4938 "configure" +#line 5607 "configure" #include "confdefs.h" #include <stdio.h> @@ -4951,7 +5620,7 @@ exit(pf == 0); } EOF -if { (eval echo configure:4955: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:5624: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_printf_declared=yes else @@ -4974,15 +5643,17 @@ EOF fi echo $ac_n "checking whether ulimit can substitute for getdtablesize""... $ac_c" 1>&6 -echo "configure:4978: checking whether ulimit can substitute for getdtablesize" >&5 +echo "configure:5647: checking whether ulimit can substitute for getdtablesize" >&5 if eval "test \"`echo '$''{'bash_cv_ulimit_maxfds'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check ulimit if cross compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check ulimit if cross compiling -- defaulting to no" 1>&2; exit 1; } + bash_cv_ulimit_maxfds=no + else cat > conftest.$ac_ext <<EOF -#line 4986 "configure" +#line 5657 "configure" #include "confdefs.h" main() @@ -4992,7 +5663,7 @@ exit (maxfds == -1L); } EOF -if { (eval echo configure:4996: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:5667: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_ulimit_maxfds=yes else @@ -5015,15 +5686,17 @@ EOF fi echo $ac_n "checking to see if getenv can be redefined""... $ac_c" 1>&6 -echo "configure:5019: checking to see if getenv can be redefined" >&5 +echo "configure:5690: checking to see if getenv can be redefined" >&5 if eval "test \"`echo '$''{'bash_cv_getenv_redef'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check getenv redefinition if cross compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check getenv redefinition if cross compiling -- defaulting to yes" 1>&2; exit 1; } + bash_cv_getenv_redef=yes + else cat > conftest.$ac_ext <<EOF -#line 5027 "configure" +#line 5700 "configure" #include "confdefs.h" #ifdef HAVE_UNISTD_H @@ -5058,7 +5731,7 @@ exit(s == 0); /* force optimizer to leave getenv in */ } EOF -if { (eval echo configure:5062: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:5735: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_getenv_redef=yes else @@ -5081,15 +5754,17 @@ EOF fi echo $ac_n "checking if getcwd() calls popen()""... $ac_c" 1>&6 -echo "configure:5085: checking if getcwd() calls popen()" >&5 +echo "configure:5758: checking if getcwd() calls popen()" >&5 if eval "test \"`echo '$''{'bash_cv_getcwd_calls_popen'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check whether getcwd calls popen if cross compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check whether getcwd calls popen if cross compiling -- defaulting to no" 1>&2; exit 1; } + bash_cv_getcwd_calls_popen=no + else cat > conftest.$ac_ext <<EOF -#line 5093 "configure" +#line 5768 "configure" #include "confdefs.h" #include <stdio.h> @@ -5144,7 +5819,7 @@ main() } EOF -if { (eval echo configure:5148: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:5823: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_getcwd_calls_popen=no else @@ -5167,12 +5842,12 @@ EOF fi echo $ac_n "checking for declaration of sbrk in <unistd.h>""... $ac_c" 1>&6 -echo "configure:5171: checking for declaration of sbrk in <unistd.h>" >&5 +echo "configure:5846: checking for declaration of sbrk in <unistd.h>" >&5 if eval "test \"`echo '$''{'bash_cv_sbrk_declared'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 5176 "configure" +#line 5851 "configure" #include "confdefs.h" #include <unistd.h> EOF @@ -5198,15 +5873,17 @@ fi echo $ac_n "checking for presence of POSIX-style sigsetjmp/siglongjmp""... $ac_c" 1>&6 -echo "configure:5202: checking for presence of POSIX-style sigsetjmp/siglongjmp" >&5 +echo "configure:5877: checking for presence of POSIX-style sigsetjmp/siglongjmp" >&5 if eval "test \"`echo '$''{'bash_cv_func_sigsetjmp'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check for sigsetjmp/siglongjmp if cross-compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check for sigsetjmp/siglongjmp if cross-compiling -- defaulting to missing" 1>&2; exit 1; } + bash_cv_func_sigsetjmp=missing + else cat > conftest.$ac_ext <<EOF -#line 5210 "configure" +#line 5887 "configure" #include "confdefs.h" #ifdef HAVE_UNISTD_H @@ -5247,7 +5924,7 @@ exit(1); #endif } EOF -if { (eval echo configure:5251: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:5928: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_func_sigsetjmp=present else @@ -5259,7 +5936,6 @@ fi rm -fr conftest* fi - fi echo "$ac_t""$bash_cv_func_sigsetjmp" 1>&6 @@ -5272,15 +5948,17 @@ fi echo $ac_n "checking whether or not strcoll and strcmp differ""... $ac_c" 1>&6 -echo "configure:5276: checking whether or not strcoll and strcmp differ" >&5 +echo "configure:5952: checking whether or not strcoll and strcmp differ" >&5 if eval "test \"`echo '$''{'bash_cv_func_strcoll_broken'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check strcoll if cross compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check strcoll if cross compiling -- defaulting to no" 1>&2; exit 1; } + bash_cv_func_strcoll_broken=no + else cat > conftest.$ac_ext <<EOF -#line 5284 "configure" +#line 5962 "configure" #include "confdefs.h" #include <stdio.h> @@ -5319,7 +5997,7 @@ char *v[]; } EOF -if { (eval echo configure:5323: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:6001: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_func_strcoll_broken=yes else @@ -5331,7 +6009,6 @@ fi rm -fr conftest* fi - fi echo "$ac_t""$bash_cv_func_strcoll_broken" 1>&6 @@ -5346,15 +6023,17 @@ fi echo $ac_n "checking if signal handlers must be reinstalled when invoked""... $ac_c" 1>&6 -echo "configure:5350: checking if signal handlers must be reinstalled when invoked" >&5 +echo "configure:6027: checking if signal handlers must be reinstalled when invoked" >&5 if eval "test \"`echo '$''{'bash_cv_must_reinstall_sighandlers'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check signal handling if cross compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check signal handling if cross compiling -- defaulting to no" 1>&2; exit 1; } + bash_cv_must_reinstall_sighandlers=no + else cat > conftest.$ac_ext <<EOF -#line 5358 "configure" +#line 6037 "configure" #include "confdefs.h" #include <signal.h> @@ -5401,7 +6080,7 @@ main() } EOF -if { (eval echo configure:5405: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:6084: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_must_reinstall_sighandlers=no else @@ -5425,15 +6104,17 @@ fi echo $ac_n "checking for presence of necessary job control definitions""... $ac_c" 1>&6 -echo "configure:5429: checking for presence of necessary job control definitions" >&5 +echo "configure:6108: checking for presence of necessary job control definitions" >&5 if eval "test \"`echo '$''{'bash_cv_job_control_missing'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check job control if cross-compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check job control if cross-compiling -- defaulting to missing" 1>&2; exit 1; } + bash_cv_job_control_missing=missing + else cat > conftest.$ac_ext <<EOF -#line 5437 "configure" +#line 6118 "configure" #include "confdefs.h" #include <sys/types.h> @@ -5480,7 +6161,7 @@ exit(1); exit(0); } EOF -if { (eval echo configure:5484: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:6165: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_job_control_missing=present else @@ -5492,7 +6173,6 @@ fi rm -fr conftest* fi - fi echo "$ac_t""$bash_cv_job_control_missing" 1>&6 @@ -5504,15 +6184,17 @@ EOF fi echo $ac_n "checking for presence of named pipes""... $ac_c" 1>&6 -echo "configure:5508: checking for presence of named pipes" >&5 +echo "configure:6188: checking for presence of named pipes" >&5 if eval "test \"`echo '$''{'bash_cv_sys_named_pipes'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then - { echo "configure: error: cannot check for named pipes if cross-compiling" 1>&2; exit 1; } + { echo "configure: error: cannot check for named pipes if cross-compiling -- defaulting to missing" 1>&2; exit 1; } + bash_cv_sys_named_pipes=missing + else cat > conftest.$ac_ext <<EOF -#line 5516 "configure" +#line 6198 "configure" #include "confdefs.h" #include <sys/types.h> @@ -5546,7 +6228,7 @@ unlink ("/tmp/sh-np-autoconf"); exit(0); } EOF -if { (eval echo configure:5550: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:6232: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then bash_cv_sys_named_pipes=present else @@ -5558,7 +6240,6 @@ fi rm -fr conftest* fi - fi echo "$ac_t""$bash_cv_sys_named_pipes" 1>&6 @@ -5571,12 +6252,12 @@ fi echo $ac_n "checking for TIOCGWINSZ in sys/ioctl.h""... $ac_c" 1>&6 -echo "configure:5575: checking for TIOCGWINSZ in sys/ioctl.h" >&5 +echo "configure:6256: checking for TIOCGWINSZ in sys/ioctl.h" >&5 if eval "test \"`echo '$''{'bash_cv_tiocgwinsz_in_ioctl'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 5580 "configure" +#line 6261 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/ioctl.h> @@ -5584,7 +6265,7 @@ int main() { int x = TIOCGWINSZ; ; return 0; } EOF -if { (eval echo configure:5588: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:6269: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_tiocgwinsz_in_ioctl=yes else @@ -5605,12 +6286,12 @@ EOF fi echo $ac_n "checking for TIOCSTAT in sys/ioctl.h""... $ac_c" 1>&6 -echo "configure:5609: checking for TIOCSTAT in sys/ioctl.h" >&5 +echo "configure:6290: checking for TIOCSTAT in sys/ioctl.h" >&5 if eval "test \"`echo '$''{'bash_cv_tiocstat_in_ioctl'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 5614 "configure" +#line 6295 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/ioctl.h> @@ -5618,7 +6299,7 @@ int main() { int x = TIOCSTAT; ; return 0; } EOF -if { (eval echo configure:5622: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:6303: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_tiocstat_in_ioctl=yes else @@ -5639,12 +6320,12 @@ EOF fi echo $ac_n "checking for FIONREAD in sys/ioctl.h""... $ac_c" 1>&6 -echo "configure:5643: checking for FIONREAD in sys/ioctl.h" >&5 +echo "configure:6324: checking for FIONREAD in sys/ioctl.h" >&5 if eval "test \"`echo '$''{'bash_cv_fionread_in_ioctl'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 5648 "configure" +#line 6329 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/ioctl.h> @@ -5652,7 +6333,7 @@ int main() { int x = FIONREAD; ; return 0; } EOF -if { (eval echo configure:5656: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:6337: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_fionread_in_ioctl=yes else @@ -5674,19 +6355,19 @@ fi echo $ac_n "checking for speed_t in sys/types.h""... $ac_c" 1>&6 -echo "configure:5678: checking for speed_t in sys/types.h" >&5 +echo "configure:6359: checking for speed_t in sys/types.h" >&5 if eval "test \"`echo '$''{'bash_cv_speed_t_in_sys_types'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 5683 "configure" +#line 6364 "configure" #include "confdefs.h" #include <sys/types.h> int main() { speed_t x; ; return 0; } EOF -if { (eval echo configure:5690: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:6371: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_speed_t_in_sys_types=yes else @@ -5707,12 +6388,12 @@ EOF fi echo $ac_n "checking whether programs are able to redeclare getpw functions""... $ac_c" 1>&6 -echo "configure:5711: checking whether programs are able to redeclare getpw functions" >&5 +echo "configure:6392: checking whether programs are able to redeclare getpw functions" >&5 if eval "test \"`echo '$''{'bash_cv_can_redecl_getpw'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 5716 "configure" +#line 6397 "configure" #include "confdefs.h" #include <sys/types.h> #include <pwd.h> @@ -5723,7 +6404,7 @@ int main() { struct passwd *z; z = getpwent(); z = getpwuid(0); z = getpwnam("root"); ; return 0; } EOF -if { (eval echo configure:5727: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:6408: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_can_redecl_getpw=yes else @@ -5746,12 +6427,12 @@ fi case "$host_os" in hpux*) echo $ac_n "checking whether $host_os needs _KERNEL for RLIMIT defines""... $ac_c" 1>&6 -echo "configure:5750: checking whether $host_os needs _KERNEL for RLIMIT defines" >&5 +echo "configure:6431: checking whether $host_os needs _KERNEL for RLIMIT defines" >&5 if eval "test \"`echo '$''{'bash_cv_kernel_rlimit'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 5755 "configure" +#line 6436 "configure" #include "confdefs.h" #include <sys/types.h> @@ -5764,7 +6445,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:5768: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:6449: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_kernel_rlimit=no else @@ -5772,22 +6453,22 @@ else cat conftest.$ac_ext >&5 rm -rf conftest* cat > conftest.$ac_ext <<EOF -#line 5776 "configure" +#line 6457 "configure" #include "confdefs.h" - #include <sys/types.h> - #define _KERNEL - #include <sys/resource.h> - #undef _KERNEL - +#include <sys/types.h> +#define _KERNEL +#include <sys/resource.h> +#undef _KERNEL + int main() { int f; f = RLIMIT_DATA; - + ; return 0; } EOF -if { (eval echo configure:5791: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:6472: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* bash_cv_kernel_rlimit=yes else @@ -5821,14 +6502,14 @@ if test "X$bash_cv_termcap_lib" = "X"; then _bash_needmsg=yes else echo $ac_n "checking which library has the termcap functions""... $ac_c" 1>&6 -echo "configure:5825: checking which library has the termcap functions" >&5 +echo "configure:6506: checking which library has the termcap functions" >&5 _bash_needmsg= fi if eval "test \"`echo '$''{'bash_cv_termcap_lib'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo $ac_n "checking for tgetent in -ltermcap""... $ac_c" 1>&6 -echo "configure:5832: checking for tgetent in -ltermcap" >&5 +echo "configure:6513: checking for tgetent in -ltermcap" >&5 ac_lib_var=`echo termcap'_'tgetent | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -5836,7 +6517,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ltermcap $LIBS" cat > conftest.$ac_ext <<EOF -#line 5840 "configure" +#line 6521 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -5847,7 +6528,7 @@ int main() { tgetent() ; return 0; } EOF -if { (eval echo configure:5851: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:6532: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -5866,7 +6547,7 @@ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then else echo "$ac_t""no" 1>&6 echo $ac_n "checking for tgetent in -lcurses""... $ac_c" 1>&6 -echo "configure:5870: checking for tgetent in -lcurses" >&5 +echo "configure:6551: checking for tgetent in -lcurses" >&5 ac_lib_var=`echo curses'_'tgetent | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -5874,7 +6555,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lcurses $LIBS" cat > conftest.$ac_ext <<EOF -#line 5878 "configure" +#line 6559 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -5885,7 +6566,7 @@ int main() { tgetent() ; return 0; } EOF -if { (eval echo configure:5889: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:6570: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -5904,7 +6585,7 @@ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then else echo "$ac_t""no" 1>&6 echo $ac_n "checking for tgetent in -lncurses""... $ac_c" 1>&6 -echo "configure:5908: checking for tgetent in -lncurses" >&5 +echo "configure:6589: checking for tgetent in -lncurses" >&5 ac_lib_var=`echo ncurses'_'tgetent | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -5912,7 +6593,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lncurses $LIBS" cat > conftest.$ac_ext <<EOF -#line 5916 "configure" +#line 6597 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -5923,7 +6604,7 @@ int main() { tgetent() ; return 0; } EOF -if { (eval echo configure:5927: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:6608: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -5952,10 +6633,10 @@ fi if test "X$_bash_needmsg" = "Xyes"; then echo $ac_n "checking which library has the termcap functions""... $ac_c" 1>&6 -echo "configure:5956: checking which library has the termcap functions" >&5 +echo "configure:6637: checking which library has the termcap functions" >&5 fi echo "$ac_t""using $bash_cv_termcap_lib" 1>&6 -if test $bash_cv_termcap_lib = gnutermcap; then +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" @@ -5975,7 +6656,7 @@ fi echo $ac_n "checking whether /dev/fd is available""... $ac_c" 1>&6 -echo "configure:5979: checking whether /dev/fd is available" >&5 +echo "configure:6660: checking whether /dev/fd is available" >&5 if eval "test \"`echo '$''{'bash_cv_dev_fd'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -6011,7 +6692,7 @@ EOF fi echo $ac_n "checking for default mail directory""... $ac_c" 1>&6 -echo "configure:6015: checking for default mail directory" >&5 +echo "configure:6696: checking for default mail directory" >&5 if eval "test \"`echo '$''{'bash_cv_mail_dir'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -6103,6 +6784,7 @@ linux*) LOCAL_LDFLAGS=-rdynamic ;; # allow dynamic loading aix4.2*) LOCAL_LDFLAGS="-bexpall -brtl" ;;# allow dynamic loading *qnx*) LOCAL_CFLAGS="-Dqnx -F -3s" LOCAL_LDFLAGS="-3s -lunix -lncurses" ;; powerux) LOCAL_LIBS="-lgen" ;; +cygwin32*) LOCAL_LIBS="-luser32" ;; esac case "$host_cpu" in @@ -6122,12 +6804,13 @@ esac # this should be packaged into a script accessible via ${srcdir}/support case "$srcdir" in .) ;; -*) for d in doc tests support lib ; do # dirs +*) for d in doc tests support lib examples; do # dirs test -d $d || mkdir $d done - for ld in readline glob tilde malloc termcap; do # libdirs + 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 ;; esac @@ -6150,6 +6833,8 @@ BUILD_DIR=`pwd` + + #AC_SUBST(ALLOCA_SOURCE) #AC_SUBST(ALLOCA_OBJECT) @@ -6255,8 +6940,9 @@ ac_given_srcdir=$srcdir ac_given_INSTALL="$INSTALL" trap 'rm -fr `echo "Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \ - lib/malloc/Makefile lib/termcap/Makefile lib/tilde/Makefile \ - doc/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 + lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile \ + lib/tilde/Makefile doc/Makefile support/Makefile \ + examples/loadables/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS <<EOF @@ -6301,6 +6987,8 @@ s%@HISTORY_LIB@%$HISTORY_LIB%g s%@HISTORY_DEP@%$HISTORY_DEP%g s%@CC@%$CC%g s%@CPP@%$CPP%g +s%@CC_FOR_BUILD@%$CC_FOR_BUILD%g +s%@SIGNAMES_H@%$SIGNAMES_H%g s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g s%@INSTALL_DATA@%$INSTALL_DATA%g s%@AR@%$AR%g @@ -6311,6 +6999,7 @@ s%@ALLOCA@%$ALLOCA%g s%@TERMCAP_LIB@%$TERMCAP_LIB%g s%@TERMCAP_DEP@%$TERMCAP_DEP%g s%@JOBS_O@%$JOBS_O%g +s%@PROFILE_FLAGS@%$PROFILE_FLAGS%g s%@incdir@%$incdir%g s%@BUILD_DIR@%$BUILD_DIR%g s%@BASHVERS@%$BASHVERS%g @@ -6361,8 +7050,9 @@ EOF cat >> $CONFIG_STATUS <<EOF CONFIG_FILES=\${CONFIG_FILES-"Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \ - lib/malloc/Makefile lib/termcap/Makefile lib/tilde/Makefile \ - doc/Makefile"} + lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile \ + lib/tilde/Makefile doc/Makefile support/Makefile \ + examples/loadables/Makefile"} EOF cat >> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then diff --git a/configure.in b/configure.in index e64dc4c0..dee3db3d 100644 --- a/configure.in +++ b/configure.in @@ -1,12 +1,12 @@ dnl -dnl Configure script for bash-2.01 +dnl Configure script for bash-2.02 dnl dnl report bugs to chet@po.cwru.edu dnl dnl Process this file with autoconf to produce a configure script. dnl checks for version info -AC_REVISION([for Bash 2.01, version 1.28, from autoconf version] AC_ACVERSION)dnl +AC_REVISION([for Bash 2.02, version 2.19, from autoconf version] AC_ACVERSION)dnl AC_INIT(shell.h) AC_CONFIG_HEADER(config.h) @@ -34,19 +34,20 @@ dnl and some need a special compiler or loader dnl look in the NOTES file for more case "${host_cpu}-${host_os}" in alpha-*) opt_gnu_malloc=no ;; # alpha running osf/1 or linux -*cray*-*) opt_gnu_malloc=no ;; # Crays +*[Cc]ray*-*) opt_gnu_malloc=no ;; # Crays *-osf1*) opt_gnu_malloc=no ;; # other osf/1 machines sparc-svr4*) opt_gnu_malloc=no ;; # sparc SVR4, SVR4.2 sparc-netbsd*) opt_gnu_malloc=no ;; # needs 8-byte alignment sgi-irix6*) opt_gnu_malloc=no ;; # needs 8-byte alignment sparc-linux*) opt_gnu_malloc=no ;; # sparc running linux; requires ELF -*-freebsd*) opt_gnu_malloc=no ;; # they claim it's better +#*-freebsd*) opt_gnu_malloc=no ;; # they claim it's better *-aix*) opt_gnu_malloc=no ;; # AIX machines *-nextstep*) opt_gnu_malloc=no ;; # NeXT machines running NeXTstep *-dgux*) opt_gnu_malloc=no ;; # DG/UX machines *-qnx*) opt_gnu_malloc=no ;; # QNX 4.2 *-machten4) opt_gnu_malloc=no ;; # MachTen 4.x -*-bsdi2.1|*-bsdi3.0) opt_gnu_malloc=no ; : ${CC:=shlicc2} ;; # for loadable builtins +*-bsdi2.1|*-bsdi3.?) opt_gnu_malloc=no ; : ${CC:=shlicc2} ;; # for loadable builtins +*-cygwin32*) opt_gnu_malloc=no ;; # Cygnus's CYGWIN32 environment esac dnl arguments to configure @@ -104,10 +105,16 @@ 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_usg_echo=no +opt_cond_command=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, --enable-minimal-config a minimal sh-like configuration, opt_minimal_config=$enableval) @@ -120,6 +127,7 @@ if test $opt_minimal_config = yes; then 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 fi AC_ARG_ENABLE(alias, --enable-alias enable shell aliases, opt_alias=$enableval) @@ -127,9 +135,11 @@ AC_ARG_ENABLE(array-variables, --enable-array-variables include shell array vari AC_ARG_ENABLE(bang-history, --enable-bang-history turn on csh-style history substitution, opt_bang_history=$enableval) AC_ARG_ENABLE(brace-expansion, --enable-brace-expansion include brace expansion, opt_brace_expansion=$enableval) AC_ARG_ENABLE(command-timing, --enable-command-timing enable the time reserved word and command timing, opt_command_timing=$enableval) +AC_ARG_ENABLE(cond-command, --enable-cond-command enable the conditional command, opt_cond_command=$enableval) AC_ARG_ENABLE(directory-stack, --enable-directory-stack enable builtins pushd/popd/dirs, opt_dirstack=$enableval) AC_ARG_ENABLE(disabled-builtins, --enable-disabled-builtins allow disabled builtins to still be invoked, opt_disabled_builtins=$enableval) AC_ARG_ENABLE(dparen-arithmetic, [--enable-dparen-arithmetic include ((...)) command], opt_dparen_arith=$enableval) +AC_ARG_ENABLE(extended-glob, --enable-extended-glob include ksh-style extended pattern matching, opt_extended_glob=$enableval) AC_ARG_ENABLE(help-builtin, --enable-help-builtin include the help builtin, opt_help=$enableval) AC_ARG_ENABLE(history, --enable-history turn on command history, opt_history=$enableval) AC_ARG_ENABLE(job-control, --enable-job-control enable job control features, opt_job_control=$enableval) @@ -140,6 +150,10 @@ AC_ARG_ENABLE(restricted, --enable-restricted enable a restricted shell, opt_res AC_ARG_ENABLE(select, --enable-select include select command, opt_select=$enableval) AC_ARG_ENABLE(usg-echo-default, --enable-usg-echo-default make the echo builtin expand escape sequences by default, opt_usg_echo=$enableval) +dnl options that alter how bash is compiled and linked +AC_ARG_ENABLE(profiling, --enable-profiling allow profiling with gprof, opt_profiling=$enableval) +AC_ARG_ENABLE(static-link, --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 if test $opt_alias = yes; then @@ -202,6 +216,12 @@ fi if test $opt_usg_echo = yes ; then AC_DEFINE(DEFAULT_ECHO_TO_USG) 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_minimal_config" = yes; then TESTSCRIPT=run-minimal @@ -226,19 +246,74 @@ esyscmd(cat _distribution)dnl [BASHPATCH=]dnl esyscmd(cat _patchlevel)dnl -echo "Beginning configuration for bash-$BASHVERS" +echo "Beginning configuration for bash-$BASHVERS for ${host_cpu}-${host_vendor}-${host_os}" dnl compilation checks +dnl AC_PROG_CC sets $cross_compiling to `yes' if cross-compiling for a +dnl different environment AC_PROG_CC +BASH_LARGE_FILE_SUPPORT AC_ISC_POSIX AC_MINIX +dnl BEGIN changes for CYGNUS cross-building for cygwin32 + +dnl load up the cross-building cache file -- add more cases and cache +dnl files as necessary +if test "x$cross_compiling" = "xyes"; then + case "${host}" in + *-cygwin32*) + cross_cache=${srcdir}/cross-build/cygwin32.cache + if test -r "${cross_cache}"; then + echo "loading cross-build cache file ${cross_cache}" + . ${cross_cache} + fi + unset cross_cache + ;; + *) echo "configure: cross-compiling for a non-cygwin32 target is not supported" >&2 + ;; + esac +fi + +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 Set SIGNAMES_H based on whether or not we're cross-compiling +if test "x$cross_compiling" = "xno"; then + SIGNAMES_H=lsignames.h +else + SIGNAMES_H='$(srcdir)/cross-build/win32sig.h' +fi +AC_SUBST(SIGNAMES_H) + +dnl END changes for CYGNUS cross-building for cygwin32 + 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 + opt_static_link=yes +fi + +if test "$opt_static_link" = yes; then + # if we're using gcc, add `-static' to LDFLAGS + if test -n "$GCC" || test "$ac_cv_prog_gcc" = "yes"; then + LDFLAGS="$LDFLAGS -static" + fi +fi + AC_SUBST(CFLAGS) AC_SUBST(CPPFLAGS) AC_SUBST(LDFLAGS) @@ -287,8 +362,9 @@ AC_CHECK_FUNCS(dup2 select getdtablesize getgroups gethostname \ dnl checks for c library functions AC_CHECK_FUNCS(bcopy bzero confstr getcwd strcasecmp setenv putenv \ - setlinebuf setlocale strchr strerror tcgetattr uname \ - sysconf ulimit times tzset siginterrupt memmove) + setlinebuf setlocale strchr strerror strtod strtol \ + strtoul tcgetattr uname sysconf ulimit times tzset \ + siginterrupt memmove) dnl checks for locale functions AC_CHECK_HEADERS(libintl.h) @@ -304,8 +380,10 @@ if test "$ac_cv_func_bindtextdomain" = "no"; then fi 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 @@ -315,7 +393,8 @@ AC_HEADER_DIRENT AC_HEADER_TIME AC_CHECK_HEADERS(unistd.h stdlib.h stdarg.h varargs.h limits.h string.h \ - memory.h locale.h termcap.h termio.h termios.h dlfcn.h) + memory.h locale.h termcap.h termio.h termios.h dlfcn.h \ + stddef.h) AC_CHECK_HEADERS(sys/ptem.h sys/pte.h sys/stream.h sys/select.h sys/file.h \ sys/resource.h sys/param.h sys/socket.h \ sys/time.h sys/times.h sys/wait.h) @@ -339,6 +418,24 @@ AC_CHECK_TYPE(time_t, long) AC_TYPE_SIGNAL +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(char *) + +AC_CHECK_TYPE(int32_t) +if test "$ac_cv_type_int32_t" = "no"; then + BASH_TYPE_INT32_T +fi +AC_CHECK_TYPE(u_int32_t) +if test "$ac_cv_type_u_int32_t" = "no"; then + BASH_TYPE_U_INT32_T +fi + +AC_CHECK_TYPE(ptrdiff_t) +if test "$ac_cv_type_ptrdiff_t" = "no"; then + BASH_TYPE_PTRDIFF_T +fi + dnl structures AC_HEADER_STAT AC_HEADER_EGREP(struct timeval, sys/time.h, bash_cv_struct_timeval=yes, ) @@ -370,6 +467,10 @@ BASH_DUP2_CLOEXEC_CHECK BASH_PGRP_SYNC BASH_SIGNAL_CHECK +if test "$ac_cv_sys_restartable_syscalls" = "no"; then +BASH_SYS_RESTARTABLE_SYSCALLS +fi + dnl checking for the presence of certain library symbols BASH_SYS_ERRLIST BASH_SYS_SIGLIST @@ -471,6 +572,7 @@ linux*) LOCAL_LDFLAGS=-rdynamic ;; # allow dynamic loading aix4.2*) LOCAL_LDFLAGS="-bexpall -brtl" ;;# allow dynamic loading *qnx*) LOCAL_CFLAGS="-Dqnx -F -3s" LOCAL_LDFLAGS="-3s -lunix -lncurses" ;; powerux) LOCAL_LIBS="-lgen" ;; +cygwin32*) LOCAL_LIBS="-luser32" ;; esac case "$host_cpu" in @@ -490,17 +592,20 @@ esac # this should be packaged into a script accessible via ${srcdir}/support case "$srcdir" in .) ;; -*) for d in doc tests support lib ; do # dirs +*) for d in doc tests support lib examples; do # dirs test -d $d || mkdir $d done - for ld in readline glob tilde malloc termcap; do # libdirs + 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 ;; esac BUILD_DIR=`pwd` +AC_SUBST(PROFILE_FLAGS) + AC_SUBST(incdir) AC_SUBST(BUILD_DIR) @@ -522,8 +627,9 @@ AC_SUBST(LOCAL_DEFS) #AC_SUBST(ALLOCA_OBJECT) AC_OUTPUT([Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \ - lib/malloc/Makefile lib/termcap/Makefile lib/tilde/Makefile \ - doc/Makefile], + lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile \ + lib/tilde/Makefile doc/Makefile support/Makefile \ + examples/loadables/Makefile], [ # Makefile uses this timestamp file to record whether config.h is up to date. echo timestamp > stamp-h @@ -22,23 +22,25 @@ #include "config.h" -#include <stdio.h> +#include "bashtypes.h" #if defined (HAVE_UNISTD_H) # include <unistd.h> #endif +#include <stdio.h> + #include "shell.h" WORD_DESC * -copy_word (word) - WORD_DESC *word; +copy_word (w) + WORD_DESC *w; { WORD_DESC *new_word; new_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC)); - FASTCOPY ((char *)word, (char *)new_word, sizeof (WORD_DESC)); - new_word->word = savestring (word->word); + FASTCOPY ((char *)w, (char *)new_word, sizeof (WORD_DESC)); + new_word->word = savestring (w->word); return (new_word); } @@ -201,12 +203,47 @@ copy_if_command (com) 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->op = copy_word (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 = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_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 = copy_redirects (com->redirects); @@ -276,6 +313,18 @@ copy_command (command) 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; diff --git a/cross-build/cygwin32.cache b/cross-build/cygwin32.cache new file mode 100644 index 00000000..346a310d --- /dev/null +++ b/cross-build/cygwin32.cache @@ -0,0 +1,39 @@ +# 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'} + +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'} + +# end of cross-build/cygwin32.cache diff --git a/cross-build/win32sig.h b/cross-build/win32sig.h new file mode 100644 index 00000000..13ffc754 --- /dev/null +++ b/cross-build/win32sig.h @@ -0,0 +1,254 @@ +/* This file is used when cross-compiling for the CYGWIN32 environment on + a Unix machine. */ +#include <sys/types.h> +#include <signal.h> + +#ifndef __GNUC__ +# error cross compiling requires gcc +#endif + +/* A translation list so we can be polite to our users. Use gcc + labelled initializers to set up the array. Note that some entries + might wind up being NULL. */ + +char *signal_names[NSIG + 2] = { + [0] "EXIT", + +#ifdef SIGLOST + [SIGLOST] "SIGLOST", +#endif + +#ifdef SIGMSG + [SIGMSG] "SIGMSG", +#endif + +#ifdef SIGDANGER + [SIGDANGER] "SIGDANGER", +#endif + +#ifdef SIGMIGRATE + [SIGMIGRATE] "SIGMIGRATE", +#endif + +#ifdef SIGPRE + [SIGPRE] "SIGPRE", +#endif + +#ifdef SIGVIRT + [SIGVIRT] "SIGVIRT", +#endif + +#ifdef SIGALRM1 + [SIGALRM1] "SIGALRM1", +#endif + +#ifdef SIGWAITING + [SIGWAITING] "SIGWAITING", +#endif + +#ifdef SIGGRANT + [SIGGRANT] "SIGGRANT", +#endif + +#ifdef SIGKAP + [SIGKAP] "SIGKAP", +#endif + +#ifdef SIGRETRACT + [SIGRETRACT] "SIGRETRACT", +#endif + +#ifdef SIGSOUND + [SIGSOUND] "SIGSOUND", +#endif + +#ifdef SIGSAK + [SIGSAK] "SIGSAK", +#endif + +#ifdef SIGLWP + [SIGLWP] "SIGLWP", +#endif + +#ifdef SIGFREEZE + [SIGFREEZE] "SIGFREEZE", +#endif + +#ifdef SIGTHAW + [SIGTHAW] "SIGTHAW", +#endif + +#ifdef SIGCANCEL + [SIGCANCEL] "SIGCANCEL", +#endif + +#ifdef SIGDIL + [SIGDIL] "SIGDIL", +#endif + +#ifdef SIGCLD +#ifndef SIGCHLD + [SIGCLD] "SIGCLD", +#else +#if SIGCHLD != SIGCLD + [SIGCLD] "SIGCLD", +#endif +#endif +#endif + +#ifdef SIGPWR + [SIGPWR] "SIGPWR", +#endif + +#ifdef SIGPOLL +#ifndef SIGIO + [SIGPOLL] "SIGPOLL", +#else +#if SIGIO != SIGPOLL + [SIGPOLL] "SIGPOLL", +#endif +#endif +#endif + +#ifdef SIGWINDOW + [SIGWINDOW] "SIGWINDOW", +#endif + +#ifdef SIGHUP + [SIGHUP] "SIGHUP", +#endif + +#ifdef SIGINT + [SIGINT] "SIGINT", +#endif + +#ifdef SIGQUIT + [SIGQUIT] "SIGQUIT", +#endif + +#ifdef SIGILL + [SIGILL] "SIGILL", +#endif + +#ifdef SIGTRAP + [SIGTRAP] "SIGTRAP", +#endif + +#ifdef SIGIOT +#ifndef SIGABRT + [SIGIOT] "SIGIOT", +#else +#if SIGABRT != SIGIOT + [SIGIOT] "SIGIOT", +#endif +#endif +#endif + +#ifdef SIGABRT + [SIGABRT] "SIGABRT", +#endif + +#ifdef SIGEMT + [SIGEMT] "SIGEMT", +#endif + +#ifdef SIGFPE + [SIGFPE] "SIGFPE", +#endif + +#ifdef SIGKILL + [SIGKILL] "SIGKILL", +#endif + +#ifdef SIGBUS + [SIGBUS] "SIGBUS", +#endif + +#ifdef SIGSEGV + [SIGSEGV] "SIGSEGV", +#endif + +#ifdef SIGSYS + [SIGSYS] "SIGSYS", +#endif + +#ifdef SIGPIPE + [SIGPIPE] "SIGPIPE", +#endif + +#ifdef SIGALRM + [SIGALRM] "SIGALRM", +#endif + +#ifdef SIGTERM + [SIGTERM] "SIGTERM", +#endif + +#ifdef SIGURG + [SIGURG] "SIGURG", +#endif + +#ifdef SIGSTOP + [SIGSTOP] "SIGSTOP", +#endif + +#ifdef SIGTSTP + [SIGTSTP] "SIGTSTP", +#endif + +#ifdef SIGCONT + [SIGCONT] "SIGCONT", +#endif + +#ifdef SIGCHLD + [SIGCHLD] "SIGCHLD", +#endif + +#ifdef SIGTTIN + [SIGTTIN] "SIGTTIN", +#endif + +#ifdef SIGTTOU + [SIGTTOU] "SIGTTOU", +#endif + +#ifdef SIGIO + [SIGIO] "SIGIO", +#endif + +#ifdef SIGXCPU + [SIGXCPU] "SIGXCPU", +#endif + +#ifdef SIGXFSZ + [SIGXFSZ] "SIGXFSZ", +#endif + +#ifdef SIGVTALRM + [SIGVTALRM] "SIGVTALRM", +#endif + +#ifdef SIGPROF + [SIGPROF] "SIGPROF", +#endif + +#ifdef SIGWINCH + [SIGWINCH] "SIGWINCH", +#endif + +#ifdef SIGINFO + [SIGINFO] "SIGINFO", +#endif + +#ifdef SIGUSR1 + [SIGUSR1] "SIGUSR1", +#endif + +#ifdef SIGUSR2 + [SIGUSR2] "SIGUSR2", +#endif + + [NSIG] "DEBUG", + + [NSIG + 1] (char *)0x0 +}; diff --git a/dispose_cmd.c b/dispose_cmd.c index d0b6bbdb..4bf2c042 100644 --- a/dispose_cmd.c +++ b/dispose_cmd.c @@ -20,6 +20,8 @@ #include "config.h" +#include "bashtypes.h" + #if defined (HAVE_UNISTD_H) # include <unistd.h> #endif @@ -132,6 +134,29 @@ dispose_command (command) 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; @@ -150,13 +175,32 @@ dispose_command (command) 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 */ + /* How to free a WORD_DESC. */ void -dispose_word (word) - WORD_DESC *word; +dispose_word (w) + WORD_DESC *w; { - FREE (word->word); - free (word); + FREE (w->word); + free (w); } /* How to get rid of a linked list of words. A WORD_LIST. */ diff --git a/dispose_cmd.h b/dispose_cmd.h index 11166dd7..8fc2f78b 100644 --- a/dispose_cmd.h +++ b/dispose_cmd.h @@ -29,4 +29,8 @@ extern void dispose_words __P((WORD_LIST *)); extern void dispose_word_array __P((char **)); extern void dispose_redirects __P((REDIRECT *)); +#if defined (COND_COMMAND) +extern void dispose_cond_node __P((COND_COM *)); +#endif + #endif /* !_DISPOSE_CMD_H_ */ @@ -1,4 +1,4 @@ -This is the Bash FAQ, version 2.5, for Bash version 2.01. +This is the Bash FAQ, version 2.11, for Bash version 2.02. This document contains a set of frequently-asked questions concerning Bash, the GNU Bourne-Again Shell. Bash is a freely-available command @@ -13,7 +13,7 @@ chet@po.cwru.edu. This document is available for anonymous FTP with the URL -ftp://slc2.ins.cwru.edu/pub/bash/FAQ +ftp://ftp.cwru.edu/pub/bash/FAQ ---------- Contents: @@ -34,8 +34,8 @@ Section A: The Basics Section B: The latest version -11) What's new in version 2.01? -12) Are there any user-visible incompatibilities between bash-2.01 and +11) What's new in version 2.02? +12) Are there any user-visible incompatibilities between bash-2.02 and bash-1.14.7? Section C: Differences from other Unix shells @@ -120,23 +120,22 @@ of Case Western Reserve University. 2) What's the latest version? -The latest version is 2.01, first made available on June 6, 1997. +The latest version is 2.02, first made available on Monday, 20 April, 1998. 3) Where can I get it? Bash is the GNU project's shell, and so is available from the master GNU archive site, prep.ai.mit.edu, and its mirrors. The -latest version is also available for FTP from slc2.ins.cwru.edu, -the maintainer's machine. The following URLs tell how to get -version 2.01: +latest version is also available for FTP from ftp.cwru.edu. +The following URLs tell how to get version 2.02: -ftp://prep.ai.mit.edu/pub/gnu/bash-2.01.tar.gz -ftp://slc2.ins.cwru.edu/pub/dist/bash-2.01.tar.gz +ftp://prep.ai.mit.edu/pub/gnu/bash-2.02.tar.gz +ftp://ftp.cwru.edu/pub/bash/bash-2.02.tar.gz Formatted versions of the documentation are available with the URLs: -ftp://prep.ai.mit.edu/pub/gnu/bash-doc-2.01.tar.gz -ftp://slc2.ins.cwru.edu/pub/dist/bash-doc-2.01.tar.gz +ftp://prep.ai.mit.edu/pub/gnu/bash-doc-2.02.tar.gz +ftp://ftp.cwru.edu/pub/bash/bash-doc-2.02.tar.gz 4) On what machines will bash run? @@ -162,8 +161,22 @@ project. For more information about the project, look at the URL http://www.cygnus.com/misc/gnu-win32 -Cygnus has ported bash-1.14.7. Maybe someday they (or I) will port -bash-2.01 (or later) to the GNU-Win32 environment. +Cygnus has ported bash-1.14.7, and their port is part of the current +gnu-win32 release. Cygnus has also done a port of bash-2.01 to the +GNU-Win32 environment, and it should be available as part of their next +release. + +Bash-2.02 should require no local Cygnus changes to build and run under +GNU-WIN32. + +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 + +Softway Systems has ported bash-2.01.1 to their OpenNT system, a +Unix subsystem for NT that replaces the Microsoft POSIX subsystem. +Check out http://www.opennt.com for more information. D. J. Delorie has ported bash-1.14.7 to run under MS-DOS, as part of the DJGPP project. For more information on the project, see @@ -179,11 +192,13 @@ The corresponding source is ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bsh1147s.zip -A port of bash-1.12 is available for OS/2 from +Ports of bash-1.12 and bash-2.0 are available for OS/2 from -ftp://hobbes.nmsu.edu/os2/unix/bash_112.zip +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 it. +I haven't looked at either, but the second appears to be a binary-only +distribution. Beware. 6) How can I build bash with gcc? @@ -193,11 +208,11 @@ file INSTALL in the distribution for more information. 7) How can I make bash my login shell? Some machines let you use `chsh' to change your login shell. Other -systems use `passwd -s'. If one of these works for you, that's all -you need. Note that many systems require the full pathname to a shell -to appear in /etc/shells before you can make it your login shell. For -this, you may need the assistance of your friendly local system -administrator. +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 @@ -298,15 +313,37 @@ Reference Manual. Section B: The latest version -11) What's new in version 2.01? +11) What's new in version 2.02? + +Bash-2.02 has a number of new features. Here's a short list: -Bash-2.01 contains only a few 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 $(<filename) command substitution, which is equivalent to + $(cat filename) +new tilde prefixes that expand to directories from the directory stack +new `**' arithmetic operator to do exponentiation +case-insensitive globbing (filename expansion) +menu completion a la tcsh +`magic-space' history expansion function like tcsh +the readline inputrc `language' has a new file inclusion directive ($include) + +Bash-2.01 contained only a few new features: new `GROUPS' builtin array variable containing the user's group list new bindable readline commands: history-and-alias-expand-line and alias-expand-line -Bash-2.0 contains extensive changes and new features from bash-1.14.7. +Bash-2.0 contained extensive changes and new features from bash-1.14.7. Here's a short list: new `time' reserved word to time pipelines, shell builtins, and @@ -344,11 +381,11 @@ grammar tighter and smaller (66 reduce-reduce conflicts gone) lots of code now smaller and faster test suite greatly expanded -12) Are there any user-visible incompatibilities between bash-2.01 and +12) Are there any user-visible incompatibilities between bash-2.02 and bash-1.14.7? -There are a few incompatibilities between version 1.14.7 and version 2.01. -They are detailed in the file COMPAT in the bash-2.01 distribution. +There are a few incompatibilities between version 1.14.7 and version 2.02. +They are detailed in the file COMPAT in the bash-2.02 distribution. Section C: Differences from other Unix shells @@ -494,7 +531,7 @@ Implementation differences: 15) Which new features in ksh-93 are not in bash, and which are? -New things in ksh-93 not in bash-2.01: +New things in ksh-93 not in bash-2.02: associative arrays floating point arithmetic ++, --, comma arithmetic operators @@ -510,12 +547,12 @@ New things in ksh-93 not in bash-2.01: variables: .sh.edchar, .sh.edmode, .sh.edcol, .sh.edtext, HISTEDIT, .sh.version, .sh.name, .sh.subscript, .sh.value backreferences in pattern matching - print -f and printf (bash has loadable versions) + print -f (bash has a loadable version) `fc' has been renamed to `hist' read -t/-d `.' can execute shell functions -New things in ksh-93 present in bash-2.01: +New things in ksh-93 present in bash-2.02: ?: arithmetic operator expansions: ${!param}, ${param:offset[:len]}, ${param/pat[/str]} compound array assignment @@ -808,7 +845,7 @@ and the \] escape to signal the end of such a sequence. 27) How can I find the value of a shell variable whose name is the value of another shell variable? -Bash-2.01 supports this directly. You can use +Bash-2.02 supports this directly. You can use ${!var} @@ -830,7 +867,7 @@ parameter: 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 bash-2.01, +before `eval' is executed. In bash-2.02, echo ${!#} @@ -1055,7 +1092,7 @@ is, in fact, a syntax error. Redirections may only precede `simple commands'. A subshell construct such as the above is one of the shell's `compound commands'. A redirection may only follow a compound command. -The file CWRU/sh-redir-hack in the bash-2.01 distribution is an +The file CWRU/sh-redir-hack in the bash-2.02 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 @@ -1100,34 +1137,30 @@ Postscript files created from the above source are available in the documentation distribution. There is additional documentation available for anonymous FTP from host -slc2.ins.cwru.edu in the `pub/bash' directory. +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. There are rumors of a second edition of this book, describing -bash-2.0 (and 2.01). I do not know what ORA's publication schedule for -this edition is. +in bash-2.0. + +A second edition of this book is available, just published in January, 1998. +The ISBN number is 1-56592-347-2. Look for it in the same fine bookstores +or on the web. 39) What's coming in future versions? These are features I plan to include in a future version of bash. -POSIX.2-style globbing character classes ([:alpha:], [:alnum:], etc.) -POSIX.2-style globbing equivalence classes -POSIX.2-style globbing collating symbols -a bash debugger (a minimally-tested version is included with bash-2.01) +a bash debugger (a minimally-tested version is included with bash-2.02) +Programmable completion a la zsh 40) 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. -Programmable completion a la zsh -menu completion a la tcsh -the ksh [[...]] extended test command -the ksh egrep-style extended pattern matching operators associative arrays (not really all that hard) breaking some of the shell functionality into embeddable libraries better internationalization using GNU `gettext' @@ -1135,13 +1168,15 @@ an option to use external files for the long `help' text timeouts for the `read' builtin the ksh-93 ${!prefix*} and ${!prefix@} operators arithmetic ++ and -- prefix and postfix operators +date-stamped command history 41) When will the next release appear? -The next version will appear sometime in 1997. Never make predictions. +The next version will appear sometime in 1998. Never make +predictions. -This document is Copyright 1995, 1996 by Chester Ramey. +This document is Copyright 1995, 1996, 1998 by Chester Ramey. Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, and distribute diff --git a/doc/Makefile.in b/doc/Makefile.in index 98f76b03..62e041d2 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -30,6 +30,8 @@ TEX = tex MAKEINFO = makeinfo TEXI2DVI = ${topdir}/support/texi2dvi TEXI2HTML = ${topdir}/support/texi2html +MAN2HTML = ${BUILD_DIR}/support/man2html +HTMLPOST = ${srcdir}/htmlpost.sh QUIETPS = #set this to -q to shut up dvips DVIPS = dvips -D 300 $(QUIETPS) -o $@ # tricky TEXINPUTDIR = $(RL_LIBDIR)/doc @@ -45,7 +47,7 @@ GROFF = groff HSUSER = $(RL_LIBDIR)/doc/hsuser.texinfo RLUSER = $(RL_LIBDIR)/doc/rluser.texinfo -.SUFFIXES: .0 .1 .3 .ms .ps .txt .dvi +.SUFFIXES: .0 .1 .3 .ms .ps .txt .dvi .html .1.ps: $(RM) $@ @@ -55,6 +57,10 @@ RLUSER = $(RL_LIBDIR)/doc/rluser.texinfo $(RM) $@ -${NROFF} -man $< > $@ +.1.html: + $(RM) $@ + -${MAN2HTML} $< | ${HTMLPOST} > $@ + .ms.ps: $(RM) $@ -${GROFF} -ms $< > $@ @@ -71,6 +77,10 @@ RLUSER = $(RL_LIBDIR)/doc/rluser.texinfo $(RM) $@ -${NROFF} -man $< > $@ +.3.html: + $(RM) $@ + -${MAN2HTML} $< > $@ + all: ps info dvi text html nodvi: ps info text html @@ -78,7 +88,7 @@ ps: bash.ps bashbug.ps readline.ps article.ps builtins.ps dvi: bashref.dvi bashref.ps info: bashref.info text: bash.0 bashbug.0 builtins.0 readline.0 -html: bashref.html +html: bashref.html bash.html bashref.dvi: $(srcdir)/bashref.texi $(HSUSER) $(RLUSER) TEXINPUTS=.:$(TEXINPUTDIR):$$TEXINPUTS $(TEXI2DVI) $(srcdir)/bashref.texi @@ -102,6 +112,7 @@ bashman.ps: bash.dvi bash.txt: bash.1 bash.ps: bash.1 +bash.html: bash.1 $(MAN2HTML) bashbug.ps: bashbug.1 builtins.ps: builtins.1 bash.1 bash.0: bash.1 @@ -111,6 +122,9 @@ readline.0: readline.3 readline.ps: readline.3 article.ps: article.ms +$(MAN2HTML): ${topdir}/support/man2html.c + -( cd ${BUILD_DIR}/support ; ${MAKE} ${MFLAGS} man2html) + faq: faq.news faq.news2 faq.mail faq.version faq.version: FAQ.version FAQ @@ -6,11 +6,11 @@ .\" Case Western Reserve University .\" chet@ins.CWRU.Edu .\" -.\" Last Change: Mon May 19 12:45:24 EDT 1997 +.\" Last Change: Wed Apr 1 12:16:09 EST 1998 .\" .\" bash_builtins, strip all but Built-Ins section .if \n(zZ=1 .ig zZ -.TH BASH 1 "1997 May 19" GNU +.TH BASH 1 "1998 Apr 1" GNU .\" .\" There's some problem with having a `@' .\" in a tagged paragraph with the BSD man macros. @@ -61,19 +61,19 @@ also incorporates useful features from the \fIKorn\fP and \fIC\fP shells (\fBksh\fP and \fBcsh\fP). .PP .B Bash -is ultimately intended to be a conformant implementation of the IEEE +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 flags when it is invoked: +interprets the following options when it is invoked: .PP .PD 0 .TP 10 .BI \-c "\| string\^" If the .B \-c -flag is present, then commands are read from +option is present, then commands are read from .IR string . If there are arguments after the .IR string , @@ -83,7 +83,7 @@ they are assigned to the positional parameters, starting with .B \-r If the .B \-r -flag is present, the shell becomes +option is present, the shell becomes .I restricted (see .SM @@ -93,13 +93,13 @@ below). .B \-i If the .B \-i -flag is present, the shell is +option is present, the shell is .IR interactive . .TP .B \-s If the .B \-s -flag is present, or if no arguments remain after option +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. @@ -130,6 +130,10 @@ single-character options in order for them to be recognized. .PP .PD 0 .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 @@ -309,8 +313,8 @@ it tries to mimic the startup behavior of historical versions of .B sh as closely as possible, while conforming to the POSIX standard as well. -When invoked as a login shell, it first attempts to read and execute -commands from +When invoked as an interactive login shell, it first attempts to +read and execute commands from .I /etc/profile and .IR ~/.profile , @@ -349,13 +353,12 @@ is started in mode, as with the .B \-\-posix command line option, it follows the POSIX standard for startup files. -In this mode, the +In this mode, interactive shells expand the .SM .B ENV -variable is expanded and commands are read and executed from the file +variable and commands are read and executed from the file whose name is the expanded value. No other startup files are read. -This is done by interactive shells only. .PP .B Bash attempts to determine when it is being run by the remote shell @@ -427,8 +430,8 @@ 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 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" @@ -582,6 +585,67 @@ 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. +.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 +.RE +.LP +The \fB&&\fP and +.if t \fB\(bv\(bv\fP +.if n \fB||\fP +operators do not execute \fIexpression2\fP if the value of +\fIexpression1\fP is sufficient to determine the return value of +the entire conditional expression. +.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 @@ -591,6 +655,9 @@ 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 \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 @@ -694,7 +761,6 @@ below), a word beginning with causes that word and all remaining characters on that line to be ignored. An interactive shell without the .B interactive_comments -.B shopt option enabled does not allow comments. The .B interactive_comments option is on by default in interactive shells. @@ -717,8 +783,9 @@ A non-quoted backslash (\fB\e\fP) is the .IR "escape character" . It preserves the literal value of the next character that follows, with the exception of <newline>. If a \fB\e\fP<newline> pair -appears, and the backslash is not quoted, the \fB\e\fP<newline> -is treated as a line continuation (that is, it is effectively ignored). +appears, and the backslash is not itself quoted, the \fB\e\fP<newline> +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 @@ -791,7 +858,12 @@ vertical tab backslash .TP .B \e\fInnn\fP -the character whose ASCII code is \fInnn\fP (octal) +the character whose ASCII code is the octal value \fInnn\fP +(one to three digits) +.TP +.B \ex\fInnn\fP +the character whose ASCII code is the hexadecimal value \fInnn\fP +(one to three digits) .PD .RE .LP @@ -844,7 +916,7 @@ removal (see .SM .B EXPANSION below). If the variable has its -.B \-i +.B integer attribute set (see .B declare below in @@ -852,8 +924,8 @@ below in .BR "SHELL BUILTIN COMMANDS" ) then .I value -is subject to arithmetic expansion even if the $((...)) syntax does -not appear (see +is subject to arithmetic expansion even if the $((...)) expansion is +not used (see .B "Arithmetic Expansion" below). Word splitting is not performed, with the exception @@ -894,8 +966,8 @@ 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 +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 @@ -911,12 +983,10 @@ 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 as a -separate word. That is, `` -.BR $@ '' -is equivalent to -``\fB$1\fP'' ``\fB$2\fP'' ... -When there are no positional parameters, ``\fB$@\fP'' and +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 @@ -934,7 +1004,7 @@ by the builtin command, or those set by the shell itself (such as the .B \-i -flag). +option). .TP .B $ Expands to the process ID of the shell. In a () subshell, it @@ -980,7 +1050,7 @@ The following variables are set by the shell: .PD 0 .TP .B PPID -The process ID of the shell's parent. +The process ID of the shell's parent. This variable is readonly. .TP .B PWD The current working directory as set by the @@ -999,14 +1069,15 @@ builtin command when no arguments are supplied. .TP .B UID Expands to the user ID of the current user, initialized at shell startup. +This variable is readonly. .TP .B EUID Expands to the effective user ID of the current user, initialized at -shell startup. +shell startup. This variable is readonly. .TP .B GROUPS An array variable containing the list of groups of which the current -user is a member. +user is a member. This variable is readonly. .TP .B BASH Expands to the full file name used to invoke this instance of @@ -1017,8 +1088,8 @@ Expands to a string describing the version of this instance of .BR bash . .TP .B BASH_VERSINFO -An array variable whose members hold version information for this -instance of +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 @@ -1219,22 +1290,23 @@ A common value is ``/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:.''. .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 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 +command. +This is a colon-separated list of directories in which the shell looks +for destination directories specified by the .B cd -command. A sample value is -``.:~:/usr''. +command. +A sample value is ``.:~:/usr''. .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 . +.IR ~/.bashrc . The value of .SM .B BASH_ENV @@ -1262,8 +1334,10 @@ If this variable is unset, 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 may be specified by separating the file name from -the message with a `?'. $_ stands for the name of the current mailfile. +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 @@ -1397,7 +1471,14 @@ This variable overrides the value of \fBLANG\fP and any other .TP .B LC_COLLATE This variable determines the collation order used when sorting the -results of pathname expansion. +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 @@ -1487,6 +1568,9 @@ of .BR HISTIGNORE . This variable's function is superseded by .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 HISTIGNORE A colon-separated list of patterns used to decide which command lines @@ -1499,6 +1583,9 @@ 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 histchars The two or three characters which control history expansion @@ -1507,7 +1594,7 @@ and tokenization (see .B HISTORY EXPANSION below). The first character is the .IR "history expansion character" , -that is, the character which signals the start of a history +the character which signals the start of a history expansion, normally `\fB!\fP'. The second character is the .IR "quick substitution" @@ -1515,7 +1602,7 @@ character, which is used as shorthand for re-running the previous command entered, substituting one string for another in the command. The default is `\fB^\fP'. The optional third character is the character -which signifies that the remainder of the line is a comment when found +which 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 @@ -1623,7 +1710,7 @@ referencing element zero. .PP The .B unset -builtin is used to destroy arrays. \fBunset\fP \fIname\fP[\fIsubscript\fP] +builtin is used to destroy arrays. \fBunset\fP \fBname\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 @@ -1672,7 +1759,7 @@ 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'' +"\fB$@\fP" and "\fB${\fP\fIname\fP\fB[@]}\fP" as explained above (see .SM .BR PARAMETERS ). @@ -1687,9 +1774,9 @@ the form of an optional .IR preamble , followed by a series of comma-separated strings between a pair of braces, followed by an optional -.IR postamble . +.IR postscript . The preamble is prefixed to each string contained -within the braces, and the postamble is then appended +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 @@ -1753,39 +1840,51 @@ command (see below). .SS Tilde Expansion .PP -If a word begins with a tilde character (`\fB~\fP'), all of the characters -preceding the first slash (or all characters, if there is no slash) -are treated as a possible \fIlogin name\fP. If this \fIlogin name\fP -is the null string, the tilde is replaced with the value of the -parameter +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. +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 a `+' follows the tilde, the value of +If the tilde-prefix is a `~+', the value of the shell variable .SM .B PWD -replaces the tilde and `+'. If -a `\-' follows, the value of -.SM -.B OLDPWD -is substituted. -If the value following the tilde is a valid \fIlogin name\fP, -the tilde and \fIlogin name\fP are replaced with the home directory -associated with that name. If the name is invalid, or the tilde -expansion fails, the word is unchanged. +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 -tildes immediately following a +Each variable assignment is checked for unquoted tilde-prefixes immediately +following a .B : or .BR = . -In these cases, tilde substitution is also performed. Consequently, one -may use file names with tildes in assignments to +In these cases, tilde expansion is also performed. +Consequently, one may use file names with tildes in assignments to .SM .BR PATH , .SM @@ -1803,6 +1902,11 @@ 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} @@ -1880,7 +1984,7 @@ ${\fIparameter\fP\fB:\fP\fIoffset\fP\fB:\fP\fIlength\fP} .PD \fBSubstring Expansion.\fP Expands to up to \fIlength\fP characters of \fIparameter\fP, -starting at \fIoffset\fP. +starting at the characters 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 @@ -1896,8 +2000,8 @@ 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. +Substring indexing is zero-based unless the positional parameters +are used, in which case the indexing starts at 1. .TP ${\fB#\fP\fIparameter\fP} The length in characters of the value of \fIparameter\fP is substituted. @@ -1907,14 +2011,14 @@ is .B * or .BR @ , -the length substituted is the number of positional parameters. +the value substituted is the number of positional parameters. If .I parameter is an array name subscripted by .B * or .BR @ , -the length substituted is the number of elements in the array. +the value substituted is the number of elements in the array. .TP .PD 0 ${\fIparameter\fP\fB#\fP\fIword\fP} @@ -1927,7 +2031,7 @@ is expanded to produce a pattern just as in pathname expansion. If the pattern matches the beginning of the value of .IR parameter , -then the expansion is the value of +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. @@ -1955,9 +2059,9 @@ ${\fIparameter\fP\fB%%\fP\fIword\fP} .PD The \fIword\fP is expanded to produce a pattern just as in pathname expansion. -If the pattern matches a trailing portion of the value of +If the pattern matches a trailing portion of the expanded value of .IR parameter , -then the expansion is the value of +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. @@ -2014,7 +2118,7 @@ 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 +\fICommand substitution\fP allows the output of a command to replace the command name. There are two forms: .PP .RS @@ -2030,6 +2134,10 @@ or 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 @@ -2037,10 +2145,12 @@ backslash retains its literal meaning except when followed by .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 old form, +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 @@ -2086,7 +2196,7 @@ the file will provide input for \fIlist\fP. If the \fB<(\fP\fIlist\^\fP\fB)\fP form is used, the file passed as an argument should be read to obtain the output of \fIlist\fP. .PP -On systems that support it, \fIprocess substitution\fP is performed +When available, \fIprocess substitution\fP is performed simultaneously with parameter and variable expansion, command substitution, and arithmetic expansion. @@ -2169,6 +2279,7 @@ option has been set, scans each word for the characters .BR * , .BR ? , +.BR ( , and .BR [ . If one of these characters appears, then the word is @@ -2180,8 +2291,14 @@ If no matching file names are found, and the shell option .B nullglob is disabled, the word is left unchanged. -If the option is set, and no matches are found, +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 ``.'' @@ -2189,7 +2306,8 @@ at the start of a name or immediately following a slash must be matched explicitly, unless the shell option .B dotglob is set. -The slash character must always be matched explicitly. +When matching a pathname, the slash character must always be +matched explicitly. In other cases, the .B ``.'' character is not treated specially. @@ -2199,7 +2317,8 @@ below under .SM .B SHELL BUILTIN COMMANDS for a description of the -.B nullglob +.BR nocaseglob , +.BR nullglob , and .B dotglob shell options. @@ -2245,6 +2364,13 @@ option is disabled when .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. 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 @@ -2275,13 +2401,78 @@ 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 xdigit +.if t alnum alpha ascii blank cntrl digit graph lower print punct space upper xdigit +.br +A character class matches any character belonging to that class. +.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 ` , +.BR ' , and \^\f3"\fP\^ that did not result from one of the above expansions are removed. .SH REDIRECTION @@ -2307,11 +2498,11 @@ the redirection refers to the standard input (file descriptor the redirection refers to the standard output (file descriptor 1). .PP -The word that follows the redirection operator in the following -descriptions is subjected to brace expansion, tilde expansion, -parameter expansion, command substitution, arithmetic expansion, -quote removal, and pathname expansion. If it expands to more -than one word, +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, and pathname expansion. +If it expands to more than one word, .B bash reports an error. .PP @@ -2335,6 +2526,8 @@ directs only the standard output to file because the standard error was duplicated as standard output before the standard output was redirected to .IR dirlist . +.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 @@ -2372,18 +2565,21 @@ The general format for redirecting output is: If the redirection operator is .BR > , and the -.B \-C +.B noclobber option to the .B set builtin has been enabled, the redirection will fail if the filename -whose name results from the expansion of \fIword\fP exists. +whose name results from the expansion of \fIword\fP exists and is +a regular file. If the redirection operator is .BR >| , -then the value of the -.B \-C +or the redirection operator is +.B > +and the +.B noclobber option to the .B set -builtin command is not tested, and the redirection is attempted even +builtin command is not enabled, the redirection is attempted even if the file named by \fIword\fP exists. .SS Appending Redirected Output .PP @@ -2460,7 +2656,8 @@ are quoted, the .I delimiter is the result of quote removal on .IR word , -and the lines in the here-document are not expanded. Otherwise, +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 pair @@ -2494,7 +2691,11 @@ 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 +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 \- , @@ -2513,6 +2714,9 @@ The operator 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. @@ -2532,6 +2736,8 @@ or on file descriptor 0 if .I n is not specified. If the file does not exist, it is created. .SH ALIASES +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 .I aliases that may be set and unset with the @@ -2596,7 +2802,7 @@ command does not take effect until the next line of input is read. The commands following the alias definition on that line are not affected by the new alias. This behavior is also an issue when functions are executed. -Aliases are expanded when the function definition is read, +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 @@ -2605,7 +2811,7 @@ alias definitions on a separate line, and do not use .B alias in compound commands. .PP -Note that for almost every purpose, aliases are superseded by +For almost every purpose, aliases are superseded by shell functions. .SH FUNCTIONS A shell function, defined as described above under @@ -2644,7 +2850,7 @@ execution resumes with the next command after the function call. When a function completes, the values of the positional parameters and the special parameter .B # -are restored to the values they had prior to function +are restored to the values they had prior to the function's execution. .PP Function names and definitions may be listed with the @@ -2669,6 +2875,258 @@ builtin. .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 builtin command and +\fBArithmetic Expansion\fP). +Evaluation is done in long integers with no check for overflow, +though division by 0 is trapped and flagged as an error. +The following list of operators is grouped into levels of +equal-precedence operators. +The levels are listed in order of decreasing precedence. +.PP +.PD 0 +.TP +.B \- + +unary minus and plus +.TP +.B ! ~ +logical and bitwise negation +.TP +.B ** +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 evaluation +.TP +.B = *= /= %= += \-= <<= >>= &= ^= |= +assignment +.PD +.PP +Shell variables are allowed as operands; parameter expansion is +performed before the expression is evaluated. +The value of a parameter is coerced to a long integer within +an expression. A shell variable need not have its integer attribute +turned on to be used in an expression. +.PP +Constants with a leading 0 are interpreted as octal numbers. +A leading 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 +/dev/fd/\fIn\fP, then file descriptor \fIn\fP 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 \-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. +.TP +\fIfile1\fP \-\fBot\fP \fIfile2\fP +True if \fIfile1\fP is older than \fIfile2\fP. +.TP +\fIfile1\fP \fB\-ef\fP \fIfile2\fP +True if \fIfile1\fP and \fIfile2\fP have the same device and +inode numbers. +.TP +.B \-o \fIoptname\fP +True if shell option +.I optname +is enabled. +See the list of options under the description of the +.B \-o +option to the +.B set +builtin 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. +.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 @@ -2703,10 +3161,11 @@ A full search of the directories in .B PATH is performed only if the command is not found in the hash table. If the search is unsuccessful, the shell prints an error -message and returns a non-zero exit status. +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. +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 @@ -2734,6 +3193,68 @@ 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 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. .SH ENVIRONMENT When a program is invoked it is given an array of strings called the @@ -2777,7 +3298,7 @@ by that command. .PP If the .B \-k -flag is set (see the +option is set (see the .B set builtin command below), then .I all @@ -2791,7 +3312,7 @@ invokes an external command, the variable is set to the full file name of the command and passed to that command in its environment. .SH "EXIT STATUS" -For the purposes of the shell, a command which exits with a +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, \fBbash\fP uses @@ -2801,6 +3322,9 @@ 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. @@ -2811,7 +3335,7 @@ executed, unless a syntax error occurs, in which case it exits with a non-zero value. See also the \fBexit\fP builtin command below. .SH SIGNALS -When \fBbash\fP is interactive, it ignores +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), @@ -2833,16 +3357,16 @@ and .SM .BR SIGTSTP . .PP -Synchronous jobs started by \fBbash\fP have signals set to the -values inherited by the shell from its parent. When job control -is not in effect, background jobs (jobs started with -.BR & ) +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 -.BR SIGQUIT . +.B SIGQUIT +as well. Commands run as a result of command substitution ignore the keyboard-generated job control signals .SM @@ -2859,18 +3383,44 @@ The shell exits by default upon receipt of a Before exiting, it resends the .SM .B SIGHUP -to all jobs, running or stopped. To prevent the shell from -sending the signal to a particular job, remove it from the +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 use -.B "disown \-h" -to mark it to not receive +below) or marked +to not receive .SM -.BR SIGHUP . +.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) @@ -2944,7 +3494,7 @@ Control-Y) causes the process to be stopped when it attempts to read input from the terminal, and control to be returned to .BR bash . -You may then manipulate the state of this job, using the +The user may then manipulate the state of this job, using the .B bg command to continue it in the background, the .B fg @@ -2983,7 +3533,7 @@ and refer to the shell's notion of the .IR "current job" , which is the last job stopped while it was in -the foreground. +the foreground or started in the background. The .I "previous job" may be referenced using @@ -3016,7 +3566,7 @@ any other output. If the option to the .B set builtin command -is set, +is enabled, .B bash reports such changes immediately. .PP @@ -3062,6 +3612,9 @@ the hostname .B \en newline .TP +.B \er +carriage return +.TP .B \es the name of the shell, the basename of .B $0 @@ -3245,13 +3798,13 @@ 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 +.I inputrc file is simple. All that is required is the name of the command or the text of a macro and a key sequence to which it should be bound. The name may be specified in one of two ways: as a symbolic key name, possibly with \fIMeta\-\fP or \fIControl\-\fP prefixes, or as a key sequence. -When using the form \fBkeyname\fP:\fIfunction\-name\fP or \fImacro\fP, +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 @@ -3277,7 +3830,7 @@ expressed on the right hand side (that is, to insert the text .I "> output" into the line). .PP -In the second form, \fB"keyseq"\fP:\fIfunction\-name\fP or \fImacro\fP, +In the second form, \fB"keyseq"\fP:\^\fIfunction\-name\fP or \fImacro\fP, .B keyseq differs from .B keyname @@ -3305,8 +3858,9 @@ and .I "ESC [ 1 1 ~" is bound to insert the text .BR "Function Key 1" . -The full set of escape sequences is +The full set of GNU Emacs style escape sequences is .RS +.PD 0 .TP .B \eC\- control prefix @@ -3326,11 +3880,53 @@ literal " .B \e' literal ' .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. Backslash -will quote any character in the macro text, including " and '. +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 character whose ASCII code is the octal value \fInnn\fP +(one to three digits) +.TP +.B \ex\fInnn\fP +the character whose ASCII code is the hexadecimal value \fInnn\fP +(one to three 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 @@ -3381,6 +3977,10 @@ 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 @@ -3433,7 +4033,7 @@ regardless of what the terminal claims it can support. The name is a synonym for this variable. .TP .B keymap (emacs) -Set the current readline keymap. The set of legal keymap names is +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 . @@ -3457,6 +4057,10 @@ 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 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 @@ -3474,7 +4078,7 @@ completions. Readline implements a facility similar in spirit to the conditional compilation features of the C preprocessor which allows key bindings and variable settings to be performed as the result -of tests. There are three parser directives used. +of tests. There are four parser directives used. .IP \fB$if\fP The .B $if @@ -3495,7 +4099,7 @@ 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 +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 @@ -3511,6 +4115,7 @@ 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 @@ -3521,11 +4126,21 @@ key sequence that quotes the current or previous word in Bash: .RE .RE .IP \fB$endif\fP -This command, as you saw in the previous example, terminates an +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 @@ -3561,7 +4176,7 @@ the line, thereby executing the command from the history list. .PP Non-incremental searches read the entire search string before starting to search for matching history lines. The search string may be -typed by the user or part of the contents of the current line. +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 @@ -3667,9 +4282,11 @@ 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 the way the shell does when it reads it. This +Expand the line as the shell does. This performs alias and history expansion as well as all of the shell word expansions. See .SM @@ -3683,6 +4300,13 @@ See .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 @@ -3708,8 +4332,7 @@ argument is ignored. .B delete\-char (C\-d) Delete the character under the cursor. If point is at the beginning of the line, there are no characters in the line, and -the last character typed was not -.BR C\-d , +the last character typed was not bound to \fBdelete\-char\fP, then return .SM .BR EOF . @@ -3719,7 +4342,7 @@ Delete the character behind the cursor. When given a numeric argument, save the deleted text on the kill ring. .TP .B quoted\-insert (C\-q, C\-v) -Add the next character that you type to the line verbatim. This is +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) @@ -3739,15 +4362,15 @@ moving the cursor over that word as well. .TP .B upcase\-word (M\-u) Uppercase the current (or following) word. With a negative argument, -do the previous word, but do not move point. +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, -do the previous word, but do not move point. +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, -do the previous word, but do not move point. +capitalize the previous word, but do not move point. .PD .SS Killing and Yanking .PP @@ -3761,7 +4384,8 @@ Kill backward to the beginning of the line. .TP .B unix\-line\-discard (C\-u) Kill backward from point to the beginning of the line. -.\" There is no real difference between this and backward-kill-line +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 the @@ -3792,9 +4416,11 @@ 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 the cursor. @@ -3848,6 +4474,19 @@ 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 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 complete\-filename (M\-/) Attempt filename completion on the text before point. .TP @@ -3883,7 +4522,7 @@ treating it as a hostname. Attempt completion on the text before point, treating it as a command name. Command completion attempts to match the text against aliases, reserved words, shell -functions, builtins, and finally executable filenames, +functions, shell builtins, and finally executable filenames, in that order. .TP .B possible\-command\-completions (C\-x !) @@ -3945,7 +4584,7 @@ is equivalent to Incremental undo, separately remembered for each line. .TP .B revert\-line (M\-r) -Undo all changes made to this line. This is like typing the +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 @@ -4132,16 +4771,16 @@ fix errors in previous commands quickly. History expansion is performed immediately after a complete line is read, before the shell breaks it into words. It takes place in two parts. -The first is to determine which line from the previous history +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 previous history is the \fIevent\fP, +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 as one word. +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 @@ -4240,7 +4879,7 @@ Word designators are used to select desired words from the event. A .B : separates the event specification from the word designator. -It can be omitted if the word designator begins with a +It may be omitted if the word designator begins with a .BR ^ , .BR $ , .BR * , @@ -4359,82 +4998,6 @@ or `\fB:&\fP'. If used with in place of /, and the final delimiter is optional if it is the last character of the event line. .PD -.SH "ARITHMETIC EVALUATION" -The shell allows arithmetic expressions to be evaluated, under -certain circumstances (see the \fBlet\fP builtin command and -\fBArithmetic Expansion\fP). -Evaluation -is done in long integers with no check for overflow, though division -by 0 is trapped and flagged as an error. The following list of -operators is grouped into levels of equal-precedence operators. -The levels are listed in order of decreasing precedence. -.PP -.PD 0 -.TP -.B \- + -unary minus and plus -.TP -.B ! ~ -logical and bitwise negation -.TP -.B * / % -multiplication, division, remainder -.TP -.B + \- -addition, subtraction -.TP -.B << >> -left and right bitwise shifts -.TP -.B <= >= < > -comparison -.TP -.B == != -equality and inequality -.TP -.B & -bitwise AND -.TP -.B ^ -bitwise exclusive OR -.TP -.B | -bitwise OR -.TP -.B && -logical AND -.TP -.B || -logical OR -.TP -.B \fIexpr\fP?\fIexpr\fP:\fIexpr\fP -conditional evaluation -.TP -.B = *= /= %= += \-= <<= >>= &= ^= |= -assignment -.PD -.PP -Shell variables are allowed as operands; parameter expansion is -performed before the expression is evaluated. -The value of a parameter is coerced to a long integer within -an expression. A shell variable need not have its integer attribute -turned on to be used in an expression. -.PP -Constants with a leading 0 are interpreted as octal numbers. -A leading 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 "SHELL BUILTIN COMMANDS" .\" start of bash_builtins .zZ @@ -4494,7 +5057,7 @@ 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. +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 @@ -4511,7 +5074,8 @@ is supplied, the name and value of the alias is printed. no alias has been defined. .TP \fBbg\fP [\fIjobspec\fP] -Place \fIjobspec\fP in the background, as if it had been started with +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. @@ -4522,7 +5086,9 @@ job control enabled, if \fIjobspec\fP was not found or started without job control. .TP .PD 0 -\fBbind\fP [\fB\-m\fP \fIkeymap\fP] [\fB\-lpsvPSV\fP] [\fB\-q\fP \fIname\fP] [\fB\-r\fP \fIkeyseq\fP] +\fBbind\fP [\fB\-m\fP \fIkeymap\fP] [\fB\-lpsvPSV\fP] +.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 @@ -4584,6 +5150,9 @@ Read key bindings from \fIfilename\fP. .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. .PD @@ -4613,11 +5182,11 @@ is executed. Execute the specified shell builtin, passing it .IR arguments , and return its exit status. -This is useful when you wish to define a +This is useful when defining a function whose name is the same as a shell builtin, -but need the functionality of the -builtin within the function itself. The \fBcd\fP builtin is -commonly redefined this way. The return status is false if +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 @@ -4689,7 +5258,7 @@ is printed. The option causes a single word indicating the command or file name used to invoke .I command -to be printed; the +to be displayed; the .B \-V option produces a more verbose description. If the @@ -4770,7 +5339,7 @@ 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. +by subsequent assignment statements or unset. .TP .B \-x Mark \fIname\fPs for export to subsequent commands via the environment. @@ -4782,13 +5351,13 @@ may not be used to destroy an array variable. When used in a function, makes each \fIname\fP local, as with the .B local -command. The return value is 0 unless an illegal option is encountered, +command. The return value is 0 unless an invalid option is encountered, an attempt is made to define a function using "\-f foo=bar", an attempt is made to assign a value to a readonly variable, an attempt is made to assign a value to an array variable without using the compound assignment syntax (see .B Arrays -above), one of the \fInames\fP is not a legal shell variable name, +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 \-f. @@ -4834,16 +5403,17 @@ prefixing each entry with its index in the stack. .PD .PP The return value is 0 unless an -illegal option is supplied or \fIn\fP indexes beyond the end +invalid option is supplied or \fIn\fP indexes beyond the end of the directory stack. .RE .TP -\fBdisown\fP [\fB\-h\fP] [\fIjobspec\fP ...] +\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, the job is not removed from the table, -but is marked so that +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 @@ -4851,8 +5421,21 @@ is not sent to the job if the shell receives a .BR SIGHUP . If no .I jobspec -is present, the \fIcurrent job\fP is used. The return value is -0 unless a +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 @@ -4904,15 +5487,21 @@ vertical tab .B \e\e backslash .TP -.B \ennn -the character whose ASCII code is \fInnn\fP (octal) +.B \e\fInnn\fP +the character whose ASCII code is the octal value \fInnn\fP +(one to three digits) +.TP +.B \ex\fInnn\fP +the character whose ASCII code is the hexadecimal value \fInnn\fP +(one to three digits) .PD .RE .TP \fBenable\fP [\fB\-adnps\fP] [\fB\-f\fP \fIfilename\fP] [\fIname\fP ...] -Enable and disable builtin shell commands. This allows -the execution of a disk command which has the same name as a shell -builtin without specifying a full file name. +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 with 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 @@ -4958,7 +5547,7 @@ or only null arguments, .B eval returns 0. .TP -\fBexec\fP [\fB\-cl\fP] [\fB\-a\fP \fIname\fP] [\fIcommand\fP] [\fIarguments\fP] +\fBexec\fP [\fB\-cl\fP] [\fB\-a\fP \fIname\fP] [\fIcommand\fP [\fIarguments\fP]] If .I command is specified, it replaces the shell. @@ -4990,7 +5579,8 @@ 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. +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 @@ -5028,9 +5618,9 @@ The option causes the export property to be removed from the named variables. .B export -returns an exit status of 0 unless an illegal option is +returns an exit status of 0 unless an invalid option is encountered, -one of the \fInames\fP is not a legal shell variable name, or +one of the \fInames\fP is not a valid shell variable name, or .B \-f is supplied with a .I name @@ -5067,13 +5657,13 @@ command for editing and \-16 for listing. .sp 1 The .B \-n -flag suppresses +option suppresses the command numbers when listing. The .B \-r -flag reverses the order of +option reverses the order of the commands. If the .B \-l -flag is given, +option is given, the commands are listed on standard output. Otherwise, the editor given by .I ename @@ -5112,7 +5702,7 @@ and typing .if t \f(CWr\fP re-executes the last command. .sp 1 -If the first form is used, the return value is 0 unless an illegal +If the first form is used, the return value is 0 unless an invalid option is encountered or .I first or @@ -5130,9 +5720,10 @@ does not specify a valid history line, in which case returns failure. .TP \fBfg\fP [\fIjobspec\fP] -Place +Resume .I jobspec -in the foreground, and make it the current job. If +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, @@ -5178,23 +5769,35 @@ calls to 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 illegal options or missing option arguments are +are printed when invalid options or missing option arguments are encountered. If the variable .SM .B OPTERR -is set to 0, no error message will be displayed, even if the first +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 illegal option is seen, +If an invalid option is seen, .B getopts places ? into .I name @@ -5227,12 +5830,6 @@ and is set to the option character found. .sp 1 .B getopts -normally parses the positional parameters, but if more arguments are -given in -.IR args , -.B getopts -parses those instead. -.B getopts returns true if an option, specified or unspecified, is found. It returns false if the end of options is encountered or an error occurs. @@ -5256,7 +5853,7 @@ remembered locations. If no arguments are given, information about remembered commands is printed. The return status is true unless a .I name -is not found or an illegal option is supplied. +is not found or an invalid option is supplied. .TP \fBhelp\fP [\fIpattern\fP] Display helpful information about builtin commands. If @@ -5330,7 +5927,7 @@ history list is removed before the are added. .PD .PP -The return value is 0 unless an illegal option is encountered or an +The return value is 0 unless an invalid option is encountered or an error occurs while reading or writing the history file. .RE .TP @@ -5366,8 +5963,8 @@ Restrict output to stopped jobs. If .I jobspec is given, output is restricted to information about that job. -The return status is 0 unless an illegal option is encountered -or an illegal +The return status is 0 unless an invalid option is encountered +or an invalid .I jobspec is supplied. .PP @@ -5391,7 +5988,7 @@ returning its exit status. .PD 0 \fBkill\fP [\fB\-s\fP \fIsigspec\fP | \fB\-n\fP \fIsignum\fP | \fB\-\fP\fIsigspec\fP] [\fIpid\fP | \fIjobspec\fP] ... .TP -\fBkill\fP \fB\-l\fP [\fIsignum\fP | \fIsigspec\fP] +\fBkill\fP \fB\-l\fP [\fIsigspec\fP | \fIexit_status\fP] .PD Send the signal named by .I sigspec @@ -5419,18 +6016,21 @@ If is not present, then .SM .B SIGTERM -is assumed. An argument of +is assumed. +An argument of .B \-l -lists the signal names. If any arguments are supplied when +lists the signal names. +If any arguments are supplied when .B \-l -is given, the names of the specified signals are listed, and -the return status is 0. The arguments to +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 -may be either signal names or signal numbers; if signal names -are given, the corresponding signal number is displayed. +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 illegal option is encountered. +if an error occurs or an invalid option is encountered. .TP \fBlet\fP \fIarg\fP [\fIarg\fP ...] Each @@ -5445,9 +6045,9 @@ evaluates to 0, returns 1; 0 is returned otherwise. .TP \fBlocal\fP [\fIname\fP[=\fIvalue\fP] ...] -For each argument, create a local variable named -.IR name , -and assign it +For each argument, a local variable named +.I name +is created, and assigned .IR value . When .B local @@ -5461,7 +6061,7 @@ an error to use .B local when not within a function. The return status is 0 unless .B local -is used outside a function, or an illegal +is used outside a function, or an invalid .I name is supplied. .TP @@ -5502,11 +6102,29 @@ command is successful, a .B dirs is performed as well, and the return status is 0. .B popd -returns false if an illegal option is encountered, the directory stack +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, %b causes +\fBprintf\fP to expand backslash escape sequences in the corresponding +\fIargument\fP, and %q 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. +.TP .PD 0 \fBpushd\fP [\fB\-n\fP] [\fIdir\fP] .TP @@ -5574,7 +6192,8 @@ If the .B \-L option is used, symbolic links are followed. The return status is 0 unless an error occurs while -reading the name of the current directory. +reading the name of the current directory or an +invalid option is supplied. .TP \fBread\fP [\fB\-er\fP] [\fB\-a\fP \fIaname\fP] [\fB\-p\fP \fIprompt\fP] [\fIname\fP ...] One line is read from the standard input, and the first word @@ -5582,13 +6201,16 @@ is assigned to the first .IR name , the second word to the second .IR name , -and so on, with leftover words assigned to the last +and so on, with leftover words and their intervening separators assigned +to the last .IR name . -Only the characters in +If there are fewer words read from the standard input than names, +the remaining names are assigned empty values. +The characters in .SM .B IFS -are recognized as word delimiters. Options, if supplied, have the -following meanings: +are used to split the line into words. +Options, if supplied, have the following meanings: .RS .PD 0 .TP @@ -5608,6 +6230,7 @@ of the array variable starting at 0. .I aname is unset before any new values are assigned. +Other \fIname\fP arguments are ignored. .TP .B \-e If the standard input @@ -5646,10 +6269,13 @@ If no arguments are given, or if the .B \-p option is supplied, a list of all readonly names is printed. -The return status is 0 unless an illegal option is encountered, +The +.B \-p +option causes output to be displayed in a format thatmay be reused as input. +The return status is 0 unless an invalid option is encountered, one of the .I names -is not a legal shell variable name, or +is not a valid shell variable name, or .B \-f is supplied with a .I name @@ -5674,7 +6300,8 @@ the return status is false. .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 re-used as input. +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 @@ -5720,7 +6347,7 @@ Disable pathname expansion. .TP 8 .B \-h Remember the location of commands as they are looked up for execution. -This is on by default. +This is enabled by default. .TP 8 .B \-k All arguments in the form of assignment statements @@ -5728,7 +6355,7 @@ are placed in the environment for a command, not just those that precede the command name. .TP 8 .B \-m -Monitor mode. Job control is enabled. This flag is on +Monitor mode. Job control is enabled. This option is on by default for interactive shells on systems that support it (see .SM @@ -5860,10 +6487,12 @@ Turn on .I privileged mode. In this mode, the .B $ENV -file is not processed, and shell functions -are not inherited from the environment. This is enabled automatically -on startup if the effective user (group) id is not equal to the real -user (group) id. Turning this option off causes the effective user +file is not processed, shell functions are not inherited from the +environment, and the variable +The \fBSHELLOPTS\fP variable, if it appears in the environment, is ignored. +This is enabled automatically on startup if the effective user (group) +id is not equal to the real user (group) id. +Turning this option off causes the effective user and group ids to be set to the real user and group ids. .TP 8 .B \-t @@ -5907,7 +6536,7 @@ instead of .B \-H Enable .B ! -style history substitution. This flag is on by +style history substitution. This option is on by default when the shell is interactive. .TP 8 .B \-P @@ -5921,7 +6550,7 @@ follows the logical chain of directories when performing commands which change the current directory. .TP 8 .B \-\- -If no arguments follow this flag, then the positional parameters are +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 \- . @@ -5937,16 +6566,13 @@ If there are no \fIarg\fPs, the positional parameters remain unchanged. .PD .PP -The flags are off by default -unless otherwise noted. -Using + rather than \- causes these flags -to be turned off. The -flags can also be specified as options to an -invocation of the shell. The current -set of flags may be found in +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 illegal option is encountered. +The return status is always true unless an invalid option is encountered. .RE .TP \fBshift\fP [\fIn\fP] @@ -5977,8 +6603,10 @@ Toggle the values of variables controlling optional shell behavior. With no options, or with the .B \-p option, a list of all settable options is displayed, with -an indication of whether or not each is set. Other options have -the following meanings: +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 @@ -6015,7 +6643,7 @@ by default. .PP The return status when listing options is zero if all \fIoptnames\fP are enabled, non-zero otherwise. When setting or unsetting options, -the return status is zero unless an \fIoptname\fP is not a legal shell +the return status is zero unless an \fIoptname\fP is not a valid shell option. .PP The list of \fBshopt\fP options is: @@ -6081,6 +6709,10 @@ If set, aliases are expanded as described above under .BR ALIASES . This option is enabled by default for interactive shells. .TP 8 +.B extglob +If set, the extended pattern matching features described above under +\fBPathname Expansion\fP are enabled. +.TP 8 .B histappend If set, the history list is appended to the file named by the value of the @@ -6103,8 +6735,8 @@ the \fBreadline\fP editing buffer, allowing further modification. .B hostcomplete If set, and .B readline -is being used, bash will attempt to perform hostname completion when a -word beginning with \fB@\fP is being completed (see +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 @@ -6112,6 +6744,12 @@ under 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 # @@ -6132,6 +6770,14 @@ 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 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 @@ -6160,7 +6806,7 @@ If set, the .SM .B PATH to find the directory containing the file supplied as an argument. -This is enabled by default. +This option is enabled by default. .RE .TP \fBsuspend\fP [\fB\-f\fP] @@ -6182,154 +6828,91 @@ is not supplied, or if job control is not enabled. Return a status of 0 or 1 depending on the evaluation of the conditional expression .IR expr . -Expressions may be unary or binary. Unary -expressions are often used to examine the status of a file. There -are string operators and numeric comparison operators as well. Each -operator and operand must be a separate argument. If \fIfile\fP -is of the form /dev/fd/\fIn\fP, then file descriptor \fIn\fP is -checked. Expressions are composed of the following primaries: +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 \-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 \-k \fIfile\fP -True if \fIfile\fP has its ``sticky'' bit set. -.TP -.B \-L \fIfile\fP -True if \fIfile\fP exists and is a symbolic link. -.TP -.B \-p \fIfile\fP -True if \fIfile\fP exists and is a named pipe. -.TP -.B \-r \fIfile\fP -True if \fIfile\fP exists and is readable. -.TP -.B \-s \fIfile\fP -True if \fIfile\fP exists and has a size greater than zero. -.TP -.B \-S \fIfile\fP -True if \fIfile\fP exists and is a socket. -.TP -.B \-t \fIfd\fP -True if -.I fd -is opened on a terminal. -.TP -.B \-u \fIfile\fP -True if \fIfile\fP exists and its set-user-id bit is set. -.TP -.B \-w \fIfile\fP -True if \fIfile\fP exists and is writable. -.TP -.B \-x \fIfile\fP -True if \fIfile\fP exists and is executable. -.TP -.B \-O \fIfile\fP -True if \fIfile\fP exists and is owned by the effective user id. -.TP -.B \-G \fIfile\fP -True if \fIfile\fP exists and is owned by the effective group id. -.TP -\fIfile1\fP \-\fBnt\fP \fIfile2\fP -True if \fIfile1\fP is newer (according to -modification date) than \fIfile2\fP. -.TP -\fIfile1\fP \-\fBot\fP \fIfile2\fP -True if \fIfile1\fP is older than \fIfile2\fP. -.TP -\fIfile1\fP \fB\-ef\fP \fIfile2\fP -True if \fIfile1\fP and \fIfile2\fP have the same device and -inode numbers. -.TP -.B \-o \fIoptname\fP -True if shell option -.I optname -is enabled. -See the list of options under the description of the -.B \-o -option to the -.B set -builtin above. -.TP -.B \-z \fIstring\fP -True if the length of \fIstring\fP is zero. -.TP -.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. -.TP -\fIstring1\fP \fB!=\fP \fIstring2\fP -True if the strings are not equal. -.TP -\fIstring1\fP \fB<\fP \fIstring2\fP -True if \fIstring1\fP sorts before \fIstring2\fP lexicographically. -.TP -\fIstring1\fP \fB>\fP \fIstring2\fP -True if \fIstring1\fP sorts after \fIstring2\fP lexicographically. -.TP .B ! \fIexpr\fP True if .I expr 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 +and .I expr2 are true. .TP \fIexpr1\fP \-\fBo\fP \fIexpr2\fP True if either .I expr1 -OR +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 -.I \fIarg1\fP \fBOP\fP \fIarg2\fP +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 -.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 +.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 @@ -6401,14 +6984,14 @@ is invalid; otherwise .B trap returns true. .TP -\fBtype\fP [\fB\-all\fP] [\fB\-type\fP | \fB\-path\fP] \fIname\fP [\fIname\fP ...] +\fBtype\fP [\fB\-atp\fP] \fIname\fP [\fIname\fP ...] With no options, indicate how each .I name would be interpreted if used as a command name. If the -.B \-type -flag is used, +.B \-t +option is used, .B type prints a string which is one of .IR alias , @@ -6426,49 +7009,36 @@ If the is not found, then nothing is printed, and an exit status of false is returned. If the -.B \-path -flag is used, +.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 -.B \-type +or nothing if \f(CWtype -t name\fP would not return .IR file . If a command is hashed, -.B \-path +.B \-p prints the hashed value, not necessarily the file that appears first in .SM .BR PATH . If the -.B \-all -flag is used, +.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 \-path -flag is not also used. +.B \-p +option is not also used. The table of hashed commands is not consulted when using -.BR \-all . -.B type -accepts -.BR \-a , -.BR \-t , -and -.B \-p -in place of -.BR \-all , -.BR \-type , -and -.BR \-path , -respectively. +.BR \-a . .B type returns true if any of the arguments are found, false if none are found. @@ -6550,12 +7120,12 @@ and and .BR \-u , which are unscaled values. The return status is 0 -unless an illegal option is encountered, a non-numeric argument +unless an invalid option is encountered, a non-numeric argument other than \fBunlimited\fP is supplied as \fIlimit\fP, or an error occurs while setting a new limit. .RE .TP -\fBumask\fP [\fB\-S\fP] [\fImode\fP] +\fBumask\fP [\fB\-p\fP] [\fB\-S\fP] [\fImode\fP] The user file-creation mask is set to .IR mode . If @@ -6575,6 +7145,11 @@ 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 @@ -6652,7 +7227,7 @@ 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: +with the exception that the following are disallowed or not performed: .IP \(bu changing directories with \fBcd\fP .IP \(bu @@ -6672,6 +7247,8 @@ 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 @@ -6693,7 +7270,7 @@ option to the builtin command .IP \(bu turning off restricted mode with -.BR "set +r" . +\fBset +r\fP or \fBset +o restricted\fP. .PP These restrictions are enforced after any startup files are read. .PP @@ -6761,7 +7338,7 @@ Once you have determined that a bug actually exists, use the 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 \fPbug-bash\fP@\fIprep.ai.MIT.Edu\fP or posted to the Usenet +to \fIbug-bash@gnu.org\fP or posted to the Usenet newsgroup .BR gnu.bash.bug . .PP diff --git a/doc/bashref.info b/doc/bashref.info index 4707a20a..2ba11f05 100644 --- a/doc/bashref.info +++ b/doc/bashref.info @@ -1,19 +1,19 @@ This is Info file bashref.info, produced by Makeinfo version 1.67 from -the input file /usr/homes/chet/src/bash/bash-2.01.1/doc/bashref.texi. +the input file /usr/homes/chet/src/bash/src/doc/bashref.texi. INFO-DIR-SECTION Utilities START-INFO-DIR-ENTRY -* Bash: (bash). GNU Bourne-Again SHell +* Bash: (bash). The GNU Bourne-Again SHell. END-INFO-DIR-ENTRY This text is a brief description of the features that are present in the Bash shell. -This is Edition 2.0, last updated 19 May 1997, +This is Edition 2.2, last updated 1 April 1998, of `The GNU Bash Reference Manual', -for `Bash', Version 2.01. +for `Bash', Version 2.02. -Copyright (C) 1991, 1993, 1996 Free Software Foundation, Inc. +Copyright (C) 1991, 1993, 1996, 1997 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice @@ -27,7 +27,7 @@ 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. +by the Free Software Foundation. File: bashref.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) @@ -38,8 +38,8 @@ Bash Features This text is a brief description of the features that are present in the Bash shell. - This is Edition 2.0, last updated 19 May 1997, of `The GNU Bash -Reference Manual', for `Bash', Version 2.01. + This is Edition 2.2, last updated 1 April 1998, of `The GNU Bash +Reference Manual', for `Bash', Version 2.02. Copyright (C) 1991, 1993, 1996 Free Software Foundation, Inc. @@ -66,12 +66,6 @@ on shell behavior. * Bourne Shell Features:: Features similar to those found in the Bourne shell. -* Csh Features:: Features originally found in the - Berkeley C-Shell. - -* Korn Shell Features:: Features originally found in the Korn - Shell. - * Bash Features:: Features found only in Bash. * Job Control:: A chapter describing what job control is @@ -124,16 +118,16 @@ ancestor of the current Unix shell `/bin/sh', which appeared in the Seventh Edition Bell Labs Research version of Unix. Bash is an `sh'-compatible shell that incorporates useful features -from the Korn shell `ksh' and the C shell `csh'. It is ultimately -intended to be a conformant implementation of the IEEE POSIX Shell and -Tools specification (IEEE Working Group 1003.2). It offers functional +from the Korn shell `ksh' and the C shell `csh'. It is intended to be +a conformant implementation of the IEEE POSIX Shell and Tools +specification (IEEE Working Group 1003.2). It offers functional improvements over `sh' for both interactive and programming use. While the GNU operating system will include a version of `csh', Bash will be the default shell. Like other GNU software, Bash is quite portable. It currently runs on nearly every version of Unix and a few -other operating systems - independently-supported ports exist for OS/2 -and Windows NT. +other operating systems - independently-supported ports exist for +MS-DOS, OS/2, Windows 95, and Windows NT. File: bashref.info, Node: What is a shell?, Prev: What is Bash?, Up: Introduction @@ -144,20 +138,22 @@ What is a shell? At its base, a shell is simply a macro processor that executes commands. A Unix shell is both a command interpreter, which provides the user interface to the rich set of Unix utilities, and a programming -language, allowing these utilitites to be combined. The shell reads -commands either from a terminal or a file. Files containing commands -can be created, and become commands themselves. These new commands -have the same status as system commands in directories like `/bin', -allowing users or groups to establish custom environments. +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 like +`/bin', allowing users or groups to establish custom environments. A shell allows execution of Unix commands, both synchronously and -asynchronously. The "redirection" constructs permit fine-grained -control of the input and output of those commands, and the shell allows -control over the contents of their environment. Unix shells also -provide a small set of built-in commands ("builtins") implementing -functionality impossible (e.g., `cd', `break', `continue', and `exec'), -or inconvenient (`history', `getopts', `kill', or `pwd', for example) -to obtain via separate utilities. Shells may be used interactively or +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 "redirection" constructs permit fine-grained control of +the input and output of those commands, and the shell allows control +over the contents of their environment. Unix shells also provide a +small set of built-in commands ("builtins") implementing functionality +impossible (e.g., `cd', `break', `continue', and `exec'), or +inconvenient (`history', `getopts', `kill', or `pwd', for example) to +obtain via separate utilities. Shells may be used interactively or non-interactively: they accept input typed from the keyboard or from a file. All of the shell builtins are described in subsequent sections. @@ -271,7 +267,7 @@ of the Bourne shell builtin commands are available in Bash, and the rules for evaluation and quoting are taken from the POSIX 1003.2 specification for the `standard' Unix shell. - This chapter briefly summarizes the shell's "building blocks": + This chapter briefly summarizes the shell's `building blocks': commands, control structures, shell functions, shell parameters, shell expansions, redirections, which are a way to direct input and output from and to named files, and how the shell executes commands. @@ -279,13 +275,7 @@ from and to named files, and how the shell executes commands. * Menu: * Shell Syntax:: What your input means to the shell. -* Simple Commands:: The most common type of command. -* Pipelines:: Connecting the input and output of several - commands. -* Lists:: How to execute commands sequentially. -* Looping Constructs:: Shell commands for iterative action. -* Conditional Constructs:: Shell commands for conditional execution. -* Command Grouping:: Ways to group commands. +* Shell Commands:: The types of commands you can use. * Shell Functions:: Grouping commands by name. * Shell Parameters:: Special shell variables. * Shell Expansions:: How Bash expands variables and the various @@ -295,7 +285,7 @@ from and to named files, and how the shell executes commands. * Shell Scripts:: Executing files of shell commands. -File: bashref.info, Node: Shell Syntax, Next: Simple Commands, Up: Basic Shell Features +File: bashref.info, Node: Shell Syntax, Next: Shell Commands, Up: Basic Shell Features Shell Syntax ============ @@ -322,11 +312,12 @@ reads and executes a command. Basically, the shell does the following: Invoking Bash::.), or from the user's terminal. 2. Breaks the input into words and operators, obeying the quoting - rules described in *Note Quoting::. Tokens are separated by + rules described in *Note Quoting::. These tokens are separated by `metacharacters'. Alias expansion is performed by this step (*note Aliases::.). - 3. Parses the tokens into simple and compound commands. + 3. Parses the tokens into simple and compound commands (*note Shell + Commands::.). 4. Performs the various shell expansions (*note Shell Expansions::.), breaking the expanded tokens into lists of filenames (*note @@ -339,7 +330,7 @@ reads and executes a command. Basically, the shell does the following: 6. Executes the command (*note Executing Commands::.). 7. Optionally waits for the command to complete and collects its exit - status. + status (*note Exit Status::.). @@ -365,10 +356,10 @@ or words to the shell. Quoting can be used to disable special treatment for special characters, to prevent reserved words from being recognized as such, and to prevent parameter expansion. - Each of the shell `metacharacters' (*note Definitions::.) has -special meaning to the shell and must be quoted if they are to -represent themselves. There are three quoting mechanisms: the ESCAPE -CHARACTER, single quotes, and double quotes. + Each of the shell metacharacters (*note Definitions::.) has special +meaning to the shell and must be quoted if it is to represent itself. +There are three quoting mechanisms: the ESCAPE CHARACTER, single +quotes, and double quotes. File: bashref.info, Node: Escape Character, Next: Single Quotes, Up: Quoting @@ -379,8 +370,9 @@ Escape Character A non-quoted backslash `\' is the Bash escape character. It preserves the literal value of the next character that follows, with the exception of `newline'. If a `\newline' pair appears, and the -backslash is not quoted, the `\newline' is treated as a line -continuation (that is, it is effectively ignored). +backslash itself is not quoted, the `\newline' is treated as a line +continuation (that is, it is removed from the input stream and +effectively ignored). File: bashref.info, Node: Single Quotes, Next: Double Quotes, Prev: Escape Character, Up: Quoting @@ -401,10 +393,13 @@ Double Quotes Enclosing characters in double quotes preserves the literal value of all characters within the quotes, with the exception of `$', ``', and `\'. The characters `$' and ``' retain their special meaning within -double quotes. The backslash retains its special meaning only when -followed by one of the following characters: `$', ``', `"', `\', or -`newline'. A double quote may be quoted within double quotes by -preceding it with a backslash. +double quotes (*note Shell Expansions::.). The backslash retains its +special meaning only when followed by one of the following characters: +`$', ``', `"', `\', or `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. The special parameters `*' and `@' have special meaning when in double quotes (*note Shell Parameter Expansion::.). @@ -448,7 +443,12 @@ present, are decoded as follows: backslash `\NNN' - the character whose `ASCII' code is NNN in octal + the character whose `ASCII' code is the octal value NNN (one to + three digits) + +`\xNNN' + the character whose `ASCII' code is the hexadecimal value NNN (one + to three digits) The result is single-quoted, as if the dollar sign had not been present. @@ -475,28 +475,45 @@ Bash Builtins::.), a word beginning with `#' causes that word and all remaining characters on that line to be ignored. An interactive shell without the `interactive_comments' option enabled does not allow comments. The `interactive_comments' option is on by default in -interactive shells. +interactive shells. *Note Is This Shell Interactive?::, for a +description of what makes a shell interactive. -File: bashref.info, Node: Simple Commands, Next: Pipelines, Prev: Shell Syntax, Up: Basic Shell Features +File: bashref.info, Node: Shell Commands, Next: Shell Functions, Prev: Shell Syntax, Up: Basic Shell Features + +Shell Commands +============== + +* 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. + + +File: bashref.info, Node: Simple Commands, Next: Pipelines, Up: Shell Commands Simple Commands -=============== +--------------- - A simple command is the kind of command you'll encounter most often. + A simple command is the kind of command encountered most often. It's just a sequence of words separated by `blank's, terminated by one -of the shell control operators (*note Definitions::.). The first word -generally specifies a command to be executed. +of the shell's control operators (*note Definitions::.). The first +word generally specifies a command to be executed. The return status (*note Exit Status::.) of a simple command is its exit status as provided by the POSIX.1 `waitpid' function, or 128+N if the command was terminated by signal N. -File: bashref.info, Node: Pipelines, Next: Lists, Prev: Simple Commands, Up: Basic Shell Features +File: bashref.info, Node: Pipelines, Next: Lists, Prev: Simple Commands, Up: Shell Commands Pipelines -========= +--------- A `pipeline' is a sequence of simple commands separated by `|'. @@ -508,22 +525,30 @@ the next command. That is, each command reads the previous command's output. The reserved word `time' causes timing statistics to be printed for -the pipeline once it finishes. The `-p' option changes the output -format to that specified by POSIX. The `TIMEFORMAT' variable may be -set to a format string that specifies how the timing information should -be displayed. *Note Bash Variables::, for a description of the -available formats. +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 `-p' option changes the output format to that +specified by POSIX. The `TIMEFORMAT' variable may be set to a format +string that specifies how the timing information should be displayed. +*Note Bash Variables::, for a description of the available formats. +The use of `time' as a reserved word permits the timing of shell +builtins, shell functions, and pipelines. An external `time' command +cannot time these easily. + + If the pipeline is not executed asynchronously (*note Lists::.), the +shell waits for all commands in the pipeline to complete. - Each command in a pipeline is executed in its own subshell. The exit -status of a pipeline is the exit status of the last command in the -pipeline. If the reserved word `!' precedes the pipeline, the exit -status is the logical NOT of the exit status of the last command. + Each command in a pipeline is executed in its own subshell (*note +Command Execution Environment::.). The exit status of a pipeline is +the exit status of the last command in the pipeline. If the reserved +word `!' precedes the pipeline, the exit status is the logical negation +of the exit status of the last command. -File: bashref.info, Node: Lists, Next: Looping Constructs, Prev: Pipelines, Up: Basic Shell Features +File: bashref.info, Node: Lists, Next: Looping Constructs, Prev: Pipelines, Up: Shell Commands Lists of Commands -================= +----------------- A `list' is a sequence of one or more pipelines separated by one of the operators `;', `&', `&&', or `||', and optionally terminated by one @@ -533,11 +558,15 @@ of `;', `&', or a `newline'. followed by `;' and `&', which have equal precedence. If a command is terminated by the control operator `&', the shell -executes the command in the BACKGROUND in a subshell. The shell does -not wait for the command to finish, and the return status is 0 (true). -Commands separated by a `;' are executed sequentially; the shell waits -for each command to terminate in turn. The return status is the exit -status of the last command executed. +executes the command asynchronously in a subshell. This is known as +executing the command in the BACKGROUND. The shell does not wait for +the command to finish, and the return status is 0 (true). The standard +input for asynchronous commands, in the absence of any explicit +redirections, is redirected from `/dev/null'. + + Commands separated by a `;' are executed sequentially; the shell +waits for each command to terminate in turn. The return status is the +exit status of the last command executed. The control operators `&&' and `||' denote AND lists and OR lists, respectively. An AND list has the form @@ -549,52 +578,59 @@ zero. An OR list has the form COMMAND || COMMAND2 -COMMAND2 is executed if and only if COMMAND returns a non-zero exit +COMMAND2 is executed if, and only if, COMMAND returns a non-zero exit status. The return status of AND and OR lists is the exit status of the last command executed in the list. -File: bashref.info, Node: Looping Constructs, Next: Conditional Constructs, Prev: Lists, Up: Basic Shell Features +File: bashref.info, Node: Looping Constructs, Next: Conditional Constructs, Prev: Lists, Up: Shell Commands Looping Constructs -================== - - Note that wherever you see a `;' in the description of a command's -syntax, it may be replaced indiscriminately with one or more newlines. +------------------ Bash supports the following looping constructs. + Note that wherever you see a `;' in the description of a command's +syntax, it may be replaced with one or more newlines. + `until' The syntax of the `until' command is: until TEST-COMMANDS; do CONSEQUENT-COMMANDS; done - Execute CONSEQUENT-COMMANDS as long as the final command in - TEST-COMMANDS has an exit status which is not zero. + Execute CONSEQUENT-COMMANDS as long as TEST-COMMANDS has an exit + status which is not zero. The return status is the exit status of + the last command executed in CONSEQUENT-COMMANDS, or zero if none + was executed. `while' The syntax of the `while' command is: while TEST-COMMANDS; do CONSEQUENT-COMMANDS; done - Execute CONSEQUENT-COMMANDS as long as the final command in - TEST-COMMANDS has an exit status of zero. + Execute CONSEQUENT-COMMANDS as long as TEST-COMMANDS has an exit + status of zero. The return status is the exit status of the last + command executed in CONSEQUENT-COMMANDS, or zero if none was + executed. `for' The syntax of the `for' command is: for NAME [in WORDS ...]; do COMMANDS; done - Execute COMMANDS for each member in WORDS, with NAME bound to the - current member. If `in WORDS' is not present, `in "$@"' is - assumed. + Expand WORDS, and execute COMMANDS once for each member in the + resultant list, with NAME bound to the current member. If `in + WORDS' is not present, `in "$@"' is assumed. The return status is + the exit status of the last command that executes. If there are + no items in the expansion of WORDS, no commands are executed, and + the return status is zero. The `break' and `continue' builtins (*note Bourne Shell Builtins::.) may be used to control loop execution. -File: bashref.info, Node: Conditional Constructs, Next: Command Grouping, Prev: Looping Constructs, Up: Basic Shell Features +File: bashref.info, Node: Conditional Constructs, Next: Command Grouping, Prev: Looping Constructs, Up: Shell Commands Conditional Constructs -====================== +---------------------- `if' The syntax of the `if' command is: @@ -606,21 +642,36 @@ Conditional Constructs [else ALTERNATE-CONSEQUENTS;] fi - Execute CONSEQUENT-COMMANDS only if the final command in - TEST-COMMANDS has an exit status of zero. Otherwise, each `elif' - list is executed in turn, and if its exit status is zero, the - corresponding MORE-CONSEQUENTS is executed and the command - completes. If `else ALTERNATE-CONSEQUENTS' is present, and the - final command in the final `if' or `elif' clause has a non-zero - exit status, then execute ALTERNATE-CONSEQUENTS. + The TEST-COMMANDS list is executed, and if its return status is + zero, the CONSEQUENT-COMMANDS list is executed. If TEST-COMMANDS + returns a non-zero status, each `elif' list is executed in turn, + and if its exit status is zero, the corresponding MORE-CONSEQUENTS + is executed and the command completes. If `else + ALTERNATE-CONSEQUENTS' is present, and the final command in the + final `if' or `elif' clause has a non-zero exit status, then + ALTERNATE-CONSEQUENTS is executed. The return status is the exit + status of the last command executed, or zero if no condition + tested true. `case' The syntax of the `case' command is: - `case WORD in [ ( PATTERN [| PATTERN]...) COMMANDS ;;]... esac' + `case WORD in [ [(] PATTERN [| PATTERN]...) COMMAND-LIST ;;]... esac' - Selectively execute COMMANDS based upon WORD matching PATTERN. - The `|' is used to separate multiple patterns. + `case' will selectively execute the COMMAND-LIST corresponding to + the first PATTERN that matches WORD. The `|' is used to separate + multiple patterns, and the `)' operator terminates a pattern list. + A list of patterns and an associated command-list is known as a + CLAUSE. Each clause must be terminated with `;;'. The WORD + undergoes tilde expansion, parameter expansion, command + substitution, arithmetic expansion, and quote removal before + matching is attempted. Each PATTERN undergoes tilde expansion, + parameter expansion, command substitution, and arithmetic + expansion. + + There may be an arbitrary number of `case' clauses, each terminated + by a `;;'. The first pattern that matches determines the + command-list that is executed. Here is an example using `case' in a script that could be used to describe one interesting feature of an animal: @@ -635,24 +686,96 @@ Conditional Constructs esac echo " legs." + The return status is zero if no PATTERN is matched. Otherwise, the + return status is the exit status of the COMMAND-LIST executed. + +`select' + The `select' construct allows the easy generation of menus. It + has almost the same syntax as the `for' command: + + select NAME [in WORDS ...]; do COMMANDS; done + + The list of words following `in' is expanded, generating a list of + items. The set of expanded words is printed on the standard error + output stream, each preceded by a number. If the `in WORDS' is + omitted, the positional parameters are printed, as if `in "$@"' + had been specifed. The `PS3' prompt is then displayed and a line + is read from the standard input. If the line consists of a number + corresponding to one of the displayed words, then the value of + NAME is set to that word. If the line is empty, the words and + prompt are displayed again. If `EOF' is read, the `select' + command completes. Any other value read causes NAME to be set to + null. The line read is saved in the variable `REPLY'. + + The COMMANDS are executed after each selection until a `break' or + `return' command is executed, at which point the `select' command + completes. + + 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. + + select fname in *; + do + echo you picked $fname \($REPLY\) + break; + done + `((...))' (( EXPRESSION )) - The EXPRESSION is evaluated according to the rules described below - (*note Arithmetic Evaluation::.). If the value of the expression - is non-zero, the return status is 0; otherwise the return status - is 1. This is exactly equivalent to + The arithmetic EXPRESSION is evaluated according to the rules + described below (*note 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 let "EXPRESSION" - The `select' construct, which allows users to choose from a list of -items presented as a menu, is also available. *Note Korn Shell -Constructs::, for a full description of `select'. + *Note Bash Builtins::, for a full description of the `let' builtin. + +`[[...]]' + [[ EXPRESSION ]] + + Return a status of 0 or 1 depending on the evaluation of the + conditional expression EXPRESSION. Expressions are composed of + the primaries described below in *Note Bash Conditional + Expressions::. Word splitting and filename expansion are not + performed on the words between the `[[' and `]]'; tilde expansion, + parameter and variable expansion, arithmetic expansion, command + substitution, process substitution, and quote removal are + performed. + + When the `==' and `!=' operators are used, the string to the right + of the operator is considered a pattern and matched according to + the rules described below in *Note 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: + + `( EXPRESSION )' + Returns the value of EXPRESSION. This may be used to + override the normal precedence of operators. + + `! EXPRESSION' + True if EXPRESSION is false. + + `EXPRESSION1 && EXPRESSION2' + True if both EXPRESSION1 and EXPRESSION2 are true. + + `EXPRESSION1 || EXPRESSION2' + True if either EXPRESSION1 or EXPRESSION2 is true. + + The && and || commands do not execute EXPRESSION2 if the value of + EXPRESSION1 is sufficient to determine the return value of the + entire conditional expression. -File: bashref.info, Node: Command Grouping, Next: Shell Functions, Prev: Conditional Constructs, Up: Basic Shell Features +File: bashref.info, Node: Command Grouping, Prev: Conditional Constructs, Up: Shell Commands Grouping Commands -================= +----------------- Bash provides two ways to group a list of commands to be executed as a unit. When commands are grouped, redirections may be applied to the @@ -663,8 +786,8 @@ the list may be redirected to a single stream. ( LIST ) Placing a list of commands between parentheses causes a subshell - to be created, and each of the commands to be executed in that - subshell. Since the LIST is executed in a subshell, variable + to be created, and each of the commands in LIST to be executed in + that subshell. Since the LIST is executed in a subshell, variable assignments do not remain in effect after the subshell completes. `{}' @@ -672,7 +795,7 @@ the list may be redirected to a single stream. Placing a list of commands between curly braces causes the list to be executed in the current shell context. No subshell is created. - The semicolon following LIST is required. + The semicolon (or newline) following LIST is required. In addition to the creation of a subshell, there is a subtle difference between these two constructs due to historical reasons. The @@ -685,7 +808,7 @@ LIST by whitespace. LIST. -File: bashref.info, Node: Shell Functions, Next: Shell Parameters, Prev: Command Grouping, Up: Basic Shell Features +File: bashref.info, Node: Shell Functions, Next: Shell Parameters, Prev: Shell Commands, Up: Basic Shell Features Shell Functions =============== @@ -699,10 +822,11 @@ context; no new process is created to interpret them. [ `function' ] NAME () { COMMAND-LIST; } This defines a shell function named NAME. The reserved word -`function' is optional. The BODY of the function is the COMMAND-LIST -between { and }. This list is executed whenever NAME is specified as -the name of a command. The exit status of a function is the exit -status of the last command executed in the body. +`function' is optional. If the `function' reserved word is supplied, +the parentheses are optional. The BODY of the function is the +COMMAND-LIST between { and }. This list is executed whenever NAME is +specified as the name of a command. The exit status of a function is +the exit status of the last command executed in the body. When a function is executed, the arguments to the function become the positional parameters during its execution (*note Positional @@ -714,8 +838,10 @@ parameter `0' is unchanged. function completes and execution resumes with the next command after the function call. When a function completes, the values of the positional parameters and the special parameter `#' are restored to the -values they had prior to function execution. If a numeric argument is -given to `return', that is the function return status. +values they had prior to the function's execution. If a numeric +argument is given to `return', that is the function's return status; +otherwise the functions's return status is the exit status of the last +command executed before the `return'. Variables local to the function may be declared with the `local' builtin. These variables are visible only to the function and the @@ -749,12 +875,12 @@ the `unset' builtin command. If VALUE is not given, the variable is assigned the null string. All VALUEs undergo tilde expansion, parameter and variable expansion, command substitution, arithmetic expansion, and quote removal (detailed -below). If the variable has its `-i' attribute set (see the +below). If the variable has its `integer' attribute set (see the description of the `declare' builtin in *Note Bash Builtins::), then -VALUE is subject to arithmetic expansion even if the `$((...))' syntax -does not appear (*note Arithmetic Expansion::.). Word splitting is not -performed, with the exception of `"$@"' as explained below. Filename -expansion is not performed. +VALUE is subject to arithmetic expansion even if the `$((...))' +expansion is not used (*note Arithmetic Expansion::.). Word splitting +is not performed, with the exception of `"$@"' as explained below. +Filename expansion is not performed. File: bashref.info, Node: Positional Parameters, Next: Special Parameters, Up: Shell Parameters @@ -765,10 +891,10 @@ Positional Parameters A POSITIONAL PARAMETER is a parameter denoted by one or more digits, other than the single digit `0'. Positional parameters are assigned from the shell's arguments when it is invoked, and may be reassigned -using the `set' builtin command. Positional parameters may not be -assigned to with assignment statements. The positional parameters are -temporarily replaced when a shell function is executed (*note Shell -Functions::.). +using the `set' builtin command. Positional parameter `N' may be +referenced as `${N}'. Positional parameters may not be assigned to +with assignment statements. The positional parameters are temporarily +replaced when a shell function is executed (*note Shell Functions::.). When a positional parameter consisting of more than a single digit is expanded, it must be enclosed in braces. @@ -794,7 +920,7 @@ only be referenced; assignment to them is not allowed. `@' Expands to the positional parameters, starting from one. When the - expansion occurs within double quotes, each parameter expands as a + expansion occurs within double quotes, each parameter expands to a separate word. That is, `"$@"' is equivalent to `"$1" "$2" ...'. When there are no positional parameters, `"$@"' and `$@' expand to nothing (i.e., they are removed). @@ -813,7 +939,7 @@ only be referenced; assignment to them is not allowed. `$' Expands to the process ID of the shell. In a `()' subshell, it - expands to the process ID of the current shell, not the subshell. + expands to the process ID of the invoking shell, not the subshell. `!' Expands to the process ID of the most recently executed background @@ -821,17 +947,18 @@ only be referenced; assignment to them is not allowed. `0' Expands to the name of the shell or shell script. This is set at - shell initialization. If Bash is invoked with a file of commands, - `$0' is set to the name of that file. If Bash is started with the - `-c' option, then `$0' is set to the first argument after the - string to be executed, if one is present. Otherwise, it is set to - the filename used to invoke Bash, as given by argument zero. + shell initialization. If Bash is invoked with a file of commands + (*note Shell Scripts::.), `$0' is set to the name of that file. + If Bash is started with the `-c' option (*note Invoking Bash::.), + then `$0' is set to the first argument after the string to be + executed, if one is present. Otherwise, it is set to the filename + used to invoke Bash, as given by argument zero. `_' At shell startup, set to the absolute filename of the shell or shell script being executed as passed in the argument list. Subsequently, expands to the last argument to the previous command, - after expansion. Also set to the full filename of each command + 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. @@ -859,8 +986,11 @@ into `token's. There are seven kinds of expansion performed: * 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 @@ -869,11 +999,6 @@ into `token's. There are seven kinds of expansion performed: * Quote Removal:: How and when quote characters are removed from words. - Brace expansion, tilde expansion, and arithmetic expansion are -described in other sections. For brace expansion, see *Note Brace -Expansion::; for tilde expansion, see *Note Tilde Expansion::; and for -arithmetic expansion, see *Note Arithmetic Expansion::. - The order of expansions is: brace expansion, tilde expansion, parameter, variable, and arithmetic expansion and command substitution (done in a left-to-right fashion), word splitting, and filename @@ -881,7 +1006,7 @@ expansion. On systems that can support it, there is an additional expansion available: PROCESS SUBSTITUTION. This is performed at the same time as -parameter, variable, and arithemtic expansion and command substitution. +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 @@ -893,7 +1018,106 @@ expansions of `"$@"' (*note Special Parameters::.) and `"${NAME[@]}"' performed. -File: bashref.info, Node: Shell Parameter Expansion, Next: Command Substitution, Up: Shell Expansions +File: bashref.info, Node: Brace Expansion, Next: Tilde Expansion, Up: Shell Expansions + +Brace Expansion +--------------- + + Brace expansion is a mechanism by which arbitrary strings may be +generated. This mechanism is similar to FILENAME EXPANSION (*note +Filename Expansion::.), but the file names generated need not exist. +Patterns to be brace expanded take the form of an optional PREAMBLE, +followed by a series of comma-separated strings between a pair of +braces, followed by an optional POSTSCRIPT. The preamble is prepended +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, + bash$ echo a{d,c,b}e + ade ace abe + + Brace expansion is performed before any other expansions, and any +characters special to other expansions are preserved in the result. It +is strictly textual. Bash does not apply any syntactic interpretation +to the context of the expansion or the text between the braces. + + A correctly-formed brace expansion must contain unquoted opening and +closing braces, and at least one unquoted comma. Any incorrectly +formed brace expansion is left unchanged. + + This construct is typically used as shorthand when the common prefix +of the strings to be generated is longer than in the above example: + mkdir /usr/local/src/bash/{old,new,dist,bugs} + or + chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}} + + +File: bashref.info, Node: Tilde Expansion, Next: Shell Parameter Expansion, Prev: Brace Expansion, Up: Shell Expansions + +Tilde Expansion +--------------- + + If a word begins with an unquoted tilde character (`~'), all of the +characters up to the first unquoted slash (or all characters, if there +is no unquoted slash) are considered a 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 LOGIN NAME. +If this login name is the null string, the tilde is replaced with the +value of the `HOME' shell variable. If `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 `~+', the value of the shell variable `PWD' +replaces the tilde-prefix. If the tilde-prefix is `~-', the value of +the shell variable `OLDPWD', if it is set, is substituted. + + If the characters following the tilde in the tilde-prefix consist of +a number N, 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 `dirs' builtin invoked with the characters +following tilde in the tilde-prefix as an argument (*note The Directory +Stack::.). If the tilde-prefix, sans the tilde, consists of a number +without a leading `+' or `-', `+' 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 `:' or `='. In these cases, tilde expansion is +also performed. Consequently, one may use file names with tildes in +assignments to `PATH', `MAILPATH', and `CDPATH', and the shell assigns +the expanded value. + + The following table shows how Bash treats unquoted tilde-prefixes: + +`~' + The value of `$HOME' + +`~/foo' + `$HOME/foo' + +`~fred/foo' + The subdirectory `foo' of the home directory of the user `fred' + +`~+/foo' + `$PWD/foo' + +`~-/foo' + `${OLDPWD-'~-'}/foo' + +`~N' + The string that would be displayed by `dirs +N' + +`~+N' + The string that would be displayed by `dirs +N' + +`~-N' + The string that would be displayed by `dirs -N' + + +File: bashref.info, Node: Shell Parameter Expansion, Next: Command Substitution, Prev: Tilde Expansion, Up: Shell Expansions Shell Parameter Expansion ------------------------- @@ -904,6 +1128,11 @@ 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 `}' 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 ${PARAMETER}. The value of PARAMETER is substituted. The braces are required when PARAMETER is a positional parameter with more than one digit, or when PARAMETER is @@ -945,11 +1174,11 @@ parameter that is unset. `${PARAMETER:OFFSET}' `${PARAMETER:OFFSET:LENGTH}' - Expands to up to LENGTH characters of PARAMETER, starting at - OFFSET. If LENGTH is omitted, expands to the substring of - PARAMETER, starting at the character specified by OFFSET. LENGTH - and OFFSET are arithmetic expressions (*note Arithmetic - Evaluation::.). This is referred to as Substring Expansion. + Expands to up to LENGTH characters of PARAMETER, starting at the + character specified by OFFSET. If LENGTH is omitted, expands to + the substring of PARAMETER, starting at the character specified by + OFFSET. LENGTH and OFFSET are arithmetic expressions (*note Shell + Arithmetic::.). This is referred to as Substring Expansion. LENGTH must evaluate to a number greater than or equal to zero. If OFFSET evaluates to a number less than zero, the value is used @@ -957,43 +1186,44 @@ parameter that is unset. is `@', the result is LENGTH positional parameters beginning at OFFSET. If PARAMETER is an array name indexed by `@' or `*', the result is the LENGTH members of the array beginning with - ${PARAMETER[OFFSET]}. Substring indexing is zero-based unless the - positional parameters are used, in which case the indexing starts - at 1. + `${PARAMETER[OFFSET]}'. Substring indexing is zero-based unless + the positional parameters are used, in which case the indexing + starts at 1. `${#PARAMETER}' - The length in characters of the value of PARAMETER is substituted. - If PARAMETER is `*' or `@', the length substituted is the number - of positional parameters. If PARAMETER is an array name - subscripted by `*' or `@', the length substituted is the number of - elements in the array. + The length in characters of the expanded value of PARAMETER is + substituted. If PARAMETER is `*' or `@', the value substituted is + the number of positional parameters. If PARAMETER is an array + name subscripted by `*' or `@', the value substituted is the + number of elements in the array. `${PARAMETER#WORD}' `${PARAMETER##WORD}' The WORD is expanded to produce a pattern just as in filename expansion (*note Filename Expansion::.). If the pattern matches - the beginning of the value of PARAMETER, then the expansion is the - value of PARAMETER with the shortest matching pattern (the `#' - case) or the longest matching pattern (the `##' case) deleted. If - PARAMETER is `@' or `*', the pattern removal operation is applied - to each positional parameter in turn, and the expansion is the - resultant list. If PARAMETER is an array variable subscripted with - `@' or `*', the pattern removal operation is applied to each - member of the array in turn, and the expansion is the resultant - list. + the beginning of the expanded value of PARAMETER, then the result + of the expansion is the expanded value of PARAMETER with the + shortest matching pattern (the `#' case) or the longest matching + pattern (the `##' case) deleted. If PARAMETER is `@' or `*', the + pattern removal operation is applied to each positional parameter + in turn, and the expansion is the resultant list. If PARAMETER is + an array variable subscripted with `@' or `*', the pattern removal + operation is applied to each member of the array in turn, and the + expansion is the resultant list. `${PARAMETER%WORD}' `${PARAMETER%%WORD}' The WORD is expanded to produce a pattern just as in filename - expansion. If the pattern matches a trailing portion of the value - of PARAMETER, then the expansion is the value of PARAMETER with - the shortest matching pattern (the `%' case) or the longest - matching pattern (the `%%' case) deleted. If PARAMETER is `@' or - `*', the pattern removal operation is applied to each positional - parameter in turn, and the expansion is the resultant list. If - PARAMETER is an array variable subscripted with `@' or `*', the - pattern removal operation is applied to each member of the array - in turn, and the expansion is the resultant list. + expansion. If the pattern matches a trailing portion of the + expanded value of PARAMETER, then the result of the expansion is + the value of PARAMETER with the shortest matching pattern (the `%' + case) or the longest matching pattern (the `%%' case) deleted. If + PARAMETER is `@' or `*', the pattern removal operation is applied + to each positional parameter in turn, and the expansion is the + resultant list. If PARAMETER is an array variable subscripted + with `@' or `*', the pattern removal operation is applied to each + member of the array in turn, and the expansion is the resultant + list. `${PARAMETER/PATTERN/STRING}' `${PARAMETER//PATTERN/STRING}' @@ -1013,7 +1243,7 @@ parameter that is unset. is the resultant list. -File: bashref.info, Node: Command Substitution, Next: Process Substitution, Prev: Shell Parameter Expansion, Up: Shell Expansions +File: bashref.info, Node: Command Substitution, Next: Arithmetic Expansion, Prev: Shell Parameter Expansion, Up: Shell Expansions Command Substitution -------------------- @@ -1027,21 +1257,47 @@ or Bash performs the expansion by executing COMMAND and replacing the command substitution with the standard output of the command, with any -trailing newlines deleted. +trailing newlines deleted. Embedded newlines are not deleted, but they +may be removed during word splitting. The command substitution `$(cat +FILE)' can be replaced by the equivalent but faster `$(< FILE)'. When the old-style backquote form of substitution is used, backslash retains its literal meaning except when followed by `$', ``', or `\'. -When using the `$(COMMAND)' form, all characters between the -parentheses make up the command; none are treated specially. +The first backquote not preceded by a backslash terminates the command +substitution. When using the `$(COMMAND)' form, all characters between +the parentheses make up the command; none are treated specially. - Command substitutions may be nested. To nest when using the old -form, escape the inner backquotes with backslashes. + 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. -File: bashref.info, Node: Process Substitution, Next: Word Splitting, Prev: Command Substitution, Up: Shell Expansions +File: bashref.info, Node: Arithmetic Expansion, Next: Process Substitution, Prev: Command Substitution, Up: Shell Expansions + +Arithmetic Expansion +-------------------- + + Arithmetic expansion allows the evaluation of an arithmetic +expression and the substitution of the result. The format for +arithmetic expansion is: + + $(( EXPRESSION )) + + The expression is treated as if it were within double quotes, but a +double quote inside the parentheses is not treated specially. All +tokens in the expression undergo parameter expansion, command +substitution, and quote removal. Arithmetic substitutions may be +nested. + + The evaluation is performed according to the rules listed below +(*note Shell Arithmetic::.). If the expression is invalid, Bash prints +a message indicating failure to the standard error and no substitution +occurs. + + +File: bashref.info, Node: Process Substitution, Next: Word Splitting, Prev: Arithmetic Expansion, Up: Shell Expansions Process Substitution -------------------- @@ -1061,9 +1317,9 @@ to the current command as the result of the expansion. If the LIST. If the `<(LIST)' form is used, the file passed as an argument should be read to obtain the output of LIST. - On systems that support it, process substitution is performed -simultaneously with parameter and variable expansion, command -substitution, and arithmetic expansion. + When available, process substitution is performed simultaneously with +parameter and variable expansion, command substitution, and arithmetic +expansion. File: bashref.info, Node: Word Splitting, Next: Filename Expansion, Prev: Process Substitution, Up: Shell Expansions @@ -1101,32 +1357,51 @@ File: bashref.info, Node: Filename Expansion, Next: Quote Removal, Prev: Word Filename Expansion ------------------ +* Menu: + +* Pattern Matching:: How the shell matches patterns. + After word splitting, unless the `-f' option has been set (*note The -Set Builtin::.), Bash scans each word for the characters `*', `?', and -`['. If one of these characters appears, then the word is regarded as -a PATTERN, and replaced with an alphabetically sorted list of file +Set Builtin::.), Bash scans each word for the characters `*', `?', `(', +and `['. If one of these characters appears, then the word is regarded +as a PATTERN, and replaced with an alphabetically sorted list of file names matching the pattern. If no matching file names are found, and -the shell option `nullglob' is disabled, the word is left unchanged. If -the option is set, and no matches are found, the word is removed. When -a pattern is used for filename generation, the character `.' at the -start of a filename or immediately following a slash must be matched -explicitly, unless the shell option `dotglob' is set. The slash -character must always be matched explicitly. In other cases, the `.' -character is not treated specially. See the description of `shopt' in -*Note Bash Builtins::, for a description of the `nullglob' and -`dotglob' options. +the shell option `nullglob' is disabled, the word is left unchanged. +If the `nullglob' option is set, and no matches are found, the word is +removed. If the shell option `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 `.' at +the start of a filename or immediately following a slash must be +matched explicitly, unless the shell option `dotglob' is set. When +matching a file name, the slash character must always be matched +explicitly. In other cases, the `.' character is not treated specially. + + See the description of `shopt' in *Note Bash Builtins::, for a +description of the `nocaseglob', `nullglob', and `dotglob' options. The `GLOBIGNORE' shell variable may be used to restrict the set of -filenames matching a PATTERN. If `GLOBIGNORE' is set, each matching +filenames matching a pattern. If `GLOBIGNORE' is set, each matching filename that also matches one of the patterns in `GLOBIGNORE' is removed from the list of matches. The filenames `.' and `..' are -always ignored, even when `GLOBIGNORE'. is set. However, setting +always ignored, even when `GLOBIGNORE' is set. However, setting `GLOBIGNORE' has the effect of enabling the `dotglob' shell option, so all other filenames beginning with a `.' will match. To get the old behavior of ignoring filenames beginning with a `.', make `.*' one of the patterns in `GLOBIGNORE'. The `dotglob' option is disabled when `GLOBIGNORE' is unset. + +File: bashref.info, Node: Pattern Matching, Up: Filename Expansion + +Pattern Matching +................ + + 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. The special pattern characters must be +quoted if they are to be matched literally. + The special pattern characters have the following meanings: `*' Matches any string, including the null string. @@ -1143,6 +1418,43 @@ the patterns in `GLOBIGNORE'. The `dotglob' option is disabled when the first or last character in the set. A `]' may be matched by including it as the first character in the set. + Within `[' and `]', CHARACTER CLASSES can be specified using the + syntax `[:'CLASS`:]', where CLASS is one of the following classes + defined in the POSIX.2 standard: + alnum alpha ascii blank cntrl digit graph lower + print punct space upper xdigit + + A character class matches any character belonging to that class. + + Within `[' and `]', an EQUIVALENCE CLASS can be specified using + the syntax `[='C`=]', which matches all characters with the same + collation weight (as defined by the current locale) as the + character C. + + Within `[' and `]', the syntax `[.'SYMBOL`.]' matches the + collating symbol SYMBOL. + + If the `extglob' shell option is enabled using the `shopt' builtin, +several extended pattern matching operators are recognized. In the +following description, a PATTERN-LIST is a list of one or more patterns +separated by a `|'. Composite patterns may be formed using one or more +of the following sub-patterns: + +`?(PATTERN-LIST)' + Matches zero or one occurrence of the given patterns. + +`*(PATTERN-LIST)' + Matches zero or more occurrences of the given patterns. + +`+(PATTERN-LIST)' + Matches one or more occurrences of the given patterns. + +`@(PATTERN-LIST)' + Matches exactly one of the given patterns. + +`!(PATTERN-LIST)' + Matches anything except one of the given patterns. + File: bashref.info, Node: Quote Removal, Prev: Filename Expansion, Up: Shell Expansions @@ -1172,11 +1484,11 @@ the redirection refers to the standard input (file descriptor 0). If the first character of the redirection operator is `>', the redirection refers to the standard output (file descriptor 1). - The word that follows the redirection operator in the following -descriptions is subjected to brace expansion, tilde expansion, -parameter expansion, command substitution, arithmetic expansion, quote -removal, and filename expansion. If it expands to more than one word, -Bash reports an error. + 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, and filename expansion. If it expands to +more than one word, Bash reports an error. Note that the order of redirections is significant. For example, the command @@ -1190,6 +1502,8 @@ directs only the standard output to file DIRLIST, because the standard error was duplicated as standard output before the standard output was redirected to DIRLIST. + A failure to open or create a file causes the redirection to fail. + Redirecting Input ----------------- @@ -1212,12 +1526,12 @@ to zero size. The general format for redirecting output is: [n]>[|]WORD - If the redirection operator is `>', and the `-C' option to the `set' -builtin has been enabled, the redirection will fail if the filename -whose name results from the expansion of WORD exists. If the -redirection operator is `>|', then the value of the `-C' option to the -`set' builtin command is not tested, and the redirection is attempted -even if the file named by WORD exists. + If the redirection operator is `>', and the `noclobber' option to +the `set' builtin has been enabled, the redirection will fail if the +filename whose name results from the expansion of WORD exists and is a +regular file. If the redirection operator is `>|', or the redirection +operator is `>' and the `noclobber' option is not enabled, the +redirection is attempted even if the file named by WORD exists. Appending Redirected Output --------------------------- @@ -1264,11 +1578,11 @@ as the standard input for a command. No parameter expansion, command substitution, filename expansion, or arithmetic expansion is performed on WORD. If any characters in WORD are quoted, the DELIMITER is the result of quote removal on WORD, and -the lines in the here-document are not expanded. Otherwise, all lines -of the here-document are subjected to parameter expansion, command -substitution, and arithmetic expansion. In the latter case, the pair -`\newline' is ignored, and `\' must be used to quote the characters -`\', `$', and ``'. +the lines in the here-document are not expanded. If WORD is unquoted, +all lines of the here-document are subjected to parameter expansion, +command substitution, and arithmetic expansion. In the latter case, +the pair `\newline' is ignored, and `\' must be used to quote the +characters `\', `$', and ``'. If the redirection operator is `<<-', then all leading tab characters are stripped from input lines and the line containing @@ -1283,18 +1597,20 @@ Duplicating File Descriptors is used to duplicate input file descriptors. If WORD expands to one or more digits, the file descriptor denoted by `n' is made to be a copy of -that file descriptor. If WORD evaluates to `-', file descriptor `n' is -closed. If `n' is not specified, the standard input (file descriptor -0) is used. +that file descriptor. If the digits in WORD do not specify a file +descriptor open for input, a redirection error occurs. If WORD +evaluates to `-', file descriptor `n' is closed. If `n' is not +specified, the standard input (file descriptor 0) is used. The operator [n]>&WORD is used similarly to duplicate output file descriptors. If `n' is not -specified, the standard output (file descriptor 1) is used. As a -special case, if `n' is omitted, and WORD does not expand to one or -more digits, the standard output and standard error are redirected as -described previously. +specified, the standard output (file descriptor 1) is used. If the +digits in WORD do not specify a file descriptor open for output, a +redirection error occurs. As a special case, if `n' is omitted, and +WORD does not expand to one or more digits, the standard output and +standard error are redirected as described previously. Opening File Descriptors for Reading and Writing ------------------------------------------------ @@ -1314,8 +1630,15 @@ 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 @@ -1325,7 +1648,50 @@ Executing Commands receives a signal. -File: bashref.info, Node: Command Search and Execution, Next: Environment, Up: Executing Commands +File: bashref.info, Node: Simple Command Expansion, Next: Command Search and Execution, Up: Executing Commands + +Simple Command Expansion +------------------------ + + When a simple command is executed, the shell performs the following +expansions, assignments, and redirections, from left to right. + + 1. The words that the parser has marked as variable assignments (those + preceding the command name) and redirections are saved for later + processing. + + 2. The words that are not variable assignments or redirections are + expanded (*note 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. + + 3. Redirections are performed as described above (*note + Redirections::.). + + 4. The text after the `=' in each variable assignment undergoes tilde + expansion, parameter expansion, command substitution, arithmetic + expansion, and quote removal before being assigned to the variable. + + 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. + + +File: bashref.info, Node: Command Search and Execution, Next: Command Execution Environment, Prev: Simple Command Expansion, Up: Executing Commands Command Search and Execution ---------------------------- @@ -1345,24 +1711,95 @@ taken. 3. If the name is neither a shell function nor a builtin, and contains no slashes, Bash searches each element of `$PATH' for a directory containing an executable file by that name. Bash uses a - hash table to remember the full filenames of executable files (see - the description of `hash' in *Note Bourne Shell Builtins::) to - avoid multiple `PATH' searches. A full search of the directories + hash table to remember the full pathnames of executable files to + avoid multiple `PATH' searches (see the description of `hash' in + *Note Bourne Shell Builtins::). A full search of the directories in `$PATH' is performed only if the command is not found in the hash table. If the search is unsuccessful, the shell prints an - error message and returns a nonzero exit status. + error message and returns an exit status of 127. 4. If the search is successful, or if the command name contains one - or more slashes, the shell executes the named program. Argument 0 - is set to the name given, and the remaining arguments to the - command are set to the arguments supplied, if any. + 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. 5. If this execution fails because the file is not in executable - format, and the file is not a directory, it is assumed to be SHELL - SCRIPT (*note Shell Scripts::.). + format, and the file is not a directory, it is assumed to be a + SHELL SCRIPT and the shell executes it as described in *Note Shell + Scripts::. + + 6. If the command was not begun asynchronously, the shell waits for + the command to complete and collects its exit status. + -File: bashref.info, Node: Environment, Next: Exit Status, Prev: Command Search and Execution, Up: Executing Commands +File: bashref.info, Node: Command Execution Environment, Next: Environment, Prev: Command Search and Execution, Up: Executing Commands + +Command Execution Environment +----------------------------- + + The shell has an EXECUTION ENVIRONMENT, which consists of the +following: + + * open files inherited by the shell at invocation, as modified by + redirections supplied to the `exec' builtin + + * the current working directory as set by `cd', `pushd', or `popd', + or inherited by the shell at invocation + + * the file creation mode mask as set by `umask' or inherited from + the shell's parent + + * current traps set by `trap' + + * shell parameters that are set by variable assignment or with `set' + or inherited from the shell's parent in the environment + + * shell functions defined during execution or inherited from the + shell's parent in the environment + + * options enabled at invocation (either by default or with + command-line arguments) or by `set' + + * options enabled by `shopt' + + * shell aliases defined with `alias' (*note Aliases::.) + + * various process IDs, including those of background jobs (*note + Lists::.), the value of `$$', and the value of `$PPID' + + 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. + + * the shell's open files, plus any modifications and additions + specified by redirections to the command + + * the current working directory + + * the file creation mode mask + + * shell variables marked for export, along with variables exported + for the command, passed in the environment (*note Environment::.) + + * traps caught by the shell are reset to the values inherited from + the shell's parent, and traps ignored by the shell are ignored + + 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. + + +File: bashref.info, Node: Environment, Next: Exit Status, Prev: Command Execution Environment, Up: Executing Commands Environment ----------- @@ -1380,15 +1817,16 @@ and deleted from the environment. If the value of a parameter in the environment is modified, the new value becomes part of the environment, replacing the old. The environment inherited by any executed command consists of the shell's initial environment, whose values may be -modified in the shell, less any pairs removed by the `unset' command, -plus any additions via the `export' and `declare -x' commands. +modified in the shell, less any pairs removed by the `unset' and +`export -n' commands, plus any additions via the `export' and `declare +-x' commands. The environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments, as described in *Note Shell Parameters::. These assignment statements affect only the environment seen by that command. - If the `-k' flag is set (*note The Set Builtin::., then all + If the `-k' option is set (*note The Set Builtin::.), then all parameter assignments are placed in the environment for a command, not just those that precede the command name. @@ -1402,24 +1840,28 @@ File: bashref.info, Node: Exit Status, Next: Signals, Prev: Environment, Up: Exit Status ----------- - For the purposes of the shell, a command which exits with a zero -exit status has succeeded. A non-zero exit status indicates failure. -This seemingly counter-intuitive scheme is used so there is one -well-defined way to indicate success and a variety of ways to indicate -various failure modes. When a command terminates on a fatal signal -whose number is N, Bash uses the value 128+N as the exit status. + 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 N, Bash uses the value 128+N as the exit status. If a command is not found, the child process created to execute it returns a status of 127. If a command is found but is not executable, the return status is 126. + 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 (*note Conditional Constructs::.) and some of the list constructs (*note Lists::.). All of the Bash builtins return an exit status of zero if they succeed and a non-zero status on failure, so they may be used by the -conditional and list constructs. +conditional and list constructs. All builtins return an exit status of +2 to indicate incorrect usage. File: bashref.info, Node: Signals, Prev: Exit Status, Up: Executing Commands @@ -1427,26 +1869,40 @@ File: bashref.info, Node: Signals, Prev: Exit Status, Up: Executing Commands Signals ------- - When Bash is interactive, it ignores `SIGTERM' (so that `kill 0' -does not kill an interactive shell), and `SIGINT' is caught and handled -(so that the `wait' builtin is interruptible). When Bash receives a -`SIGINT', it breaks out of any executing loops. In all cases, Bash -ignores `SIGQUIT'. If job control is in effect (*note Job Control::.), -Bash ignores `SIGTTIN', `SIGTTOU', and `SIGTSTP'. + When Bash is interactive, in the absence of any traps, it ignores +`SIGTERM' (so that `kill 0' does not kill an interactive shell), and +`SIGINT' is caught and handled (so that the `wait' builtin is +interruptible). When Bash receives a `SIGINT', it breaks out of any +executing loops. In all cases, Bash ignores `SIGQUIT'. If job control +is in effect (*note Job Control::.), Bash ignores `SIGTTIN', `SIGTTOU', +and `SIGTSTP'. - Synchronous jobs started by Bash have signals set to the values + 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, background jobs (commands terminated with `&') ignore `SIGINT' -and `SIGQUIT'. Commands run as a result of command substitution ignore -the keyboard-generated job control signals `SIGTTIN', `SIGTTOU', and +effect, asynchronous commands ignore `SIGINT' and `SIGQUIT' as well. +Commands run as a result of command substitution ignore the +keyboard-generated job control signals `SIGTTIN', `SIGTTOU', and `SIGTSTP'. The shell exits by default upon receipt of a `SIGHUP'. Before -exiting, it resends the `SIGHUP' to all jobs, running or stopped. To -prevent the shell from sending the `SIGHUP' signal to a particular job, -remove it from the jobs table with the `disown' builtin (*note Job -Control Builtins::.) or use `disown -h' to mark it to not receive -`SIGHUP'. +exiting, it resends the `SIGHUP' to all jobs, running or stopped. +Stopped jobs are sent `SIGCONT' to ensure that they receive the +`SIGHUP'. To prevent the shell from sending the `SIGHUP' signal to a +particular job, it should be removed from the jobs table with the +`disown' builtin (*note Job Control Builtins::.) or marked to not +receive `SIGHUP' using `disown -h'. + + If the `huponexit' shell option has been set with `shopt' (*note +Bash Builtins::.), Bash sends a `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 `wait' builtin, the reception of a signal for which a +trap has been set will cause the `wait' builtin to return immediately +with an exit status greater than 128, immediately after which the trap +is executed. File: bashref.info, Node: Shell Scripts, Prev: Executing Commands, Up: Basic Shell Features @@ -1475,7 +1931,9 @@ is equivalent to executing if `filename' is an executable shell script. This subshell reinitializes itself, so that the effect is as if a new shell had been -invoked to interpret the script. +invoked to interpret the script, with the exception that the locations +of commands remembered by the parent (see the description of `hash' in +*Note Bourne Shell Builtins::) are retained by the child. Most versions of Unix make this a part of the kernel's command execution mechanism. If the first line of a script begins with the two @@ -1489,7 +1947,7 @@ versions of Unix limit the interpreter name and argument to a maximum of 32 characters. -File: bashref.info, Node: Bourne Shell Features, Next: Csh Features, Prev: Basic Shell Features, Up: Top +File: bashref.info, Node: Bourne Shell Features, Next: Bash Features, Prev: Basic Shell Features, Up: Top Bourne Shell Style Features *************************** @@ -1505,7 +1963,8 @@ Bourne Shell Style Features This section briefly summarizes things which Bash inherits from the Bourne Shell: builtins, variables, and other features. It also lists -the significant differences between Bash and the Bourne Shell. +the significant differences between Bash and the Bourne Shell. Many of +the builtins have been extended by POSIX or Bash. File: bashref.info, Node: Bourne Shell Builtins, Next: Bourne Shell Variables, Up: Bourne Shell Features @@ -1520,16 +1979,24 @@ standard. `:' : [ARGUMENTS] Do nothing beyond expanding ARGUMENTS and performing redirections. + The return status is zero. `.' . FILENAME Read and execute commands from the FILENAME argument in the - current shell context. + current shell context. If FILENAME does not contain a slash, the + `$PATH' variable is used to find FILENAME. The current directory + is searched if FILENAME is not found in `$PATH'. The return + status is the exit status of the last command executed, or zero if + no commands are executed. If FILENAME is not found, or cannot be + read, the return status is non-zero. `break' break [N] Exit from a `for', `while', `until', or `select' loop. If N is - supplied, the Nth enclosing loop is exited. + supplied, the Nth enclosing loop is exited. N must be greater + than or equal to 1. The return status is zero unless N is not + greater than or equal to 1. `cd' cd [-LP] [DIRECTORY] @@ -1537,41 +2004,55 @@ standard. is not given, the value of the `HOME' shell variable is used. If the shell variable `CDPATH' exists, it is used as a search path. If DIRECTORY begins with a slash, `CDPATH' is not used. The `-P' - option means to not follow symbolic links; symlinks are followed - by default or with the `-L' option. + option means to not follow symbolic links; symbolic links are + followed by default or with the `-L' option. If DIRECTORY is `-', + it is equivalent to `$OLDPWD'. The return status is zero if the + directory is successfully changed, non-zero otherwise. `continue' continue [N] Resume the next iteration of an enclosing `for', `while', `until', or `select' loop. If N is supplied, the execution of the Nth - enclosing loop is resumed. + enclosing loop is resumed. N must be greater than or equal to 1. + The return status is zero unless N is not greater than or equal to + 1. `eval' eval [ARGUMENTS] The arguments are concatenated together into a single command, - which is then read and executed. + which is then read and executed, and its exit status returned as + the exit status of `eval'. If there are no arguments or only + empty arguments, the return status is zero. `exec' - exec [-cl] [-a NAME] [COMMAND] [ARGUMENTS] - If COMMAND is supplied, it replaces the shell. If the `-l' option - is supplied, the shell places a dash in the zeroth arg passed to - COMMAND. This is what the `login' program does. The `-c' option - causes COMMAND to be executed with an empty environment. If `-a' - is supplied, the shell passes NAME as the zeroth argument to - COMMAND. If no COMMAND is specified, redirections may be used to - affect the current shell environment. + exec [-cl] [-a NAME] [COMMAND [ARGUMENTS]] + If COMMAND is supplied, it replaces the shell without creating a + new process. If the `-l' option is supplied, the shell places a + dash in the zeroth arg passed to COMMAND. This is what the + `login' program does. The `-c' option causes COMMAND to be + executed with an empty environment. If `-a' is supplied, the + shell passes NAME as the zeroth argument to COMMAND. If no + COMMAND is specified, redirections may be used to affect the + current shell environment. If there are no redirection errors, the + return status is zero; otherwise the return status is non-zero. `exit' exit [N] Exit the shell, returning a status of N to the shell's parent. + Any trap on `EXIT' is executed before the shell terminates. `export' export [-fn] [-p] [NAME[=VALUE]] Mark each NAME to be passed to child processes in the environment. If the `-f' option is supplied, the NAMEs refer to shell - functions. The `-n' option means to no longer mark each NAME for - export. If no NAMES are supplied, or if the `-p' option is given, - a list of exported names is displayed. + functions; otherwise the names refer to shell variables. The `-n' + option means to no longer mark each NAME for export. If no NAMES + are supplied, or if the `-p' option is given, a list of exported + names is displayed. The `-p' option displays output in a form + that may be reused as input. The return status is zero unless an + invalid option is supplied, one of the names is not a valid shell + variable name, or `-f' is supplied with a name that is not a shell + function. `getopts' getopts OPTSTRING NAME [ARGS] @@ -1589,14 +2070,21 @@ standard. reset between multiple calls to `getopts' within the same shell invocation if a new set of parameters is to be used. + When the end of options is encountered, `getopts' exits with a + return value greater than zero. `OPTIND' is set to the index of + the first non-option argument, and `name' is set to `?'. + + `getopts' normally parses the positional parameters, but if more + arguments are given in ARGS, `getopts' parses those instead. + `getopts' can report errors in two ways. If the first character of OPTSTRING is a colon, SILENT error reporting is used. In normal - operation diagnostic messages are printed when illegal options or + operation diagnostic messages are printed when invalid options or missing option arguments are encountered. If the variable `OPTERR' - is set to 0, no error message will be displayed, even if the first + is set to 0, no error messages will be displayed, even if the first character of `optstring' is not a colon. - If an illegal option is seen, `getopts' places `?' into NAME and, + If an invalid option is seen, `getopts' places `?' into NAME and, if not silent, prints an error message and unsets `OPTARG'. If `getopts' is silent, the option character found is placed in `OPTARG' and no diagnostic message is printed. @@ -1607,57 +2095,125 @@ standard. colon (`:') is placed in NAME and `OPTARG' is set to the option character found. - `getopts' normally parses the positional parameters, but if more - arguments are given in ARGS, `getopts' parses those instead. - `hash' hash [-r] [-p FILENAME] [NAME] - Remember the full filenames of commands specified as arguments, so - they need not be searched for on subsequent invocations. The - commands are found by searching through the directories listed in - `$PATH'. The `-p' option inhibits the path search, and FILENAME - is used as the location of NAME. The `-r' option causes the shell - to forget all remembered locations. If no arguments are given, - information about remembered commands is printed. + Remember the full pathnames of commands specified as NAME + arguments, so they need not be searched for on subsequent + invocations. The commands are found by searching through the + directories listed in `$PATH'. The `-p' option inhibits the path + search, and FILENAME is used as the location of NAME. The `-r' + option causes the shell to forget all remembered locations. If no + arguments are given, information about remembered commands is + printed. The return status is zero unless a NAME is not found or + an invalid option is supplied. `pwd' pwd [-LP] Print the current working directory. If the `-P' option is supplied, the path printed will not contain symbolic links. If the `-L' option is supplied, the path printed may contain symbolic - links. + 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. `readonly' readonly [-apf] [NAME] ... - Mark each NAME as unchangable. The values of these names may not - be changed by subsequent assignment. If the `-f' option is - supplied, each NAME refers to a shell function. The `-a' option - means each NAME refers to an array variable. If no NAME arguments - are given, or if the `-p' option is supplied, a list of all - readonly names is printed. + Mark each NAME as readonly. The values of these names may not be + changed by subsequent assignment. If the `-f' option is supplied, + each NAME refers to a shell function. The `-a' option means each + NAME refers to an array variable. If no NAME arguments are given, + or if the `-p' option is supplied, a list of all readonly names is + printed. The `-p' option causes output to be displayed in a + format that may be reused as input. The return status is zero + unless an invalid option is supplied, one of the NAME arguments is + not a valid shell variable or function name, or the `-f' option is + supplied with a name that is not a shell function. `return' return [N] - Cause a shell function to exit with value N. This may also be used - to terminate execution of a script being executed with the `.' - builtin. + Cause a shell function to exit with the return value N. This may + also be used to terminate execution of a script being executed + with the `.' builtin, returning either N or the exit status of the + last command executed within the script as the exit status of the + script. The return status is false if `return' is used outside a + function and not during the execution of a script by `.'. `shift' shift [N] - Shift positional parameters to the left by N. The positional - parameters from N+1 ... are renamed to `$1' ... . Parameters - represented by the numbers `$#' to N+1 are unset. N must be a - non-negative number less than or equal to `$#'. + Shift the positional parameters to the left by N. The positional + parameters from N+1 ... `$#' are renamed to `$1' ... `$#'-N+1. + Parameters represented by the numbers `$#' to N+1 are unset. N + must be a non-negative number less than or equal to `$#'. If N is + zero or greater than `$#', the positional parameters are not + changed. The return status is zero unless N is greater than `$#' + or less than zero, non-zero otherwise. `test' `[' - Evaluate a conditional expression (*note Bash Conditional - Expressions::.). + Evaluate a conditional expression EXPR. Each operator and operand + must be a separate argument. Expressions are composed of the + primaries described below in *Note Bash Conditional Expressions::. + + Expressions may be combined using the following operators, listed + in decreasing order of precedence. + + `! EXPR' + True if EXPR is false. + + `( EXPR )' + Returns the value of EXPR. This may be used to override the + normal precedence of operators. + + `EXPR1 -a EXPR2' + True if both EXPR1 and EXPR2 are true. + + `EXPR1 -o EXPR2' + True if either EXPR1 or EXPR2 is true. + + The `test' and `[' builtins evaluate conditional expressions using + a set of rules based on the number of arguments. + + 0 arguments + The expression is false. + + 1 argument + The expression is true if and only if the argument is not + null. + + 2 arguments + If the first argument is `!', the expression is true if and + only if the second argument is null. If the first argument + is one of the unary conditional operators (*note 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. + + 3 arguments + If the second argument is one of the binary conditional + operators (*note 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 `!', the value is the negation of the two-argument test + using the second and third arguments. If the first argument + is exactly `(' and the third argument is exactly `)', the + result is the one-argument test of the second argument. + Otherwise, the expression is false. The `-a' and `-o' + operators are considered binary operators in this case. + + 4 arguments + If the first argument is `!', the result is the negation of + the three-argument expression composed of the remaining + arguments. Otherwise, the expression is parsed and evaluated + according to precedence using the rules listed above. + + 5 or more arguments + The expression is parsed and evaluated according to precedence + using the rules listed above. `times' times Print out the user and system times used by the shell and its - children. + children. The return status is zero. `trap' trap [-lp] [ARG] [SIGSPEC ...] @@ -1669,33 +2225,42 @@ standard. If ARG is `-p', the shell displays the trap commands associated with each SIGSPEC. If no arguments are supplied, or only `-p' is given, `trap' prints the list of commands associated with each - signal number. Each SIGSPEC is either a signal name such as - `SIGINT' (with or without the `SIG' prefix) or a signal number. - If a SIGSPEC is `0' or `EXIT', ARG is executed when the shell - exits. If a SIGSPEC is `DEBUG', the command ARG is executed after - every simple command. The `-l' option causes the shell to print a - list of signal names and their corresponding numbers. + signal number in a form that may be reused as shell input. Each + SIGSPEC is either a signal name such as `SIGINT' (with or without + the `SIG' prefix) or a signal number. If a SIGSPEC is `0' or + `EXIT', ARG is executed when the shell exits. If a SIGSPEC is + `DEBUG', the command ARG is executed after every simple command. + The `-l' option causes the shell to print a list of signal names + and their corresponding numbers. Signals ignored upon entry to the shell cannot be trapped or reset. Trapped signals are reset to their original values in a child process when it is created. + The return status is zero unless a SIGSPEC does not specify a + valid signal. + `umask' - umask [-S] [MODE] + umask [-p] [-S] [MODE] Set the shell process's file creation mask to MODE. If MODE begins with a digit, it is interpreted as an octal number; if not, it is interpreted as a symbolic mode mask similar to that accepted by the `chmod' command. If MODE is omitted, the current value of the mask is printed. If the `-S' option is supplied without a - MODE argument, the mask is printed in a symbolic format. + MODE argument, the mask is printed in a symbolic format. If the + `-p' option is supplied, and 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 MODE argument is + supplied, and non-zero otherwise. `unset' unset [-fv] [NAME] Each variable or function NAME is removed. If no options are supplied, or the `-v' option is given, each NAME refers to a shell variable. If the `-f' option is given, the NAMEs refer to shell - functions, and the function definition is removed. Read-only - variables and functions may not be unset. + functions, and the function definition is removed. Readonly + variables and functions may not be unset. The return status is + zero unless a NAME does not exist or is readonly. File: bashref.info, Node: Bourne Shell Variables, Next: Other Bourne Shell Features, Prev: Bourne Shell Builtins, Up: Bourne Shell Features @@ -1706,47 +2271,49 @@ Bourne Shell Variables Bash uses certain shell variables in the same way as the Bourne shell. In some cases, Bash assigns a default value to the variable. -`IFS' - A list of characters that separate fields; used when the shell - splits words as part of expansion. - -`PATH' - A colon-separated list of directories in which the shell looks for - commands. +`CDPATH' + A colon-separated list of directories used as a search path for + the `cd' builtin command. `HOME' The current user's home directory; the default for the `cd' builtin - command. - -`CDPATH' - A colon-separated list of directories used as a search path for - the `cd' command. + command. The value of this variable is also used by tilde + expansion (*note Tilde Expansion::.). -`MAILPATH' - A colon-separated list of files which the shell periodically checks - for new mail. You can also specify what message is printed by - separating the file name from the message with a `?'. When used - in the text of the message, `$_' stands for the name of the - current mailfile. +`IFS' + A list of characters that separate fields; used when the shell + splits words as part of expansion. `MAIL' If this parameter is set to a filename and the `MAILPATH' variable is not set, Bash informs the user of the arrival of mail in the specified file. +`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 `?'. When used in the text + of the message, `$_' expands to the name of the current mail file. + +`OPTARG' + The value of the last option argument processed by the `getopts' + builtin. + +`OPTIND' + The index of the last option argument processed by the `getopts' + builtin. + +`PATH' + A colon-separated list of directories in which the shell looks for + commands. + `PS1' The primary prompt string. The default value is `\s-\v\$ '. `PS2' The secondary prompt string. The default value is `> '. -`OPTIND' - The index of the last option processed by the `getopts' builtin. - -`OPTARG' - The value of the last option argument processed by the `getopts' - builtin. - File: bashref.info, Node: Other Bourne Shell Features, Prev: Bourne Shell Variables, Up: Bourne Shell Features @@ -1762,9 +2329,9 @@ Other Bourne Shell Features expansion, redirection, and quoting as the Bourne Shell. Bash uses the POSIX 1003.2 standard as the specification of how these features are to be implemented. There are some differences between the traditional -Bourne shell and the POSIX standard; this section quickly details the -differences of significance. A number of these differences are -explained in greater depth in subsequent sections. +Bourne shell and Bash; this section quickly details the differences of +significance. A number of these differences are explained in greater +depth in subsequent sections. File: bashref.info, Node: Major Differences From The Bourne Shell, Up: Other Bourne Shell Features @@ -1772,202 +2339,233 @@ File: bashref.info, Node: Major Differences From The Bourne Shell, Up: Other B Major Differences From The SVR4.2 Bourne Shell ---------------------------------------------- - Bash is POSIX-conformant, even where the POSIX specification differs -from traditional `sh' behavior. + * Bash is POSIX-conformant, even where the POSIX specification + differs from traditional `sh' behavior. - Bash has multi-character invocation options (*note Invoking Bash::.). + * Bash has multi-character invocation options (*note Invoking + Bash::.). - Bash has command-line editing (*note Command Line Editing::.) and -the `bind' builtin. + * Bash has command-line editing (*note Command Line Editing::.) and + the `bind' builtin. - Bash has command history (*note Bash History Facilities::.) and the -`history' and `fc' builtins to manipulate it. + * Bash has command history (*note Bash History Facilities::.) and the + `history' and `fc' builtins to manipulate it. - Bash implements `csh'-like history expansion (*note History -Interaction::.). + * Bash implements `csh'-like history expansion (*note History + Interaction::.). - Bash has one-dimensional array variables (*note Arrays::.), and the -appropriate variable expansions and assignment syntax to use them. -Some of the Bash builtins take options to act on arrays. Bash provides -some built-in array variables. + * Bash has one-dimensional array variables (*note 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. - Bash implements the `!' keyword to negate the return value of a -pipeline (*note Pipelines::.). Very useful when an `if' statement -needs to act only if a test fails. + * The `$'...'' quoting syntax, which expands ANSI-C + backslash-escaped characters in the text between the single quotes, + is supported (*note ANSI-C Quoting::.). - Bash includes the `select' compound command, which allows the -generation of simple menus (*note Korn Shell Constructs::.). + * Bash supports the `$"..."' quoting syntax to do locale-specific + translation of the characters between the double quotes. The + `-D', `--dump-strings', and `--dump-po-strings' invocation options + list the translatable strings found in a script (*note Locale + Translation::.). - Bash includes brace expansion (*note Brace Expansion::.) and tilde -expansion (*note Tilde Expansion::.). + * Bash implements the `!' keyword to negate the return value of a + pipeline (*note Pipelines::.). Very useful when an `if' statement + needs to act only if a test fails. - Bash implements command aliases and the `alias' and `unalias' -builtins (*note Aliases::.). + * Bash has the `time' reserved word and command timing (*note + Pipelines::.). The display of the timing statistics may be + controlled with the `TIMEFORMAT' variable. - Bash provides shell arithmetic and arithmetic expansion (*note Shell -Arithmetic::.). + * Bash includes the `select' compound command, which allows the + generation of simple menus (*note Conditional Constructs::.). - The POSIX and `ksh'-style `$()' form of command substitution is -implemented (*note Command Substitution::.), and preferred to the -Bourne shell's ```' (which is also implemented for backwards -compatibility). + * Bash includes the `[[' compound command, which makes conditional + testing part of the shell grammar (*note Conditional + Constructs::.). - Variables present in the shell's initial environment are -automatically exported to child processes. The Bourne shell does not -normally do this unless the variables are explicitly marked using the -`export' command. + * Bash includes brace expansion (*note Brace Expansion::.) and tilde + expansion (*note Tilde Expansion::.). - Bash includes the POSIX and `ksh'-style pattern removal `%', `#', -`%%' and `##' constructs to remove leading or trailing substrings from -variable values (*note Shell Parameter Expansion::.). + * Bash implements command aliases and the `alias' and `unalias' + builtins (*note Aliases::.). - The expansion `${#xx}', which returns the length of `$xx', is -supported (*note Shell Parameter Expansion::.). + * Bash provides shell arithmetic, the `((' compound command (*note + Conditional Constructs::.), and arithmetic expansion (*note Shell + Arithmetic::.). - The `$'...'' quoting syntax, which expands ANSI-C backslash-escaped -characters in the text between the single quotes, is supported (*note -ANSI-C Quoting::.). + * Variables present in the shell's initial environment are + automatically exported to child processes. The Bourne shell does + not normally do this unless the variables are explicitly marked + using the `export' command. - Bash supports the `$"..."' quoting syntax to do locale-specific -translation of the characters between the double quotes. The `-D' and -`--dump-strings' invocation options list the translatable strings found -in a script (*note Locale Translation::.). + * Bash includes the POSIX pattern removal `%', `#', `%%' and `##' + expansions to remove leading or trailing substrings from variable + values (*note Shell Parameter Expansion::.). - The expansion `${var:'OFFSET`[:'LENGTH`]}', which expands to the -substring of `var''s value of length LENGTH, optionally beginning at -OFFSET, is present (*note Shell Parameter Expansion::.). + * The expansion `${#xx}', which returns the length of `${xx}', is + supported (*note Shell Parameter Expansion::.). - The expansion `${var/[/]'PATTERN`[/'REPLACEMENT`]}', which matches -PATTERN and replaces it with REPLACEMENT in the value of `var', is -available (*note Shell Parameter Expansion::.). + * The expansion `${var:'OFFSET`[:'LENGTH`]}', which expands to the + substring of `var''s value of length LENGTH, beginning at OFFSET, + is present (*note Shell Parameter Expansion::.). - Bash has INDIRECT variable expansion using `${!word}' (*note Shell -Parameter Expansion::.). + * The expansion `${var/[/]'PATTERN`[/'REPLACEMENT`]}', which matches + PATTERN and replaces it with REPLACEMENT in the value of `var', is + available (*note Shell Parameter Expansion::.). - Bash can expand positional parameters beyond `$9' using `${NUM}'. + * Bash has INDIRECT variable expansion using `${!word}' (*note Shell + Parameter Expansion::.). - Bash has process substitution (*note Process Substitution::.). + * Bash can expand positional parameters beyond `$9' using `${NUM}'. - Bash automatically assigns variables that provide information about -the current user (`UID', `EUID', and `GROUPS'), the current host -(`HOSTTYPE', `OSTYPE', `MACHTYPE', and `HOSTNAME'), and the instance of -Bash that is running (`BASH', `BASH_VERSION', and `BASH_VERSINFO'. -*Note Bash Variables::, for details. + * The POSIX `$()' form of command substitution is implemented (*note + Command Substitution::.), and preferred to the Bourne shell's ```' + (which is also implemented for backwards compatibility). - The `IFS' variable is used to split only the results of expansion, -not all words (*note Word Splitting::.). This closes a longstanding -shell security hole. + * Bash has process substitution (*note Process Substitution::.). - It is possible to have a variable and a function with the same name; -`sh' does not separate the two name spaces. + * Bash automatically assigns variables that provide information + about the current user (`UID', `EUID', and `GROUPS'), the current + host (`HOSTTYPE', `OSTYPE', `MACHTYPE', and `HOSTNAME'), and the + instance of Bash that is running (`BASH', `BASH_VERSION', and + `BASH_VERSINFO'). *Note Bash Variables::, for details. - Bash functions are permitted to have local variables using the -`local' builtin, and thus useful recursive functions may be written. + * The `IFS' variable is used to split only the results of expansion, + not all words (*note Word Splitting::.). This closes a + longstanding shell security hole. - Variable assignments preceding commands affect only that command, -even builtins and functions (*note Environment::.). In `sh', all -variable assignments preceding commands are global unless the command -is executed from the file system. + * Bash implements the full set of POSIX.2 filename expansion + operators, including CHARACTER CLASSES, EQUIVALENCE CLASSES, and + COLLATING SYMBOLS (*note Filename Expansion::.). - Bash performs filename expansion on filenames specified as operands -to output redirection operators. + * Bash implements extended pattern matching features when the + `extglob' shell option is enabled (*note Pattern Matching::.). - Bash contains the `<>' redirection operator, allowing a file to be -opened for both reading and writing, and the `&>' redirection operator, -for directing standard output and standard error to the same file -(*note Redirections::.). + * It is possible to have a variable and a function with the same + name; `sh' does not separate the two name spaces. - The `noclobber' option is available to avoid overwriting existing -files with output redirection (*note The Set Builtin::.). The `>|' -redirection operator may be used to override `noclobber'. + * Bash functions are permitted to have local variables using the + `local' builtin, and thus useful recursive functions may be + written. - Bash interprets special backslash-escaped characters in the prompt -strings when interactive (*note Printing a Prompt::.). + * Variable assignments preceding commands affect only that command, + even builtins and functions (*note Environment::.). In `sh', all + variable assignments preceding commands are global unless the + command is executed from the file system. - Bash allows you to write a function to override a builtin, and -provides access to that builtin's functionality within the function via -the `builtin' and `command' builtins (*note Bash Builtins::.). + * Bash performs filename expansion on filenames specified as operands + to input and output redirection operators. - The `command' builtin allows selective disabling of functions when -command lookup is performed (*note Bash Builtins::.). + * Bash contains the `<>' redirection operator, allowing a file to be + opened for both reading and writing, and the `&>' redirection + operator, for directing standard output and standard error to the + same file (*note Redirections::.). - Individual builtins may be enabled or disabled using the `enable' -builtin (*note Bash Builtins::.). + * The `noclobber' option is available to avoid overwriting existing + files with output redirection (*note The Set Builtin::.). The + `>|' redirection operator may be used to override `noclobber'. - The Bash `hash' builtin allows a name to be associated with an -arbitrary filename, even when that filename cannot be found by -searching the `$PATH', using `hash -p'. + * The Bash `cd' and `pwd' builtins (*note Bourne Shell Builtins::.) + each take `-L' and `-P' builtins to switch between logical and + physical modes. - Shell functions may be exported to children via the environment -(*note Shell Functions::.). + * 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 `builtin' and `command' builtins (*note Bash + Builtins::.). - Bash includes a `help' builtin for quick reference to shell -facilities (*note Bash Builtins::.). + * The `command' builtin allows selective disabling of functions when + command lookup is performed (*note Bash Builtins::.). - The Bash `read' builtin (*note Bash Builtins::.) will read a line -ending in `\' with the `-r' option, and will use the `REPLY' variable -as a default if no arguments are supplied. The Bash `read' builtin -also accepts a prompt string with the `-p' option and will use Readline -to obtain the line when given the `-e' option. + * Individual builtins may be enabled or disabled using the `enable' + builtin (*note Bash Builtins::.). - Bash includes the `shopt' builtin, for finer control of shell -optional capabilities (*note Bash Builtins::.). + * The Bash `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 + (*note Bourne Shell Builtins::.). - Bash has much more optional behavior controllable with the `set' -builtin (*note The Set Builtin::.). + * Shell functions may be exported to children via the environment + using `export -f' (*note Shell Functions::.). - The `disown' builtin can remove a job from the internal shell job -table (*note Job Control Builtins::.). + * The Bash `export', `readonly', and `declare' builtins can take a + `-f' option to act on shell functions, a `-p' option to display + variables with various attributes set in a format that can be used + as shell input, a `-n' option to remove various variable + attributes, and `name=value' arguments to set variable attributes + and values simultaneously. - The `return' builtin may be used to abort execution of scripts -executed with the `.' or `source' builtins (*note Bourne Shell -Builtins::.). + * The Bash `hash' builtin allows a name to be associated with an + arbitrary filename, even when that filename cannot be found by + searching the `$PATH', using `hash -p' (*note Bourne Shell + Builtins::.). + + * Bash includes a `help' builtin for quick reference to shell + facilities (*note Bash Builtins::.). + + * The `printf' builtin is available to display formatted output + (*note Bash Builtins::.). + + * The Bash `read' builtin (*note Bash Builtins::.) will read a line + ending in `\' with the `-r' option, and will use the `REPLY' + variable as a default if no arguments are supplied. The Bash + `read' builtin also accepts a prompt string with the `-p' option + and will use Readline to obtain the line when given the `-e' + option. - The `test' builtin (*note Bourne Shell Builtins::.) is slightly -different, as it implements the POSIX 1003.2 algorithm, which specifies -the behavior based on the number of arguments. + * The `return' builtin may be used to abort execution of scripts + executed with the `.' or `source' builtins (*note Bourne Shell + Builtins::.). - The `trap' builtin (*note Bourne Shell Builtins::.) allows a `DEBUG' -pseudo-signal specification, similar to `EXIT'. Commands specified -with a `DEBUG' trap are executed after every simple command. The -`DEBUG' trap is not inherited by shell functions. + * Bash includes the `shopt' builtin, for finer control of shell + optional capabilities (*note Bash Builtins::.). - The Bash `export', `readonly', and `declare' builtins can take a -`-f' option to act on shell functions, a `-p' option to display -variables with various attributes set in a format that can be used as -shell input, a `-n' option to remove various variable attributes, and -`name=value' arguments to set variable attributes and values -simultaneously. + * Bash has much more optional behavior controllable with the `set' + builtin (*note The Set Builtin::.). - The Bash `cd' and `pwd' builtins (*note Bourne Shell Builtins::.) -each take `-L' and `-P' builtins to switch between logical and physical -modes. + * The `test' builtin (*note Bourne Shell Builtins::.) is slightly + different, as it implements the POSIX algorithm, which specifies + the behavior based on the number of arguments. - The Bash `type' builtin is more extensive and gives more information -about the names it finds (*note Bash Builtins::.). + * The `trap' builtin (*note Bourne Shell Builtins::.) allows a + `DEBUG' pseudo-signal specification, similar to `EXIT'. Commands + specified with a `DEBUG' trap are executed after every simple + command. The `DEBUG' trap is not inherited by shell functions. - Bash implements a `csh'-like directory stack, and provides the -`pushd', `popd', and `dirs' builtins to manipulate it (*note C Shell -Builtins::.). Bash also makes the directory stack visible as the value -of the `DIRSTACK' shell variable. + * The Bash `type' builtin is more extensive and gives more + information about the names it finds (*note Bash Builtins::.). - The Bash restricted mode is more useful (*note The Restricted -Shell::.); the SVR4.2 shell restricted mode is too limited. + * The Bash `umask' builtin permits a `-p' option to cause the output + to be displayed in the form of a `umask' command that may be + reused as input (*note Bourne Shell Builtins::.). - Bash has the `time' reserved word and command timing (*note -Pipelines::.). The display of the timing statistics may be controlled -with the `TIMEFORMAT' variable. + * Bash implements a `csh'-like directory stack, and provides the + `pushd', `popd', and `dirs' builtins to manipulate it (*note The + Directory Stack::.). Bash also makes the directory stack visible + as the value of the `DIRSTACK' shell variable. - The SVR4.2 shell has two privilege-related builtins (`mldmode' and -`priv') not present in Bash. + * Bash interprets special backslash-escaped characters in the prompt + strings when interactive (*note Printing a Prompt::.). - Bash does not have the `stop' or `newgrp' builtins. + * The Bash restricted mode is more useful (*note The Restricted + Shell::.); the SVR4.2 shell restricted mode is too limited. - Bash does not use the `SHACCT' variable or perform shell accounting. + * The `disown' builtin can remove a job from the internal shell job + table (*note Job Control Builtins::.) or suppress the sending of + `SIGHUP' to a job when the shell exits as the result of a `SIGHUP'. - The SVR4.2 `sh' uses a `TIMEOUT' variable like Bash uses `TMOUT'. + * The SVR4.2 shell has two privilege-related builtins (`mldmode' and + `priv') not present in Bash. - More features unique to Bash may be found in *Note Bash Features::. + * Bash does not have the `stop' or `newgrp' builtins. + + * Bash does not use the `SHACCT' variable or perform shell + accounting. + + * The SVR4.2 `sh' uses a `TIMEOUT' variable like Bash uses `TMOUT'. + +More features unique to Bash may be found in *Note Bash Features::. Implementation Differences From The SVR4.2 Shell ------------------------------------------------ @@ -1985,18 +2583,18 @@ from many of the limitations of the SVR4.2 shell. For instance: * The SVR4.2 shell uses a baroque memory management scheme based on trapping `SIGSEGV'. If the shell is started from a process with `SIGSEGV' blocked (e.g., by using the `system()' C library - function call), the shell misbehaves badly. + function call), it misbehaves badly. * In a questionable attempt at security, the SVR4.2 shell, when invoked without the `-p' option, will alter its real and effective UID and GID if they are less than some magic threshold value, commonly 100. This can lead to unexpected results. - * The SVR4.2 shell does not allow users to trap `SIGALRM' or - `SIGCHLD'. + * The SVR4.2 shell does not allow users to trap `SIGSEGV', + `SIGALRM', or `SIGCHLD'. - * For some reason, the SVR4.2 shell does not allow the `MAILCHECK' - variable to be unset. + * The SVR4.2 shell does not allow the `IFS', `MAILCHECK', `PATH', + `PS1', or `PS2' variables to be unset. * The SVR4.2 shell treats `^' as the undocumented equivalent of `|'. @@ -2013,470 +2611,7 @@ from many of the limitations of the SVR4.2 shell. For instance: turns on job control). -File: bashref.info, Node: Csh Features, Next: Korn Shell Features, Prev: Bourne Shell Features, Up: Top - -C-Shell Style Features -********************** - - The C-Shell ("`csh'") was created by Bill Joy at The University of -California at Berkeley. It is generally considered to have better -features for interactive use than the original Bourne shell. Some of -the `csh' features present in Bash include job control, history -expansion, `protected' redirection, and several variables to control -the interactive behaviour of the shell (e.g., `IGNOREEOF'). - - *Note Using History Interactively::, for details on history -expansion. - -* Menu: - -* Brace Expansion:: Expansion of expressions within braces. -* Tilde Expansion:: Expansion of the ~ character. -* C Shell Builtins:: Builtin commands adopted from the C Shell. -* C Shell Variables:: Variables which Bash uses in essentially - the same way as the C Shell. - - -File: bashref.info, Node: Brace Expansion, Next: Tilde Expansion, Up: Csh Features - -Brace Expansion -=============== - - Brace expansion is a mechanism by which arbitrary strings may be -generated. This mechanism is similar to FILENAME EXPANSION (*note -Filename Expansion::.), but the file names generated need not exist. -Patterns to be brace expanded take the form of an optional PREAMBLE, -followed by a series of comma-separated strings between a pair of -braces, followed by an optional POSTAMBLE. The preamble is prepended -to each string contained within the braces, and the postamble is then -appended to each resulting string, expanding left to right. - - Brace expansions may be nested. The results of each expanded string -are not sorted; left to right order is preserved. For example, - bash$ echo a{d,c,b}e - ade ace abe - - Brace expansion is performed before any other expansions, and any -characters special to other expansions are preserved in the result. It -is strictly textual. Bash does not apply any syntactic interpretation -to the context of the expansion or the text between the braces. - - A correctly-formed brace expansion must contain unquoted opening and -closing braces, and at least one unquoted comma. Any incorrectly -formed brace expansion is left unchanged. - - This construct is typically used as shorthand when the common prefix -of the strings to be generated is longer than in the above example: - mkdir /usr/local/src/bash/{old,new,dist,bugs} - or - chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}} - - -File: bashref.info, Node: Tilde Expansion, Next: C Shell Builtins, Prev: Brace Expansion, Up: Csh Features - -Tilde Expansion -=============== - - Bash has tilde (~) expansion, similar, but not identical, to that of -`csh'. The following table shows what unquoted words beginning with a -tilde expand to. - -`~' - The current value of `$HOME'. - -`~/foo' - `$HOME/foo' - -`~fred/foo' - The subdirectory `foo' of the home directory of the user `fred'. - -`~+/foo' - `$PWD/foo' - -`~-/foo' - `$OLDPWD/foo' - - Bash will also tilde expand words following redirection operators -and words following `=' in assignment statements. - - -File: bashref.info, Node: C Shell Builtins, Next: C Shell Variables, Prev: Tilde Expansion, Up: Csh Features - -C Shell Builtins -================ - - Bash has several builtin commands whose definition is very similar -to `csh'. - -`pushd' - pushd [DIR | +N | -N] [-n] - - Save the current directory on a list and then `cd' to DIR. With no - arguments, exchanges the top two directories. - - `+N' - Brings the Nth directory (counting from the left of the list - printed by `dirs', starting with zero) to the top of the list - by rotating the stack. - - `-N' - Brings the Nth directory (counting from the right of the list - printed by `dirs', starting with zero) to the top of the list - by rotating the stack. - - `-n' - Suppresses the normal change of directory when adding - directories to the stack, so that only the stack is - manipulated. - - `DIR' - Makes the current working directory be the top of the stack, - and then `cd's to DIR. You can see the saved directory list - with the `dirs' command. - -`popd' - popd [+N | -N] [-n] - - Pop the directory stack, and `cd' to the new top directory. When - no arguments are given, `popd' removes the top directory from the - stack and performs a `cd' to the new top directory. The elements - are numbered from 0 starting at the first directory listed with - `dirs'; i.e., `popd' is equivalent to `popd +0'. - `+N' - Removes the Nth directory (counting from the left of the list - printed by `dirs'), starting with zero. - - `-N' - Removes the Nth directory (counting from the right of the - list printed by `dirs'), starting with zero. - - `-n' - Suppresses the normal change of directory when removing - directories from the stack, so that only the stack is - manipulated. - -`dirs' - dirs [+N | -N] [-clvp] - Display the list of currently remembered directories. Directories - find their way onto the list with the `pushd' command; you can get - back up through the list with the `popd' command. - `+N' - Displays the Nth directory (counting from the left of the - list printed by `dirs' when invoked without options), starting - with zero. - - `-N' - Displays the Nth directory (counting from the right of the - list printed by `dirs' when invoked without options), starting - with zero. - - `-c' - Clears the directory stack by deleting all of the elements. - - `-l' - Produces a longer listing; the default listing format uses a - tilde to denote the home directory. - - `-p' - Causes `dirs' to print the directory stack with one entry per - line. - - `-v' - Causes `dirs' to print the directory stack with one entry per - line, prepending each entry with its index in the stack. - -`history' - history [-c] [N] - history [-anrw] [FILENAME] - history -ps ARG - - Display the history list with line numbers. Lines prefixed with - with a `*' have been modified. An argument of N says to list only - the last N lines. Options, if supplied, have the following - meanings: - - `-w' - Write out the current history to the history file. - - `-r' - Read the current history file and append its contents to the - history list. - - `-a' - Append the new history lines (history lines entered since the - beginning of the current Bash session) to the history file. - - `-n' - Append the history lines not already read from the history - file to the current history list. These are lines appended - to the history file since the beginning of the current Bash - session. - - `-c' - Clear the history list. This may be combined with the other - options to replace the history list completely. - - `-s' - The ARGs are added to the end of the history list as a single - entry. - - `-p' - Perform history substitution on the ARGs and display the - result on the standard output, without storing the results in - the history list. - - When the `-w', `-r', `-a', or `-n' option is used, if FILENAME is - given, then it is used as the history file. If not, then the - value of the `HISTFILE' variable is used. - -`logout' - Exit a login shell. - -`source' - A synonym for `.' (*note Bourne Shell Builtins::.). - - -File: bashref.info, Node: C Shell Variables, Prev: C Shell Builtins, Up: Csh Features - -C Shell Variables -================= - -`IGNOREEOF' - If this variable is set, its value is used the number of - consecutive `EOF's Bash will read before exiting. By default, - Bash will exit upon reading a single `EOF'. If `IGNOREEOF' is not - set to a numeric value, Bash acts as if its value were 10. - - -File: bashref.info, Node: Korn Shell Features, Next: Bash Features, Prev: Csh Features, Up: Top - -Korn Shell Style Features -************************* - - This section describes features primarily inspired by the Korn Shell -(`ksh'). In some cases, the POSIX 1003.2 standard has adopted these -commands and variables from the Korn Shell; Bash implements those -features using the POSIX standard as a guide. - -* Menu: - -* Korn Shell Constructs:: Shell grammar constructs adopted from the - Korn Shell -* Korn Shell Builtins:: Builtin commands adopted from the Korn Shell. -* Korn Shell Variables:: Variables which Bash uses in essentially - the same way as the Korn Shell. -* Aliases:: Substituting one command for another. - - -File: bashref.info, Node: Korn Shell Constructs, Next: Korn Shell Builtins, Up: Korn Shell Features - -Korn Shell Constructs -===================== - - Bash includes the Korn Shell `select' construct. This construct -allows the easy generation of menus. It has almost the same syntax as -the `for' command. - - The syntax of the `select' command is: - select NAME [in WORDS ...]; do COMMANDS; done - - The list of words following `in' is expanded, generating a list of -items. The set of expanded words is printed on the standard error, -each preceded by a number. If the `in WORDS' is omitted, the -positional parameters are printed. The `PS3' prompt is then displayed -and a line is read from the standard input. If the line consists of a -number corresponding to one of the displayed words, then the value of -NAME is set to that word. If the line is empty, the words and prompt -are displayed again. If `EOF' is read, the `select' command completes. -Any other value read causes NAME to be set to null. The line read is -saved in the variable `REPLY'. - - The COMMANDS are executed after each selection until a `break' or -`return' command is executed, at which point the `select' command -completes. - - Bash also has adopted command timing from the Korn shell. If the -`time' reserved word precedes a pipeline, which may consist of a single -command, timing statistics for the pipeline are displayed when it -completes. The statistics currently consist of elapsed (wall-clock) -time and user and system time consumed by the command's execution. - - The use of `time' as a reserved word permits the timing of shell -builtins, shell functions, and pipelines. An external `time' command -cannot time these easily. - - -File: bashref.info, Node: Korn Shell Builtins, Next: Korn Shell Variables, Prev: Korn Shell Constructs, Up: Korn Shell Features - -Korn Shell Builtins -=================== - - This section describes Bash builtin commands taken from `ksh'. - -`fc' - `fc [-e ENAME] [-nlr] [FIRST] [LAST]' - `fc -s [PAT=REP] [COMMAND]' - - Fix Command. In the first form, a range of commands from FIRST to - LAST is selected from the history list. Both FIRST and LAST may - be specified as a string (to locate the most recent command - beginning with that string) or as a number (an index into the - history list, where a negative number is used as an offset from the - current command number). If LAST is not specified it is set to - FIRST. If FIRST is not specified it is set to the previous - command for editing and -16 for listing. If the `-l' flag is - given, the commands are listed on standard output. The `-n' flag - suppresses the command numbers when listing. The `-r' flag - reverses the order of the listing. Otherwise, the editor given by - ENAME is invoked on a file containing those commands. If ENAME is - not given, the value of the following variable expansion is used: - `${FCEDIT:-${EDITOR:-vi}}'. This says to use the value of the - `FCEDIT' variable if set, or the value of the `EDITOR' variable if - that is set, or `vi' if neither is set. When editing is complete, - the edited commands are echoed and executed. - - In the second form, COMMAND is re-executed after each instance of - PAT in the selected command is replaced by REP. - - A useful alias to use with the `fc' command is `r='fc -s'', so - that typing `r cc' runs the last command beginning with `cc' and - typing `r' re-executes the last command (*note Aliases::.). - -`let' - The `let' builtin allows arithmetic to be performed on shell - variables. For details, refer to *Note Arithmetic Builtins::. - -`typeset' - The `typeset' command is supplied for compatibility with the Korn - shell; however, it has been deprecated in favor of the `declare' - command (*note Bash Builtins::.). - - -File: bashref.info, Node: Korn Shell Variables, Next: Aliases, Prev: Korn Shell Builtins, Up: Korn Shell Features - -Korn Shell Variables -==================== - -`REPLY' - The default variable for the `read' builtin. - -`RANDOM' - Each time this parameter is referenced, a random integer between 0 - and 32767 is generated. Assigning a value to this variable seeds - the random number generator. - -`SECONDS' - This variable expands to the number of seconds since the shell was - started. Assignment to this variable resets the count to the - value assigned, and the expanded value becomes the value assigned - plus the number of seconds since the assignment. - -`PS3' - The value of this variable is used as the prompt for the `select' - command. If this variable is not set, the `select' command - prompts with `#? ' - -`PS4' - This is the prompt printed before the command line is echoed when - the `-x' option is set (*note The Set Builtin::.). The default is - `+ '. - -`PWD' - The current working directory as set by the `cd' builtin. - -`OLDPWD' - The previous working directory as set by the `cd' builtin. - -`TMOUT' - If set to a value greater than zero, the value is interpreted as - the number of seconds to wait for input after issuing the primary - prompt. Bash terminates after that number of seconds if input does - not arrive. - -`LINENO' - The line number in the script or shell function currently - executing. - -`FCEDIT' - The editor used as a default by the `fc' builtin command. - - -File: bashref.info, Node: Aliases, Prev: Korn Shell Variables, Up: Korn Shell Features - -Aliases -======= - -* Menu: - -* Alias Builtins:: Builtins commands to maniuplate aliases. - - The shell maintains a list of ALIASES that may be set and unset with -the `alias' and `unalias' builtin commands. - - The first word of each command, if unquoted, is checked to see if it -has an alias. If so, that word is replaced by the text of the alias. -The alias name and the replacement text may contain any valid shell -input, including shell metacharacters, with the exception that the -alias name may not contain <=>. The first word of the replacement text -is tested for aliases, but a word that is identical to an alias being -expanded is not expanded a second time. This means that one may alias -`ls' to `"ls -F"', for instance, and Bash does not try to recursively -expand the replacement text. If the last character of the alias value -is a space or tab character, then the next command word following the -alias is also checked for alias expansion. - - Aliases are created and listed with the `alias' command, and removed -with the `unalias' command. - - There is no mechanism for using arguments in the replacement text, -as in `csh'. If arguments are needed, a shell function should be used -(*note Shell Functions::.). - - Aliases are not expanded when the shell is not interactive, unless -the `expand_aliases' shell option is set using `shopt' (*note Bash -Builtins::.). - - The rules concerning the definition and use of aliases are somewhat -confusing. Bash always reads at least one complete line of input -before executing any of the commands on that line. Aliases are -expanded when a command is read, not when it is executed. Therefore, an -alias definition appearing on the same line as another command does not -take effect until the next line of input is read. The commands -following the alias definition on that line are not affected by the new -alias. This behavior is also an issue when functions are executed. -Aliases are expanded when the function definition is read, not when the -function is executed, because a function definition is itself a -compound command. As a consequence, aliases defined in a function are -not available until after that function is executed. To be safe, -always put alias definitions on a separate line, and do not use `alias' -in compound commands. - - Note that for almost every purpose, aliases are superseded by shell -functions. - - -File: bashref.info, Node: Alias Builtins, Up: Aliases - -Alias Builtins --------------- - -`alias' - alias [`-p'] [NAME[=VALUE] ...] - - Without arguments or with the `-p' option, `alias' prints the list - of aliases on the standard output in a form that allows them to be - reused as input. If arguments are supplied, an alias is defined - for each NAME whose VALUE is given. If no VALUE is given, the name - and value of the alias is printed. - -`unalias' - unalias [-a] [NAME ... ] - - Remove each NAME from the list of aliases. If `-a' is supplied, - all aliases are removed. - - -File: bashref.info, Node: Bash Features, Next: Job Control, Prev: Korn Shell Features, Up: Top +File: bashref.info, Node: Bash Features, Next: Job Control, Prev: Bourne Shell Features, Up: Top Bash Features ************* @@ -2496,7 +2631,9 @@ Bash Features the `test' builtin. * Bash Variables:: List of variables that exist in Bash. * Shell Arithmetic:: Arithmetic on shell variables. -* Arrays:: Array 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 @@ -2517,6 +2654,10 @@ Invoking Bash that you can use. These options must appear on the command line before the single-character options in order for them to be recognized. +`--dump-po-strings' + Equivalent to `-D', but the output is in the GNU `gettext' PO + (portable object) file format. + `--dump-strings' Equivalent to `-D'. @@ -2526,8 +2667,8 @@ the single-character options in order for them to be recognized. `--login' Make this shell act as if it were directly invoked by login. This is equivalent to `exec -l bash' but can be issued from another - shell, such as `csh'. If you wanted to replace your current login - shell with a Bash login shell, you would say `exec bash --login'. + shell, such as `csh'. `exec bash --login' will replace the + current shell with a Bash login shell. `--noediting' Do not use the GNU Readline library (*note Command Line Editing::.) @@ -2564,8 +2705,8 @@ the single-character options in order for them to be recognized. Show version information for this instance of Bash on the standard output and exit successfully. - There are several single-character options you can give which are -not available with the `set' builtin. + There are several single-character options that may be supplied at +invocation which are not available with the `set' builtin. `-c STRING' Read and execute commands from STRING after processing the @@ -2576,10 +2717,10 @@ not available with the `set' builtin. Force the shell to run interactively. `-r' - Make the shell restricted. + Make the shell a restricted shell (*note The Restricted Shell::.). `-s' - If this flag is present, or if no arguments remain after option + 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. @@ -2591,8 +2732,13 @@ not available with the `set' builtin. (*note Locale Translation::.). This implies the `-n' option; no commands will be executed. +`--' + A `--' signals the end of options and disables further option + processing. Any arguments after the `--' are treated as filenames + and arguments. + An *interactive* shell is one whose input and output are both -connected to terminals (as determined by `isatty()'), or one started +connected to terminals (as determined by `isatty(3)'), or one started with the `-i' option. If arguments remain after option processing, and neither the `-c' @@ -2652,10 +2798,10 @@ name. behavior of historical versions of `sh' as closely as possible, while conforming to the POSIX standard as well. - When invoked as a login shell, it first attempts to read and execute -commands from `/etc/profile' and `~/.profile', in that order. The -`--noprofile' option may be used to inhibit this behavior. When -invoked as an interactive shell with the name `sh', `bash' looks for + When invoked as an interactive login shell, it first attempts to read +and execute commands from `/etc/profile' and `~/.profile', in that +order. The `--noprofile' option may be used to inhibit this behavior. +When invoked as an interactive shell with the name `sh', Bash looks for the variable `ENV', expands its value if it is defined, and uses the expanded value as the name of a file to read and execute. Since a shell invoked as `sh' does not attempt to read and execute commands @@ -2668,16 +2814,16 @@ are read. When Bash is started in POSIX mode, as with the `--posix' command line option, it follows the POSIX standard for startup files. In this -mode, the `ENV' variable is expanded and commands are read and executed -from the file whose name is the expanded value. No other startup files -are read. This is done by interactive shells only. +mode, interactive shells expand the `ENV' variable and commands are +read and executed from the file whose name is the expanded value. No +other startup files are read. Bash attempts to determine when it is being run by the remote shell daemon, usually `rshd'. If Bash determines it is being run by rshd, it reads and executes commands from `~/.bashrc', if that file exists and is readable. It will not do this if invoked as `sh'. The `--norc' option may be used to inhibit this behavior, and the `--rcfile' option -may be used to force another file to be read, but rshd does not +may be used to force another file to be read, but `rshd' does not generally invoke the shell with those options or allow them to be specified. @@ -2691,10 +2837,9 @@ Is This Shell Interactive? whose input and output are both connected to terminals (as determined by `isatty(3)'), or one started with the `-i' option. - You may wish to determine within a startup script whether Bash is -running interactively or not. To do this, examine the variable `$PS1'; -it is unset in non-interactive shells, and set in interactive shells. -Thus: + To determine within a startup script whether Bash is running +interactively or not, examine the variable `$PS1'; it is unset in +non-interactive shells, and set in interactive shells. Thus: if [ -z "$PS1" ]; then echo This shell is not interactive @@ -2702,8 +2847,8 @@ Thus: echo This shell is interactive fi - Alternatively, you may test the value of the `-' special parameter. -It contains `i' when the shell is interactive. For example: + Alternatively, startup scripts may test the value of the `-' special +parameter. It contains `i' when the shell is interactive. For example: case "$-" in *i*) echo This shell is interactive ;; @@ -2720,7 +2865,8 @@ Bash Builtin Commands been extended in Bash. `bind' - bind [-m KEYMAP] [-lpsvPSV] [-q NAME] [-r KEYSEQ] + bind [-m KEYMAP] [-lpsvPSV] + bind [-m KEYMAP] [-q FUNCTION] [-u FUNCTION] [-r KEYSEQ] bind [-m KEYMAP] -f FILENAME bind [-m KEYMAP] KEYSEQ:FUNCTION-NAME @@ -2740,57 +2886,71 @@ been extended in Bash. `vi-command'; `emacs' is equivalent to `emacs-standard'. `-l' - List the names of all Readline functions + List the names of all Readline functions. `-p' Display Readline function names and bindings in such a way - that they can be re-read + that they can be re-read. `-P' - List current Readline function names and bindings + List current Readline function names and bindings. `-v' Display Readline variable names and values in such a way that - they can be re-read + they can be re-read. `-V' - List current Readline variable names and values + List current Readline variable names and values. `-s' Display Readline key sequences bound to macros and the - strings they output in such a way that they can be re-read + strings they output in such a way that they can be re-read. `-S' Display Readline key sequences bound to macros and the - strings they output + strings they output. `-f FILENAME' - Read key bindings from FILENAME + Read key bindings from FILENAME. - `-q' - Query about which keys invoke the named FUNCTION + `-q FUNCTION' + Query about which keys invoke the named FUNCTION. + + `-u FUNCTION' + Unbind all keys bound to the named FUNCTION. `-r KEYSEQ' - Remove any current binding for KEYSEQ + Remove any current binding for KEYSEQ. + + The return status is zero unless an invalid option is supplied or + an error occurs. `builtin' builtin [SHELL-BUILTIN [ARGS]] - Run a shell builtin. This is useful when you wish to define a - shell function with the same name as a shell builtin, but need the - functionality of the builtin within the function itself. + Run a shell builtin, passing it 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 + SHELL-BUILTIN is not a shell builtin command. `command' - command [-pVv] COMMAND [ARGS ...] - Runs COMMAND with ARG ignoring shell functions. If you have a - shell function called `ls', and you wish to call the command `ls', - you can say `command ls'. The `-p' option means to use a default - value for `$PATH' that is guaranteed to find all of the standard - utilities. + command [-pVv] COMMAND [ARGUMENTS ...] + Runs COMMAND with ARGUMENTS ignoring any shell function named + COMMAND. Only shell builtin commands or commands found by + searching the `PATH' are executed. If there is a shell function + named `ls', running `command ls' within the function will execute + the external command `ls' instead of calling the function + recursively. The `-p' option means to use a default value for + `$PATH' that is guaranteed to find all of the standard utilities. + The return status in this case is 127 if COMMAND cannot be found + or an error occurred, and the exit status of COMMAND otherwise. If either the `-V' or `-v' option is supplied, a description of COMMAND is printed. The `-v' option causes a single word indicating the command or file name used to invoke COMMAND to be - printed; the `-V' option produces a more verbose description. + displayed; the `-V' option produces a more verbose description. + In this case, the return status is zero if COMMAND is found, and + non-zero if not. `declare' declare [-afFrxi] [-p] [NAME[=VALUE]] @@ -2818,7 +2978,7 @@ been extended in Bash. `-r' Make NAMEs readonly. These names cannot then be assigned - values by subsequent assignment statements. + values by subsequent assignment statements or unset. `-x' Mark each NAME for export to subsequent commands via the @@ -2828,11 +2988,21 @@ been extended in Bash. used in a function, `declare' makes each NAME local, as with the `local' command. + The return status is zero unless an invalid option is encountered, + an attempt is made to define a function using `-f foo=bar', an + attempt is made to assign a value to a readonly variable, an + attempt is made to assign a value to an array variable without + using the compound assignment syntax (*note Arrays::.), one of the + 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 `-f'. + `echo' - echo [-neE] [arg ...] - Output the `arg's, separated by spaces, terminated with a newline. - The return status is always 0. If `-n' is specified, the - trailing newline is suppressed. If the `-e' option is given, + echo [-neE] [ARG ...] + Output the ARGs, separated by spaces, terminated with a newline. + The return status is always 0. If `-n' is specified, the trailing + newline is suppressed. If the `-e' option is given, interpretation of the following backslash-escaped characters is enabled. The `-E' option disables the interpretation of these escape characters, even on systems where they are interpreted by @@ -2867,13 +3037,20 @@ been extended in Bash. `\\' backslash - `\nnn' - the character whose ASCII code is `nnn' (octal) + `\NNN' + the character whose `ASCII' code is the octal value NNN (one + to three digits) + + `\xNNN' + the character whose `ASCII' code is the hexadecimal value NNN + (one to three digits) `enable' enable [-n] [-p] [-f FILENAME] [-ads] [NAME ...] - Enable and disable builtin shell commands. This allows you to use - a disk command which has the same name as a shell builtin. If + 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 with specifying a full pathname, even though the + shell normally searches for builtins before disk commands. If `-n' is used, the NAMEs become disabled. Otherwise NAMEs are enabled. For example, to use the `test' binary found via `$PATH' instead of the shell builtin version, type `enable -n test'. @@ -2886,39 +3063,73 @@ been extended in Bash. The `-f' option means to load the new builtin command NAME from shared object FILENAME, on systems that support dynamic loading. - The `-d' option will delete a builtin loaded with `-f'. If there - are no options, a list of the shell builtins is displayed. The - `-s' option restricts `enable' to the POSIX.2 special builtins. + The `-d' option will delete a builtin loaded with `-f'. + + If there are no options, a list of the shell builtins is displayed. + The `-s' option restricts `enable' to the POSIX special builtins. If `-s' is used with `-f', the new builtin becomes a special builtin. + The return status is zero unless a NAME is not a shell builtin or + there is an error loading a new builtin from a shared object. + `help' help [PATTERN] Display helpful information about builtin commands. If PATTERN is specified, `help' gives detailed help on all commands matching - PATTERN, otherwise a list of the builtins is printed. + PATTERN, otherwise a list of the builtins is printed. The return + status is zero unless no command matches PATTERN. + +`let' + let EXPRESSION [EXPRESSION] + The `let' builtin allows arithmetic to be performed on shell + variables. Each EXPRESSION is evaluated according to the rules + given below in *Note Shell Arithmetic::. If the last EXPRESSION + evaluates to 0, `let' returns 1; otherwise 0 is returned. `local' local NAME[=VALUE] - For each argument, create a local variable called NAME, and give - it VALUE. `local' can only be used within a function; it makes - the variable NAME have a visible scope restricted to that function - and its children. + For each argument, a local variable named NAME is created, and + assigned VALUE. `local' can only be used within a function; it + makes the variable NAME have a visible scope restricted to that + function and its children. The return status is zero unless + `local' is used outside a function or an invalid NAME is supplied. `logout' logout [N] Exit a login shell, returning a status of N to the shell's parent. +`printf' + `printf' FORMAT [ARGUMENTS] + Write the formatted ARGUMENTS to the standard output under the + control of the FORMAT. The FORMAT is a character string which + contains three types of objects: plain characters, which are + simply copied to standard output, character escape sequences, + which are converted and copied to the standard output, and format + specifications, each of which causes printing of the next + successive ARGUMENT. In addition to the standard `printf(1)' + formats, `%b' causes `printf' to expand backslash escape sequences + in the corresponding ARGUMENT, and `%q' causes `printf' to output + the corresponding ARGUMENT in a format that can be reused as shell + input. + + The FORMAT is reused as necessary to consume all of the ARGUMENTS. + If the FORMAT requires more ARGUMENTS than are supplied, the extra + format specifications behave as if a zero value or null string, as + appropriate, had been supplied. + `read' read [-a ANAME] [-p PROMPT] [-er] [NAME ...] One line is read from the standard input, and the first word is assigned to the first NAME, the second word to the second NAME, - and so on, with leftover words assigned to the last NAME. Only - the characters in the value of the `IFS' variable are recognized - as word delimiters. If no names are supplied, the line read is - assigned to the variable `REPLY'. The return code is zero, unless - end-of-file is encountered. Options, if supplied, have the - following meanings: + and so on, with leftover words and their intervening separators + assigned to the last NAME. If there are fewer words read from the + standard input than names, the remaining names are assigned empty + values. The characters in the value of the `IFS' variable are + used to split the line into words. If no names are supplied, the + line read is assigned to the variable `REPLY'. The return code is + zero, unless end-of-file is encountered. Options, if supplied, + have the following meanings: `-r' If this option is given, a backslash-newline pair is not @@ -2926,13 +3137,15 @@ been extended in Bash. line. `-p PROMPT' - Display `prompt', without a trailing newline, before - attempting to read any input. The prompt is displayed only - if input is coming from a terminal. + Display PROMPT, without a trailing newline, before attempting + to read any input. The prompt is displayed only if input is + coming from a terminal. `-a ANAME' The words are assigned to sequential indices of the array - variable ANAME, starting at 0. + variable ANAME, starting at 0. All elements are removed from + ANAME before the assignment. Other NAME arguments are + ignored. `-e' Readline (*note Command Line Editing::.) is used to obtain @@ -2943,10 +3156,11 @@ been extended in Bash. Toggle the values of variables controlling optional shell behavior. With no options, or with the `-p' option, a list of all settable options is displayed, with an indication of whether or not each is - set. Other options have the following meanings: + set. The `-p' option causes output to be displayed in a form that + may be reused as input. Other options have the following meanings: `-s' - Enable (set) each OPTNAME + Enable (set) each OPTNAME. `-u' Disable (unset) each OPTNAME. @@ -2961,7 +3175,7 @@ been extended in Bash. Restricts the values of OPTNAME to be those defined for the `-o' option to the `set' builtin (*note The Set Builtin::.). - If either of `-s' or `-u' is used with no OPTNAME arguments, the + If either `-s' or `-u' is used with no OPTNAME arguments, the display is limited to those options which are set or unset, respectively. @@ -2970,7 +3184,7 @@ been extended in Bash. The return status when listing options is zero if all OPTNAMES are enabled, non-zero otherwise. When setting or unsetting options, - the return status is zero unless an OPTNAME is not a legal shell + the return status is zero unless an OPTNAME is not a valid shell option. The list of `shopt' options is: @@ -3011,6 +3225,15 @@ been extended in Bash. builtin command. An interactive shell does not exit if `exec' fails. + `expand_aliases' + If set, aliases are expanded as described below< under Aliases + (*note Aliases::.). This option is enabled by default for + interactive shells. + + `extglob' + If set, the extended pattern matching features described above + (*note Pattern Matching::.) are enabled. + `histappend' If set, the history list is appended to the file named by the value of the `HISTFILE' variable when the shell exits, rather @@ -3028,10 +3251,14 @@ been extended in Bash. `hostcomplete' If set, and Readline is being used, Bash will attempt to - perform hostname completion when a word beginning with `@' is + perform hostname completion when a word containing a `@' is being completed (*note Commands For Completion::.). This option is enabled by default. + `huponexit' + If set, Bash will send `SIGHUP' to all jobs when an + interactive login shell exits (*note Signals::.). + `interactive_comments' Allow a word beginning with `#' to cause that word and all remaining characters on that line to be ignored in an @@ -3047,6 +3274,10 @@ been extended in Bash. accessed since the last time it was checked, the message `"The mail in MAILFILE has been read"' is displayed. + `nocaseglob' + If set, Bash matches filenames in a case-insensitive fashion + when performing filename expansion. + `nullglob' If set, Bash allows filename patterns which match no files to expand to a null string, rather than themselves. @@ -3064,29 +3295,44 @@ been extended in Bash. `sourcepath' If set, the `source' builtin uses the value of `PATH' to find the directory containing the file supplied as an argument. - This is enabled by default. + This option is enabled by default. + + The return status when listing options is zero if all OPTNAMES are + enabled, non-zero otherwise. When setting or unsetting options, + the return status is zero unless an OPTNAME is not a valid shell + option. + +`source' + source FILENAME + A synonym for `.' (*note Bourne Shell Builtins::.). `type' - type [-all] [-type | -path] [NAME ...] + type [-atp] [NAME ...] For each NAME, indicate how it would be interpreted if used as a command name. - If the `-type' flag is used, `type' returns a single word which is + If the `-t' option is used, `type' prints a single word which is one of `alias', `function', `builtin', `file' or `keyword', if NAME is an alias, shell function, shell builtin, disk file, or shell reserved word, respectively. If the NAME is not found, then nothing is printed, and `type' returns a failure status. - If the `-path' flag is used, `type' either returns the name of the - disk file that would be executed, or nothing if `-type' would not + If the `-p' option is used, `type' either returns the name of the + disk file that would be executed, or nothing if `-t' would not return `file'. - If the `-all' flag is used, returns all of the places that contain - an executable named FILE. This includes aliases and functions, if - and only if the `-path' flag is not also used. + If the `-a' option is used, `type' returns all of the places that + contain an executable named FILE. This includes aliases and + functions, if and only if the `-p' option is not also used. - `type' accepts `-a', `-t', and `-p' as equivalent to `-all', - `-type', and `-path', respectively. + The return status is zero if any of the NAMES are found, non-zero + if none are found. + +`typeset' + typeset [-afFrxi] [-p] [NAME[=VALUE]] + The `typeset' command is supplied for compatibility with the Korn + shell; however, it has been deprecated in favor of the `declare' + builtin command. `ulimit' ulimit [-acdflmnpstuvSH] [LIMIT] @@ -3094,46 +3340,46 @@ been extended in Bash. started by the shell, on systems that allow such control. If an option is given, it is interpreted as follows: `-S' - change and report the soft limit associated with a resource. + Change and report the soft limit associated with a resource. `-H' - change and report the hard limit associated with a resource. + Change and report the hard limit associated with a resource. `-a' - all current limits are reported. + All current limits are reported. `-c' - the maximum size of core files created. + The maximum size of core files created. `-d' - the maximum size of a process's data segment. + The maximum size of a process's data segment. `-f' - the maximum size of files created by the shell. + The maximum size of files created by the shell. `-l' The maximum size that may be locked into memory. `-m' - the maximum resident set size. + The maximum resident set size. `-n' - the maximum number of open file descriptors. + The maximum number of open file descriptors. `-p' - the pipe buffer size. + The pipe buffer size. `-s' - the maximum stack size. + The maximum stack size. `-t' - the maximum amount of cpu time in seconds. + The maximum amount of cpu time in seconds. `-u' - the maximum number of processes available to a single user. + The maximum number of processes available to a single user. `-v' - the maximum amount of virtual memory available to the process. + The maximum amount of virtual memory available to the process. If LIMIT is given, it is the new value of the specified resource. Otherwise, the current value of the soft limit for the specified @@ -3144,16 +3390,27 @@ been extended in Bash. which is in seconds, `-p', which is in units of 512-byte blocks, and `-n' and `-u', which are unscaled values. + The return status is zero unless an invalid option is supplied, a + non-numeric argument other than `unlimited' is supplied as a + LIMIT, or an error occurs while setting a new limit. + File: bashref.info, Node: The Set Builtin, Next: Bash Conditional Expressions, Prev: Bash Builtins, Up: Bash Features The Set Builtin =============== - This builtin is so overloaded that it deserves its own section. + This builtin is so complicated that it deserves its own section. `set' - set [-abefhkmnptuvxdBCHP] [-o OPTION] [ARGUMENT ...] + set [--abefhkmnptuvxBCHP] [-o OPTION] [ARGUMENT ...] + + If no options or arguments are supplied, `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: `-a' Mark variables which are modified or created for export. @@ -3164,15 +3421,18 @@ The Set Builtin prompt. `-e' - Exit immediately if a simple command exits with a non-zero - status. + Exit immediately if a simple command (*note Simple + Commands::.) exits with a non-zero status, unless the command + that fails is part of an `until' or `while' loop, part of an + `if' statement, part of a `&&' or `||' list, or if the + command's return status is being inverted using `!'. `-f' Disable file name generation (globbing). `-h' Locate and remember (hash) commands as they are looked up for - execution. + execution. This option is enabled by default. `-k' All arguments in the form of assignment statements are placed @@ -3183,29 +3443,31 @@ The Set Builtin Job control is enabled (*note Job Control::.). `-n' - Read commands but do not execute them. + 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. `-o OPTION-NAME' - Set the flag corresponding to OPTION-NAME: + Set the option corresponding to OPTION-NAME: `allexport' - same as `-a'. + Same as `-a'. `braceexpand' - same as `-B'. + Same as `-B'. `emacs' - use an `emacs'-style line editing interface (*note + Use an `emacs'-style line editing interface (*note Command Line Editing::.). `errexit' - same as `-e'. + Same as `-e'. `hashall' - same as `-h'. + Same as `-h'. `histexpand' - same as `-H'. + Same as `-H'. `history' Enable command history, as described in *Note Bash @@ -3213,84 +3475,91 @@ The Set Builtin interactive shells. `ignoreeof' - the shell will not exit upon reading EOF. + An interactive shell will not exit upon reading EOF. `keyword' - same as `-k'. + Same as `-k'. `monitor' - same as `-m'. + Same as `-m'. `noclobber' - same as `-C'. + Same as `-C'. `noexec' - same as `-n'. + Same as `-n'. `noglob' - same as `-f'. + Same as `-f'. `notify' - same as `-b'. + Same as `-b'. `nounset' - same as `-u'. + Same as `-u'. `onecmd' - same as `-t'. + Same as `-t'. `physical' - same as `-P'. + Same as `-P'. `posix' - change the behavior of Bash where the default operation + Change the behavior of Bash where the default operation differs from the POSIX 1003.2 standard to match the - standard. This is intended to make Bash behave as a - strict superset of that standard. + standard (*note Bash POSIX Mode::.). This is intended + to make Bash behave as a strict superset of that + standard. `privileged' - same as `-p'. + Same as `-p'. `verbose' - same as `-v'. + Same as `-v'. `vi' - use a `vi'-style line editing interface. + Use a `vi'-style line editing interface. `xtrace' - same as `-x'. + Same as `-x'. `-p' - Turn on privileged mode. In this mode, the `$BASH_ENV' file - is not processed, and shell functions are not inherited from - the environment. This is enabled automatically on startup if - the effective user (group) id is not equal to the real user - (group) id. Turning this option off causes the effective user - and group ids to be set to the real user and group ids. + Turn on privileged mode. In this mode, the `$BASH_ENV' and + `$ENV' files are not processed, shell functions are not + inherited from the environment, and the `SHELLOPTS' variable, + if it appears in the environment, is ignored. This is + enabled automatically on startup if the effective user + (group) id is not equal to the real user (group) id. Turning + this option off causes the effective user and group ids to be + set to the real user and group ids. `-t' Exit after reading and executing one command. `-u' - Treat unset variables as an error when substituting. + 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. `-v' Print shell input lines as they are read. `-x' - Print commands and their arguments as they are executed. + Print a trace of simple commands and their arguments after + they are expanded and before they are executed. `-B' The shell will perform brace expansion (*note Brace Expansion::.). This option is on by default. `-C' - Disallow output redirection to existing files. + Prevent output redirection using `>', `>&', and `<>' from + overwriting existing files. `-H' Enable `!' style history substitution (*note History - Interaction::.). This flag is on by default for interactive - shells. + Interaction::.). This option is on by default for + interactive shells. `-P' If set, do not follow symbolic links when performing commands @@ -3299,7 +3568,8 @@ The Set Builtin the logical chain of directories when performing commands which change the current directory. - For example, if `/usr/sys' is a link to `/usr/local/sys' then: + For example, if `/usr/sys' is a symbolic link to + `/usr/local/sys' then: $ cd /usr/sys; echo $PWD /usr/sys $ cd ..; pwd @@ -3312,7 +3582,7 @@ The Set Builtin /usr/local `--' - If no arguments follow this flag, then the positional + If no arguments follow this option, then the positional parameters are unset. Otherwise, the positional parameters are set to the ARGUMENTS, even if some of them begin with a `-'. @@ -3323,13 +3593,16 @@ The Set Builtin options are turned off. If there are no arguments, the positional parameters remain unchanged. - Using `+' rather than `-' causes these flags to be turned off. - The flags can also be used upon invocation of the shell. The - current set of flags may be found in `$-'. + Using `+' rather than `-' 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 `$-'. The remaining N ARGUMENTS are positional parameters and are - assigned, in order, to `$1', `$2', ... `$N'. If no arguments are - given, all shell variables are printed. + assigned, in order, to `$1', `$2', ... `$N'. The special + parameter `#' is set to N. + + The return status is always zero unless an invalid option is + supplied. File: bashref.info, Node: Bash Conditional Expressions, Next: Bash Variables, Prev: The Set Builtin, Up: Bash Features @@ -3337,14 +3610,17 @@ File: bashref.info, Node: Bash Conditional Expressions, Next: Bash Variables, Bash Conditional Expressions ============================ - Conditional expressions are used by the `test' and `[' builtins. + Conditional expressions are used by the `[[' compound command and +the `test' and `[' 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. Each operator and operand must -be a separate argument. If FILE is of the form `/dev/fd/N', then file -descriptor N is checked. Expressions are composed of the following -primaries: +numeric comparison operators as well. If any FILE argument to one of +the primaries is of the form `/dev/fd/N', then file descriptor N is +checked. + +`-a FILE' + True if FILE exists. `-b FILE' True if FILE exists and is a block special file. @@ -3362,16 +3638,13 @@ primaries: True if FILE exists and is a regular file. `-g FILE' - True if FILE exists and is set-group-id. + True if FILE exists and its set-group-id bit is set. `-k FILE' - True if FILE has its "sticky" bit set. - -`-L FILE' - True if FILE exists and is a symbolic link. + True if FILE exists and its "sticky" bit is set. `-p FILE' - True if FILE exists and is a named pipe. + True if FILE exists and is a named pipe (FIFO). `-r FILE' True if FILE exists and is readable. @@ -3379,11 +3652,8 @@ primaries: `-s FILE' True if FILE exists and has a size greater than zero. -`-S FILE' - True if FILE exists and is a socket. - `-t FD' - True if FD is opened on a terminal. + True if file descriptor FD is open and refers to a terminal. `-u FILE' True if FILE exists and its set-user-id bit is set. @@ -3400,6 +3670,15 @@ primaries: `-G FILE' True if FILE exists and is owned by the effective group id. +`-L FILE' + True if FILE exists and is a symbolic link. + +`-S FILE' + True if FILE exists and is a socket. + +`-N FILE' + True if FILE exists and has been modified since it was last read. + `FILE1 -nt FILE2' True if FILE1 is newer (according to modification date) than FILE2. @@ -3421,26 +3700,19 @@ primaries: `STRING' True if the length of STRING is non-zero. -`STRING1 = STRING2' - True if the strings are equal. `==' may be used in place of `='. +`STRING1 == STRING2' + True if the strings are equal. `=' may be used in place of `=='. `STRING1 != STRING2' True if the strings are not equal. `STRING1 < STRING2' - True if STRING1 sorts before STRING2 lexicographically. + True if STRING1 sorts before STRING2 lexicographically in the + current locale. `STRING1 > STRING2' - True if STRING1 sorts after STRING2 lexicographically. - -`! EXPR' - True if EXPR is false. - -`EXPR1 -a EXPR2' - True if both EXPR1 and EXPR2 are true. - -`EXPR1 -o EXPR2' - True if either EXPR1 and EXPR2 is true. + True if STRING1 sorts after STRING2 lexicographically in the + current locale. `ARG1 OP ARG2' `OP' is one of `-eq', `-ne', `-lt', `-le', `-gt', or `-ge'. These @@ -3449,44 +3721,6 @@ primaries: greater than or equal to ARG2, respectively. ARG1 and ARG2 may be positive or negative integers. - The Bash `test' and `[' builtins evaluate conditional expressions -using a set of rules based on the number of arguments. These are the -rules: - -0 arguments - The expression is false. - -1 argument - The expression is true if and only if the argument is not null. - -2 arguments - If the first argument is `!', the expression is true if and only - if the second argument is null. If the first argument is one of - the listed unary operators, the expression is true if the unary - test is true. If the first argument is not a legal unary - operator, the expression is false. - -3 arguments - If the first argument is `!', the value is the negation of the - two-argument test using the second and third arguments. If the - second argument is one of the binary operators, the result of the - expression is the result of the binary test using the first and - third arguments as operands. If the first argument is exactly `(' - and the third argument is exactly `)', the result is the - one-argument test of the second argument. Otherwise, the - expression is false. The `-a' and `-o' operators are considered - binary operators in this case. - -4 arguments - If the first argument is `!', the result is the negation of the - three-argument expression composed of the remaining arguments. - Otherwise, the expression is parsed and evaluated according to - precedence. `-a' has a higher precedence than `-o'. - -5 or more arguments - The expression is parsed and evaluated according to precedence, - with `-a' having a higher precedence than `-o'. - File: bashref.info, Node: Bash Variables, Next: Shell Arithmetic, Prev: Bash Conditional Expressions, Up: Bash Features @@ -3496,49 +3730,95 @@ Bash Variables These variables are set or used by Bash, but other shells do not normally treat them specially. +`BASH' + The full pathname used to execute the current instance of Bash. + `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. *Note Bash Startup Files::. -`TIMEFORMAT' - The value of this parameter is used as a format string specifying - how the timing information for pipelines prefixed with the `time' - reserved word should be displayed. The `%' character introduces an - escape sequence that is expanded to a time value or other - information. The escape sequences and their meanings are as - follows; the braces denote optional portions. +`BASH_VERSION' + The version number of the current instance of Bash. - `%%' - A literal `%'. +`BASH_VERSINFO' + A readonly array variable whose members hold version information + for this instance of Bash. The values assigned to the array + members are as follows: - `%[P][l]R' - The elapsed time in seconds. + `BASH_VERSINFO[0]' + The major version number (the RELEASE). - `%[P][l]U' - The number of CPU seconds spent in user mode. + `BASH_VERSINFO[1]' + The minor version number (the VERSION). - `%[P][l]S' - The number of CPU seconds spent in system mode. + `BASH_VERSINFO[2]' + The patch level. - `%P' - The CPU percentage, computed as (%U + %S) / %R. + `BASH_VERSINFO[3]' + The build version. - The optional P is a digit specifying the precision, the number of - fractional digits after a decimal point. A value of 0 causes no - decimal point or fraction to be output. At most three places - after the decimal point may be specified; values of P greater than - 3 are changed to 3. If P is not specified, the value 3 is used. + `BASH_VERSINFO[4]' + The release status (e.g., BETA1). - The optional `l' specifies a longer format, including minutes, of - the form MMmSS.FFs. The value of P determines whether or not the - fraction is included. + `BASH_VERSINFO[5]' + The value of `MACHTYPE'. - If this variable is not set, bash acts as if it had the value - `$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS''. - If the value is null, no timing information is displayed. A - trailing newline is added when the format string is displayed. +`DIRSTACK' + An array variable (*note Arrays::.) containing the current + contents of the directory stack. Directories appear in the stack + in the order they are displayed by the `dirs' builtin. Assigning + to members of this array variable may be used to modify + directories already in the stack, but the `pushd' and `popd' + builtins must be used to add and remove directories. Assignment + to this variable will not change the current directory. If + `DIRSTACK' is unset, it loses its special properties, even if it + is subsequently reset. + +`EUID' + The numeric effective user id of the current user. This variable + is readonly. + +`FCEDIT' + The editor used as a default by the `-e' option to the `fc' + builtin command. + +`FIGNORE' + A colon-separated list of suffixes to ignore when performing + filename completion. A file name whose suffix matches one of the + entries in `FIGNORE' is excluded from the list of matched file + names. A sample value is `.o:~' + +`GLOBIGNORE' + A colon-separated list of patterns defining the set of filenames to + be ignored by filename expansion. If a filename matched by a + filename expansion pattern also matches one of the patterns in + `GLOBIGNORE', it is removed from the list of matches. + +`GROUPS' + An array variable containing the list of groups of which the + current user is a member. This variable is readonly. + +`histchars' + Up to three characters which control history expansion, quick + substitution, and tokenization (*note History Interaction::.). + The first character is the "history-expansion-char", that is, the + character which signifies the start of a history expansion, + normally `!'. The second character is the character which + signifies `quick substitution' when seen as the first character on + a line, normally `^'. The optional third character is the + character which indicates that the remainder of the line is a + comment when found as the first character of a word, usually `#'. + The history comment character causes history substitution to be + skipped for the remaining words on the line. It does not + necessarily cause the shell parser to treat the rest of the line + as a comment. + +`HISTCMD' + The history number, or index in the history list, of the current + command. If `HISTCMD' is unset, it loses its special properties, + even if it is subsequently reset. `HISTCONTROL' Set to a value of `ignorespace', it means don't enter lines which @@ -3546,7 +3826,9 @@ normally treat them specially. of `ignoredups', it means don't enter lines which match the last entered line. A value of `ignoreboth' combines the two options. Unset, or set to any other value than those above, means to save - all lines on the history list. + all lines on the history list. 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 `HISTCONTROL'. `HISTIGNORE' A colon-separated list of patterns used to decide which command @@ -3557,7 +3839,9 @@ normally treat them specially. applied. In addition to the normal shell pattern matching characters, `&' matches the previous history line. `&' may be escaped using a backslash. The backslash is removed before - attempting a match. + 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 `HISTIGNORE'. `HISTIGNORE' subsumes the function of `HISTCONTROL'. A pattern of `&' is identical to `ignoredups', and a pattern of `[ ]*' is @@ -3570,8 +3854,8 @@ normally treat them specially. default is `~/.bash_history'. `HISTSIZE' - If set, this is the maximum number of commands to remember in the - history. + The maximum number of commands to remember on the history list. + The default value is 500. `HISTFILESIZE' The maximum number of lines contained in the history file. When @@ -3580,26 +3864,6 @@ normally treat them specially. default value is 500. The history file is also truncated to this size after writing it when an interactive shell exits. -`histchars' - Up to three characters which control history expansion, quick - substitution, and tokenization (*note History Interaction::.). - The first character is the "history-expansion-char", that is, the - character which signifies the start of a history expansion, - normally `!'. The second character is the character which - signifies `quick substitution' when seen as the first character on - a line, normally `^'. The optional third character is the - character which signifies the remainder of the line is a comment, - when found as the first character of a word, usually `#'. The - history comment character causes history substitution to be - skipped for the remaining words on the line. It does not - necessarily cause the shell parser to treat the rest of the line - as a comment. - -`HISTCMD' - The history number, or index in the history list, of the current - command. If `HISTCMD' is unset, it loses its special properties, - even if it is subsequently reset. - `HOSTFILE' Contains the name of a file in the same format as `/etc/hosts' that should be read when the shell needs to complete a hostname. You @@ -3607,165 +3871,180 @@ normally treat them specially. complete a hostname, Bash will add the contents of the new file to the already existing database. -`MAILCHECK' - How often (in seconds) that the shell should check for mail in the - files specified in `MAILPATH'. +`HOSTNAME' + The name of the current host. -`PROMPT_COMMAND' - If present, this contains a string which is a command to execute - before the printing of each primary prompt (`$PS1'). +`HOSTTYPE' + A string describing the machine Bash is running on. -`UID' - The numeric real user id of the current user. +`IGNOREEOF' + Controls the action of the shell on receipt of an `EOF' character + as the sole input. If set, the value denotes the number of + consecutive `EOF' characters that can be read as the first + character on an input line before the shell will exit. If the + variable exists but does not have a numeric value (or has no + value) then the default is 10. If the variable does not exist, + then `EOF' signifies the end of input to the shell. This is only + in effect for interactive shells. -`EUID' - The numeric effective user id of the current user. +`INPUTRC' + The name of the Readline startup file, overriding the default of + `~/.inputrc'. -`GROUPS' - An array variable containing the list of groups of which the - current user is a member. +`LANG' + Used to determine the locale category for any category not + specifically selected with a variable starting with `LC_'. -`PPID' - The process id of the shell's parent process. +`LC_ALL' + This variable overrides the value of `LANG' and any other `LC_' + variable specifying a locale category. -`HOSTNAME' - The name of the current host. +`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 (*note Filename + Expansion::.). -`HOSTTYPE' - A string describing the machine Bash is running on. +`LC_CTYPE' + This variable determines the interpretation of characters and the + behavior of character classes within filename expansion and pattern + matching (*note Filename Expansion::.). -`OSTYPE' - A string describing the operating system Bash is running on. +`LC_MESSAGES' + This variable determines the locale used to translate double-quoted + strings preceded by a `$' (*note Locale Translation::.). + +`LINENO' + The line number in the script or shell function currently + executing. `MACHTYPE' A string that fully describes the system type on which Bash is executing, in the standard GNU CPU-COMPANY-SYSTEM format. -`SHELLOPTS' - A colon-separated list of enabled shell options. Each word in the - list is a valid argument for the `-o' option to the `set' builtin - command (*note The Set Builtin::.). The options appearing in - `SHELLOPTS' are those reported as `on' by `set -o'. If this - variable is in the environment when Bash starts up, each shell - option in the list will be enabled before reading any startup - files. This variable is readonly. +`MAILCHECK' + How often (in seconds) that the shell should check for mail in the + files specified in the `MAILPATH' or `MAIL' variables. -`FIGNORE' - A colon-separated list of suffixes to ignore when performing - filename completion. A file name whose suffix matches one of the - entries in `FIGNORE' is excluded from the list of matched file - names. A sample value is `.o:~' +`OLDPWD' + The previous working directory as set by the `cd' builtin. -`GLOBIGNORE' - A colon-separated list of patterns defining the set of filenames to - be ignored by filename expansion. If a filename matched by a - filename expansion pattern also matches one of the patterns in - `GLOBIGNORE', it is removed from the list of matches. +`OPTERR' + If set to the value 1, Bash displays error messages generated by + the `getopts' builtin command. -`DIRSTACK' - An array variable (*note Arrays::.) containing the current - contents of the directory stack. Directories appear in the stack - in the order they are displayed by the `dirs' builtin. Assigning - to members of this array variable may be used to modify - directories already in the stack, but the `pushd' and `popd' - builtins must be used to add and remove directories. Assignment - to this variable will not change the current directory. If - `DIRSTACK' is unset, it loses its special properties, even if it - is subsequently reset. +`OSTYPE' + A string describing the operating system Bash is running on. `PIPESTATUS' An array variable (*note Arrays::.) containing a list of exit status values from the processes in the most-recently-executed foreground pipeline (which may contain only a single command). -`INPUTRC' - The name of the Readline startup file, overriding the default of - `~/.inputrc'. - -`BASH' - The full filename used to execute the current instance of Bash. +`PPID' + The process id of the shell's parent process. This variable is + readonly. -`BASH_VERSION' - The version number of the current instance of Bash. +`PROMPT_COMMAND' + If present, this contains a string which is a command to execute + before the printing of each primary prompt (`$PS1'). -`BASH_VERSINFO' - An array variable whose members hold version information for this - instance of Bash. The values assigned to the array members are as - follows: +`PS3' + The value of this variable is used as the prompt for the `select' + command. If this variable is not set, the `select' command + prompts with `#? ' - `BASH_VERSINFO[0]' - The major version number (the RELEASE). +`PS4' + This is the prompt printed before the command line is echoed when + the `-x' option is set (*note The Set Builtin::.). The first + character of `PS4' is replicated multiple times, as necessary, to + indicate multiple levels of indirection. The default is `+ '. - `BASH_VERSINFO[1]' - The minor version number (the VERSION). +`PWD' + The current working directory as set by the `cd' builtin. - `BASH_VERSINFO[2]' - The patch level. +`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. - `BASH_VERSINFO[3]' - The build version. +`REPLY' + The default variable for the `read' builtin. - `BASH_VERSINFO[4]' - The release status (e.g., BETA1). +`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. - `BASH_VERSINFO[5]' - The value of `MACHTYPE'. +`SHELLOPTS' + A colon-separated list of enabled shell options. Each word in the + list is a valid argument for the `-o' option to the `set' builtin + command (*note The Set Builtin::.). The options appearing in + `SHELLOPTS' are those reported as `on' by `set -o'. If this + variable is in the environment when Bash starts up, each shell + option in the list will be enabled before reading any startup + files. This variable is readonly. `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. -`OPTERR' - If set to the value 1, Bash displays error messages generated by - the `getopts' builtin command. +`TIMEFORMAT' + The value of this parameter is used as a format string specifying + how the timing information for pipelines prefixed with the `time' + reserved word should be displayed. The `%' character introduces an + escape sequence that is expanded to a time value or other + information. The escape sequences and their meanings are as + follows; the braces denote optional portions. -`LANG' - Used to determine the locale category for any category not - specifically selected with a variable starting with `LC_'. + `%%' + A literal `%'. -`LC_ALL' - This variable overrides the value of `LANG' and any other `LC_' - variable specifying a locale category. + `%[P][l]R' + The elapsed time in seconds. -`LC_COLLATE' - This variable determines the collation order used when sorting the - results of filename expansion (*note Filename Expansion::.). + `%[P][l]U' + The number of CPU seconds spent in user mode. -`LC_MESSAGES' - This variable determines the locale used to translate double-quoted - strings preceded by a `$' (*note Locale Translation::.). + `%[P][l]S' + The number of CPU seconds spent in system mode. -`IGNOREEOF' - Controls the action of the shell on receipt of an `EOF' character - as the sole input. If set, then the value of it is the number of - consecutive `EOF' characters that can be read as the first - character on an input line before the shell will exit. If the - variable exists but does not have a numeric value (or has no - value) then the default is 10. If the variable does not exist, - then `EOF' signifies the end of input to the shell. This is only - in effect for interactive shells. + `%P' + The CPU percentage, computed as (%U + %S) / %R. - -File: bashref.info, Node: Shell Arithmetic, Next: Arrays, Prev: Bash Variables, Up: Bash Features + The optional P is a digit specifying the precision, the number of + fractional digits after a decimal point. A value of 0 causes no + decimal point or fraction to be output. At most three places + after the decimal point may be specified; values of P greater than + 3 are changed to 3. If P is not specified, the value 3 is used. -Shell Arithmetic -================ + The optional `l' specifies a longer format, including minutes, of + the form MMmSS.FFs. The value of P determines whether or not the + fraction is included. -* Menu: + If this variable is not set, Bash acts as if it had the value + `$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'' + If the value is null, no timing information is displayed. A + trailing newline is added when the format string is displayed. -* Arithmetic Evaluation:: How shell arithmetic works. -* Arithmetic Expansion:: How to use arithmetic in shell expansions. -* Arithmetic Builtins:: Builtin commands that use shell arithmetic. +`TMOUT' + If set to a value greater than zero, the value is interpreted as + the number of seconds to wait for input after issuing the primary + prompt. Bash terminates after that number of seconds if input does + not arrive. - Bash includes several mechanisms to evaluate arithmetic expressions -and display the result or use it as part of a command. +`UID' + The numeric real user id of the current user. This variable is + readonly. -File: bashref.info, Node: Arithmetic Evaluation, Next: Arithmetic Expansion, Up: Shell Arithmetic +File: bashref.info, Node: Shell Arithmetic, Next: Aliases, Prev: Bash Variables, Up: Bash Features -Arithmetic Evaluation ---------------------- +Shell Arithmetic +================ The shell allows arithmetic expressions to be evaluated, as one of the shell expansions or by the `let' builtin. @@ -3781,6 +4060,9 @@ The levels are listed in order of decreasing precedence. `! ~' logical and bitwise negation +`**' + exponentiation + `* / %' multiplication, division, remainder @@ -3838,43 +4120,83 @@ parentheses are evaluated first and may override the precedence rules above. -File: bashref.info, Node: Arithmetic Expansion, Next: Arithmetic Builtins, Prev: Arithmetic Evaluation, Up: Shell Arithmetic +File: bashref.info, Node: Aliases, Next: Arrays, Prev: Shell Arithmetic, Up: Bash Features -Arithmetic Expansion --------------------- +Aliases +======= - Arithmetic expansion allows the evaluation of an arithmetic -expression and the substitution of the result. The format for -arithmetic expansion is: +* Menu: - $(( EXPRESSION )) +* Alias Builtins:: Builtins commands to maniuplate aliases. - The expression is treated as if it were within double quotes, but a -double quote inside the braces or parentheses is not treated specially. -All tokens in the expression undergo parameter expansion, command -substitution, and quote removal. Arithmetic substitutions may be -nested. + 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 `alias' and `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 `='. The first word of the replacement +text is tested for aliases, but a word that is identical to an alias +being expanded is not expanded a second time. This means that one may +alias `ls' to `"ls -F"', for instance, and Bash does not try to +recursively expand the replacement text. If the last character of the +alias value is a space or tab character, then the next command word +following the alias is also checked for alias expansion. + + Aliases are created and listed with the `alias' command, and removed +with the `unalias' command. + + There is no mechanism for using arguments in the replacement text, +as in `csh'. If arguments are needed, a shell function should be used +(*note Shell Functions::.). + + Aliases are not expanded when the shell is not interactive, unless +the `expand_aliases' shell option is set using `shopt' (*note Bash +Builtins::.). + + The rules concerning the definition and use of aliases are somewhat +confusing. Bash always reads at least one complete line of input +before executing any of the commands on that line. Aliases are +expanded when a command is read, not when it is executed. Therefore, an +alias definition appearing on the same line as another command does not +take effect until the next line of input is read. The commands +following the alias definition on that line are not affected by the new +alias. This behavior is also an issue when functions are executed. +Aliases are expanded when 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 `alias' +in compound commands. - The evaluation is performed according to the rules listed above. If -the expression is invalid, Bash prints a message indicating failure and -no substitution occurs. + For almost every purpose, aliases are superseded by shell functions. -File: bashref.info, Node: Arithmetic Builtins, Prev: Arithmetic Expansion, Up: Shell Arithmetic +File: bashref.info, Node: Alias Builtins, Up: Aliases -Arithmetic Builtins -------------------- +Alias Builtins +-------------- -`let' - let EXPRESSION [EXPRESSION] - The `let' builtin allows arithmetic to be performed on shell - variables. Each EXPRESSION is evaluated according to the rules - given previously (*note Arithmetic Evaluation::.). If the last - EXPRESSION evaluates to 0, `let' returns 1; otherwise 0 is - returned. +`alias' + alias [`-p'] [NAME[=VALUE] ...] + + Without arguments or with the `-p' option, `alias' prints the list + of aliases on the standard output in a form that allows them to be + reused as input. If arguments are supplied, an alias is defined + for each NAME whose VALUE is given. If no VALUE is given, the name + and value of the alias is printed. + +`unalias' + unalias [-a] [NAME ... ] + + Remove each NAME from the list of aliases. If `-a' is supplied, + all aliases are removed. -File: bashref.info, Node: Arrays, Next: Printing a Prompt, Prev: Shell Arithmetic, Up: Bash Features +File: bashref.info, Node: Arrays, Next: The Directory Stack, Prev: Aliases, Up: Bash Features Arrays ====== @@ -3927,9 +4249,9 @@ is the number of elements in the array. Referencing an array variable without a subscript is equivalent to referencing element zero. The `unset' builtin is used to destroy arrays. `unset' -NAME[SUBSCRIPT] destroys the array element at index SUBSCRIPT. `unset' -NAME, where NAME is an array, removes the entire array. A subscript of -`*' or `@' also removes the entire array. +`name[SUBSCRIPT]' destroys the array element at index SUBSCRIPT. +`unset' NAME, where NAME is an array, removes the entire array. A +subscript of `*' or `@' also removes the entire array. The `declare', `local', and `readonly' builtins each accept a `-a' option to specify an array. The `read' builtin accepts a `-a' option @@ -3939,85 +4261,181 @@ The `set' and `declare' builtins display array values in a way that allows them to be reused as input. -File: bashref.info, Node: Printing a Prompt, Next: The Restricted Shell, Prev: Arrays, Up: Bash Features +File: bashref.info, Node: The Directory Stack, Next: Printing a Prompt, Prev: Arrays, Up: Bash Features + +The Directory Stack +=================== + + The directory stack is a list of recently-visited directories. The +`pushd' builtin adds directories to the stack as it changes the current +directory, and the `popd' builtin removes specified directories from +the stack and changes the current directory to the directory removed. +The `dirs' builtin displays the contents of the directory stack. + + The contents of the directory stack are also visible as the value of +the `DIRSTACK' shell variable. + +`dirs' + dirs [+N | -N] [-clvp] + Display the list of currently remembered directories. Directories + are added to the list with the `pushd' command; the `popd' command + removes directories from the list. + `+N' + Displays the Nth directory (counting from the left of the + list printed by `dirs' when invoked without options), starting + with zero. + + `-N' + Displays the Nth directory (counting from the right of the + list printed by `dirs' when invoked without options), starting + with zero. + + `-c' + Clears the directory stack by deleting all of the elements. + + `-l' + Produces a longer listing; the default listing format uses a + tilde to denote the home directory. + + `-p' + Causes `dirs' to print the directory stack with one entry per + line. + + `-v' + Causes `dirs' to print the directory stack with one entry per + line, prefixing each entry with its index in the stack. + +`popd' + popd [+N | -N] [-n] + + Remove the top entry from the directory stack, and `cd' to the new + top directory. When no arguments are given, `popd' removes the + top directory from the stack and performs a `cd' to the new top + directory. The elements are numbered from 0 starting at the first + directory listed with `dirs'; i.e., `popd' is equivalent to `popd + +0'. + `+N' + Removes the Nth directory (counting from the left of the list + printed by `dirs'), starting with zero. + + `-N' + Removes the Nth directory (counting from the right of the + list printed by `dirs'), starting with zero. + + `-n' + Suppresses the normal change of directory when removing + directories from the stack, so that only the stack is + manipulated. + +`pushd' + pushd [DIR | +N | -N] [-n] + + Save the current directory on the top of the directory stack and + then `cd' to DIR. With no arguments, `pushd' exchanges the top + two directories. + + `+N' + Brings the Nth directory (counting from the left of the list + printed by `dirs', starting with zero) to the top of the list + by rotating the stack. + + `-N' + Brings the Nth directory (counting from the right of the list + printed by `dirs', starting with zero) to the top of the list + by rotating the stack. + + `-n' + Suppresses the normal change of directory when adding + directories to the stack, so that only the stack is + manipulated. + + `DIR' + Makes the current working directory be the top of the stack, + and then executes the equivalent of ``cd' DIR'. `cd's to DIR. + + +File: bashref.info, Node: Printing a Prompt, Next: The Restricted Shell, Prev: The Directory Stack, Up: Bash Features Controlling the Prompt ====================== The value of the variable `PROMPT_COMMAND' is examined just before Bash prints each primary prompt. If it is set and non-null, then the -value is executed just as if you had typed it on the command line. +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: `\a' - a bell character. + A bell character. `\d' - the date, in "Weekday Month Date" format (e.g., "Tue May 26"). + The date, in "Weekday Month Date" format (e.g., "Tue May 26"). `\e' - an escape character. + An escape character. `\h' - the hostname, up to the first `.'. + The hostname, up to the first `.'. `\H' - the hostname. + The hostname. `\n' - newline. + A newline. + +`\r' + A carriage return. `\s' - the name of the shell, the basename of `$0' (the portion following + The name of the shell, the basename of `$0' (the portion following the final slash). `\t' - the time, in 24-hour HH:MM:SS format. + 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:SS format. `\@' - the time, in 12-hour am/pm format. + The time, in 12-hour am/pm format. + +`\u' + The username of the current user. `\v' - the version of Bash (e.g., 2.00) + The version of Bash (e.g., 2.00) `\V' - the release of Bash, version + patchlevel (e.g., 2.00.0) + The release of Bash, version + patchlevel (e.g., 2.00.0) `\w' - the current working directory. + The current working directory. `\W' - the basename of `$PWD'. - -`\u' - your username. + The basename of `$PWD'. `\!' - the history number of this command. + The history number of this command. `\#' - the command number of this command. + The command number of this command. `\$' - if the effective uid is 0, `#', otherwise `$'. + If the effective uid is 0, `#', otherwise `$'. -`\nnn' - the character corresponding to the octal number `nnn'. +`\NNN' + The character whose ASCII code is the octal value NNN. `\\' - a backslash. + A backslash. `\[' - begin a sequence of non-printing characters. This could be used to + Begin a sequence of non-printing characters. This could be used to embed a terminal control sequence into the prompt. `\]' - end a sequence of non-printing characters. + End a sequence of non-printing characters. File: bashref.info, Node: The Restricted Shell, Next: Bash POSIX Mode, Prev: Printing a Prompt, Up: Bash Features @@ -4042,6 +4460,9 @@ with the exception that the following are disallowed: * Importing function definitions from the shell environment at startup. + * Parsing the value of `SHELLOPTS' from the shell environment at + startup. + * Redirecting output using the `>', `>|', `<>', `>&', `&>', and `>>' redirection operators. @@ -4052,7 +4473,7 @@ with the exception that the following are disallowed: * Specifying the `-p' option to the `command' builtin. - * Turning off restricted mode with `set +r'. + * Turning off restricted mode with `set +r' or `set +o restricted'. File: bashref.info, Node: Bash POSIX Mode, Prev: The Restricted Shell, Up: Bash Features @@ -4080,11 +4501,11 @@ specified by POSIX.2 in areas where the Bash default differs. 5. The POSIX.2 `PS1' and `PS2' expansions of `!' to the history number and `!!' to `!' are enabled, and parameter expansion is - performed on the value regardless of the setting of the - `promptvars' option. + performed on the values of `PS1' and `PS2' regardless of the + setting of the `promptvars' option. - 6. Interactive comments are enabled by default. (Note that Bash has - them on by default anyway.) + 6. Interactive comments are enabled by default. (Bash has them on by + default anyway.) 7. The POSIX.2 startup files are executed (`$ENV') rather than the normal Bash files. @@ -4101,42 +4522,51 @@ specified by POSIX.2 in areas where the Bash default differs. 11. Non-interactive shells exit if FILENAME in `.' FILENAME is not found. - 12. Redirection operators do not perform filename expansion on the word + 12. Non-interactive shells exit if a syntax error in an arithmetic + expansion results in an invalid expression. + + 13. Redirection operators do not perform filename expansion on the word in the redirection unless the shell is interactive. - 13. Function names must be valid shell `name's. That is, they may not + 14. Function names must be valid shell `name's. That is, they may not contain characters other than letters, digits, and underscores, and - may not start with a digit. Declaring a function with an illegal + may not start with a digit. Declaring a function with an invalid name causes a fatal syntax error in non-interactive shells. - 14. POSIX.2 `special' builtins are found before shell functions during + 15. POSIX.2 `special' builtins are found before shell functions during command lookup. - 15. If a POSIX.2 special builtin returns an error status, a + 16. If a POSIX.2 special builtin returns an error status, a non-interactive shell exits. The fatal errors are those listed in the POSIX.2 standard, and include things like passing incorrect options, redirection errors, variable assignment errors for assignments preceding the command name, and so on. - 16. If the `cd' builtin finds a directory to change to using + 17. If the `cd' builtin finds a directory to change to using `$CDPATH', the value it assigns to the `PWD' variable does not contain any symbolic links, as if `cd -P' had been executed. - 17. A non-interactive shell exits with an error status if a variable + 18. If `$CDPATH' is set, the `cd' builtin will not implicitly append + the current directory to it. This means that `cd' will fail if no + valid directory name can be constructed from any of the entries in + `$CDPATH', even if the a directory with the same name as the name + given as an argument to `cd' exists in the current directory. + + 19. 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. + trying to assign a value to a readonly variable. - 18. A non-interactive shell exits with an error status if the iteration + 20. 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. + `select' statement is a readonly variable. - 19. Process substitution is not available. + 21. Process substitution is not available. - 20. Assignment statements preceding POSIX.2 `special' builtins persist + 22. Assignment statements preceding POSIX.2 special builtins persist in the shell environment after the builtin completes. - 21. The `export' and `readonly' builtin commands display their output + 23. The `export' and `readonly' builtin commands display their output in the format required by POSIX.2. @@ -4152,7 +4582,7 @@ File: bashref.info, Node: Job Control, Next: Using History Interactively, Pre Job Control *********** - This chapter disusses what job control is, how it works, and how + This chapter discusses what job control is, how it works, and how Bash allows you to access its facilities. * Menu: @@ -4176,8 +4606,7 @@ interface supplied jointly by the system's terminal driver and Bash. The shell associates a JOB with each pipeline. It keeps a table of currently executing jobs, which may be listed with the `jobs' command. -When Bash starts a job asynchronously (in the background), it prints a -line that looks like: +When Bash starts a job asynchronously, it prints a line that looks like: [1] 25647 indicating that this job is job number 1 and that the process ID of the @@ -4199,16 +4628,17 @@ signal by the terminal driver, which, unless caught, suspends the process. If the operating system on which Bash is running supports job -control, Bash allows you to use it. Typing the SUSPEND character -(typically `^Z', Control-Z) while a process is running causes that -process to be stopped and returns you to Bash. Typing the DELAYED -SUSPEND character (typically `^Y', Control-Y) causes the process to be -stopped when it attempts to read input from the terminal, and control to -be returned to Bash. You may then manipulate the state of this job, -using the `bg' command to continue it in the background, the `fg' -command to continue it in the foreground, or the `kill' command to kill -it. A `^Z' takes effect immediately, and has the additional side -effect of causing pending output and typeahead to be discarded. +control, Bash contains facilities to use it. Typing the SUSPEND +character (typically `^Z', Control-Z) while a process is running causes +that process to be stopped and returns control to Bash. Typing the +DELAYED SUSPEND character (typically `^Y', Control-Y) causes the +process to be stopped when it attempts to read input from the terminal, +and control to be returned to Bash. The user then manipulates the +state of this job, using the `bg' command to continue it in the +background, the `fg' command to continue it in the foreground, or the +`kill' command to kill it. A `^Z' takes effect immediately, and has +the additional side effect of causing pending output and typeahead to +be discarded. There are a number of ways to refer to a job in the shell. The character `%' introduces a job name. Job number `n' may be referred to @@ -4219,10 +4649,10 @@ other hand, refers to any job containing the string `ce' in its command line. If the prefix or substring matches more than one job, Bash reports an error. The symbols `%%' and `%+' refer to the shell's notion of the current job, which is the last job stopped while it was -in the foreground. The previous job may be referenced using `%-'. In -output pertaining to jobs (e.g., the output of the `jobs' command), the -current job is always flagged with a `+', and the previous job with a -`-'. +in the foreground or started in the background. The previous job may +be referenced using `%-'. In output pertaining to jobs (e.g., the +output of the `jobs' command), the current job is always flagged with a +`+', and the previous job with a `-'. Simply naming a job can be used to bring it into the foreground: `%1' is a synonym for `fg %1', bringing job 1 from the background into @@ -4232,14 +4662,14 @@ equivalent to `bg %1' The shell learns immediately whenever a job changes state. Normally, Bash waits until it is about to print a prompt before reporting changes in a job's status so as to not interrupt any other -output. If the the `-b' option to the `set' builtin is set, Bash +output. If the the `-b' option to the `set' builtin is enabled, Bash reports such changes immediately (*note The Set Builtin::.). - If you attempt to exit Bash while jobs are stopped, the shell prints -a message warning you that you have stopped jobs. You may then use the -`jobs' command to inspect their status. If you do this, or try to exit -again immediately, you are not warned again, and the stopped jobs are -terminated. + If an attempt to exit Bash is while jobs are stopped, the shell +prints a message warning that there are stopped jobs. The `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. File: bashref.info, Node: Job Control Builtins, Next: Job Control Variables, Prev: Job Control Basics, Up: Job Control @@ -4249,27 +4679,35 @@ Job Control Builtins `bg' bg [JOBSPEC] - Place JOBSPEC into the background, as if it had been started with - `&'. If JOBSPEC is not supplied, the current job is used. + Resume the suspended job JOBSPEC in the background, as if it had + been started with `&'. If 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 + JOBSPEC was not found or JOBSPEC specifies a job that was started + without job control. `fg' fg [JOBSPEC] - Bring JOBSPEC into the foreground and make it the current job. If - JOBSPEC is not supplied, the current job is used. + Resume the job JOBSPEC in the foreground and make it the current + job. If 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, JOBSPEC does not specify a valid job or + JOBSPEC specifies a job that was started without job control. `jobs' jobs [-lpnrs] [JOBSPEC] - jobs -x COMMAND [JOBSPEC] + jobs -x COMMAND [ARGUMENTS] The first form lists the active jobs. The options have the following meanings: `-l' - List process IDs in addition to the normal information + List process IDs in addition to the normal information. `-n' Display information only about jobs that have changed status - since you were last notified of their status. + since the user was last notified of their status. `-p' List only the process ID of the job's process group leader. @@ -4290,30 +4728,41 @@ Job Control Builtins status. `kill' - kill [-s SIGSPEC] [-n SIGNUM] [-SIGSPEC] JOBSPEC - kill -l [SIGSPEC] + kill [-s SIGSPEC] [-n SIGNUM] [-SIGSPEC] JOBSPEC or PID + kill -l [EXIT_STATUS] Send a signal specified by SIGSPEC or SIGNUM to the process named - by JOBSPEC. SIGSPEC is either a signal name such as `SIGINT' - (with or without the `SIG' prefix) or a signal number; SIGNUM is a - signal number. If SIGSPEC and SIGNUM are not present, `SIGTERM' - is used. The `-l' option lists the signal names, or the signal - name corresponding to SIGSPEC. + by job specification JOBSPEC or process ID PID. SIGSPEC is either + a signal name such as `SIGINT' (with or without the `SIG' prefix) + or a signal number; SIGNUM is a signal number. If SIGSPEC and + SIGNUM are not present, `SIGTERM' is used. The `-l' option lists + the signal names. If any arguments are supplied when `-l' is + given, the names of the signals corresponding to the arguments are + listed, and the return status is zero. 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. `wait' wait [JOBSPEC|PID] Wait until the child process specified by process ID PID or job - specification JOBSPEC exits and report its exit status. If a job - spec is given, all processes in the job are waited for. If no - arguments are given, all currently active child processes are - waited for. + specification 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 JOBSPEC nor PID specifies an active child process + of the shell, the return status is 127. `disown' - disown [-h] [JOBSPEC ...] + disown [-ar] [-h] [JOBSPEC ...] Without options, each JOBSPEC is removed from the table of active jobs. If the `-h' option is given, the job is not removed from the table, but is marked so that `SIGHUP' is not sent to the job - if the shell receives a `SIGHUP'. If JOBSPEC is not present, the - current job is used. + if the shell receives a `SIGHUP'. If JOBSPEC is not present, and + neither the `-a' nor `-r' option is supplied, the current job is + used. If no JOBSPEC is supplied, the `-a' option means to remove + or mark all jobs; the `-r' option without a JOBSPEC argument + restricts operation to running jobs. `suspend' suspend [-f] @@ -4333,13 +4782,13 @@ Job Control Variables `auto_resume' This variable controls how the shell interacts with the user and job control. If this variable exists then single word simple - commands without redirects are treated as candidates for resumption - of an existing job. There is no ambiguity allowed; if 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 `exact', the string supplied - must match the name of a stopped job exactly; if set to + 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 `exact', the string + supplied must match the name of a stopped job exactly; if set to `substring', the string supplied needs to match a substring of the name of a stopped job. The `substring' value provides functionality analogous to the `%?' job ID (*note Job Control @@ -4355,17 +4804,19 @@ Using History Interactively This chapter describes how to use the GNU History Library interactively, from a user's standpoint. It should be considered a -user's guide. For information on using the GNU History Library in your -own programs, see the GNU Readline Library Manual. +user's guide. For information on using the GNU History Library in +other programs, see the GNU Readline Library Manual. * 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. -File: bashref.info, Node: Bash History Facilities, Next: History Interaction, Up: Using History Interactively +File: bashref.info, Node: Bash History Facilities, Next: Bash History Builtins, Up: Using History Interactively Bash History Facilities ======================= @@ -4390,12 +4841,11 @@ saving the history, the history file is truncated to contain no more than `$HISTFILESIZE' lines. If `HISTFILESIZE' is not set, no truncation is performed. - The builtin command `fc' (*note Korn Shell Builtins::.) may be used -to list or edit and re-execute a portion of the history list. The -`history' builtin (*note C Shell Builtins::.) can be used to display or -modify the history list and manipulate the history file. When using -the command-line editing, search commands are available in each editing -mode that provide access to the history list. + The builtin command `fc' may be used to list or edit and re-execute +a portion of the history list. The `history' builtin can be used to +display or modify the history list and manipulate the history file. +When using the command-line editing, search commands are available in +each editing mode that provide access to the history list. The shell allows control over which commands are saved on the history list. The `HISTCONTROL' and `HISTIGNORE' variables may be set to cause @@ -4404,14 +4854,96 @@ shell option, if enabled, causes the shell to attempt to save each line of a multi-line command in the same history entry, adding semicolons where necessary to preserve syntactic correctness. The `lithist' shell option causes the shell to save the command with embedded newlines -instead of semicolons. *Note Bash Builtins:: for a description of +instead of semicolons. *Note Bash Builtins::, for a description of `shopt'. -File: bashref.info, Node: History Interaction, Prev: Bash History Facilities, Up: Using History Interactively +File: bashref.info, Node: Bash History Builtins, Next: History Interaction, Prev: Bash History Facilities, Up: Using History Interactively + +Bash History Builtins +===================== -Interactive History Expansion -============================= + Bash provides two builtin commands that allow you to manipulate the +history list and history file. + +`fc' + `fc [-e ENAME] [-nlr] [FIRST] [LAST]' + `fc -s [PAT=REP] [COMMAND]' + + Fix Command. In the first form, a range of commands from FIRST to + LAST is selected from the history list. Both FIRST and LAST may + be specified as a string (to locate the most recent command + beginning with that string) or as a number (an index into the + history list, where a negative number is used as an offset from the + current command number). If LAST is not specified it is set to + FIRST. If FIRST is not specified it is set to the previous + command for editing and -16 for listing. If the `-l' flag is + given, the commands are listed on standard output. The `-n' flag + suppresses the command numbers when listing. The `-r' flag + reverses the order of the listing. Otherwise, the editor given by + ENAME is invoked on a file containing those commands. If ENAME is + not given, the value of the following variable expansion is used: + `${FCEDIT:-${EDITOR:-vi}}'. This says to use the value of the + `FCEDIT' variable if set, or the value of the `EDITOR' variable if + that is set, or `vi' if neither is set. When editing is complete, + the edited commands are echoed and executed. + + In the second form, COMMAND is re-executed after each instance of + PAT in the selected command is replaced by REP. + + A useful alias to use with the `fc' command is `r='fc -s'', so + that typing `r cc' runs the last command beginning with `cc' and + typing `r' re-executes the last command (*note Aliases::.). + +`history' + history [-c] [N] + history [-anrw] [FILENAME] + history -ps ARG + + Display the history list with line numbers. Lines prefixed with + with a `*' have been modified. An argument of N says to list only + the last N lines. Options, if supplied, have the following + meanings: + + `-w' + Write out the current history to the history file. + + `-r' + Read the current history file and append its contents to the + history list. + + `-a' + Append the new history lines (history lines entered since the + beginning of the current Bash session) to the history file. + + `-n' + Append the history lines not already read from the history + file to the current history list. These are lines appended + to the history file since the beginning of the current Bash + session. + + `-c' + Clear the history list. This may be combined with the other + options to replace the history list completely. + + `-s' + The ARGs are added to the end of the history list as a single + entry. + + `-p' + Perform history substitution on the ARGs and display the + result on the standard output, without storing the results in + the history list. + + When the `-w', `-r', `-a', or `-n' option is used, if FILENAME is + given, then it is used as the history file. If not, then the + value of the `HISTFILE' variable is used. + + +File: bashref.info, Node: History Interaction, Prev: Bash History Builtins, Up: Using History Interactively + +History Expansion +================= The History library provides a history expansion feature that is similar to the history expansion provided by `csh'. This section @@ -4423,17 +4955,16 @@ to a previous command into the current input line, or fix errors in previous commands quickly. History expansion takes place in two parts. The first is to -determine which line from the previous history should be used during +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 previous -history is called the "event", and the portions of that line that are -acted upon are called "words". Various "modifiers" are available to -manipulate the selected words. The line is broken into words in the -same fashion that Bash does, so that several English (or Unix) words -surrounded by quotes are considered as one word. History expansions -are introduced by the appearance of the history expansion character, -which is `!' by default. Only `\' and `'' may be used to escape the -history expansion character. +inclusion into the current one. The line selected from the history is +called the "event", and the portions of that line that are acted upon +are called "words". Various "modifiers" are available to manipulate +the selected words. The line is broken into words in the same fashion +that Bash does, so that several words surrounded by quotes are +considered one word. History expansions are introduced by the +appearance of the history expansion character, which is `!' by default. +Only `\' and `'' may be used to escape the history expansion character. Several shell options settable with the `shopt' builtin (*note Bash Builtins::.) may be used to tailor the behavior of history expansion. @@ -4447,7 +4978,8 @@ correction. The `-p' option to the `history' builtin command may be used to see what a history expansion will do before using it. The `-s' option to the `history' builtin may be used to add commands to the end of the history list without actually executing them, so that they are -available for subsequent recall. +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 `histchars' variable. @@ -4469,7 +5001,7 @@ history list. `!' Start a history substitution, except when followed by a space, tab, - the end of the line, <=> or <(>. + the end of the line, `=' or `('. `!N' Refer to command line N. @@ -4502,7 +5034,7 @@ Word Designators ---------------- Word designators are used to select desired words from the event. A -`:' separates the event specification from the word designator. It can +`:' separates the event specification from the word designator. It may be omitted if the word designator begins with a `^', `$', `*', `-', or `%'. Words are numbered from the beginning of the line, with the first word being denoted by 0 (zero). Words are inserted into the current @@ -4698,8 +5230,8 @@ Printing characters Insert the character into the line at the cursor. <C-_> - Undo the last thing that you did. You can undo all the way back - to an empty line. + Undo the last editing command. You can undo all the way back to an + empty line. File: bashref.info, Node: Readline Movement Commands, Next: Readline Killing Commands, Prev: Readline Bare Essentials, Up: Readline Interaction @@ -4720,7 +5252,8 @@ about the line. Move to the end of the line. <M-f> - Move forward a word. + Move forward a word, where a word is composed of letters and + digits. <M-b> Move backward a word. @@ -4768,8 +5301,8 @@ available to be yanked back later, when you are typing another line. Kill from the cursor to the previous whitespace. This is different than <M-DEL> because the word boundaries differ. - And, here is how to "yank" the text back into the line. Yanking -means to copy the most-recently-killed text from the kill buffer. + Here is how to "yank" the text back into the line. Yanking means to +copy the most-recently-killed text from the kill buffer. <C-y> Yank the most recently killed text back into the buffer at the @@ -4793,10 +5326,10 @@ act in a backward direction. For example, to kill text back to the start of the line, you might type `M-- C-k'. The general way to pass numeric arguments to a command is to type -meta digits before the command. If the first `digit' you type is a -minus sign (<->), then the sign of the argument will be negative. Once -you have typed one meta digit to get the argument started, you can type -the remainder of the digits, and then the command. For example, to give +meta digits before the command. If the first `digit' typed is a minus +sign (<->), then the sign of the argument will be negative. Once you +have typed one meta digit to get the argument started, you can type the +remainder of the digits, and then the command. For example, to give the <C-d> command an argument of 10, you could type `M-1 0 C-d'. @@ -4811,24 +5344,24 @@ string. There are two search modes: INCREMENTAL and NON-INCREMENTAL. Incremental searches begin before the user has finished typing the search string. As each character of the search string is typed, -readline displays the next entry from the history matching the string +Readline displays the next entry from the history matching the string typed so far. An incremental search requires only as many characters -as needed to find the desired history entry. The Escape character is -used to terminate an incremental search. Control-J will also terminate -the search. Control-G will abort an incremental search and restore the +as needed to find the desired history entry. The <ESC> character is +used to terminate an incremental search. <C-j> will also terminate the +search. <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 Control-S or Control-R as +matching entries in the history list, type <C-s> or <C-r> as appropriate. This will search backward or forward in the history for the next entry matching the search string typed so far. Any other key -sequence bound to a readline command will terminate the search and -execute that command. For instance, a `newline' will terminate the -search and accept the line, thereby executing the command from the -history list. +sequence bound to a Readline command will terminate the search and +execute that command. For instance, a <RET> will terminate the search +and accept the line, thereby executing the command from the history +list. Non-incremental searches read the entire search string before starting to search for matching history lines. The search string may be -typed by the user or part of the contents of the current line. +typed by the user or be part of the contents of the current line. File: bashref.info, Node: Readline Init File, Next: Bindable Readline Commands, Prev: Readline Interaction, Up: Command Line Editing @@ -4837,12 +5370,11 @@ Readline Init File ================== Although the Readline library comes with a set of `emacs'-like -keybindings installed by default, it is possible that you would like to -use a different set of keybindings. You can customize programs that -use Readline by putting commands in an "inputrc" file in your home -directory. The name of this file is taken from the value of the shell -variable `INPUTRC'. If that variable is unset, the default is -`~/.inputrc'. +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 "inputrc" file in his home directory. The name +of this file is taken from the value of the shell variable `INPUTRC'. +If that variable is unset, the default is `~/.inputrc'. When a program which uses the Readline library starts up, the init file is read, and the key bindings are set. @@ -4871,14 +5403,15 @@ comments. Lines beginning with a `$' indicate conditional constructs settings and key bindings. Variable Settings - You can change the state of a few variables in Readline by using - the `set' command within the init file. Here is how you would - specify that you wish to use `vi' line editing commands: + You can modify the run-time behavior of Readline by altering the + values of variables in Readline using the `set' command within the + init file. Here is how to change from the default Emacs-like key + binding to use `vi' line editing commands: set editing-mode vi - Right now, there are only a few variables which can be set; so - few, in fact, that we just list them here: + A great deal of run-time behavior is changeable with the following + variables. `bell-style' Controls what happens when Readline wants to ring the @@ -4892,6 +5425,11 @@ Variable Settings `insert-comment' command is executed. The default value is `"#"'. + `completion-ignore-case' + If set to `on', Readline performs filename matching and + completion in a case-insensitive fashion. The default value + is `off'. + `completion-query-items' The number of possible completions that determines when the user is asked whether he wants to see the list of @@ -4902,23 +5440,23 @@ Variable Settings `convert-meta' If set to `on', Readline will convert characters with the - eigth bit set to an ASCII key sequence by stripping the eigth - bit and prepending an <ESC> character, converting them to a - meta-prefixed key sequence. The default value is `on'. + eighth bit set to an ASCII key sequence by stripping the + eighth bit and prepending an <ESC> character, converting them + to a meta-prefixed key sequence. The default value is `on'. `disable-completion' - If set to `On', readline will inhibit word completion. + If set to `On', Readline will inhibit word completion. Completion characters will be inserted into the line as if they had been mapped to `self-insert'. The default is `off'. `editing-mode' - The `editing-mode' variable controls which editing mode you - are using. By default, Readline starts up in Emacs editing - mode, where the keystrokes are most similar to Emacs. This - variable can be set to either `emacs' or `vi'. + The `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 `emacs' or `vi'. `enable-keypad' - When set to `on', readline will try to enable the application + When set to `on', Readline will try to enable the application keypad when it is called. Some systems need this to enable the arrow keys. The default is `off'. @@ -4928,7 +5466,7 @@ Variable Settings `horizontal-scroll-mode' This variable can be set to either `on' or `off'. Setting it - to `on' means that the text of the lines that you edit will + to `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 `off'. @@ -4947,9 +5485,9 @@ Variable Settings appended. The default is `on'. `mark-modified-lines' - This variable, when set to `on', says to display an asterisk - (`*') at the start of history lines which have been modified. - This variable is `off' by default. + This variable, when set to `on', causes Readline to display an + asterisk (`*') at the start of history lines which have been + modified. This variable is `off' by default. `input-meta' If set to `on', Readline will enable eight-bit input (it will @@ -4963,6 +5501,11 @@ Variable Settings eighth bit set directly rather than as a meta-prefixed escape sequence. The default is `off'. + `print-completions-horizontally' + If set to `on', Readline will display completions with matches + sorted horizontally in alphabetical order, rather than down + the screen. The default is `off'. + `show-all-if-ambiguous' This alters the default behavior of the completion functions. If set to `on', words which have more than one possible @@ -4977,9 +5520,9 @@ Variable Settings Key Bindings The syntax for controlling key bindings in the init file is simple. First you have to know the name of the command that you - want to change. The following pages contain tables of the command - name, the default keybinding, and a short description of what the - command does. + 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 the name of the key you wish to bind the command to, a colon, and then the @@ -4994,8 +5537,8 @@ Key Bindings Meta-Rubout: backward-kill-word Control-o: "> output" - In the above example, `C-u' is bound to the function - `universal-argument', and `C-o' is bound to run the macro + In the above example, <C-u> is bound to the function + `universal-argument', and <C-o> is bound to run the macro expressed on the right hand side (that is, to insert the text `> output' into the line). @@ -5010,38 +5553,76 @@ Key Bindings "\C-x\C-r": re-read-init-file "\e[11~": "Function Key 1" - In the above example, `C-u' is bound to the function + In the above example, <C-u> is bound to the function `universal-argument' (just as it was in the first example), - `C-x C-r' is bound to the function `re-read-init-file', and - `ESC [ 1 1 ~' is bound to insert the text `Function Key 1'. - The following escape sequences are available when specifying - key sequences: + `<C-x> <C-r>' is bound to the function `re-read-init-file', + and `<ESC> <[> <1> <1> <~>' is bound to insert the text + `Function Key 1'. + + The following GNU Emacs style escape sequences are available when + specifying key sequences: + + `\C-' + control prefix + + `\M-' + meta prefix + + `\e' + an escape character - `\C-' - control prefix + `\\' + backslash + + `\"' + <"> + + `\'' + <'> + + In addition to the GNU Emacs style escape sequences, a second set + of backslash escapes is available: - `\M-' - meta prefix + `\a' + alert (bell) + + `\b' + backspace + + `\d' + delete + + `\f' + form feed + + `\n' + newline + + `\r' + carriage return - `\e' - an escape character + `\t' + horizontal tab - `\\' - backslash + `\v' + vertical tab - `\"' - <"> + `\NNN' + the character whose ASCII code is the octal value NNN (one to + three digits) - `\'' - <'> + `\xNNN' + the character whose ASCII code is the hexadecimal value NNN + (one to three digits) - When entering the text of a macro, single or double quotes - should be used to indicate a macro definition. Unquoted text - is assumed to be a function name. Backslash will quote any - character in the macro text, including `"' and `''. For - example, the following binding will make `C-x \' insert a - single `\' into the line: - "\C-x\\": "\\" + 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 `''. For example, + the following binding will make `C-x \' insert a single `\' into + the line: + "\C-x\\": "\\" File: bashref.info, Node: Conditional Init Constructs, Next: Sample Init File, Prev: Readline Init File Syntax, Up: Readline Init File @@ -5052,7 +5633,7 @@ Conditional Init Constructs Readline implements a facility similar in spirit to the conditional compilation features of the C preprocessor which allows key bindings and variable settings to be performed as the result of tests. There -are three parser directives used. +are four parser directives used. `$if' The `$if' construct allows bindings to be made based on the @@ -5072,8 +5653,8 @@ are three parser directives used. The `term=' form may be used to include terminal-specific key bindings, perhaps to bind the key sequences output by the terminal's function keys. The word on the right side of the - `=' is tested against the full name of the terminal and the - portion of the terminal name before the first `-'. This + `=' is tested against both the full name of the terminal and + the portion of the terminal name before the first `-'. This allows `sun' to match both `sun' and `sun-cmd', for instance. `application' @@ -5090,13 +5671,18 @@ are three parser directives used. $endif `$endif' - This command, as you saw in the previous example, terminates an - `$if' command. + This command, as seen in the previous example, terminates an `$if' + command. `$else' Commands in this branch of the `$if' directive are executed if the test fails. +`$include' + This directive takes a single filename as an argument and reads + commands and bindings from that file. + $include /etc/inputrc + File: bashref.info, Node: Sample Init File, Prev: Conditional Init Constructs, Up: Readline Init File @@ -5114,6 +5700,11 @@ binding, variable assignment, and conditional syntax. # 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 @@ -5262,8 +5853,8 @@ Commands For Manipulating The History `accept-line (Newline, Return)' Accept the line regardless of where the cursor is. If this line is non-empty, add it to the history list according to the setting of - the `HISTCONTROL' variable. If this line was a history line, then - restore the history line to its original state. + the `HISTCONTROL' and `HISTIGNORE' variables. If this line was a + history line, then restore the history line to its original state. `previous-history (C-p)' Move `up' through the history list. @@ -5275,8 +5866,8 @@ Commands For Manipulating The History Move to the first line in the history. `end-of-history (M->)' - Move to the end of the input history, i.e., the line you are - entering. + Move to the end of the input history, i.e., the line currently + being entered. `reverse-search-history (C-r)' Search backward starting at the current line and moving `up' @@ -5300,7 +5891,7 @@ Commands For Manipulating The History `history-search-forward ()' Search forward through the history for the string of characters between the start of the current line and the current cursor - position (the `point'). This is a non-incremental search. By + position (the POINT). This is a non-incremental search. By default, this command is unbound. `history-search-backward ()' @@ -5318,7 +5909,9 @@ Commands For Manipulating The History `yank-last-arg (M-., M-_)' Insert last argument to the previous command (the last word of the previous history entry). With an argument, behave exactly like - `yank-nth-arg'. + `yank-nth-arg'. Successive calls to `yank-last-arg' move back + through the history list, inserting the last argument of each line + in turn. File: bashref.info, Node: Commands For Text, Next: Commands For Killing, Prev: Commands For History, Up: Bindable Readline Commands @@ -5329,18 +5922,16 @@ Commands For Changing Text `delete-char (C-d)' Delete the character under the cursor. If the cursor is at the beginning of the line, there are no characters in the line, and - the last character typed was not `C-d', then return `EOF'. + the last character typed was not bound to `delete-char', then + return `EOF'. `backward-delete-char (Rubout)' - Delete the character behind the cursor. A numeric arg says to kill - the characters instead of deleting them. + Delete the character behind the cursor. A numeric argument means + to kill the characters instead of deleting them. `quoted-insert (C-q, C-v)' - Add the next character that you type to the line verbatim. This is - how to insert key sequences like <C-q>, for example. - -`tab-insert (M-TAB)' - Insert a tab character. + Add the next character typed to the line verbatim. This is how to + insert key sequences like <C-q>, for example. `self-insert (a, b, A, 1, !, ...)' Insert yourself. @@ -5349,7 +5940,7 @@ Commands For Changing Text Drag the character before the cursor forward over the character at the cursor, moving the cursor forward as well. If the insertion point is at the end of the line, then this transposes the last two - characters of the line. Negative argumentss don't work. + characters of the line. Negative arguments don't work. `transpose-words (M-t)' Drag the word behind the cursor past the word in front of the @@ -5357,15 +5948,15 @@ Commands For Changing Text `upcase-word (M-u)' Uppercase the current (or following) word. With a negative - argument, do the previous word, but do not move the cursor. + argument, uppercase the previous word, but do not move the cursor. `downcase-word (M-l)' Lowercase the current (or following) word. With a negative - argument, do the previous word, but do not move the cursor. + argument, lowercase the previous word, but do not move the cursor. `capitalize-word (M-c)' Capitalize the current (or following) word. With a negative - argument, do the previous word, but do not move the cursor. + argument, capitalize the previous word, but do not move the cursor. File: bashref.info, Node: Commands For Killing, Next: Numeric Arguments, Prev: Commands For Text, Up: Bindable Readline Commands @@ -5382,7 +5973,7 @@ Killing And Yanking `unix-line-discard (C-u)' Kill backward from the cursor to the beginning of the current line. - Save the killed text on the kill-ring. + The killed text is saved on the kill-ring. `kill-whole-line ()' Kill all characters on the current line, no matter where the @@ -5407,20 +5998,22 @@ Killing And Yanking `kill-region ()' Kill the text between the point and the *mark* (saved cursor - position. This text is referred to as the REGION. By default, + position). This text is referred to as the REGION. By default, this command is unbound. `copy-region-as-kill ()' - Copy the text in the region to the kill buffer, so you can yank it + Copy the text in the region to the kill buffer, so it can be yanked right away. By default, this command is unbound. `copy-backward-word ()' - Copy the word before point to the kill buffer. By default, this + Copy the word before point to the kill buffer. The word + boundaries are the same as `backward-word'. By default, this command is unbound. `copy-forward-word ()' - Copy the word following point to the kill buffer. By default, - this command is unbound. + Copy the word following point to the kill buffer. The word + boundaries are the same as `forward-word'. By default, this + command is unbound. `yank (C-y)' Yank the top of the kill ring into the buffer at the current @@ -5463,8 +6056,8 @@ Letting Readline Type For You Attempt to do completion on the text before the cursor. This is application-specific. Generally, if you are typing a filename argument, you can do filename completion; if you are typing a - command, you can do command completion, if you are typing in a - symbol to GDB, you can do symbol name completion, if you are + command, you can do command completion; if you are typing in a + symbol to GDB, you can do symbol name completion; if you are typing in a variable to Bash, you can do variable name completion, and so on. Bash attempts completion treating the text as a variable (if the text begins with `$'), username (if the text @@ -5479,6 +6072,17 @@ Letting Readline Type For You Insert all completions of the text before point that would have been generated by `possible-completions'. +`menu-complete ()' + Similar to `complete', but replaces the word to be completed with + a single match from the list of possible completions. Repeated + execution of `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 and the original text is restored. + An argument of N moves 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 `TAB', but is unbound by + default. + `complete-filename (M-/)' Attempt filename completion on the text before point. @@ -5513,8 +6117,8 @@ Letting Readline Type For You `complete-command (M-!)' Attempt completion on the text before point, treating it as a command name. Command completion attempts to match the text - against aliases, reserved words, shell functions, builtins, and - finally executable filenames, in that order. + against aliases, reserved words, shell functions, shell builtins, + and finally executable filenames, in that order. `possible-command-completions (C-x !)' List the possible completions of the text before point, treating @@ -5566,16 +6170,15 @@ Some Miscellaneous Commands bound to the corresponding uppercase character. `prefix-meta (ESC)' - Make the next character that you type be metafied. This is for - people without a meta key. Typing `ESC f' is equivalent to typing - `M-f'. + Make the next character typed be metafied. This is for keyboards + without a meta key. Typing `ESC f' is equivalent to typing `M-f'. `undo (C-_, C-x C-u)' Incremental undo, separately remembered for each line. `revert-line (M-r)' - Undo all changes made to this line. This is like typing the `undo' - command enough times to get back to the beginning. + Undo all changes made to this line. This is like executing the + `undo' command enough times to get back to the beginning. `tilde-expand (M-~)' Perform tilde expansion on the current word. @@ -5606,19 +6209,19 @@ Some Miscellaneous Commands comment. `dump-functions ()' - Print all of the functions and their key bindings to the readline + Print all of the functions and their key bindings to the Readline output stream. If a numeric argument is supplied, the output is formatted in such a way that it can be made part of an INPUTRC file. This command is unbound by default. `dump-variables ()' Print all of the settable variables and their values to the - readline output stream. If a numeric argument is supplied, the + Readline output stream. If a numeric argument is supplied, the output is formatted in such a way that it can be made part of an INPUTRC file. This command is unbound by default. `dump-macros ()' - Print all of the readline key sequences bound to macros and the + Print all of the Readline key sequences bound to macros and the strings they ouput. If a numeric argument is supplied, the output is formatted in such a way that it can be made part of an INPUTRC file. This command is unbound by default. @@ -5630,24 +6233,27 @@ Some Miscellaneous Commands `glob-list-expansions (C-x g)' The list of expansions that would have been generated by - `glob-expand-word' is inserted into the line, replacing the word - before point. + `glob-expand-word' is displayed, and the line is redrawn. `display-shell-version (C-x C-v)' Display version information about the current instance of Bash. `shell-expand-line (M-C-e)' - Expand the line the way the shell does when it reads it. This - performs alias and history expansion as well as all of the shell - word expansions. + Expand the line as the shell does. This performs alias and + history expansion as well as all of the shell word expansions + (*note Shell Expansions::.). `history-expand-line (M-^)' Perform history expansion on the current line. -`alias-expand-line' +`magic-space ()' + Perform history expansion on the current line and insert a space + (*note History Interaction::.). + +`alias-expand-line ()' Perform alias expansion on the current line (*note Aliases::.). -`history-and-alias-expand-line' +`history-and-alias-expand-line ()' Perform history and alias expansion on the current line. `insert-last-argument (M-., M-_)' @@ -5692,7 +6298,7 @@ Installing Bash This chapter provides basic instructions for installing Bash on the various supported platforms. The distribution supports nearly every version of Unix (and, someday, GNU). Other independent ports exist for -OS/2, Windows 95, and Windows NT. +MS-DOS, OS/2, Windows 95, and Windows NT. * Menu: @@ -5738,10 +6344,10 @@ compiler output (useful mainly for debugging `configure'). If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. - If you need to do unusual things to compile the package, please try -to figure out how `configure' could check whether or not to do them, -and mail diffs or instructions to `bash-maintainers@prep.ai.mit.edu' so -they can be considered for the next release. + If you need to do unusual things to compile Bash, please try to +figure out how `configure' could check whether or not to do them, and +mail diffs or instructions to <bash-maintainers@gnu.org> so they can be +considered for the next release. The file `configure.in' is used to create `configure' by a program called Autoconf. You only need `configure.in' if you want to change it @@ -5847,8 +6453,8 @@ than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you -give `configure' the option `--exec-prefix=PATH', the package will use -`PATH' as the prefix for installing programs and libraries. +give `configure' the option `--exec-prefix=PATH', `make install' will +use `PATH' as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. @@ -5858,9 +6464,9 @@ Specifying the System Type ========================== There may be some features `configure' can not figure out -automatically, but needs to determine by the type of host the package -will run on. Usually `configure' can figure that out, but if it prints -a message saying it can not guess the host type, give it the +automatically, but needs to determine by the type of host Bash will run +on. Usually `configure' can figure that out, but if it prints a +message saying it can not guess the host type, give it the `--host=TYPE' option. `TYPE' can either be a short name for the system type, such as `sun4', or a canonical name with three fields: `CPU-COMPANY-SYSTEM' (e.g., `sparc-sun-sunos4.1.2'). @@ -5922,12 +6528,11 @@ Optional Features ================= The Bash `configure' has a number of `--enable-FEATURE' options, -where FEATURE indicates an optional part of the package. There are -also several `--with-PACKAGE' options, where PACKAGE is something like -`gnu-malloc' or `purify' (for the Purify memory allocation checker). To -turn off the default use of a package, use `--without-PACKAGE'. To -configure Bash without a feature that is enabled by default, use -`--disable-FEATURE'. +where FEATURE indicates an optional part of Bash. There are also +several `--with-PACKAGE' options, where PACKAGE is something like +`gnu-malloc' or `purify'. To turn off the default use of a package, use +`--without-PACKAGE'. To configure Bash without a feature that is +enabled by default, use `--disable-FEATURE'. Here is a complete list of the `--enable-' and `--with-' options that the Bash `configure' recognizes. @@ -5942,17 +6547,20 @@ that the Bash `configure' recognizes. `--with-glibc-malloc' Use the GNU libc version of `malloc' in `lib/malloc/gmalloc.c'. - This is somewhat slower than the default `malloc', but wastes - considerably less space. + This is not the version of `malloc' that appears in glibc version + 2, but a modified version of the `malloc' from glibc version 1. + This is somewhat slower than the default `malloc', but wastes less + space on a per-allocation basis, and will return memory to the + operating system under some circumstances. `--with-gnu-malloc' Use the GNU version of `malloc' in `lib/malloc/malloc.c'. This is not the same `malloc' that appears in GNU libc, but an older version derived from the 4.2 BSD `malloc'. This `malloc' is very - fast, but wastes a lot of space. This option is enabled by - default. The `NOTES' file contains a list of systems for which - this should be turned off, and `configure' disables this option - automatically for a number of systems. + fast, but wastes some space on each allocation. This option is + enabled by default. The `NOTES' file contains a list of systems + for which this should be turned off, and `configure' disables this + option automatically for a number of systems. `--with-purify' Define this to use the Purify memory allocation checker from Pure @@ -5962,9 +6570,20 @@ that the Bash `configure' recognizes. This produces a shell with minimal features, close to the historical Bourne shell. -The `minimal-config' option can be used to disable all of the following -options, but it is processed first, so individual options may be -enabled using `enable-FEATURE'. + There are several `--enable-' options that alter how Bash is +compiled and linked, rather than changing run-time features. + +`--enable-profiling' + This builds a Bash binary that produces profiling information to be + processed by `gprof' each time it is executed. + +`--enable-static-link' + This causes Bash to be linked statically, if `gcc' is being used. + This could be used to build a version to use as root's shell. + + The `minimal-config' option can be used to disable all of the +following options, but it is processed first, so individual options may +be enabled using `enable-FEATURE'. All of the following options except for `disabled-builtins' and `usg-echo-default' are enabled by default, unless the operating system @@ -5972,16 +6591,19 @@ does not provide the necessary support. `--enable-alias' Allow alias expansion and include the `alias' and `unalias' - builtins. + builtins (*note Aliases::.). `--enable-array-variables' - Include support for one-dimensional array shell variables. + Include support for one-dimensional array shell variables (*note + Arrays::.). `--enable-bang-history' - Include support for `csh'-like history substitution. + Include support for `csh'-like history substitution (*note History + Interaction::.). `--enable-brace-expansion' Include `csh'-like brace expansion ( `b{a,b}c' ==> `bac bbc' ). + See *Note Brace Expansion::, for a complete description. `--enable-command-timing' Include support for recognizing `time' as a reserved word and for @@ -5989,9 +6611,13 @@ does not provide the necessary support. This allows pipelines as well as shell builtins and functions to be timed. +`--enable-cond-command' + Include support for the `[[' conditional command (*note + Conditional Constructs::.). + `--enable-directory-stack' Include support for a `csh'-like directory stack and the `pushd', - `popd', and `dirs' builtins. + `popd', and `dirs' builtins (*note The Directory Stack::.). `--enable-disabled-builtins' Allow builtin commands to be invoked via `builtin xxx' even after @@ -6000,7 +6626,12 @@ does not provide the necessary support. commands. `--enable-dparen-arithmetic' - Include support for the `ksh' `((...))' command. + Include support for the `((...))' command (*note Conditional + Constructs::.). + +`--enable-extended-glob' + Include support for the extended pattern matching features + described above under *Note Pattern Matching::. `--enable-help-builtin' Include the `help' builtin, which displays help on shell builtins @@ -6011,20 +6642,22 @@ does not provide the necessary support. commands. `--enable-job-control' - This enables job control features, if the OS supports them. + This enables the job control features (*note Job Control::.), if + the operating system supports them. `--enable-process-substitution' This enables process substitution (*note Process Substitution::.) - if the OS provides the necessary support. + if the operating system provides the necessary support. `--enable-prompt-string-decoding' Turn on the interpretation of a number of backslash-escaped characters in the `$PS1', `$PS2', `$PS3', and `$PS4' prompt - strings. + strings. See *Note Printing a Prompt::, for a complete list of + prompt string escape sequences. `--enable-readline' Include support for command-line editing and history with the Bash - version of the Readline library. + version of the Readline library (*note Command Line Editing::.). `--enable-restricted' Include support for a "restricted shell". If this is enabled, @@ -6032,8 +6665,8 @@ does not provide the necessary support. The Restricted Shell::, for a description of restricted mode. `--enable-select' - Include the `ksh' `select' builtin, which allows the generation of - simple menus. + Include the `select' builtin, which allows the generation of simple + menus (*note Conditional Constructs::.). `--enable-usg-echo-default' Make the `echo' builtin expand backslash-escaped characters by @@ -6059,8 +6692,8 @@ of Bash that you have. Once you have determined that a bug actually exists, use the `bashbug' command to submit a bug report. If you have a fix, you are encouraged to mail that as well! Suggestions and `philosophical' bug -reports may be mailed to `bug-bash@prep.ai.MIT.Edu' or posted to the -Usenet newsgroup `gnu.bash.bug'. +reports may be mailed to <bug-bash@gnu.org> or posted to the Usenet +newsgroup `gnu.bash.bug'. All bug reports should include: * The version number of Bash. @@ -6077,8 +6710,7 @@ Usenet newsgroup `gnu.bash.bug'. `bashbug' inserts the first three items automatically into the template it provides for filing a bug report. - Please send all reports concerning this manual to -`chet@ins.CWRU.Edu'. + Please send all reports concerning this manual to <chet@po.CWRU.Edu>. File: bashref.info, Node: Builtin Index, Next: Reserved Word Index, Prev: Reporting Bugs, Up: Top @@ -6100,7 +6732,7 @@ Index of Shell Builtin Commands * command: Bash Builtins. * continue: Bourne Shell Builtins. * declare: Bash Builtins. -* dirs: C Shell Builtins. +* dirs: The Directory Stack. * disown: Job Control Builtins. * echo: Bash Builtins. * enable: Bash Builtins. @@ -6108,21 +6740,20 @@ Index of Shell Builtin Commands * exec: Bourne Shell Builtins. * exit: Bourne Shell Builtins. * export: Bourne Shell Builtins. -* fc: Korn Shell Builtins. +* fc: Bash History Builtins. * fg: Job Control Builtins. * getopts: Bourne Shell Builtins. * hash: Bourne Shell Builtins. * help: Bash Builtins. -* history: C Shell Builtins. +* history: Bash History Builtins. * jobs: Job Control Builtins. * kill: Job Control Builtins. -* let <1>: Arithmetic Builtins. -* let: Korn Shell Builtins. +* let: Bash Builtins. * local: Bash Builtins. -* logout <1>: Bash Builtins. -* logout: C Shell Builtins. -* popd: C Shell Builtins. -* pushd: C Shell Builtins. +* logout: Bash Builtins. +* popd: The Directory Stack. +* printf: Bash Builtins. +* pushd: The Directory Stack. * pwd: Bourne Shell Builtins. * read: Bash Builtins. * readonly: Bourne Shell Builtins. @@ -6130,13 +6761,13 @@ Index of Shell Builtin Commands * set: The Set Builtin. * shift: Bourne Shell Builtins. * shopt: Bash Builtins. -* source: C Shell Builtins. +* source: Bash Builtins. * suspend: Job Control Builtins. * test: Bourne Shell Builtins. * times: Bourne Shell Builtins. * trap: Bourne Shell Builtins. * type: Bash Builtins. -* typeset: Korn Shell Builtins. +* typeset: Bash Builtins. * ulimit: Bash Builtins. * umask: Bourne Shell Builtins. * unalias: Alias Builtins. @@ -6152,6 +6783,8 @@ Shell Reserved Words * Menu: * !: Pipelines. +* [[: Conditional Constructs. +* ]]: Conditional Constructs. * case: Conditional Constructs. * do: Looping Constructs. * done: Looping Constructs. @@ -6163,7 +6796,7 @@ Shell Reserved Words * function: Shell Functions. * if: Conditional Constructs. * in: Conditional Constructs. -* select: Korn Shell Constructs. +* select: Conditional Constructs. * then: Conditional Constructs. * time: Pipelines. * until: Looping Constructs. @@ -6204,7 +6837,7 @@ Parameter and Variable Index * enable-keypad: Readline Init File Syntax. * EUID: Bash Variables. * expand-tilde: Readline Init File Syntax. -* FCEDIT: Korn Shell Variables. +* FCEDIT: Bash Variables. * FIGNORE: Bash Variables. * GLOBIGNORE: Bash Variables. * GROUPS: Bash Variables. @@ -6221,23 +6854,23 @@ Parameter and Variable Index * HOSTNAME: Bash Variables. * HOSTTYPE: Bash Variables. * IFS: Bourne Shell Variables. -* IGNOREEOF <1>: Bash Variables. -* IGNOREEOF: C Shell Variables. +* IGNOREEOF: Bash Variables. * input-meta: Readline Init File Syntax. * INPUTRC: Bash Variables. * keymap: Readline Init File Syntax. * LANG: Bash Variables. * LC_ALL: Bash Variables. * LC_COLLATE: Bash Variables. +* LC_CTYPE: Bash Variables. * LC_MESSAGES: Bash Variables. -* LINENO: Korn Shell Variables. +* LINENO: Bash Variables. * MACHTYPE: Bash Variables. * MAIL: Bourne Shell Variables. * MAILCHECK: Bash Variables. * MAILPATH: Bourne Shell Variables. * mark-modified-lines: Readline Init File Syntax. * meta-flag: Readline Init File Syntax. -* OLDPWD: Korn Shell Variables. +* OLDPWD: Bash Variables. * OPTARG: Bourne Shell Variables. * OPTERR: Bash Variables. * OPTIND: Bourne Shell Variables. @@ -6249,17 +6882,17 @@ Parameter and Variable Index * PROMPT_COMMAND: Bash Variables. * PS1: Bourne Shell Variables. * PS2: Bourne Shell Variables. -* PS3: Korn Shell Variables. -* PS4: Korn Shell Variables. -* PWD: Korn Shell Variables. -* RANDOM: Korn Shell Variables. -* REPLY: Korn Shell Variables. -* SECONDS: Korn Shell Variables. +* PS3: Bash Variables. +* PS4: Bash Variables. +* PWD: Bash Variables. +* RANDOM: Bash Variables. +* REPLY: Bash Variables. +* SECONDS: Bash Variables. * SHELLOPTS: Bash Variables. * SHLVL: Bash Variables. * show-all-if-ambiguous: Readline Init File Syntax. * TIMEFORMAT: Bash Variables. -* TMOUT: Korn Shell Variables. +* TMOUT: Bash Variables. * UID: Bash Variables. * visible-stats: Readline Init File Syntax. @@ -6312,6 +6945,7 @@ Function Index * kill-region (): Commands For Killing. * kill-whole-line (): Commands For Killing. * kill-word (M-d): Commands For Killing. +* menu-complete (): Commands For Completion. * next-history (C-n): Commands For History. * non-incremental-forward-search-history (M-n): Commands For History. * non-incremental-reverse-search-history (M-p): Commands For History. @@ -6326,7 +6960,6 @@ Function Index * self-insert (a, b, A, 1, !, ...): Commands For Text. * set-mark (C-@): Miscellaneous Commands. * start-kbd-macro (C-x (): Keyboard Macros. -* tab-insert (M-TAB): Commands For Text. * tilde-expand (M-~): Miscellaneous Commands. * transpose-chars (C-t): Commands For Text. * transpose-words (M-t): Commands For Text. @@ -6349,7 +6982,7 @@ Concept Index * Menu: * alias expansion: Aliases. -* arithmetic evaluation: Arithmetic Evaluation. +* arithmetic evaluation: Shell Arithmetic. * arithmetic expansion: Arithmetic Expansion. * arithmetic, shell: Shell Arithmetic. * arrays: Arrays. @@ -6361,6 +6994,7 @@ Concept Index * builtin: Definitions. * command editing: Readline Bare Essentials. * command execution: Command Search and Execution. +* command expansion: Simple Command Expansion. * command history: Bash History Facilities. * command search: Command Search and Execution. * command substitution: Command Substitution. @@ -6370,16 +7004,19 @@ Concept Index * commands, lists: Lists. * commands, looping: Looping Constructs. * commands, pipelines: Pipelines. +* commands, shell: Shell Commands. * commands, simple: Simple Commands. * comments, shell: Comments. * configuration: Basic Installation. * control operator: Definitions. +* directory stack: The Directory Stack. * editing command lines: Readline Bare Essentials. * environment: Environment. -* evaluation, arithmetic: Arithmetic Evaluation. +* evaluation, arithmetic: Shell Arithmetic. * event designators: Event Designators. -* exit status <1>: Definitions. -* exit status: Exit Status. +* execution environment: Command Execution Environment. +* exit status <1>: Exit Status. +* exit status: Definitions. * expansion: Shell Expansions. * expansion, arithmetic: Arithmetic Expansion. * expansion, brace: Brace Expansion. @@ -6387,13 +7024,14 @@ Concept Index * expansion, parameter: Shell Parameter Expansion. * expansion, pathname: Filename Expansion. * expansion, tilde: Tilde Expansion. -* expressions, arithmetic: Arithmetic Evaluation. +* expressions, arithmetic: Shell Arithmetic. * expressions, conditional: Bash Conditional Expressions. * field: Definitions. * filename: Definitions. * filename expansion: Filename Expansion. * foreground: Job Control Basics. * functions, shell: Shell Functions. +* history builtins: Bash History Builtins. * history events: Event Designators. * history expansion: History Interaction. * history list: Bash History Facilities. @@ -6410,6 +7048,7 @@ Concept Index * kill ring: Readline Killing Commands. * killing text: Readline Killing Commands. * localization: Locale Translation. +* matching, pattern: Pattern Matching. * metacharacter: Definitions. * name: Definitions. * notation, readline: Readline Bare Essentials. @@ -6419,6 +7058,7 @@ Concept Index * parameters, positional: Positional Parameters. * parameters, special: Special Parameters. * pathname expansion: Filename Expansion. +* pattern matching: Pattern Matching. * pipeline: Pipelines. * POSIX: Definitions. * POSIX Mode: Bash POSIX Mode. @@ -6433,6 +7073,7 @@ Concept Index * reserved word: Definitions. * restricted shell: The Restricted Shell. * return status: Definitions. +* shell arithmetic: Shell Arithmetic. * shell function: Shell Functions. * shell script: Shell Scripts. * shell variable: Shell Parameters. @@ -6451,123 +7092,120 @@ Concept Index Tag Table: -Node: Top1179 -Node: Introduction3283 -Node: What is Bash?3508 -Node: What is a shell?4592 -Node: Definitions6473 -Node: Basic Shell Features9134 -Node: Shell Syntax10655 -Node: Shell Operation10945 -Node: Quoting12179 -Node: Escape Character13214 -Node: Single Quotes13645 -Node: Double Quotes13974 -Node: ANSI-C Quoting14670 -Node: Locale Translation15402 -Node: Comments15823 -Node: Simple Commands16347 -Node: Pipelines16936 -Node: Lists18007 -Node: Looping Constructs19282 -Node: Conditional Constructs20459 -Node: Command Grouping22526 -Node: Shell Functions23912 -Node: Shell Parameters25685 -Node: Positional Parameters27008 -Node: Special Parameters27702 -Node: Shell Expansions30268 -Node: Shell Parameter Expansion32272 -Node: Command Substitution38280 -Node: Process Substitution39280 -Node: Word Splitting40186 -Node: Filename Expansion41638 -Node: Quote Removal44004 -Node: Redirections44290 -Node: Executing Commands50031 -Node: Command Search and Execution50486 -Node: Environment52220 -Node: Exit Status53856 -Node: Signals54873 -Node: Shell Scripts56084 -Node: Bourne Shell Features57953 -Node: Bourne Shell Builtins58623 -Node: Bourne Shell Variables66977 -Node: Other Bourne Shell Features68514 -Node: Major Differences From The Bourne Shell69271 -Node: Csh Features79631 -Node: Brace Expansion80549 -Node: Tilde Expansion82104 -Node: C Shell Builtins82736 -Node: C Shell Variables87292 -Node: Korn Shell Features87700 -Node: Korn Shell Constructs88428 -Node: Korn Shell Builtins90143 -Node: Korn Shell Variables92301 -Node: Aliases93860 -Node: Alias Builtins96326 -Node: Bash Features96942 -Node: Invoking Bash97933 -Node: Bash Startup Files101798 -Node: Is This Shell Interactive?105373 -Node: Bash Builtins106356 -Node: The Set Builtin122211 -Node: Bash Conditional Expressions127586 -Node: Bash Variables132237 -Node: Shell Arithmetic142271 -Node: Arithmetic Evaluation142739 -Node: Arithmetic Expansion144769 -Node: Arithmetic Builtins145573 -Node: Arrays146044 -Node: Printing a Prompt149071 -Node: The Restricted Shell150669 -Node: Bash POSIX Mode151899 -Node: Job Control155583 -Node: Job Control Basics156048 -Node: Job Control Builtins160191 -Node: Job Control Variables163114 -Node: Using History Interactively164261 -Node: Bash History Facilities164850 -Node: History Interaction167248 -Node: Event Designators169810 -Node: Word Designators170737 -Node: Modifiers171986 -Node: Command Line Editing173303 -Node: Introduction and Notation173963 -Node: Readline Interaction175001 -Node: Readline Bare Essentials176193 -Node: Readline Movement Commands177736 -Node: Readline Killing Commands178648 -Node: Readline Arguments180368 -Node: Searching181345 -Node: Readline Init File182981 -Node: Readline Init File Syntax184037 -Node: Conditional Init Constructs191820 -Node: Sample Init File194101 -Node: Bindable Readline Commands197134 -Node: Commands For Moving197884 -Node: Commands For History198731 -Node: Commands For Text201404 -Node: Commands For Killing203148 -Node: Numeric Arguments205174 -Node: Commands For Completion206300 -Node: Keyboard Macros209262 -Node: Miscellaneous Commands209820 -Node: Readline vi Mode214036 -Node: Installing Bash214914 -Node: Basic Installation215983 -Node: Compilers and Options218908 -Node: Compiling For Multiple Architectures219642 -Node: Installation Names221299 -Node: Specifying the System Type222021 -Node: Sharing Defaults222732 -Node: Operation Controls223397 -Node: Optional Features224302 -Node: Reporting Bugs229185 -Node: Builtin Index230265 -Node: Reserved Word Index233732 -Node: Variable Index235059 -Node: Function Index240327 -Node: Concept Index244750 +Node: Top1197 +Node: Introduction3153 +Node: What is Bash?3378 +Node: What is a shell?4472 +Node: Definitions6494 +Node: Basic Shell Features9155 +Node: Shell Syntax10378 +Node: Shell Operation10667 +Node: Quoting11961 +Node: Escape Character12986 +Node: Single Quotes13458 +Node: Double Quotes13787 +Node: ANSI-C Quoting14685 +Node: Locale Translation15554 +Node: Comments15975 +Node: Shell Commands16589 +Node: Simple Commands17100 +Node: Pipelines17659 +Node: Lists19186 +Node: Looping Constructs20641 +Node: Conditional Constructs22246 +Node: Command Grouping28184 +Node: Shell Functions29561 +Node: Shell Parameters31525 +Node: Positional Parameters32851 +Node: Special Parameters33600 +Node: Shell Expansions36221 +Node: Brace Expansion38144 +Node: Tilde Expansion39705 +Node: Shell Parameter Expansion42037 +Node: Command Substitution48379 +Node: Arithmetic Expansion49653 +Node: Process Substitution50498 +Node: Word Splitting51392 +Node: Filename Expansion52844 +Node: Pattern Matching54808 +Node: Quote Removal57197 +Node: Redirections57483 +Node: Executing Commands63553 +Node: Simple Command Expansion64220 +Node: Command Search and Execution66143 +Node: Command Execution Environment68146 +Node: Environment70600 +Node: Exit Status72257 +Node: Signals73454 +Node: Shell Scripts75349 +Node: Bourne Shell Features77385 +Node: Bourne Shell Builtins78115 +Node: Bourne Shell Variables92056 +Node: Other Bourne Shell Features93761 +Node: Major Differences From The Bourne Shell94504 +Node: Bash Features106693 +Node: Invoking Bash107796 +Node: Bash Startup Files111981 +Node: Is This Shell Interactive?115540 +Node: Bash Builtins116511 +Node: The Set Builtin137351 +Node: Bash Conditional Expressions143960 +Node: Bash Variables147033 +Node: Shell Arithmetic159463 +Node: Aliases161511 +Node: Alias Builtins164086 +Node: Arrays164702 +Node: The Directory Stack167723 +Node: Printing a Prompt171073 +Node: The Restricted Shell172736 +Node: Bash POSIX Mode174072 +Node: Job Control178233 +Node: Job Control Basics178699 +Node: Job Control Builtins182898 +Node: Job Control Variables187190 +Node: Using History Interactively188340 +Node: Bash History Facilities189019 +Node: Bash History Builtins191360 +Node: History Interaction194728 +Node: Event Designators197280 +Node: Word Designators198207 +Node: Modifiers199456 +Node: Command Line Editing200773 +Node: Introduction and Notation201433 +Node: Readline Interaction202471 +Node: Readline Bare Essentials203663 +Node: Readline Movement Commands205203 +Node: Readline Killing Commands206168 +Node: Readline Arguments207883 +Node: Searching208857 +Node: Readline Init File210475 +Node: Readline Init File Syntax211514 +Node: Conditional Init Constructs220379 +Node: Sample Init File222817 +Node: Bindable Readline Commands225986 +Node: Commands For Moving226736 +Node: Commands For History227583 +Node: Commands For Text230412 +Node: Commands For Killing232146 +Node: Numeric Arguments234295 +Node: Commands For Completion235421 +Node: Keyboard Macros238991 +Node: Miscellaneous Commands239549 +Node: Readline vi Mode243869 +Node: Installing Bash244747 +Node: Basic Installation245824 +Node: Compilers and Options248734 +Node: Compiling For Multiple Architectures249468 +Node: Installation Names251125 +Node: Specifying the System Type251850 +Node: Sharing Defaults252554 +Node: Operation Controls253219 +Node: Optional Features254124 +Node: Reporting Bugs260319 +Node: Builtin Index261390 +Node: Reserved Word Index264793 +Node: Variable Index266251 +Node: Function Index271456 +Node: Concept Index275885 End Tag Table diff --git a/doc/bashref.texi b/doc/bashref.texi index 2d1717d1..854090ec 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -5,13 +5,13 @@ @c %**end of header @ignore -last change: Mon May 19 12:55:22 EDT 1997 +last change: Wed Mar 25 11:36:48 EST 1998 @end ignore -@set EDITION 2.0 -@set VERSION 2.01 -@set UPDATED 19 May 1997 -@set UPDATE-MONTH May 1997 +@set EDITION 2.2 +@set VERSION 2.02 +@set UPDATED 1 April 1998 +@set UPDATE-MONTH April 1998 @iftex @finalout @@ -22,12 +22,12 @@ last change: Mon May 19 12:55:22 EDT 1997 @defcodeindex rw @set BashFeatures +@ifinfo @dircategory Utilities @direntry -* Bash: (bash). GNU Bourne-Again SHell + * Bash: (bash). The GNU Bourne-Again SHell. @end direntry -@ifinfo @format This text is a brief description of the features that are present in the Bash shell. @@ -36,7 +36,7 @@ This is Edition @value{EDITION}, last updated @value{UPDATED}, of @cite{The GNU Bash Reference Manual}, for @code{Bash}, Version @value{VERSION}. -Copyright (C) 1991, 1993, 1996 Free Software Foundation, Inc. +Copyright (C) 1991, 1993, 1996, 1997 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice @@ -57,7 +57,7 @@ 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. +by the Free Software Foundation. @end format @end ifinfo @@ -125,12 +125,6 @@ reference on shell behavior. * Bourne Shell Features:: Features similar to those found in the Bourne shell. -* Csh Features:: Features originally found in the - Berkeley C-Shell. - -* Korn Shell Features:: Features originally found in the Korn - Shell. - * Bash Features:: Features found only in Bash. * Job Control:: A chapter describing what job control is @@ -181,16 +175,17 @@ of Unix. Bash is an @code{sh}-compatible shell that incorporates useful features from the Korn shell @code{ksh} and the C shell @code{csh}. -It is ultimately intended to be a -conformant implementation of the @sc{IEEE} @sc{POSIX} Shell and Tools -specification (@sc{IEEE} Working Group 1003.2). It offers functional -improvements over @code{sh} for both interactive and programming use. +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 will include a version of @code{csh}, Bash will be the default shell. Like other @sc{GNU} software, Bash is quite portable. It currently runs on nearly every version of Unix and a few other operating systems @minus{} -independently-supported ports exist for @sc{OS/2} and Windows @sc{NT}. +independently-supported ports exist for @sc{MS-DOS}, @sc{OS/2}, +Windows @sc{95}, and Windows @sc{NT}. @node What is a shell? @section What is a shell? @@ -199,14 +194,17 @@ At its base, a shell is simply a macro processor that executes commands. A Unix shell is both a command interpreter, which provides the user interface to the rich set of Unix utilities, and a programming language, allowing these utilitites to be -combined. The shell reads commands either from a terminal or a -file. Files containing commands can be created, and become +combined. Files containing commands can be created, and become commands themselves. These new commands have the same status as system commands in directories like @file{/bin}, allowing users or groups to establish custom environments. A shell allows execution of Unix commands, both synchronously and -asynchronously. The @dfn{redirection} constructs permit +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, and the shell allows control over the contents of their environment. Unix shells also provide a small set of built-in @@ -351,7 +349,7 @@ 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": +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 @@ -359,13 +357,7 @@ and to named files, and how the shell executes commands. @menu * Shell Syntax:: What your input means to the shell. -* Simple Commands:: The most common type of command. -* Pipelines:: Connecting the input and output of several - commands. -* Lists:: How to execute commands sequentially. -* Looping Constructs:: Shell commands for iterative action. -* Conditional Constructs:: Shell commands for conditional execution. -* Command Grouping:: Ways to group commands. +* Shell Commands:: The types of commands you can use. * Shell Functions:: Grouping commands by name. * Shell Parameters:: Special shell variables. * Shell Expansions:: How Bash expands variables and the various @@ -400,12 +392,13 @@ supplied as an argument to the @samp{-c} invocation option @item Breaks the input into words and operators, obeying the quoting rules -described in @ref{Quoting}. Tokens are separated by +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. +Parses the tokens into simple and compound commands +(@pxref{Shell Commands}). @item Performs the various shell expansions (@pxref{Shell Expansions}), breaking @@ -421,7 +414,7 @@ Executes the command (@pxref{Executing Commands}). @item Optionally waits for the command to complete and collects its exit -status. +status (@pxref{Exit Status}). @end enumerate @@ -446,9 +439,9 @@ disable special treatment for special characters, to prevent reserved words from being recognized as such, and to prevent parameter expansion. -Each of the shell @code{metacharacters} (@pxref{Definitions}) -has special meaning to the shell and must be quoted if they are to -represent themselves. There are three quoting mechanisms: the +Each of the shell metacharacters (@pxref{Definitions}) +has special meaning to the shell and must be quoted if it is to +represent itself. There are three quoting mechanisms: the @var{escape character}, single quotes, and double quotes. @node Escape Character @@ -456,8 +449,9 @@ represent themselves. There are three quoting mechanisms: the A non-quoted backslash @samp{\} is the Bash escape character. It preserves the literal value of the next character that follows, with the exception of @code{newline}. If a @code{\newline} pair -appears, and the backslash is not quoted, the @code{\newline} -is treated as a line continuation (that is, it is effectively ignored). +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 @@ -473,10 +467,13 @@ Enclosing characters in double quotes preserves the literal value of all characters within the quotes, with the exception of @samp{$}, @samp{`}, and @samp{\}. The characters @samp{$} and @samp{`} -retain their special meaning within double quotes. The backslash -retains its special meaning only when followed by one of the following -characters: +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. @@ -512,7 +509,11 @@ vertical tab @item \\ backslash @item \@var{nnn} -the character whose @code{ASCII} code is @var{nnn} in octal +the character whose @code{ASCII} code is the octal value @var{nnn} +(one to three digits) +@item \x@var{nnn} +the character whose @code{ASCII} code is the hexadecimal value @var{nnn} +(one to three digits) @end table @noindent @@ -541,14 +542,29 @@ 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{Is This Shell Interactive?}, for a description of what makes +a shell interactive. + +@node Shell Commands +@section Shell Commands +@cindex commands, shell +@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 -@section Simple Commands +@subsection Simple Commands @cindex commands, simple -A simple command is the kind of command you'll encounter most often. +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 control operators (@pxref{Definitions}). The +by one of the shell's control operators (@pxref{Definitions}). The first word generally specifies a command to be executed. The return status (@pxref{Exit Status}) of a simple command is @@ -557,7 +573,7 @@ by the @sc{POSIX.1} @code{waitpid} function, or 128+@var{n} if the command was terminated by signal @var{n}. @node Pipelines -@section Pipelines +@subsection Pipelines @cindex pipeline @cindex commands, pipelines @@ -579,19 +595,28 @@ 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 @samp{-p} option changes the output format to that specified by @sc{POSIX}. The @code{TIMEFORMAT} variable may be set to a format string that specifies how the timing information should be displayed. @xref{Bash Variables}, for a description of the available formats. +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. The exit +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 @sc{NOT} of the exit status of the last command. +exit status is the logical negation of the exit status of the last command. @node Lists -@section Lists of Commands +@subsection Lists of Commands @cindex commands, lists A @code{list} is a sequence of one or more pipelines separated by one @@ -604,11 +629,15 @@ have equal precedence, followed by @samp{;} and @samp{&}, which have equal precedence. If a command is terminated by the control operator @samp{&}, -the shell executes the command in the @var{background} -in a subshell. The shell does not wait for the command to -finish, and the return status is 0 (true). Commands separated by a -@samp{;} are executed sequentially; the shell waits for each -command to terminate in turn. The return status is the +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). +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{||} @@ -628,7 +657,7 @@ An @sc{OR} list has the form @end example @noindent -@var{command2} is executed if and only if @var{command} +@var{command2} is executed if, and only if, @var{command} returns a non-zero exit status. The return status of @@ -636,15 +665,14 @@ The return status of executed in the list. @node Looping Constructs -@section Looping Constructs +@subsection Looping Constructs @cindex commands, looping -Note that wherever you see a @samp{;} in the description of a -command's syntax, it may be replaced indiscriminately with -one or more newlines. - Bash supports the following looping constructs. +Note that wherever you see a @samp{;} in the description of a +command's syntax, it may be replaced with one or more newlines. + @table @code @item until @rwindex until @@ -654,8 +682,10 @@ The syntax of the @code{until} command is: @example until @var{test-commands}; do @var{consequent-commands}; done @end example -Execute @var{consequent-commands} as long as the final command in +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 @@ -664,8 +694,10 @@ The syntax of the @code{while} command is: while @var{test-commands}; do @var{consequent-commands}; done @end example -Execute @var{consequent-commands} as long as the final command in +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 @@ -674,17 +706,19 @@ The syntax of the @code{for} command is: @example for @var{name} [in @var{words} @dots{}]; do @var{commands}; done @end example -Execute @var{commands} for each member in @var{words}, with @var{name} -bound to the current member. If @samp{in @var{words}} is not -present, @samp{in "$@@"} is assumed. - +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, @samp{in "$@@"} is assumed. +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. @end table The @code{break} and @code{continue} builtins (@pxref{Bourne Shell Builtins}) may be used to control loop execution. @node Conditional Constructs -@section Conditional Constructs +@subsection Conditional Constructs @cindex commands, conditional @table @code @@ -705,15 +739,17 @@ if @var{test-commands}; then fi @end example -Execute @var{consequent-commands} only if the final command in -@var{test-commands} has an exit status of zero. -Otherwise, each @code{elif} list is executed in turn, -and if its exit status is zero, +The @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 execute @var{alternate-consequents}. +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 @@ -722,11 +758,23 @@ has a non-zero exit status, then execute @var{alternate-consequents}. The syntax of the @code{case} command is: @example -@code{case @var{word} in [ ( @var{pattern} [| @var{pattern}]@dots{}) @var{commands} ;;]@dots{} esac} +@code{case @var{word} in [ [(] @var{pattern} [| @var{pattern}]@dots{}) @var{command-list} ;;]@dots{} esac} @end example -Selectively execute @var{commands} based upon @var{word} matching -@var{pattern}. The @samp{|} is used to separate multiple patterns. +@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: @@ -743,27 +791,115 @@ 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 @code{PS3} prompt is then displayed and a line is read from the +standard input. +If the line consists of a number corresponding to one of the displayed +words, then the value of @var{name} is set to that word. +If the line is empty, the words and prompt are displayed again. +If @code{EOF} is read, the @code{select} command completes. +Any other value read causes @var{name} to be set to null. +The line read is saved in the variable @code{REPLY}. + +The @var{commands} are executed after each selection until a +@code{break} or @code{return} command is executed, at which +point the @code{select} command completes. + +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 @var{expression} is evaluated according to the rules described -below (@pxref{Arithmetic Evaluation}). +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. + +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 && and || commands do not execute @var{expression2} if the +value of @var{expression1} is sufficient to determine the return +value of the entire conditional expression. -The @code{select} construct, which allows users to choose from a list -of items presented as a menu, is also available. -@xref{Korn Shell Constructs}, for a full description of @code{select}. +@end table @node Command Grouping -@section Grouping Commands +@subsection Grouping Commands @cindex commands, grouping Bash provides two ways to group a list of commands to be executed @@ -778,9 +914,9 @@ commands in the list may be redirected to a single stream. @end example Placing a list of commands between parentheses causes a subshell -to be created, and each of the commands to be executed in that -subshell. Since the @var{list} is executed in a subshell, variable -assignments do not remain in effect after the subshell completes. +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 @{ @@ -791,7 +927,7 @@ assignments do not remain in effect after the subshell completes. Placing a list of commands between curly braces causes the list to be executed in the current shell context. No subshell is created. -The semicolon following @var{list} is required. +The semicolon (or newline) following @var{list} is required. @end table In addition to the creation of a subshell, there is a subtle difference @@ -821,9 +957,11 @@ Functions are declared using this syntax: @end example This defines a shell function named @var{name}. The reserved -word @code{function} is optional. The @var{body} of the -function is the @var{command-list} between @{ and @}. This list -is executed whenever @var{name} is specified as the +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. @@ -839,9 +977,11 @@ is executed in a function, the function completes and execution resumes with the next command after the function call. When a function completes, the values of the positional parameters and the special parameter @samp{#} -are restored to the values they had prior to function +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 return status. +that is the function's return status; otherwise the functions'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 @@ -880,11 +1020,11 @@ If @var{value} is not given, the variable is assigned the null string. All @var{value}s undergo tilde expansion, parameter and variable expansion, command substitution, arithmetic expansion, and quote -removal (detailed below). If the variable has its @samp{-i} attribute -set (see the description of the @code{declare} builtin in +removal (detailed below). If the variable has its @code{integer} +attribute set (see the description of the @code{declare} builtin in @ref{Bash Builtins}), then @var{value} is subject to arithmetic expansion even if the @code{$((@dots{}))} -syntax does not appear (@pxref{Arithmetic Expansion}). +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. @@ -893,12 +1033,12 @@ Filename expansion is not performed. @subsection Positional Parameters @cindex parameters, positional -A @var{positional parameter} -is a parameter denoted by one or more +A @var{positional parameter} is a parameter denoted by one or more digits, other than the single digit @code{0}. Positional parameters are assigned from the shell's arguments when it is invoked, -and may be reassigned using the @code{set} -builtin command. Positional parameters may not be assigned to +and may be reassigned using the @code{set} builtin command. +Positional parameter @code{N} may be referenced as @code{$@{N@}}. +Positional parameters may not be assigned to with assignment statements. The positional parameters are temporarily replaced when a shell function is executed (@pxref{Shell Functions}). @@ -931,7 +1071,7 @@ separators. @item @@ Expands to the positional parameters, starting from one. When the -expansion occurs within double quotes, each parameter expands as a +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 @@ -953,8 +1093,7 @@ builtin command, or those set by the shell itself @item $ Expands to the process @sc{ID} of the shell. In a @code{()} subshell, it -expands to the process @sc{ID} of the current shell, not the -subshell. +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 @@ -962,10 +1101,10 @@ Expands to the process @sc{ID} of the most recently executed background @item 0 Expands to the name of the shell or shell script. This is set at -shell initialization. If Bash is invoked with a file of commands, -@code{$0} is set to the name of that file. If Bash -is started with the @samp{-c} option, then @code{$0} -is set to the first argument after the string to be +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 @samp{-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. @@ -974,7 +1113,7 @@ At shell startup, set to the absolute filename of the shell or shell script being executed as passed in the argument list. Subsequently, expands to the last argument to the previous command, after expansion. -Also set to the full filename of each command executed and placed in +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 @@ -996,8 +1135,11 @@ Expansion is performed on the command line after it has been split into @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 @@ -1007,11 +1149,6 @@ Expansion is performed on the command line after it has been split into words. @end menu -Brace expansion, tilde expansion, and arithmetic expansion are described -in other sections. For brace expansion, see @ref{Brace Expansion}; for -tilde expansion, see @ref{Tilde Expansion}; and for arithmetic expansion, -see @ref{Arithmetic Expansion}. - The order of expansions is: brace expansion, tilde expansion, parameter, variable, and arithmetic expansion and command substitution @@ -1020,7 +1157,7 @@ expansion. On systems that can support it, there is an additional expansion available: @var{process substitution}. This is performed at the -same time as parameter, variable, and arithemtic expansion and +same time as parameter, variable, and arithmetic expansion and command substitution. Only brace expansion, word splitting, and filename expansion @@ -1033,6 +1170,124 @@ The only exceptions to this are the expansions of 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 a series of comma-separated strings +between a pair of braces, followed by an optional @var{postscript}. +The preamble is prepended 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 + +Brace expansion is performed before any other expansions, +and any characters special to other expansions are preserved +in the result. It is strictly textual. Bash +does not apply any syntactic interpretation to the context of the +expansion or the text between the braces. + +A correctly-formed brace expansion must contain unquoted opening +and closing braces, and at least one unquoted comma. +Any incorrectly formed brace expansion is left unchanged. + +This construct is typically used as shorthand when the common +prefix of the strings to be generated is longer than in the +above example: +@example +mkdir /usr/local/src/bash/@{old,new,dist,bugs@} +@end example +or +@example +chown root /usr/@{ucb/@{ex,edit@},lib/@{ex?.?*,how_ex@}@} +@end example + +@node Tilde Expansion +@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 @code{HOME} shell variable. +If @code{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 @code{PWD} replaces the tilde-prefix. +If the tilde-prefix is @samp{~-}, the value of the shell variable +@code{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 +@code{PATH}, @code{MAILPATH}, and @code{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 @@ -1045,6 +1300,11 @@ 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} @@ -1098,11 +1358,11 @@ is null or unset, nothing is substituted, otherwise the expansion of @item $@{@var{parameter}:@var{offset}@} @itemx $@{@var{parameter}:@var{offset}:@var{length}@} Expands to up to @var{length} characters of @var{parameter}, -starting at @var{offset}. +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{Arithmetic Evaluation}). +(@pxref{Shell Arithmetic}). This is referred to as Substring Expansion. @var{length} must evaluate to a number greater than or equal to zero. @@ -1112,27 +1372,25 @@ If @var{parameter} is @samp{@@}, the result is @var{length} positional parameters beginning at @var{offset}. If @var{parameter} is an array name indexed by @samp{@@} or @samp{*}, the result is the @var{length} -members of the array beginning with $@{@var{parameter}[@var{offset}]@}. -Substring indexing is zero-based unless the positional parameters are -used, in which case the indexing starts at 1. +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{parameter}@} -The length in characters of the value of @var{parameter} is substituted. -If @var{parameter} -is @samp{*} or @samp{@@}, -the length substituted is the number of positional parameters. -If @var{parameter} -is an array name subscripted -by @samp{*} or @samp{@@}, -the length substituted is the number of elements in the array. +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 value of @var{parameter}, -then the expansion is the value of @var{parameter} +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{*}, @@ -1147,10 +1405,10 @@ array in turn, and the expansion is the resultant list. @itemx $@{@var{parameter}%%@var{word}@} The @var{word} is expanded to produce a pattern just as in filename expansion. -If the pattern matches a trailing portion of the value of -@var{parameter}, then the expansion is the value of @var{parameter} -with the shortest matching pattern (the @samp{%} case) or the -longest matching pattern (the @samp{%%} case) deleted. +If 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. @@ -1204,19 +1462,48 @@ or 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{\}. +@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 old form, -escape the inner backquotes with backslashes. +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 substitutions 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 @@ -1241,9 +1528,9 @@ the file will provide input for @var{list}. If the @code{<(@var{list})} form is used, the file passed as an argument should be read to obtain the output of @var{list}. -On systems that support it, process substitution is performed -simultaneously with parameter and variable expansion, -command substitution, and arithmetic expansion. +When available, process substitution is performed simultaneously with +parameter and variable expansion, command substitution, and arithmetic +expansion. @node Word Splitting @subsection Word Splitting @@ -1282,38 +1569,46 @@ 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 @samp{-f} -option has been set (@pxref{The Set Builtin}), -Bash scans each word for the characters -@samp{*}, @samp{?}, and @samp{[}. +After word splitting, unless the @samp{-f} option has been set +(@pxref{The Set Builtin}), Bash scans each word for the characters +@samp{*}, @samp{?}, @samp{(}, and @samp{[}. If one of these characters appears, then the word is regarded as a @var{pattern}, and replaced with an alphabetically sorted list of file names matching the pattern. If no matching file names are found, and the shell option @code{nullglob} is disabled, the word is left -unchanged. If the option is set, and no matches are found, the word -is removed. When a pattern is used for filename generation, -the character @samp{.} +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. The slash character must always be matched explicitly. +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{nullglob} and @code{dotglob} options. +for a description of the @code{nocaseglob}, @code{nullglob}, +and @code{dotglob} options. The @code{GLOBIGNORE} shell variable may be used to restrict the set of filenames matching a -@var{pattern}. If @code{GLOBIGNORE} +pattern. If @code{GLOBIGNORE} is set, each matching filename that also matches one of the patterns in @code{GLOBIGNORE} is removed from the list of matches. The filenames @file{.} and @file{..} -are always ignored, even when @code{GLOBIGNORE}. +are always ignored, even when @code{GLOBIGNORE} is set. However, setting @code{GLOBIGNORE} has the effect of enabling the @code{dotglob} shell option, so all other filenames beginning with a @@ -1323,6 +1618,16 @@ To get the old behavior of ignoring filenames beginning with a The @code{dotglob} option is disabled when @code{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 NUL character may not +occur in a pattern. 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 * @@ -1339,6 +1644,49 @@ 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. + +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.2} standard: +@example +alnum alpha ascii blank cntrl digit graph lower +print punct space upper xdigit +@end example +@noindent +A character class matches any character belonging to that class. + +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 @@ -1369,11 +1717,11 @@ descriptor 0). If the first character of the redirection operator is @samp{>}, the redirection refers to the standard output (file descriptor 1). -The word that follows the redirection operator in the following -descriptions is subjected to brace expansion, tilde expansion, -parameter expansion, command substitution, arithmetic expansion, -quote removal, and filename expansion. If it expands to more -than one word, Bash reports an error. +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, and filename expansion. +If it expands to more than one word, Bash reports an error. Note that the order of redirections is significant. For example, the command @@ -1391,6 +1739,8 @@ 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}. +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} @@ -1416,13 +1766,13 @@ The general format for redirecting output is: [n]>[|]@var{word} @end example -If the redirection operator is @samp{>}, and the @samp{-C} option to the -@code{set} builtin has been enabled, the redirection will fail if the -filename whose name results from the expansion of @var{word} exists. -If the redirection operator is @samp{>|}, -then the value of the @samp{-C} option to the @code{set} -builtin command is not tested, and the redirection is attempted even -if the file named by @var{word} exists. +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 filename 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 @@ -1479,7 +1829,8 @@ No parameter expansion, command substitution, filename expansion, or arithmetic expansion is performed on @var{word}. If any characters in @var{word} are quoted, the @var{delimiter} is the result of quote removal on @var{word}, -and the lines in the here-document are not expanded. Otherwise, +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 pair @code{\newline} is ignored, and @samp{\} @@ -1501,7 +1852,10 @@ The redirection operator is used to duplicate input file descriptors. If @var{word} expands to one or more digits, the file descriptor denoted by @code{n} -is made to be a copy of that file descriptor. If @var{word} +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 @code{n} is closed. If @code{n} is not specified, the standard input (file descriptor 0) is used. @@ -1513,6 +1867,8 @@ The operator is used similarly to duplicate output file descriptors. If @code{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 @code{n} is omitted, and @var{word} does not expand to one or more digits, the standard output and standard error are redirected as described previously. @@ -1532,8 +1888,15 @@ is not specified. If the file does not exist, it is created. @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 @@ -1541,8 +1904,54 @@ is not specified. If the file does not exist, it is created. * 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 @@ -1568,26 +1977,118 @@ If the name is neither a shell function nor a builtin, and contains no slashes, Bash searches each element of @code{$PATH} for a directory containing an executable file by that name. Bash uses a hash table to remember the full -filenames of executable files (see the description of -@code{hash} in @ref{Bourne Shell Builtins}) to avoid multiple -@code{PATH} searches. +pathnames of executable files to avoid multiple @code{PATH} searches +(see the description of @code{hash} in @ref{Bourne Shell Builtins}). A full search of the directories in @code{$PATH} is performed only if the command is not found in the hash table. If the search is unsuccessful, the shell prints an error -message and returns a nonzero exit status. +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. +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 -@var{shell script} (@pxref{Shell Scripts}). +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 IDs, including those of background jobs +(@pxref{Lists}), the value of @code{$$}, and the value of +@code{$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 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. + @node Environment @subsection Environment @cindex environment @@ -1608,8 +2109,9 @@ in the environment is modified, the new value becomes part of the environment, replacing the old. The environment inherited by any executed command consists of the shell's initial environment, whose values may be modified in the shell, -less any pairs removed by the @code{unset} command, plus any -additions via the @code{export} and @samp{declare -x} commands. +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 @@ -1617,7 +2119,7 @@ parameter assignments, as described in @ref{Shell Parameters}. These assignment statements affect only the environment seen by that command. -If the @samp{-k} flag is set (@pxref{The Set Builtin}, then all +If the @samp{-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. @@ -1629,7 +2131,7 @@ command in its environment. @subsection Exit Status @cindex exit status -For the purposes of the shell, a command which exits with a +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 @@ -1642,6 +2144,9 @@ 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}). @@ -1649,12 +2154,13 @@ 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, it ignores +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). @@ -1663,21 +2169,37 @@ In all cases, Bash ignores @code{SIGQUIT}. If job control is in effect (@pxref{Job Control}), Bash ignores @code{SIGTTIN}, @code{SIGTTOU}, and @code{SIGTSTP}. -Synchronous jobs started by Bash have signals set to the -values inherited by the shell from its parent. When job control -is not in effect, background jobs (commands terminated with @samp{&}) -ignore @code{SIGINT} and @code{SIGQUIT}. -Commands run as a result of command substitution ignore the -keyboard-generated job control signals +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, it resends the @code{SIGHUP} -to all jobs, running or stopped. To prevent the shell from -sending the @code{SIGHUP} signal to a particular job, remove it -from the jobs table with the @code{disown} builtin -(@pxref{Job Control Builtins}) -or use @code{disown -h} to mark it to not receive @code{SIGHUP}. +Before exiting, it 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 @@ -1711,7 +2233,10 @@ bash filename @var{arguments} @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. +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 kernel's command execution mechanism. If the first line of a script begins with @@ -1737,9 +2262,9 @@ name and argument to a maximum of 32 characters. @end menu This section briefly summarizes things which Bash inherits from -the Bourne Shell: builtins, variables, -and other features. It also lists the significant differences -between Bash and the Bourne Shell. +the Bourne Shell: builtins, variables, and other features. +It also lists the significant differences between Bash and the Bourne Shell. +Many of the builtins have been extended by @sc{POSIX} or Bash. @node Bourne Shell Builtins @section Bourne Shell Builtins @@ -1755,6 +2280,7 @@ Shell. These commands are implemented as specified by the @sc{POSIX} : [@var{arguments}] @end example Do nothing beyond expanding @var{arguments} and performing redirections. +The return status is zero. @item . @btindex . @@ -1762,7 +2288,13 @@ Do nothing beyond expanding @var{arguments} and performing redirections. . @var{filename} @end example Read and execute commands from the @var{filename} argument in the -current shell context. +current shell context. If @var{filename} does not contain a slash, +the @code{$PATH} variable is used to find +@var{filename}. The current directory is searched if @var{filename} +is not found in @code{$PATH}. +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. @item break @btindex break @@ -1771,6 +2303,8 @@ 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 @@ -1782,8 +2316,11 @@ is not given, the value of the @code{HOME} shell variable is used. If the shell variable @code{CDPATH} exists, it is used as a search path. If @var{directory} begins with a slash, @code{CDPATH} is not used. The @samp{-P} option means -to not follow symbolic links; symlinks are followed by default or with the -@samp{-L} option. +to not follow symbolic links; symbolic links are followed by default +or with the @samp{-L} option. +If @var{directory} is @samp{-}, it is equivalent to @code{$OLDPWD}. +The return status is zero if the directory is successfully changed, +non-zero otherwise. @item continue @btindex continue @@ -1792,33 +2329,39 @@ 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. +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. +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}] +exec [-cl] [-a @var{name}] [@var{command} [@var{arguments}]] @end example If @var{command} -is supplied, it replaces the shell. -If the @samp{-l} option is supplied, -the shell places a dash in the zeroth arg passed to @var{command}. +is supplied, it replaces the shell without creating a new process. +If the @samp{-l} option is supplied, the shell places a dash in the +zeroth arg passed to @var{command}. This is what the @code{login} program does. -The @samp{-c} option causes @var{command} -to be executed with an empty environment. -If @samp{-a} is supplied, the shell passes @var{name} -as the zeroth argument to @var{command}. +The @samp{-c} option causes @var{command} to be executed with an empty +environment. +If @samp{-a} is supplied, the shell passes @var{name} as the zeroth +argument to @var{command}. If no @var{command} is specified, redirections may be used to affect -the current shell environment. +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 @@ -1826,6 +2369,7 @@ the current shell environment. exit [@var{n}] @end example Exit the shell, returning a status of @var{n} to the shell's parent. +Any trap on @code{EXIT} is executed before the shell terminates. @item export @btindex export @@ -1834,10 +2378,14 @@ export [-fn] [-p] [@var{name}[=@var{value}]] @end example Mark each @var{name} to be passed to child processes in the environment. If the @samp{-f} option is supplied, the @var{name}s -refer to shell functions. The @samp{-n} option means to no longer mark -each @var{name} for export. +refer to shell functions; otherwise the names refer to shell variables. +The @samp{-n} option means to no longer mark each @var{name} for export. If no @var{names} are supplied, or if the @samp{-p} option is given, a list of exported names is displayed. +The @samp{-p} option displays output in a form that may be reused as input. +The return status is zero unless an invalid option is supplied, one of +the names is not a valid shell variable name, or @samp{-f} is supplied +with a name that is not a shell function. @item getopts @btindex getopts @@ -1852,26 +2400,34 @@ Each time it is invoked, @code{getopts} places the next option in the shell variable @var{name}, initializing @var{name} if it does not exist, and the index of the next argument to be processed into the -variable @code{OPTIND}. @code{OPTIND} -is initialized to 1 each time the shell or a shell script -is invoked. When an option requires an argument, +variable @code{OPTIND}. +@code{OPTIND} is initialized to 1 each time the shell or a shell script +is invoked. +When an option requires an argument, @code{getopts} places that argument into the variable @code{OPTARG}. -The shell does not reset @code{OPTIND} -automatically; it must be manually reset between multiple -calls to @code{getopts} -within the same shell invocation if a new set of parameters -is to be used. +The shell does not reset @code{OPTIND} automatically; it must be manually +reset between multiple calls to @code{getopts} within the same shell +invocation if a new set of parameters is to be used. + +When the end of options is encountered, @code{getopts} exits with a +return value greater than zero. +@code{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 illegal options or missing option arguments are +are printed when invalid options or missing option arguments are encountered. If the variable @code{OPTERR} -is set to 0, no error message will be displayed, even if the first +is set to 0, no error messages will be displayed, even if the first character of @code{optstring} is not a colon. -If an illegal option is seen, +If an invalid option is seen, @code{getopts} places @samp{?} into @var{name} and, if not silent, prints an error message and unsets @code{OPTARG}. If @code{getopts} is silent, the option character found is placed in @@ -1883,72 +2439,152 @@ is not silent, a question mark (@samp{?}) is placed in @var{name}, If @code{getopts} is silent, then a colon (@samp{:}) is placed in @var{name} and @code{OPTARG} is set to the option character found. -@code{getopts} -normally parses the positional parameters, but if more arguments are -given in @var{args}, @code{getopts} parses those instead. - @item hash @btindex hash @example hash [-r] [-p @var{filename}] [@var{name}] @end example -Remember the full filenames of commands specified as arguments, -so they need not be searched for on subsequent invocations. The -commands are found by searching through the directories listed in -@code{$PATH}. The @samp{-p} option inhibits the path search, and -@var{filename} is used as the location of @var{name}. -The @samp{-r} option causes the shell to forget -all remembered locations. If no arguments are given, information -about remembered commands is printed. +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 +@code{$PATH}. +The @samp{-p} option inhibits the path search, and @var{filename} is +used as the location of @var{name}. +The @samp{-r} option causes the shell to forget all remembered locations. +If no arguments are given, information about remembered commands is printed. +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 current working directory. If the @samp{-P} option is supplied, -the path printed will not contain symbolic links. If the @samp{-L} option -is supplied, the path printed may contain symbolic links. +Print the current working directory. +If the @samp{-P} option is supplied, the path printed will not +contain symbolic links. +If the @samp{-L} option is supplied, the path printed may contain +symbolic links. +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}] @dots{} @end example -Mark each @var{name} as unchangable. The values of these names may not -be changed by subsequent assignment. If the @samp{-f} option is supplied, -each @var{name} refers to a shell function. The @samp{-a} option means -each @var{name} refers to an array variable. +Mark each @var{name} as readonly. +The values of these names may not be changed by subsequent assignment. +If the @samp{-f} option is supplied, each @var{name} refers to a shell +function. +The @samp{-a} option means each @var{name} refers to an array variable. If no @var{name} arguments are given, or if the @samp{-p} option is supplied, a list of all readonly names is printed. +The @samp{-p} option causes output to be displayed in a format that +may be reused as input. +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 @samp{-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 value @var{n}. This may also be used -to terminate execution of a script being executed with the @code{.} -builtin. +Cause a shell function to exit with the return value @var{n}. +This may also be used to terminate execution of a script being executed +with the @code{.} builtin, returning either @var{n} or the exit status +of the last command executed within the script as the exit status of the +script. +The return status is false if @code{return} is used outside a function +and not during the execution of a script by @samp{.}. @item shift @btindex shift @example shift [@var{n}] @end example -Shift positional parameters to the left by @var{n}. -The positional parameters from @var{n}+1 @dots{} -are renamed to -@code{$1} @dots{} . -Parameters represented by the numbers -@code{$#} to @var{n}+1 are unset. @var{n} -must be a non-negative number less than or equal to @code{$#}. +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. +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 (@pxref{Bash Conditional Expressions}). +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}. + +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 @@ -1956,6 +2592,7 @@ Evaluate a conditional expression (@pxref{Bash Conditional Expressions}). 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 @@ -1971,7 +2608,8 @@ each @var{sigspec} is ignored by the shell and commands it invokes. If @var{arg} is @samp{-p}, the shell displays the trap commands associated with each @var{sigspec}. If no arguments are supplied, or only @samp{-p} is given, @code{trap} prints the list of commands -associated with each signal number. +associated with each signal number in a form that may be reused as +shell input. 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} @@ -1985,10 +2623,13 @@ 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 [-S] [@var{mode}] +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; @@ -1997,6 +2638,10 @@ to that accepted by the @code{chmod} command. If @var{mode} is omitted, the current value of the mask is printed. If the @samp{-S} option is supplied without a @var{mode} argument, the mask is printed in a symbolic format. +If the @samp{-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. @item unset @btindex unset @@ -2008,8 +2653,9 @@ If no options are supplied, or the @samp{-v} option is given, each @var{name} refers to a shell variable. If the @samp{-f} option is given, the @var{name}s refer to shell functions, and the function definition is removed. -Read-only variables and functions may not be unset. - +Readonly variables and functions may not be unset. +The return status is zero unless a @var{name} does not exist or is +readonly. @end table @node Bourne Shell Variables @@ -2020,48 +2666,50 @@ In some cases, Bash assigns a default value to the variable. @vtable @code -@item IFS -A list of characters that separate fields; used when the shell splits -words as part of expansion. - -@item PATH -A colon-separated list of directories in which the shell looks for -commands. +@item 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 CDPATH -A colon-separated list of directories used as a search path for -the @code{cd} command. - -@item MAILPATH -A colon-separated list of files which the shell periodically checks -for new mail. You can -also specify what message is printed by separating the file name from -the message with a @samp{?}. When used in the text of the message, -@code{$_} stands for the name of the current mailfile. +@item 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 @code{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. + @item PS1 The primary prompt string. The default value is @samp{\s-\v\$ }. @item PS2 The secondary prompt string. The default value is @samp{> }. -@item OPTIND -The index of the last option processed by the -@code{getopts} builtin. - -@item OPTARG -The value of the last option argument processed by the -@code{getopts} builtin. - @end vtable @node Other Bourne Shell Features @@ -2072,155 +2720,235 @@ The value of the last option argument processed by the Bash and the Bourne shell. @end menu -Bash implements essentially the same grammar, parameter and variable -expansion, redirection, and quoting as the Bourne Shell. Bash uses the -@sc{POSIX} 1003.2 standard as the specification of how these features are to be -implemented. There are some differences between the traditional Bourne -shell and the @sc{POSIX} standard; this section quickly details the differences -of significance. A number of these differences are explained in greater -depth in subsequent sections. +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 +subsequent sections. @node Major Differences From The Bourne Shell @subsection Major Differences From The SVR4.2 Bourne Shell +@itemize @bullet + +@item Bash is @sc{POSIX}-conformant, even where the @sc{POSIX} specification differs from traditional @code{sh} behavior. +@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 has command history (@pxref{Bash History Facilities}) and the @code{history} and @code{fc} builtins to manipulate it. -Bash implements @code{csh}-like history expansion (@pxref{History Interaction}). +@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. -Some of the Bash builtins take options to act on arrays. Bash provides -some built-in array variables. +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 @samp{-D}, @samp{--dump-strings}, and @samp{--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 +@code{TIMEFORMAT} variable. + +@item Bash includes the @code{select} compound command, which allows the -generation of simple menus (@pxref{Korn Shell Constructs}). +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}). -Bash provides shell arithmetic and arithmetic expansion -(@pxref{Shell Arithmetic}). - -The @sc{POSIX} and @code{ksh}-style @code{$()} form of command substitution -is implemented (@pxref{Command Substitution}), -and preferred to the Bourne shell's @code{``} (which -is also implemented for backwards compatibility). +@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. -Bash includes the @sc{POSIX} and @code{ksh}-style pattern removal -@samp{%}, @samp{#}, @samp{%%} and @samp{##} constructs to remove -leading or trailing substrings from variable values -(@pxref{Shell Parameter Expansion}). +@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}). -The expansion @code{$@{#xx@}}, which returns the length of @code{$xx}, +@item +The expansion @code{$@{#xx@}}, which returns the length of @code{$@{xx@}}, is supported (@pxref{Shell Parameter Expansion}). -The @code{$'@dots{}'} quoting syntax, which expands ANSI-C -backslash-escaped characters in the text between the single quotes, -is supported (@pxref{ANSI-C Quoting}). - -Bash supports the @code{$"@dots{}"} quoting syntax to do -locale-specific translation of the characters between the double -quotes. The @samp{-D} and @samp{--dump-strings} invocation options -list the translatable strings found in a script -(@pxref{Locale Translation}). - +@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}, optionally beginning at @var{offset}, is present +@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 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 (@code{UID}, @code{EUID}, and @code{GROUPS}), the current host (@code{HOSTTYPE}, @code{OSTYPE}, @code{MACHTYPE}, and @code{HOSTNAME}), and the instance of Bash that is running (@code{BASH}, -@code{BASH_VERSION}, and @code{BASH_VERSINFO}. @xref{Bash Variables}, +@code{BASH_VERSION}, and @code{BASH_VERSINFO}). @xref{Bash Variables}, for details. +@item The @code{IFS} variable is used to split only the results of expansion, not all words (@pxref{Word Splitting}). This closes a longstanding shell security hole. +@item +Bash implements the full set of @sc{POSIX.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. +@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 output redirection operators. +to input and output redirection operators. +@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 The @code{noclobber} option is available to avoid overwriting existing files with output redirection (@pxref{The Set Builtin}). The @samp{>|} redirection operator may be used to override @code{noclobber}. -Bash interprets special backslash-escaped characters in the prompt -strings when interactive (@pxref{Printing a Prompt}). +@item +The Bash @code{cd} and @code{pwd} builtins (@pxref{Bourne Shell Builtins}) +each take @samp{-L} and @samp{-P} builtins to switch between logical and +physical modes. -Bash allows you to write a function to override a builtin, and provides +@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}). -The Bash @code{hash} builtin allows a name to be associated with -an arbitrary filename, even when that filename cannot be found by -searching the @code{$PATH}, using @samp{hash -p}. +@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 -(@pxref{Shell Functions}). +using @code{export -f} (@pxref{Shell Functions}). + +@item +The Bash @code{export}, @code{readonly}, and @code{declare} builtins can +take a @samp{-f} option to act on shell functions, a @samp{-p} option to +display variables with various attributes set in a format that can be +used as shell input, a @samp{-n} option to remove various variable +attributes, and @samp{name=value} arguments to set variable attributes +and values simultaneously. +@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 @code{$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 @samp{-r} option, and will use the @code{REPLY} variable as a @@ -2228,69 +2956,79 @@ default if no arguments are supplied. The Bash @code{read} builtin also accepts a prompt string with the @samp{-p} option and will use Readline to obtain the line when given the @samp{-e} option. +@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}). +@item Bash has much more optional behavior controllable with the @code{set} builtin (@pxref{The Set Builtin}). -The @code{disown} builtin can remove a job from the internal shell -job table (@pxref{Job Control Builtins}). - -The @code{return} builtin may be used to abort execution of scripts -executed with the @code{.} or @code{source} builtins -(@pxref{Bourne Shell Builtins}). - +@item The @code{test} builtin (@pxref{Bourne Shell Builtins}) -is slightly different, as it implements the -@sc{POSIX} 1003.2 algorithm, which specifies the behavior based on the -number of arguments. +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 after every simple command. The @code{DEBUG} trap is not inherited by shell functions. -The Bash @code{export}, @code{readonly}, and @code{declare} builtins can -take a @samp{-f} option to act on shell functions, a @samp{-p} option to -display variables with various attributes set in a format that can be -used as shell input, a @samp{-n} option to remove various variable -attributes, and @samp{name=value} arguments to set variable attributes -and values simultaneously. - -The Bash @code{cd} and @code{pwd} builtins (@pxref{Bourne Shell Builtins}) -each take @samp{-L} and @samp{-P} builtins to switch between logical and -physical modes. - +@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 @samp{-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{C Shell Builtins}). +(@pxref{The Directory Stack}). Bash also makes the directory stack visible as the value of the @code{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 @sc{SVR4.2} shell restricted mode is too limited. -Bash has the @code{time} reserved word and command timing (@pxref{Pipelines}). -The display of the timing statistics may be controlled with the -@code{TIMEFORMAT} variable. +@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 @sc{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 @code{SHACCT} variable or perform shell accounting. +@item The @sc{SVR4.2} @code{sh} uses a @code{TIMEOUT} variable like Bash uses @code{TMOUT}. -More features unique to Bash may be found in -@ref{Bash Features}. +@end itemize + +@noindent +More features unique to Bash may be found in @ref{Bash Features}. @subsection Implementation Differences From The SVR4.2 Shell @@ -2313,7 +3051,7 @@ This can be the cause of some hard-to-find errors. The @sc{SVR4.2} shell uses a baroque memory management scheme based on trapping @code{SIGSEGV}. If the shell is started from a process with @code{SIGSEGV} blocked (e.g., by using the @code{system()} C library -function call), the shell misbehaves badly. +function call), it misbehaves badly. @item In a questionable attempt at security, the @sc{SVR4.2} shell, @@ -2323,12 +3061,12 @@ magic threshold value, commonly 100. This can lead to unexpected results. @item -The @sc{SVR4.2} shell does not allow users to trap @code{SIGALRM} or -@code{SIGCHLD}. +The @sc{SVR4.2} shell does not allow users to trap @code{SIGSEGV}, +@code{SIGALRM}, or @code{SIGCHLD}. @item -For some reason, the @sc{SVR4.2} shell does not allow the @code{MAILCHECK} -variable to be unset. +The @sc{SVR4.2} shell does not allow the @code{IFS}, @code{MAILCHECK}, +@code{PATH}, @code{PS1}, or @code{PS2} variables to be unset. @item The @sc{SVR4.2} shell treats @samp{^} as the undocumented equivalent of @@ -2350,515 +3088,6 @@ The @sc{SVR4.2} shell behaves differently when invoked as @code{jsh} (it turns on job control). @end itemize -@node Csh Features -@chapter C-Shell Style Features - -The C-Shell (@dfn{@code{csh}}) was created by Bill Joy at The -University of California at Berkeley. It -is generally considered to have better features for interactive use than -the original Bourne shell. Some of the @code{csh} features present in -Bash include job control, history expansion, `protected' redirection, and -several variables to control the interactive behaviour of the shell -(e.g., @code{IGNOREEOF}). - -@xref{Using History Interactively}, for details on history expansion. - -@menu -* Brace Expansion:: Expansion of expressions within braces. -* Tilde Expansion:: Expansion of the ~ character. -* C Shell Builtins:: Builtin commands adopted from the C Shell. -* C Shell Variables:: Variables which Bash uses in essentially - the same way as the C Shell. -@end menu - -@node Brace Expansion -@section Brace Expansion -@cindex brace expansion -@cindex expansion, brace - -Brace expansion -is a mechanism by which arbitrary strings -may be generated. This mechanism is similar to -@var{filename expansion} (@pxref{Filename Expansion}), -but the file names generated -need not exist. Patterns to be brace expanded take -the form of an optional @var{preamble}, -followed by a series of comma-separated strings -between a pair of braces, followed by an optional @var{postamble}. -The preamble is prepended to each string contained -within the braces, and the postamble is then appended -to each resulting string, expanding left to right. - -Brace expansions may be nested. The results of each expanded -string are not sorted; left to right order is preserved. -For example, -@example -bash$ echo a@{d,c,b@}e -ade ace abe -@end example - -Brace expansion is performed before any other expansions, -and any characters special to other expansions are preserved -in the result. It is strictly textual. Bash -does not apply any syntactic interpretation to the context of the -expansion or the text between the braces. - -A correctly-formed brace expansion must contain unquoted opening -and closing braces, and at least one unquoted comma. -Any incorrectly formed brace expansion is left unchanged. - -This construct is typically used as shorthand when the common -prefix of the strings to be generated is longer than in the -above example: -@example -mkdir /usr/local/src/bash/@{old,new,dist,bugs@} -@end example -or -@example -chown root /usr/@{ucb/@{ex,edit@},lib/@{ex?.?*,how_ex@}@} -@end example - -@node Tilde Expansion -@section Tilde Expansion -@cindex tilde expansion -@cindex expansion, tilde - -Bash has tilde (~) expansion, similar, but not identical, to that of -@code{csh}. The following table shows what unquoted words beginning -with a tilde expand to. - -@table @code -@item ~ -The current value of @code{$HOME}. -@item ~/foo -@file{$HOME/foo} - -@item ~fred/foo -The subdirectory @code{foo} of the home directory of the user -@code{fred}. - -@item ~+/foo -@file{$PWD/foo} - -@item ~-/foo -@file{$OLDPWD/foo} -@end table - -Bash will also tilde expand words following redirection operators -and words following @samp{=} in assignment statements. - -@node C Shell Builtins -@section C Shell Builtins - -Bash has several builtin commands whose definition is very similar -to @code{csh}. - -@table @code -@btindex pushd -@item pushd -@example -pushd [@var{dir} | @var{+N} | @var{-N}] [-n] -@end example - -Save the current directory on a list and then @code{cd} to -@var{dir}. With no -arguments, exchanges the top two directories. - -@table @code -@item +@var{N} -Brings the @var{N}th directory (counting from the left of the -list printed by @code{dirs}, 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 -@code{cd}s to @var{dir}. You can see the saved directory list -with the @code{dirs} command. -@end table - -@item popd -@btindex popd -@example -popd [+@var{N} | -@var{N}] [-n] -@end example - -Pop the directory stack, and @code{cd} to the new top directory. When -no arguments are given, @code{popd} -removes the top directory from the stack and -performs a @code{cd} to the new top directory. The -elements are numbered from 0 starting at the first directory listed with -@code{dirs}; i.e., @code{popd} is equivalent to @code{popd +0}. -@table @code -@item +@var{N} -Removes the @var{N}th directory (counting from the left of the -list printed by @code{dirs}), starting with zero. -@item -@var{N} -Removes the @var{N}th directory (counting from the right of the -list printed by @code{dirs}), starting with zero. -@item -n -Suppresses the normal change of directory when removing directories -from the stack, so that only the stack is manipulated. -@end table - -@item dirs -@btindex dirs -@example -dirs [+@var{N} | -@var{N}] [-clvp] -@end example -Display the list of currently remembered directories. Directories -find their way onto the list with the @code{pushd} command; you can get -back up through the list with the @code{popd} command. -@table @code -@item +@var{N} -Displays the @var{N}th directory (counting from the left of the -list printed by @code{dirs} when invoked without options), starting -with zero. -@item -@var{N} -Displays the @var{N}th directory (counting from the right of the -list printed by @code{dirs} when invoked without options), starting -with zero. -@item -c -Clears the directory stack by deleting all of the elements. -@item -l -Produces a longer listing; the default listing format uses a -tilde to denote the home directory. -@item -p -Causes @code{dirs} to print the directory stack with one entry per -line. -@item -v -Causes @code{dirs} to print the directory stack with one entry per -line, prepending each entry with its index in the stack. -@end table - -@item history -@btindex history -@example -history [-c] [@var{n}] -history [-anrw] [@var{filename}] -history -ps @var{arg} -@end example - -Display the history list with line numbers. Lines prefixed with -with a @samp{*} have been modified. An argument of @var{n} says -to list only the last @var{n} lines. Options, if supplied, have -the following meanings: - -@table @code -@item -w -Write out the current history to the history file. - -@item -r -Read the current history file and append its contents to -the history list. - -@item -a -Append the new -history lines (history lines entered since the beginning of the -current Bash session) to the history file. - -@item -n -Append the history lines not already read from the history file -to the current history list. These are lines appended to the history -file since the beginning of the current Bash session. - -@item -c -Clear the history list. This may be combined -with the other options to replace the history list completely. - -@item -s -The @var{arg}s are added to the end of -the history list as a single entry. - -@item -p -Perform history substitution on the @var{arg}s and display the result -on the standard output, without storing the results in the history list. -@end table - -When the @samp{-w}, @samp{-r}, @samp{-a}, or @samp{-n} option is -used, if @var{filename} -is given, then it is used as the history file. If not, then -the value of the @code{HISTFILE} variable is used. - -@item logout -@btindex logout -Exit a login shell. - -@item source -@btindex source -A synonym for @code{.} (@pxref{Bourne Shell Builtins}). - -@end table - -@node C Shell Variables -@section C Shell Variables - -@vtable @code - -@item IGNOREEOF -If this variable is set, its value is used the number of consecutive -@code{EOF}s Bash will read before exiting. By default, Bash will exit -upon reading a single @code{EOF}. If @code{IGNOREEOF} is not set to -a numeric value, Bash acts as if its value were 10. - -@end vtable - -@node Korn Shell Features -@chapter Korn Shell Style Features - -This section describes features primarily inspired by the -Korn Shell (@code{ksh}). In some cases, the @sc{POSIX} 1003.2 -standard has adopted these commands and variables from the -Korn Shell; Bash implements those features using the @sc{POSIX} -standard as a guide. - -@menu -* Korn Shell Constructs:: Shell grammar constructs adopted from the - Korn Shell -* Korn Shell Builtins:: Builtin commands adopted from the Korn Shell. -* Korn Shell Variables:: Variables which Bash uses in essentially - the same way as the Korn Shell. -* Aliases:: Substituting one command for another. -@end menu - -@node Korn Shell Constructs -@section Korn Shell Constructs - -Bash includes the Korn Shell @code{select} construct. This construct -allows the easy generation of menus. It has almost the same syntax as -the @code{for} command. - -The syntax of the @code{select} command is: -@rwindex select -@example -select @var{name} [in @var{words} @dots{}]; do @var{commands}; done -@end example - -The list of words following @code{in} is expanded, generating a list -of items. The set of expanded words is printed on the standard -error, each preceded by a number. If the @samp{in @var{words}} -is omitted, the positional parameters are printed. The -@code{PS3} prompt is then displayed and a line is read from the standard -input. If the line consists of a number corresponding to one of -the displayed words, then the value of @var{name} -is set to that word. If the line is empty, the words and prompt -are displayed again. If @code{EOF} is read, the @code{select} -command completes. Any other value read causes @var{name} -to be set to null. The line read is saved in the variable -@code{REPLY}. - -The @var{commands} are executed after each selection until a -@code{break} or @code{return} command is executed, at which -point the @code{select} command completes. - -Bash also has adopted command timing from the Korn shell. If the -@code{time} reserved word precedes a pipeline, which may consist -of a single command, timing statistics for the pipeline are displayed -when it completes. -The statistics currently consist of elapsed (wall-clock) time and -user and system time consumed by the command's execution. - -The use of @code{time} as a reserved word permits the timing of -shell builtins, shell functions, and pipelines. An external -@code{time} command cannot time these easily. - -@node Korn Shell Builtins -@section Korn Shell Builtins - -This section describes Bash builtin commands taken from @code{ksh}. - -@table @code - -@item fc -@btindex fc -@example -@code{fc [-e @var{ename}] [-nlr] [@var{first}] [@var{last}]} -@code{fc -s [@var{pat}=@var{rep}] [@var{command}]} -@end example - -Fix Command. In the first form, a range of commands from @var{first} to -@var{last} is selected from the history list. Both @var{first} and -@var{last} may be specified as a string (to locate the most recent -command beginning with that string) or as a number (an index into the -history list, where a negative number is used as an offset from the -current command number). If @var{last} is not specified it is set to -@var{first}. If @var{first} is not specified it is set to the previous -command for editing and @minus{}16 for listing. If the @samp{-l} flag is -given, the commands are listed on standard output. The @samp{-n} flag -suppresses the command numbers when listing. The @samp{-r} flag -reverses the order of the listing. Otherwise, the editor given by -@var{ename} is invoked on a file containing those commands. If -@var{ename} is not given, the value of the following variable expansion -is used: @code{$@{FCEDIT:-$@{EDITOR:-vi@}@}}. This says to use the -value of the @code{FCEDIT} variable if set, or the value of the -@code{EDITOR} variable if that is set, or @code{vi} if neither is set. -When editing is complete, the edited commands are echoed and executed. - -In the second form, @var{command} is re-executed after each instance -of @var{pat} in the selected command is replaced by @var{rep}. - -A useful alias to use with the @code{fc} command is @code{r='fc -s'}, so -that typing @samp{r cc} runs the last command beginning with @code{cc} -and typing @samp{r} re-executes the last command (@pxref{Aliases}). - -@item let -@btindex let -The @code{let} builtin allows arithmetic to be performed on shell variables. -For details, refer to @ref{Arithmetic Builtins}. - -@item typeset -@btindex typeset -The @code{typeset} command is supplied for compatibility with the Korn -shell; however, it has been deprecated in favor of the -@code{declare} command (@pxref{Bash Builtins}). - -@end table - -@node Korn Shell Variables -@section Korn Shell Variables - -@vtable @code - -@item REPLY -The default variable for the @code{read} builtin. - -@item RANDOM -Each time this parameter is referenced, a random integer -between 0 and 32767 is generated. Assigning a value to this -variable seeds the random number generator. - -@item SECONDS -This variable expands to the number of seconds since the -shell was started. Assignment to this variable resets -the count to the value assigned, and the expanded value -becomes the value assigned plus the number of seconds -since the assignment. - -@item PS3 -The value of this variable is used as the prompt for the -@code{select} command. If this variable is not set, the -@code{select} command prompts with @samp{#? } - -@item PS4 -This is the prompt printed before the command line is echoed -when the @samp{-x} option is set (@pxref{The Set Builtin}). -The default is @samp{+ }. - -@item PWD -The current working directory as set by the @code{cd} builtin. - -@item OLDPWD -The previous working directory as set by the @code{cd} builtin. - -@item TMOUT -If set to a value greater than zero, the value is interpreted as -the number of seconds to wait for input after issuing the primary -prompt. -Bash terminates after that number of seconds if input does -not arrive. - -@item LINENO -The line number in the script or shell function currently executing. - -@item FCEDIT -The editor used as a default by the @code{fc} builtin command. - -@end vtable - -@node Aliases -@section Aliases -@cindex alias expansion - -@menu -* Alias Builtins:: Builtins commands to maniuplate aliases. -@end menu - -The shell maintains a list of @var{aliases} -that may be set and unset with the @code{alias} and -@code{unalias} builtin commands. - -The first word of each command, if unquoted, -is checked to see if it has an -alias. If so, that word is replaced by the text of the alias. -The alias name and the replacement text may contain any valid -shell input, including shell metacharacters, with the exception -that the alias name may not contain @key{=}. -The first word of the replacement text is tested for -aliases, but a word that is identical to an alias being expanded -is not expanded a second time. This means that one may alias -@code{ls} to @code{"ls -F"}, -for instance, and Bash does not try to recursively expand the -replacement text. If the last character of the alias value is a -space or tab character, then the next command word following the -alias is also checked for alias expansion. - -Aliases are created and listed with the @code{alias} -command, and removed with the @code{unalias} command. - -There is no mechanism for using arguments in the replacement text, -as in @code{csh}. -If arguments are needed, a shell function should be used -(@pxref{Shell Functions}). - -Aliases are not expanded when the shell is not interactive, -unless the @code{expand_aliases} shell option is set using -@code{shopt} (@pxref{Bash Builtins}). - -The rules concerning the definition and use of aliases are -somewhat confusing. Bash -always reads at least one complete line -of input before executing any -of the commands on that line. Aliases are expanded when a -command is read, not when it is executed. Therefore, an -alias definition appearing on the same line as another -command does not take effect until the next line of input is read. -The commands following the alias definition -on that line are not affected by the new alias. -This behavior is also an issue when functions are executed. -Aliases are expanded when the function definition is read, -not when the function is executed, because a function definition -is itself a compound command. As a consequence, aliases -defined in a function are not available until after that -function is executed. To be safe, always put -alias definitions on a separate line, and do not use @code{alias} -in compound commands. - -Note that for almost every purpose, aliases are superseded by -shell functions. - -@node Alias Builtins -@subsection Alias Builtins - -@table @code - -@item alias -@btindex alias -@example -alias [@code{-p}] [@var{name}[=@var{value}] @dots{}] -@end example - -Without arguments or with the @samp{-p} option, @code{alias} prints -the list of aliases on the standard output in a form that allows -them to be reused as input. -If arguments are supplied, an alias is defined for each @var{name} -whose @var{value} is given. If no @var{value} is given, the name -and value of the alias is printed. - -@item unalias -@btindex unalias -@example -unalias [-a] [@var{name} @dots{} ] -@end example - -Remove each @var{name} from the list of aliases. If @samp{-a} is -supplied, all aliases are removed. -@end table - @node Bash Features @chapter Bash Features @@ -2876,7 +3105,9 @@ This section describes features unique to Bash. the @code{test} builtin. * Bash Variables:: List of variables that exist in Bash. * Shell Arithmetic:: Arithmetic on shell variables. -* Arrays:: Array 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 @@ -2899,6 +3130,10 @@ line before the single-character options in order for them to be recognized. @table @code +@item --dump-po-strings +Equivalent to @samp{-D}, but the output is in the GNU @code{gettext} +PO (portable object) file format. + @item --dump-strings Equivalent to @samp{-D}. @@ -2908,9 +3143,8 @@ Display a usage message on standard output and exit sucessfully. @item --login Make this shell act as if it were directly invoked by login. This is equivalent to @samp{exec -l bash} but can be issued from -another shell, such as @code{csh}. If you wanted to replace your -current login shell with a Bash login shell, you would say -@samp{exec bash --login}. +another shell, such as @code{csh}. @samp{exec bash --login} +will replace the current shell with a Bash login shell. @item --noediting Do not use the @sc{GNU} Readline library (@pxref{Command Line Editing}) @@ -2950,8 +3184,8 @@ Bash on the standard output and exit successfully. @end table -There are several single-character options you can give which are -not available with the @code{set} builtin. +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} @@ -2963,10 +3197,10 @@ positional parameters, starting with @code{$0}. Force the shell to run interactively. @item -r -Make the shell restricted. +Make the shell a restricted shell (@pxref{The Restricted Shell}). @item -s -If this flag is present, or if no arguments remain after option +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. @@ -2979,11 +3213,16 @@ are subject to language translation when the current locale is not @code{C} or @code{POSIX} (@pxref{Locale Translation}). This implies the @samp{-n} option; no commands will be executed. +@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 interactive shell An @emph{interactive} shell is one whose input and output are both -connected to terminals (as determined by @code{isatty()}), or one +connected to terminals (as determined by @code{isatty(3)}), or one started with the @samp{-i} option. If arguments remain after option processing, and neither the @@ -3046,13 +3285,13 @@ If Bash is invoked with the name @code{sh}, it tries to mimic the startup behavior of historical versions of @code{sh} as closely as possible, while conforming to the @sc{POSIX} standard as well. -When invoked as a login shell, it first attempts to read and execute -commands from @file{/etc/profile} and @file{~/.profile}, in that order. +When invoked as an interactive login shell, it first attempts to read +and execute commands from @file{/etc/profile} and @file{~/.profile}, in +that order. The @samp{--noprofile} option may be used to inhibit this behavior. -When invoked as an interactive shell with the name @code{sh}, -@code{bash} looks for the variable @code{ENV}, -expands its value if it is defined, and uses the -expanded value as the name of a file to read and execute. +When invoked as an interactive shell with the name @code{sh}, Bash +looks for the variable @code{ENV}, expands its value if it is defined, +and uses the expanded value as the name of a file to read and execute. Since a shell invoked as @code{sh} does not attempt to read and execute commands from any other startup files, the @samp{--rcfile} option has no effect. @@ -3065,10 +3304,10 @@ the startup files are read. When Bash is started in @sc{POSIX} mode, as with the @samp{--posix} command line option, it follows the @sc{POSIX} standard for startup files. -In this mode, the @code{ENV} variable is expanded and commands are read -and executed from the file whose name is the expanded value. +In this mode, interactive shells expand the @code{ENV} variable +and commands are read and executed from the file whose name is the +expanded value. No other startup files are read. -This is done by interactive shells only. 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 @@ -3077,8 +3316,8 @@ file exists and is readable. It will not do this if invoked as @code{sh}. The @samp{--norc} option may be used to inhibit this behavior, and the @samp{--rcfile} option may be used to force another file to be read, but -rshd does not generally invoke the shell with those options or allow -them to be specified. +@code{rshd} does not generally invoke the shell with those options or +allow them to be specified. @node Is This Shell Interactive? @section Is This Shell Interactive? @@ -3089,8 +3328,8 @@ is one whose input and output are both connected to terminals (as determined by @code{isatty(3)}), or one started with the @samp{-i} option. -You may wish to determine within a startup script whether Bash is -running interactively or not. To do this, examine the variable +To determine within a startup script whether Bash is +running interactively or not, examine the variable @code{$PS1}; it is unset in non-interactive shells, and set in interactive shells. Thus: @@ -3102,7 +3341,8 @@ else fi @end example -Alternatively, you may test the value of the @samp{-} special parameter. +Alternatively, startup scripts may test the value of the @samp{-} +special parameter. It contains @code{i} when the shell is interactive. For example: @example @@ -3123,7 +3363,8 @@ or have been extended in Bash. @item bind @btindex bind @example -bind [-m @var{keymap}] [-lpsvPSV] [-q @var{name}] [-r @var{keyseq}] +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}] @var{keyseq:function-name} @end example @@ -3153,65 +3394,83 @@ names are @code{emacs} is equivalent to @code{emacs-standard}. @item -l -List the names of all Readline functions +List the names of all Readline functions. @item -p Display Readline function names and bindings in such a way that they -can be re-read +can be re-read. @item -P -List current Readline function names and bindings +List current Readline function names and bindings. @item -v Display Readline variable names and values in such a way that they -can be re-read +can be re-read. @item -V -List current Readline variable names and values +List current Readline variable names and values. @item -s Display Readline key sequences bound to macros and the strings they output -in such a way that they can be re-read +in such a way that they can be re-read. @item -S -Display Readline key sequences bound to macros and the strings they output +Display Readline key sequences bound to macros and the strings they output. @item -f @var{filename} -Read key bindings from @var{filename} +Read key bindings from @var{filename}. -@item -q -Query about which keys invoke the named @var{function} +@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} +Remove any current binding for @var{keyseq}. @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. This is useful when you wish to define a -shell function with the same name as a shell builtin, but need the -functionality of the builtin within the function itself. +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 command @btindex command @example -command [-pVv] @var{command} [@var{args} @dots{}] +command [-pVv] @var{command} [@var{arguments} @dots{}] @end example -Runs @var{command} with @var{arg} ignoring shell functions. If -you have a shell function called @code{ls}, and you wish to call -the command @code{ls}, you can say @samp{command ls}. The -@samp{-p} option means to use a default value for @code{$PATH} +Runs @var{command} with @var{arguments} ignoring any shell function +named @var{command}. +Only shell builtin commands or commands found by searching the +@code{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 @samp{-p} option means to use a default value for @code{$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 @samp{-V} or @samp{-v} option is supplied, a description of @var{command} is printed. The @samp{-v} option causes a single word indicating the command or file name used to -invoke @var{command} to be printed; the @samp{-V} option produces -a more verbose description. +invoke @var{command} to be displayed; the @samp{-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 @@ -3244,30 +3503,40 @@ 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. +by subsequent assignment statements or unset. @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. +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. + +The return status is zero unless an invalid option is encountered, +an attempt is made to define a function using @code{-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 @samp{-f}. @item echo @btindex echo @example -echo [-neE] [arg @dots{}] +echo [-neE] [@var{arg} @dots{}] @end example -Output the @code{arg}s, separated by spaces, terminated with a -newline. The return status is always 0. If @samp{-n} is -specified, the trailing newline is suppressed. If the @samp{-e} -option is given, interpretation of the following backslash-escaped -characters is enabled. The @samp{-E} option disables the interpretation -of these escape characters, even on systems where they are interpreted -by default. +Output the @var{arg}s, separated by spaces, terminated with a +newline. +The return status is always 0. +If @samp{-n} is specified, the trailing newline is suppressed. +If the @samp{-e} option is given, interpretation of the following +backslash-escaped characters is enabled. +The @samp{-E} option disables the interpretation of these escape characters, +even on systems where they are interpreted by default. @code{echo} interprets the following escape sequences: @table @code @item \a @@ -3290,8 +3559,12 @@ horizontal tab vertical tab @item \\ backslash -@item \nnn -the character whose ASCII code is @code{nnn} (octal) +@item \@var{nnn} +the character whose @code{ASCII} code is the octal value @var{nnn} +(one to three digits) +@item \x@var{nnn} +the character whose @code{ASCII} code is the hexadecimal value @var{nnn} +(one to three digits) @end table @item enable @@ -3299,8 +3572,10 @@ the character whose ASCII code is @code{nnn} (octal) @example enable [-n] [-p] [-f @var{filename}] [-ads] [@var{name} @dots{}] @end example -Enable and disable builtin shell commands. This allows you to -use a disk command which has the same name as a shell builtin. +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 with specifying a full pathname, +even though the shell normally searches for builtins before disk commands. If @samp{-n} is used, the @var{name}s become disabled. Otherwise @var{name}s are enabled. For example, to use the @code{test} binary found via @code{$PATH} instead of the shell builtin version, type @@ -3315,31 +3590,48 @@ each builtin with an indication of whether or not it is enabled. The @samp{-f} option means to load the new builtin command @var{name} from shared object @var{filename}, on systems that support dynamic loading. The @samp{-d} option will delete a builtin loaded with @samp{-f}. + If there are no options, a list of the shell builtins is displayed. -The @samp{-s} option restricts @code{enable} to the @sc{POSIX.2} special +The @samp{-s} option restricts @code{enable} to the @sc{POSIX} special builtins. If @samp{-s} is used with @samp{-f}, the new builtin becomes a special builtin. +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 [@var{pattern}] @end example -Display helpful information about builtin commands. If -@var{pattern} is specified, @code{help} gives detailed help +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 builtins is printed. 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{name}[=@var{value}] @end example -For each argument, create a local variable called @var{name}, and -give it @var{value}. +For each argument, a local variable named @var{name} is created, +and assigned @var{value}. @code{local} can only be used within a function; it makes the variable @var{name} have a visible scope restricted to that function and its -children. +children. The return status is zero unless @code{local} is used outside +a function or an invalid @var{name} is supplied. @item logout @btindex logout @@ -3349,20 +3641,45 @@ logout [@var{n}] 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. + @item read @btindex read @example read [-a @var{aname}] [-p @var{prompt}] [-er] [@var{name} @dots{}] @end example One line is read from the standard input, and the first word -is assigned to the first -@var{name}, the second word to the second @var{name}, -and so on, with leftover words assigned to the last @var{name}. -Only the characters in the value of the @code{IFS} variable -are recognized as word delimiters. If no names -are supplied, the line read is assigned to the variable @code{REPLY}. -The return code is zero, unless end-of-file is encountered. Options, -if supplied, have the following meanings: +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 standard input than names, +the remaining names are assigned empty values. +The characters in the value of the @code{IFS} variable +are used to split the line into words. +If no names are supplied, the line read is assigned to the +variable @code{REPLY}. +The return code is zero, unless end-of-file is encountered. +Options, if supplied, have the following meanings: @table @code @item -r @@ -3370,13 +3687,15 @@ If this option is given, a backslash-newline pair is not ignored, and the backslash is considered to be part of the line. @item -p @var{prompt} -Display @code{prompt}, without a +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 -a @var{aname} -The words are assigned to -sequential indices of the array variable @var{aname}, starting at 0. +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 -e Readline (@pxref{Command Line Editing}) @@ -3389,14 +3708,15 @@ is used to obtain the line. shopt [-pqsu] [-o] [@var{optname} @dots{}] @end example Toggle the values of variables controlling optional shell behavior. -With no options, or with the @samp{-p} -option, a list of all settable options is displayed, with -an indication of whether or not each is set. Other options have -the following meanings: +With no options, or with the @samp{-p} option, a list of all settable +options is displayed, with an indication of whether or not each is set. +The @samp{-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} +Enable (set) each @var{optname}. @item -u Disable (unset) each @var{optname}. @@ -3414,8 +3734,7 @@ Restricts the values of @code{set} builtin (@pxref{The Set Builtin}). @end table -If either of -@samp{-s} or @samp{-u} +If either @samp{-s} or @samp{-u} is used with no @var{optname} arguments, the display is limited to those options which are set or unset, respectively. @@ -3424,7 +3743,7 @@ by default. The return status when listing options is zero if all @var{optnames} are enabled, non-zero otherwise. When setting or unsetting options, -the return status is zero unless an @var{optname} is not a legal shell +the return status is zero unless an @var{optname} is not a valid shell option. The list of @code{shopt} options is: @@ -3470,6 +3789,15 @@ 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 +(@pxref{Aliases}). +This option is enabled by default for interactive shells. + +@item extglob +If set, the extended pattern matching features described above +(@pxref{Pattern Matching}) are enabled. + @item histappend If set, the history list is appended to the file named by the value of the @code{HISTFILE} @@ -3488,10 +3816,14 @@ the Readline editing buffer, allowing further modification. @item hostcomplete If set, and Readline is being used, Bash will attempt to perform -hostname completion when a word beginning with @samp{@@} is being +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 @@ -3508,6 +3840,10 @@ 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 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. @@ -3525,18 +3861,31 @@ number of positional parameters. @item sourcepath If set, the @code{source} builtin uses the value of @code{PATH} to find the directory containing the file supplied as an argument. -This is enabled by default. +This option is enabled 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 [-all] [-type | -path] [@var{name} @dots{}] +type [-atp] [@var{name} @dots{}] @end example For each @var{name}, indicate how it would be interpreted if used as a command name. -If the @samp{-type} flag is used, @code{type} returns a single word +If the @samp{-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, @@ -3544,16 +3893,26 @@ disk file, or shell reserved word, respectively. If the @var{name} is not found, then nothing is printed, and @code{type} returns a failure status. -If the @samp{-path} flag is used, @code{type} either returns the name -of the disk file that would be executed, or nothing if @samp{-type} +If the @samp{-p} option is used, @code{type} either returns the name +of the disk file that would be executed, or nothing if @samp{-t} would not return @samp{file}. -If the @samp{-all} flag is used, returns all of the places that contain -an executable named @var{file}. This includes aliases and functions, -if and only if the @samp{-path} flag is not also used. +If the @samp{-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 @samp{-p} option +is not also used. -@code{type} accepts @samp{-a}, @samp{-t}, and @samp{-p} as equivalent to -@samp{-all}, @samp{-type}, and @samp{-path}, respectively. +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}]] +@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 @@ -3565,46 +3924,46 @@ 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. +Change and report the soft limit associated with a resource. @item -H -change and report the hard limit associated with a resource. +Change and report the hard limit associated with a resource. @item -a -all current limits are reported. +All current limits are reported. @item -c -the maximum size of core files created. +The maximum size of core files created. @item -d -the maximum size of a process's data segment. +The maximum size of a process's data segment. @item -f -the maximum size of files created by the shell. +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. +The maximum resident set size. @item -n -the maximum number of open file descriptors. +The maximum number of open file descriptors. @item -p -the pipe buffer size. +The pipe buffer size. @item -s -the maximum stack size. +The maximum stack size. @item -t -the maximum amount of cpu time in seconds. +The maximum amount of cpu time in seconds. @item -u -the maximum number of processes available to a single user. +The maximum number of processes available to a single user. @item -v -the maximum amount of virtual memory available to the process. +The maximum amount of virtual memory available to the process. @end table @@ -3618,20 +3977,31 @@ increments, except for @samp{-t}, which is in seconds, @samp{-p}, which is in units of 512-byte blocks, and @samp{-n} and @samp{-u}, which are unscaled values. +The return status is zero unless an invalid option is supplied, a +non-numeric argument other than @code{unlimited} is supplied as a +@var{limit}, or an error occurs while setting a new limit. + @end table @node The Set Builtin @section The Set Builtin -This builtin is so overloaded that it deserves its own section. +This builtin is so complicated that it deserves its own section. @table @code @item set @btindex set @example -set [-abefhkmnptuvxdBCHP] [-o @var{option}] [@var{argument} @dots{}] +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 which are modified or created for export. @@ -3641,13 +4011,18 @@ Cause the status of terminated background jobs to be reported immediately, rather than before printing the next primary prompt. @item -e -Exit immediately if a simple command exits with a non-zero status. +Exit immediately if a simple command (@pxref{Simple Commands}) exits +with a non-zero status, unless the command that fails is part of an +@code{until} or @code{while} loop, part of an @code{if} statement, +part of a @code{&&} or @code{||} list, or if the command's return +status is being inverted using @code{!}. @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 @@ -3658,89 +4033,94 @@ the command name. Job control is enabled (@pxref{Job Control}). @item -n -Read commands but do not execute them. +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 flag corresponding to @var{option-name}: +Set the option corresponding to @var{option-name}: @table @code @item allexport -same as @code{-a}. +Same as @code{-a}. @item braceexpand -same as @code{-B}. +Same as @code{-B}. @item emacs -use an @code{emacs}-style line editing interface (@pxref{Command Line Editing}). +Use an @code{emacs}-style line editing interface (@pxref{Command Line Editing}). @item errexit -same as @code{-e}. +Same as @code{-e}. @item hashall -same as @code{-h}. +Same as @code{-h}. @item histexpand -same as @code{-H}. +Same as @code{-H}. @item history Enable command history, as described in @ref{Bash History Facilities}. This option is on by default in interactive shells. @item ignoreeof -the shell will not exit upon reading EOF. +An interactive shell will not exit upon reading EOF. @item keyword -same as @code{-k}. +Same as @code{-k}. @item monitor -same as @code{-m}. +Same as @code{-m}. @item noclobber -same as @code{-C}. +Same as @code{-C}. @item noexec -same as @code{-n}. +Same as @code{-n}. @item noglob -same as @code{-f}. +Same as @code{-f}. @item notify -same as @code{-b}. +Same as @code{-b}. @item nounset -same as @code{-u}. +Same as @code{-u}. @item onecmd -same as @code{-t}. +Same as @code{-t}. @item physical -same as @code{-P}. +Same as @code{-P}. @item posix -change the behavior of Bash where the default operation differs -from the @sc{POSIX} 1003.2 standard to match the standard. This -is intended to make Bash behave as a strict superset of that +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}. +Same as @code{-p}. @item verbose -same as @code{-v}. +Same as @code{-v}. @item vi -use a @code{vi}-style line editing interface. +Use a @code{vi}-style line editing interface. @item xtrace -same as @code{-x}. +Same as @code{-x}. @end table @item -p Turn on privileged mode. -In this mode, the @code{$BASH_ENV} -file is not processed, and shell functions -are not inherited from the environment. This is enabled automatically +In this mode, the @code{$BASH_ENV} and @code{$ENV} files are not +processed, shell functions are not inherited from the environment, +and the @code{SHELLOPTS} variable, if it appears in the environment, +is ignored. +This is enabled automatically on startup if the effective user (group) id is not equal to the real user (group) id. Turning this option off causes the effective user and group ids to be set to the real user and group ids. @@ -3749,24 +4129,28 @@ and group ids to be set to the real user and group ids. Exit after reading and executing one command. @item -u -Treat unset variables as an error when substituting. +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 commands and their arguments as they are executed. +Print a trace of simple commands and their arguments after they are +expanded and before they are executed. @item -B The shell will perform brace expansion (@pxref{Brace Expansion}). This option is on by default. @item -C -Disallow output redirection to existing files. +Prevent output redirection using @samp{>}, @samp{>&}, and @samp{<>} +from overwriting existing files. @item -H Enable @samp{!} style history substitution (@pxref{History Interaction}). -This flag is on by default for interactive shells. +This option is on by default for interactive shells. @item -P If set, do not follow symbolic links when performing commands such as @@ -3775,7 +4159,8 @@ is used instead. By default, Bash follows the logical chain of directories when performing commands which change the current directory. -For example, if @file{/usr/sys} is a link to @file{/usr/local/sys} then: +For example, if @file{/usr/sys} is a symbolic link to @file{/usr/local/sys} +then: @example $ cd /usr/sys; echo $PWD /usr/sys @@ -3793,7 +4178,7 @@ $ cd ..; pwd @end example @item -- -If no arguments follow this flag, then the positional parameters are +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{-}. @@ -3804,29 +4189,34 @@ and @samp{-v} options are turned off. If there are no arguments, the positional parameters remain unchanged. @end table -Using @samp{+} rather than @samp{-} causes these flags to be -turned off. The flags can also be used upon invocation of the -shell. The current set of flags may be found in @code{$-}. +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}. If -no arguments are given, all shell variables are printed. +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 Bash Conditional Expressions @section Bash Conditional Expressions @cindex expressions, conditional -Conditional expressions are used by the @code{test} and @code{[} builtins. +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. Each -operator and operand must be a separate argument. If @var{file} -is of the form @file{/dev/fd/@var{N}}, then file descriptor @var{N} is -checked. Expressions are composed of the following primaries: +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 any @var{file} argument to one of the primaries is of the form +@file{/dev/fd/@var{N}}, then file descriptor @var{N} 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. @@ -3843,16 +4233,13 @@ True if @var{file} exists. True if @var{file} exists and is a regular file. @item -g @var{file} -True if @var{file} exists and is set-group-id. +True if @var{file} exists and its set-group-id bit is set. @item -k @var{file} -True if @var{file} has its "sticky" bit set. - -@item -L @var{file} -True if @var{file} exists and is a symbolic link. +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. +True if @var{file} exists and is a named pipe (FIFO). @item -r @var{file} True if @var{file} exists and is readable. @@ -3860,11 +4247,8 @@ True if @var{file} exists and is readable. @item -s @var{file} True if @var{file} exists and has a size greater than zero. -@item -S @var{file} -True if @var{file} exists and is a socket. - @item -t @var{fd} -True if @var{fd} is opened on a terminal. +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. @@ -3881,6 +4265,15 @@ 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}. @@ -3904,27 +4297,20 @@ True if the length of @var{string} is zero. @itemx @var{string} True if the length of @var{string} is non-zero. -@item @var{string1} = @var{string2} -True if the strings are equal. @samp{==} may be used in place of -@samp{=}. +@item @var{string1} == @var{string2} +True if the strings are equal. +@samp{=} may be used in place of @samp{==}. @item @var{string1} != @var{string2} True if the strings are not equal. @item @var{string1} < @var{string2} -True if @var{string1} sorts before @var{string2} lexicographically. +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. - -@item ! @var{expr} -True if @var{expr} is false. - -@item @var{expr1} -a @var{expr2} -True if both @var{expr1} and @var{expr2} are true. - -@item @var{expr1} -o @var{expr2} -True if either @var{expr1} and @var{expr2} is true. +True if @var{string1} sorts after @var{string2} lexicographically +in the current locale. @item @var{arg1} OP @var{arg2} @code{OP} is one of @@ -3937,43 +4323,6 @@ may be positive or negative integers. @end table -The Bash @code{test} and @code{[} builtins evaluate conditional -expressions using a set of rules based on the number of arguments. -These are the rules: - -@table @asis -@item 0 arguments -The expression is false. -@item 1 argument -The expression is true if and only if the argument is not null. -@item 2 arguments -If the first argument is @samp{!}, the expression is true if and -only if the second argument is null. If the first argument is -one of the listed unary operators, the expression is true if the -unary test is true. If the first argument is not a legal unary -operator, the expression is false. -@item 3 arguments -If the first argument is @samp{!}, the value is the negation of -the two-argument test using the second and third arguments. -If the second argument is one of the binary operators, the result -of the expression is the result of the binary test using the first -and third arguments as operands. -If the first argument is exactly @samp{(} and the third argument is -exactly @samp{)}, the result is the one-argument test of the second -argument. -Otherwise, the expression is false. -The @samp{-a} and @samp{-o} operators are considered binary operators -in this case. -@item 4 arguments -If the first argument is @samp{!}, the result is the negation of -the three-argument expression composed of the remaining arguments. -Otherwise, the expression is parsed and evaluated according to -precedence. @samp{-a} has a higher precedence than @samp{-o}. -@item 5 or more arguments -The expression is parsed and evaluated according to precedence, -with @samp{-a} having a higher precedence than @samp{-o}. -@end table - @node Bash Variables @section Bash Variables @@ -3982,56 +4331,101 @@ do not normally treat them specially. @vtable @code +@item BASH +The full pathname used to execute the current instance of Bash. + @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 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. +@item BASH_VERSION +The version number of the current instance of Bash. + +@item BASH_VERSINFO +A readonly array variable whose members hold version information for +this instance of Bash. +The values assigned to the array members are as follows: @table @code -@item %% -A literal @samp{%}. +@item BASH_VERSINFO[0] +The major version number (the @var{release}). -@item %[@var{p}][l]R -The elapsed time in seconds. +@item BASH_VERSINFO[1] +The minor version number (the @var{version}). -@item %[@var{p}][l]U -The number of CPU seconds spent in user mode. +@item BASH_VERSINFO[2] +The patch level. -@item %[@var{p}][l]S -The number of CPU seconds spent in system mode. +@item BASH_VERSINFO[3] +The build version. + +@item BASH_VERSINFO[4] +The release status (e.g., @var{beta1}). + +@item BASH_VERSINFO[5] +The value of @code{MACHTYPE}. -@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. +@item DIRSTACK +An array variable (@pxref{Arrays}) +containing the current contents of the directory stack. +Directories appear in the stack in the order they are displayed by the +@code{dirs} builtin. +Assigning to members of this array variable may be used to modify +directories already in the stack, but the @code{pushd} and @code{popd} +builtins must be used to add and remove directories. +Assignment to this variable will not change the current directory. +If @code{DIRSTACK} is unset, it loses its special properties, even if +it is subsequently reset. -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. +@item EUID +The numeric effective user id of the current user. This variable +is readonly. -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 FCEDIT +The editor used as a default by the @samp{-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 +@code{FIGNORE} +is excluded from the list of matched file names. A sample +value is @samp{.o:~} + +@item GLOBIGNORE +A colon-separated list of patterns defining the set of filenames to +be ignored by filename expansion. +If a filename matched by a filename expansion pattern also matches one +of the patterns in @code{GLOBIGNORE}, it is removed from the list +of matches. + +@item GROUPS +An array variable containing the list of groups of which the current +user is a member. This variable is readonly. + +@item histchars +Up to three characters which control history expansion, quick +substitution, and tokenization (@pxref{History Interaction}). +The first character is the +@dfn{history-expansion-char}, that is, the character which signifies the +start of a history expansion, normally @samp{!}. The second character is the +character which signifies `quick substitution' when seen as the first +character on a line, normally @samp{^}. The optional third character is the +character which 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 @code{HISTCMD} is unset, it loses its special properties, +even if it is subsequently reset. @item HISTCONTROL Set to a value of @samp{ignorespace}, it means don't enter lines which @@ -4040,6 +4434,9 @@ of @samp{ignoredups}, it means don't enter lines which match the last entered line. A value of @samp{ignoreboth} combines the two options. Unset, or set to any other value than those above, means to save all lines on the history list. +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 +@code{HISTCONTROL}. @item HISTIGNORE A colon-separated list of patterns used to decide which command @@ -4051,6 +4448,9 @@ 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 +@code{HISTIGNORE}. @code{HISTIGNORE} subsumes the function of @code{HISTCONTROL}. A pattern of @samp{&} is identical to @code{ignoredups}, and a @@ -4063,8 +4463,8 @@ The name of the file to which the command history is saved. The default is @file{~/.bash_history}. @item HISTSIZE -If set, this is the maximum number of commands to remember in the -history. +The maximum number of commands to remember on the history list. +The default value is 500. @item HISTFILESIZE The maximum number of lines contained in the history file. When this @@ -4073,25 +4473,6 @@ necessary, to contain no more than that number of lines. The default value is 500. The history file is also truncated to this size after writing it when an interactive shell exits. -@item histchars -Up to three characters which control history expansion, quick -substitution, and tokenization (@pxref{History Interaction}). -The first character is the -@dfn{history-expansion-char}, that is, the character which signifies the -start of a history expansion, normally @samp{!}. The second character is the -character which signifies `quick substitution' when seen as the first -character on a line, normally @samp{^}. The optional third character is the -character which signifies the remainder of the line is a comment, when -found as the first character of a word, usually @samp{#}. The history -comment character causes history substitution to be skipped for the -remaining words on the line. It does not necessarily cause the shell -parser to treat the rest of the line as a comment. - -@item HISTCMD -The history number, or index in the history list, of the current -command. If @code{HISTCMD} is unset, it loses its special properties, -even if it is subsequently reset. - @item HOSTFILE Contains the name of a file in the same format as @file{/etc/hosts} that should be read when the shell needs to complete a hostname. You can @@ -4099,76 +4480,70 @@ change the file interactively; the next time you attempt to complete a hostname, Bash will add the contents of the new file to the already existing database. -@item MAILCHECK -How often (in seconds) that the shell should check for mail -in the files specified in @code{MAILPATH}. +@item HOSTNAME +The name of the current host. -@item PROMPT_COMMAND -If present, this contains a string which is a command to execute -before the printing of each primary prompt (@code{$PS1}). +@item HOSTTYPE +A string describing the machine Bash is running on. -@item UID -The numeric real user id of the current user. +@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 EUID -The numeric effective user id of the current user. +@item INPUTRC +The name of the Readline startup file, overriding the default +of @file{~/.inputrc}. -@item GROUPS -An array variable containing the list of groups of which the current -user is a member. +@item LANG +Used to determine the locale category for any category not specifically +selected with a variable starting with @code{LC_}. -@item PPID -The process id of the shell's parent process. +@item LC_ALL +This variable overrides the value of @code{LANG} and any other +@code{LC_} variable specifying a locale category. -@item HOSTNAME -The name of the current host. +@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 HOSTTYPE -A string describing the machine Bash is running on. +@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 OSTYPE -A string describing the operating system Bash is running on. +@item LC_MESSAGES +This variable determines the locale used to translate double-quoted +strings preceded by a @samp{$} (@pxref{Locale Translation}). + +@item LINENO +The line number in the script or shell function currently executing. @item MACHTYPE A string that fully describes the system type on which Bash is executing, in the standard GNU @var{cpu-company-system} format. -@item SHELLOPTS -A colon-separated list of enabled shell options. Each word in -the list is a valid argument for the @samp{-o} option to the -@code{set} builtin command (@pxref{The Set Builtin}). -The options appearing in @code{SHELLOPTS} are those reported -as @samp{on} by @samp{set -o}. -If this variable is in the environment when Bash -starts up, each shell option in the list will be enabled before -reading any startup files. This variable is readonly. +@item MAILCHECK +How often (in seconds) that the shell should check for mail in the +files specified in the @code{MAILPATH} or @code{MAIL} variables. -@item FIGNORE -A colon-separated list of suffixes to ignore when performing -filename completion. -A file name whose suffix matches one of the entries in -@code{FIGNORE} -is excluded from the list of matched file names. A sample -value is @samp{.o:~} +@item OLDPWD +The previous working directory as set by the @code{cd} builtin. -@item GLOBIGNORE -A colon-separated list of patterns defining the set of filenames to -be ignored by filename expansion. -If a filename matched by a filename expansion pattern also matches one -of the patterns in @code{GLOBIGNORE}, it is removed from the list -of matches. +@item OPTERR +If set to the value 1, Bash displays error messages +generated by the @code{getopts} builtin command. -@item DIRSTACK -An array variable (@pxref{Arrays}) -containing the current contents of the directory stack. -Directories appear in the stack in the order they are displayed by the -@code{dirs} builtin. -Assigning to members of this array variable may be used to modify -directories already in the stack, but the @code{pushd} and @code{popd} -builtins must be used to add and remove directories. -Assignment to this variable will not change the current directory. -If @code{DIRSTACK} is unset, it loses its special properties, even if -it is subsequently reset. +@item OSTYPE +A string describing the operating system Bash is running on. @item PIPESTATUS An array variable (@pxref{Arrays}) @@ -4176,94 +4551,120 @@ containing a list of exit status values from the processes in the most-recently-executed foreground pipeline (which may contain only a single command). -@item INPUTRC -The name of the Readline startup file, overriding the default -of @file{~/.inputrc}. - -@item BASH -The full filename used to execute the current instance of Bash. - -@item BASH_VERSION -The version number of the current instance of Bash. - -@item BASH_VERSINFO -An array variable whose members hold version information for this -instance of Bash. -The values assigned to the array members are as follows: +@item PPID +The process id of the shell's parent process. This variable +is readonly. -@table @code +@item PROMPT_COMMAND +If present, this contains a string which is a command to execute +before the printing of each primary prompt (@code{$PS1}). -@item BASH_VERSINFO[0] -The major version number (the @var{release}). +@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 BASH_VERSINFO[1] -The minor version number (the @var{version}). +@item PS4 +This is the prompt printed before the command line is echoed +when the @samp{-x} option is set (@pxref{The Set Builtin}). +The first character of @code{PS4} is replicated multiple times, as +necessary, to indicate multiple levels of indirection. +The default is @samp{+ }. -@item BASH_VERSINFO[2] -The patch level. +@item PWD +The current working directory as set by the @code{cd} builtin. -@item BASH_VERSINFO[3] -The build version. +@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 BASH_VERSINFO[4] -The release status (e.g., @var{beta1}). +@item REPLY +The default variable for the @code{read} builtin. -@item BASH_VERSINFO[5] -The value of @code{MACHTYPE}. +@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. -@end table +@item SHELLOPTS +A colon-separated list of enabled shell options. Each word in +the list is a valid argument for the @samp{-o} option to the +@code{set} builtin command (@pxref{The Set Builtin}). +The options appearing in @code{SHELLOPTS} are those reported +as @samp{on} by @samp{set -o}. +If this variable is in the environment when Bash +starts up, each shell option in the list will be enabled before +reading any startup files. This variable is readonly. @item 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 OPTERR -If set to the value 1, Bash displays error messages -generated by the @code{getopts} builtin command. +@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. -@item LANG -Used to determine the locale category for any category not specifically -selected with a variable starting with @code{LC_}. +@table @code -@item LC_ALL -This variable overrides the value of @code{LANG} and any other -@code{LC_} variable specifying a locale category. +@item %% +A literal @samp{%}. -@item LC_COLLATE -This variable determines the collation order used when sorting the -results of filename expansion (@pxref{Filename Expansion}). +@item %[@var{p}][l]R +The elapsed time in seconds. -@item LC_MESSAGES -This variable determines the locale used to translate double-quoted -strings preceded by a @samp{$} (@pxref{Locale Translation}). +@item %[@var{p}][l]U +The number of CPU seconds spent in user mode. -@item IGNOREEOF -Controls the action of the shell on receipt of an @code{EOF} character -as the sole input. If set, then the value of it is the number -of consecutive @code{EOF} characters that can be read as the -first character on an input line -before the shell will exit. If the variable exists but does not -have a numeric value (or has no value) then the default is 10. -If the variable does not exist, then @code{EOF} signifies the end of -input to the shell. This is only in effect for interactive shells. +@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, the value is interpreted as +the number of seconds to wait for input after issuing the primary +prompt. +Bash terminates after that number of seconds if input does +not arrive. + +@item UID +The numeric real user id of the current user. This variable is readonly. @end vtable @node Shell Arithmetic @section Shell Arithmetic @cindex arithmetic, shell - -@menu -* Arithmetic Evaluation:: How shell arithmetic works. -* Arithmetic Expansion:: How to use arithmetic in shell expansions. -* Arithmetic Builtins:: Builtin commands that use shell arithmetic. -@end menu - -Bash includes several mechanisms to evaluate arithmetic expressions -and display the result or use it as part of a command. - -@node Arithmetic Evaluation -@subsection Arithmetic Evaluation +@cindex shell arithmetic @cindex expressions, arithmetic @cindex evaluation, arithmetic @cindex arithmetic evaluation @@ -4284,6 +4685,9 @@ unary minus and plus @item ! ~ logical and bitwise negation +@item ** +exponentiation + @item * / % multiplication, division, remainder @@ -4343,43 +4747,95 @@ Operators are evaluated in order of precedence. Sub-expressions in parentheses are evaluated first and may override the precedence rules above. -@node Arithmetic Expansion -@subsection Arithmetic Expansion -@cindex expansion, arithmetic -@cindex arithmetic expansion +@node Aliases +@section Aliases +@cindex alias expansion -Arithmetic expansion allows the evaluation of an arithmetic expression -and the substitution of the result. The format for arithmetic expansion is: +@menu +* Alias Builtins:: Builtins commands to maniuplate aliases. +@end menu -@example -$(( @var{expression} )) -@end example +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 @var{aliases} +that may be set and unset with the @code{alias} and +@code{unalias} builtin commands. -The expression is treated as if it were within double quotes, but -a double quote inside the braces or parentheses is not treated -specially. All tokens in the expression undergo parameter -expansion, command substitution, and quote removal. Arithmetic -substitutions may be nested. +The 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. -The evaluation is performed according to the rules listed above. -If the expression is invalid, Bash -prints a message indicating failure and no substitution occurs. +For almost every purpose, aliases are superseded by +shell functions. -@node Arithmetic Builtins -@subsection Arithmetic Builtins +@node Alias Builtins +@subsection Alias Builtins @table @code -@item let -@btindex let +@item alias +@btindex alias @example -let @var{expression} [@var{expression}] +alias [@code{-p}] [@var{name}[=@var{value}] @dots{}] @end example -The @code{let} builtin allows arithmetic to be performed on shell -variables. Each @var{expression} is evaluated according to the -rules given previously (@pxref{Arithmetic Evaluation}). If the -last @var{expression} evaluates to 0, @code{let} returns 1; -otherwise 0 is returned. + +Without arguments or with the @samp{-p} option, @code{alias} prints +the list of aliases on the standard output in a form that allows +them to be reused as input. +If arguments are supplied, an alias is defined for each @var{name} +whose @var{value} is given. If no @var{value} is given, the name +and value of the alias is printed. + +@item unalias +@btindex unalias +@example +unalias [-a] [@var{name} @dots{} ] +@end example + +Remove each @var{name} from the list of aliases. If @samp{-a} is +supplied, all aliases are removed. @end table @node Arrays @@ -4451,7 +4907,7 @@ Referencing an array variable without a subscript is equivalent to referencing element zero. The @code{unset} builtin is used to destroy arrays. -@code{unset} @var{name[subscript]} +@code{unset} @code{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 @@ -4467,64 +4923,167 @@ 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 + +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 @code{DIRSTACK} shell variable. + +@table @code + +@item dirs +@btindex dirs +@example +dirs [+@var{N} | -@var{N}] [-clvp] +@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 @code{PROMPT_COMMAND} is examined just before Bash prints each primary prompt. If it is set and non-null, then the -value is executed just as if you had typed it on the command line. +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. +A bell character. @item \d -the date, in "Weekday Month Date" format (e.g., "Tue May 26"). +The date, in "Weekday Month Date" format (e.g., "Tue May 26"). @item \e -an escape character. +An escape character. @item \h -the hostname, up to the first `.'. +The hostname, up to the first `.'. @item \H -the hostname. +The hostname. @item \n -newline. +A newline. +@item \r +A carriage return. @item \s -the name of the shell, the basename of @code{$0} (the portion +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. +The time, in 24-hour HH:MM:SS format. @item \T -the time, in 12-hour HH:MM:SS format. +The time, in 12-hour HH:MM:SS format. @item \@@ -the time, in 12-hour am/pm format. +The time, in 12-hour am/pm format. +@item \u +The username of the current user. @item \v -the version of Bash (e.g., 2.00) +The version of Bash (e.g., 2.00) @item \V -the release of Bash, version + patchlevel (e.g., 2.00.0) +The release of Bash, version + patchlevel (e.g., 2.00.0) @item \w -the current working directory. +The current working directory. @item \W -the basename of @code{$PWD}. -@item \u -your username. +The basename of @code{$PWD}. @item \! -the history number of this command. +The history number of this command. @item \# -the command number of this command. +The command number of this command. @item \$ -if the effective uid is 0, @code{#}, otherwise @code{$}. -@item \nnn -the character corresponding to the octal number @code{nnn}. +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. +A backslash. @item \[ -begin a sequence of non-printing characters. This could be used to +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 a sequence of non-printing characters. @end table @node The Restricted Shell @@ -4552,6 +5111,8 @@ builtin command. @item Importing function definitions from the shell environment at startup. @item +Parsing the value of @code{SHELLOPTS} from the shell environment at startup. +@item Redirecting output using the @samp{>}, @samp{>|}, @samp{<>}, @samp{>&}, @samp{&>}, and @samp{>>} redirection operators. @item @@ -4562,7 +5123,7 @@ Adding or deleting builtin commands with the @item Specifying the @samp{-p} option to the @code{command} builtin. @item -Turning off restricted mode with @samp{set +r}. +Turning off restricted mode with @samp{set +r} or @samp{set +o restricted}. @end itemize @node Bash POSIX Mode @@ -4595,12 +5156,12 @@ Reserved words may not be aliased. @item The @sc{POSIX.2} @code{PS1} and @code{PS2} expansions of @samp{!} to the history number and @samp{!!} to @samp{!} are enabled, -and parameter expansion is performed on -the value regardless of the setting of the @code{promptvars} option. +and parameter expansion is performed on the values of @code{PS1} and +@code{PS2} regardless of the setting of the @code{promptvars} option. @item -Interactive comments are enabled by default. (Note that Bash has -them on by default anyway.) +Interactive comments are enabled by default. (Bash has them on by +default anyway.) @item The @sc{POSIX.2} startup files are executed (@code{$ENV}) rather than @@ -4623,13 +5184,17 @@ 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 Function names must be valid shell @code{name}s. That is, they may not contain characters other than letters, digits, and underscores, and -may not start with a digit. Declaring a function with an illegal name +may not start with a digit. Declaring a function with an invalid name causes a fatal syntax error in non-interactive shells. @item @@ -4650,22 +5215,30 @@ value it assigns to the @code{PWD} variable does not contain any symbolic links, as if @samp{cd -P} had been executed. @item +If @code{$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 @code{$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 read-only variable. +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 read-only variable. +@code{select} statement is a readonly variable. @item Process substitution is not available. @item -Assignment statements preceding @sc{POSIX.2} @code{special} builtins +Assignment statements preceding @sc{POSIX.2} special builtins persist in the shell environment after the builtin completes. @item @@ -4686,7 +5259,7 @@ builtins, not just special ones. @node Job Control @chapter Job Control -This chapter disusses what job control is, how it works, and how +This chapter discusses what job control is, how it works, and how Bash allows you to access its facilities. @menu @@ -4714,7 +5287,7 @@ by the system's terminal driver and Bash. The shell associates a @var{job} with each pipeline. It keeps a table of currently executing jobs, which may be listed with the @code{jobs} command. When Bash starts a job -asynchronously (in the background), it prints a line that looks +asynchronously, it prints a line that looks like: @example [1] 25647 @@ -4741,13 +5314,13 @@ read from (write to) the terminal are sent a @code{SIGTTIN} caught, suspends the process. If the operating system on which Bash is running supports -job control, Bash allows you to use it. Typing the +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 -you to Bash. Typing the @var{delayed suspend} character +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. You may then manipulate the state of +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} @@ -4764,7 +5337,8 @@ other hand, refers to any job containing the string @samp{ce} in its command line. If the prefix or substring matches more than one job, Bash reports an error. The symbols @samp{%%} and @samp{%+} refer to the shell's notion of the current job, which -is the last job stopped while it was in the foreground. The +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 @@ -4779,15 +5353,14 @@ The shell learns immediately whenever a job changes state. Normally, Bash waits until it is about to print a prompt before reporting changes in a job's status so as to not interrupt any other output. If the -the @samp{-b} option to the @code{set} builtin is set, +the @samp{-b} option to the @code{set} builtin is enabled, Bash reports such changes immediately (@pxref{The Set Builtin}). -If you attempt to exit Bash while jobs are stopped, the -shell prints a message warning you that you have stopped jobs. -You may then use the -@code{jobs} command to inspect their status. If you do this, or -try to exit again immediately, you are not warned again, and the -stopped jobs are terminated. +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 @@ -4799,23 +5372,31 @@ stopped jobs are terminated. @example bg [@var{jobspec}] @end example -Place @var{jobspec} into the background, as if it had been started -with @samp{&}. If @var{jobspec} is not supplied, the current job -is used. +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 -Bring @var{jobspec} into the foreground and make it the current job. +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 [-lpnrs] [@var{jobspec}] -jobs -x @var{command} [@var{jobspec}] +jobs -x @var{command} [@var{arguments}] @end example The first form lists the active jobs. The options have the @@ -4823,15 +5404,14 @@ following meanings: @table @code @item -l -List process @sc{ID}s in addition to the normal information +List process @sc{ID}s in addition to the normal information. @item -n Display information only about jobs that have changed status since -you were last notified of their status. +the user was last notified of their status. @item -p -List only the process @sc{ID} of the job's process group -leader. +List only the process @sc{ID} of the job's process group leader. @item -r Restrict output to running jobs. @@ -4853,16 +5433,22 @@ passing it @var{argument}s, returning its exit status. @item kill @btindex kill @example -kill [-s @var{sigspec}] [-n @var{signum}] [-@var{sigspec}] @var{jobspec} -kill -l [@var{sigspec}] +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 @var{jobspec}. +named by job specification @var{jobspec} or process 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 @samp{-l} option lists the signal names, or the signal name -corresponding to @var{sigspec}. +The @samp{-l} option lists the signal names. +If any arguments are supplied when @samp{-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 @@ -4870,21 +5456,29 @@ corresponding to @var{sigspec}. wait [@var{jobspec}|@var{pid}] @end example Wait until the child process specified by process @sc{ID} @var{pid} or job -specification @var{jobspec} exits and report its exit status. If a job -spec is given, all processes in the job are waited for. If no arguments -are given, all currently active child processes are waited for. +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 [-h] [@var{jobspec} @dots{}] +disown [-ar] [-h] [@var{jobspec} @dots{}] @end example Without options, each @var{jobspec} is removed from the table of active jobs. If the @samp{-h} option is given, the job is not removed from the table, but is marked so that @code{SIGHUP} is not sent to the job if the shell receives a @code{SIGHUP}. -If @var{jobspec} is not present, the current job is used. +If @var{jobspec} is not present, and neither the @samp{-a} nor @samp{-r} +option is supplied, the current job is used. +If no @var{jobspec} is supplied, the @samp{-a} option means to remove or +mark all jobs; the @samp{-r} option without a @var{jobspec} +argument restricts operation to running jobs. @item suspend @btindex suspend @@ -4909,7 +5503,7 @@ supplied process @sc{ID}s. @item auto_resume This variable controls how the shell interacts with the user and job control. If this variable exists then single word simple -commands without redirects are treated as candidates for resumption +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. @@ -4941,7 +5535,7 @@ analogous to the @samp{%} job @sc{ID}. This chapter provides basic instructions for installing Bash on the various supported platforms. The distribution supports nearly every version of Unix (and, someday, @sc{GNU}). Other independent ports exist for -@sc{OS/2}, Windows 95, and Windows @sc{NT}. +@sc{MS-DOS}, @sc{OS/2}, Windows @sc{95}, and Windows @sc{NT}. @menu * Basic Installation:: Installation instructions. @@ -4991,10 +5585,10 @@ If at some point @file{config.cache} contains results you don't want to keep, you may remove or edit it. -If you need to do unusual things to compile the package, please +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 -@code{bash-maintainers@@prep.ai.mit.edu} so they can be +@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} @@ -5112,7 +5706,7 @@ giving @code{configure} the option @samp{--prefix=PATH}. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give @code{configure} the option -@samp{--exec-prefix=PATH}, the package will use @samp{PATH} as the +@samp{--exec-prefix=PATH}, @samp{make install} will use @samp{PATH} as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. @@ -5120,8 +5714,8 @@ other data files will still use the regular prefix. @section Specifying the System Type There may be some features @code{configure} can not figure out -automatically, but needs to determine by the type of host the -package will run on. Usually @code{configure} can figure that +automatically, but needs 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 @samp{--host=TYPE} option. @samp{TYPE} can either be a short name for the system type, such as @samp{sun4}, @@ -5182,11 +5776,10 @@ options. @section Optional Features The Bash @code{configure} has a number of @samp{--enable-@var{FEATURE}} -options, where @var{FEATURE} indicates an optional part of the -package. There are also several @samp{--with-@var{PACKAGE}} options, -where @var{PACKAGE} is something like @samp{gnu-malloc} or -@samp{purify} (for the Purify memory allocation checker). To -turn off the default use of a package, use +options, where @var{FEATURE} indicates an optional part of Bash. +There are also several @samp{--with-@var{PACKAGE}} options, +where @var{PACKAGE} is something like @samp{gnu-malloc} or @samp{purify}. +To turn off the default use of a package, use @samp{--without-@var{PACKAGE}}. To configure Bash without a feature that is enabled by default, use @samp{--disable-@var{FEATURE}}. @@ -5204,16 +5797,21 @@ database. @item --with-glibc-malloc Use the @sc{GNU} libc version of @code{malloc} in -@file{lib/malloc/gmalloc.c}. This is somewhat slower than the -default @code{malloc}, but wastes considerably less space. +@file{lib/malloc/gmalloc.c}. This is not the version of @code{malloc} +that appears in glibc version 2, but a modified version of the +@code{malloc} from glibc version 1. This is somewhat slower than the +default @code{malloc}, but wastes less space on a per-allocation +basis, and will return memory to the operating system under +some circumstances. @item --with-gnu-malloc Use the @sc{GNU} version of @code{malloc} in @file{lib/malloc/malloc.c}. This is not the same @code{malloc} that appears in @sc{GNU} libc, but an older version derived from the 4.2 @sc{BSD} @code{malloc}. This @code{malloc} is -very fast, but wastes a lot of space. This option is enabled by -default. The @file{NOTES} file contains a list of systems for +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. @@ -5226,7 +5824,19 @@ This produces a shell with minimal features, close to the historical Bourne shell. @end table -@noindent +There are several @samp{--enable-} options that alter how Bash is +compiled and linked, rather than changing run-time features. + +@table @code +@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}}. @@ -5239,26 +5849,34 @@ necessary support. @table @code @item --enable-alias Allow alias expansion and include the @code{alias} and @code{unalias} -builtins. +builtins (@pxref{Aliases}). @item --enable-array-variables -Include support for one-dimensional array shell variables. +Include support for one-dimensional array shell variables +(@pxref{Arrays}). @item --enable-bang-history -Include support for @code{csh}-like history substitution. +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}. 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. +@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} @@ -5267,7 +5885,12 @@ See @ref{Bash Builtins}, for details of the @code{builtin} and @code{enable} builtin commands. @item --enable-dparen-arithmetic -Include support for the @code{ksh} @code{((@dots{}))} command. +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 @@ -5278,20 +5901,22 @@ Include command history and the @code{fc} and @code{history} builtin commands. @item --enable-job-control -This enables job control features, if the @sc{OS} supports them. +This enables the job control features (@pxref{Job Control}), +if the operating system supports them. @item --enable-process-substitution This enables process substitution (@pxref{Process Substitution}) if -the @sc{OS} provides the necessary support. +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 @code{$PS1}, @code{$PS2}, @code{$PS3}, and @code{$PS4} prompt -strings. +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. +version of the Readline library (@pxref{Command Line Editing}). @item --enable-restricted Include support for a @dfn{restricted shell}. If this is enabled, Bash, @@ -5299,8 +5924,8 @@ 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{ksh} @code{select} builtin, which allows the -generation of simple menus. +Include the @code{select} builtin, which allows the generation of simple +menus (@pxref{Conditional Constructs}). @item --enable-usg-echo-default Make the @code{echo} builtin expand backslash-escaped characters by default, @@ -5329,7 +5954,7 @@ 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 @code{bug-bash@@prep.ai.MIT.Edu} or posted to the Usenet +to @email{bug-bash@@gnu.org} or posted to the Usenet newsgroup @code{gnu.bash.bug}. All bug reports should include: @@ -5352,7 +5977,7 @@ to reproduce it. the template it provides for filing a bug report. Please send all reports concerning this manual to -@code{chet@@ins.CWRU.Edu}. +@email{chet@@po.CWRU.Edu}. @node Builtin Index @appendix Index of Shell Builtin Commands diff --git a/doc/htmlpost.sh b/doc/htmlpost.sh new file mode 100755 index 00000000..aa015425 --- /dev/null +++ b/doc/htmlpost.sh @@ -0,0 +1,19 @@ +#! /bin/sh +# +# Some of these should really be done by man2html +# +# The ~/xxx links don't really work -- netscape doesn't expand the home +# directory of the user running navigator +# + +sed -e 's|<B>gnu.bash.bug</B>|<A HREF="news:gnu.bash.bug">gnu.bash.bug</A>|' \ + -e 's|<I>/bin/bash</I>|<A HREF="file:/bin/bash"><I>/bin/bash</I></A>|' \ + -e 's|<I>/etc/profile</I>|<A HREF="file:/etc/profile"><I>/etc/profile</I></A>|' \ + -e 's|<I>~/.bash_profile</I>|<A HREF="file:~/.bash_profile"><I>~/.bash_profile</I></A>|' \ + -e 's|<I>~/.bash_login</I>|<A HREF="file:~/.bash_login"><I>~/.bash_login</I></A>|' \ + -e 's|<I>~/.profile</I>|<A HREF="file:~/.profile"><I>~/.profile</I></A>|' \ + -e 's|<I>~/.bashrc</I>|<A HREF="file:~/.bashrc"><I>~/.bashrc</I></A>|' \ + -e 's|<I>~/.bash_logout</I>|<A HREF="file:~/.bash_logout"><I>~/.bash_logout</I></A>|' \ + -e 's|<I>~/.bash_history</I>|<A HREF="file:~/.bash_history"><I>~/.bash_history</I></A>|' \ + -e 's|<I>~/.inputrc</I>|<A HREF="file:~/.inputrc"><I>~/.inputrc</I></A>|' \ + -e 's|<I>/etc/inputrc</I>|<A HREF="file:/etc/inputrc"><I>/etc/inputrc</I></A>|' diff --git a/doc/readline.3 b/doc/readline.3 index 3d161689..bb9f7590 100644 --- a/doc/readline.3 +++ b/doc/readline.3 @@ -6,9 +6,9 @@ .\" Case Western Reserve University .\" chet@ins.CWRU.Edu .\" -.\" Last Change: Wed Feb 5 14:13:22 EST 1997 +.\" Last Change: Thu Feb 19 10:26:47 EST 1998 .\" -.TH READLINE 3 "1997 Feb 5" GNU +.TH READLINE 3 "1998 Feb 19" GNU .\" .\" File Name macro. This used to be `.PN', for Path Name, .\" but Sun doesn't seem to like that very much. @@ -159,7 +159,7 @@ command or the text of a macro and a key sequence to which it should be bound. The name may be specified in one of two ways: as a symbolic key name, possibly with \fIMeta\-\fP or \fIControl\-\fP prefixes, or as a key sequence. -When using the form \fBkeyname\fP:\fIfunction-name\fP or \fImacro\fP, +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 @@ -185,7 +185,7 @@ expressed on the right hand side (that is, to insert the text .I >&output into the line). .PP -In the second form, \fB"keyseq"\fP:\fIfunction\-name\fP or \fImacro\fP, +In the second form, \fB"keyseq"\fP:\^\fIfunction\-name\fP or \fImacro\fP, .B keyseq differs from .B keyname @@ -213,8 +213,9 @@ and .I "ESC [ 1 1 ~" is bound to insert the text .BR "Function Key 1" . -The full set of escape sequences is +The full set of GNU Emacs style escape sequences is .RS +.PD 0 .TP .B \eC\- control prefix @@ -234,11 +235,53 @@ literal " .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 character whose ASCII code is the octal value \fInnn\fP +(one to three digits) +.TP +.B \ex\fInnn\fP +the character whose ASCII code is the hexadecimal value \fInnn\fP +(one to three 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. Backslash -will quote any character in the macro text, including " and '. +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 @@ -288,6 +331,10 @@ This command is bound to 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 @@ -346,7 +393,7 @@ the value of also affects the default keymap. .TP .B mark\-directories (On) -If set to \fBOn\fP, completed directory names have a slash +If set to \fBOn\fP, complete<d directory names have a slash appended. .TP .B mark\-modified\-lines (Off) @@ -363,6 +410,10 @@ 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 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 @@ -380,7 +431,7 @@ completions. Readline implements a facility similar in spirit to the conditional compilation features of the C preprocessor which allows key bindings and variable settings to be performed as the result -of tests. There are three parser directives used. +of tests. There are four parser directives used. .IP \fB$if\fP The .B $if @@ -417,6 +468,7 @@ 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 @@ -427,11 +479,21 @@ key sequence that quotes the current or previous word in Bash: .RE .RE .IP \fB$endif\fP -This command, as you saw in the previous example, terminates an +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 @@ -464,7 +526,7 @@ the line, thereby executing the command from the history list. .PP Non-incremental searches read the entire search string before starting to search for matching history lines. The search string may be -typed by the user or part of the contents of the current line. +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 @@ -567,6 +629,8 @@ 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. .PD .SS Commands for Changing Text .PP @@ -575,9 +639,7 @@ behave exactly like \fByank\-nth\-arg\fP. .B delete\-char (C\-d) Delete the character under the cursor. If point is at the beginning of the line, there are no characters in the line, and -the last character typed was not -.BR C\-d , -then return +the last character typed was not bound to \fBBdelete\-char\fP, then return .SM .BR EOF . .TP @@ -606,15 +668,15 @@ moving the cursor over that word as well. .TP .B upcase\-word (M\-u) Uppercase the current (or following) word. With a negative argument, -do the previous word, but do not move point. +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, -do the previous word, but do not move point. +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, -do the previous word, but do not move point. +capitalize the previous word, but do not move point. .PD .SS Killing and Yanking .PP @@ -628,6 +690,7 @@ 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 @@ -660,9 +723,11 @@ 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 the cursor. @@ -720,6 +785,19 @@ List the possible completions of the text before point. 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 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. .PD .SS Keyboard Macros .PP @@ -765,7 +843,7 @@ is equivalent to Incremental undo, separately remembered for each line. .TP .B revert\-line (M\-r) -Undo all changes made to this line. This is like typing the +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 @@ -795,15 +873,6 @@ variable is inserted at the beginning of the current line, and the line is accepted as if a newline had been typed. This makes the current line a shell comment. .TP -.B glob\-expand\-word (C\-x *) -The word before point is treated as a pattern for pathname expansion, -and the list of matching file names is inserted, replacing the word. -.TP -.B glob\-list\-expansions (C\-x g) -The list of expansions that would have been generated by -.B glob\-expand\-word -is inserted into the line, replacing the word before point. -.TP .B dump\-functions Print all of the functions and their key bindings to the readline output stream. If a numeric argument is supplied, @@ -1097,10 +1166,10 @@ version of the library that you have. .PP Once you have determined that a bug actually exists, mail a -bug report to \fIbug\-readline\fP@\fIprep.ai.MIT.Edu\fP. +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@\fIprep.ai.MIT.Edu\fP or posted to the Usenet +to \fPbug-readline\fP@\fIgnu.org\fP or posted to the Usenet newsgroup .BR gnu.bash.bug . .PP @@ -190,6 +190,16 @@ internal_error (format, arg1, arg2, arg3, arg4, arg5) } void +internal_warning (format, arg1, arg2, arg3, arg4, arg5) + char *format; +{ + fprintf (stderr, "%s: warning: ", get_name_for_error ()); + + fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); + fprintf (stderr, "\n"); +} + +void sys_error (format, arg1, arg2, arg3, arg4, arg5) char *format; { @@ -322,6 +332,31 @@ internal_error (format, va_alist) 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 ()); + +#if defined (PREFER_STDARG) + va_start (args, format); +#else + va_start (args); +#endif + + vfprintf (stderr, format, args); + fprintf (stderr, "\n"); + + va_end (args); +} + +void +#if defined (PREFER_STDARG) sys_error (const char *format, ...) #else sys_error (format, va_alist) @@ -47,4 +47,7 @@ extern void sys_error __P((const char *, ...)); /* Report an internal error. */ extern void internal_error __P((const char *, ...)); +/* Report an internal warning. */ +extern void internal_warning __P((const char *, ...)); + #endif /* !_ERROR_H_ */ @@ -23,6 +23,9 @@ #include "config.h" #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -257,3 +260,38 @@ read_command () return (result); } + +/* 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, whom) + char *s, *whom; +{ + WORD_LIST *wl; + COMMAND *saved_global; + + push_stream (1); + + saved_global = global_command; + global_command = (COMMAND *)0; + + with_input_from_string (s, whom); + if (parse_command () != 0 || global_command == 0 || global_command->type != cm_simple) + { + if (global_command) + dispose_command (global_command); + wl = (WORD_LIST *)NULL; + } + else + { + wl = global_command->value.Simple->words; + free (global_command->value.Simple); + free (global_command); + } + + global_command = saved_global; + + pop_stream (); + + return (wl); +} diff --git a/examples/functions/basename2 b/examples/functions/basename2 new file mode 100644 index 00000000..a42231cf --- /dev/null +++ b/examples/functions/basename2 @@ -0,0 +1,43 @@ +#From: "Grigoriy Strokin" <grg@philol.msu.ru> +#Newsgroups: comp.unix.shell +#Subject: fast basename and dirname functions for BASH/SH +#Date: Sat, 27 Dec 1997 21:18:40 +0300 +# +#Please send your comments to grg@philol.msu.ru + +function basename() +{ + local name="${1##*/}" + echo "${name%$2}" +} + +function dirname() +{ + local dir="${1%${1##*/}}" + [ "${dir:=./}" != "/" ] && dir="${dir%?}" + echo "$dir" +} + +# Two additional functions: +# 1) namename prints the basename without extension +# 2) ext prints extension of a file, including "." + +function namename() +{ + local name=${1##*/} + local name0="${name%.*}" + echo "${name0:-$name}" +} +function ext() +{ + local name=${1##*/} + local name0="${name%.*}" + local ext=${name0:+${name#$name0}} + echo "${ext:-.}" +} + + + + + + diff --git a/examples/functions/getoptx.bash b/examples/functions/getoptx.bash new file mode 100644 index 00000000..23e5de52 --- /dev/null +++ b/examples/functions/getoptx.bash @@ -0,0 +1,302 @@ +#From: "Grigoriy Strokin" <grg@philol.msu.ru> +#Newsgroups: comp.unix.shell +#Subject: BASH: getopt function that parses long-named options +#Date: Mon, 22 Dec 1997 20:35:18 +0300 + +#Hi, I have written a BASH function named getoptex, that is like bash builtin +#"getopts", but does parse long-named options and optional arguments. It only +#uses builtin bash commands, so it is very fast. In order to use it in your +#bash scripts, include a command ". getopt.sh" (<dot> getopt.sh) to the file +#containing your script, and that will define functions getopt, getoptex, and +#optlistex (the file getopt.sh with its detailed description is listed +#below). + +#*** file getopt.sh *** + +#! /bin/bash +# +# getopt.sh: +# functions like getopts but do long-named options parsing +# and support optional arguments +# +# Version 1.0 1997 by Grigoriy Strokin (grg@philol.msu.ru), Public Domain +# Date created: December 21, 1997 +# Date modified: December 21, 1997 +# +# IMPORTANT FEATURES +# +# 1) Parses both short and long-named options +# 2) Supports optional arguments +# 3) Only uses bash builtins, thus no calls to external +# utilities such as expr or sed is done. Therefore, +# parsing speed is high enough +# +# +# DESCRIPTION +# +# FUNCTION getopt +# Usage: getopt OPTLIST {"$@"|ALTERNATIVE_PARAMETERS} +# +# like getopts, but parse options with both required and optional arguments, +# Options with optional arguments must have "." instead of ":" after them. +# Furthemore, a variable name to place option name cannot be specified +# and is always placed in OPTOPT variable +# +# This function is provided for compatibility with getopts() +# OPTLIST style, and it actually calls getoptex (see bellow) +# +# NOTE that a list of parameters is required and must be either "$@", +# if processing command line arguments, or some alternative parameters. +# +# FUNCTION getoptex +# Usage: getoptex OPTION_LIST {"$@"|ALTERNATIVE_PARAMETERS} +# +# like getopts, but parse long-named options. +# +# Both getopt and getoptex return 0 if an option has been parsed, +# and 1 if all options are already parsed or an error occured +# +# Both getopt and getoptex set or test the following variables: +# +# OPTERR -- tested for whether error messages must be given for invalid +options +# +# OPTOPT -- set to the name of an option parsed, +# or to "?" if no more options or error +# OPTARG -- set to the option argument, if any; +# unset if ther is no argument; +# on error, set to the erroneous option name +# +# OPTIND -- Initialized to 1. +# Then set to the number of the next parameter to be parsed +# when getopt or getoptex will be called next time. +# When all options are parsed, contains a number of +# the first non-option argument. +# +# +# OPTOFS -- If a parameter number $OPTIND containg an option parsed +# does not contain any more options, OPTOFS is unset; +# otherwise, OPTOFS is set to such a number of "?" signs +# which is equal to the number of options parsed +# +# You might not set variables OPTIND and OPTOFS yourself +# unless you want to parse a list of parameters more than once. +# Otherwise, you whould unset OPTIND (or set it to 1) +# and unset OPTOFS each time you want to parse a new parameters +list +# +# Option list format is DIFFERENT from one for getopts or getopt. +getopts-style +# option list can be converted to getoptex-style using a function optlistex +# (see bellow) +# +# DESCRIPTION of option list used with getoptex: +# Option names are separated by whitespace. Options consiting of +# more than one character are treated as long-named (--option) +# +# Special characters can appear at the and of option names specifying +# whether an argument is required (default is ";"): +# ";" (default) -- no argument +# ":" -- required argument +# "," -- optional argument +# +# For example, an option list "a b c help version f: file: separator." +# defines the following options: +# -a, -b, -c, --help, --version -- no argument +# -f, --file -- argument required +# --separator -- optional argument +# +# FUNCTION optlistex +# Usage new_style_optlist=`optlistex OLD_STYLE_OPTLIST` +# +# Converts getopts-style option list in a format suitable for use with getoptex +# Namely, it inserts spaces after each option name. +# +# +# HOW TO USE +# +# In order o use in your bash scripts the functions described, +# include a command ". getopt.sh" to the file containing the script, +# which will define functions getopt, getoptex, and optlistex +# +# EXAMPLES +# +# See files 'getopt1' and 'getopt2' that contain sample scripts that use +# getopt and getoptex functions respectively +# +# +# Please send your comments to grg@philol.msu.ru + +function getoptex() +{ + let $# || return 1 + local optlist="${1#;}" + let OPTIND || OPTIND=1 + [ $OPTIND -lt $# ] || return 1 + shift $OPTIND + if [ "$1" != "-" -a "$1" != "${1#-}" ] + then OPTIND=$[OPTIND+1]; if [ "$1" != "--" ] + then + local o + o="-${1#-$OPTOFS}" + for opt in ${optlist#;} + do + OPTOPT="${opt%[;.:]}" + unset OPTARG + local opttype="${opt##*[^;:.]}" + [ -z "$opttype" ] && opttype=";" + if [ ${#OPTOPT} -gt 1 ] + then # long-named option + case $o in + "--$OPTOPT") + if [ "$opttype" != ":" ]; then return 0; fi + OPTARG="$2" + if [ -z "$OPTARG" ]; + then # error: must have an agrument + let OPTERR && echo "$0: error: $OPTOPT must have an argument" >&2 + OPTARG="$OPTOPT"; + OPTOPT="?" + return 1; + fi + OPTIND=$[OPTIND+1] # skip option's argument + return 0 + ;; + "--$OPTOPT="*) + if [ "$opttype" = ";" ]; + then # error: must not have arguments + let OPTERR && echo "$0: error: $OPTOPT must not have arguments" >&2 + OPTARG="$OPTOPT" + OPTOPT="?" + return 1 + fi + OPTARG=${o#"--$OPTOPT="} + return 0 + ;; + esac + else # short-named option + case "$o" in + "-$OPTOPT") + unset OPTOFS + [ "$opttype" != ":" ] && return 0 + OPTARG="$2" + if [ -z "$OPTARG" ] + then + echo "$0: error: -$OPTOPT must have an argument" >&2 + OPTARG="$OPTOPT" + OPTOPT="?" + return 1 + fi + OPTIND=$[OPTIND+1] # skip option's argument + return 0 + ;; + "-$OPTOPT"*) + if [ $opttype = ";" ] + then # an option with no argument is in a chain of options + OPTOFS="$OPTOFS?" # move to the next option in the chain + OPTIND=$[OPTIND-1] # the chain still has other options + return 0 + else + unset OPTOFS + OPTARG="${o#-$OPTOPT}" + return 0 + fi + ;; + esac + fi + done + echo "$0: error: invalid option: $o" + fi; fi + OPTOPT="?" + unset OPTARG + return 1 +} +function optlistex +{ + local l="$1" + local m # mask + local r # to store result + while [ ${#m} -lt $[${#l}-1] ]; do m="$m?"; done # create a "???..." mask + while [ -n "$l" ] + do + r="${r:+"$r "}${l%$m}" # append the first character of $l to $r + l="${l#?}" # cut the first charecter from $l + m="${m#?}" # cut one "?" sign from m + if [ -n "${l%%[^:.;]*}" ] + then # a special character (";", ".", or ":") was found + r="$r${l%$m}" # append it to $r + l="${l#?}" # cut the special character from l + m="${m#?}" # cut one more "?" sign + fi + done + echo $r +} +function getopt() +{ + local optlist=`optlistex "$1"` + shift + getoptex "$optlist" "$@" + return $? +} + +#************************************** +# cut here +#************************************** +#*** (end of getopt.sh) *** + + +#*** file getopt1 *** + +#! /bin/bash +# getopt1: +# Sample script using the function getopt +# +# Type something like "getopt1 -ab -d 10 -e20 text1 text2" +# on the command line to see how it works +# +# See getopt.sh for more information +#. getopt.sh +#echo Using getopt to parse arguments: +#while getopt "abcd:e." "$@" +#do +# echo "Option <$OPTOPT> ${OPTARG:+has an arg <$OPTARG>}" +#done +#shift $[OPTIND-1] +#for arg in "$@" +#do +# echo "Non option argument <$arg>" +#done +# +#************************************** +# cut here +#************************************** +#*** (end of getopt1) *** +# +# +#*** file getopt2 *** +# +#! /bin/bash +# getopt2: +# Sample script using the function getoptex +# +# Type something like "getopt2 -ab -d 10 -e20 --opt1 --opt4=100 text1 text2" +# to see how it works +# +# See getopt.sh for more information +. getopt.sh +#echo Using getoptex to parse arguments: +#while getoptex "a; b; c; d: e. opt1 opt2 opt3 opt4: opt5." "$@" +#do +# echo "Option <$OPTOPT> ${OPTARG:+has an arg <$OPTARG>}" +#done +#shift $[OPTIND-1] +#for arg in "$@" +#do +# echo "Non option argument <$arg>" +#done +# +#************************************** +# cut here +#************************************** +#*** (end of getopt2) *** + + diff --git a/examples/functions/inetaddr b/examples/functions/inetaddr new file mode 100644 index 00000000..776b204a --- /dev/null +++ b/examples/functions/inetaddr @@ -0,0 +1,44 @@ +# +# inet2hex - Internet address conversion, dotted-decimal to hex +# +inet2hex () +{ + local IFS + + IFS=. + set -- $1 + + if (( $# != 4 )); then + echo "inet2hex: incorrect input format: $1" >&2 + echo "inet2hex: usage: inet2hex XX.XX.XX.XX" >&2 + return 2 + fi + + printf "0x%02x%02x%02x%02x\n" $1 $2 $3 $4 +} + +# +# hex2inet - Internet address conversion, hex to dotted-decimal +# +hex2inet () +{ + local x1 x2 x3 x4 + + case "$1" in + 0x*) h=${1#??} ;; + *) h=$1 ;; + esac + + if (( ${#h} != 8 )); then + echo "hex2inet: $h not in inet format" >&2 + echo "hex2inet: usage: hex2inet [0x]XXXXXXXX" >&2 + return 2 + fi + + x1=$(( 0x${h:0:2} )) + x2=$(( 0x${h:2:2} )) + x3=$(( 0x${h:4:2} )) + x4=$(( 0x${h:6:2} )) + + printf "%d.%d.%d.%d\n" $x1 $x2 $x3 $x4 +} diff --git a/examples/functions/inpath b/examples/functions/inpath index 7755b33b..cb4c93da 100644 --- a/examples/functions/inpath +++ b/examples/functions/inpath @@ -1,5 +1,6 @@ inpath() { + local PROG path=$(echo $PATH | sed 's/^:/.:/ s/::/:.:/g s/:$/:./ @@ -9,7 +10,5 @@ inpath() do [ -x $x/$1 ] && { PROG=$x/$1; break; } done - [ -z "$PROG" ] - return + [ -n "$PROG" ] } - diff --git a/examples/functions/isnum.bash b/examples/functions/isnum.bash new file mode 100644 index 00000000..1eff13fb --- /dev/null +++ b/examples/functions/isnum.bash @@ -0,0 +1,23 @@ +#From: jrmartin@rainey.blueneptune.com (James R. Martin) +#Newsgroups: comp.unix.shell +#Subject: Re: testing user input on numeric or character value +#Date: 26 Nov 1997 01:28:43 GMT + +# isnum returns True if its argument is a valid number, +# and False (retval=1) if it is any other string. +# The first pattern requires a digit before the decimal +# point, and the second after the decimal point. + +# BASH NOTE: make sure you have executed `shopt -s extglob' before +# trying to use this function, or it will not work + +function isnum # string +{ + case $1 in + ?([-+])+([0-9])?(.)*([0-9])?([Ee]?([-+])+([0-9])) ) + return 0;; + ?([-+])*([0-9])?(.)+([0-9])?([Ee]?([-+])+([0-9])) ) + return 0;; + *) return 1;; + esac +} diff --git a/examples/functions/isnum2 b/examples/functions/isnum2 new file mode 100644 index 00000000..e2e7a5f5 --- /dev/null +++ b/examples/functions/isnum2 @@ -0,0 +1,22 @@ +isnum2() +{ + case "$1" in + '[-+]' | '') return 1;; # empty or bare `-' or `+' + [-+]*[!0-9]*) return 1;; # non-digit with leading sign + [-+]*) return 0;; # OK + *[!0-9]*) return 1;; # non-digit + *) return 0;; # OK + esac +} + +# this one handles floating point +isnum3() +{ + case "$1" in + '') return 1;; # empty + *[!0-9.+-]*) return 1;; # non-digit, +, -, or . + *?[-+]*) return 1;; # sign as second or later char + *.*.*) return 1;; # multiple decimal points + *) return 0;; # OK + esac +} diff --git a/examples/functions/jdate.bash b/examples/functions/jdate.bash new file mode 100644 index 00000000..9488ed90 --- /dev/null +++ b/examples/functions/jdate.bash @@ -0,0 +1,78 @@ +#From: damatex@CAM.ORG (Mario Boudreault) +#Newsgroups: comp.unix.shell +#Subject: JULIAN DATE CONVERSION SUB +#Date: 4 Aug 1995 10:23:28 -0400 +#Message-ID: <3vtah0$jb3@ocean.CAM.ORG> + +#For those using shells and who want to convert dates to a julian number +#here is a shell script (wihtout validation) that can be used as a base +#program for your shell scripts. + +#Special thanks to Ed Ferguson@ti.com who sent me the algorithm to compute +#that date. + +# +# MODIFIED BY CHET RAMEY TO CONVERT TO bash v2 SYNTAX +# + +# cnvdate - Conversion de dates en julienne et vice et versa... +# +# Par : Mario Boudreault Damatex Inc Montreal, Canada +# Date: 2 Aout 1995 +# Rev.: 2 Aout 1995 +# +# Usage: +# cvdate [-j] YYYMMDD pour convertir en nbre de jours +# cvdate -d {julian number} pour convertir en AAAAMMJJ +# + +jul_date() +{ + # + # Separe ANNEE, MOIS et JOUR... + # + YEAR=`echo $DATE | awk ' { print substr($0,1,4) } '` + MONTH=`echo $DATE | awk ' { print substr($0,5,2) } '` + DAY=`echo $DATE | awk ' { print substr($0,7,2) } '` + # + # Execute la formule magique... + # + A=$(( $DAY - 32075 + 1461 * ( $YEAR + 4800 - ( 14 - $MONTH ) / 12 ) \ + / 4 + 367 * ( $MONTH - 2 + ( 14 - $MONTH ) / 12 * 12 ) / 12 - \ + 3 * ( ( $YEAR + 4900 - ( 14 - $MONTH ) / 12 ) / 100 ) / 4 )) + echo $A +} + +day_date() +{ + TEMP1=$(( $DATE + 68569 )) + TEMP2=$(( 4 * $TEMP1 / 146097 )) + TEMP1=$(( $TEMP1 - ( 146097 * $TEMP2 + 3 ) / 4 )) + Y=$(( 4000 * ( $TEMP1 + 1 ) / 1461001 )) + TEMP1=$(( $TEMP1 - 1461 * $Y / 4 + 31 )) + M=$(( 80 * $TEMP1 / 2447 )) + D=$(( $TEMP1 - 2447 * $M / 80 )) + TEMP1=$(( $M / 11 )) + M=$(( $M + 2 - 12 * $TEMP1 )) + Y=$(( 100 * ( $TEMP2 - 49 ) + $Y + $TEMP1 )) + M=`echo $M | awk ' { M=$0 ; if ( length($0) == 1 ) M="0"$0 } END { print M } '` + D=`echo $D | awk ' { D=$0 ; if ( length($0) == 1 ) D="0"$0 } END { print D } '` + echo $Y$M$D +} + +# main() + +if [ $# -eq 1 ]; then + DATE=$1 + jul_date +elif [ "$1" = '-j' ]; then + DATE=$2 + jul_date +elif [ "$1" = '-d' ]; then + DATE=$2 + day_date +fi +# +# Termine +# +exit 0 diff --git a/examples/functions/pathfuncs b/examples/functions/pathfuncs new file mode 100644 index 00000000..47896bf5 --- /dev/null +++ b/examples/functions/pathfuncs @@ -0,0 +1,48 @@ +#From: "Simon J. Gerraty" <sjg@zen.void.oz.au> +#Message-Id: <199510091130.VAA01188@zen.void.oz.au> +#Subject: Re: a shell idea? +#Date: Mon, 09 Oct 1995 21:30:20 +1000 + + +# NAME: +# add_path.sh - add dir to path +# +# DESCRIPTION: +# These functions originated in /etc/profile and ksh.kshrc, but +# are more useful in a separate file. +# +# SEE ALSO: +# /etc/profile +# +# AUTHOR: +# Simon J. Gerraty <sjg@zen.void.oz.au> + +# RCSid: +# $Id: add_path.sh,v 1.1 1995/09/30 12:45:23 sjg Exp $ +# +# @(#)Copyright (c) 1991 Simon J. Gerraty +# +# This file is provided in the hope that it will +# be of use. There is absolutely NO WARRANTY. +# Permission to copy, redistribute or otherwise +# use this file is hereby granted provided that +# the above copyright notice and this notice are +# left intact. + +# is $1 missing from $2 (or PATH) ? +no_path() { + eval "case :\$${2-PATH}: in *:$1:*) return 1;; *) return 0;; esac" +} +# if $1 exists and is not in path, append it +add_path () { + [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="\$${2:-PATH}:$1" +} +# if $1 exists and is not in path, prepend it +pre_path () { + [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="$1:\$${2:-PATH}" +} +# if $1 is in path, remove it +del_path () { + no_path $* || eval ${2:-PATH}=`eval echo :'$'${2:-PATH}: | + sed -e "s;:$1:;:;g" -e "s;^:;;" -e "s;:\$;;"` +} diff --git a/examples/functions/shcat2 b/examples/functions/shcat2 new file mode 100644 index 00000000..6fe90f40 --- /dev/null +++ b/examples/functions/shcat2 @@ -0,0 +1,19 @@ +shcat() +{ + while read -r line + do + echo "$line" + done +} + +shcat2() +{ + while [ $# -ge 1 ]; do + case "$1" in + -) shcat ;; + *) shcat < "$1" ;; + esac + shift + done + exit 0 +} diff --git a/examples/loadables/Makefile b/examples/loadables/Makefile.in index 9f93bca7..9773144d 100644 --- a/examples/loadables/Makefile +++ b/examples/loadables/Makefile.in @@ -1,41 +1,64 @@ # # Simple makefile for the sample loadable builtins # -CC = cc +# This includes some boilerplate definitions added by configure, but will +# still need hand-editing +# +# 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 = /bin/sh # SunOS 4 -PICFLAG = -pic +#PICFLAG = -pic # Some versions of gcc, esp. on NetBSD and FreeBSD -#PICFLAG = -fpic +PICFLAG = -fpic # Linux -- could also be -fpic #PICFLAG = -fPIC # SunOS 5 #PICFLAG = -K pic # SVR4, SVR4.2, Irix #PICFLAG = -K PIC -# BSD/OS 2.1 +# BSD/OS 2.1, BSD/OS 3.x #PICFLAG = # AIX 4.2 #PICFLAG = -K -# SunOS 4, BSD/OS 2.1, SVR4.2, SVR4, Linux, AIX 4.2, etc. +# SunOS 4, BSD/OS 2.1, BSD/OS 3.x, SVR4.2, SVR4, Linux, AIX 4.2, etc. LD = ld # SunOS 5, Linux -#LD = cc +#LD = ${CC} # SunOS 4 -LDOPT = -assert pure-text +#LDOPT = -assert pure-text # OSF/1, Digital UNIX #LDOPT = -shared -soname $@ -expect_unresolved '*' -# SunOS 5 +# SunOS 5 using sun cc #LDOPT = -dy -z text -G -i -h $@ +# SunOS 5 using gcc with Sun ld +#LDOPT = -shared -Wl,-dy -Wl,-G -Wl,-i # SVR4, SVR4.2 #LDOPT = -dy -z text -G -h $@ # NetBSD, FreeBSD -- might also need -r -#LDOPT = -x -Bshareable +LDOPT = -x -Bshareable # Linux #LDOPT = -shared -# BSD/OS 2.1 +# BSD/OS 2.1, BSD/OS 3.x #LDOPT = -r # AIX 4.2 #LDOPT = -bdynamic -bnoentry -bexpall -G @@ -43,19 +66,25 @@ LDOPT = -assert pure-text # other libraries to link the shared object against # BSD/OS 2.1 #LDLIBS = -lc_s.2.1.0 +# BSD/OS 3.0, BSD/OS 3.1 +#LDLIBS = -lc_s.3.0.0 + -srcdir = ../.. -INC= -I$(srcdir) -I$(srcdir)/builtins -I$(srcdir)/lib +INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \ + -I$(BUILD_DIR) -I$(BUILD_DIR)/lib -I$(BUILD_DIR)/builtins .c.o: $(CC) $(PICFLAG) $(CFLAGS) $(INC) -c -o $@ $< -all: printf print truefalse sleep pushd finfo logname basename dirname \ - tty pathchk tee head rmdir sprintf -others: necho getconf hello cat -printf: printf.o - $(LD) $(LDOPT) -o $@ printf.o $(LDLIBS) +ALLPROG = print truefalse sleep pushd finfo logname basename dirname \ + tty pathchk tee head rmdir sprintf +OTHERPROG = necho getconf hello cat + +all: $(ALLPROG) +others: $(OTHERPROG) + +everything: all others sprintf: sprintf.o $(LD) $(LDOPT) -o $@ sprintf.o $(LDLIBS) @@ -110,3 +139,31 @@ rmdir: rmdir.o head: head.o $(LD) $(LDOPT) -o $@ head.o $(LDLIBS) + +clean: + $(RM) $(ALLPROG) $(OTHERPROG) *.o + +mostlyclean: clean + +distclean maintainer-clean: clean + $(RM) Makefile + +print.o: print.c +truefalse.o: truefalse.c +sleep.o: sleep.c +pushd.o: pushd.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 +sprintf.o: sprintf.c +necho.o: necho.c +getconf.o: getconf.c +hello.o: hello.c +cat.o: cat.c + diff --git a/examples/loadables/getconf.c b/examples/loadables/getconf.c index 3b53331d..0f264edb 100644 --- a/examples/loadables/getconf.c +++ b/examples/loadables/getconf.c @@ -1,4 +1,6 @@ /* + * ORIGINAL COPYRIGHT STATEMENT: + * * Copyright (c) 1994 Winning Strategies, Inc. * All rights reserved. * @@ -31,14 +33,13 @@ /* * POSIX.2 getconf utility * - * Written by: + * Originally Written by: * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc. + * + * Heavily modified for inclusion in bash by + * Chet Ramey <chet@po.cwru.edu> */ -#ifndef lint -static char rcsid[] = "$Id: getconf.c,v 1.2 1994/05/10 00:04:12 jtc Exp $"; -#endif /* not lint */ - #include <stdio.h> #include <limits.h> #include <locale.h> @@ -48,7 +49,8 @@ static char rcsid[] = "$Id: getconf.c,v 1.2 1994/05/10 00:04:12 jtc Exp $"; #include "shell.h" #include "builtins.h" #include "stdc.h" - +#include "common.h" +#include "bashgetopt.h" struct conf_variable { @@ -57,25 +59,66 @@ struct conf_variable long value; }; -/* BSD/OS does not define this; use Posix.2 recommended minimum value. */ +/* Some systems do not define these; use POSIX.2 minimum recommended values. */ #ifndef _POSIX2_COLL_WEIGHTS_MAX -#define _POSIX2_COLL_WEIGHTS_MAX 2 +# define _POSIX2_COLL_WEIGHTS_MAX 2 #endif 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 - /* Utility Limit Minimum Values */ + /* Single UNIX Specification version 2 Configurable Variable Values */ +#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 }, + { "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 }, + { "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 }, + { "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 /* _CS_XBS5_ILP32_OFF32_CFLAGS */ + + /* POSIX.2 Utility Limit Minimum Values */ { "POSIX2_BC_BASE_MAX", CONSTANT, _POSIX2_BC_BASE_MAX }, { "POSIX2_BC_DIM_MAX", CONSTANT, _POSIX2_BC_DIM_MAX }, { "POSIX2_BC_SCALE_MAX", CONSTANT, _POSIX2_BC_SCALE_MAX }, { "POSIX2_BC_STRING_MAX", CONSTANT, _POSIX2_BC_STRING_MAX }, { "POSIX2_COLL_WEIGHTS_MAX", CONSTANT, _POSIX2_COLL_WEIGHTS_MAX }, +#if defined (_POSIX2_EQUIV_CLASS_MAX) + { "POSIX2_EQUIV_CLASS_MAX", CONSTANT, _POSIX2_EQUIV_CLASS_MAX }, +#endif { "POSIX2_EXPR_NEST_MAX", CONSTANT, _POSIX2_EXPR_NEST_MAX }, { "POSIX2_LINE_MAX", CONSTANT, _POSIX2_LINE_MAX }, { "POSIX2_RE_DUP_MAX", CONSTANT, _POSIX2_RE_DUP_MAX }, +#if defined (_POSIX2_VERSION) { "POSIX2_VERSION", CONSTANT, _POSIX2_VERSION }, +#endif /* POSIX.1 Minimum Values */ { "_POSIX_ARG_MAX", CONSTANT, _POSIX_ARG_MAX }, @@ -92,7 +135,7 @@ static const struct conf_variable conf_table[] = { "_POSIX_STREAM_MAX", CONSTANT, _POSIX_STREAM_MAX }, { "_POSIX_TZNAME_MAX", CONSTANT, _POSIX_TZNAME_MAX }, - /* Symbolic Utility Limits */ + /* POSIX.2 Symbolic Utility Limits */ { "BC_BASE_MAX", SYSCONF, _SC_BC_BASE_MAX }, { "BC_DIM_MAX", SYSCONF, _SC_BC_DIM_MAX }, { "BC_SCALE_MAX", SYSCONF, _SC_BC_SCALE_MAX }, @@ -102,15 +145,25 @@ static const struct conf_variable conf_table[] = { "LINE_MAX", SYSCONF, _SC_LINE_MAX }, { "RE_DUP_MAX", SYSCONF, _SC_RE_DUP_MAX }, - /* Optional Facility Configuration Values */ + /* POSIX.2 Optional Facility Configuration Values */ { "POSIX2_C_BIND", SYSCONF, _SC_2_C_BIND }, { "POSIX2_C_DEV", SYSCONF, _SC_2_C_DEV }, +#if defined (_SC_2_C_VERSION) + { "POSIX2_C_VERSION", SYSCONF, _SC_2_C_VERSION }, +#endif +#if defined (_SC_2_CHAR_TERM) { "POSIX2_CHAR_TERM", SYSCONF, _SC_2_CHAR_TERM }, +#endif { "POSIX2_FORT_DEV", SYSCONF, _SC_2_FORT_DEV }, { "POSIX2_FORT_RUN", SYSCONF, _SC_2_FORT_RUN }, { "POSIX2_LOCALEDEF", SYSCONF, _SC_2_LOCALEDEF }, { "POSIX2_SW_DEV", SYSCONF, _SC_2_SW_DEV }, +#if defined (_SC2_UPE) { "POSIX2_UPE", SYSCONF, _SC_2_UPE }, +#endif +#if !defined (_POSIX2_VERSION) && defined (_SC_2_VERSION) + { "POSIX2_VERSION" SYSCONF, _SC_2_VERSION }, +#endif /* POSIX.1 Configurable System Variables */ { "ARG_MAX", SYSCONF, _SC_ARG_MAX }, @@ -124,6 +177,140 @@ static const struct conf_variable conf_table[] = { "_POSIX_SAVED_IDS", SYSCONF, _SC_SAVED_IDS }, { "_POSIX_VERSION", SYSCONF, _SC_VERSION }, + /* POSIX.1 Optional Facility Configuration Values */ +#if defined (_SC_ASYNCHRONOUS_IO) + { "_POSIX_ASYNCHRONOUS_IO", SYSCONF, _SC_ASYNCHRONOUS_IO }, +#endif +#if defined (_SC_FSYNC) + { "_POSIX_FSYNC", SYSCONF, _SC_FSYNC }, +#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_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_REALTIME_SIGNALS) + { "_POSIX_REALTIME_SIGNALS", SYSCONF, _SC_REALTIME_SIGNALS }, +#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 +#if defined (_SC_SYNCHRONIZED_IO) + { "_POSIX_SYNCHRONIZED_IO", SYSCONF, _SC_SYNCHRONIZED_IO }, +#endif +#if defined (_SC_TIMERS) + { "_POSIX_TIMERS", SYSCONF, _SC_TIMERS }, +#endif +#if defined (_SC_THREADS) + { "_POSIX_THREADS", SYSCONF, _SC_THREADS }, + { "_POSIX_THREAD_ATTR_STACKADDR", SYSCONF, _SC_THREAD_ATTR_STACKADDR }, + { "_POSIX_THREAD_ATTR_STACKSIZE", SYSCONF, _SC_THREAD_ATTR_STACKSIZE }, + { "_POSIX_THREAD_PRIORITY_SCHEDULING", SYSCONF, _SC_THREAD_PRIORITY_SCHEDULING }, + { "_POSIX_THREAD_PRIO_INHERIT", SYSCONF, _SC_THREAD_PRIO_INHERIT }, + { "_POSIX_THREAD_PRIO_PROTECT", SYSCONF, _SC_THREAD_PRIO_PROTECT }, + { "_POSIX_THREAD_PROCESS_SHARED", SYSCONF, _SC_THREAD_PROCESS_SHARED }, +# if defined (_SC_THREAD_SAFE_FUNCTIONS) + { "_POSIX_THREAD_SAFE_FUNCTIONS", SYSCONF, _SC_THREAD_SAFE_FUNCTIONS }, +# endif +#endif /* _SC_THREADS */ + + /* XPG 4.2 Configurable System Variables. */ +#if defined (_SC_ATEXIT_MAX) + { "ATEXIT_MAX", SYSCONF, _SC_ATEXIT_MAX }, +#endif +#if defined (_SC_IOV_MAX) + { "IOV_MAX", SYSCONF, _SC_IOV_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_AIO_LISTIO_MAX) + { "AIO_LISTIO_MAX", SYSCONF, _SC_AIO_LISTIO_MAX }, + { "AIO_MAX", SYSCONF, _SC_AIO_MAX }, + { "AIO_PRIO_DELTA_MAX", SYSCONF, _SC_AIO_PRIO_DELTA_MAX }, + { "DELAYTIMER_MAX", SYSCONF, _SC_DELAYTIMER_MAX }, +#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 + { "MQ_OPEN_MAX", SYSCONF, _SC_MQ_OPEN_MAX }, + { "MQ_PRIO_MAX", SYSCONF, _SC_MQ_PRIO_MAX }, + { "RTSIG_MAX", SYSCONF, _SC_RTSIG_MAX }, + { "SEM_NSEMS_MAX", SYSCONF, _SC_SEM_NSEMS_MAX }, + { "SEM_VALUE_MAX", SYSCONF, _SC_SEM_VALUE_MAX }, + { "SIGQUEUE_MAX", SYSCONF, _SC_SIGQUEUE_MAX }, + { "TIMER_MAX", SYSCONF, _SC_TIMER_MAX }, +#endif /* _SC_AIO_LISTIO_MAX */ +#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_TTY_NAME_MAX) + { "TTY_NAME_MAX", SYSCONF, _SC_TTY_NAME_MAX }, +#endif + +#if defined (_SC_PTHREAD_DESTRUCTOR_ITERATIONS) + { "PTHREAD_DESTRUCTOR_ITERATIONS", SYSCONF, _SC_THREAD_DESTRUCTOR_ITERATIONS }, + { "PTHREAD_KEYS_MAX", SYSCONF, _SC_THREAD_KEYS_MAX }, + { "PTHREAD_STACK_MIN", SYSCONF, _SC_THREAD_STACK_MIN }, + { "PTHREAD_THREADS_MAX", SYSCONF, _SC_THREAD_THREADS_MAX }, +#endif /* _SC_PTHREAD_DESTRUCTOR_ITERATIONS */ + + /* XPG 4.2 Optional Facility Configuration Values */ +#if defined (_SC_XOPEN_UNIX) + { "_XOPEN_UNIX", SYSCONF, _SC_XOPEN_UNIX }, + { "_XOPEN_CRYPT", SYSCONF, _SC_XOPEN_CRYPT }, + { "_XOPEN_ENH_I18N", SYSCONF, _SC_XOPEN_ENH_I18N }, + { "_XOPEN_SHM", SYSCONF, _SC_XOPEN_SHM }, + { "_XOPEN_VERSION", SYSCONF, _SC_XOPEN_VERSION }, +# if defined (_SC_XOPEN_XCU_VERSION) + { "_XOPEN_XCU_VERSION", SYSCONF, _SC_XOPEN_XCU_VERSION }, +# endif +#endif +#if defined (_SC_XOPEN_REALTIME) + { "_XOPEN_REALTIME", SYSCONF, _SC_XOPEN_REALTIME }, + { "_XOPEN_REALTIME_THREADS", SYSCONF, _SC_XOPEN_REALTIME_THREADS }, +#endif +#if defined (_SC_XOPEN_LEGACY) + { "_XOPEN_LEGACY", SYSCONF, _SC_XOPEN_LEGACY }, +#endif /* _SC_XOPEN_LEGACY */ + + /* Single UNIX Specification version 2 Optional Facility Configuration Values */ +#if defined (_SC_XBS5_ILP32_OFF32) + { "_XBS5_ILP32_OFF32", SYSCONF, _SC_XBS5_ILP32_OFF32 }, + { "_XBS5_ILP32_OFFBIG", SYSCONF, _SC_XBS5_ILP32_OFFBIG }, + { "_XBS5_LP64_OFF64", SYSCONF, _SC_XBS5_LP64_OFF64 }, + { "_XBS5_LPBIG_OFFBIG", SYSCONF, _SC_XBS5_LPBIG_OFFBIG }, +#endif /* _SC_XBS5_ILP32_OFF32 */ + + /* POSIX.1 Configurable Pathname Values */ { "LINK_MAX", PATHCONF, _PC_LINK_MAX }, { "MAX_CANON", PATHCONF, _PC_MAX_CANON }, { "MAX_INPUT", PATHCONF, _PC_MAX_INPUT }, @@ -134,81 +321,93 @@ static const struct conf_variable conf_table[] = { "_POSIX_NO_TRUNC", PATHCONF, _PC_NO_TRUNC }, { "_POSIX_VDISABLE", PATHCONF, _PC_VDISABLE }, + /* 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 + { NULL } }; +static int num_getconf_variables = sizeof(conf_table) / sizeof(struct conf_variable) - 1; + extern char *this_command_name; extern char *xmalloc (); extern char **make_builtin_argv (); -static int getconf_main (); + +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; + int c, r, opt, aflag; char **v; - WORD_LIST *l; - v = make_builtin_argv (list, &c); - r = getconf_main (c, v); - free (v); + aflag = 0; + reset_internal_getopt(); + while ((opt = internal_getopt (list, "ah")) != -1) { + switch (opt) { + case 'a': + aflag = 1; + break; + case 'h': + getconf_help(); + return(EXECUTION_SUCCESS); + 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 int -getconf_main(argc, argv) - int argc; - char **argv; +static void +getconf_help() { - int ch; const struct conf_variable *cp; + register int i, column; - long val; - size_t slen; - char *sval; - - setlocale(LC_ALL, ""); - - while ((ch = getopt(argc, argv, "")) != -1) { - switch (ch) { - case '?': - default: - builtin_usage(); - return(EX_USAGE); - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - - if (argc < 1 || argc > 2) { - builtin_usage(); - return(EX_USAGE); - /* NOTREACHED */ - } - + builtin_usage(); + printf("Acceptable variable names are:\n"); for (cp = conf_table; cp->name != NULL; cp++) { - if (strcmp(*argv, cp->name) == 0) - break; - } - if (cp->name == NULL) { - builtin_error ("%s: unknown variable", *argv); - return (EXECUTION_FAILURE); + if (cp->type == PATHCONF) + printf("%s pathname\n", cp->name); + else + printf("%s\n", cp->name); } +} - if (cp->type == PATHCONF) { - if (argc != 2) { - builtin_usage(); - return(EX_USAGE); - } - } else { - if (argc != 1) { - builtin_usage(); - return(EX_USAGE); - } - } +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 CONSTANT: @@ -216,19 +415,33 @@ getconf_main(argc, argv) 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) { - builtin_error ("%s", strerror (errno)); + if (all) + printf("getconf: %s\n", strerror (errno)); + else + builtin_error ("%s", strerror (errno)); return (EXECUTION_FAILURE); } @@ -240,9 +453,12 @@ getconf_main(argc, argv) case PATHCONF: errno = 0; - if ((val = pathconf(argv[1], cp->value)) == -1) { + if ((val = pathconf(vpath, cp->value)) == -1) { if (errno != 0) { - builtin_error ("%s: %s", argv[1], strerror (errno)); + if (all) + printf("getconf: %s: %s\n", vpath, strerror (errno)); + else + builtin_error ("%s: %s", vpath, strerror (errno)); return (EXECUTION_FAILURE); } @@ -256,6 +472,56 @@ getconf_main(argc, argv) 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.", @@ -267,6 +533,6 @@ struct builtin getconf_struct = { getconf_builtin, BUILTIN_ENABLED, getconf_doc, - "getconf sysvar or getconf pathvar pathname", + "getconf -a or getconf -h or getconf sysvar or getconf pathvar pathname", 0 }; diff --git a/examples/loadables/print.c b/examples/loadables/print.c index 8fea61cf..71449244 100644 --- a/examples/loadables/print.c +++ b/examples/loadables/print.c @@ -1,37 +1,4 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/types.h> +#include "bashtypes.h" #include <errno.h> #include <limits.h> @@ -47,44 +14,15 @@ extern int errno; #endif -#define PF(f, func) { \ - if (fieldwidth) \ - if (precision) \ - (void)fprintf(ofp, f, fieldwidth, precision, func); \ - else \ - (void)fprintf(ofp, f, fieldwidth, func); \ - else if (precision) \ - (void)fprintf(ofp, f, precision, func); \ - else \ - (void)fprintf(ofp, f, func); \ -} - -static int asciicode __P((void)); -static void escape __P((char *)); -static int getchr __P((void)); -static double getdouble __P((void)); -static int getint __P((int *)); -static int getlong __P((long *)); -static char *getstr __P((void)); -static char *mklong __P((char *, int)); -static void usage __P((void)); - -static char **gargv; - int print_builtin (); -static int printf_main (); static int printargs (); static FILE *ofp; extern char *ansicstr (); -extern char *single_quote (); -extern char **make_builtin_argv (); extern char *this_command_name; -extern int optind; - static char *print_doc[] = { "Output the arguments. The -f option means to use the argument as a", "format string as would be supplied to printf(1). The rest of the", @@ -168,12 +106,15 @@ opt_end: if (pfmt) { - v = word_list_to_argv (list, 0, 2, &c); - v[0] = this_command_name; - v[1] = pfmt; - r = printf_main (c, v); - free (v); - return r; + 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) @@ -198,7 +139,8 @@ opt_end: return 0; } -static int printargs (list, ofp) +static int +printargs (list, ofp) WORD_LIST *list; FILE *ofp; { @@ -208,7 +150,7 @@ static int printargs (list, ofp) for (sawc = 0, l = list; l; l = l->next) { - ostr = ansicstr (l->word->word, strlen (l->word->word), &sawc); + ostr = ansicstr (l->word->word, strlen (l->word->word), &sawc, (int *)0); fprintf (ofp, "%s", ostr); free (ostr); if (sawc) @@ -219,335 +161,3 @@ static int printargs (list, ofp) return (1); } -static int -printf_main(argc, argv) - int argc; - char *argv[]; -{ - static char *skip1, *skip2; - int ch, end, fieldwidth, precision; - char convch, nextch, *format, *fmt, *start; - - while ((ch = getopt(argc, argv, "")) != EOF) - switch (ch) { - case '?': - default: - usage(); - return (1); - } - argc -= optind; - argv += optind; - - if (argc < 1) { - usage(); - return (1); - } - - /* - * Basic algorithm is to scan the format string for conversion - * specifications -- once one is found, find out if the field - * width or precision is a '*'; if it is, gather up value. Note, - * format strings are reused as necessary to use up the provided - * arguments, arguments of zero/null string are provided to use - * up the format string. - */ - skip1 = "#-+ 0"; - skip2 = "*0123456789"; - - escape(fmt = format = *argv); /* backslash interpretation */ - gargv = ++argv; - for (;;) { - end = 0; - /* find next format specification */ -next: for (start = fmt;; ++fmt) { - if (!*fmt) { - /* avoid infinite loop */ - if (end == 1) { - warnx("missing format character", - NULL, NULL); - return (1); - } - end = 1; - if (fmt > start) - (void)printf("%s", start); - if (!*gargv) - return (0); - fmt = format; - goto next; - } - /* %% prints a % */ - if (*fmt == '%') { - if (*++fmt != '%') - break; - *fmt++ = '\0'; - (void)printf("%s", start); - goto next; - } - } - - /* skip to field width */ - for (; strchr(skip1, *fmt); ++fmt); - if (*fmt == '*') { - if (getint(&fieldwidth)) - return (1); - } else - fieldwidth = 0; - - /* skip to possible '.', get following precision */ - for (; strchr(skip2, *fmt); ++fmt); - if (*fmt == '.') - ++fmt; - if (*fmt == '*') { - if (getint(&precision)) - return (1); - } else - precision = 0; - - /* skip to conversion char */ - for (; strchr(skip2, *fmt); ++fmt); - if (!*fmt) { - warnx("missing format character", NULL, NULL); - return (1); - } - - convch = *fmt; - nextch = *++fmt; - *fmt = '\0'; - switch(convch) { - case 'c': { - char p; - - p = getchr(); - PF(start, p); - break; - } - case 's': { - char *p; - - p = getstr(); - PF(start, p); - break; - } - case 'b': { /* expand escapes in argument */ - char *p; - - p = getstr(); - escape(p); - PF(start, p); - break; - } - case 'q': { /* print with shell single quoting */ - char *p, *p2; - - p = getstr(); - p2 = single_quote(p); - PF(start, p2); - free(p2); - break; - } - case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { - long p; - char *f; - - if ((f = mklong(start, convch)) == NULL) - return (1); - if (getlong(&p)) - return (1); - PF(f, p); - break; - } - case 'e': case 'E': case 'f': case 'g': case 'G': { - double p; - - p = getdouble(); - PF(start, p); - break; - } - default: - warnx("illegal format character", NULL, NULL); - return (1); - } - *fmt = nextch; - } - /* NOTREACHED */ -} - -static char * -mklong(str, ch) - char *str; - int ch; -{ - static char copy[64]; - int len; - - len = strlen(str) + 2; - memmove(copy, str, len - 3); - copy[len - 3] = 'l'; - copy[len - 2] = ch; - copy[len - 1] = '\0'; - return (copy); -} - -static void -escape(fmt) - register char *fmt; -{ - register char *store; - register int value, c; - - for (store = fmt; c = *fmt; ++fmt, ++store) { - if (c != '\\') { - *store = c; - continue; - } - switch (*++fmt) { - case '\0': /* EOS, user error */ - *store = '\\'; - *++store = '\0'; - return; - case '\\': /* backslash */ - case '\'': /* single quote */ - *store = *fmt; - break; - case 'a': /* bell/alert */ - *store = '\7'; - break; - case 'b': /* backspace */ - *store = '\b'; - break; - case 'c': - return; - case 'e': - case 'E': - *store = '\033'; - break; - case 'f': /* form-feed */ - *store = '\f'; - break; - case 'n': /* newline */ - *store = '\n'; - break; - case 'r': /* carriage-return */ - *store = '\r'; - break; - case 't': /* horizontal tab */ - *store = '\t'; - break; - case 'v': /* vertical tab */ - *store = '\13'; - break; - /* octal constant */ - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - for (c = 3, value = 0; - c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { - value <<= 3; - value += *fmt - '0'; - } - --fmt; - *store = value; - break; - default: - *store = *fmt; - break; - } - } - *store = '\0'; -} - -static int -getchr() -{ - if (!*gargv) - return ('\0'); - return ((int)**gargv++); -} - -static char * -getstr() -{ - if (!*gargv) - return (""); - return (*gargv++); -} - -static char *Number = "+-.0123456789"; -static int -getint(ip) - int *ip; -{ - long val; - - if (getlong(&val)) - return (1); - if (val > INT_MAX) { - warnx("%s: %s", *gargv, strerror(ERANGE)); - return (1); - } - *ip = val; - return (0); -} - -static int -getlong(lp) - long *lp; -{ - long val; - char *ep; - - if (!*gargv) { - *lp = 0; - return (0); - } - if (strchr(Number, **gargv)) { - errno = 0; - val = strtol(*gargv, &ep, 0); - if (*ep != '\0') { - warnx("%s: illegal number", *gargv, NULL); - return (1); - } - if (errno == ERANGE) - if (val == LONG_MAX) { - warnx("%s: %s", *gargv, strerror(ERANGE)); - return (1); - } - if (val == LONG_MIN) { - warnx("%s: %s", *gargv, strerror(ERANGE)); - return (1); - } - - *lp = val; - ++gargv; - return (0); - } - *lp = (long)asciicode(); - return (0); -} - -static double -getdouble() -{ - if (!*gargv) - return ((double)0); - if (strchr(Number, **gargv)) - return (atof(*gargv++)); - return ((double)asciicode()); -} - -static int -asciicode() -{ - register int ch; - - ch = **gargv; - if (ch == '\'' || ch == '"') - ch = (*gargv)[1]; - ++gargv; - return (ch); -} - -static void -usage() -{ - (void)fprintf(stderr, "usage: print [-Rnprs] [-u unit] [-f format] [arg ...]\n"); -} diff --git a/examples/loadables/printf.c b/examples/loadables/printf.c deleted file mode 100644 index 33996c6e..00000000 --- a/examples/loadables/printf.c +++ /dev/null @@ -1,460 +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 <sys/types.h> - -#include <errno.h> -#include <limits.h> -#include <stdio.h> - -#include "bashansi.h" -#include "shell.h" -#include "builtins.h" -#include "stdc.h" - -#if !defined (errno) -extern int errno; -#endif - -#define PF(f, func) { \ - if (fieldwidth) \ - if (precision) \ - (void)printf(f, fieldwidth, precision, func); \ - else \ - (void)printf(f, fieldwidth, func); \ - else if (precision) \ - (void)printf(f, precision, func); \ - else \ - (void)printf(f, func); \ -} - -static int asciicode __P((void)); -static void escape __P((char *)); -static int getchr __P((void)); -static double getdouble __P((void)); -static int getint __P((int *)); -static int getlong __P((long *)); -static char *getstr __P((void)); -static char *mklong __P((char *, int)); -static void usage __P((void)); - -static char **gargv; - -int printf_builtin (); -static int printf_main (); -extern char *this_command_name; -extern char *single_quote (); -extern char **make_builtin_argv (); - -static char *printf_doc[] = { - "printf formats and prints its arguments, after the first, under control", - "of the format. The format is a character string which contains three", - "types of objects: plain characters, which are simply copied to standard", - "output, character escape sequences which are converted and copied to the", - "standard output, and format specifications, each of which causes printing", - "of the next successive argument. In addition to the standard printf(1)", - "formats, %%b means to expand escapes in the corresponding argument, and", - "%%q means to quote the argument in a way that can be reused as shell input.", - (char *)NULL -}; - -struct builtin printf_struct = { - "printf", - printf_builtin, - BUILTIN_ENABLED, - printf_doc, - "printf format [arguments]", - (char *)0 -}; - -int -printf_builtin (list) - WORD_LIST *list; -{ - int c, r; - char **v; - WORD_LIST *l; - - v = make_builtin_argv (list, &c); - r = printf_main (c, v); - free (v); - fflush(stdout); - - return r; -} - -static int -printf_main(argc, argv) - int argc; - char *argv[]; -{ - extern int optind; - static char *skip1, *skip2; - int ch, end, fieldwidth, precision; - char convch, nextch, *format, *fmt, *start; - - while ((ch = getopt(argc, argv, "")) != EOF) - switch (ch) { - case '?': - default: - usage(); - return (1); - } - argc -= optind; - argv += optind; - - if (argc < 1) { - usage(); - return (1); - } - - /* - * Basic algorithm is to scan the format string for conversion - * specifications -- once one is found, find out if the field - * width or precision is a '*'; if it is, gather up value. Note, - * format strings are reused as necessary to use up the provided - * arguments, arguments of zero/null string are provided to use - * up the format string. - */ - skip1 = "#-+ 0"; - skip2 = "*0123456789"; - - escape(fmt = format = *argv); /* backslash interpretation */ - gargv = ++argv; - for (;;) { - end = 0; - /* find next format specification */ -next: for (start = fmt;; ++fmt) { - if (!*fmt) { - /* avoid infinite loop */ - if (end == 1) { - warnx("missing format character", - NULL, NULL); - return (1); - } - end = 1; - if (fmt > start) - (void)printf("%s", start); - if (!*gargv) - return (0); - fmt = format; - goto next; - } - /* %% prints a % */ - if (*fmt == '%') { - if (*++fmt != '%') - break; - *fmt++ = '\0'; - (void)printf("%s", start); - goto next; - } - } - - /* skip to field width */ - for (; strchr(skip1, *fmt); ++fmt); - if (*fmt == '*') { - if (getint(&fieldwidth)) - return (1); - } else - fieldwidth = 0; - - /* skip to possible '.', get following precision */ - for (; strchr(skip2, *fmt); ++fmt); - if (*fmt == '.') - ++fmt; - if (*fmt == '*') { - if (getint(&precision)) - return (1); - } else - precision = 0; - - /* skip to conversion char */ - for (; strchr(skip2, *fmt); ++fmt); - if (!*fmt) { - warnx("missing format character", NULL, NULL); - return (1); - } - - convch = *fmt; - nextch = *++fmt; - *fmt = '\0'; - switch(convch) { - case 'c': { - char p; - - p = getchr(); - PF(start, p); - break; - } - case 's': { - char *p; - - p = getstr(); - PF(start, p); - break; - } - case 'b': { /* expand escapes in argument */ - char *p; - - p = getstr(); - escape(p); - PF("%s", p); - break; - } - case 'q': { /* print with shell single quoting */ - char *p, *p2; - - p = getstr(); - p2 = single_quote(p); - PF("%s", p2); - free(p2); - break; - } - case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { - long p; - char *f; - - if ((f = mklong(start, convch)) == NULL) - return (1); - if (getlong(&p)) - return (1); - PF(f, p); - break; - } - case 'e': case 'E': case 'f': case 'g': case 'G': { - double p; - - p = getdouble(); - PF(start, p); - break; - } - default: - warnx("illegal format character", NULL, NULL); - return (1); - } - *fmt = nextch; - } - /* NOTREACHED */ -} - -static char * -mklong(str, ch) - char *str; - int ch; -{ - static char copy[64]; - int len; - - len = strlen(str) + 2; - memmove(copy, str, len - 3); - copy[len - 3] = 'l'; - copy[len - 2] = ch; - copy[len - 1] = '\0'; - return (copy); -} - -static void -escape(fmt) - register char *fmt; -{ - register char *store; - register int value, c; - - for (store = fmt; c = *fmt; ++fmt, ++store) { - if (c != '\\') { - *store = c; - continue; - } - switch (*++fmt) { - case '\0': /* EOS, user error */ - *store = '\\'; - *++store = '\0'; - return; - case '\\': /* backslash */ - case '\'': /* single quote */ - *store = *fmt; - break; - case 'a': /* bell/alert */ - *store = '\7'; - break; - case 'b': /* backspace */ - *store = '\b'; - break; - case 'c': - return; - case 'e': - case 'E': - *store = '\033'; - break; - case 'f': /* form-feed */ - *store = '\f'; - break; - case 'n': /* newline */ - *store = '\n'; - break; - case 'r': /* carriage-return */ - *store = '\r'; - break; - case 't': /* horizontal tab */ - *store = '\t'; - break; - case 'v': /* vertical tab */ - *store = '\13'; - break; - /* octal constant */ - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - for (c = 3, value = 0; - c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { - value <<= 3; - value += *fmt - '0'; - } - --fmt; - *store = value; - break; - default: - *store = *fmt; - break; - } - } - *store = '\0'; -} - -static int -getchr() -{ - if (!*gargv) - return ('\0'); - return ((int)**gargv++); -} - -static char * -getstr() -{ - if (!*gargv) - return (""); - return (*gargv++); -} - -static char *Number = "+-.0123456789"; -static int -getint(ip) - int *ip; -{ - long val; - - if (getlong(&val)) - return (1); - if (val > INT_MAX) { - warnx("%s: %s", *gargv, strerror(ERANGE)); - return (1); - } - *ip = val; - return (0); -} - -static int -getlong(lp) - long *lp; -{ - long val; - char *ep; - - if (!*gargv) { - *lp = 0; - return (0); - } - if (strchr(Number, **gargv)) { - errno = 0; - val = strtol(*gargv, &ep, 0); - if (*ep != '\0') { - warnx("%s: illegal number", *gargv, NULL); - return (1); - } - if (errno == ERANGE) - if (val == LONG_MAX) { - warnx("%s: %s", *gargv, strerror(ERANGE)); - return (1); - } - if (val == LONG_MIN) { - warnx("%s: %s", *gargv, strerror(ERANGE)); - return (1); - } - - *lp = val; - ++gargv; - return (0); - } - *lp = (long)asciicode(); - return (0); -} - -static double -getdouble() -{ - if (!*gargv) - return ((double)0); - if (strchr(Number, **gargv)) - return (atof(*gargv++)); - return ((double)asciicode()); -} - -static int -asciicode() -{ - register int ch; - - ch = **gargv; - if (ch == '\'' || ch == '"') - ch = (*gargv)[1]; - ++gargv; - return (ch); -} - -static void -usage() -{ - (void)fprintf(stderr, "usage: printf format [arg ...]\n"); -} diff --git a/examples/misc/alias-conv.bash b/examples/misc/aliasconv.bash index cb92ee0a..cb92ee0a 100755 --- a/examples/misc/alias-conv.bash +++ b/examples/misc/aliasconv.bash diff --git a/examples/misc/alias-conv.sh b/examples/misc/aliasconv.sh index 4cbebfb4..4cbebfb4 100755 --- a/examples/misc/alias-conv.sh +++ b/examples/misc/aliasconv.sh diff --git a/examples/scripts.v2/cal2day.bash b/examples/scripts.v2/cal2day.bash new file mode 100644 index 00000000..f26128b6 --- /dev/null +++ b/examples/scripts.v2/cal2day.bash @@ -0,0 +1,49 @@ +#!/bin/bash +# cal2day - "parse" appropriate calendar output to match date number +# with day name. +# +# usage: cal2day month day [year] +# +# ORIGINAL *TAG:33239 3:Dec 9 1997:0755:sh.d/cal2day: +# +# Obtained from usenet +# +# Converted to bash v2 syntax by Chet Ramey <chet@po.cwru.edu> + +#1 PARSE OPTIONS +while getopts :dls _inst +do case $_inst in + (d) format='%1d%.0s\n' ;; # 0, 1, ..., 7 + (l) format='%0.s%-s\n' ;; # Sunday, Monday, ..., Saturday + (s) format='%0.s%-.3s\n' ;; # Sun, Mon, ..., Sat + esac +done +shift $((OPTIND-1)) + +#2 PARAMETER VALUES +((!$#)) && set -- $(date '+%m %d') +: ${format:='%0.s%-.3s\n'} +: ${1:?missing month parameter [1-12]} +: ${2:?missing day parameter [1-31]} + +#3 CALCULATE DAY-OF-WEEK FROM DATE +cal $1 ${3:-$(date +%Y)} | gawk -FX ' +BEGIN { day="Sunday Monday Tuesday WednesdayThursday Friday Saturday" + sub(/^0/, "", daynum) + dayre="(^| )" daynum "( |$)" + } +#NR==2 { print length($0) } +NR==1 || NR==2 \ + { next } +dayre { if (match($0, dayre)) + { #print RSTART, RLENGTH, substr($0, RSTART, RLENGTH) + if (daynum<=9 || RSTART==1) RSTART-=1 + exit + } + } +END { # 20/21 char width assumed + printf format, RSTART/3, substr(day, RSTART*3+1, 9) + } +' daynum=$2 format=$format - + +exit 0 diff --git a/examples/scripts/fixfiles.bash b/examples/scripts/fixfiles.bash new file mode 100644 index 00000000..67311eed --- /dev/null +++ b/examples/scripts/fixfiles.bash @@ -0,0 +1,92 @@ +#! /bin/bash +# +# From: c2a192@ugrad.cs.ubc.ca (Kazimir Kylheku) +# Newsgroups: comp.unix.shell,comp.os.linux.misc +# Subject: GNU Bash Script to fix filenames +# Date: 28 Mar 1996 14:54:43 -0800 +# Organization: Computer Science, University of B.C., Vancouver, B.C., Canada +# +#This is a script which takes a list of directories, descends through each one +#and ``corrects'' filenames that: +# +# - contain filename globbing characters: * ? [ ] +# - quote characters: ' " +# - control characters: 0-31 (127 is not dealt with---oops) +# - - or + as the first character +# +# The GNU version of 'tr' is required. Also requires 'sed'. +# +# Script to process a given list of directories recursively +# and rename each file to something that is reasonable. +# +# The rules are: +# +# 1. replace each space, [, ], *, ", and ' character in the name with a +# period. +# 2. replace each control character 1..31 with a printable character obtained +# by adding 64 to the ascii value. ^A becomes A, ^B becomes B and so on. +# 3. replace a - or + occuring at the beginning of the name with a # +# +# 4. if the resulting name has been changed in any way, then +# 5. if a file of the new name already exists, then +# 6. add a . to the new name and goto step 5. +# 7. rename the old name to the new name +# +# written by Kaz Kylheku <kaz@cafe.net> +# March 1996 +# Vancouver, Canada +# +# requires GNU 'bash', GNU 'tr', and some sort of 'sed' program. +# +# minimal conversion to bash v2 syntax done by Chet Ramey + +processfile() +{ + new_name="`echo -n $1 | tr '\173\175\052\077\042\047 ' '.......' | + tr '[\000-\037]' '[\100-\137]' | + sed -e 's/^-/#/' -e 's/+/#/'`" + if [ "$new_name" != "$1" ] ; then + while [ -e "$new_name" ] ; do + new_name="${new_name}." + done + echo changing \"$1\" to \"$new_name\" in `pwd` + mv -- "$1" "$new_name" + fi +} + +processdir() +{ + set -f + local savepwd="$PWD" + if cd "$1" ; then + set +f + for file in * ; do + set -f + if [ "$file" != "." -a "$file" != ".." ] ; then + if [ -L "$file" ] ; then + echo "skipping symlink" $file in `pwd` + elif [ -d "$file" ] ; then + processdir "$file" + elif [ -f "$file" ] ; then + processfile "$file" + fi + fi + done + cd "$savepwd" + fi +} + +shopt -s nullglob dotglob + +if [ $# = 0 ] ; then + echo "$0: must specify a list of directories" >&2 + echo "$0: usage: $0 directory [directory ...]" >&2 + exit 2 +fi + +while [ $# != 0 ] ; do + processdir "$1" + shift +done + +exit 0 diff --git a/examples/scripts/hanoi.bash b/examples/scripts/hanoi.bash new file mode 100644 index 00000000..c3081257 --- /dev/null +++ b/examples/scripts/hanoi.bash @@ -0,0 +1,21 @@ +# Towers of Hanoi in bash +# +# cribbed from the ksh93 book, example from exercises on page 85 +# +# Chet Ramey +# chet@po.cwru.edu + +hanoi() # n from to spare +{ + typeset -i nm1=$1-1 + ((nm1>0)) && hanoi $nm1 $2 $4 $3 + echo "Move disc $2 to $3" + ((nm1>0)) && hanoi $nm1 $4 $3 $2 +} + +case $1 in +[1-9]) + hanoi $1 1 2 3;; +*) echo "${0##*/}: Argument must be from 1 to 9" + exit 1;; +esac diff --git a/examples/scripts/krand.bash b/examples/scripts/krand.bash new file mode 100755 index 00000000..dfdfd323 --- /dev/null +++ b/examples/scripts/krand.bash @@ -0,0 +1,74 @@ +# Originally +# +# From: bsh20858@news.fhda.edu (Brian S Hiles) +# Newsgroups: comp.unix.shell +# Subject: Re: getting random numbers +# Date: 23 Jan 1997 23:27:30 GMT +# Message-ID: <5c8s52$eif@tiptoe.fhda.edu> + +# @(#) krand Produces a random number within integer limits +# "krand" Korn shell script generates a random number in a +# specified range with an optionally specified ``seed'' value. +# Author: Peter Turnbull, May 1993 +# Modified by: Becca Thomas, January 1994 + +# changed the optional third argument to a -s option, converted to +# bash v2 syntax -- chet@po.cwru.edu + +PROGNAME=${0##*/} +USAGE="usage: $PROGNAME [-s seed] lower-limit upper-limit" + +Seed=$$ # Initialize random-number seed value with PID + +usage() +{ + echo ${PROGNAME}: "$USAGE" >&2 +} + +errexit() +{ + echo ${PROGNAME}: "$@" >&2 + exit 1 +} + +# Process command-line arguments: +while getopts "s:" opt; do + case "$opt" in + s) Seed=$OPTARG ;; + *) usage ; exit 2;; + esac +done + +shift $(($OPTIND - 1)) + +case $# in + 2) Lower=$1; Upper=$2 ;; + *) usage ; exit 2;; +esac + +# Check that specified values are integers: +expr "$Lower" + 0 >/dev/null 2>&1 +[ $? -eq 2 ] && { errexit "lower ($Lower) not an integer"; } +expr "$Upper" + 0 >/dev/null 2>&1 +[ $? -eq 2 ] && { errexit "upper ($Upper) not an integer"; } +expr "$Seed" + 0 >/dev/null 2>&1 +[ $? -eq 2 ] && { errexit "seed ($Seed) not an integer"; } + +# Check that values are in the correct range: +if (( "$Lower" < 0 )) || [ ${#Lower} -gt 5 ]; then + errexit "lower limit ($Lower) less than zero" +fi +if (( "$Upper" > 32767 )) || [ ${#Upper} -gt 5 ]; then + errexit "upper limit ($Upper) greater than 32767" +fi +if (( "$Seed" < 0 )) || (( "$Seed" > 32767 )) || [ ${#Seed} -gt 5 ]; then + errexit "seed value ($Seed) out of range (0 to 32767)" +fi +(( "$Upper" <= "$Lower" )) && errexit "upper limit ($Upper) <= lower limit ($Lower)" + +# Seed the random-number generator: +RANDOM=$Seed +# Compute value, scaled within range: +let rand="$RANDOM % ($Upper - $Lower + 1) + $Lower" +# Report result: +echo $rand diff --git a/examples/scripts/randomcard.bash b/examples/scripts/randomcard.bash new file mode 100644 index 00000000..9cb6b50c --- /dev/null +++ b/examples/scripts/randomcard.bash @@ -0,0 +1,18 @@ +# The following prints a random card from a card deck. +# +# cribbed from the ksh93 book, example from page 70 +# +# chet@po.cwru.edu +# +declare -i i=0 + +# load the deck +for suit in clubs diamonds hearts spades; do + for n in ace 2 3 4 5 6 7 8 9 10 jack queen king; do + card[i]="$n of $suit" + i=i+1 # let is not required with integer variables + done +done + +# and print a random card +echo ${card[RANDOM%52]} diff --git a/examples/scripts/scrollbar b/examples/scripts/scrollbar index c177179e..388bea8e 100755 --- a/examples/scripts/scrollbar +++ b/examples/scripts/scrollbar @@ -9,17 +9,17 @@ # converted from ksh syntax to bash v2 syntax by Chet Ramey WIDTH=${COLUMNS:-80} +WMINUS=$(( $WIDTH - 1 )) [ $# -lt 1 ] && set -- TESTING -# Posix.2 compatible printf command or bash loadable builtin -# in examples/loadables/printf +# use the bash-2.02 printf builtin Text=$(printf "%-${WIDTH}s" "$*") -Text=$(echo "$Text" | tr ' ' '_') +Text=${Text// /_} while : do printf "%-.${WIDTH}s\r" "$Text" - LastC=$(expr "$Text" : '.*\(.\)$') - Text=$(printf "%-.${WIDTH}s" "$LastC$Text") + LastC=${Text:${WMINUS}:1} + Text="$LastC""${Text%?}" done diff --git a/examples/scripts/scrollbar2 b/examples/scripts/scrollbar2 new file mode 100755 index 00000000..0e536341 --- /dev/null +++ b/examples/scripts/scrollbar2 @@ -0,0 +1,24 @@ +#!/bin/bash +# +# scrollbar - display scrolling text +# +# usage: scrollbar args +# +# A cute hack originally from Heiner Steven <hs@bintec.de> +# +# converted from ksh syntax to bash v2 syntax by Chet Ramey + +WIDTH=${COLUMNS:-80} +WMINUS=$(( $WIDTH - 1 )) + +[ $# -lt 1 ] && set -- TESTING + +# use the bash-2.02 printf builtin +Text=$(printf "%-${WIDTH}s" "$*") + +while : +do + printf "%-.${WIDTH}s\r" "$Text" + LastC=${Text:${WMINUS}:1} + Text="$LastC""${Text%?}" +done diff --git a/examples/scripts/showperm.bash b/examples/scripts/showperm.bash new file mode 100644 index 00000000..2e06c0bc --- /dev/null +++ b/examples/scripts/showperm.bash @@ -0,0 +1,53 @@ +#Newsgroups: comp.unix.shell +#From: gwc@root.co.uk (Geoff Clare) +#Subject: Re: Determining permissions on a file +#Message-ID: <Dr79nw.DtL@root.co.uk> +#Date: Fri, 10 May 1996 17:23:56 GMT + +#Here's a bit of Korn shell that converts the symbolic permissions produced +#by "ls -l" into octal, using only shell builtins. How to create a script +#combining this with an "ls -l" is left as an exercise... +# +# +# Converted to Bash v2 syntax by Chet Ramey <chet@po.cwru.edu> +# +# usage: showperm modestring +# +# example: showperm '-rwsr-x--x' +# + +[ -z "$1" ] && { + echo "showperm: usage: showperm modestring" >&2 + exit 2 +} + +tmode="$1" + +typeset -i omode sbits +typeset pmode + +# check for set-uid, etc. bits +sbits=0 +case $tmode in +???[sS]*) (( sbits += 8#4000 )) ;; # set-uid +??????[sSl]*) (( sbits += 8#2000 )) ;; # set-gid or mand. lock +?????????[tT]*) (( sbits += 8#1000 )) ;; # sticky +esac + +omode=0 +while : +do + tmode=${tmode#?} + case $tmode in + "") break ;; + [-STl]*) (( omode *= 2 )) ;; + [rwxst]*) (( omode = omode*2 + 1 )) ;; + *) echo "$0: first letter of \"$tmode\" is unrecognized" >&2 + (( omode *= 2 )) + ;; + esac +done + +(( omode += sbits )) + +printf "0%o\n" $omode diff --git a/examples/scripts/timeout b/examples/scripts/timeout new file mode 100644 index 00000000..ac8d88f4 --- /dev/null +++ b/examples/scripts/timeout @@ -0,0 +1,53 @@ +#Newsgroups: comp.unix.admin,comp.unix.solaris,comp.unix.shell +#From: gwc@root.co.uk (Geoff Clare) +#Subject: Re: timeout -t <sec> <unix command> (Re: How to give rsh a shorter timeout?) +#Message-ID: <EoBxrs.223@root.co.uk> +#Date: Fri, 13 Feb 1998 18:23:52 GMT + +# +# Conversion to bash v2 syntax done by Chet Ramey <chet@po.cwru.edu +# UNTESTED +# + +prog=${0##*/} +usage="usage: $prog [-signal] [timeout] [:interval] [+delay] [--] <command>" + +SIG=-TERM # default signal sent to the process when the timer expires +timeout=60 # default timeout +interval=15 # default interval between checks if the process is still alive +delay=2 # default delay between posting the given signal and + # destroying the process (kill -KILL) + +while : +do + case $1 in + --) shift; break ;; + -*) SIG=$1 ;; + [0-9]*) timeout=$1 ;; + :*) EXPR='..\(.*\)' ; interval=`expr x"$1" : "$EXPR"` ;; + +*) EXPR='..\(.*\)' ; delay=`expr x"$1" : "$EXPR"` ;; + *) break ;; + esac + shift +done + +case $# in +0) echo "$prog: $usage" >&2 ; exit 2 ;; +esac + +( + for t in $timeout $delay + do + while (( $t > $interval )) + do + sleep $interval + kill -0 $$ || exit + t=$(( $t - $interval )) + done + sleep $t + kill $SIG $$ && kill -0 $$ || exit + SIG=-KILL + done +) 2> /dev/null & + +exec "$@" diff --git a/examples/startup-files/Bashrc b/examples/startup-files/Bashrc.bfox index efe7d88b..efe7d88b 100644 --- a/examples/startup-files/Bashrc +++ b/examples/startup-files/Bashrc.bfox diff --git a/execute_cmd.c b/execute_cmd.c index 5a9f10fd..e3da9bfb 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -26,11 +26,15 @@ #include <stdio.h> #include <ctype.h> #include "bashtypes.h" -#include <sys/file.h> +#ifndef _MINIX +# include <sys/file.h> +#endif #include "filecntl.h" #include "posixstat.h" #include <signal.h> -#include <sys/param.h> +#ifndef _MINIX +# include <sys/param.h> +#endif #if defined (HAVE_UNISTD_H) # include <unistd.h> @@ -54,7 +58,7 @@ # endif #endif -#if defined (HAVE_SYS_RESOURCE_H) +#if defined (HAVE_SYS_RESOURCE_H) && !defined (RLIMTYPE) # include <sys/resource.h> #endif @@ -78,10 +82,16 @@ extern int errno; #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 */ @@ -121,17 +131,17 @@ extern int close (); /* Static functions defined and used in this file. */ static void close_pipes (), do_piping (), bind_lastarg (); static void cleanup_redirects (); -static void add_undo_close_redirect (), add_exec_redirect (); -static int add_undo_redirect (); -static int do_redirection_internal (), do_redirections (); -static int expandable_redirection_filename (); -static char *find_user_command_internal (), *find_user_command_in_path (); -static char *find_in_path_element (), *find_absolute_program (); static int execute_for_command (); #if defined (SELECT_COMMAND) static int execute_select_command (); #endif +#if defined (DPAREN_ARITHMETIC) +static int execute_arith_command (); +#endif +#if defined (COND_COMMAND) +static int execute_cond_command (); +#endif #if defined (COMMAND_TIMING) static int time_command (); #endif @@ -165,21 +175,6 @@ struct stat SB; /* used for debugging */ static int special_builtin_failed; -/* 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; - -/* The file name which we would try to execute, except that it isn't - possible to execute it. This is the first file that matches the - name that we are looking for while we are searching $PATH for a - suitable one to execute. If we cannot find a suitable executable - file, then we use this one. */ -static char *file_to_lose_on; - /* For catching RETURN in a function. */ int return_catch_flag; int return_catch_value; @@ -201,10 +196,6 @@ REDIRECT *exec_redirection_undo_list = (REDIRECT *)NULL; environment. */ int subshell_environment; -/* Non-zero if we should stat every command found in the hash table to - make sure it still exists. */ -int check_hashed_filenames; - struct fd_bitmap *current_fds_to_close = (struct fd_bitmap *)NULL; #define FD_BITMAP_DEFAULT_SIZE 32L @@ -313,6 +304,12 @@ shell_control_structure (type) #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: @@ -345,7 +342,7 @@ cleanup_func_redirects (list) } #endif -static void +void dispose_exec_redirects () { if (exec_redirection_undo_list) @@ -384,41 +381,6 @@ open_files () fprintf (stderr, "\n"); } -static int -stdin_redirects (redirs) - REDIRECT *redirs; -{ - REDIRECT *rp; - int n; - - for (n = 0, rp = redirs; rp; rp = rp->next) - switch (rp->instruction) - { - case r_input_direction: - case r_inputa_direction: - case r_input_output: - case r_reading_until: - case r_deblank_reading_until: - n++; - break; - case r_duplicating_input: - case r_duplicating_input_word: - case r_close_this: - n += (rp->redirector == 0); - break; - case r_output_direction: - case r_appending_to: - case r_duplicating_output: - case r_err_and_out: - case r_output_force: - case r_duplicating_output_word: - break; - } - - return n; -} - - static void async_redirect_stdin () { @@ -458,7 +420,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, { int exec_result, invert, ignore_return, was_debug_trap; REDIRECT *my_undo_list, *exec_undo_list; - pid_t last_pid; + volatile pid_t last_pid; if (command == 0 || breaking || continuing || read_but_dont_execute) return (EXECUTION_SUCCESS); @@ -782,7 +744,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, run_debug_trap (); if (ignore_return == 0 && invert == 0 && - ((posixly_correct && interactive == 0 && special_builtin_failed) || + ((posixly_correct && interactive == 0 && special_builtin_failed) || (exit_immediately_on_error && (exec_result != EXECUTION_SUCCESS)))) { last_command_exit_value = exec_result; @@ -879,6 +841,22 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, 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; + exec_result = execute_cond_command (command->value.Cond); + break; +#endif + case cm_function_def: exec_result = execute_intern_function (command->value.Function_def->name, command->value.Function_def->command); @@ -977,7 +955,7 @@ timeval_to_cpu (rt, ut, st) if (t1.tv_sec < 100000000) t1.tv_sec *= 10; else - t2.tv_sec /= 10; + t2.tv_sec /= 10; } return ((t2.tv_sec == 0) ? 0 : t1.tv_sec / t2.tv_sec); @@ -1015,7 +993,7 @@ mkfmt (buf, prec, lng, sec, sec_fraction) while (min /= 10); aind++; while (abuf[aind]) - buf[ind++] = abuf[aind++]; + buf[ind++] = abuf[aind++]; buf[ind++] = 'm'; } @@ -1086,16 +1064,16 @@ print_formatted_time (fp, format, rs, rsf, us, usf, ss, ssf, cpu) for (s = format; *s; s++) { if (*s != '%' || s[1] == '\0') - { - RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); - str[sindex++] = *s; - } + { + 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; - } + { + s++; + RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); + str[sindex++] = *s; + } else if (s[1] == 'P') { s++; @@ -1189,6 +1167,9 @@ time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close) rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close); command->flags = old_flags; + rs = us = ss = 0L; + rsf = usf = ssf = cpu = 0; + #if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) gettimeofday (&after, &dtz); getrusage (RUSAGE_SELF, &selfa); @@ -1304,7 +1285,7 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) 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 + 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"); @@ -1535,10 +1516,10 @@ execute_for_command (for_command) if (check_identifier (for_command->name, 1) == 0) { if (posixly_correct && interactive_shell == 0) - { - last_command_exit_value = EX_USAGE; - jump_to_top_level (EXITPROG); - } + { + last_command_exit_value = EX_USAGE; + jump_to_top_level (EXITPROG); + } return (EXECUTION_FAILURE); } @@ -1755,7 +1736,7 @@ select_query (list, list_len, prompt) { len = STRLEN (l->word->word); if (len > max_elem_len) - max_elem_len = len; + max_elem_len = len; } indices_len = NUMBER_LEN (list_len); max_elem_len += indices_len + RP_SPACE_LEN + 2; @@ -1776,7 +1757,7 @@ select_query (list, list_len, prompt) if (*repl_string == 0) continue; if (legal_number (repl_string, &reply) == 0) - continue; + return ""; if (reply < 1 || reply > list_len) return ""; @@ -1858,12 +1839,12 @@ execute_select_command (select_command) return_val = setjmp (return_catch); if (return_val) - { + { retval = return_catch_value; break; - } + } else - retval = execute_command (select_command->action); + retval = execute_command (select_command->action); REAP (); QUIT; @@ -1933,7 +1914,7 @@ execute_case_command (case_command) es = expand_word_leave_quoted (list->word, 0); if (es && es->word && es->word->word && *(es->word->word)) - pattern = quote_string_for_globbing (es->word->word, 1); + pattern = quote_string_for_globbing (es->word->word, QGLOB_CVTNULL); else { pattern = xmalloc (1); @@ -1943,7 +1924,7 @@ execute_case_command (case_command) /* Since the pattern does not undergo quote removal (as per Posix.2, section 3.9.4.3), the fnmatch () call must be able to recognize backslashes as escape characters. */ - match = fnmatch (pattern, word, 0) != FNM_NOMATCH; + match = fnmatch (pattern, word, FNMATCH_EXTFLAG) != FNM_NOMATCH; free (pattern); dispose_words (es); @@ -2070,6 +2051,134 @@ execute_if_command (if_command) } } +#if defined (DPAREN_ARITHMETIC) +static int +execute_arith_command (arith_command) + ARITH_COM *arith_command; +{ + int result, expok, expresult; + WORD_LIST *new, *p, *printit; + WORD_DESC *w; + + result = 0; + + this_command_name = "(("; + /* If we're in a function, update the line number information. */ + if (variable_context) + line_number = arith_command->line - function_line_number; + + new = expand_words (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); + + result = evalexp (new->word->word, &expok); + dispose_words (new); + + if (expok == 0) + return (EXECUTION_FAILURE); + + return (result == 0 ? EXECUTION_FAILURE : EXECUTION_SUCCESS); +} +#endif /* DPAREN_ARITHMETIC */ + +#if defined (COND_COMMAND) + +static char *nullstr = ""; + +static int +execute_cond_node (cond) + COND_COM *cond; +{ + int result, invert, patmatch; + char *arg1, *arg2, *print2; + + invert = (cond->flags & CMD_INVERT_RETURN); + + if (cond->type == COND_EXPR) + result = execute_cond_node (cond->left); + else if (cond->type == COND_OR) + { + result = execute_cond_node (cond->left); + if (result != EXECUTION_SUCCESS) + result = execute_cond_node (cond->right); + } + else if (cond->type == COND_AND) + { + result = execute_cond_node (cond->left); + if (result == EXECUTION_SUCCESS) + result = execute_cond_node (cond->right); + } + else if (cond->type == COND_UNARY) + { + arg1 = cond_expand_word (cond->left->op, 0); + if (arg1 == 0) + arg1 = nullstr; + if (echo_command_at_execute) + xtrace_print_cond_term (cond->type, invert, cond->op, arg1, (char *)NULL); + result = unary_test (cond->op->word, arg1) ? EXECUTION_SUCCESS : EXECUTION_FAILURE; + if (arg1 != nullstr) + free (arg1); + } + else if (cond->type == COND_BINARY) + { + patmatch = (cond->op->word[1] == '=') && (cond->op->word[2] == '\0') && + (cond->op->word[0] == '!' || cond->op->word[0] == '='); + + arg1 = cond_expand_word (cond->left->op, 0); + if (arg1 == 0) + arg1 = nullstr; + arg2 = cond_expand_word (cond->right->op, patmatch); + if (arg2 == 0) + arg2 = nullstr; + + if (echo_command_at_execute) + xtrace_print_cond_term (cond->type, invert, cond->op, arg1, arg2); + + result = binary_test (cond->op->word, arg1, arg2, TEST_PATMATCH|TEST_ARITHEXP) + ? EXECUTION_SUCCESS + : EXECUTION_FAILURE; + if (arg1 != nullstr) + free (arg1); + if (arg2 != nullstr) + free (arg2); + } + else + { + programming_error ("execute_cond_node: %d: unknown conditional command type", cond->type); + 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 result; + + result = EXECUTION_SUCCESS; + + this_command_name = "[["; + /* If we're in a function, update the line number information. */ + if (variable_context) + line_number = cond_command->line - function_line_number; + +#if 0 + debug_print_cond_command (cond_command); +#endif + last_command_exit_value = result = execute_cond_node (cond_command); + return (result); +} +#endif /* COND_COMMAND */ + static void bind_lastarg (arg) char *arg; @@ -2167,13 +2276,14 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) { WORD_LIST *words, *lastword; char *command_line, *lastarg, *temp; - int first_word_quoted, result, builtin_is_special; + int first_word_quoted, result, builtin_is_special, already_forked; pid_t old_last_command_subst_pid; Function *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) @@ -2182,14 +2292,40 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) /* Remember what this command line looks like at invocation. */ command_string_index = 0; print_simple_command (simple_command); - command_line = xmalloc (1 + strlen (the_printed_command)); - strcpy (command_line, the_printed_command); /* XXX memory leak on errors */ first_word_quoted = simple_command->words ? (simple_command->words->word->flags & W_QUOTED): 0; old_last_command_subst_pid = last_command_subst_pid; + already_forked = 0; + if (pipe_in != NO_PIPE || pipe_out != NO_PIPE || async) + { + /* XXX memory leak if expand_words() error causes a jump_to_top_level */ + command_line = savestring (the_printed_command); + + if (make_child (command_line, async) == 0) + { + already_forked = 1; + simple_command->flags |= CMD_NO_FORK; + + do_piping (pipe_in, pipe_out); + pipe_in = pipe_out = -1; + + subshell_environment = SUBSHELL_ASYNC; + } + 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) @@ -2208,11 +2344,17 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) if (words == 0) { result = execute_null_command (simple_command->redirects, - pipe_in, pipe_out, async, + pipe_in, pipe_out, + already_forked ? 0 : async, old_last_command_subst_pid); - FREE (command_line); - bind_lastarg ((char *)NULL); - return (result); + if (already_forked) + exit (result); + else + { + bind_lastarg ((char *)NULL); + set_pipestatus_from_exit (result); + return (result); + } } lastarg = (char *)NULL; @@ -2252,7 +2394,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) #if defined (JOB_CONTROL) /* Is this command a job control related thing? */ - if (words->word->word[0] == '%') + if (words->word->word[0] == '%' && already_forked == 0) { this_command_name = async ? "bg" : "fg"; last_shell_builtin = this_shell_builtin; @@ -2264,7 +2406,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) /* One other possiblilty. The user may want to resume an existing job. If they do, find out whether this word is a candidate for a running job. */ - if (job_control && async == 0 && + if (job_control && already_forked == 0 && async == 0 && !first_word_quoted && !words->next && words->word->word[0] && @@ -2337,37 +2479,25 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) if (builtin || func) { - if ((pipe_in != NO_PIPE) || (pipe_out != NO_PIPE) || async) + if (already_forked) { - if (make_child (command_line, async) == 0) - { - /* 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 (); - } + /* reset_terminating_signals (); */ /* XXX */ + /* Cancel traps, in trap.c. */ + restore_original_signals (); - execute_subshell_builtin_or_function - (words, simple_command->redirects, builtin, func, - pipe_in, pipe_out, async, fds_to_close, - simple_command->flags); - } - else + if (async) { - close_pipes (pipe_in, pipe_out); -#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) - unlink_fifo_list (); -#endif - command_line = (char *)NULL; /* don't free this. */ - goto return_result; + if ((simple_command->flags & CMD_STDIN_REDIR) && + pipe_in == NO_PIPE && + (stdin_redirects (simple_command->redirects) == 0)) + async_redirect_stdin (); + setup_async_signals (); } + + execute_subshell_builtin_or_function + (words, simple_command->redirects, builtin, func, + pipe_in, pipe_out, async, fds_to_close, + simple_command->flags); } else { @@ -2378,9 +2508,9 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) { if (result > EX_SHERRBASE) { - result = builtin_status (result); - if (builtin_is_special) - special_builtin_failed = 1; + 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 @@ -2393,13 +2523,18 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) if (result == EX_USAGE) result = EX_BADUSAGE; else if (result > EX_SHERRBASE) - result = EXECUTION_FAILURE; + result = EXECUTION_FAILURE; } + set_pipestatus_from_exit (result); + goto return_result; } } + if (command_line == 0) + command_line = savestring (the_printed_command); + execute_disk_command (words, simple_command->redirects, command_line, pipe_in, pipe_out, async, fds_to_close, simple_command->flags); @@ -2492,8 +2627,12 @@ execute_builtin (builtin, words, flags, subshell) and `eval' are special builtins. */ if (posixly_correct && builtin_env) merge_builtin_env (); +#if 0 dispose_builtin_env (); discard_unwind_frame ("builtin_env"); +#else + run_unwind_frame ("builtin_env"); +#endif } if (eval_unwind) @@ -2540,8 +2679,12 @@ execute_function (var, words, flags, fds_to_close, async, subshell) if (subshell == 0) { debug_trap = savestring (debug_trap); + /* XXX order is important here! unwind-protect commands are run + in reverse order of registering. If this causes problems, + take out the xfree unwind-protect and live with the small + memory leak. */ + add_unwind_protect (xfree, debug_trap); add_unwind_protect (set_debug_trap, debug_trap); - /* XXX - small memory leak here -- hard to fix */ } restore_default_signal (DEBUG_TRAP); } @@ -2657,12 +2800,12 @@ execute_subshell_builtin_or_function (words, redirects, builtin, var, else if (result) exit (EXECUTION_FAILURE); else - { - r = execute_builtin (builtin, words, flags, 1); - if (r == EX_USAGE) - r = EX_BADUSAGE; - exit (r); - } + { + r = execute_builtin (builtin, words, flags, 1); + if (r == EX_USAGE) + r = EX_BADUSAGE; + exit (r); + } } else exit (execute_function (var, words, flags, fds_to_close, async, 1)); @@ -2827,8 +2970,8 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out, 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. */ + by make_child to ensure that SIGINT and SIGQUIT are ignored + in asynchronous children. */ if (async) { if ((cmdflags & CMD_STDIN_REDIR) && @@ -3000,19 +3143,8 @@ initialize_subshell () /* If we're not interactive, close the file descriptor from which we're reading the current shell script. */ -#if defined (BUFFERED_INPUT) - if (interactive_shell == 0 && default_buffered_input >= 0) - { - close_buffered_fd (default_buffered_input); - default_buffered_input = bash_input.location.buffered_fd = -1; - } -#else - if (interactive_shell == 0 && default_input) - { - fclose (default_input); - default_input = (FILE *)NULL; - } -#endif + if (interactive_shell == 0) + unset_bash_input (1); } #if defined (HAVE_SETOSTYPE) && defined (_POSIX_SOURCE) @@ -3197,7 +3329,10 @@ do_piping (pipe_in, pipe_out) if (dup2 (pipe_in, 0) < 0) sys_error ("cannot duplicate fd %d to fd 0", pipe_in); if (pipe_in > 0) - close (pipe_in); + close (pipe_in); +#ifdef __CYGWIN32__ + setmode (0, O_TEXT); +#endif } if (pipe_out != NO_PIPE) { @@ -3207,1226 +3342,18 @@ do_piping (pipe_in, pipe_out) sys_error ("cannot duplicate fd %d to fd 1", pipe_out); if (pipe_out == 0 || pipe_out > 1) close (pipe_out); - } - else - if (dup2 (1, 2) < 0) - sys_error ("cannot duplicate fd 1 to fd 2"); - } -} - -static void -redirection_error (temp, error) - REDIRECT *temp; - int error; -{ - char *filename; - - if (expandable_redirection_filename (temp)) - { - if (posixly_correct && !interactive_shell) - disallow_filename_globbing++; - filename = redirection_expand (temp->redirectee.filename); - if (posixly_correct && !interactive_shell) - disallow_filename_globbing--; - if (filename == 0) - filename = savestring (temp->redirectee.filename->word); - if (filename == 0) - { - filename = xmalloc (1); - filename[0] = '\0'; - } - } - else - filename = itos (temp->redirectee.dest); - - switch (error) - { - case AMBIGUOUS_REDIRECT: - internal_error ("%s: ambiguous redirect", filename); - break; - - case NOCLOBBER_REDIRECT: - internal_error ("%s: cannot overwrite existing file", filename); - break; - -#if defined (RESTRICTED_SHELL) - case RESTRICTED_REDIRECT: - internal_error ("%s: restricted: cannot redirect output", filename); - break; -#endif /* RESTRICTED_SHELL */ - - 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 (filename); -} - -/* Perform the redirections on LIST. If FOR_REAL, then actually make - input and output file descriptors, otherwise just do whatever is - neccessary for side effecting. INTERNAL says to remember how to - undo the redirections later, if non-zero. If SET_CLEXEC is non-zero, - file descriptors opened in do_redirection () have their close-on-exec - flag set. */ -static int -do_redirections (list, for_real, internal, set_clexec) - REDIRECT *list; - int for_real, internal, set_clexec; -{ - int error; - REDIRECT *temp; - - if (internal) - { - 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, for_real, internal, set_clexec); - 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_input_output: - case r_output_force: - case r_duplicating_input_word: - case r_duplicating_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; - - tlist1 = make_word_list (copy_word (word), (WORD_LIST *)NULL); - tlist2 = expand_words_no_vars (tlist1); - dispose_words (tlist1); - - if (!tlist2 || tlist2->next) - { - /* We expanded to no words, or to more than a single word. - Dispose of the word list and return NULL. */ - if (tlist2) - dispose_words (tlist2); - return ((char *)NULL); - } - result = string_list (tlist2); /* XXX savestring (tlist2->word->word)? */ - dispose_words (tlist2); - return (result); -} - -/* 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); - } - } - fclose (fp); - dispose_words (tlist); - } - 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) - WORD_DESC *redirectee; -{ - char filename[24]; - int r, fd; - - /* Make the filename for the temp file. */ - sprintf (filename, "/tmp/t%d-sh", (int)time ((time_t *) 0) + (int)getpid ()); - - /* Make sure we open it exclusively. */ - fd = open (filename, O_TRUNC | O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd < 0) - return (fd); - - errno = r = 0; /* XXX */ - /* write_here_document returns 0 on success, errno on failure. */ - if (redirectee->word) - r = write_here_document (fd, redirectee); - - close (fd); - if (r) - { - unlink (filename); - errno = r; - return (-1); - } - - /* XXX - this is raceable */ - /* Make the document really temporary. Also make it the input. */ - fd = open (filename, O_RDONLY, 0600); - - if (fd < 0) - { - r = errno; - unlink (filename); - errno = r; - return -1; - } - - if (unlink (filename) < 0) - { - r = errno; - close (fd); - errno = r; - return (-1); - } - - 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, ri) - char *filename; - int flags; - 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, 0666); - return ((fd < 0 && errno == EEXIST) ? NOCLOBBER_REDIRECT : fd); - } - fd = open (filename, flags, 0666); - - /* 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); -} - -/* Do the specific redirection requested. Returns errno or one of the - special redirection errors (*_REDIRECT) in case of error, 0 on success. - If FOR_REAL is zero, then just do whatever is neccessary to produce the - appropriate side effects. REMEMBERING, if non-zero, says to remember - how to undo each redirection. If SET_CLEXEC is non-zero, then - we set all file descriptors > 2 that we open to be close-on-exec. */ -static int -do_redirection_internal (redirect, for_real, remembering, set_clexec) - REDIRECT *redirect; - int for_real, remembering, set_clexec; -{ - WORD_DESC *redirectee; - int redir_fd, fd, redirector, r; - 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 (ri == r_duplicating_input_word || ri == r_duplicating_output_word) - { - /* We have [N]>&WORD or [N]<&WORD. Expand WORD, then translate - the redirection into a new one and continue. */ - redirectee_word = redirection_expand (redirectee); - - if (redirectee_word == 0) - return (AMBIGUOUS_REDIRECT); - else if (redirectee_word[0] == '-' && redirectee_word[1] == '\0') - { - rd.dest = 0L; - new_redirect = make_redirection (redirector, r_close_this, rd); - } - else if (all_digits (redirectee_word)) - { - if (ri == r_duplicating_input_word) - { - rd.dest = atol (redirectee_word); - new_redirect = make_redirection (redirector, r_duplicating_input, rd); - } - else - { - rd.dest = atol (redirectee_word); - new_redirect = make_redirection (redirector, r_duplicating_output, rd); - } - } - else if (ri == r_duplicating_output_word && redirector == 1) - { - if (posixly_correct == 0) - { - rd.filename = make_bare_word (redirectee_word); - new_redirect = make_redirection (1, r_err_and_out, rd); - } - else - new_redirect = copy_redirect (redirect); - } - else - { - free (redirectee_word); - return (AMBIGUOUS_REDIRECT); - } - - free (redirectee_word); - - /* Set up the variables needed by the rest of the function from the - new redirection. */ - if (new_redirect->instruction == r_err_and_out) - { - char *alloca_hack; - - /* Copy the word without allocating any memory that must be - explicitly freed. */ - redirectee = (WORD_DESC *)alloca (sizeof (WORD_DESC)); - xbcopy ((char *)new_redirect->redirectee.filename, - (char *)redirectee, sizeof (WORD_DESC)); - - alloca_hack = (char *) - alloca (1 + strlen (new_redirect->redirectee.filename->word)); - redirectee->word = alloca_hack; - strcpy (redirectee->word, new_redirect->redirectee.filename->word); - } - else - /* It's guaranteed to be an integer, and shouldn't be freed. */ - redirectee = new_redirect->redirectee.filename; - - redir_fd = new_redirect->redirectee.dest; - redirector = new_redirect->redirector; - ri = new_redirect->instruction; - - /* Overwrite the flags element of the old redirect with the new value. */ - redirect->flags = new_redirect->flags; - dispose_redirects (new_redirect); - } - - switch (ri) - { - case r_output_direction: - case r_appending_to: - case r_input_direction: - case r_inputa_direction: - case r_err_and_out: /* command &>filename */ - case r_input_output: - case r_output_force: - if (posixly_correct && !interactive_shell) - disallow_filename_globbing++; - redirectee_word = redirection_expand (redirectee); - if (posixly_correct && !interactive_shell) - disallow_filename_globbing--; - - if (redirectee_word == 0) - return (AMBIGUOUS_REDIRECT); - -#if defined (RESTRICTED_SHELL) - if (restricted && (WRITE_REDIRECT (ri))) - { - free (redirectee_word); - return (RESTRICTED_REDIRECT); - } -#endif /* RESTRICTED_SHELL */ - - /* If we are in noclobber mode, you are not allowed to overwrite - existing files. Check before opening. */ - if (noclobber && OUTPUT_REDIRECT (ri)) - { - fd = noclobber_open (redirectee_word, redirect->flags, ri); - if (fd == NOCLOBBER_REDIRECT) - { - free (redirectee_word); - return (NOCLOBBER_REDIRECT); - } - } - else - { - fd = open (redirectee_word, redirect->flags, 0666); -#if defined (AFS) - if ((fd < 0) && (errno == EACCES)) - fd = open (redirectee_word, redirect->flags & ~O_CREAT, 0666); -#endif /* AFS */ - } - free (redirectee_word); - - if (fd < 0) - return (errno); - - if (for_real) - { - if (remembering) - /* Only setup to undo it if the thing to undo is active. */ - if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1)) - add_undo_redirect (redirector); - else - add_undo_close_redirect (redirector); - -#if defined (BUFFERED_INPUT) - check_bash_input (redirector); -#endif - - if ((fd != redirector) && (dup2 (fd, redirector) < 0)) - return (errno); - -#if defined (BUFFERED_INPUT) - /* Do not change the buffered stream for an implicit redirection - of /dev/null to fd 0 for asynchronous commands without job - control (r_inputa_direction). */ - if (ri == r_input_direction || ri == r_input_output) - duplicate_buffered_stream (fd, redirector); -#endif /* BUFFERED_INPUT */ - - /* - * If we're remembering, then this is the result of a while, for - * or until loop with a loop redirection, or a function/builtin - * executing in the parent shell with a redirection. In the - * function/builtin case, we want to set all file descriptors > 2 - * to be close-on-exec to duplicate the effect of the old - * for i = 3 to NOFILE close(i) loop. In the case of the loops, - * both sh and ksh leave the file descriptors open across execs. - * The Posix standard mentions only the exec builtin. - */ - if (set_clexec && (redirector > 2)) - SET_CLOSE_ON_EXEC (redirector); - } - - if (fd != redirector) - { -#if defined (BUFFERED_INPUT) - if (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) - { - if (for_real) - { - if (remembering) - add_undo_redirect (2); - if (dup2 (1, 2) < 0) - return (errno); - } - } - break; - - case r_reading_until: - case r_deblank_reading_until: - /* REDIRECTEE is a pointer to a WORD_DESC containing the text of - the new input. Place it in a temporary file. */ - if (redirectee) - { - fd = here_document_to_fd (redirectee); - - if (fd < 0) - { - heredoc_errno = errno; - return (HEREDOC_REDIRECT); - } - - if (for_real) - { - if (remembering) - /* Only setup to undo it if the thing to undo is active. */ - if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1)) - add_undo_redirect (redirector); - else - add_undo_close_redirect (redirector); - -#if defined (BUFFERED_INPUT) - check_bash_input (redirector); -#endif - if (fd != redirector && dup2 (fd, redirector) < 0) - { - r = errno; - close (fd); - return (r); - } - -#if defined (BUFFERED_INPUT) - duplicate_buffered_stream (fd, redirector); -#endif - - if (set_clexec && (redirector > 2)) - SET_CLOSE_ON_EXEC (redirector); - } - -#if defined (BUFFERED_INPUT) - close_buffered_fd (fd); -#else - close (fd); -#endif - } - break; - - case r_duplicating_input: - case r_duplicating_output: - if (for_real && (redir_fd != redirector)) - { - if (remembering) - /* Only setup to undo it if the thing to undo is active. */ - if (fcntl (redirector, F_GETFD, 0) != -1) - add_undo_redirect (redirector); - else - add_undo_close_redirect (redirector); - -#if defined (BUFFERED_INPUT) - check_bash_input (redirector); +#ifdef __CYGWIN32__ + setmode (1, O_TEXT); #endif - /* This is correct. 2>&1 means dup2 (1, 2); */ - if (dup2 (redir_fd, redirector) < 0) - return (errno); - -#if defined (BUFFERED_INPUT) - if (ri == r_duplicating_input) - duplicate_buffered_stream (redir_fd, redirector); -#endif /* BUFFERED_INPUT */ - - /* First duplicate the close-on-exec state of redirectee. dup2 - leaves the flag unset on the new descriptor, which means it - stays open. Only set the close-on-exec bit for file descriptors - greater than 2 in any case, since 0-2 should always be open - unless closed by something like `exec 2<&-'. */ - /* if ((already_set || set_unconditionally) && (ok_to_set)) - set_it () */ - if (((fcntl (redir_fd, F_GETFD, 0) == 1) || set_clexec) && - (redirector > 2)) - SET_CLOSE_ON_EXEC (redirector); - } - break; - - case r_close_this: - if (for_real) - { - if (remembering && (fcntl (redirector, F_GETFD, 0) != -1)) - add_undo_redirect (redirector); - -#if defined (BUFFERED_INPUT) - check_bash_input (redirector); - close_buffered_fd (redirector); -#else /* !BUFFERED_INPUT */ - close (redirector); -#endif /* !BUFFERED_INPUT */ - } - break; - - case r_duplicating_input_word: - case r_duplicating_output_word: - break; - } - return (0); -} - -#define SHELL_FD_BASE 10 - -/* Remember the file descriptor associated with the slot FD, - on REDIRECTION_UNDO_LIST. Note that the list will be reversed - before it is executed. Any redirections that need to be undone - even if REDIRECTION_UNDO_LIST is discarded by the exec builtin - are also saved on EXEC_REDIRECTION_UNDO_LIST. */ -static int -add_undo_redirect (fd) - int fd; -{ - int new_fd, clexec_flag; - REDIRECT *new_redirect, *closer, *dummy_redirect; - - new_fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE); - - if (new_fd < 0) - { - sys_error ("redirection error"); - return (-1); - } - - clexec_flag = fcntl (fd, F_GETFD, 0); - - rd.dest = 0L; - closer = make_redirection (new_fd, r_close_this, rd); - dummy_redirect = copy_redirects (closer); - - rd.dest = (long)new_fd; - new_redirect = make_redirection (fd, r_duplicating_output, rd); - new_redirect->next = closer; - - closer->next = redirection_undo_list; - redirection_undo_list = new_redirect; - - /* Save redirections that need to be undone even if the undo list - is thrown away by the `exec' builtin. */ - add_exec_redirect (dummy_redirect); - - /* File descriptors used only for saving others should always be - marked close-on-exec. Unfortunately, we have to preserve the - close-on-exec state of the file descriptor we are saving, since - fcntl (F_DUPFD) sets the new file descriptor to remain open - across execs. If, however, the file descriptor whose state we - are saving is <= 2, we can just set the close-on-exec flag, - because file descriptors 0-2 should always be open-on-exec, - and the restore above in do_redirection() will take care of it. */ - if (clexec_flag || fd < 3) - SET_CLOSE_ON_EXEC (new_fd); - - return (0); -} - -/* Set up to close FD when we are finished with the current command - and its redirections. */ -static void -add_undo_close_redirect (fd) - int fd; -{ - REDIRECT *closer; - - rd.dest = 0L; - closer = make_redirection (fd, r_close_this, rd); - closer->next = redirection_undo_list; - redirection_undo_list = closer; -} - -static void -add_exec_redirect (dummy_redirect) - REDIRECT *dummy_redirect; -{ - dummy_redirect->next = exec_redirection_undo_list; - exec_redirection_undo_list = dummy_redirect; -} - -#define u_mode_bits(x) (((x) & 0000700) >> 6) -#define g_mode_bits(x) (((x) & 0000070) >> 3) -#define o_mode_bits(x) (((x) & 0000007) >> 0) -#define X_BIT(x) ((x) & 1) - -/* Return some flags based on information about this file. - The EXISTS bit is non-zero if the file is found. - The EXECABLE bit is non-zero the file is executble. - Zero is returned if the file is not found. */ -int -file_status (name) - char *name; -{ - struct stat finfo; - - /* 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); - -#if defined (AFS) - /* We have to use access(2) to determine access because AFS does not - support Unix file system semantics. This may produce wrong - answers for non-AFS files when ruid != euid. I hate AFS. */ - if (access (name, X_OK) == 0) - return (FS_EXISTS | FS_EXECABLE); - else - return (FS_EXISTS); -#else /* !AFS */ - - /* Find out if the file is actually executable. By definition, the - only other criteria is that the file has an execute bit set that - we can use. */ - - /* Root only requires execute permission for any of owner, group or - others to be able to exec a file. */ - if (current_user.euid == (uid_t)0) - { - int bits; - - bits = (u_mode_bits (finfo.st_mode) | - g_mode_bits (finfo.st_mode) | - o_mode_bits (finfo.st_mode)); - - if (X_BIT (bits)) - return (FS_EXISTS | FS_EXECABLE); - } - - /* If we are the owner of the file, the owner execute bit applies. */ - if (current_user.euid == finfo.st_uid && X_BIT (u_mode_bits (finfo.st_mode))) - return (FS_EXISTS | FS_EXECABLE); - - /* If we are in the owning group, the group permissions apply. */ - if (group_member (finfo.st_gid) && X_BIT (g_mode_bits (finfo.st_mode))) - return (FS_EXISTS | FS_EXECABLE); - - /* If `others' have execute permission to the file, then so do we, - since we are also `others'. */ - if (X_BIT (o_mode_bits (finfo.st_mode))) - return (FS_EXISTS | FS_EXECABLE); - - return (FS_EXISTS); -#endif /* !AFS */ -} - -/* Return non-zero if FILE exists and is executable. - Note that this function is the definition of what an - executable file is; do not change this unless YOU know - what an executable file is. */ -int -executable_file (file) - char *file; -{ - int s; - - s = file_status (file); - return ((s & FS_EXECABLE) && ((s & FS_DIRECTORY) == 0)); -} - -int -is_directory (file) - char *file; -{ - return (file_status (file) & FS_DIRECTORY); -} - -/* DOT_FOUND_IN_SEARCH becomes non-zero when find_user_command () - encounters a `.' as the directory pathname while scanning the - list of possible pathnames; i.e., if `.' comes before the directory - containing the file of interest. */ -int dot_found_in_search = 0; - -/* Locate the executable file referenced by NAME, searching along - the contents of the shell PATH variable. Return a new string - which is the full pathname to the file, or NULL if the file - couldn't be found. If a file is found that isn't executable, - and that is the only match, then return that. */ -char * -find_user_command (name) - char *name; -{ - return (find_user_command_internal (name, FS_EXEC_PREFERRED|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 file found. */ -char * -find_path_file (name) - char *name; -{ - return (find_user_command_internal (name, FS_EXISTS)); -} - -static char * -_find_user_command_internal (name, flags) - char *name; - int flags; -{ - char *path_list; - SHELL_VAR *var; - - /* Search for the value of PATH in both the temporary environment, and - in the regular list of variables. */ - if (var = find_variable_internal ("PATH", 1)) /* XXX could be array? */ - path_list = value_cell (var); - else - path_list = (char *)NULL; - - if (path_list == 0 || *path_list == '\0') - return (savestring (name)); - - return (find_user_command_in_path (name, path_list, flags)); -} - -static char * -find_user_command_internal (name, flags) - char *name; - int flags; -{ -#ifdef __WIN32__ - char *res, *dotexe; - - dotexe = xmalloc (strlen (name) + 5); - strcpy (dotexe, name); - strcat (dotexe, ".exe"); - res = _find_user_command_internal (dotexe, flags); - free (dotexe); - if (res == 0) - res = _find_user_command_internal (name, flags); - return res; -#else - return (_find_user_command_internal (name, flags)); -#endif -} - -/* Return the next element from PATH_LIST, a colon separated list of - paths. PATH_INDEX_POINTER is the address of an index into PATH_LIST; - the index is modified by this function. - Return the next element of PATH_LIST or NULL if there are no more. */ -static char * -get_next_path_element (path_list, path_index_pointer) - char *path_list; - int *path_index_pointer; -{ - char *path; - - path = extract_colon_unit (path_list, path_index_pointer); - - if (!path) - return (path); - - if (!*path) - { - free (path); - path = savestring ("."); - } - - return (path); -} - -/* 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) - char *pathname; -{ - char *hashed_file, *command; - int temp_path, st; - SHELL_VAR *path; - - hashed_file = command = (char *)NULL; - - /* If PATH is in the temporary environment for this command, don't use the - hash table to search for the full pathname. */ - path = find_tempenv_variable ("PATH"); - temp_path = path != 0; - - /* Don't waste time trying to find hashed data for a pathname - that is already completely specified or if we're using a command- - specific value for PATH. */ - if (path == 0 && absolute_program (pathname) == 0) - hashed_file = find_hashed_filename (pathname); - - /* If a command found in the hash table no longer exists, we need to - look for it in $PATH. Thank you Posix.2. This forces us to stat - every command found in the hash table. */ - - if (hashed_file && (posixly_correct || check_hashed_filenames)) - { - st = file_status (hashed_file); - if ((st ^ (FS_EXISTS | FS_EXECABLE)) != 0) - { - remove_hashed_filename (pathname); - 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) - remember_filename (pathname, command, dot_found_in_search, 1); - } - return (command); -} - -char * -user_command_matches (name, flags, state) - char *name; - int flags, state; -{ - register int i; - 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 = (char **)xmalloc (match_list_size * sizeof(char *)); - } - - /* 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 = (char **)xrealloc (match_list, (match_list_size + 1) * sizeof (char *)); - } - - match_list[match_index++] = match; - match_list[match_index] = (char *)NULL; - FREE (file_to_lose_on); - file_to_lose_on = (char *)NULL; - } - - /* We haven't returned any strings yet. */ - match_index = 0; - } - - match = match_list[match_index]; - - if (match) - match_index++; - - return (match); -} - -/* Turn PATH, a directory, and NAME, a filename, into a full pathname. - This allocates new memory and returns it. */ -static char * -make_full_pathname (path, name, name_len) - char *path, *name; - int name_len; -{ - char *full_path; - int path_len; - - path_len = strlen (path); - full_path = xmalloc (2 + path_len + name_len); - strcpy (full_path, path); - full_path[path_len] = '/'; - strcpy (full_path + path_len + 1, name); - return (full_path); -} - -static char * -find_absolute_program (name, flags) - char *name; - int flags; -{ - int st; - - st = file_status (name); - - /* If the file doesn't exist, quit now. */ - if ((st & FS_EXISTS) == 0) - return ((char *)NULL); - - /* If we only care about whether the file exists or not, return - this filename. Otherwise, maybe we care about whether this - file is executable. If it is, and that is what we want, return it. */ - if ((flags & FS_EXISTS) || ((flags & FS_EXEC_ONLY) && (st & FS_EXECABLE))) - return (savestring (name)); - - return ((char *)NULL); -} - -static char * -find_in_path_element (name, path, flags, name_len, dotinfop) - char *name, *path; - int flags, name_len; - struct stat *dotinfop; -{ - int status; - char *full_path, *xpath; - - xpath = (*path == '~') ? bash_tilde_expand (path) : path; - - /* Remember the location of "." in the path, in all its forms - (as long as they begin with a `.', e.g. `./.') */ - if (dot_found_in_search == 0 && *xpath == '.') - dot_found_in_search = same_file (".", xpath, dotinfop, (struct stat *)NULL); - - full_path = make_full_pathname (xpath, name, name_len); - - status = file_status (full_path); - - if (xpath != path) - free (xpath); - - if ((status & FS_EXISTS) == 0) - { - free (full_path); - return ((char *)NULL); - } - - /* The file exists. If the caller simply wants the first file, here it is. */ - if (flags & FS_EXISTS) - return (full_path); - - /* If the file is executable, then it satisfies the cases of - EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */ - if ((status & FS_EXECABLE) && - (((flags & FS_NODIRS) == 0) || ((status & FS_DIRECTORY) == 0))) - { - FREE (file_to_lose_on); - file_to_lose_on = (char *)NULL; - return (full_path); - } - - /* The file is not executable, but it does exist. If we prefer - an executable, then remember this one if it is the first one - we have found. */ - if ((flags & FS_EXEC_PREFERRED) && file_to_lose_on == 0) - file_to_lose_on = savestring (full_path); - - /* If we want only executable files, or we don't want directories and - this file is a directory, fail. */ - if ((flags & FS_EXEC_ONLY) || (flags & FS_EXEC_PREFERRED) || - ((flags & FS_NODIRS) && (status & FS_DIRECTORY))) - { - free (full_path); - return ((char *)NULL); - } - else - return (full_path); -} - -/* This does the dirty work for find_user_command_internal () and - user_command_matches (). - NAME is the name of the file to search for. - PATH_LIST is a colon separated list of directories to search. - FLAGS contains bit fields which control the files which are eligible. - 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) - 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); + if (dup2 (1, 2) < 0) + sys_error ("cannot duplicate fd 1 to fd 2"); +#ifdef __CYGWIN32__ + setmode (1, O_TEXT); + setmode (2, O_TEXT); +#endif } } - - /* We didn't find exactly what the user was looking for. Return - the contents of FILE_TO_LOSE_ON which is NULL when the search - required an executable, or non-NULL if a file was found and the - search would accept a non-executable as a last resort. */ - return (file_to_lose_on); } diff --git a/execute_cmd.h b/execute_cmd.h index 19e0b633..d2330342 100644 --- a/execute_cmd.h +++ b/execute_cmd.h @@ -30,15 +30,8 @@ extern int executing_line_number __P((void)); extern int execute_command __P((COMMAND *)); extern int execute_command_internal __P((COMMAND *, int, int, int, struct fd_bitmap *)); extern int shell_execve __P((char *, char **, char **)); -extern char *redirection_expand __P((WORD_DESC *)); -extern int file_status __P((char *)); -extern int executable_file __P((char *)); -extern int is_directory __P((char *)); -extern char *search_for_command __P((char *)); -extern char *find_user_command __P((char *)); -extern char *find_path_file __P((char *)); -extern char *user_command_matches __P((char *, int, int)); extern void setup_async_signals __P((void)); +extern void dispose_exec_redirects __P ((void)); #if defined (PROCESS_SUBSTITUTION) extern void close_all_files __P((void)); @@ -27,6 +27,7 @@ "-", "+" [(unary operators)] "!", "~" + "**" [(exponentiation)] "*", "/", "%" "+", "-" "<<", ">>" @@ -38,9 +39,7 @@ "&&" "||" "expr ? expr : expr" - "=", "*=", "/=", "%=", - "+=", "-=", "<<=", ">>=", - "&=", "^=", "|=" + "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=" (Note that most of these operators have special meaning to bash, and an entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure @@ -68,7 +67,11 @@ #include <stdio.h> #include "bashansi.h" + #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -99,7 +102,8 @@ #define LSH 9 /* "<<" Left SHift */ #define RSH 10 /* ">>" Right SHift */ #define OP_ASSIGN 11 /* op= expassign as in Posix.2 */ -#define COND 12 +#define COND 12 /* exp1 ? exp2 : exp3 */ +#define POWER 13 /* exp1**exp2 */ #define EQ '=' #define GT '>' #define LT '<' @@ -132,7 +136,7 @@ static procenv_t evalbuf; static void readtok (); /* lexical analyzer */ static long subexpr (), expassign (), exp0 (), exp1 (), exp2 (), exp3 (), exp4 (), exp5 (), expshift (), expland (), explor (), - expband (), expbor (), expbxor (), expcond (); + expband (), expbor (), expbxor (), expcond (), exppower (); static long strlong (); static void evalerror (); @@ -665,7 +669,7 @@ exp2 () { register long val1, val2; - val1 = exp1 (); + val1 = exppower (); while ((curtok == MUL) || (curtok == DIV) || @@ -675,7 +679,7 @@ exp2 () readtok (); - val2 = exp1 (); + val2 = exppower (); if (((op == DIV) || (op == MOD)) && (val2 == 0)) evalerror ("division by 0"); @@ -691,6 +695,25 @@ exp2 () } static long +exppower () +{ + register long val1, val2, c; + + val1 = exp1 (); + if (curtok == POWER) + { + readtok (); + val2 = exp1 (); + if (val2 == 0) + return (1L); + for (c = 1; val2--; c *= val1) + ; + val1 = c; + } + return (val1); +} + +static long exp1 () { register long val; @@ -875,6 +898,8 @@ readtok () c = LAND; else if ((c == BOR) && (c1 == BOR)) c = LOR; + else if ((c == '*') && (c1 == '*')) + c = POWER; else if (c1 == EQ && member(c, "*/%+-&^|")) { assigntok = c; /* a OP= b */ @@ -905,7 +930,7 @@ evalerror (msg) /* Convert a string to a long integer, with an arbitrary base. 0nnn -> base 8 - 0xnn -> base 16 + 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 @@ -29,11 +29,6 @@ /* Functions from expr.c. */ extern long evalexp __P((char *, int *)); -/* Functions from getcwd.c */ -#if !defined (HAVE_GETCWD) -extern char *getcwd __P((char *, size_t)); -#endif - /* Functions from print_cmd.c. */ extern char *make_command_string __P((COMMAND *)); extern void print_command __P((COMMAND *)); @@ -41,9 +36,15 @@ extern void print_simple_command __P((SIMPLE_COM *)); extern char *named_function_string __P((char *, COMMAND *, int)); extern void print_word_list __P((WORD_LIST *, char *)); extern void xtrace_print_word_list __P((WORD_LIST *)); +#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 int exit_shell __P((int)); +extern void exit_shell __P((int)); extern void disable_priv_mode __P((void)); extern void unbind_args __P((void)); @@ -51,15 +52,14 @@ extern void unbind_args __P((void)); 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 test.c. */ -extern int test_command (); +extern WORD_LIST *parse_string_to_word_list __P((char *, char *)); /* Functions from braces.c. */ #if defined (BRACE_EXPANSION) @@ -90,7 +90,35 @@ extern int list_length (); extern GENERIC_LIST *list_append (); extern GENERIC_LIST *delete_element (); -/* Declarations for functions defined in oslib.c */ +/* Declarations for functions defined in stringlib.c */ +extern char *ansicstr __P((char *, int, int *, int *)); +extern int find_name_in_array __P((char *, char **)); +extern int array_len __P((char **)); +extern void free_array_members __P((char **)); +extern void free_array __P((char **)); +extern char **copy_array __P((char **)); +extern int qsort_string_compare (); +extern void sort_char_array __P((char **)); +extern char **word_list_to_argv __P((WORD_LIST *, int, int, int *)); +extern WORD_LIST *argv_to_word_list __P((char **, int, int)); + +extern char *strsub __P((char *, char *, char *, int)); +extern void strip_leading __P((char *)); +extern void strip_trailing __P((char *, int, int)); +extern char *strindex __P((char *, char *)); +extern void xbcopy __P((char *, char *, 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/getcwd.c */ +#if !defined (HAVE_GETCWD) +extern char *getcwd __P((char *, size_t)); +#endif + +/* Declarations for functions defined in lib/sh/itos.c */ +extern char *itos __P((int)); + +/* Declarations for functions defined in lib/sh/oslib.c */ extern long get_clk_tck __P((void)); #if !defined (strerror) @@ -116,22 +144,19 @@ extern int getdtablesize __P((void)); extern int setlinebuf (); #endif -/* Declarations for functions defined in stringlib.c */ -extern char *ansicstr __P((char *, int, int *, int *)); -extern int find_name_in_array __P((char *, char **)); -extern int array_len __P((char **)); -extern void free_array_members __P((char **)); -extern void free_array __P((char **)); -extern char **copy_array __P((char **)); -extern int qsort_string_compare (); -extern void sort_char_array __P((char **)); -extern char **word_list_to_argv __P((WORD_LIST *, int, int, int *)); -extern WORD_LIST *argv_to_word_list __P((char **, int, int)); +/* declarations for functions defined in lib/sh/strtod.c */ +#if !defined (HAVE_STRTOD) +extern double strtod __P((const char *, char **)); +#endif -extern char *strsub __P((char *, char *, char *, int)); -extern void strip_leading __P((char *)); -extern void strip_trailing __P((char *, int, int)); -extern char *strindex __P((char *, char *)); -extern void xbcopy __P((char *, char *, int)); +/* declarations for functions defined in lib/sh/strtol.c */ +#if !defined (HAVE_STRTOL) +extern long strtol __P((const char *, char **, int)); +#endif + +/* declarations for functions defined in lib/sh/strtoul.c */ +#if !defined (HAVE_STRTOUL) +extern unsigned long strtoul __P((const char *, char **, int)); +#endif #endif /* _EXTERNS_H_ */ diff --git a/findcmd.c b/findcmd.c new file mode 100644 index 00000000..837b392d --- /dev/null +++ b/findcmd.c @@ -0,0 +1,580 @@ +/* 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 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 Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ + +#include "config.h" + +#include <stdio.h> +#include <ctype.h> +#include "bashtypes.h" +#ifndef _MINIX +# include <sys/file.h> +#endif +#include "filecntl.h" +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#if defined (HAVE_LIMITS_H) +# include <limits.h> +#endif + +#include "bashansi.h" + +#include "memalloc.h" +#include "shell.h" +#include "flags.h" +#include "hashlib.h" +#include "pathexp.h" +#include "hashcmd.h" + +extern int posixly_correct; + +/* Static functions defined and used in this file. */ +static char *find_user_command_internal (), *find_user_command_in_path (); +static char *find_in_path_element (), *find_absolute_program (); + +/* 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; + +#define u_mode_bits(x) (((x) & 0000700) >> 6) +#define g_mode_bits(x) (((x) & 0000070) >> 3) +#define o_mode_bits(x) (((x) & 0000007) >> 0) +#define X_BIT(x) ((x) & 1) + +/* Return some flags based on information about this file. + The EXISTS bit is non-zero if the file is found. + The EXECABLE bit is non-zero the file is executble. + Zero is returned if the file is not found. */ +int +file_status (name) + char *name; +{ + struct stat finfo; + + /* 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); + +#if defined (AFS) + /* We have to use access(2) to determine access because AFS does not + support Unix file system semantics. This may produce wrong + answers for non-AFS files when ruid != euid. I hate AFS. */ + if (access (name, X_OK) == 0) + return (FS_EXISTS | FS_EXECABLE); + else + return (FS_EXISTS); +#else /* !AFS */ + + /* Find out if the file is actually executable. By definition, the + only other criteria is that the file has an execute bit set that + we can use. */ + + /* Root only requires execute permission for any of owner, group or + others to be able to exec a file. */ + if (current_user.euid == (uid_t)0) + { + int bits; + + bits = (u_mode_bits (finfo.st_mode) | + g_mode_bits (finfo.st_mode) | + o_mode_bits (finfo.st_mode)); + + if (X_BIT (bits)) + return (FS_EXISTS | FS_EXECABLE); + } + + /* If we are the owner of the file, the owner execute bit applies. */ + if (current_user.euid == finfo.st_uid && X_BIT (u_mode_bits (finfo.st_mode))) + return (FS_EXISTS | FS_EXECABLE); + + /* If we are in the owning group, the group permissions apply. */ + if (group_member (finfo.st_gid) && X_BIT (g_mode_bits (finfo.st_mode))) + return (FS_EXISTS | FS_EXECABLE); + + /* If `others' have execute permission to the file, then so do we, + since we are also `others'. */ + if (X_BIT (o_mode_bits (finfo.st_mode))) + return (FS_EXISTS | FS_EXECABLE); + + return (FS_EXISTS); +#endif /* !AFS */ +} + +/* Return non-zero if FILE exists and is executable. + Note that this function is the definition of what an + executable file is; do not change this unless YOU know + what an executable file is. */ +int +executable_file (file) + char *file; +{ + int s; + + s = file_status (file); + return ((s & FS_EXECABLE) && ((s & FS_DIRECTORY) == 0)); +} + +int +is_directory (file) + char *file; +{ + return (file_status (file) & FS_DIRECTORY); +} + +/* Locate the executable file referenced by NAME, searching along + the contents of the shell PATH variable. Return a new string + which is the full pathname to the file, or NULL if the file + couldn't be found. If a file is found that isn't executable, + and that is the only match, then return that. */ +char * +find_user_command (name) + char *name; +{ + return (find_user_command_internal (name, FS_EXEC_PREFERRED|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 file found. */ +char * +find_path_file (name) + char *name; +{ + return (find_user_command_internal (name, FS_EXISTS)); +} + +static char * +_find_user_command_internal (name, flags) + char *name; + int flags; +{ + char *path_list, *cmd; + SHELL_VAR *var; + + /* Search for the value of PATH in both the temporary environment, and + in the regular list of variables. */ + if (var = find_variable_internal ("PATH", 1)) /* 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); + + if (var && tempvar_p (var)) + dispose_variable (var); + + return (cmd); +} + +static char * +find_user_command_internal (name, flags) + char *name; + int flags; +{ +#ifdef __WIN32__ + char *res, *dotexe; + + dotexe = xmalloc (strlen (name) + 5); + strcpy (dotexe, name); + strcat (dotexe, ".exe"); + res = _find_user_command_internal (dotexe, flags); + free (dotexe); + if (res == 0) + res = _find_user_command_internal (name, flags); + return res; +#else + return (_find_user_command_internal (name, flags)); +#endif +} + +/* Return the next element from PATH_LIST, a colon separated list of + paths. PATH_INDEX_POINTER is the address of an index into PATH_LIST; + the index is modified by this function. + Return the next element of PATH_LIST or NULL if there are no more. */ +static char * +get_next_path_element (path_list, path_index_pointer) + char *path_list; + int *path_index_pointer; +{ + char *path; + + path = extract_colon_unit (path_list, path_index_pointer); + + if (!path) + return (path); + + if (!*path) + { + free (path); + path = savestring ("."); + } + + return (path); +} + +/* 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) + char *pathname; +{ + char *hashed_file, *command; + int temp_path, st; + SHELL_VAR *path; + + hashed_file = command = (char *)NULL; + + /* If PATH is in the temporary environment for this command, don't use the + hash table to search for the full pathname. */ + path = find_tempenv_variable ("PATH"); + temp_path = path != 0; + + /* Don't waste time trying to find hashed data for a pathname + that is already completely specified or if we're using a command- + specific value for PATH. */ + if (path == 0 && absolute_program (pathname) == 0) + hashed_file = find_hashed_filename (pathname); + + /* If a command found in the hash table no longer exists, we need to + look for it in $PATH. Thank you Posix.2. This forces us to stat + every command found in the hash table. */ + + if (hashed_file && (posixly_correct || check_hashed_filenames)) + { + st = file_status (hashed_file); + if ((st ^ (FS_EXISTS | FS_EXECABLE)) != 0) + { + remove_hashed_filename (pathname); + 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); + if (tempvar_p (path)) + dispose_variable (path); + } + else + command = find_user_command (pathname); + if (command && hashing_enabled && temp_path == 0) + remember_filename (pathname, command, dot_found_in_search, 1); + } + return (command); +} + +char * +user_command_matches (name, flags, state) + char *name; + int flags, state; +{ + register int i; + 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 = (char **)xmalloc (match_list_size * sizeof(char *)); + } + + /* 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 = (char **)xrealloc (match_list, (match_list_size + 1) * sizeof (char *)); + } + + match_list[match_index++] = match; + match_list[match_index] = (char *)NULL; + FREE (file_to_lose_on); + file_to_lose_on = (char *)NULL; + } + + /* We haven't returned any strings yet. */ + match_index = 0; + } + + match = match_list[match_index]; + + if (match) + match_index++; + + return (match); +} + +/* Turn PATH, a directory, and NAME, a filename, into a full pathname. + This allocates new memory and returns it. */ +static char * +make_full_pathname (path, name, name_len) + char *path, *name; + int name_len; +{ + char *full_path; + int path_len; + + path_len = strlen (path); + full_path = xmalloc (2 + path_len + name_len); + strcpy (full_path, path); + full_path[path_len] = '/'; + strcpy (full_path + path_len + 1, name); + return (full_path); +} + +static char * +find_absolute_program (name, flags) + char *name; + int flags; +{ + int st; + + st = file_status (name); + + /* If the file doesn't exist, quit now. */ + if ((st & FS_EXISTS) == 0) + return ((char *)NULL); + + /* If we only care about whether the file exists or not, return + this filename. Otherwise, maybe we care about whether this + file is executable. If it is, and that is what we want, return it. */ + if ((flags & FS_EXISTS) || ((flags & FS_EXEC_ONLY) && (st & FS_EXECABLE))) + return (savestring (name)); + + return ((char *)NULL); +} + +static char * +find_in_path_element (name, path, flags, name_len, dotinfop) + char *name, *path; + int flags, name_len; + struct stat *dotinfop; +{ + int status; + char *full_path, *xpath; + + xpath = (*path == '~') ? bash_tilde_expand (path) : path; + + /* Remember the location of "." in the path, in all its forms + (as long as they begin with a `.', e.g. `./.') */ + if (dot_found_in_search == 0 && *xpath == '.') + dot_found_in_search = same_file (".", xpath, dotinfop, (struct stat *)NULL); + + full_path = make_full_pathname (xpath, name, name_len); + + status = file_status (full_path); + + if (xpath != path) + free (xpath); + + if ((status & FS_EXISTS) == 0) + { + free (full_path); + return ((char *)NULL); + } + + /* The file exists. If the caller simply wants the first file, here it is. */ + if (flags & FS_EXISTS) + return (full_path); + + /* If the file is executable, then it satisfies the cases of + EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */ + if ((status & FS_EXECABLE) && + (((flags & FS_NODIRS) == 0) || ((status & FS_DIRECTORY) == 0))) + { + FREE (file_to_lose_on); + file_to_lose_on = (char *)NULL; + return (full_path); + } + + /* The file is not executable, but it does exist. If we prefer + an executable, then remember this one if it is the first one + we have found. */ + if ((flags & FS_EXEC_PREFERRED) && file_to_lose_on == 0) + file_to_lose_on = savestring (full_path); + + /* If we want only executable files, or we don't want directories and + this file is a directory, fail. */ + if ((flags & FS_EXEC_ONLY) || (flags & FS_EXEC_PREFERRED) || + ((flags & FS_NODIRS) && (status & FS_DIRECTORY))) + { + free (full_path); + return ((char *)NULL); + } + else + return (full_path); +} + +/* This does the dirty work for find_user_command_internal () and + user_command_matches (). + NAME is the name of the file to search for. + PATH_LIST is a colon separated list of directories to search. + FLAGS contains bit fields which control the files which are eligible. + 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) + 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. */ + return (file_to_lose_on); +} diff --git a/findcmd.h b/findcmd.h new file mode 100644 index 00000000..f01cb7de --- /dev/null +++ b/findcmd.h @@ -0,0 +1,34 @@ +/* findcmd.h - functions from findcmd.c. */ + +/* 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_FINDCMD_H_) +#define _FINDCMD_H_ + +#include "stdc.h" + +extern int file_status __P((char *)); +extern int executable_file __P((char *)); +extern int is_directory __P((char *)); +extern char *find_user_command __P((char *)); +extern char *find_path_file __P((char *)); +extern char *search_for_command __P((char *)); +extern char *user_command_matches __P((char *, int, int)); + +#endif /* _FINDCMD_H_ */ @@ -209,8 +209,8 @@ find_flag (name) } /* Change the state of a flag, and return it's original value, or return - FLAG_ERROR if there is no flag called NAME. ON_OR_OFF should be one - of FLAG_ON or FLAG_OFF. */ + 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; @@ -226,17 +226,12 @@ change_flag (flag, on_or_off) return (FLAG_ERROR); #endif /* RESTRICTED_SHELL */ - if (value == (int *)FLAG_UNKNOWN) + if ((value == (int *)FLAG_UNKNOWN) || (on_or_off != FLAG_ON && on_or_off != FLAG_OFF)) return (FLAG_ERROR); old_value = *value; - if (on_or_off == FLAG_ON) - *value = 1; - else if (on_or_off == FLAG_OFF) - *value = 0; - else - return (FLAG_ERROR); + *value = (on_or_off == FLAG_ON) ? 1 : 0; /* Special cases for a few flags. */ switch (flag) @@ -22,7 +22,9 @@ #include "config.h" #include "bashtypes.h" -#include <sys/param.h> +#ifndef _MINIX +# include <sys/param.h> +#endif #include "posixstat.h" #if defined (HAVE_UNISTD_H) @@ -63,7 +65,9 @@ extern int errno; extern int interrupt_immediately; extern int interactive_comments; -extern char *bash_getcwd_errstr; + +/* A standard error message to use when getcwd() returns NULL. */ +char *bash_getcwd_errstr = "getcwd: cannot access parent directories"; /* Do whatever is necessary to initialize `Posix mode'. */ void @@ -75,68 +79,6 @@ posix_initialize (on) /* **************************************************************** */ /* */ -/* Integer to String Conversion */ -/* */ -/* **************************************************************** */ - -/* Number of characters that can appear in a string representation - of an integer. 32 is larger than the string rep of 2^^31 - 1. */ -#define MAX_INT_LEN 32 - -/* Integer to string conversion. This conses the string; the - caller should free it. */ -char * -itos (i) - int i; -{ - char buf[MAX_INT_LEN], *p, *ret; - int negative = 0; - unsigned int ui; - - if (i < 0) - { - negative++; - i = -i; - } - - ui = (unsigned int) i; - - p = buf + MAX_INT_LEN - 2; - p[1] = '\0'; - - do - *p-- = (ui % 10) + '0'; - while (ui /= 10); - - if (negative) - *p-- = '-'; - - ret = savestring (p + 1); - return (ret); -} - -/* atol(3) is not universal */ -long -string_to_long (s) - char *s; -{ - long ret = 0L; - int neg = 0; - - while (s && *s && whitespace (*s)) - s++; - if (*s == '-' || *s == '+') - { - neg = *s == '-'; - s++; - } - for ( ; s && *s && digit (*s); s++) - ret = (ret * 10) + digit_value (*s); - return (neg ? -ret : ret); -} - -/* **************************************************************** */ -/* */ /* Functions to convert to and from and display non-standard types */ /* */ /* **************************************************************** */ @@ -146,9 +88,11 @@ RLIMTYPE string_to_rlimtype (s) char *s; { - RLIMTYPE ret = 0; - int neg = 0; + RLIMTYPE ret; + int neg; + ret = 0; + neg = 0; while (s && *s && whitespace (*s)) s++; if (*s == '-' || *s == '+') @@ -167,7 +111,7 @@ print_rlimtype (n, addnl) int addnl; { char s[sizeof (RLIMTYPE) * 3 + 1]; - int len = sizeof (RLIMTYPE) * 3 + 1; + int len; if (n == 0) { @@ -181,6 +125,7 @@ print_rlimtype (n, addnl) n = -n; } + len = sizeof (RLIMTYPE) * 3 + 1; s[--len] = '\0'; for ( ; n != 0; n /= 10) s[--len] = n % 10 + '0'; @@ -295,53 +240,27 @@ legal_number (string, result) char *string; long *result; { - int sign; long value; - - sign = 1; - value = 0; + char *ep; if (result) *result = 0; - /* Skip leading whitespace characters. */ - while (whitespace (*string)) - string++; - - if (!*string) - return (0); + value = strtol (string, &ep, 10); - /* We allow leading `-' or `+'. */ - if (*string == '-' || *string == '+') - { - if (!digit (string[1])) - return (0); - - if (*string == '-') - sign = -1; - - string++; - } - - while (digit (*string)) + /* If *string is not '\0' but *ep is '\0' on return, the entire string + is valid. */ + if (string && *string && *ep == '\0') { if (result) - value = (value * 10) + digit_value (*string); - string++; + *result = value; + /* The SunOS4 implementation of strtol() will happily ignore + overflow conditions, so this cannot do overflow correctly + on those systems. */ + return 1; } - - /* Skip trailing whitespace, if any. */ - while (whitespace (*string)) - string++; - - /* Error if not at end of string. */ - if (*string) - return (0); - - if (result) - *result = value * sign; - - return (1); + + return (0); } /* Return 1 if this token is a legal shell `identifier'; that is, it consists @@ -700,6 +619,13 @@ canonicalize_pathname (path) *result = stub_char; result[1] = '\0'; } + +#if 1 + /* Turn `//' into `/' -- XXX experimental */ + if (result[0] == '/' && result[1] == '/' && result[2] == '\0') + result[1] = '\0'; +#endif + return (result); } @@ -911,9 +837,15 @@ extract_colon_unit (string, p_index) /* */ /* **************************************************************** */ +#if defined (PUSHD_AND_POPD) +extern char *get_dirstack_from_string __P((char *)); +#endif + /* 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 ~+. */ + 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; @@ -921,13 +853,15 @@ bash_special_tilde_expansions (text) char *result; result = (char *)NULL; - if (text[1] == '\0') - { - if (*text == '+') - result = get_string_value ("PWD"); - else if (*text == '-') - result = get_string_value ("OLDPWD"); - } + + 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 (isdigit (*text) || ((*text == '+' || *text == '-') && isdigit (text[1]))) + result = get_dirstack_from_string (text); +#endif return (result ? savestring (result) : (char *)NULL); } @@ -946,7 +880,7 @@ tilde_initialize () /* 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) + if (times_called++ == 0) { tilde_additional_prefixes = (char **)xmalloc (3 * sizeof (char *)); tilde_additional_prefixes[0] = "=~"; @@ -958,7 +892,6 @@ tilde_initialize () tilde_additional_suffixes[1] = "=~"; tilde_additional_suffixes[2] = (char *)NULL; } - times_called++; } char * @@ -1039,12 +972,31 @@ initialize_group_array () 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; @@ -25,6 +25,13 @@ #include "bashtypes.h" +#if defined (HAVE_SYS_RESOURCE_H) && defined (RLIMTYPE) +# if defined (HAVE_SYS_TIME_H) +# include <sys/time.h> +# endif +# include <sys/resource.h> +#endif + #if defined (HAVE_STRING_H) # include <string.h> #else @@ -131,7 +138,7 @@ typedef struct { /* More convenience definitions that possibly save system or libc calls. */ #define STRLEN(s) (((s) && (s)[0]) ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0) #define FREE(s) do { if (s) free (s); } while (0) -#define MEMBER(c, s) (((c) && !(s)[1] && c == s[0]) || (member(c, s))) +#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. @@ -178,9 +185,6 @@ extern void xfree __P((char *)); /* Declarations for functions defined in general.c */ extern void posix_initialize __P((int)); -extern char *itos __P((int)); -extern long string_to_long __P((char *)); - #if defined (RLIMTYPE) extern RLIMTYPE string_to_rlimtype __P((char *)); extern void print_rlimtype __P((RLIMTYPE, int)); @@ -215,11 +219,7 @@ extern char *extract_colon_unit __P((char *, int *)); extern void tilde_initialize __P((void)); extern char *bash_tilde_expand __P((char *)); -#if defined (__STDC__) && defined (gid_t) -extern int group_member __P((int)); -#else extern int group_member __P((gid_t)); -#endif extern char **get_group_list __P((int *)); #endif /* _GENERAL_H_ */ @@ -31,7 +31,7 @@ #include "bashansi.h" #include "shell.h" -#include "execute_cmd.h" +#include "findcmd.h" #include "hashcmd.h" extern int hashing_enabled; @@ -148,9 +148,15 @@ find_hashed_filename (filename) if (pathdata(item)->flags & (HASH_CHKDOT|HASH_RELPATH)) { tail = (pathdata(item)->flags & HASH_RELPATH) ? path : filename; - dotted_filename = xmalloc (3 + strlen (tail)); - dotted_filename[0] = '.'; dotted_filename[1] = '/'; - strcpy (dotted_filename + 2, tail); + /* If the pathname does not start with a `./', add a `./' to it. */ + if (tail[0] != '.' || tail[1] != '/') + { + dotted_filename = xmalloc (3 + strlen (tail)); + dotted_filename[0] = '.'; dotted_filename[1] = '/'; + strcpy (dotted_filename + 2, tail); + } + else + dotted_filename = savestring (tail); if (executable_file (dotted_filename)) return (dotted_filename); @@ -20,7 +20,7 @@ #include "hashlib.h" -#define FILENAME_HASH_BUCKETS 631 +#define FILENAME_HASH_BUCKETS 107 extern HASH_TABLE *hashed_filenames; @@ -23,6 +23,9 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "bashansi.h" #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -225,6 +228,8 @@ dispose_hash_table (table) free (table); } +/* No longer necessary; everything uses the macro */ +#if 0 /* Return the bucket_contents list of bucket BUCKET in TABLE. If TABLE doesn't have BUCKET buckets, return NULL. */ #undef get_hash_bucket @@ -238,8 +243,10 @@ get_hash_bucket (bucket, table) else return (BUCKET_CONTENTS *)NULL; } +#endif -/* #ifdef DEBUG */ +#ifdef DEBUG +void print_table_stats (table, name) HASH_TABLE *table; char *name; @@ -265,7 +272,7 @@ print_table_stats (table, name) fprintf (stderr, "%d\n", bcount); } } -/* #endif */ +#endif #ifdef TEST_HASHING @@ -21,7 +21,9 @@ #include "config.h" #include "bashtypes.h" -#include <sys/file.h> +#ifndef _MINIX +# include <sys/file.h> +#endif #include "filecntl.h" #include "posixstat.h" #include <stdio.h> @@ -96,8 +98,6 @@ ungetc_with_restart (c, stream) # define SEEK_CUR 1 #endif /* !SEEK_CUR */ -void free_buffered_stream (); - extern int return_EOF (); extern int interactive_shell; @@ -109,7 +109,7 @@ int bash_input_fd_changed; way around. This is needed so that buffers are managed properly in constructs like 3<&4. buffers[x]->b_fd == x -- that is how the correspondence is maintained. */ -BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL; +static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL; static int nbuffers; #define max(a, b) (((a) > (b)) ? (a) : (b)) @@ -140,7 +140,7 @@ static BUFFERED_STREAM * make_buffered_stream (fd, buffer, bufsize) int fd; char *buffer; - int bufsize; + size_t bufsize; { BUFFERED_STREAM *bp; @@ -269,7 +269,11 @@ duplicate_buffered_stream (fd1, fd2) } /* Return 1 if a seek on FD will succeed. */ -#define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0) +#ifndef __CYGWIN32__ +# define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0) +#else +# define fd_is_seekable(fd) 0 +#endif /* __CYGWIN32__ */ /* Take FD, a file descriptor, and create and return a buffered stream corresponding to it. If something is wrong and the file descriptor @@ -279,7 +283,7 @@ fd_to_buffered_stream (fd) int fd; { char *buffer; - int size; + size_t size; struct stat sb; if (fstat (fd, &sb) < 0) @@ -291,8 +295,9 @@ fd_to_buffered_stream (fd) if (fd_is_seekable (fd) == 0) size = 1; else - size = (sb.st_size > MAX_INPUT_BUFFER_SIZE) ? MAX_INPUT_BUFFER_SIZE - : sb.st_size; + size = (size_t)((sb.st_size > MAX_INPUT_BUFFER_SIZE) + ? MAX_INPUT_BUFFER_SIZE + : sb.st_size); buffer = (char *)xmalloc (size); @@ -354,6 +359,20 @@ close_buffered_fd (fd) return (close_buffered_stream (buffers[fd])); } +/* Make the BUFFERED_STREAM associcated with buffers[FD] be BP, and return + the old BUFFERED_STREAM. */ +BUFFERED_STREAM * +set_buffered_stream (fd, bp) + int fd; + BUFFERED_STREAM *bp; +{ + BUFFERED_STREAM *ret; + + ret = buffers[fd]; + buffers[fd] = bp; + return ret; +} + /* Read a buffer full of characters from BP, a buffered stream. */ static int b_fill_buffer (bp) @@ -36,6 +36,10 @@ 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 0x1 #define B_ERROR 0x2 #define B_UNBUFF 0x4 @@ -46,15 +50,15 @@ typedef struct BSTREAM { int b_fd; char *b_buffer; /* The buffer that holds characters read. */ - int b_size; /* How big the buffer is. */ + size_t b_size; /* How big the buffer is. */ int b_used; /* How much of the buffer we're using, */ int b_flag; /* Flag values. */ int b_inputp; /* The input pointer, index into b_buffer. */ } BUFFERED_STREAM; +#if 0 extern BUFFERED_STREAM **buffers; - -extern BUFFERED_STREAM *fd_to_buffered_stream (); +#endif extern int default_buffered_input; @@ -102,6 +106,7 @@ extern int ungetc_with_restart (); 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 *)); @@ -37,9 +37,9 @@ # include <sys/time.h> #endif -#if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_WAIT3) && !defined (_POSIX_VERSION) +#if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_WAIT3) && !defined (_POSIX_VERSION) && !defined (RLIMTYPE) # include <sys/resource.h> -#endif /* !_POSIX_VERSION && HAVE_SYS_RESOURCE_H && HAVE_WAIT3 */ +#endif /* !_POSIX_VERSION && HAVE_SYS_RESOURCE_H && HAVE_WAIT3 && !RLIMTYPE */ #include <sys/file.h> #include "filecntl.h" @@ -165,7 +165,6 @@ extern sigset_t top_level_mask; #if defined (ARRAY_VARS) static int *pstatuses; /* list of pipeline statuses */ static int statsize; -static void set_pipestatus_array (); #endif static void setjstatus (); static void get_new_window_size (); @@ -229,7 +228,7 @@ static int waitchld (); static PROCESS *find_pipeline (); static char *current_working_directory (); static char *job_working_directory (); -static pid_t last_pid (); +static pid_t find_last_pid (), last_pid (); static int set_new_line_discipline (), map_over_jobs (), last_running_job (); static int most_recent_job_in_state (), last_stopped_job (), find_job (); static void notify_of_job_status (), cleanup_dead_jobs (), discard_pipeline (); @@ -544,8 +543,13 @@ cleanup_dead_jobs () BLOCK_CHILD (set, oset); for (i = 0; i < job_slots; i++) +#if 0 + if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i) && + (interactive_shell || (find_last_pid (i) != last_asynchronous_pid))) +#else if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i)) - delete_job (i); +#endif + delete_job (i, 0); UNBLOCK_CHILD (oset); } @@ -553,14 +557,17 @@ cleanup_dead_jobs () /* Delete the job at INDEX from the job list. Must be called with SIGCHLD blocked. */ void -delete_job (job_index) - int job_index; +delete_job (job_index, warn_stopped) + int job_index, warn_stopped; { register JOB *temp; - if (jobs_list_frozen) + if (job_slots == 0 || jobs_list_frozen) return; + if (warn_stopped && subshell_environment == 0 && STOPPED (job_index)) + internal_warning ("deleting stopped job %d with process group %d", job_index+1, jobs[job_index]->pgrp); + temp = jobs[job_index]; if (job_index == current_job || job_index == previous_job) reset_current (); @@ -583,6 +590,9 @@ nohup_job (job_index) { register JOB *temp; + if (job_slots == 0) + return; + if (temp = jobs[job_index]) temp->flags |= J_NOHUP; } @@ -981,7 +991,17 @@ print_pipeline (p, job_index, format, stream) } if (format || (p == last)) - fprintf (stream, "\r\n"); + { + /* 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; @@ -1028,12 +1048,12 @@ pretty_print_job (job_index, format, stream) 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; - print_pipeline (p, job_index, format, stream); - UNBLOCK_CHILD (oset); } @@ -1137,11 +1157,7 @@ make_child (command, async_p) /* Close default_buffered_input if it's > 0. We don't close it if it's 0 because that's the file descriptor used when redirecting input, and it's wrong to close the file in that case. */ - if (default_buffered_input > 0) - { - close_buffered_fd (default_buffered_input); - default_buffered_input = bash_input.location.buffered_fd = -1; - } + unset_bash_input (0); #endif /* BUFFERED_INPUT */ /* Restore top-level signal mask. */ @@ -1406,22 +1422,32 @@ set_tty_state () process in that job's pipeline. This is the one whose exit status counts. */ static pid_t -last_pid (job) +find_last_pid (job) int job; { register PROCESS *p; - sigset_t set, oset; - - BLOCK_CHILD (set, oset); p = jobs[job]->pipe; while (p->next != jobs[job]->pipe) p = p->next; - UNBLOCK_CHILD (oset); return (p->pid); } +static pid_t +last_pid (job) + int job; +{ + pid_t pid; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + pid = find_last_pid (job); + UNBLOCK_CHILD (oset); + + return (pid); +} + /* Wait for a particular child of the shell to finish executing. This low-level function prints an error message if PID is not a child of this shell. It returns -1 if it fails, or 0 if not. */ @@ -1431,6 +1457,7 @@ wait_for_single_pid (pid) { register PROCESS *child; sigset_t set, oset; + int r, job; BLOCK_CHILD (set, oset); child = find_pipeline (pid); @@ -1442,7 +1469,20 @@ wait_for_single_pid (pid) return (127); } - return (wait_for (pid)); + r = wait_for (pid); + + /* POSIX.2: if we just waited for $!, we can remove the job from the + jobs table. */ + if (pid == last_asynchronous_pid) + { + BLOCK_CHILD (set, oset); + job = find_job (pid); + if (job != NO_JOB && jobs[job] && DEADJOB (job)) + jobs[job]->flags |= J_NOTIFIED; + UNBLOCK_CHILD (oset); + } + + return r; } /* Wait for all of the backgrounds of this shell to finish. */ @@ -1759,9 +1799,28 @@ 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); + UNBLOCK_CHILD(oset); pid = last_pid (job); - return (wait_for (pid)); + r = wait_for (pid); + + /* POSIX.2: if we just waited for $!, we can remove the job from the + jobs table. */ + if (pid == last_asynchronous_pid) + { + 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 @@ -2325,6 +2384,7 @@ waitchld (wpid, block) the original handler is SIG_DFL, we need to resend the signal to ourselves. */ SigHandler *temp_handler; + 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 @@ -2436,7 +2496,15 @@ notify_of_job_status () if ((job_control == 0 && interactive_shell) || startup_state == 2 || (startup_state == 0 && WIFSIGNALED (s) == 0)) { +#if 0 if (DEADJOB (job)) +#else + /* 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) != last_asynchronous_pid))) +#endif jobs[job]->flags |= J_NOTIFIED; continue; } @@ -2448,6 +2516,12 @@ notify_of_job_status () { case JDEAD: if (interactive_shell == 0 && termsig && WIFSIGNALED (s) && +#if 1 + termsig != SIGINT && +#endif +#if defined (DONT_REPORT_SIGPIPE) + termsig != SIGPIPE && +#endif signal_is_trapped (termsig) == 0) { fprintf (stderr, "%s: line %d: ", get_name_for_error (), line_number); @@ -2818,9 +2892,11 @@ give_terminal_to (pgrp) /* 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). */ + 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 () +delete_all_jobs (running_only) + int running_only; { register int i; sigset_t set, oset; @@ -2832,20 +2908,24 @@ delete_all_jobs () current_job = previous_job = NO_JOB; for (i = 0; i < job_slots; i++) - if (jobs[i]) - delete_job (i); + if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) + delete_job (i, 1); - free ((char *)jobs); - job_slots = 0; + if (running_only == 0) + { + free ((char *)jobs); + job_slots = 0; + } } UNBLOCK_CHILD (oset); } /* Mark all jobs in the job array so that they don't get a SIGHUP when the - shell gets one. */ + shell gets one. If RUNNING_ONLY is nonzero, mark only running jobs. */ void -nohup_all_jobs () +nohup_all_jobs (running_only) + int running_only; { register int i; sigset_t set, oset; @@ -2855,7 +2935,7 @@ nohup_all_jobs () if (job_slots) { for (i = 0; i < job_slots; i++) - if (jobs[i]) + if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) nohup_job (i); } @@ -2875,7 +2955,11 @@ mark_dead_jobs_as_notified () BLOCK_CHILD (set, oset); for (i = 0; i < job_slots; i++) +#if 0 if (jobs[i] && DEADJOB (i)) +#else + if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i) != last_asynchronous_pid))) +#endif jobs[i]->flags |= J_NOTIFIED; UNBLOCK_CHILD (oset); @@ -2910,7 +2994,7 @@ without_job_control () { stop_making_children (); start_pipeline (); - delete_all_jobs (); + delete_all_jobs (0); set_job_control (0); } @@ -3023,30 +3107,3 @@ setjstatus (j) set_pipestatus_array (pstatuses); #endif } - -#if defined (ARRAY_VARS) -static void -set_pipestatus_array (ps) - int *ps; -{ - SHELL_VAR *v; - ARRAY *a; - register int i; - char *t; - - v = find_variable ("PIPESTATUS"); - if (v == 0) - v = make_new_array_variable ("PIPESTATUS"); - if (array_p (v) == 0) - return; /* Do nothing if not an array variable. */ - a = array_cell (v); - if (a) - empty_array (a); - for (i = 0; ps[i] != -1; i++) - { - t = itos (ps[i]); - array_add_element (a, i, t); - free (t); - } -} -#endif @@ -110,10 +110,10 @@ extern void restore_pipeline __P((int)); extern void start_pipeline __P((void)); extern int stop_pipeline __P((int, COMMAND *)); -extern void delete_job __P((int)); +extern void delete_job __P((int, int)); extern void nohup_job __P((int)); -extern void delete_all_jobs __P((void)); -extern void nohup_all_jobs __P((void)); +extern void delete_all_jobs __P((int)); +extern void nohup_all_jobs __P((int)); extern void terminate_current_pipeline __P((void)); extern void terminate_stopped_jobs __P((void)); diff --git a/lib/glob/collsyms.h b/lib/glob/collsyms.h new file mode 100644 index 00000000..4f90083c --- /dev/null +++ b/lib/glob/collsyms.h @@ -0,0 +1,129 @@ +/* collsyms.h -- collating symbol names and their corresponding characters + (in ascii) as given by POSIX.2 in table 2.8. */ + +/* 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _COLLSYMS_H_ +# define _COLLSYSMS_H_ + +/* The upper-case letters, lower-case letters, and digits are omitted from + this table. The digits are not included in the table in the POSIX.2 + spec. The upper and lower case letters are translated by the code + in fnmatch.c:collsym(). */ + +typedef struct _collsym { + char *name; + char code; +} COLLSYM; + +static COLLSYM posix_collsyms[] = +{ + "NUL", '\0', + "SOH", '\001', + "STX", '\002', + "ETX", '\003', + "EOT", '\004', + "ENQ", '\005', + "ACK", '\006', +#ifdef __STDC__ + "alert", '\a', +#else + "alert", '\007', +#endif + "backspace", '\b', + "tab", '\t', + "newline", '\n', + "vertical-tab", '\v', + "form-feed", '\f', + "carriage-return", '\r', + "SO", '\016', + "SI", '\017', + "DLE", '\020', + "DC1", '\021', + "DC2", '\022', + "DC3", '\023', + "DC4", '\024', + "NAK", '\025', + "SYN", '\026', + "ETB", '\027', + "CAN", '\030', + "EM", '\031', + "SUB", '\032', + "ESC", '\033', + "IS4", '\034', + "IS3", '\035', + "IS2", '\036', + "IS1", '\037', + "space", ' ', + "exclamation-mark", '!', + "quotation-mark", '"', + "number-sign", '#', + "dollar-sign", '$', + "percent-sign", '%', + "ampersand", '&', + "apostrophe", '\'', + "left-parenthesis", '(', + "right-parenthesis", ')', + "asterisk", '*', + "plus-sign", '+', + "comma", ',', + "hyphen", '-', + "minus", '-', /* extension from POSIX.2 */ + "dash", '-', /* extension from POSIX.2 */ + "period", '.', + "slash", '/', + "solidus", '/', /* extension from POSIX.2 */ + "zero", '0', + "one", '1', + "two", '2', + "three", '3', + "four", '4', + "five", '5', + "six", '6', + "seven", '7', + "eight", '8', + "nine", '9', + "colon", ':', + "semicolon", ';', + "less-than-sign", '<', + "equals-sign", '=', + "greater-than-sign", '>', + "question-mark", '?', + "commercial-at", '@', + /* upper-case letters omitted */ + "left-square-bracket",'[', + "backslash", '\\', + "reverse-solidus", '\\', + "right-square-bracket", ']', + "circumflex", '^', + "circumflex-accent", '^', /* extension from POSIX.2 */ + "underscore", '_', + "grave-accent", '`', + /* lower-case letters omitted */ + "left-brace", '{', /* extension from POSIX.2 */ + "left-curly-bracket", '{', + "vertical-line", '|', + "right-brace", '}', /* extension from POSIX.2 */ + "right-curly-bracket", '}', + "tilde", '~', + "DEL", '\177', + 0, 0, +}; + +#endif diff --git a/lib/glob/fnmatch.c b/lib/glob/fnmatch.c index 2f8eb240..b5fdcc16 100644 --- a/lib/glob/fnmatch.c +++ b/lib/glob/fnmatch.c @@ -1,238 +1,738 @@ -/* Copyright (C) 1991 Free Software Foundation, Inc. -This file is part of the GNU C Library. +/* fnmatch.c -- ksh-like extended pattern matching for the shell and filename + globbing. */ + +/* Copyright (C) 1991, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <config.h> + +#include "fnmatch.h" +#include "collsyms.h" +#include <ctype.h> -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. +static int gmatch (); +static char *brackmatch (); +#ifdef EXTENDED_GLOB +static int extmatch (); +#endif + +#if !defined (isascii) +# define isascii(c) ((unsigned int)(c) <= 0177) +#endif -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. +/* Note that these evaluate C many times. */ -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. */ +#define ISUPPER(c) (isascii (c) && isupper (c)) +#define ISLOWER(c) (isascii (c) && islower (c)) -#include <errno.h> -#include "fnmatch.h" +#ifndef isblank +# define isblank(c) ((c) == ' ' || (c) == '\t') +#endif -#if !defined (__GNU_LIBRARY__) && !defined (STDC_HEADERS) -# if !defined (errno) -extern int errno; -# endif /* !errno */ +#ifndef isgraph +# define isgraph(c) ((c) != ' ' && isprint((c))) #endif -/* Match STRING against the filename pattern PATTERN, returning zero if - it matches, FNM_NOMATCH if not. */ +#ifndef isxdigit +# define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) +#endif + +# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) + +#ifndef STREQ +#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0) +#define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0) +#endif + +#if defined (HAVE_STRCOLL) +static int rangecmp (c1, c2) + int c1, c2; +{ + static char s1[2] = { ' ', '\0' }; + static char s2[2] = { ' ', '\0' }; + int ret; + + /* Eight bits only. Period. */ + c1 &= 0xFF; + c2 &= 0xFF; + + if (c1 == c2) + return (0); + + s1[0] = c1; + s2[0] = c2; + + if ((ret = strcoll (s1, s2)) != 0) + return ret; + return (c1 - c2); +} +#else /* !HAVE_STRCOLL */ +# define rangecmp(c1, c2) ((c1) - (c2)) +#endif /* !HAVE_STRCOLL */ + +#if defined (HAVE_STRCOLL) +static int collequiv (c1, c2) + int c1, c2; +{ + return (rangecmp (c1, c2) == 0); +} +#else +# define collequiv(c1, c2) ((c1) == (c2)) +#endif + +static int +collsym (s, len) + char *s; + int len; +{ + register struct _collsym *csp; + + for (csp = posix_collsyms; csp->name; csp++) + { + if (STREQN(csp->name, s, len) && csp->name[len] == '\0') + return (csp->code); + } + if (len == 1) + return s[0]; + return -1; +} + int fnmatch (pattern, string, flags) char *pattern; char *string; int flags; { - register char *p = pattern, *n = string; - register char c; + char *se, *pe; - if ((flags & ~__FNM_FLAGS) != 0) - { - errno = EINVAL; - return (-1); - } + if (string == 0 || pattern == 0) + return FNM_NOMATCH; + + se = string + strlen (string); + pe = pattern + strlen (pattern); + + return (gmatch (string, se, pattern, pe, flags)); +} + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, FNM_NOMATCH if not. */ +static int +gmatch (string, se, pattern, pe, flags) + char *string, *se; + char *pattern, *pe; + int flags; +{ + register char *p, *n; /* pattern, string */ + register char c; /* current pattern character */ + register char sc; /* current string character */ - while ((c = *p++) != '\0') + p = pattern; + n = string; + + if (string == 0 || pattern == 0) + return FNM_NOMATCH; + + while (p < pe) { + c = *p++; + c = FOLD (c); + + sc = n < se ? *n : '\0'; + +#ifdef EXTENDED_GLOB + if ((flags & FNM_EXTMATCH) && *p == '(' && + (c == '+' || c == '*' || c == '?' || c == '@' || c == '!')) /* ) */ + /* extmatch () will handle recursively calling gmatch, so we can + just return what extmatch() returns. */ + return (extmatch (c, n, se, p, pe, flags)); +#endif + switch (c) { - case '?': - if (*n == '\0') - return (FNM_NOMATCH); - else if ((flags & FNM_PATHNAME) && *n == '/') + case '?': /* Match single character */ + if (sc == '\0') + return FNM_NOMATCH; + else if ((flags & FNM_PATHNAME) && sc == '/') /* If we are matching a pathname, `?' can never match a `/'. */ - return (FNM_NOMATCH); - else if ((flags & FNM_PERIOD) && *n == '.' && + return FNM_NOMATCH; + else if ((flags & FNM_PERIOD) && sc == '.' && (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) /* `?' cannot match a `.' if it is the first character of the string or if it is the first character following a slash and we are matching a pathname. */ - return (FNM_NOMATCH); + return FNM_NOMATCH; break; - case '\\': - if (!(flags & FNM_NOESCAPE)) + case '\\': /* backslash escape removes special meaning */ + if (p == pe) + return FNM_NOMATCH; + + if ((flags & FNM_NOESCAPE) == 0) { c = *p++; - if (c == '\0') - return (FNM_NOMATCH); + /* A trailing `\' cannot match. */ + if (p > pe) + return FNM_NOMATCH; + c = FOLD (c); } - if (*n != c) - return (FNM_NOMATCH); + if (FOLD (sc) != c) + return FNM_NOMATCH; break; - case '*': - if ((flags & FNM_PERIOD) && *n == '.' && + case '*': /* Match zero or more characters */ + if (p == pe) + return 0; + + if ((flags & FNM_PERIOD) && sc == '.' && (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) /* `*' cannot match a `.' if it is the first character of the string or if it is the first character following a slash and we are matching a pathname. */ - return (FNM_NOMATCH); + return FNM_NOMATCH; /* Collapse multiple consecutive, `*' and `?', but make sure that one character of the string is consumed for each `?'. */ - for (c = *p++; c == '?' || c == '*'; c = *p++) + for (c = *p++; (c == '?' || c == '*'); c = *p++) { - if ((flags & FNM_PATHNAME) && *n == '/') + if ((flags & FNM_PATHNAME) && sc == '/') /* A slash does not match a wildcard under FNM_PATHNAME. */ - return (FNM_NOMATCH); + return FNM_NOMATCH; else if (c == '?') { - if (*n == '\0') - return (FNM_NOMATCH); + if (sc == '\0') + return FNM_NOMATCH; /* One character of the string is consumed in matching this ? wildcard, so *??? won't match if there are fewer than three characters. */ n++; + sc = n < se ? *n : '\0'; } + +#ifdef EXTENDED_GLOB + /* Handle ******(patlist) */ + if ((flags & FNM_EXTMATCH) && c == '*' && *p == '(') /*)*/ + return (extmatch (c, n, se, p, pe, flags)); +#endif + if (p == pe) + break; } - if (c == '\0') + /* If we've hit the end of the pattern and the last character of + the pattern was handled by the loop above, we've succeeded. + Otherwise, we need to match that last character. */ + if (p == pe && (c == '?' || c == '*')) return (0); /* General case, use recursion. */ { - char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; - for (--p; *n != '\0'; ++n) + char c1; + + c1 = ((flags & FNM_NOESCAPE) == 0 && c == '\\') ? *p : c; + c1 = FOLD (c1); + for (--p; n < se; ++n) /* Only call fnmatch if the first character indicates a possible match. */ - if ((c == '[' || *n == c1) && - fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + if ((c == '[' || FOLD (*n) == c1) && + gmatch (n, se, p, pe, flags & ~FNM_PERIOD) == 0) return (0); - return (FNM_NOMATCH); + return FNM_NOMATCH; } case '[': { - /* Nonzero if the sense of the character class is inverted. */ - register int not; - - if (*n == '\0') - return (FNM_NOMATCH); + if (sc == '\0' || n == se) + return FNM_NOMATCH; /* A character class cannot match a `.' if it is the first character of the string or if it is the first character following a slash and we are matching a pathname. */ - if ((flags & FNM_PERIOD) && *n == '.' && + if ((flags & FNM_PERIOD) && sc == '.' && (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) return (FNM_NOMATCH); - /* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that - is not preceded by a backslash and is not part of a bracket - expression produces undefined results.' This implementation - treats the `[' as just a character to be matched if there is - not a closing `]'. This code will have to be changed when - POSIX.2 character classes are implemented. */ - { - register char *np; - - for (np = p; np && *np && *np != ']'; np++) - ; - - if (np && !*np) - { - if (*n != '[') - return (FNM_NOMATCH); - break; - } - } - - not = (*p == '!' || *p == '^'); - if (not) - ++p; - - c = *p++; - for (;;) - { - register char cstart, cend; - - /* Initialize cstart and cend in case `-' is the last - character of the pattern. */ - cstart = cend = c; - - if (!(flags & FNM_NOESCAPE) && c == '\\') - { - if (*p == '\0') - return FNM_NOMATCH; - cstart = cend = *p++; - } - - if (c == '\0') - /* [ (unterminated) loses. */ - return (FNM_NOMATCH); - - c = *p++; - - if ((flags & FNM_PATHNAME) && c == '/') - /* [/] can never match. */ - return (FNM_NOMATCH); - - /* This introduces a range, unless the `-' is the last - character of the class. Find the end of the range - and move past it. */ - if (c == '-' && *p != ']') - { - cend = *p++; - if (!(flags & FNM_NOESCAPE) && cend == '\\') - cend = *p++; - if (cend == '\0') - return (FNM_NOMATCH); - - c = *p++; - } - - if (*n >= cstart && *n <= cend) - goto matched; - - if (c == ']') - break; - } - if (!not) - return (FNM_NOMATCH); - break; - - matched: - /* Skip the rest of the [...] that already matched. */ - while (c != ']') - { - if (c == '\0') - /* [... (unterminated) loses. */ - return (FNM_NOMATCH); - - c = *p++; - if (!(flags & FNM_NOESCAPE) && c == '\\') - { - if (*p == '\0') - return FNM_NOMATCH; - /* XXX 1003.2d11 is unclear if this is right. */ - ++p; - } - } - if (not) - return (FNM_NOMATCH); + p = brackmatch (p, sc, flags); + if (p == 0) + return FNM_NOMATCH; } break; default: - if (c != *n) + if (c != FOLD (sc)) return (FNM_NOMATCH); } ++n; } - if (*n == '\0') + if (n == se) return (0); + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return (FNM_NOMATCH); +} + +/* Parse a bracket expression collating symbol ([.sym.]) starting at P, find + the value of the symbol, and move P past the collating symbol expression. + The value is returned in *VP, if VP is not null. */ +static char * +parse_collsym (p, vp) + char *p; + int *vp; +{ + register int pc; + int val; + + p++; /* move past the `.' */ + + for (pc = 0; p[pc]; pc++) + if (p[pc] == '.' && p[pc+1] == ']') + break; + val = collsym (p, pc); + if (vp) + *vp = val; + return (p + pc + 2); +} + +static char * +brackmatch (p, test, flags) + char *p; + unsigned char test; + int flags; +{ + register char cstart, cend, c; + register int not; /* Nonzero if the sense of the character class is inverted. */ + int pc, brcnt; + char *savep; + + test = FOLD (test); + + savep = p; + + /* POSIX.2 3.13.1 says that an exclamation mark (`!') shall replace the + circumflex (`^') in its role in a `nonmatching list'. A bracket + expression starging with an unquoted circumflex character produces + unspecified results. This implementation treats the two identically. */ + if (not = (*p == '!' || *p == '^')) + ++p; + + c = *p++; + for (;;) + { + /* Initialize cstart and cend in case `-' is the last + character of the pattern. */ + cstart = cend = c; + + /* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find + the end of the equivalence class, move the pattern pointer past + it, and check for equivalence. XXX - this handles only + single-character equivalence classes, which is wrong, or at + least incomplete. */ + if (c == '[' && *p == '=' && p[2] == '=' && p[3] == ']') + { + pc = FOLD (p[1]); + p += 4; + if (collequiv (test, pc)) + goto matched; + else + { + c = *p++; + if (c == '\0') + return ((test == '[') ? savep : (char *)0); + c = FOLD (c); + continue; + } + } + + /* POSIX.2 character class expression. See POSIX.2 2.8.3.2. */ + if (c == '[' && *p == ':') + { + pc = 0; /* make sure invalid char classes don't match. */ + if (STREQN (p+1, "alnum:]", 7)) + { pc = isalnum (test); p += 8; } + else if (STREQN (p+1, "alpha:]", 7)) + { pc = isalpha (test); p += 8; } + else if (STREQN (p+1, "blank:]", 7)) + { pc = isblank (test); p += 8; } + else if (STREQN (p+1, "cntrl:]", 7)) + { pc = iscntrl (test); p += 8; } + else if (STREQN (p+1, "digit:]", 7)) + { pc = isdigit (test); p += 8; } + else if (STREQN (p+1, "graph:]", 7)) + { pc = isgraph (test); p += 8; } + else if (STREQN (p+1, "lower:]", 7)) + { pc = ISLOWER (test); p += 8; } + else if (STREQN (p+1, "print:]", 7)) + { pc = isprint (test); p += 8; } + else if (STREQN (p+1, "punct:]", 7)) + { pc = ispunct (test); p += 8; } + else if (STREQN (p+1, "space:]", 7)) + { pc = isspace (test); p += 8; } + else if (STREQN (p+1, "upper:]", 7)) + { pc = ISUPPER (test); p += 8; } + else if (STREQN (p+1, "xdigit:]", 8)) + { pc = isxdigit (test); p += 9; } + else if (STREQN (p+1, "ascii:]", 7)) + { pc = isascii (test); p += 8; } + if (pc) + goto matched; + else + { + /* continue the loop here, since this expression can't be + the first part of a range expression. */ + c = *p++; + if (c == '\0') + return ((test == '[') ? savep : (char *)0); + else if (c == ']') + break; + c = FOLD (c); + continue; + } + } + + /* POSIX.2 collating symbols. See POSIX.2 2.8.3.2. Find the end of + the symbol name, make sure it is terminated by `.]', translate + the name to a character using the external table, and do the + comparison. */ + if (c == '[' && *p == '.') + { + p = parse_collsym (p, &pc); + /* An invalid collating symbol cannot be the first point of a + range. If it is, we set cstart to one greater than `test', + so any comparisons later will fail. */ + cstart = (pc == -1) ? test + 1 : pc; + } + + if (!(flags & FNM_NOESCAPE) && c == '\\') + { + if (*p == '\0') + return (char *)0; + cstart = cend = *p++; + } + + cstart = cend = FOLD (cstart); + + /* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that + is not preceded by a backslash and is not part of a bracket + expression produces undefined results.' This implementation + treats the `[' as just a character to be matched if there is + not a closing `]'. */ + if (c == '\0') + return ((test == '[') ? savep : (char *)0); + + c = *p++; + c = FOLD (c); + + if ((flags & FNM_PATHNAME) && c == '/') + /* [/] can never match when matching a pathname. */ + return (char *)0; + + /* This introduces a range, unless the `-' is the last + character of the class. Find the end of the range + and move past it. */ + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return (char *)0; + if (cend == '[' && *p == '.') + { + p = parse_collsym (p, &pc); + /* An invalid collating symbol cannot be the second part of a + range expression. If we get one, we set cend to one fewer + than the test character to make sure the range test fails. */ + cend = (pc == -1) ? test - 1 : pc; + } + cend = FOLD (cend); + + c = *p++; + + /* POSIX.2 2.8.3.2: ``The ending range point shall collate + equal to or higher than the starting range point; otherwise + the expression shall be treated as invalid.'' Note that this + applies to only the range expression; the rest of the bracket + expression is still checked for matches. */ + if (rangecmp (cstart, cend) > 0) + { + if (c == ']') + break; + c = FOLD (c); + continue; + } + } + + if (rangecmp (test, cstart) >= 0 && rangecmp (test, cend) <= 0) + goto matched; + + if (c == ']') + break; + } + /* No match. */ + return (!not ? (char *)0 : p); + +matched: + /* Skip the rest of the [...] that already matched. */ + brcnt = (c != ']') + (c == '[' && (*p == '=' || *p == ':' || *p == '.')); + while (brcnt > 0) + { + /* A `[' without a matching `]' is just another character to match. */ + if (c == '\0') + return ((test == '[') ? savep : (char *)0); + + c = *p++; + if (c == '[' && (*p == '=' || *p == ':' || *p == '.')) + brcnt++; + else if (c == ']') + brcnt--; + else if (!(flags & FNM_NOESCAPE) && c == '\\') + { + if (*p == '\0') + return (char *)0; + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + } + return (not ? (char *)0 : p); +} + +#if defined (EXTENDED_GLOB) +/* ksh-like extended pattern matching: + + [?*+@!](pat-list) + + where pat-list is a list of one or patterns separated by `|'. Operation + is as follows: + + ?(patlist) match zero or one of the given patterns + *(patlist) match zero or more of the given patterns + +(patlist) match one or more of the given patterns + @(patlist) match exactly one of the given patterns + !(patlist) match anything except one of the given patterns +*/ + +/* Scan a pattern starting at STRING and ending at END, keeping track of + embedded () and []. If DELIM is 0, we scan until a matching `)' + because we're scanning a `patlist'. Otherwise, we scan until we see + DELIM. In all cases, we never scan past END. The return value is the + first character after the matching DELIM. */ +static char * +patscan (string, end, delim) + char *string, *end; + int delim; +{ + int pnest, bnest; + char *s, c; + + pnest = bnest = 0; + for (s = string; c = *s; s++) + { + switch (c) + { + case '\0': + return ((char *)0); + case '[': + bnest++; + break; + case ']': + if (bnest) + bnest--; + break; + case '(': + if (bnest == 0) + pnest++; + break; + case ')': + if (bnest == 0) + pnest--; + if (pnest <= 0) + return ++s; + break; + case '|': + if (bnest == 0 && pnest == 0 && delim == '|') + return ++s; + break; + } + } + return (char *)0; +} + +/* Return 0 if dequoted pattern matches S in the current locale. */ +static int +strcompare (p, pe, s, se) + char *p, *pe, *s, *se; +{ + int ret; + char c1, c2; + + c1 = *pe; + c2 = *se; + + *pe = *se = '\0'; +#if defined (HAVE_STRCOLL) + ret = strcoll (p, s); +#else + ret = strcmp (p, s); +#endif + + *pe = c1; + *se = c2; + + return (ret == 0 ? ret : FNM_NOMATCH); +} + +/* Match a ksh extended pattern specifier. Return FNM_NOMATCH on failure or + 0 on success. This is handed the entire rest of the pattern and string + the first time an extended pattern specifier is encountered, so it calls + gmatch recursively. */ +static int +extmatch (xc, s, se, p, pe, flags) + int xc; /* select which operation */ + char *s, *se; + char *p, *pe; + int flags; +{ + char *prest; /* pointer to rest of pattern */ + char *psub; /* pointer to sub-pattern */ + char *pnext; /* pointer to next sub-pattern */ + char *srest; /* pointer to rest of string */ + int m1, m2; + + switch (xc) + { + case '+': /* match one or more occurrences */ + case '*': /* match zero or more occurrences */ + prest = patscan (p, pe, 0); + if (prest == 0) + /* If PREST is 0, we failed to scan a valid pattern. In this + case, we just want to compare the two as strings. */ + return (strcompare (p - 1, pe, s, se)); + + /* If we can get away with no matches, don't even bother. Just + call gmatch on the rest of the pattern and return success if + it succeeds. */ + if (xc == '*' && (gmatch (s, se, prest, pe, flags) == 0)) + return 0; + + /* OK, we have to do this the hard way. First, we make sure one of + the subpatterns matches, then we try to match the rest of the + string. */ + for (psub = p + 1; ; psub = pnext) + { + pnext = patscan (psub, pe, '|'); + for (srest = s; srest <= se; srest++) + { + /* Match this substring (S -> SREST) against this + subpattern (psub -> pnext - 1) */ + m1 = gmatch (s, srest, psub, pnext - 1, flags) == 0; + /* OK, we matched a subpattern, so make sure the rest of the + string matches the rest of the pattern. Also handle + multiple matches of the pattern. */ + if (m1) + m2 = (gmatch (srest, se, prest, pe, flags) == 0) || + (s != srest && gmatch (srest, se, p - 1, pe, flags) == 0); + if (m1 && m2) + return (0); + } + if (pnext == prest) + break; + } + return (FNM_NOMATCH); + + case '?': /* match zero or one of the patterns */ + case '@': /* match exactly one of the patterns */ + prest = patscan (p, pe, 0); + if (prest == 0) + return (strcompare (p - 1, pe, s, se)); + + /* If we can get away with no matches, don't even bother. Just + call gmatch on the rest of the pattern and return success if + it succeeds. */ + if (xc == '?' && (gmatch (s, se, prest, pe, flags) == 0)) + return 0; + + /* OK, we have to do this the hard way. First, we see if one of + the subpatterns matches, then, if it does, we try to match the + rest of the string. */ + for (psub = p + 1; ; psub = pnext) + { + pnext = patscan (psub, pe, '|'); + srest = (prest == pe) ? se : s; + for ( ; srest <= se; srest++) + { + if (gmatch (s, srest, psub, pnext - 1, flags) == 0 && + gmatch (srest, se, prest, pe, flags) == 0) + return (0); + } + if (pnext == prest) + break; + } + return (FNM_NOMATCH); + + case '!': /* match anything *except* one of the patterns */ + prest = patscan (p, pe, 0); + if (prest == 0) + return (strcompare (p - 1, pe, s, se)); + + for (srest = s; srest <= se; srest++) + { + m1 = 0; + for (psub = p + 1; ; psub = pnext) + { + pnext = patscan (psub, pe, '|'); + /* If one of the patterns matches, just bail immediately. */ + if (m1 = (gmatch (s, srest, psub, pnext - 1, flags) == 0)) + break; + if (pnext == prest) + break; + } + if (m1 == 0 && gmatch (srest, se, prest, pe, flags) == 0) + return (0); + } + return (FNM_NOMATCH); + } + return (FNM_NOMATCH); } +#endif /* EXTENDED_GLOB */ + +#ifdef TEST +main (c, v) + int c; + char **v; +{ + char *string, *pat; + + string = v[1]; + pat = v[2]; + + if (fnmatch (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/fnmatch.h b/lib/glob/fnmatch.h index 62c8c8fa..ac0ba202 100644 --- a/lib/glob/fnmatch.h +++ b/lib/glob/fnmatch.h @@ -17,14 +17,24 @@ not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _FNMATCH_H - #define _FNMATCH_H 1 +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in <unistd.h>. */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + /* Bits set in the FLAGS argument to `fnmatch'. */ -#define FNM_PATHNAME (1 << 0)/* No wildcard can ever match `/'. */ -#define FNM_NOESCAPE (1 << 1)/* Backslashes don't quote special chars. */ -#define FNM_PERIOD (1 << 2)/* Leading `.' is matched only explicitly. */ -#define __FNM_FLAGS (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD) +/* standard flags */ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ + +/* extended flags */ +#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#define FNM_EXTMATCH (1 << 5) /* Use ksh-like extended matching. */ /* Value returned by `fnmatch' if STRING does not match PATTERN. */ #define FNM_NOMATCH 1 @@ -33,4 +43,4 @@ Cambridge, MA 02139, USA. */ returning zero if it matches, FNM_NOMATCH if not. */ extern int fnmatch(); -#endif /* fnmatch.h */ +#endif /* _FNMATCH_H */ diff --git a/lib/glob/glob.c b/lib/glob/glob.c index 6d2f58fa..6a9679fc 100644 --- a/lib/glob/glob.c +++ b/lib/glob/glob.c @@ -25,20 +25,29 @@ #pragma alloca #endif /* _AIX && RISC6000 && !__GNUC__ */ +#if defined (SHELL) +# include "bashtypes.h" +#else +# include <sys/types.h> +#endif + #if defined (HAVE_UNISTD_H) # include <unistd.h> #endif -#if defined (HAVE_STDLIB_H) -# include <stdlib.h> +#if defined (SHELL) +# include "bashansi.h" #else -# if defined (SHELL) -# include "ansi_stdlib.h" -# endif /* SHELL */ +# if defined (HAVE_STDLIB_H) +# include <stdlib.h> +# endif +# if defined (HAVE_STRING_H) +# include <string.h> +# else /* !HAVE_STRING_H */ +# include <strings.h> +# endif /* !HAVE_STRING_H */ #endif -#include <sys/types.h> - #if defined (HAVE_DIRENT_H) # include <dirent.h> # define D_NAMLEN(d) strlen ((d)->d_name) @@ -66,27 +75,25 @@ # define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) #endif /* _POSIX_SOURCE */ -#if defined (HAVE_STRING_H) -# include <string.h> -#else /* !HAVE_STRING_H */ -# include <strings.h> -#endif /* !HAVE_STRING_H */ - #if !defined (HAVE_BCOPY) # define bcopy(s, d, n) ((void) memcpy ((d), (s), (n))) #endif /* !HAVE_BCOPY */ -/* If the opendir () on your system lets you open non-directory files, - then we consider that not robust. */ -#if defined (OPENDIR_NOT_ROBUST) -# if defined (SHELL) -# include "posixstat.h" -# else /* !SHELL */ -# include <sys/stat.h> -# endif /* !SHELL */ -#endif /* OPENDIR_NOT_ROBUST */ - -#include "memalloc.h" +#if defined (SHELL) +# include "posixstat.h" +#else /* !SHELL */ +# include <sys/stat.h> +#endif /* !SHELL */ + +#include "filecntl.h" +#if !defined (F_OK) +# define F_OK 0 +#endif + +#if defined (SHELL) +# include "memalloc.h" +#endif + #include "fnmatch.h" #if !defined (HAVE_STDLIB_H) && !defined (SHELL) @@ -104,14 +111,20 @@ extern void free (); #if defined (SHELL) extern void throw_to_top_level (); +extern int test_eaccess (); extern int interrupt_state; +extern int extended_glob; #endif /* SHELL */ /* 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; @@ -120,9 +133,12 @@ int glob_pattern_p (pattern) char *pattern; { - register char *p = pattern; + register char *p; register char c; - int open = 0; + int bopen; + + p = pattern; + bopen = 0; while ((c = *p++) != '\0') switch (c) @@ -132,13 +148,20 @@ glob_pattern_p (pattern) return (1); case '[': /* Only accept an open brace if there is a close */ - open++; /* brace to match it. Bracket expressions must be */ + bopen++; /* brace to match it. Bracket expressions must be */ continue; /* complete, according to Posix.2 */ case ']': - if (open) + if (bopen) return (1); continue; + case '+': /* extended matching operators */ + case '@': + case '!': + if (*p == '(') /*) */ + return (1); + continue; + case '\\': if (*p++ == '\0') return (0); @@ -168,6 +191,35 @@ dequote_pathname (pathname) } + +/* Test whether NAME exists. */ + +#if defined (HAVE_LSTAT) +# define GLOB_TESTNAME(name) (lstat (name, &finfo)) +#else /* !HAVE_LSTAT */ +# if defined (SHELL) && !defined (AFS) +# define GLOB_TESTNAME(name) (test_eaccess (nextname, F_OK)) +# else /* !SHELL || AFS */ +# define GLOB_TESTNAME(name) (access (nextname, F_OK)) +# endif /* !SHELL || AFS */ +#endif /* !HAVE_LSTAT */ + +/* Return 0 if DIR is a directory, -1 otherwise. */ +static int +glob_testdir (dir) + char *dir; +{ + struct stat finfo; + + if (stat (dir, &finfo) < 0) + return (-1); + + if (S_ISDIR (finfo.st_mode) == 0) + return (-1); + + return (0); +} + /* Return a vector of names of files in directory DIR whose names match glob pattern PAT. The names are not in any particular order. @@ -204,103 +256,161 @@ glob_vector (pat, dir) int lose, skip; register char **name_vector; register unsigned int i; -#if defined (OPENDIR_NOT_ROBUST) - struct stat finfo; - - if (stat (dir, &finfo) < 0) - return ((char **) &glob_error_return); - - if (!S_ISDIR (finfo.st_mode)) - return ((char **) &glob_error_return); -#endif /* OPENDIR_NOT_ROBUST */ - - d = opendir (dir); - if (d == NULL) - return ((char **) &glob_error_return); + int flags; /* Flags passed to fnmatch (). */ lastlink = 0; - count = 0; - lose = 0; - skip = 0; + count = lose = skip = 0; /* If PAT is empty, skip the loop, but return one (empty) filename. */ - if (!pat || !*pat) + if (pat == 0 || *pat == '\0') { + if (glob_testdir (dir) < 0) + return ((char **) &glob_error_return); + nextlink = (struct globval *)alloca (sizeof (struct globval)); - nextlink->next = lastlink; + nextlink->next = (struct globval *)0; nextname = (char *) malloc (1); - if (!nextname) + if (nextname == 0) lose = 1; else { lastlink = nextlink; nextlink->name = nextname; nextname[0] = '\0'; - count++; + count = 1; } + skip = 1; } - /* Scan the directory, finding all names that match. - For each name that matches, allocate a struct globval - on the stack and store the name in it. - Chain those structs together; lastlink is the front of the chain. */ - while (!skip) + /* 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 flags; /* Flags passed to fnmatch (). */ -#if defined (SHELL) - /* Make globbing interruptible in the bash shell. */ - if (interrupt_state) + 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); + if (nextname == 0) + lose = 1; + else { - closedir (d); - lose = 1; - goto lost; + strcpy (nextname, dir); + nextname[dirlen++] = '/'; + strcpy (nextname + dirlen, pat); + + if (GLOB_TESTNAME (nextname) >= 0) + { + free (nextname); + nextlink = (struct globval *)alloca (sizeof (struct globval)); + nextlink->next = (struct globval *)0; + nextname = (char *) malloc (strlen (pat) + 1); + if (nextname == 0) + lose = 1; + else + { + lastlink = nextlink; + nextlink->name = nextname; + strcpy (nextname, pat); + count = 1; + } + } + else + free (nextname); } -#endif /* SHELL */ - - dp = readdir (d); - if (dp == NULL) - break; - /* If this directory entry is not to be used, try again. */ - if (!REAL_DIR_ENTRY (dp)) - continue; + skip = 1; + } - /* If a dot must be explicity matched, check to see if they do. */ - if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.' && - (pat[0] != '\\' || pat[1] != '.')) - continue; + 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 fnmatch(). We don't + need to do this every time through the loop. */ flags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME; - if (fnmatch (pat, dp->d_name, flags) != FNM_NOMATCH) +#ifdef FNM_CASEFOLD + if (glob_ignore_case) + flags |= FNM_CASEFOLD; +#endif + +#ifdef SHELL + if (extended_glob) + flags |= FNM_EXTMATCH; +#endif + + /* 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) { - nextlink = (struct globval *) alloca (sizeof (struct globval)); - nextlink->next = lastlink; - nextname = (char *) malloc (D_NAMLEN (dp) + 1); - if (nextname == NULL) +#if defined (SHELL) + /* Make globbing interruptible in the shell. */ + if (interrupt_state) { lose = 1; break; } - lastlink = nextlink; - nextlink->name = nextname; - bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1); - ++count; +#endif /* SHELL */ + + dp = readdir (d); + if (dp == NULL) + break; + + /* If this directory entry is not to be used, try again. */ + if (REAL_DIR_ENTRY (dp) == 0) + continue; + + /* If a dot must be explicity matched, check to see if they do. */ + if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.' && + (pat[0] != '\\' || pat[1] != '.')) + continue; + + if (fnmatch (pat, dp->d_name, flags) != FNM_NOMATCH) + { + nextlink = (struct globval *) alloca (sizeof (struct globval)); + nextlink->next = lastlink; + nextname = (char *) malloc (D_NAMLEN (dp) + 1); + if (nextname == NULL) + { + lose = 1; + break; + } + lastlink = nextlink; + nextlink->name = nextname; + bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1); + ++count; + } } + + (void) closedir (d); } - (void) closedir (d); - if (!lose) + if (lose == 0) { name_vector = (char **) malloc ((count + 1) * sizeof (char *)); lose |= name_vector == NULL; } /* Have we run out of memory? */ -#if defined (SHELL) - lost: -#endif if (lose) { /* Here free the strings we have got. */ @@ -313,7 +423,8 @@ glob_vector (pat, dir) if (interrupt_state) throw_to_top_level (); #endif /* SHELL */ - return (NULL); + + return ((char **)NULL); } /* Copy the name pointers from the linked list into the vector. */ diff --git a/lib/glob/glob.h b/lib/glob/glob.h index a72dede1..ac83f1ef 100644 --- a/lib/glob/glob.h +++ b/lib/glob/glob.h @@ -26,5 +26,6 @@ extern char **glob_filename __P((char *)); extern char *glob_error_return; extern int noglob_dot_filenames; +extern int glob_ignore_case; #endif /* _GLOB_H_ */ diff --git a/lib/malloc/getpagesize.h b/lib/malloc/getpagesize.h index 0b75b898..6085a5c5 100644 --- a/lib/malloc/getpagesize.h +++ b/lib/malloc/getpagesize.h @@ -16,6 +16,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> # if defined (_SC_PAGESIZE) # define getpagesize() sysconf(_SC_PAGESIZE) @@ -27,7 +30,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #endif #if !defined (getpagesize) -# include <sys/param.h> +# ifndef _MINIX +# include <sys/param.h> +# endif # if defined (PAGESIZE) # define getpagesize() PAGESIZE # else /* !PAGESIZE */ diff --git a/lib/malloc/gmalloc.c b/lib/malloc/gmalloc.c index 8690b126..dd24146d 100644 --- a/lib/malloc/gmalloc.c +++ b/lib/malloc/gmalloc.c @@ -1,7 +1,3 @@ -/* DO NOT EDIT THIS FILE -- it is automagically generated. -*- C -*- */ - -#define _MALLOC_INTERNAL - /* The malloc headers and source files from the C library follow here. */ /* Declarations for `malloc' and friends. @@ -20,118 +16,173 @@ Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. +ot, write to the Free Software Foundation, Inc., 59 Temple Place - +Suite 330, Boston, MA 02111-1307, USA. The author may be reached (Email) at the address mike@ai.mit.edu, or (US mail) as Mike Haertel c/o Free Software Foundation. */ -#ifndef _MALLOC_H - -#define _MALLOC_H 1 +/* XXX NOTES: + 1. Augment the mstats struct so we can see how many blocks for fragments + and how many blocks for large requests were allocated. +*/ -#ifdef _MALLOC_INTERNAL +/* CHANGES: + 1. Reorganized the source for my benefit. + 2. Integrated the range-checking code by default. + 3. free(0) no longer dumps core. + 4. Extended the statistics. + 5. Fixed a couple of places where the stats were not kept correctly. +*/ #ifdef HAVE_CONFIG_H #include <config.h> #endif -#if defined(_LIBC) || defined(STDC_HEADERS) || defined(USG) -#include <string.h> +#if defined (HAVE_STRING_H) +# include <string.h> #else -#ifndef memset -#define memset(s, zero, n) bzero ((s), (n)) -#endif -#ifndef memcpy -#define memcpy(d, s, n) bcopy ((s), (d), (n)) -#endif +# include <strings.h> #endif -#if defined (__GNU_LIBRARY__) || (defined (__STDC__) && __STDC__) -#include <limits.h> -#else -#ifndef CHAR_BIT -#define CHAR_BIT 8 +#if defined (HAVE_LIMITS_H) +# include <limits.h> #endif + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif +# include <unistd.h> #endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> +#if defined (HAVE_STDDEF_H) +# include <stddef.h> #endif +#include <errno.h> -#endif /* _MALLOC_INTERNAL. */ +#if defined (RCHECK) && !defined (botch) +# include <stdio.h> +# define STDIO_H_INCLUDED +#endif +#include "stdc.h" -#ifdef __cplusplus -extern "C" -{ +#ifndef errno +extern int errno; #endif -#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) -#undef __P -#define __P(args) args -#undef __ptr_t -#define __ptr_t void * -#else /* Not C++ or ANSI C. */ -#undef __P -#define __P(args) () -#undef const -#define const -#undef __ptr_t -#define __ptr_t char * -#endif /* C++ or ANSI C. */ - -#if defined (__STDC__) && __STDC__ -#include <stddef.h> -#define __malloc_size_t size_t -#define __malloc_ptrdiff_t ptrdiff_t +/* Need an autoconf test for this. */ +#if __STDC__ +# undef genptr_t +# define genptr_t void * #else -#define __malloc_size_t unsigned int -#define __malloc_ptrdiff_t int +# undef genptr_t +# define genptr_t char * +#endif /* !__STDC__ */ + +#if !defined (HAVE_MEMSET) +# define memset(s, zero, n) bzero ((s), (n)) +#endif +#if !defined (HAVE_MEMCPY) +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +#endif + +/* Cope with systems lacking `memmove'. */ +#if !defined (HAVE_MEMMOVE) && !defined (memmove) +static void malloc_safe_bcopy __P ((genptr_t, genptr_t, size_t)); +# define memmove(to, from, size) malloc_safe_bcopy ((from), (to), (size)) #endif #ifndef NULL #define NULL 0 #endif +#ifndef min +#define min(A, B) ((A) < (B) ? (A) : (B)) +#endif + +/* Return values for `mprobe': these are the kinds of inconsistencies that + `mcheck' enables detection of. */ +enum mcheck_status + { + MCHECK_DISABLED = -1, /* Consistency checking is not turned on. */ + MCHECK_OK, /* Block is fine. */ + MCHECK_FREE, /* Block freed twice. */ + MCHECK_HEAD, /* Memory before the block was clobbered. */ + MCHECK_TAIL /* Memory after the block was clobbered. */ + }; + +/* Statistics available to the user. */ +struct mstats + { + size_t bytes_total; /* Total size of the heap. */ + size_t chunks_used; /* Chunks allocated by the user. */ + size_t bytes_used; /* Byte total of user-allocated chunks. */ + size_t chunks_free; /* Chunks in the free list. */ + size_t bytes_free; /* Byte total of chunks in the free list. */ + int nmalloc; /* Total number of calls to malloc. */ + int nfree; /* Total number of calls to free. */ + int nrealloc; /* Total number of calls to realloc. */ + int nsbrk; /* Total number of calls to sbrk. */ + size_t tsbrk; /* Total number of bytes allocated via sbrk. */ + int negsbrk; /* Total number of calls to sbrk with a negative arg */ + size_t tnegsbrk; /* Total number of bytes returned to the kernel. */ + }; + +#ifdef RCHECK +/* Arbitrary magical numbers. */ +#define MAGICWORD 0xfedabeeb +#define MAGICFREE 0xd8675309 +#define MAGICBYTE ((char) 0xd7) +#define MALLOCFLOOD ((char) 0x93) +#define FREEFLOOD ((char) 0x95) +struct hdr + { + size_t size; /* Exact size requested by user. */ + u_int32_t magic; /* Magic number to check header integrity. */ + }; +#endif /* RCHECK */ + +/* Functions exported by this library. */ /* Allocate SIZE bytes of memory. */ -extern __ptr_t malloc __P ((__malloc_size_t __size)); +extern genptr_t malloc __P ((size_t __size)); + /* Re-allocate the previously allocated block - in __ptr_t, making the new block SIZE bytes long. */ -extern __ptr_t realloc __P ((__ptr_t __ptr, __malloc_size_t __size)); + in genptr_t, making the new block SIZE bytes long. */ +extern genptr_t realloc __P ((genptr_t __ptr, size_t __size)); + /* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ -extern __ptr_t calloc __P ((__malloc_size_t __nmemb, __malloc_size_t __size)); +extern genptr_t calloc __P ((size_t __nmemb, size_t __size)); + /* Free a block allocated by `malloc', `realloc' or `calloc'. */ -extern void free __P ((__ptr_t __ptr)); +extern void free __P ((genptr_t __ptr)); /* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ -#if ! (defined (_MALLOC_INTERNAL) && __DJGPP__ - 0 == 1) /* Avoid conflict. */ -extern __ptr_t memalign __P ((__malloc_size_t __alignment, - __malloc_size_t __size)); -#endif +extern genptr_t memalign __P ((size_t __alignment, size_t __size)); -/* Allocate SIZE bytes on a page boundary. */ -#if ! (defined (_MALLOC_INTERNAL) && defined (emacs)) /* Avoid conflict. */ -extern __ptr_t valloc __P ((__malloc_size_t __size)); -#endif +/* Pick up the current statistics. */ +extern struct mstats mstats __P ((void)); +#ifdef RCHECK +extern enum mcheck_status mprobe __P((genptr_t ptr)); +#endif -#ifdef _MALLOC_INTERNAL +/* End of exported functions. */ /* The allocator divides the heap into blocks of fixed size; large requests receive one or more whole blocks, and small requests receive a fragment of a block. Fragment sizes are powers of two, and all fragments of a block are the same size. When all the fragments in a block have been freed, the block itself is freed. */ -#define INT_BIT (CHAR_BIT * sizeof(int)) -#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) -#define BLOCKSIZE (1 << BLOCKLOG) +#define BLOCKLOG 12 +#define BLOCKSIZE 4096 /* 1 << BLOCKLOG */ #define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) /* Determine the amount of memory spanned by the initial heap table (not an absolute limit). */ -#define HEAP (INT_BIT > 16 ? 4194304 : 65536) +#define HEAP 4194304 /* 1 << 22 */ /* Number of contiguous free blocks allowed to build up at the end of memory before they will be returned to the system. */ @@ -150,40 +201,43 @@ typedef union { struct { - __malloc_size_t nfree; /* Free frags in a fragmented block. */ - __malloc_size_t first; /* First free fragment of the block. */ + size_t nfree; /* Free frags in a fragmented block. */ + size_t first; /* First free fragment of the block. */ } frag; /* For a large object, in its first block, this has the number of blocks in the object. In the other blocks, this has a negative number which says how far back the first block is. */ - __malloc_ptrdiff_t size; + ptrdiff_t size; } info; } busy; - /* Heap information for a free block - (that may be the first of a free cluster). */ + /* Heap information for a free block (that may be the first of a + free cluster). */ struct { - __malloc_size_t size; /* Size (in blocks) of a free cluster. */ - __malloc_size_t next; /* Index of next free cluster. */ - __malloc_size_t prev; /* Index of previous free cluster. */ + size_t size; /* Size (in blocks) of a free cluster. */ + size_t next; /* Index of next free cluster. */ + size_t prev; /* Index of previous free cluster. */ } free; } malloc_info; /* Pointer to first block of the heap. */ -extern char *_heapbase; +static char *_heapbase; /* Table indexed by block number giving per-block information. */ -extern malloc_info *_heapinfo; +static malloc_info *_heapinfo; /* Address to block number and vice versa. */ #define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) -#define ADDRESS(B) ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase)) +#define ADDRESS(B) ((genptr_t) (((B) - 1) * BLOCKSIZE + _heapbase)) + +/* Number of info entries. */ +static size_t heapsize; /* Current search index for the heap table. */ -extern __malloc_size_t _heapindex; +static size_t _heapindex; /* Limit of valid info table indices. */ -extern __malloc_size_t _heaplimit; +static size_t _heaplimit; /* Doubly linked lists of free fragments. */ struct list @@ -193,270 +247,127 @@ struct list }; /* Free list headers for each fragment size. */ -extern struct list _fraghead[]; +static struct list _fraghead[BLOCKLOG]; -/* List of blocks allocated with `memalign' (or `valloc'). */ +/* List of blocks allocated with `memalign'. */ struct alignlist { struct alignlist *next; - __ptr_t aligned; /* The address that memaligned returned. */ - __ptr_t exact; /* The address that malloc returned. */ + genptr_t aligned; /* The address that memaligned returned. */ + genptr_t exact; /* The address that malloc returned. */ }; -extern struct alignlist *_aligned_blocks; -/* Instrumentation. */ -extern __malloc_size_t _chunks_used; -extern __malloc_size_t _bytes_used; -extern __malloc_size_t _chunks_free; -extern __malloc_size_t _bytes_free; +/* List of blocks allocated by memalign. */ +static struct alignlist *_aligned_blocks = NULL; /* Internal versions of `malloc', `realloc', and `free' - used when these functions need to call each other. - They are the same but don't call the hooks. */ -extern __ptr_t _malloc_internal __P ((__malloc_size_t __size)); -extern __ptr_t _realloc_internal __P ((__ptr_t __ptr, __malloc_size_t __size)); -extern void _free_internal __P ((__ptr_t __ptr)); - -#endif /* _MALLOC_INTERNAL. */ + used when these functions need to call each other. */ +static genptr_t imalloc __P ((size_t __size)); +static genptr_t irealloc __P ((genptr_t __ptr, size_t __size)); +static void ifree __P ((genptr_t __ptr)); /* Given an address in the middle of a malloc'd object, return the address of the beginning of the object. */ -extern __ptr_t malloc_find_object_address __P ((__ptr_t __ptr)); +static genptr_t malloc_find_object_address __P ((genptr_t __ptr)); /* Underlying allocation function; successive calls should return contiguous pieces of memory. */ -extern __ptr_t (*__morecore) __P ((__malloc_ptrdiff_t __size)); - -/* Default value of `__morecore'. */ -extern __ptr_t __default_morecore __P ((__malloc_ptrdiff_t __size)); - -/* If not NULL, this function is called after each time - `__morecore' is called to increase the data size. */ -extern void (*__after_morecore_hook) __P ((void)); +static genptr_t default_morecore __P ((ptrdiff_t __size)); /* Number of extra blocks to get each time we ask for more core. - This reduces the frequency of calling `(*__morecore)'. */ -extern __malloc_size_t __malloc_extra_blocks; + This reduces the frequency of calling `default_morecore'. */ +static size_t malloc_extra_blocks; /* Nonzero if `malloc' has been called and done its initialization. */ -extern int __malloc_initialized; +static int malloc_initialized; /* Function called to initialize malloc data structures. */ -extern int __malloc_initialize __P ((void)); +static int malloc_initialize __P ((void)); -/* Hooks for debugging versions. */ -extern void (*__malloc_initialize_hook) __P ((void)); -extern void (*__free_hook) __P ((__ptr_t __ptr)); -extern __ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); -extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); -extern __ptr_t (*__memalign_hook) __P ((__malloc_size_t __size, - __malloc_size_t __alignment)); - -/* Return values for `mprobe': these are the kinds of inconsistencies that - `mcheck' enables detection of. */ -enum mcheck_status - { - MCHECK_DISABLED = -1, /* Consistency checking is not turned on. */ - MCHECK_OK, /* Block is fine. */ - MCHECK_FREE, /* Block freed twice. */ - MCHECK_HEAD, /* Memory before the block was clobbered. */ - MCHECK_TAIL /* Memory after the block was clobbered. */ - }; - -/* Activate a standard collection of debugging hooks. This must be called - before `malloc' is ever called. ABORTFUNC is called with an error code - (see enum above) when an inconsistency is detected. If ABORTFUNC is - null, the standard function prints on stderr and then calls `abort'. */ -extern int mcheck __P ((void (*__abortfunc) __P ((enum mcheck_status)))); - -/* Check for aberrations in a particular malloc'd block. You must have - called `mcheck' already. These are the same checks that `mcheck' does - when you free or reallocate a block. */ -extern enum mcheck_status mprobe __P ((__ptr_t __ptr)); - -/* Activate a standard collection of tracing hooks. */ -extern void mtrace __P ((void)); -extern void muntrace __P ((void)); - -/* Statistics available to the user. */ -struct mstats - { - __malloc_size_t bytes_total; /* Total size of the heap. */ - __malloc_size_t chunks_used; /* Chunks allocated by the user. */ - __malloc_size_t bytes_used; /* Byte total of user-allocated chunks. */ - __malloc_size_t chunks_free; /* Chunks in the free list. */ - __malloc_size_t bytes_free; /* Byte total of chunks in the free list. */ - }; - -/* Pick up the current statistics. */ -extern struct mstats mstats __P ((void)); - -/* Call WARNFUN with a warning message when memory usage is high. */ -extern void memory_warnings __P ((__ptr_t __start, - void (*__warnfun) __P ((const char *)))); - - -/* Relocating allocator. */ - -/* Allocate SIZE bytes, and store the address in *HANDLEPTR. */ -extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); - -/* Free the storage allocated in HANDLEPTR. */ -extern void r_alloc_free __P ((__ptr_t *__handleptr)); - -/* Adjust the block at HANDLEPTR to be SIZE bytes long. */ -extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); - - -#ifdef __cplusplus -} +#ifdef RCHECK +static void zmemset __P((genptr_t, int, size_t)); +static enum mcheck_status checkhdr __P((const struct hdr *)); +static void mabort __P((enum mcheck_status)); #endif -#endif /* malloc.h */ -/* Memory allocator `malloc'. - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. - Written May 1989 by Mike Haertel. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include <malloc.h> -#endif -#include <errno.h> - -/* How to really get more memory. */ -__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore; - -/* Debugging hook for `malloc'. */ -__ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); - -/* Pointer to the base of the first block. */ -char *_heapbase; - -/* Block information table. Allocated with align/__free (not malloc/free). */ -malloc_info *_heapinfo; - -/* Number of info entries. */ -static __malloc_size_t heapsize; - -/* Search index in the info table. */ -__malloc_size_t _heapindex; - -/* Limit of valid info table indices. */ -__malloc_size_t _heaplimit; - -/* Free lists for each fragment size. */ -struct list _fraghead[BLOCKLOG]; - /* Instrumentation. */ -__malloc_size_t _chunks_used; -__malloc_size_t _bytes_used; -__malloc_size_t _chunks_free; -__malloc_size_t _bytes_free; - -/* Are you experienced? */ -int __malloc_initialized; - -__malloc_size_t __malloc_extra_blocks; - -void (*__malloc_initialize_hook) __P ((void)); -void (*__after_morecore_hook) __P ((void)); - +static size_t chunks_used; +static size_t bytes_used; +static size_t chunks_free; +static size_t bytes_free; +static int nmalloc, nfree, nrealloc; +static int nsbrk; +static size_t tsbrk; +static int negsbrk; +static size_t tnegsbrk; /* Aligned allocation. */ -static __ptr_t align __P ((__malloc_size_t)); -static __ptr_t +static genptr_t align (size) - __malloc_size_t size; + size_t size; { - __ptr_t result; + genptr_t result; unsigned long int adj; - result = (*__morecore) (size); + result = default_morecore (size); adj = (unsigned long int) ((unsigned long int) ((char *) result - (char *) NULL)) % BLOCKSIZE; if (adj != 0) { - __ptr_t new; + genptr_t new; adj = BLOCKSIZE - adj; - new = (*__morecore) (adj); + new = default_morecore (adj); result = (char *) result + adj; } - if (__after_morecore_hook) - (*__after_morecore_hook) (); - return result; } /* Get SIZE bytes, if we can get them starting at END. Return the address of the space we got. If we cannot get space at END, fail and return -1. */ -static __ptr_t get_contiguous_space __P ((__malloc_ptrdiff_t, __ptr_t)); -static __ptr_t +static genptr_t get_contiguous_space (size, position) - __malloc_ptrdiff_t size; - __ptr_t position; + ptrdiff_t size; + genptr_t position; { - __ptr_t before; - __ptr_t after; + genptr_t before; + genptr_t after; - before = (*__morecore) (0); + before = default_morecore (0); /* If we can tell in advance that the break is at the wrong place, fail now. */ if (before != position) return 0; /* Allocate SIZE bytes and get the address of them. */ - after = (*__morecore) (size); + after = default_morecore (size); if (!after) return 0; /* It was not contiguous--reject it. */ if (after != position) { - (*__morecore) (- size); + default_morecore (- size); return 0; } return after; } - /* This is called when `_heapinfo' and `heapsize' have just been set to describe a new info table. Set up the table to describe itself and account for it in the statistics. */ -static void register_heapinfo __P ((void)); -#ifdef __GNUC__ -__inline__ -#endif -static void +inline static void register_heapinfo () { - __malloc_size_t block, blocks; + size_t block, blocks; block = BLOCK (_heapinfo); blocks = BLOCKIFY (heapsize * sizeof (malloc_info)); /* Account for the _heapinfo block itself in the statistics. */ - _bytes_used += blocks * BLOCKSIZE; - ++_chunks_used; + bytes_used += blocks * BLOCKSIZE; + ++chunks_used; /* Describe the heapinfo block itself in the heapinfo. */ _heapinfo[block].busy.type = 0; @@ -467,15 +378,12 @@ register_heapinfo () } /* Set everything up and remember that we have. */ -int -__malloc_initialize () +static int +malloc_initialize () { - if (__malloc_initialized) + if (malloc_initialized) return 0; - if (__malloc_initialize_hook) - (*__malloc_initialize_hook) (); - heapsize = HEAP / BLOCKSIZE; _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info)); if (_heapinfo == NULL) @@ -489,22 +397,43 @@ __malloc_initialize () register_heapinfo (); - __malloc_initialized = 1; + malloc_initialized = 1; return 1; } +/* Allocate INCREMENT more bytes of data space, + and return the start of data space, or NULL on errors. + If INCREMENT is negative, shrink data space. */ +static genptr_t +default_morecore (increment) + ptrdiff_t increment; +{ + genptr_t result; + + nsbrk++; + tsbrk += increment; + if (increment < 0) + { + negsbrk++; + tnegsbrk += -increment; + } + result = (genptr_t) sbrk (increment); + if ((long)result == -1L) + return NULL; + return result; +} + static int morecore_recursing; /* Get neatly aligned memory, initializing or growing the heap info table as necessary. */ -static __ptr_t morecore __P ((__malloc_size_t)); -static __ptr_t +static genptr_t morecore (size) - __malloc_size_t size; + size_t size; { - __ptr_t result; + genptr_t result; malloc_info *newinfo, *oldinfo; - __malloc_size_t newsize; + size_t newsize; if (morecore_recursing) /* Avoid recursion. The caller will know how to handle a null return. */ @@ -515,7 +444,7 @@ morecore (size) return NULL; /* Check if we need to grow the info table. */ - if ((__malloc_size_t) BLOCK ((char *) result + size) > heapsize) + if ((size_t) BLOCK ((char *) result + size) > heapsize) { /* Calculate the new _heapinfo table size. We do not account for the added blocks in the table itself, as we hope to place them in @@ -523,8 +452,8 @@ morecore (size) existing table. */ newsize = heapsize; do - newsize *= 2; - while ((__malloc_size_t) BLOCK ((char *) result + size) > newsize); + newsize <<= 1; + while ((size_t) BLOCK ((char *) result + size) > newsize); /* We must not reuse existing core for the new info table when called from realloc in the case of growing a large block, because the @@ -540,8 +469,7 @@ morecore (size) `morecore_recursing' flag and return null. */ int save = errno; /* Don't want to clobber errno with ENOMEM. */ morecore_recursing = 1; - newinfo = (malloc_info *) _realloc_internal - (_heapinfo, newsize * sizeof (malloc_info)); + newinfo = (malloc_info *) irealloc (_heapinfo, newsize * sizeof (malloc_info)); morecore_recursing = 0; if (newinfo == NULL) errno = save; @@ -550,8 +478,7 @@ morecore (size) /* We found some space in core, and realloc has put the old table's blocks on the free list. Now zero the new part of the table and install the new table location. */ - memset (&newinfo[heapsize], 0, - (newsize - heapsize) * sizeof (malloc_info)); + memset (&newinfo[heapsize], 0, (newsize - heapsize) * sizeof (malloc_info)); _heapinfo = newinfo; heapsize = newsize; goto got_heap; @@ -566,37 +493,34 @@ morecore (size) /* Did it fail? */ if (newinfo == NULL) { - (*__morecore) (-size); + default_morecore (-size); return NULL; } /* Is it big enough to record status for its own space? If so, we win. */ - if ((__malloc_size_t) BLOCK ((char *) newinfo - + newsize * sizeof (malloc_info)) - < newsize) + if ((size_t) BLOCK ((char *) newinfo + newsize * sizeof (malloc_info)) < newsize) break; /* Must try again. First give back most of what we just got. */ - (*__morecore) (- newsize * sizeof (malloc_info)); + default_morecore (- newsize * sizeof (malloc_info)); newsize *= 2; } /* Copy the old table to the beginning of the new, and zero the rest of the new table. */ memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info)); - memset (&newinfo[heapsize], 0, - (newsize - heapsize) * sizeof (malloc_info)); + memset (&newinfo[heapsize], 0, (newsize - heapsize) * sizeof (malloc_info)); oldinfo = _heapinfo; _heapinfo = newinfo; heapsize = newsize; register_heapinfo (); - /* Reset _heaplimit so _free_internal never decides + /* Reset _heaplimit so ifree never decides it can relocate or resize the info table. */ _heaplimit = 0; - _free_internal (oldinfo); + ifree (oldinfo); /* The new heap limit includes the new table just allocated. */ _heaplimit = BLOCK ((char *) newinfo + heapsize * sizeof (malloc_info)); @@ -609,13 +533,13 @@ morecore (size) } /* Allocate memory from the heap. */ -__ptr_t -_malloc_internal (size) - __malloc_size_t size; +static genptr_t +imalloc (size) + size_t size; { - __ptr_t result; - __malloc_size_t block, blocks, lastblocks, start; - register __malloc_size_t i; + genptr_t result; + size_t block, blocks, lastblocks, start; + register size_t i; struct list *next; /* ANSI C allows `malloc (0)' to either return NULL, or to return a @@ -625,7 +549,7 @@ _malloc_internal (size) expects `malloc (0)' to return non-NULL and breaks otherwise. Be compatible. */ -#if 0 +#if 0 if (size == 0) return NULL; #endif @@ -643,7 +567,7 @@ _malloc_internal (size) { /* Small allocation to receive a fragment of a block. Determine the logarithm to base two of the fragment size. */ - register __malloc_size_t log = 1; + register size_t log = 1; --size; while ((size /= 2) != 0) ++log; @@ -656,7 +580,7 @@ _malloc_internal (size) /* There are free fragments of this size. Pop a fragment out of the fragment list and return it. Update the block's nfree and first counters. */ - result = (__ptr_t) next; + result = (genptr_t) next; next->prev->next = next->next; if (next->next != NULL) next->next->prev = next->prev; @@ -667,16 +591,16 @@ _malloc_internal (size) % BLOCKSIZE) >> log; /* Update the statistics. */ - ++_chunks_used; - _bytes_used += 1 << log; - --_chunks_free; - _bytes_free -= 1 << log; + ++chunks_used; + bytes_used += 1 << log; + --chunks_free; + bytes_free -= 1 << log; } else { /* No free fragments of the desired size, so get a new block and break it into fragments, returning the first. */ - result = malloc (BLOCKSIZE); + result = imalloc (BLOCKSIZE); if (result == NULL) return NULL; @@ -686,7 +610,7 @@ _malloc_internal (size) next->prev = &_fraghead[log]; _fraghead[log].next = next; - for (i = 2; i < (__malloc_size_t) (BLOCKSIZE >> log); ++i) + for (i = 2; i < (size_t) (BLOCKSIZE >> log); ++i) { next = (struct list *) ((char *) result + (i << log)); next->next = _fraghead[log].next; @@ -701,9 +625,9 @@ _malloc_internal (size) _heapinfo[block].busy.info.frag.nfree = i - 1; _heapinfo[block].busy.info.frag.first = i - 1; - _chunks_free += (BLOCKSIZE >> log) - 1; - _bytes_free += BLOCKSIZE - (1 << log); - _bytes_used -= BLOCKSIZE - (1 << log); + chunks_free += (BLOCKSIZE >> log) - 1; + bytes_free += BLOCKSIZE - (1 << log); + bytes_used -= BLOCKSIZE - (1 << log); } } else @@ -720,7 +644,7 @@ _malloc_internal (size) if (block == start) { /* Need to get more from the system. Get a little extra. */ - __malloc_size_t wantblocks = blocks + __malloc_extra_blocks; + size_t wantblocks = blocks + malloc_extra_blocks; block = _heapinfo[0].free.prev; lastblocks = _heapinfo[block].free.size; /* Check to see if the new core will be contiguous with the @@ -737,7 +661,7 @@ _malloc_internal (size) changed, if it got combined with a freed info table. */ block = _heapinfo[0].free.prev; _heapinfo[block].free.size += (wantblocks - lastblocks); - _bytes_free += (wantblocks - lastblocks) * BLOCKSIZE; + bytes_free += (wantblocks - lastblocks) * BLOCKSIZE; _heaplimit += wantblocks - lastblocks; continue; } @@ -751,7 +675,8 @@ _malloc_internal (size) _heapinfo[block].free.next = 0; _heapinfo[0].free.prev = block; _heapinfo[_heapinfo[block].free.prev].free.next = block; - ++_chunks_free; + ++chunks_free; + bytes_free += wantblocks * BLOCKSIZE; /* Now loop to use some of that block for this allocation. */ } } @@ -781,14 +706,14 @@ _malloc_internal (size) = _heapinfo[block].free.prev; _heapinfo[_heapinfo[block].free.prev].free.next = _heapindex = _heapinfo[block].free.next; - --_chunks_free; + --chunks_free; } _heapinfo[block].busy.type = 0; _heapinfo[block].busy.info.size = blocks; - ++_chunks_used; - _bytes_used += blocks * BLOCKSIZE; - _bytes_free -= blocks * BLOCKSIZE; + ++chunks_used; + bytes_used += blocks * BLOCKSIZE; + bytes_free -= blocks * BLOCKSIZE; /* Mark all the blocks of the object just allocated except for the first with a negative number so you can find the first block by @@ -800,113 +725,55 @@ _malloc_internal (size) return result; } -__ptr_t +genptr_t malloc (size) - __malloc_size_t size; -{ - if (!__malloc_initialized && !__malloc_initialize ()) - return NULL; - - return (__malloc_hook != NULL ? *__malloc_hook : _malloc_internal) (size); -} - -#ifndef _LIBC - -/* On some ANSI C systems, some libc functions call _malloc, _free - and _realloc. Make them use the GNU functions. */ - -__ptr_t -_malloc (size) - __malloc_size_t size; + size_t size; { - return malloc (size); -} - -void -_free (ptr) - __ptr_t ptr; -{ - free (ptr); -} - -__ptr_t -_realloc (ptr, size) - __ptr_t ptr; - __malloc_size_t size; -{ - return realloc (ptr, size); -} - +#ifdef RCHECK + struct hdr *hdr; #endif -/* Free a block of memory allocated by `malloc'. - Copyright 1990, 1991, 1992, 1994, 1995 Free Software Foundation, Inc. - Written May 1989 by Mike Haertel. -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. + nmalloc++; - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include <malloc.h> -#endif + if (malloc_initialized == 0 && malloc_initialize () == 0) + return NULL; +#ifdef RCHECK + hdr = (struct hdr *) imalloc (sizeof (struct hdr) + size + 1); + if (hdr == NULL) + return NULL; -/* Cope with systems lacking `memmove'. */ -#ifndef memmove -#if (defined (MEMMOVE_MISSING) || \ - !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG)) -#ifdef emacs -#undef __malloc_safe_bcopy -#define __malloc_safe_bcopy safe_bcopy -#endif -/* This function is defined in realloc.c. */ -extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); -#define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) -#endif + hdr->size = size; + hdr->magic = MAGICWORD; + ((char *) &hdr[1])[size] = MAGICBYTE; + zmemset ((genptr_t) (hdr + 1), MALLOCFLOOD, size); + return (genptr_t) (hdr + 1); +#else + return (imalloc (size)); #endif +} +/* Free a block of memory allocated by `malloc'. */ -/* Debugging hook for free. */ -void (*__free_hook) __P ((__ptr_t __ptr)); - -/* List of blocks allocated by memalign. */ -struct alignlist *_aligned_blocks = NULL; - -/* Return memory to the heap. - Like `free' but don't call a __free_hook if there is one. */ -void -_free_internal (ptr) - __ptr_t ptr; +/* Return memory to the heap. */ +static void +ifree (ptr) + genptr_t ptr; { int type; - __malloc_size_t block, blocks; - register __malloc_size_t i; + size_t block, blocks; + register size_t i; struct list *prev, *next; - __ptr_t curbrk; - const __malloc_size_t lesscore_threshold - /* Threshold of free space at which we will return some to the system. */ - = FINAL_FREE_BLOCKS + 2 * __malloc_extra_blocks; - + genptr_t curbrk; + size_t lesscore_threshold; register struct alignlist *l; if (ptr == NULL) return; + /* Threshold of free space at which we will return some to the system. */ + lesscore_threshold = FINAL_FREE_BLOCKS + 2 * malloc_extra_blocks; + for (l = _aligned_blocks; l != NULL; l = l->next) if (l->aligned == ptr) { @@ -922,9 +789,9 @@ _free_internal (ptr) { case 0: /* Get as many statistics as early as we can. */ - --_chunks_used; - _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; - _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; + --chunks_used; + bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; + bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; /* Find the free cluster previous to this one in the free list. Start searching at the last block referenced; this may benefit @@ -956,7 +823,7 @@ _free_internal (ptr) _heapinfo[block].free.prev = i; _heapinfo[i].free.next = block; _heapinfo[_heapinfo[block].free.next].free.prev = block; - ++_chunks_free; + ++chunks_free; } /* Now that the block is linked in, see if we can coalesce it @@ -969,14 +836,14 @@ _free_internal (ptr) _heapinfo[block].free.next = _heapinfo[_heapinfo[block].free.next].free.next; _heapinfo[_heapinfo[block].free.next].free.prev = block; - --_chunks_free; + --chunks_free; } /* How many trailing free blocks are there now? */ blocks = _heapinfo[block].free.size; /* Where is the current end of accessible core? */ - curbrk = (*__morecore) (0); + curbrk = default_morecore (0); if (_heaplimit != 0 && curbrk == ADDRESS (_heaplimit)) { @@ -984,12 +851,12 @@ _free_internal (ptr) It's possible that moving _heapinfo will allow us to return some space to the system. */ - __malloc_size_t info_block = BLOCK (_heapinfo); - __malloc_size_t info_blocks = _heapinfo[info_block].busy.info.size; - __malloc_size_t prev_block = _heapinfo[block].free.prev; - __malloc_size_t prev_blocks = _heapinfo[prev_block].free.size; - __malloc_size_t next_block = _heapinfo[block].free.next; - __malloc_size_t next_blocks = _heapinfo[next_block].free.size; + size_t info_block = BLOCK (_heapinfo); + size_t info_blocks = _heapinfo[info_block].busy.info.size; + size_t prev_block = _heapinfo[block].free.prev; + size_t prev_blocks = _heapinfo[prev_block].free.size; + size_t next_block = _heapinfo[block].free.next; + size_t next_blocks = _heapinfo[next_block].free.size; if (/* Win if this block being freed is last in core, the info table is just before it, the previous free block is just before the @@ -1012,14 +879,14 @@ _free_internal (ptr) ) { malloc_info *newinfo; - __malloc_size_t oldlimit = _heaplimit; + size_t oldlimit = _heaplimit; /* Free the old info table, clearing _heaplimit to avoid recursion into this code. We don't want to return the table's blocks to the system before we have copied them to the new location. */ _heaplimit = 0; - _free_internal (_heapinfo); + ifree (_heapinfo); _heaplimit = oldlimit; /* Tell malloc to search from the beginning of the heap for @@ -1027,7 +894,7 @@ _free_internal (ptr) _heapindex = 0; /* Allocate new space for the info table and move its data. */ - newinfo = (malloc_info *) _malloc_internal (info_blocks + newinfo = (malloc_info *) imalloc (info_blocks * BLOCKSIZE); memmove (newinfo, _heapinfo, info_blocks * BLOCKSIZE); _heapinfo = newinfo; @@ -1043,16 +910,16 @@ _free_internal (ptr) /* Now see if we can return stuff to the system. */ if (block + blocks == _heaplimit && blocks >= lesscore_threshold) { - register __malloc_size_t bytes = blocks * BLOCKSIZE; + register size_t bytes = blocks * BLOCKSIZE; _heaplimit -= blocks; - (*__morecore) (-bytes); + default_morecore (-bytes); _heapinfo[_heapinfo[block].free.prev].free.next = _heapinfo[block].free.next; _heapinfo[_heapinfo[block].free.next].free.prev = _heapinfo[block].free.prev; block = _heapinfo[block].free.prev; - --_chunks_free; - _bytes_free -= bytes; + --chunks_free; + bytes_free -= bytes; } } @@ -1062,10 +929,10 @@ _free_internal (ptr) default: /* Do some of the statistics. */ - --_chunks_used; - _bytes_used -= 1 << type; - ++_chunks_free; - _bytes_free += 1 << type; + --chunks_used; + bytes_used -= 1 << type; + ++chunks_free; + bytes_free += 1 << type; /* Get the address of the first free fragment in this block. */ prev = (struct list *) ((char *) ADDRESS (block) + @@ -1076,7 +943,7 @@ _free_internal (ptr) /* If all fragments of this block are free, remove them from the fragment list and free the whole block. */ next = prev; - for (i = 1; i < (__malloc_size_t) (BLOCKSIZE >> type); ++i) + for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i) next = next->next; prev->prev->next = next; if (next != NULL) @@ -1085,12 +952,12 @@ _free_internal (ptr) _heapinfo[block].busy.info.size = 1; /* Keep the statistics accurate. */ - ++_chunks_used; - _bytes_used += BLOCKSIZE; - _chunks_free -= BLOCKSIZE >> type; - _bytes_free -= BLOCKSIZE; + ++chunks_used; + bytes_used += BLOCKSIZE; + chunks_free -= BLOCKSIZE >> type; + bytes_free -= BLOCKSIZE; - free (ADDRESS (block)); + ifree (ADDRESS (block)); } else if (_heapinfo[block].busy.info.frag.nfree != 0) { @@ -1128,76 +995,46 @@ _free_internal (ptr) /* Return memory to the heap. */ void free (ptr) - __ptr_t ptr; + genptr_t ptr; { - if (__free_hook != NULL) - (*__free_hook) (ptr); - else - _free_internal (ptr); -} - -/* Define the `cfree' alias for `free'. */ -#ifdef weak_alias -weak_alias (free, cfree) -#else -void -cfree (ptr) - __ptr_t ptr; -{ - free (ptr); -} +#ifdef RCHECK + struct hdr *hdr; #endif -/* Change the size of a block allocated by `malloc'. - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. - Written May 1989 by Mike Haertel. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. + nfree++; - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ + if (ptr == 0) + return; -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include <malloc.h> +#ifdef RCHECK + hdr = ((struct hdr *) ptr) - 1; + checkhdr (hdr); + hdr->magic = MAGICFREE; + zmemset (ptr, FREEFLOOD, hdr->size); + ifree (hdr); +#else + ifree (ptr); #endif +} +/* Change the size of a block allocated by `malloc'. */ - -/* Cope with systems lacking `memmove'. */ -#if (defined (MEMMOVE_MISSING) || \ - !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG)) - -#ifdef emacs -#undef __malloc_safe_bcopy -#define __malloc_safe_bcopy safe_bcopy -#else - +#ifndef HAVE_MEMMOVE /* Snarfed directly from Emacs src/dispnew.c: XXX Should use system bcopy if it handles overlap. */ /* Like bcopy except never gets confused by overlap. */ -void -__malloc_safe_bcopy (afrom, ato, size) - __ptr_t afrom; - __ptr_t ato; - __malloc_size_t size; +static void +malloc_safe_bcopy (afrom, ato, size) + genptr_t afrom; + genptr_t ato; + size_t size; { - char *from = afrom, *to = ato; + char *from, *to; + from = afrom; + to = ato; if (size <= 0 || from == to) return; @@ -1245,20 +1082,7 @@ __malloc_safe_bcopy (afrom, ato, size) } } } -#endif /* emacs */ - -#ifndef memmove -extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); -#define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) -#endif - -#endif - - -#define min(A, B) ((A) < (B) ? (A) : (B)) - -/* Debugging hook for realloc. */ -__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); +#endif /* !HAVE_MEMMOVE */ /* Resize the given region to the new size, returning a pointer to the (possibly moved) region. This is optimized for speed; @@ -1266,22 +1090,22 @@ __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); achieved by unconditionally allocating and copying to a new region. This module has incestuous knowledge of the internals of both free and malloc. */ -__ptr_t -_realloc_internal (ptr, size) - __ptr_t ptr; - __malloc_size_t size; +static genptr_t +irealloc (ptr, size) + genptr_t ptr; + size_t size; { - __ptr_t result; + genptr_t result; int type; - __malloc_size_t block, blocks, oldlimit; + size_t block, blocks, oldlimit; if (size == 0) { - _free_internal (ptr); - return _malloc_internal (0); + ifree (ptr); + return imalloc (0); } else if (ptr == NULL) - return _malloc_internal (size); + return imalloc (size); block = BLOCK (ptr); @@ -1292,11 +1116,11 @@ _realloc_internal (ptr, size) /* Maybe reallocate a large block to a small fragment. */ if (size <= BLOCKSIZE / 2) { - result = _malloc_internal (size); + result = imalloc (size); if (result != NULL) { memcpy (result, ptr, size); - _free_internal (ptr); + ifree (ptr); return result; } } @@ -1314,9 +1138,9 @@ _realloc_internal (ptr, size) _heapinfo[block].busy.info.size = blocks; /* We have just created a new chunk by splitting a chunk in two. Now we will free this chunk; increment the statistics counter - so it doesn't become wrong when _free_internal decrements it. */ - ++_chunks_used; - _free_internal (ADDRESS (block + blocks)); + so it doesn't become wrong when ifree decrements it. */ + ++chunks_used; + ifree (ADDRESS (block + blocks)); result = ptr; } else if (blocks == _heapinfo[block].busy.info.size) @@ -1331,8 +1155,8 @@ _realloc_internal (ptr, size) /* Prevent free from actually returning memory to the system. */ oldlimit = _heaplimit; _heaplimit = 0; - _free_internal (ptr); - result = _malloc_internal (size); + ifree (ptr); + result = imalloc (size); if (_heaplimit == 0) _heaplimit = oldlimit; if (result == NULL) @@ -1341,13 +1165,13 @@ _realloc_internal (ptr, size) the thing we just freed. Unfortunately it might have been coalesced with its neighbors. */ if (_heapindex == block) - (void) _malloc_internal (blocks * BLOCKSIZE); + (void) imalloc (blocks * BLOCKSIZE); else { - __ptr_t previous - = _malloc_internal ((block - _heapindex) * BLOCKSIZE); - (void) _malloc_internal (blocks * BLOCKSIZE); - _free_internal (previous); + genptr_t previous; + previous = imalloc ((block - _heapindex) * BLOCKSIZE); + (void) imalloc (blocks * BLOCKSIZE); + ifree (previous); } return NULL; } @@ -1359,19 +1183,19 @@ _realloc_internal (ptr, size) default: /* Old size is a fragment; type is logarithm to base two of the fragment size. */ - if (size > (__malloc_size_t) (1 << (type - 1)) && - size <= (__malloc_size_t) (1 << type)) + if (size > (size_t) (1 << (type - 1)) && + size <= (size_t) (1 << type)) /* The new size is the same kind of fragment. */ result = ptr; else { /* The new size is different; allocate a new space, and copy the lesser of the new size and the old. */ - result = _malloc_internal (size); + result = imalloc (size); if (result == NULL) return NULL; - memcpy (result, ptr, min (size, (__malloc_size_t) 1 << type)); - _free_internal (ptr); + memcpy (result, ptr, min (size, (size_t) 1 << type)); + ifree (ptr); } break; } @@ -1379,148 +1203,75 @@ _realloc_internal (ptr, size) return result; } -__ptr_t +genptr_t realloc (ptr, size) - __ptr_t ptr; - __malloc_size_t size; + genptr_t ptr; + size_t size; { - if (!__malloc_initialized && !__malloc_initialize ()) +#ifdef RCHECK + struct hdr *hdr; + size_t osize; +#endif + + if (malloc_initialized == 0 && malloc_initialize () == 0) return NULL; - return (__realloc_hook != NULL ? *__realloc_hook : _realloc_internal) - (ptr, size); -} -/* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc. + nrealloc++; -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. +#ifdef RCHECK + hdr = ((struct hdr *) ptr) - 1; + osize = hdr->size; -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ + checkhdr (hdr); + if (size < osize) + zmemset ((char *) ptr + size, FREEFLOOD, osize - size); + hdr = (struct hdr *) irealloc ((genptr_t) hdr, sizeof (struct hdr) + size + 1); + if (hdr == NULL) + return NULL; -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include <malloc.h> + hdr->size = size; + hdr->magic = MAGICWORD; + ((char *) &hdr[1])[size] = MAGICBYTE; + if (size > osize) + zmemset ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize); + return (genptr_t) (hdr + 1); +#else + return (irealloc (ptr, size)); #endif +} /* Allocate an array of NMEMB elements each SIZE bytes long. The entire array is initialized to zeros. */ -__ptr_t +genptr_t calloc (nmemb, size) - register __malloc_size_t nmemb; - register __malloc_size_t size; + register size_t nmemb; + register size_t size; { - register __ptr_t result = malloc (nmemb * size); + register genptr_t result; + result = malloc (nmemb * size); if (result != NULL) (void) memset (result, 0, nmemb * size); return result; } -/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. -This file is part of the GNU C Library. -The GNU C Library is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -The GNU C Library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with the GNU C Library; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include <malloc.h> -#endif - -#ifndef __GNU_LIBRARY__ -#define __sbrk sbrk -#endif - -#ifdef __GNU_LIBRARY__ -/* It is best not to declare this and cast its result on foreign operating - systems with potentially hostile include files. */ - -#include <stddef.h> -extern __ptr_t __sbrk __P ((ptrdiff_t increment)); -#endif - -#ifndef NULL -#define NULL 0 -#endif - -/* Allocate INCREMENT more bytes of data space, - and return the start of data space, or NULL on errors. - If INCREMENT is negative, shrink data space. */ -__ptr_t -__default_morecore (increment) - __malloc_ptrdiff_t increment; +/* Define the `cfree' alias for `free'. */ +void +cfree (ptr) + genptr_t ptr; { - __ptr_t result = (__ptr_t) __sbrk (increment); - if (result == (__ptr_t) -1) - return NULL; - return result; + free (ptr); } -/* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc. -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include <malloc.h> -#endif - -#if __DJGPP__ - 0 == 1 - -/* There is some problem with memalign in DJGPP v1 and we are supposed - to omit it. Noone told me why, they just told me to do it. */ - -#else - -__ptr_t (*__memalign_hook) __P ((size_t __size, size_t __alignment)); - -__ptr_t +genptr_t memalign (alignment, size) - __malloc_size_t alignment; - __malloc_size_t size; + size_t alignment; + size_t size; { - __ptr_t result; + genptr_t result; unsigned long int adj, lastadj; - if (__memalign_hook) - return (*__memalign_hook) (alignment, size); - /* Allocate a block with enough extra space to pad the block with up to (ALIGNMENT - 1) bytes if necessary. */ result = malloc (size + alignment - 1); @@ -1560,7 +1311,7 @@ memalign (alignment, size) break; if (l == NULL) { - l = (struct alignlist *) malloc (sizeof (struct alignlist)); + l = (struct alignlist *) imalloc (sizeof (struct alignlist)); if (l == NULL) { free (result); @@ -1576,4 +1327,160 @@ memalign (alignment, size) return result; } -#endif /* Not DJGPP v1 */ +/* On some ANSI C systems, some libc functions call _malloc, _free + and _realloc. Make them use the GNU functions. */ + +genptr_t +_malloc (size) + size_t size; +{ + return malloc (size); +} + +void +_free (ptr) + genptr_t ptr; +{ + free (ptr); +} + +genptr_t +_realloc (ptr, size) + genptr_t ptr; + size_t size; +{ + return realloc (ptr, size); +} + +struct mstats +mstats () +{ + struct mstats result; + + result.bytes_total = (char *) default_morecore (0) - _heapbase; + result.chunks_used = chunks_used; + result.bytes_used = bytes_used; + result.chunks_free = chunks_free; + result.bytes_free = bytes_free; + result.nmalloc = nmalloc; + result.nrealloc = nrealloc; + result.nfree = nfree; + result.nsbrk = nsbrk; + result.tsbrk = tsbrk; + result.negsbrk = negsbrk; + result.tnegsbrk = tnegsbrk; + + return result; +} + +#ifdef RCHECK +/* Standard debugging hooks for `malloc'. */ + +static void +zmemset (ptr, val, size) + genptr_t ptr; + int val; + size_t size; +{ + char *cp = ptr; + + while (size--) + *cp++ = val; +} + +static enum mcheck_status +checkhdr (hdr) + const struct hdr *hdr; +{ + enum mcheck_status status; + + switch (hdr->magic) + { + default: + status = MCHECK_HEAD; + break; + case MAGICFREE: + status = MCHECK_FREE; + break; + case MAGICWORD: + if (((char *) &hdr[1])[hdr->size] != MAGICBYTE) + status = MCHECK_TAIL; + else + status = MCHECK_OK; + break; + } + if (status != MCHECK_OK) + mabort (status); + return status; +} + +#ifndef botch +botch (msg) + char *msg; +{ + fprintf (stderr, "mcheck: %s\n", msg); + fflush (stderr); + abort (); +} +#endif + +static void +mabort (status) + enum mcheck_status status; +{ + const char *msg; + + switch (status) + { + case MCHECK_OK: + msg = "memory is consistent, library is buggy"; + break; + case MCHECK_HEAD: + msg = "memory clobbered before allocated block"; + break; + case MCHECK_TAIL: + msg = "memory clobbered past end of allocated block"; + break; + case MCHECK_FREE: + msg = "block freed twice"; + break; + default: + msg = "bogus mcheck_status, library is buggy"; + break; + } + + botch (msg); +} + +enum mcheck_status +mprobe (ptr) + genptr_t ptr; +{ + return checkhdr ((struct hdr *)ptr); +} + +#ifndef STDIO_H_INCLUDED +# include <stdio.h> +#endif + +void +print_malloc_stats (s) + char *s; +{ + struct mstats ms; + + ms = mstats (); + fprintf (stderr, "Memory allocation statistics: %s\n", s ? s : ""); + fprintf (stderr, "\nTotal chunks in use: %d, total chunks free: %d\n", + ms.chunks_used, ms.chunks_free); + fprintf (stderr, "Total bytes in use: %u, total bytes free: %u\n", + ms.bytes_used, ms.bytes_free); + fprintf (stderr, "Total bytes (from heapbase): %d\n", ms.bytes_total); + fprintf (stderr, "Total mallocs: %d, total frees: %d, total reallocs: %d\n", + ms.nmalloc, ms.nfree, ms.nrealloc); + fprintf (stderr, "Total sbrks: %d, total bytes via sbrk: %d\n", + ms.nsbrk, ms.tsbrk); + fprintf (stderr, "Total negative sbrks: %d, total bytes returned to kernel: %d\n", + ms.negsbrk, ms.tnegsbrk); +} +#endif /* RCHECK */ diff --git a/lib/malloc/malloc.c b/lib/malloc/malloc.c index a8b232a1..c42ca3cc 100644 --- a/lib/malloc/malloc.c +++ b/lib/malloc/malloc.c @@ -1,6 +1,6 @@ -/* dynamic memory allocation for GNU. */ +/* malloc.c - dynamic memory allocation for bash. */ -/* Copyright (C) 1985, 1987 Free Software Foundation, Inc. +/* Copyright (C) 1985, 1987, 1997 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -41,21 +41,17 @@ what you give them. Help stamp out software-hoarding! */ * Jan 85, RMS: calls malloc_warning to issue warning on nearly full. * No longer Emacs-specific; can serve as all-purpose malloc for GNU. * You should call malloc_init to reinitialize after loading dumped Emacs. - * Call malloc_stats to get info on memory stats if MSTATS turned on. + * 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. */ +#define MALLOC_STATS /* for the time being */ /* * nextf[i] is the pointer to the next free block of size 2^(i+3). The * smallest allocatable block is 8 bytes. The overhead information will * go in the first int of the block, and the returned pointer will point * to the second. - * -#ifdef MSTATS - * nmalloc[i] is the difference between the number of mallocs and frees - * for a given block size. -#endif */ /* Define this to have free() write 0xcf into memory as it's freed, to @@ -65,38 +61,38 @@ what you give them. Help stamp out software-hoarding! */ # define MEMSCRAMBLE #endif -#if defined (emacs) || defined (HAVE_CONFIG_H) +#if defined (HAVE_CONFIG_H) # include <config.h> -#endif /* emacs */ +#endif /* HAVE_CONFIG_H */ + +#if defined (SHELL) +# include "bashtypes.h" +#else +# include <sys/types.h> +#endif #if defined (HAVE_UNISTD_H) # include <unistd.h> #endif /* Determine which kind of system this is. */ -#if defined (SHELL) -# include "bashtypes.h" +#include <signal.h> + +#if defined (HAVE_STRING_H) +# include <string.h> #else -# include <sys/types.h> +# include <strings.h> #endif -#include <signal.h> + +#if defined (MALLOC_STATS) || !defined (botch) +# include <stdio.h> +#endif /* MALLOC_STATS || !botch */ /* Define getpagesize () if the system does not. */ #ifndef HAVE_GETPAGESIZE # include "getpagesize.h" #endif -#if defined (HAVE_RESOURCE) -# include <sys/time.h> -# include <sys/resource.h> -#endif /* HAVE_RESOURCE */ - -/* Check for the needed symbols. If they aren't present, this - system's <sys/resource.h> isn't very useful to us. */ -#if !defined (RLIMIT_DATA) -# undef HAVE_RESOURCE -#endif - #if __GNUC__ > 1 # define FASTCOPY(s, d, n) __builtin_memcpy (d, s, n) #else /* !__GNUC__ */ @@ -115,7 +111,7 @@ what you give them. Help stamp out software-hoarding! */ # define NULL 0 #endif -#define start_of_data() &etext +#define NBUCKETS 30 #define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */ #define ISFREE ((char) 0x54) /* magic byte that implies free block */ @@ -124,147 +120,275 @@ what you give them. Help stamp out software-hoarding! */ memalign, with the rest of the word being the distance to the true beginning of the block. */ -extern char etext; #if !defined (SBRK_DECLARED) extern char *sbrk (); #endif /* !SBRK_DECLARED */ -/* These two are for user programs to look at, when they are interested. */ -unsigned int malloc_sbrk_used; /* amount of data space used now */ -unsigned int malloc_sbrk_unused; /* amount more we can have */ - -/* start of data space; can be changed by calling init_malloc */ -static char *data_space_start; - -static void get_lim_data (); - -#ifdef MSTATS -static int nmalloc[30]; -static int nmal, nfre; -#endif /* MSTATS */ - -/* If range checking is not turned on, all we have is a flag indicating - whether memory is allocated, an index in nextf[], and a size field; to - realloc() memory we copy either size bytes or 1<<(index+3) bytes depending - on whether the former can hold the exact size (given the value of - 'index'). If range checking is on, we always need to know how much space - is allocated, so the 'size' field is never used. */ - -struct mhead { - char mh_alloc; /* ISALLOC or ISFREE */ - char mh_index; /* index in nextf[] */ -/* Remainder are valid only when block is allocated */ - unsigned short mh_size; /* size, if < 0x10000 */ -#ifdef RCHECK - unsigned int mh_nbytes; /* number of bytes allocated */ - int mh_magic4; /* should be == MAGIC4 */ -#endif /* RCHECK */ +#ifdef MALLOC_STATS +/* + * NMALLOC[i] is the difference between the number of mallocs and frees + * for a given block size. TMALLOC[i] is the total number of mallocs for + * a given block size. NMORECORE[i] is the total number of calls to + * morecore(i). NMAL and NFRE are counts of the number of calls to malloc() + * and free(), respectively. NREALLOC is the total number of calls to + * realloc(); NRCOPY is the number of times realloc() had to allocate new + * memory and copy to it. NRECURSE is a count of the number of recursive + * calls to malloc() for the same bucket size, which can be caused by calls + * to malloc() from a signal handler. NSBRK is the number of calls to sbrk() + * (whether by morecore() or for alignment); TSBRK is the total number of + * bytes requested from the kernel with sbrk(). BYTESUSED is the total + * number of bytes consumed by blocks currently in use; BYTESFREE is the + * total number of bytes currently on all of the free lists. NBSPLIT is + * the number of times a larger block was split to satisfy a smaller request. + * NBCOALESCE is the number of times two adjacent smaller blocks off the free + * list were combined to satisfy a larger request. + */ +struct _malstats { + int nmalloc[NBUCKETS]; + int tmalloc[NBUCKETS]; + int nmorecore[NBUCKETS]; + int nmal; + int nfre; + int nrealloc; + int nrcopy; + int nrecurse; + int nsbrk; + int32_t tsbrk; + int32_t bytesused; + int32_t bytesfree; + int nbsplit; + int nbcoalesce; +}; + +static struct _malstats _mstats; + +/* Return statistics describing allocation of blocks of size BLOCKSIZE. + NFREE is the number of free blocks for this allocation size. NUSED + is the number of blocks in use. NMAL is the number of requests for + blocks of size BLOCKSIZE. NMORECORE is the number of times we had + to call MORECORE to repopulate the free list for this bucket. */ +struct bucket_stats { + u_int32_t blocksize; + int nfree; + int nused; + int nmal; + int nmorecore; +}; +#endif /* MALLOC_STATS */ + +/* 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 { + union mhead *mh_align; + struct { + char mi_alloc; /* ISALLOC or ISFREE */ /* 1 */ + char mi_index; /* index in nextf[] */ /* 1 */ + /* Remainder are valid only when block is allocated */ + u_int32_t mi_nbytes; /* # of bytes allocated */ /* 4 */ + unsigned short mi_magic2;/* should be == MAGIC2 */ /* 2 */ + } 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 /* Access free-list pointer of a block. - It is stored at block + 4. - This is not a field in the mhead structure - because we want sizeof (struct mhead) - to describe the overhead for when the block is in use, - and we do not want the free-list pointer to count in that. */ + It is stored at block + sizeof (char *). + This is not a field in the mhead structure + because we want sizeof (struct mhead) + to describe the overhead for when the block is in use, + and we do not want the free-list pointer to count in that. */ #define CHAIN(a) \ - (*(struct mhead **) (sizeof (char *) + (char *) (a))) + (*(union mhead **) (sizeof (char *) + (char *) (a))) -#ifdef RCHECK -# include <stdio.h> -# if !defined (botch) -# define botch(x) abort () -# else -extern void botch(); -# endif /* botch */ +#if defined (botch) +extern void botch (); +#else +static void +botch (s) + char *s; +{ + fprintf (stderr, "\r\nmalloc: assertion botched: %s\r\n", s); + (void)fflush (stderr); + abort (); +} +#endif /* !botch */ -# if !defined (__STRING) -# if defined (__STDC__) -# define __STRING(x) #x -# else -# define __STRING(x) "x" -# endif +#if !defined (__STRING) +# if defined (__STDC__) +# define __STRING(x) #x +# else +# define __STRING(x) "x" # endif +#endif /* !__STRING */ - /* To implement range checking, we write magic values in at the beginning - and end of each allocated block, and make sure they are undisturbed - whenever a free or a realloc occurs. */ - - /* Written in each of the 4 bytes following the block's real space */ -# define MAGIC1 0x55 - /* Written in the 4 bytes before the block's real space */ -# define MAGIC4 0x55555555 -# define ASSERT(p) if (!(p)) botch(__STRING(p)); else -# define EXTRA 4 /* 4 bytes extra for MAGIC1s */ -#else /* !RCHECK */ -# define ASSERT(p) -# define EXTRA 0 -#endif /* RCHECK */ +/* To implement range checking, we write magic values in at the beginning + and end of each allocated block, and make sure they are undisturbed + whenever a free or a realloc occurs. */ + +/* Written in each of the 4 bytes following the block's real space */ +#define MAGIC1 0x55 +/* Written in the 2 bytes before the block's real space */ +#define MAGIC2 0x5555 +#define ASSERT(p) do { if (!(p)) botch(__STRING(p)); } while (0) +#define MSLOP 4 /* 4 bytes extra for MAGIC1s */ + +/* Minimum and maximum bucket indices for block splitting (and to bound + the search for a block to split). */ +#define SPLIT_MIN 3 +#define SPLIT_MID 9 +#define SPLIT_MAX 12 + +/* Minimum and maximum bucket indices for block coalescing. */ +#define COMBINE_MIN 6 +#define COMBINE_MAX (pagebucket - 1) + +#define MIN_COMBINE_FREE 4 /* nextf[i] is free list of blocks of size 2**(i + 3) */ -static struct mhead *nextf[30]; +static union mhead *nextf[NBUCKETS]; /* busy[i] is nonzero while allocation of block size i is in progress. */ -static char busy[30]; +static char busy[NBUCKETS]; -/* Number of bytes of writable memory we can expect to be able to get */ -static unsigned int lim_data; +static int pagesz; /* system page size. */ +static int pagebucket; /* bucket for requests a page in size */ -/* Level number of warnings already issued. - 0 -- no warnings issued. - 1 -- 75% warning already issued. - 2 -- 85% warning already issued. -*/ -static int warnlevel; +#if 0 +/* Coalesce two adjacent free blocks off the free list for size NU - 1, + as long as there are at least MIN_COMBINE_FREE free blocks and we + can find two adjacent free blocks. nextf[NU -1] is assumed to not + be busy; the caller (morecore()) checks for this. */ +static void +bcoalesce (nu) + register int nu; +{ + register union mhead *mp, *mp1, *mp2; + register int nfree, nbuck; + unsigned long siz; -/* Function to call to issue a warning; - 0 means don't issue them. */ -static void (*warnfunction) (); + nbuck = nu - 1; + if (nextf[nbuck] == 0) + return; -/* nonzero once initial bunch of free blocks made */ -static int gotpool; + nfree = 1; + mp1 = nextf[nbuck]; + mp = CHAIN (mp1); + mp2 = (union mhead *)0; + while (CHAIN (mp)) + { + mp2 = mp1; + mp1 = mp; + mp = CHAIN (mp); + nfree++; + /* We may not want to run all the way through the free list here; + if we do not, we need to check a threshold value here and break + if nfree exceeds it. */ + } + if (nfree < MIN_COMBINE_FREE) + 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 (CHAIN(mp2) != mp1) + botch ("bcoalesce: CHAIN(mp2) != mp1"); + siz = 1 << (nbuck + 3); + if (CHAIN (mp1) != (union mhead *)((char *)mp1 + siz)) + return; /* not adjacent */ + +#ifdef MALLOC_STATS + _mstats.nbcoalesce++; +#endif -char *_malloc_base; + /* Since they are adjacent, remove them from the free list */ + CHAIN (mp2) = CHAIN (mp); -static void getpool (); + /* And add the combined two blocks to nextf[NU]. */ + mp1->mh_alloc = ISFREE; + mp1->mh_index = nu; + CHAIN (mp1) = nextf[nu]; + nextf[nu] = mp1; +} +#endif -/* Cause reinitialization based on job parameters; - also declare where the end of pure storage is. */ -void -malloc_init (start, warnfun) - char *start; - void (*warnfun) (); +/* Split a block at index > NU (but less than SPLIT_MAX) into a set of + blocks of the correct size, and attach them to nextf[NU]. nextf[NU] + is assumed to be empty. Must be called with signals blocked (e.g., + by morecore()). */ +static void +bsplit (nu) + register int nu; { - if (start) - data_space_start = start; - lim_data = 0; - warnlevel = 0; - warnfunction = warnfun; -} + register union mhead *mp; + int nbuck, nblks; + unsigned long siz; -/* Return the maximum size to which MEM can be realloc'd - without actually requiring copying. */ + 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; + } + } -int -malloc_usable_size (mem) - char *mem; -{ - int blocksize = 8 << (((struct mhead *) mem) - 1) -> mh_index; + if (nbuck > SPLIT_MAX || nbuck <= nu) + return; + + /* XXX might want to split only if nextf[nbuck] has >= 2 blocks free + and nbuck is below some threshold. */ + +#ifdef MALLOC_STATS + _mstats.nbsplit++; +#endif + + /* Figure out how many blocks we'll get. */ + siz = (1 << (nu + 3)); + nblks = (1 << (nbuck + 3)) / siz; - return blocksize - sizeof (struct mhead) - EXTRA; + /* Remove the block from the chain of larger blocks. */ + mp = nextf[nbuck]; + nextf[nbuck] = CHAIN (mp); + + /* Split the block and put it on the requested chain. */ + nextf[nu] = mp; + while (1) + { + mp->mh_alloc = ISFREE; + mp->mh_index = nu; + if (--nblks <= 0) break; + CHAIN (mp) = (union mhead *)((char *)mp + siz); + mp = (union mhead *)((char *)mp + siz); + } + CHAIN (mp) = 0; } static void morecore (nu) /* ask system for more memory */ register int nu; /* size index to get more of */ { - register char *cp; + register union mhead *mp; register int nblks; - register unsigned int siz; + register long siz; + long sbrk_amt; /* amount to get via sbrk() */ /* Block all signals in case we are executed from a signal handler. */ #if defined (HAVE_BSD_SIGNALS) @@ -279,82 +403,88 @@ morecore (nu) /* ask system for more memory */ # endif /* HAVE_POSIX_SIGNALS */ #endif /* HAVE_BSD_SIGNALS */ - if (!data_space_start) + siz = 1 << (nu + 3); /* size of desired block for nextf[nu] */ + + if (siz < 0) + return; /* 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 && nu < SPLIT_MAX) + { + bsplit (nu); + if (nextf[nu] != 0) + goto morecore_done; + } + +#if 0 + /* Try to coalesce two adjacent blocks from the free list on nextf[nu - 1], + if we can, and we're withing the range of the block coalescing limits. */ + if (nu >= COMBINE_MIN && nu < COMBINE_MAX && busy[nu - 1] == 0 && nextf[nu - 1]) + { + bcoalesce (nu); + if (nextf[nu] != 0) + goto morecore_done; + } +#endif + + /* Take at least a page, and figure out how many blocks of the requested + size we're getting. */ + if (siz <= pagesz) { - data_space_start = start_of_data (); + 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; + 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); - if (lim_data == 0) - get_lim_data (); - - /* On initial startup, get two blocks of each size up to 1k bytes */ - if (!gotpool) - { getpool (); getpool (); gotpool = 1; } - - /* Find current end of memory and issue warning if getting near max */ - - cp = sbrk (0); - siz = cp - data_space_start; - malloc_sbrk_used = siz; - malloc_sbrk_unused = lim_data - siz; - - if (warnfunction) - switch (warnlevel) - { - case 0: - if (siz > (lim_data / 4) * 3) - { - warnlevel++; - (*warnfunction) ("Warning: past 75% of memory limit"); - } - break; - case 1: - if (siz > (lim_data / 20) * 17) - { - warnlevel++; - (*warnfunction) ("Warning: past 85% of memory limit"); - } - break; - case 2: - if (siz > (lim_data / 20) * 19) - { - warnlevel++; - (*warnfunction) ("Warning: past 95% of memory limit"); - } - break; - } - - if ((int) cp & 0x3ff) /* land on 1K boundaries */ - sbrk (1024 - ((int) cp & 0x3ff)); - - /* Take at least 2k, and figure out how many blocks of the desired size - we're about to get */ - nblks = 1; - if ((siz = nu) < 8) - nblks = 1 << ((siz = 8) - nu); - - if ((cp = sbrk (1 << (siz + 3))) == (char *) -1) - return; /* no more room! */ - - if ((int) cp & 7) - { /* shouldn't happen, but just in case */ - cp = (char *) (((int) cp + 8) & ~7); + /* Totally out of memory. */ + if ((long)mp == -1) + return; + + /* shouldn't happen, but just in case -- require 8-byte alignment */ + if ((long)mp & 7) + { + mp = (union mhead *) (((long)mp + 8) & ~7); nblks--; } - /* save new header and link the nblks blocks together */ - nextf[nu] = (struct mhead *) cp; - siz = 1 << (nu + 3); + /* save new header and link the nblks blocks together */ + nextf[nu] = mp; while (1) { - ((struct mhead *) cp) -> mh_alloc = ISFREE; - ((struct mhead *) cp) -> mh_index = nu; + mp->mh_alloc = ISFREE; + mp->mh_index = nu; if (--nblks <= 0) break; - CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz); - cp += siz; + CHAIN (mp) = (union mhead *)((char *)mp + siz); + mp = (union mhead *)((char *)mp + siz); } - CHAIN ((struct mhead *) cp) = 0; + CHAIN (mp) = 0; +morecore_done: #if defined (HAVE_BSD_SIGNALS) sigsetmask (oldmask); #else @@ -364,44 +494,6 @@ morecore (nu) /* ask system for more memory */ #endif /* HAVE_BSD_SIGNALS */ } -static void -getpool () -{ - register int nu; - register char *cp = sbrk (0); - - if ((int) cp & 0x3ff) /* land on 1K boundaries */ - sbrk (1024 - ((int) cp & 0x3ff)); - - /* Record address of start of space allocated by malloc. */ - if (_malloc_base == 0) - _malloc_base = cp; - - /* Get 2k of storage */ - - cp = sbrk (04000); - if (cp == (char *) -1) - return; - - /* Divide it into an initial 8-word block - plus one block of size 2**nu for nu = 3 ... 10. */ - - CHAIN (cp) = nextf[0]; - nextf[0] = (struct mhead *) cp; - ((struct mhead *) cp) -> mh_alloc = ISFREE; - ((struct mhead *) cp) -> mh_index = 0; - cp += 8; - - for (nu = 0; nu < 7; nu++) - { - CHAIN (cp) = nextf[nu]; - nextf[nu] = (struct mhead *) cp; - ((struct mhead *) cp) -> mh_alloc = ISFREE; - ((struct mhead *) cp) -> mh_index = nu; - cp += 8 << nu; - } -} - #if defined (MEMSCRAMBLE) || !defined (NO_CALLOC) static char * zmemset (s, c, n) @@ -418,75 +510,130 @@ zmemset (s, c, n) } #endif /* MEMSCRAMBLE || !NO_CALLOC */ +static void +malloc_debug_dummy () +{ + ; +} + char * malloc (n) /* get a block */ - unsigned int n; + size_t n; { - register struct mhead *p; - register unsigned int nbytes; - register int nunits = 0; + register union mhead *p; + register long nbytes; + register int nunits; + /* Get the system page size and align break pointer so everything will + be page-aligned. The page size must be at least 1K -- anything + smaller is increased. */ + if (pagesz == 0) + { + register long sbrk_needed; + + pagesz = getpagesize (); + if (pagesz < 1024) + pagesz = 1024; + /* OK, how much do we need to allocate to make things page-aligned? + This partial page is wasted space. Once we figure out how much + to advance the break pointer, go ahead and do it. */ + sbrk_needed = pagesz - ((long)sbrk (0) & (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 + if ((long)sbrk (sbrk_needed) == -1) + return (NULL); + } + nunits = 0; + nbytes = 8; + while (pagesz > nbytes) + { + nbytes <<= 1; + nunits++; + } + pagebucket = nunits; + } + /* Figure out how many bytes are required, rounding up to the nearest - multiple of 4, then figure out which nextf[] area to use */ - nbytes = (n + sizeof *p + EXTRA + 3) & ~3; - { - register unsigned int shiftr = (nbytes - 1) >> 2; + multiple of 4, 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 = (n + sizeof *p + MSLOP + 3) & ~3; + nunits = 0; + if (nbytes <= (pagesz >> 1)) + { + register unsigned int shiftr; - while (shiftr >>= 1) - nunits++; - } + shiftr = (nbytes - 1) >> 2; /* == (nbytes - 1) / 4 */ + while (shiftr >>= 1) /* == (nbytes - 1) / {8,16,32,...} */ + nunits++; + } + else + { + register u_int32_t amt; + + nunits = pagebucket; + amt = pagesz; + while (nbytes > amt) + { + amt <<= 1; + nunits++; + } + } /* In case this is reentrant use of malloc from signal handler, pick a block size that no other malloc level is currently trying to allocate. That's the easiest harmless way not to interfere with the other level of execution. */ +#ifdef MALLOC_STATS + if (busy[nunits]) _mstats.nrecurse++; +#endif while (busy[nunits]) nunits++; busy[nunits] = 1; /* If there are no blocks of the appropriate size, go get some */ - /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */ if (nextf[nunits] == 0) morecore (nunits); /* Get one block off the list, and set the new list head */ - if ((p = nextf[nunits]) == 0) + if ((p = nextf[nunits]) == NULL) { busy[nunits] = 0; - return 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) -#ifdef RCHECK - botch ("block on free list clobbered"); -#else /* not RCHECK */ - abort (); -#endif /* not RCHECK */ + /* 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) + botch ("malloc: block on free list clobbered"); /* Fill in the info, and if range checking, set up the magic numbers */ - p -> mh_alloc = ISALLOC; -#ifdef RCHECK - p -> mh_nbytes = n; - p -> mh_magic4 = MAGIC4; + p->mh_alloc = ISALLOC; + p->mh_nbytes = n; + p->mh_magic2 = MAGIC2; { register char *m = (char *) (p + 1) + n; *m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1; } -#else /* not RCHECK */ - p -> mh_size = n; -#endif /* not RCHECK */ + #ifdef MEMSCRAMBLE zmemset ((char *)(p + 1), 0xdf, n); /* scramble previous contents */ #endif -#ifdef MSTATS - nmalloc[nunits]++; - nmal++; -#endif /* MSTATS */ +#ifdef MALLOC_STATS + _mstats.nmalloc[nunits]++; + _mstats.tmalloc[nunits]++; + _mstats.nmal++; +#endif /* MALLOC_STATS */ return (char *) (p + 1); } @@ -494,143 +641,123 @@ void free (mem) char *mem; { - register struct mhead *p; - { - register char *ap = mem; + register union mhead *p; + register char *ap; + register int nunits; + + if ((ap = mem) == 0) + return; - if (ap == 0) - return; + p = (union mhead *) ap - 1; - p = (struct mhead *) ap - 1; + if (p->mh_alloc == ISMEMALIGN) + { + ap -= p->mh_nbytes; + p = (union mhead *) ap - 1; + } + + if (p->mh_alloc != ISALLOC) + { + if (p->mh_alloc == ISFREE) + botch ("free: called with already freed block argument"); + else + botch ("free: called with unallocated block argument"); + } + + ASSERT (p->mh_magic2 == MAGIC2); + ap += p->mh_nbytes; + ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1); + ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1); - if (p -> mh_alloc == ISMEMALIGN) - { -#ifdef RCHECK - ap -= p->mh_nbytes; -#else - ap -= p->mh_size; /* XXX */ -#endif - p = (struct mhead *) ap - 1; - } - -#ifndef RCHECK - if (p -> mh_alloc != ISALLOC) - abort (); - -#else /* RCHECK */ - if (p -> mh_alloc != ISALLOC) - { - if (p -> mh_alloc == ISFREE) - botch ("free: Called with already freed block argument\n"); - else - botch ("free: Called with unallocated block argument\n"); - } - - ASSERT (p -> mh_magic4 == MAGIC4); - ap += p -> mh_nbytes; - ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1); - ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1); -#endif /* RCHECK */ - } #ifdef MEMSCRAMBLE - { - register int n; - -#ifdef RCHECK - n = p->mh_nbytes; -#else /* not RCHECK */ - n = p->mh_size; -#endif /* not RCHECK */ - zmemset (mem, 0xcf, n); - } + zmemset (mem, 0xcf, p->mh_nbytes); #endif - { - register int nunits = p -> mh_index; - - ASSERT (nunits <= 29); - p -> mh_alloc = ISFREE; - - /* Protect against signal handlers calling malloc. */ - busy[nunits] = 1; - /* Put this block on the free list. */ - CHAIN (p) = nextf[nunits]; - nextf[nunits] = p; - busy[nunits] = 0; - -#ifdef MSTATS - nmalloc[nunits]--; - nfre++; -#endif /* MSTATS */ - } + + nunits = p->mh_index; + + ASSERT (nunits < NBUCKETS); + p->mh_alloc = ISFREE; + + /* Protect against signal handlers calling malloc. */ + busy[nunits] = 1; + /* Put this block on the free list. */ + CHAIN (p) = nextf[nunits]; + nextf[nunits] = p; + busy[nunits] = 0; + +#ifdef MALLOC_STATS + _mstats.nmalloc[nunits]--; + _mstats.nfre++; +#endif /* MALLOC_STATS */ } char * realloc (mem, n) char *mem; - register unsigned int n; + register size_t n; { - register struct mhead *p; - register unsigned int tocopy; + register union mhead *p; + register u_int32_t tocopy; register unsigned int nbytes; register int nunits; + register char *m; + +#ifdef MALLOC_STATS + _mstats.nrealloc++; +#endif - if ((p = (struct mhead *) mem) == 0) + if (n == 0) + { + free (mem); + return (NULL); + } + if ((p = (union mhead *) mem) == 0) return malloc (n); p--; - nunits = p -> mh_index; - ASSERT (p -> mh_alloc == ISALLOC); -#ifdef RCHECK - ASSERT (p -> mh_magic4 == MAGIC4); - { - register char *m = mem + (tocopy = p -> mh_nbytes); - ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1); - ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1); - } -#else /* not RCHECK */ - if (p -> mh_index >= 13) - tocopy = (1 << (p -> mh_index + 3)) - sizeof *p; - else - tocopy = p -> mh_size; -#endif /* not RCHECK */ + nunits = p->mh_index; + ASSERT (p->mh_alloc == ISALLOC); + ASSERT (p->mh_magic2 == MAGIC2); + + m = mem + (tocopy = p->mh_nbytes); + ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1); + ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1); /* See if desired size rounds to same power of 2 as actual size. */ - nbytes = (n + sizeof *p + EXTRA + 7) & ~7; + nbytes = (n + sizeof *p + MSLOP + 7) & ~7; /* If ok, use the same block, just marking its size as changed. */ if (nbytes > (4 << nunits) && nbytes <= (8 << nunits)) { -#ifdef RCHECK - register char *m = mem + tocopy; + m = mem + tocopy; *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0; - p-> mh_nbytes = n; + p->mh_nbytes = n; m = mem + n; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; -#else /* not RCHECK */ - p -> mh_size = n; -#endif /* not RCHECK */ return mem; } +#ifdef MALLOC_STATS + _mstats.nrcopy++; +#endif + if (n < tocopy) tocopy = n; - { - register char *new; - if ((new = malloc (n)) == 0) - return 0; - FASTCOPY (mem, new, tocopy); - free (mem); - return new; - } + if ((m = malloc (n)) == 0) + return 0; + FASTCOPY (mem, m, tocopy); + free (mem); + return m; } char * memalign (alignment, size) - unsigned int alignment, size; + unsigned int alignment; + size_t size; { register char *ptr; register char *aligned; - register struct mhead *p; + register union mhead *p; ptr = malloc (size + alignment); @@ -644,9 +771,9 @@ memalign (alignment, size) /* Store a suitable indication of how to free the block, so that free can find the true beginning of it. */ - p = (struct mhead *) aligned - 1; - p -> mh_size = aligned - ptr; - p -> mh_alloc = ISMEMALIGN; + p = (union mhead *) aligned - 1; + p->mh_nbytes = aligned - ptr; + p->mh_alloc = ISMEMALIGN; return aligned; } @@ -688,72 +815,80 @@ cfree (p) } #endif /* !NO_CALLOC */ -#ifdef MSTATS -/* Return statistics describing allocation of blocks of size 2**n. */ - -struct mstats_value - { - int blocksize; - int nfree; - int nused; - }; +#ifdef MALLOC_STATS -struct mstats_value -malloc_stats (size) +struct bucket_stats +malloc_bucket_stats (size) int size; { - struct mstats_value v; - register int i; - register struct mhead *p; + struct bucket_stats v; + register union mhead *p; v.nfree = 0; - if (size < 0 || size >= 30) + if (size < 0 || size >= NBUCKETS) { v.blocksize = 0; - v.nused = 0; + v.nused = v.nmal = 0; return v; } v.blocksize = 1 << (size + 3); - v.nused = nmalloc[size]; + v.nused = _mstats.nmalloc[size]; + v.nmal = _mstats.tmalloc[size]; + v.nmorecore = _mstats.nmorecore[size]; for (p = nextf[size]; p; p = CHAIN (p)) v.nfree++; return v; } -#endif /* MSTATS */ -/* - * This function returns the total number of bytes that the process - * will be allowed to allocate via the sbrk(2) system call. On - * BSD systems this is the total space allocatable to stack and - * data. On USG systems this is the data space only. - */ - -#if !defined (HAVE_RESOURCE) -extern long ulimit (); +/* 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; -static void -get_lim_data () -{ - lim_data = ulimit (3, 0); - lim_data -= (long) data_space_start; + 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); } -#else /* HAVE_RESOURCE */ -static void -get_lim_data () +void +print_malloc_stats (s) + char *s; { - struct rlimit XXrlimit; + register int i; + int totused, totfree; + struct bucket_stats v; - getrlimit (RLIMIT_DATA, &XXrlimit); -#ifdef RLIM_INFINITY - lim_data = XXrlimit.rlim_cur & RLIM_INFINITY; /* soft limit */ -#else - lim_data = XXrlimit.rlim_cur; /* soft limit */ -#endif + fprintf (stderr, "Memory allocation statistics: %s\n\tsize\tfree\tin use\ttotal\tmorecore\n", s ? s : ""); + for (i = totused = totfree = 0; i < NBUCKETS; i++) + { + v = malloc_bucket_stats (i); + fprintf (stderr, "%12lu\t%4d\t%6d\t%5d\t%8d\n", v.blocksize, v.nfree, v.nused, v.nmal, v.nmorecore); + totfree += v.nfree * v.blocksize; + totused += v.nused * v.blocksize; + } + fprintf (stderr, "\nTotal bytes in use: %d, total bytes free: %d\n", + totused, totfree); + fprintf (stderr, "Total mallocs: %d, total frees: %d, total reallocs: %d (%d copies)\n", + _mstats.nmal, _mstats.nfre, _mstats.nrealloc, _mstats.nrcopy); + fprintf (stderr, "Total sbrks: %d, total bytes via sbrk: %d\n", + _mstats.nsbrk, _mstats.tsbrk); + fprintf (stderr, "Total blocks split: %d, total block coalesces: %d\n", + _mstats.nbsplit, _mstats.nbcoalesce); } - -#endif /* HAVE_RESOURCE */ +#endif /* MALLOC_STATS */ diff --git a/lib/malloc/ogmalloc.c b/lib/malloc/ogmalloc.c new file mode 100644 index 00000000..8690b126 --- /dev/null +++ b/lib/malloc/ogmalloc.c @@ -0,0 +1,1579 @@ +/* DO NOT EDIT THIS FILE -- it is automagically generated. -*- C -*- */ + +#define _MALLOC_INTERNAL + +/* The malloc headers and source files from the C library follow here. */ + +/* Declarations for `malloc' and friends. + Copyright 1990, 91, 92, 93, 95, 96 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_H + +#define _MALLOC_H 1 + +#ifdef _MALLOC_INTERNAL + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if defined(_LIBC) || defined(STDC_HEADERS) || defined(USG) +#include <string.h> +#else +#ifndef memset +#define memset(s, zero, n) bzero ((s), (n)) +#endif +#ifndef memcpy +#define memcpy(d, s, n) bcopy ((s), (d), (n)) +#endif +#endif + +#if defined (__GNU_LIBRARY__) || (defined (__STDC__) && __STDC__) +#include <limits.h> +#else +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#endif /* _MALLOC_INTERNAL. */ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#undef __P +#define __P(args) args +#undef __ptr_t +#define __ptr_t void * +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(args) () +#undef const +#define const +#undef __ptr_t +#define __ptr_t char * +#endif /* C++ or ANSI C. */ + +#if defined (__STDC__) && __STDC__ +#include <stddef.h> +#define __malloc_size_t size_t +#define __malloc_ptrdiff_t ptrdiff_t +#else +#define __malloc_size_t unsigned int +#define __malloc_ptrdiff_t int +#endif + +#ifndef NULL +#define NULL 0 +#endif + + +/* Allocate SIZE bytes of memory. */ +extern __ptr_t malloc __P ((__malloc_size_t __size)); +/* Re-allocate the previously allocated block + in __ptr_t, making the new block SIZE bytes long. */ +extern __ptr_t realloc __P ((__ptr_t __ptr, __malloc_size_t __size)); +/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ +extern __ptr_t calloc __P ((__malloc_size_t __nmemb, __malloc_size_t __size)); +/* Free a block allocated by `malloc', `realloc' or `calloc'. */ +extern void free __P ((__ptr_t __ptr)); + +/* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ +#if ! (defined (_MALLOC_INTERNAL) && __DJGPP__ - 0 == 1) /* Avoid conflict. */ +extern __ptr_t memalign __P ((__malloc_size_t __alignment, + __malloc_size_t __size)); +#endif + +/* Allocate SIZE bytes on a page boundary. */ +#if ! (defined (_MALLOC_INTERNAL) && defined (emacs)) /* Avoid conflict. */ +extern __ptr_t valloc __P ((__malloc_size_t __size)); +#endif + + +#ifdef _MALLOC_INTERNAL + +/* The allocator divides the heap into blocks of fixed size; large + requests receive one or more whole blocks, and small requests + receive a fragment of a block. Fragment sizes are powers of two, + and all fragments of a block are the same size. When all the + fragments in a block have been freed, the block itself is freed. */ +#define INT_BIT (CHAR_BIT * sizeof(int)) +#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) +#define BLOCKSIZE (1 << BLOCKLOG) +#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) + +/* Determine the amount of memory spanned by the initial heap table + (not an absolute limit). */ +#define HEAP (INT_BIT > 16 ? 4194304 : 65536) + +/* Number of contiguous free blocks allowed to build up at the end of + memory before they will be returned to the system. */ +#define FINAL_FREE_BLOCKS 8 + +/* Data structure giving per-block information. */ +typedef union + { + /* Heap information for a busy block. */ + struct + { + /* Zero for a large (multiblock) object, or positive giving the + logarithm to the base two of the fragment size. */ + int type; + union + { + struct + { + __malloc_size_t nfree; /* Free frags in a fragmented block. */ + __malloc_size_t first; /* First free fragment of the block. */ + } frag; + /* For a large object, in its first block, this has the number + of blocks in the object. In the other blocks, this has a + negative number which says how far back the first block is. */ + __malloc_ptrdiff_t size; + } info; + } busy; + /* Heap information for a free block + (that may be the first of a free cluster). */ + struct + { + __malloc_size_t size; /* Size (in blocks) of a free cluster. */ + __malloc_size_t next; /* Index of next free cluster. */ + __malloc_size_t prev; /* Index of previous free cluster. */ + } free; + } malloc_info; + +/* Pointer to first block of the heap. */ +extern char *_heapbase; + +/* Table indexed by block number giving per-block information. */ +extern malloc_info *_heapinfo; + +/* Address to block number and vice versa. */ +#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) +#define ADDRESS(B) ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase)) + +/* Current search index for the heap table. */ +extern __malloc_size_t _heapindex; + +/* Limit of valid info table indices. */ +extern __malloc_size_t _heaplimit; + +/* Doubly linked lists of free fragments. */ +struct list + { + struct list *next; + struct list *prev; + }; + +/* Free list headers for each fragment size. */ +extern struct list _fraghead[]; + +/* List of blocks allocated with `memalign' (or `valloc'). */ +struct alignlist + { + struct alignlist *next; + __ptr_t aligned; /* The address that memaligned returned. */ + __ptr_t exact; /* The address that malloc returned. */ + }; +extern struct alignlist *_aligned_blocks; + +/* Instrumentation. */ +extern __malloc_size_t _chunks_used; +extern __malloc_size_t _bytes_used; +extern __malloc_size_t _chunks_free; +extern __malloc_size_t _bytes_free; + +/* Internal versions of `malloc', `realloc', and `free' + used when these functions need to call each other. + They are the same but don't call the hooks. */ +extern __ptr_t _malloc_internal __P ((__malloc_size_t __size)); +extern __ptr_t _realloc_internal __P ((__ptr_t __ptr, __malloc_size_t __size)); +extern void _free_internal __P ((__ptr_t __ptr)); + +#endif /* _MALLOC_INTERNAL. */ + +/* Given an address in the middle of a malloc'd object, + return the address of the beginning of the object. */ +extern __ptr_t malloc_find_object_address __P ((__ptr_t __ptr)); + +/* Underlying allocation function; successive calls should + return contiguous pieces of memory. */ +extern __ptr_t (*__morecore) __P ((__malloc_ptrdiff_t __size)); + +/* Default value of `__morecore'. */ +extern __ptr_t __default_morecore __P ((__malloc_ptrdiff_t __size)); + +/* If not NULL, this function is called after each time + `__morecore' is called to increase the data size. */ +extern void (*__after_morecore_hook) __P ((void)); + +/* Number of extra blocks to get each time we ask for more core. + This reduces the frequency of calling `(*__morecore)'. */ +extern __malloc_size_t __malloc_extra_blocks; + +/* Nonzero if `malloc' has been called and done its initialization. */ +extern int __malloc_initialized; +/* Function called to initialize malloc data structures. */ +extern int __malloc_initialize __P ((void)); + +/* Hooks for debugging versions. */ +extern void (*__malloc_initialize_hook) __P ((void)); +extern void (*__free_hook) __P ((__ptr_t __ptr)); +extern __ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); +extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); +extern __ptr_t (*__memalign_hook) __P ((__malloc_size_t __size, + __malloc_size_t __alignment)); + +/* Return values for `mprobe': these are the kinds of inconsistencies that + `mcheck' enables detection of. */ +enum mcheck_status + { + MCHECK_DISABLED = -1, /* Consistency checking is not turned on. */ + MCHECK_OK, /* Block is fine. */ + MCHECK_FREE, /* Block freed twice. */ + MCHECK_HEAD, /* Memory before the block was clobbered. */ + MCHECK_TAIL /* Memory after the block was clobbered. */ + }; + +/* Activate a standard collection of debugging hooks. This must be called + before `malloc' is ever called. ABORTFUNC is called with an error code + (see enum above) when an inconsistency is detected. If ABORTFUNC is + null, the standard function prints on stderr and then calls `abort'. */ +extern int mcheck __P ((void (*__abortfunc) __P ((enum mcheck_status)))); + +/* Check for aberrations in a particular malloc'd block. You must have + called `mcheck' already. These are the same checks that `mcheck' does + when you free or reallocate a block. */ +extern enum mcheck_status mprobe __P ((__ptr_t __ptr)); + +/* Activate a standard collection of tracing hooks. */ +extern void mtrace __P ((void)); +extern void muntrace __P ((void)); + +/* Statistics available to the user. */ +struct mstats + { + __malloc_size_t bytes_total; /* Total size of the heap. */ + __malloc_size_t chunks_used; /* Chunks allocated by the user. */ + __malloc_size_t bytes_used; /* Byte total of user-allocated chunks. */ + __malloc_size_t chunks_free; /* Chunks in the free list. */ + __malloc_size_t bytes_free; /* Byte total of chunks in the free list. */ + }; + +/* Pick up the current statistics. */ +extern struct mstats mstats __P ((void)); + +/* Call WARNFUN with a warning message when memory usage is high. */ +extern void memory_warnings __P ((__ptr_t __start, + void (*__warnfun) __P ((const char *)))); + + +/* Relocating allocator. */ + +/* Allocate SIZE bytes, and store the address in *HANDLEPTR. */ +extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); + +/* Free the storage allocated in HANDLEPTR. */ +extern void r_alloc_free __P ((__ptr_t *__handleptr)); + +/* Adjust the block at HANDLEPTR to be SIZE bytes long. */ +extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); + + +#ifdef __cplusplus +} +#endif + +#endif /* malloc.h */ +/* Memory allocator `malloc'. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif +#include <errno.h> + +/* How to really get more memory. */ +__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore; + +/* Debugging hook for `malloc'. */ +__ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); + +/* Pointer to the base of the first block. */ +char *_heapbase; + +/* Block information table. Allocated with align/__free (not malloc/free). */ +malloc_info *_heapinfo; + +/* Number of info entries. */ +static __malloc_size_t heapsize; + +/* Search index in the info table. */ +__malloc_size_t _heapindex; + +/* Limit of valid info table indices. */ +__malloc_size_t _heaplimit; + +/* Free lists for each fragment size. */ +struct list _fraghead[BLOCKLOG]; + +/* Instrumentation. */ +__malloc_size_t _chunks_used; +__malloc_size_t _bytes_used; +__malloc_size_t _chunks_free; +__malloc_size_t _bytes_free; + +/* Are you experienced? */ +int __malloc_initialized; + +__malloc_size_t __malloc_extra_blocks; + +void (*__malloc_initialize_hook) __P ((void)); +void (*__after_morecore_hook) __P ((void)); + + +/* Aligned allocation. */ +static __ptr_t align __P ((__malloc_size_t)); +static __ptr_t +align (size) + __malloc_size_t size; +{ + __ptr_t result; + unsigned long int adj; + + result = (*__morecore) (size); + adj = (unsigned long int) ((unsigned long int) ((char *) result - + (char *) NULL)) % BLOCKSIZE; + if (adj != 0) + { + __ptr_t new; + adj = BLOCKSIZE - adj; + new = (*__morecore) (adj); + result = (char *) result + adj; + } + + if (__after_morecore_hook) + (*__after_morecore_hook) (); + + return result; +} + +/* Get SIZE bytes, if we can get them starting at END. + Return the address of the space we got. + If we cannot get space at END, fail and return -1. */ +static __ptr_t get_contiguous_space __P ((__malloc_ptrdiff_t, __ptr_t)); +static __ptr_t +get_contiguous_space (size, position) + __malloc_ptrdiff_t size; + __ptr_t position; +{ + __ptr_t before; + __ptr_t after; + + before = (*__morecore) (0); + /* If we can tell in advance that the break is at the wrong place, + fail now. */ + if (before != position) + return 0; + + /* Allocate SIZE bytes and get the address of them. */ + after = (*__morecore) (size); + if (!after) + return 0; + + /* It was not contiguous--reject it. */ + if (after != position) + { + (*__morecore) (- size); + return 0; + } + + return after; +} + + +/* This is called when `_heapinfo' and `heapsize' have just + been set to describe a new info table. Set up the table + to describe itself and account for it in the statistics. */ +static void register_heapinfo __P ((void)); +#ifdef __GNUC__ +__inline__ +#endif +static void +register_heapinfo () +{ + __malloc_size_t block, blocks; + + block = BLOCK (_heapinfo); + blocks = BLOCKIFY (heapsize * sizeof (malloc_info)); + + /* Account for the _heapinfo block itself in the statistics. */ + _bytes_used += blocks * BLOCKSIZE; + ++_chunks_used; + + /* Describe the heapinfo block itself in the heapinfo. */ + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + /* Leave back-pointers for malloc_find_address. */ + while (--blocks > 0) + _heapinfo[block + blocks].busy.info.size = -blocks; +} + +/* Set everything up and remember that we have. */ +int +__malloc_initialize () +{ + if (__malloc_initialized) + return 0; + + if (__malloc_initialize_hook) + (*__malloc_initialize_hook) (); + + heapsize = HEAP / BLOCKSIZE; + _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info)); + if (_heapinfo == NULL) + return 0; + memset (_heapinfo, 0, heapsize * sizeof (malloc_info)); + _heapinfo[0].free.size = 0; + _heapinfo[0].free.next = _heapinfo[0].free.prev = 0; + _heapindex = 0; + _heapbase = (char *) _heapinfo; + _heaplimit = BLOCK (_heapbase + heapsize * sizeof (malloc_info)); + + register_heapinfo (); + + __malloc_initialized = 1; + return 1; +} + +static int morecore_recursing; + +/* Get neatly aligned memory, initializing or + growing the heap info table as necessary. */ +static __ptr_t morecore __P ((__malloc_size_t)); +static __ptr_t +morecore (size) + __malloc_size_t size; +{ + __ptr_t result; + malloc_info *newinfo, *oldinfo; + __malloc_size_t newsize; + + if (morecore_recursing) + /* Avoid recursion. The caller will know how to handle a null return. */ + return NULL; + + result = align (size); + if (result == NULL) + return NULL; + + /* Check if we need to grow the info table. */ + if ((__malloc_size_t) BLOCK ((char *) result + size) > heapsize) + { + /* Calculate the new _heapinfo table size. We do not account for the + added blocks in the table itself, as we hope to place them in + existing free space, which is already covered by part of the + existing table. */ + newsize = heapsize; + do + newsize *= 2; + while ((__malloc_size_t) BLOCK ((char *) result + size) > newsize); + + /* We must not reuse existing core for the new info table when called + from realloc in the case of growing a large block, because the + block being grown is momentarily marked as free. In this case + _heaplimit is zero so we know not to reuse space for internal + allocation. */ + if (_heaplimit != 0) + { + /* First try to allocate the new info table in core we already + have, in the usual way using realloc. If realloc cannot + extend it in place or relocate it to existing sufficient core, + we will get called again, and the code above will notice the + `morecore_recursing' flag and return null. */ + int save = errno; /* Don't want to clobber errno with ENOMEM. */ + morecore_recursing = 1; + newinfo = (malloc_info *) _realloc_internal + (_heapinfo, newsize * sizeof (malloc_info)); + morecore_recursing = 0; + if (newinfo == NULL) + errno = save; + else + { + /* We found some space in core, and realloc has put the old + table's blocks on the free list. Now zero the new part + of the table and install the new table location. */ + memset (&newinfo[heapsize], 0, + (newsize - heapsize) * sizeof (malloc_info)); + _heapinfo = newinfo; + heapsize = newsize; + goto got_heap; + } + } + + /* Allocate new space for the malloc info table. */ + while (1) + { + newinfo = (malloc_info *) align (newsize * sizeof (malloc_info)); + + /* Did it fail? */ + if (newinfo == NULL) + { + (*__morecore) (-size); + return NULL; + } + + /* Is it big enough to record status for its own space? + If so, we win. */ + if ((__malloc_size_t) BLOCK ((char *) newinfo + + newsize * sizeof (malloc_info)) + < newsize) + break; + + /* Must try again. First give back most of what we just got. */ + (*__morecore) (- newsize * sizeof (malloc_info)); + newsize *= 2; + } + + /* Copy the old table to the beginning of the new, + and zero the rest of the new table. */ + memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info)); + memset (&newinfo[heapsize], 0, + (newsize - heapsize) * sizeof (malloc_info)); + oldinfo = _heapinfo; + _heapinfo = newinfo; + heapsize = newsize; + + register_heapinfo (); + + /* Reset _heaplimit so _free_internal never decides + it can relocate or resize the info table. */ + _heaplimit = 0; + _free_internal (oldinfo); + + /* The new heap limit includes the new table just allocated. */ + _heaplimit = BLOCK ((char *) newinfo + heapsize * sizeof (malloc_info)); + return result; + } + + got_heap: + _heaplimit = BLOCK ((char *) result + size); + return result; +} + +/* Allocate memory from the heap. */ +__ptr_t +_malloc_internal (size) + __malloc_size_t size; +{ + __ptr_t result; + __malloc_size_t block, blocks, lastblocks, start; + register __malloc_size_t i; + struct list *next; + + /* ANSI C allows `malloc (0)' to either return NULL, or to return a + valid address you can realloc and free (though not dereference). + + It turns out that some extant code (sunrpc, at least Ultrix's version) + expects `malloc (0)' to return non-NULL and breaks otherwise. + Be compatible. */ + +#if 0 + if (size == 0) + return NULL; +#endif + + if (size < sizeof (struct list)) + size = sizeof (struct list); + +#ifdef SUNOS_LOCALTIME_BUG + if (size < 16) + size = 16; +#endif + + /* Determine the allocation policy based on the request size. */ + if (size <= BLOCKSIZE / 2) + { + /* Small allocation to receive a fragment of a block. + Determine the logarithm to base two of the fragment size. */ + register __malloc_size_t log = 1; + --size; + while ((size /= 2) != 0) + ++log; + + /* Look in the fragment lists for a + free fragment of the desired size. */ + next = _fraghead[log].next; + if (next != NULL) + { + /* There are free fragments of this size. + Pop a fragment out of the fragment list and return it. + Update the block's nfree and first counters. */ + result = (__ptr_t) next; + next->prev->next = next->next; + if (next->next != NULL) + next->next->prev = next->prev; + block = BLOCK (result); + if (--_heapinfo[block].busy.info.frag.nfree != 0) + _heapinfo[block].busy.info.frag.first = (unsigned long int) + ((unsigned long int) ((char *) next->next - (char *) NULL) + % BLOCKSIZE) >> log; + + /* Update the statistics. */ + ++_chunks_used; + _bytes_used += 1 << log; + --_chunks_free; + _bytes_free -= 1 << log; + } + else + { + /* No free fragments of the desired size, so get a new block + and break it into fragments, returning the first. */ + result = malloc (BLOCKSIZE); + if (result == NULL) + return NULL; + + /* Link all fragments but the first into the free list. */ + next = (struct list *) ((char *) result + (1 << log)); + next->next = NULL; + next->prev = &_fraghead[log]; + _fraghead[log].next = next; + + for (i = 2; i < (__malloc_size_t) (BLOCKSIZE >> log); ++i) + { + next = (struct list *) ((char *) result + (i << log)); + next->next = _fraghead[log].next; + next->prev = &_fraghead[log]; + next->prev->next = next; + next->next->prev = next; + } + + /* Initialize the nfree and first counters for this block. */ + block = BLOCK (result); + _heapinfo[block].busy.type = log; + _heapinfo[block].busy.info.frag.nfree = i - 1; + _heapinfo[block].busy.info.frag.first = i - 1; + + _chunks_free += (BLOCKSIZE >> log) - 1; + _bytes_free += BLOCKSIZE - (1 << log); + _bytes_used -= BLOCKSIZE - (1 << log); + } + } + else + { + /* Large allocation to receive one or more blocks. + Search the free list in a circle starting at the last place visited. + If we loop completely around without finding a large enough + space we will have to get more memory from the system. */ + blocks = BLOCKIFY (size); + start = block = _heapindex; + while (_heapinfo[block].free.size < blocks) + { + block = _heapinfo[block].free.next; + if (block == start) + { + /* Need to get more from the system. Get a little extra. */ + __malloc_size_t wantblocks = blocks + __malloc_extra_blocks; + block = _heapinfo[0].free.prev; + lastblocks = _heapinfo[block].free.size; + /* Check to see if the new core will be contiguous with the + final free block; if so we don't need to get as much. */ + if (_heaplimit != 0 && block + lastblocks == _heaplimit && + /* We can't do this if we will have to make the heap info + table bigger to accomodate the new space. */ + block + wantblocks <= heapsize && + get_contiguous_space ((wantblocks - lastblocks) * BLOCKSIZE, + ADDRESS (block + lastblocks))) + { + /* We got it contiguously. Which block we are extending + (the `final free block' referred to above) might have + changed, if it got combined with a freed info table. */ + block = _heapinfo[0].free.prev; + _heapinfo[block].free.size += (wantblocks - lastblocks); + _bytes_free += (wantblocks - lastblocks) * BLOCKSIZE; + _heaplimit += wantblocks - lastblocks; + continue; + } + result = morecore (wantblocks * BLOCKSIZE); + if (result == NULL) + return NULL; + block = BLOCK (result); + /* Put the new block at the end of the free list. */ + _heapinfo[block].free.size = wantblocks; + _heapinfo[block].free.prev = _heapinfo[0].free.prev; + _heapinfo[block].free.next = 0; + _heapinfo[0].free.prev = block; + _heapinfo[_heapinfo[block].free.prev].free.next = block; + ++_chunks_free; + /* Now loop to use some of that block for this allocation. */ + } + } + + /* At this point we have found a suitable free list entry. + Figure out how to remove what we need from the list. */ + result = ADDRESS (block); + if (_heapinfo[block].free.size > blocks) + { + /* The block we found has a bit left over, + so relink the tail end back into the free list. */ + _heapinfo[block + blocks].free.size + = _heapinfo[block].free.size - blocks; + _heapinfo[block + blocks].free.next + = _heapinfo[block].free.next; + _heapinfo[block + blocks].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[_heapinfo[block].free.next].free.prev + = _heapindex = block + blocks; + } + else + { + /* The block exactly matches our requirements, + so just remove it from the list. */ + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapindex = _heapinfo[block].free.next; + --_chunks_free; + } + + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + ++_chunks_used; + _bytes_used += blocks * BLOCKSIZE; + _bytes_free -= blocks * BLOCKSIZE; + + /* Mark all the blocks of the object just allocated except for the + first with a negative number so you can find the first block by + adding that adjustment. */ + while (--blocks > 0) + _heapinfo[block + blocks].busy.info.size = -blocks; + } + + return result; +} + +__ptr_t +malloc (size) + __malloc_size_t size; +{ + if (!__malloc_initialized && !__malloc_initialize ()) + return NULL; + + return (__malloc_hook != NULL ? *__malloc_hook : _malloc_internal) (size); +} + +#ifndef _LIBC + +/* On some ANSI C systems, some libc functions call _malloc, _free + and _realloc. Make them use the GNU functions. */ + +__ptr_t +_malloc (size) + __malloc_size_t size; +{ + return malloc (size); +} + +void +_free (ptr) + __ptr_t ptr; +{ + free (ptr); +} + +__ptr_t +_realloc (ptr, size) + __ptr_t ptr; + __malloc_size_t size; +{ + return realloc (ptr, size); +} + +#endif +/* Free a block of memory allocated by `malloc'. + Copyright 1990, 1991, 1992, 1994, 1995 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + + +/* Cope with systems lacking `memmove'. */ +#ifndef memmove +#if (defined (MEMMOVE_MISSING) || \ + !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG)) +#ifdef emacs +#undef __malloc_safe_bcopy +#define __malloc_safe_bcopy safe_bcopy +#endif +/* This function is defined in realloc.c. */ +extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); +#define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) +#endif +#endif + + +/* Debugging hook for free. */ +void (*__free_hook) __P ((__ptr_t __ptr)); + +/* List of blocks allocated by memalign. */ +struct alignlist *_aligned_blocks = NULL; + +/* Return memory to the heap. + Like `free' but don't call a __free_hook if there is one. */ +void +_free_internal (ptr) + __ptr_t ptr; +{ + int type; + __malloc_size_t block, blocks; + register __malloc_size_t i; + struct list *prev, *next; + __ptr_t curbrk; + const __malloc_size_t lesscore_threshold + /* Threshold of free space at which we will return some to the system. */ + = FINAL_FREE_BLOCKS + 2 * __malloc_extra_blocks; + + register struct alignlist *l; + + if (ptr == NULL) + return; + + for (l = _aligned_blocks; l != NULL; l = l->next) + if (l->aligned == ptr) + { + l->aligned = NULL; /* Mark the slot in the list as free. */ + ptr = l->exact; + break; + } + + block = BLOCK (ptr); + + type = _heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Get as many statistics as early as we can. */ + --_chunks_used; + _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; + _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; + + /* Find the free cluster previous to this one in the free list. + Start searching at the last block referenced; this may benefit + programs with locality of allocation. */ + i = _heapindex; + if (i > block) + while (i > block) + i = _heapinfo[i].free.prev; + else + { + do + i = _heapinfo[i].free.next; + while (i > 0 && i < block); + i = _heapinfo[i].free.prev; + } + + /* Determine how to link this block into the free list. */ + if (block == i + _heapinfo[i].free.size) + { + /* Coalesce this block with its predecessor. */ + _heapinfo[i].free.size += _heapinfo[block].busy.info.size; + block = i; + } + else + { + /* Really link this block back into the free list. */ + _heapinfo[block].free.size = _heapinfo[block].busy.info.size; + _heapinfo[block].free.next = _heapinfo[i].free.next; + _heapinfo[block].free.prev = i; + _heapinfo[i].free.next = block; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + ++_chunks_free; + } + + /* Now that the block is linked in, see if we can coalesce it + with its successor (by deleting its successor from the list + and adding in its size). */ + if (block + _heapinfo[block].free.size == _heapinfo[block].free.next) + { + _heapinfo[block].free.size + += _heapinfo[_heapinfo[block].free.next].free.size; + _heapinfo[block].free.next + = _heapinfo[_heapinfo[block].free.next].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + --_chunks_free; + } + + /* How many trailing free blocks are there now? */ + blocks = _heapinfo[block].free.size; + + /* Where is the current end of accessible core? */ + curbrk = (*__morecore) (0); + + if (_heaplimit != 0 && curbrk == ADDRESS (_heaplimit)) + { + /* The end of the malloc heap is at the end of accessible core. + It's possible that moving _heapinfo will allow us to + return some space to the system. */ + + __malloc_size_t info_block = BLOCK (_heapinfo); + __malloc_size_t info_blocks = _heapinfo[info_block].busy.info.size; + __malloc_size_t prev_block = _heapinfo[block].free.prev; + __malloc_size_t prev_blocks = _heapinfo[prev_block].free.size; + __malloc_size_t next_block = _heapinfo[block].free.next; + __malloc_size_t next_blocks = _heapinfo[next_block].free.size; + + if (/* Win if this block being freed is last in core, the info table + is just before it, the previous free block is just before the + info table, and the two free blocks together form a useful + amount to return to the system. */ + (block + blocks == _heaplimit && + info_block + info_blocks == block && + prev_block != 0 && prev_block + prev_blocks == info_block && + blocks + prev_blocks >= lesscore_threshold) || + /* Nope, not the case. We can also win if this block being + freed is just before the info table, and the table extends + to the end of core or is followed only by a free block, + and the total free space is worth returning to the system. */ + (block + blocks == info_block && + ((info_block + info_blocks == _heaplimit && + blocks >= lesscore_threshold) || + (info_block + info_blocks == next_block && + next_block + next_blocks == _heaplimit && + blocks + next_blocks >= lesscore_threshold))) + ) + { + malloc_info *newinfo; + __malloc_size_t oldlimit = _heaplimit; + + /* Free the old info table, clearing _heaplimit to avoid + recursion into this code. We don't want to return the + table's blocks to the system before we have copied them to + the new location. */ + _heaplimit = 0; + _free_internal (_heapinfo); + _heaplimit = oldlimit; + + /* Tell malloc to search from the beginning of the heap for + free blocks, so it doesn't reuse the ones just freed. */ + _heapindex = 0; + + /* Allocate new space for the info table and move its data. */ + newinfo = (malloc_info *) _malloc_internal (info_blocks + * BLOCKSIZE); + memmove (newinfo, _heapinfo, info_blocks * BLOCKSIZE); + _heapinfo = newinfo; + + /* We should now have coalesced the free block with the + blocks freed from the old info table. Examine the entire + trailing free block to decide below whether to return some + to the system. */ + block = _heapinfo[0].free.prev; + blocks = _heapinfo[block].free.size; + } + + /* Now see if we can return stuff to the system. */ + if (block + blocks == _heaplimit && blocks >= lesscore_threshold) + { + register __malloc_size_t bytes = blocks * BLOCKSIZE; + _heaplimit -= blocks; + (*__morecore) (-bytes); + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[block].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + block = _heapinfo[block].free.prev; + --_chunks_free; + _bytes_free -= bytes; + } + } + + /* Set the next search to begin at this block. */ + _heapindex = block; + break; + + default: + /* Do some of the statistics. */ + --_chunks_used; + _bytes_used -= 1 << type; + ++_chunks_free; + _bytes_free += 1 << type; + + /* Get the address of the first free fragment in this block. */ + prev = (struct list *) ((char *) ADDRESS (block) + + (_heapinfo[block].busy.info.frag.first << type)); + + if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1) + { + /* If all fragments of this block are free, remove them + from the fragment list and free the whole block. */ + next = prev; + for (i = 1; i < (__malloc_size_t) (BLOCKSIZE >> type); ++i) + next = next->next; + prev->prev->next = next; + if (next != NULL) + next->prev = prev->prev; + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = 1; + + /* Keep the statistics accurate. */ + ++_chunks_used; + _bytes_used += BLOCKSIZE; + _chunks_free -= BLOCKSIZE >> type; + _bytes_free -= BLOCKSIZE; + + free (ADDRESS (block)); + } + else if (_heapinfo[block].busy.info.frag.nfree != 0) + { + /* If some fragments of this block are free, link this + fragment into the fragment list after the first free + fragment of this block. */ + next = (struct list *) ptr; + next->next = prev->next; + next->prev = prev; + prev->next = next; + if (next->next != NULL) + next->next->prev = next; + ++_heapinfo[block].busy.info.frag.nfree; + } + else + { + /* No fragments of this block are free, so link this + fragment into the fragment list and announce that + it is the first free fragment of this block. */ + prev = (struct list *) ptr; + _heapinfo[block].busy.info.frag.nfree = 1; + _heapinfo[block].busy.info.frag.first = (unsigned long int) + ((unsigned long int) ((char *) ptr - (char *) NULL) + % BLOCKSIZE >> type); + prev->next = _fraghead[type].next; + prev->prev = &_fraghead[type]; + prev->prev->next = prev; + if (prev->next != NULL) + prev->next->prev = prev; + } + break; + } +} + +/* Return memory to the heap. */ +void +free (ptr) + __ptr_t ptr; +{ + if (__free_hook != NULL) + (*__free_hook) (ptr); + else + _free_internal (ptr); +} + +/* Define the `cfree' alias for `free'. */ +#ifdef weak_alias +weak_alias (free, cfree) +#else +void +cfree (ptr) + __ptr_t ptr; +{ + free (ptr); +} +#endif +/* Change the size of a block allocated by `malloc'. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + + + +/* Cope with systems lacking `memmove'. */ +#if (defined (MEMMOVE_MISSING) || \ + !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG)) + +#ifdef emacs +#undef __malloc_safe_bcopy +#define __malloc_safe_bcopy safe_bcopy +#else + +/* Snarfed directly from Emacs src/dispnew.c: + XXX Should use system bcopy if it handles overlap. */ + +/* Like bcopy except never gets confused by overlap. */ + +void +__malloc_safe_bcopy (afrom, ato, size) + __ptr_t afrom; + __ptr_t ato; + __malloc_size_t size; +{ + char *from = afrom, *to = ato; + + if (size <= 0 || from == to) + return; + + /* If the source and destination don't overlap, then bcopy can + handle it. If they do overlap, but the destination is lower in + memory than the source, we'll assume bcopy can handle that. */ + if (to < from || from + size <= to) + bcopy (from, to, size); + + /* Otherwise, we'll copy from the end. */ + else + { + register char *endf = from + size; + register char *endt = to + size; + + /* If TO - FROM is large, then we should break the copy into + nonoverlapping chunks of TO - FROM bytes each. However, if + TO - FROM is small, then the bcopy function call overhead + makes this not worth it. The crossover point could be about + anywhere. Since I don't think the obvious copy loop is too + bad, I'm trying to err in its favor. */ + if (to - from < 64) + { + do + *--endt = *--endf; + while (endf != from); + } + else + { + for (;;) + { + endt -= (to - from); + endf -= (to - from); + + if (endt < to) + break; + + bcopy (endf, endt, to - from); + } + + /* If SIZE wasn't a multiple of TO - FROM, there will be a + little left over. The amount left over is + (endt + (to - from)) - to, which is endt - from. */ + bcopy (from, to, endt - from); + } + } +} +#endif /* emacs */ + +#ifndef memmove +extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); +#define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) +#endif + +#endif + + +#define min(A, B) ((A) < (B) ? (A) : (B)) + +/* Debugging hook for realloc. */ +__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); + +/* Resize the given region to the new size, returning a pointer + to the (possibly moved) region. This is optimized for speed; + some benchmarks seem to indicate that greater compactness is + achieved by unconditionally allocating and copying to a + new region. This module has incestuous knowledge of the + internals of both free and malloc. */ +__ptr_t +_realloc_internal (ptr, size) + __ptr_t ptr; + __malloc_size_t size; +{ + __ptr_t result; + int type; + __malloc_size_t block, blocks, oldlimit; + + if (size == 0) + { + _free_internal (ptr); + return _malloc_internal (0); + } + else if (ptr == NULL) + return _malloc_internal (size); + + block = BLOCK (ptr); + + type = _heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Maybe reallocate a large block to a small fragment. */ + if (size <= BLOCKSIZE / 2) + { + result = _malloc_internal (size); + if (result != NULL) + { + memcpy (result, ptr, size); + _free_internal (ptr); + return result; + } + } + + /* The new size is a large allocation as well; + see if we can hold it in place. */ + blocks = BLOCKIFY (size); + if (blocks < _heapinfo[block].busy.info.size) + { + /* The new size is smaller; return + excess memory to the free list. */ + _heapinfo[block + blocks].busy.type = 0; + _heapinfo[block + blocks].busy.info.size + = _heapinfo[block].busy.info.size - blocks; + _heapinfo[block].busy.info.size = blocks; + /* We have just created a new chunk by splitting a chunk in two. + Now we will free this chunk; increment the statistics counter + so it doesn't become wrong when _free_internal decrements it. */ + ++_chunks_used; + _free_internal (ADDRESS (block + blocks)); + result = ptr; + } + else if (blocks == _heapinfo[block].busy.info.size) + /* No size change necessary. */ + result = ptr; + else + { + /* Won't fit, so allocate a new region that will. + Free the old region first in case there is sufficient + adjacent free space to grow without moving. */ + blocks = _heapinfo[block].busy.info.size; + /* Prevent free from actually returning memory to the system. */ + oldlimit = _heaplimit; + _heaplimit = 0; + _free_internal (ptr); + result = _malloc_internal (size); + if (_heaplimit == 0) + _heaplimit = oldlimit; + if (result == NULL) + { + /* Now we're really in trouble. We have to unfree + the thing we just freed. Unfortunately it might + have been coalesced with its neighbors. */ + if (_heapindex == block) + (void) _malloc_internal (blocks * BLOCKSIZE); + else + { + __ptr_t previous + = _malloc_internal ((block - _heapindex) * BLOCKSIZE); + (void) _malloc_internal (blocks * BLOCKSIZE); + _free_internal (previous); + } + return NULL; + } + if (ptr != result) + memmove (result, ptr, blocks * BLOCKSIZE); + } + break; + + default: + /* Old size is a fragment; type is logarithm + to base two of the fragment size. */ + if (size > (__malloc_size_t) (1 << (type - 1)) && + size <= (__malloc_size_t) (1 << type)) + /* The new size is the same kind of fragment. */ + result = ptr; + else + { + /* The new size is different; allocate a new space, + and copy the lesser of the new size and the old. */ + result = _malloc_internal (size); + if (result == NULL) + return NULL; + memcpy (result, ptr, min (size, (__malloc_size_t) 1 << type)); + _free_internal (ptr); + } + break; + } + + return result; +} + +__ptr_t +realloc (ptr, size) + __ptr_t ptr; + __malloc_size_t size; +{ + if (!__malloc_initialized && !__malloc_initialize ()) + return NULL; + + return (__realloc_hook != NULL ? *__realloc_hook : _realloc_internal) + (ptr, size); +} +/* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +/* Allocate an array of NMEMB elements each SIZE bytes long. + The entire array is initialized to zeros. */ +__ptr_t +calloc (nmemb, size) + register __malloc_size_t nmemb; + register __malloc_size_t size; +{ + register __ptr_t result = malloc (nmemb * size); + + if (result != NULL) + (void) memset (result, 0, nmemb * size); + + return result; +} +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the GNU C Library; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +#ifndef __GNU_LIBRARY__ +#define __sbrk sbrk +#endif + +#ifdef __GNU_LIBRARY__ +/* It is best not to declare this and cast its result on foreign operating + systems with potentially hostile include files. */ + +#include <stddef.h> +extern __ptr_t __sbrk __P ((ptrdiff_t increment)); +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* Allocate INCREMENT more bytes of data space, + and return the start of data space, or NULL on errors. + If INCREMENT is negative, shrink data space. */ +__ptr_t +__default_morecore (increment) + __malloc_ptrdiff_t increment; +{ + __ptr_t result = (__ptr_t) __sbrk (increment); + if (result == (__ptr_t) -1) + return NULL; + return result; +} +/* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +#if __DJGPP__ - 0 == 1 + +/* There is some problem with memalign in DJGPP v1 and we are supposed + to omit it. Noone told me why, they just told me to do it. */ + +#else + +__ptr_t (*__memalign_hook) __P ((size_t __size, size_t __alignment)); + +__ptr_t +memalign (alignment, size) + __malloc_size_t alignment; + __malloc_size_t size; +{ + __ptr_t result; + unsigned long int adj, lastadj; + + if (__memalign_hook) + return (*__memalign_hook) (alignment, size); + + /* Allocate a block with enough extra space to pad the block with up to + (ALIGNMENT - 1) bytes if necessary. */ + result = malloc (size + alignment - 1); + if (result == NULL) + return NULL; + + /* Figure out how much we will need to pad this particular block + to achieve the required alignment. */ + adj = (unsigned long int) ((char *) result - (char *) NULL) % alignment; + + do + { + /* Reallocate the block with only as much excess as it needs. */ + free (result); + result = malloc (adj + size); + if (result == NULL) /* Impossible unless interrupted. */ + return NULL; + + lastadj = adj; + adj = (unsigned long int) ((char *) result - (char *) NULL) % alignment; + /* It's conceivable we might have been so unlucky as to get a + different block with weaker alignment. If so, this block is too + short to contain SIZE after alignment correction. So we must + try again and get another block, slightly larger. */ + } while (adj > lastadj); + + if (adj != 0) + { + /* Record this block in the list of aligned blocks, so that `free' + can identify the pointer it is passed, which will be in the middle + of an allocated block. */ + + struct alignlist *l; + for (l = _aligned_blocks; l != NULL; l = l->next) + if (l->aligned == NULL) + /* This slot is free. Use it. */ + break; + if (l == NULL) + { + l = (struct alignlist *) malloc (sizeof (struct alignlist)); + if (l == NULL) + { + free (result); + return NULL; + } + l->next = _aligned_blocks; + _aligned_blocks = l; + } + l->exact = result; + result = l->aligned = (char *) result + alignment - adj; + } + + return result; +} + +#endif /* Not DJGPP v1 */ diff --git a/lib/malloc/omalloc.c b/lib/malloc/omalloc.c new file mode 100644 index 00000000..a8b232a1 --- /dev/null +++ b/lib/malloc/omalloc.c @@ -0,0 +1,759 @@ +/* dynamic memory allocation for GNU. */ + +/* Copyright (C) 1985, 1987 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +In other words, you are welcome to use, share and improve this program. +You are forbidden to forbid anyone else to use, share and improve +what you give them. Help stamp out software-hoarding! */ + +/* + * @(#)nmalloc.c 1 (Caltech) 2/21/82 + * + * U of M Modified: 20 Jun 1983 ACT: strange hacks for Emacs + * + * Nov 1983, Mike@BRL, Added support for 4.1C/4.2 BSD. + * + * This is a very fast storage allocator. It allocates blocks of a small + * number of different sizes, and keeps free lists of each size. Blocks + * that don't exactly fit are passed up to the next larger size. In this + * implementation, the available sizes are (2^n)-4 (or -16) bytes long. + * This is designed for use in a program that uses vast quantities of + * memory, but bombs when it runs out. To make it a little better, it + * warns the user when he starts to get near the end. + * + * June 84, ACT: modified rcheck code to check the range given to malloc, + * rather than the range determined by the 2-power used. + * + * Jan 85, RMS: calls malloc_warning to issue warning on nearly full. + * No longer Emacs-specific; can serve as all-purpose malloc for GNU. + * You should call malloc_init to reinitialize after loading dumped Emacs. + * Call malloc_stats to get info on memory stats if MSTATS turned on. + * realloc knows how to return same block given, just changing its size, + * if the power of 2 is correct. + */ + +/* + * nextf[i] is the pointer to the next free block of size 2^(i+3). The + * smallest allocatable block is 8 bytes. The overhead information will + * go in the first int of the block, and the returned pointer will point + * to the second. + * +#ifdef MSTATS + * nmalloc[i] is the difference between the number of mallocs and frees + * for a given block size. +#endif + */ + +/* Define this to have free() write 0xcf into memory as it's freed, to + uncover callers that refer to freed memory. */ +/* SCO 3.2v4 getcwd and possibly other libc routines fail with MEMSCRAMBLE */ +#if !defined (NO_MEMSCRAMBLE) +# define MEMSCRAMBLE +#endif + +#if defined (emacs) || defined (HAVE_CONFIG_H) +# include <config.h> +#endif /* emacs */ + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +/* Determine which kind of system this is. */ +#if defined (SHELL) +# include "bashtypes.h" +#else +# include <sys/types.h> +#endif +#include <signal.h> + +/* Define getpagesize () if the system does not. */ +#ifndef HAVE_GETPAGESIZE +# include "getpagesize.h" +#endif + +#if defined (HAVE_RESOURCE) +# include <sys/time.h> +# include <sys/resource.h> +#endif /* HAVE_RESOURCE */ + +/* Check for the needed symbols. If they aren't present, this + system's <sys/resource.h> isn't very useful to us. */ +#if !defined (RLIMIT_DATA) +# undef HAVE_RESOURCE +#endif + +#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__ */ + +#if !defined (NULL) +# define NULL 0 +#endif + +#define start_of_data() &etext + +#define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */ +#define ISFREE ((char) 0x54) /* magic byte that implies free block */ + /* this is for error checking only */ +#define ISMEMALIGN ((char) 0xd6) /* Stored before the value returned by + memalign, with the rest of the word + being the distance to the true + beginning of the block. */ +extern char etext; + +#if !defined (SBRK_DECLARED) +extern char *sbrk (); +#endif /* !SBRK_DECLARED */ + +/* These two are for user programs to look at, when they are interested. */ +unsigned int malloc_sbrk_used; /* amount of data space used now */ +unsigned int malloc_sbrk_unused; /* amount more we can have */ + +/* start of data space; can be changed by calling init_malloc */ +static char *data_space_start; + +static void get_lim_data (); + +#ifdef MSTATS +static int nmalloc[30]; +static int nmal, nfre; +#endif /* MSTATS */ + +/* If range checking is not turned on, all we have is a flag indicating + whether memory is allocated, an index in nextf[], and a size field; to + realloc() memory we copy either size bytes or 1<<(index+3) bytes depending + on whether the former can hold the exact size (given the value of + 'index'). If range checking is on, we always need to know how much space + is allocated, so the 'size' field is never used. */ + +struct mhead { + char mh_alloc; /* ISALLOC or ISFREE */ + char mh_index; /* index in nextf[] */ +/* Remainder are valid only when block is allocated */ + unsigned short mh_size; /* size, if < 0x10000 */ +#ifdef RCHECK + unsigned int mh_nbytes; /* number of bytes allocated */ + int mh_magic4; /* should be == MAGIC4 */ +#endif /* RCHECK */ +}; + +/* Access free-list pointer of a block. + It is stored at block + 4. + This is not a field in the mhead structure + because we want sizeof (struct mhead) + to describe the overhead for when the block is in use, + and we do not want the free-list pointer to count in that. */ + +#define CHAIN(a) \ + (*(struct mhead **) (sizeof (char *) + (char *) (a))) + +#ifdef RCHECK +# include <stdio.h> +# if !defined (botch) +# define botch(x) abort () +# else +extern void botch(); +# endif /* botch */ + +# if !defined (__STRING) +# if defined (__STDC__) +# define __STRING(x) #x +# else +# define __STRING(x) "x" +# endif +# endif + + /* To implement range checking, we write magic values in at the beginning + and end of each allocated block, and make sure they are undisturbed + whenever a free or a realloc occurs. */ + + /* Written in each of the 4 bytes following the block's real space */ +# define MAGIC1 0x55 + /* Written in the 4 bytes before the block's real space */ +# define MAGIC4 0x55555555 +# define ASSERT(p) if (!(p)) botch(__STRING(p)); else +# define EXTRA 4 /* 4 bytes extra for MAGIC1s */ +#else /* !RCHECK */ +# define ASSERT(p) +# define EXTRA 0 +#endif /* RCHECK */ + +/* nextf[i] is free list of blocks of size 2**(i + 3) */ + +static struct mhead *nextf[30]; + +/* busy[i] is nonzero while allocation of block size i is in progress. */ + +static char busy[30]; + +/* Number of bytes of writable memory we can expect to be able to get */ +static unsigned int lim_data; + +/* Level number of warnings already issued. + 0 -- no warnings issued. + 1 -- 75% warning already issued. + 2 -- 85% warning already issued. +*/ +static int warnlevel; + +/* Function to call to issue a warning; + 0 means don't issue them. */ +static void (*warnfunction) (); + +/* nonzero once initial bunch of free blocks made */ +static int gotpool; + +char *_malloc_base; + +static void getpool (); + +/* Cause reinitialization based on job parameters; + also declare where the end of pure storage is. */ +void +malloc_init (start, warnfun) + char *start; + void (*warnfun) (); +{ + if (start) + data_space_start = start; + lim_data = 0; + warnlevel = 0; + warnfunction = warnfun; +} + +/* Return the maximum size to which MEM can be realloc'd + without actually requiring copying. */ + +int +malloc_usable_size (mem) + char *mem; +{ + int blocksize = 8 << (((struct mhead *) mem) - 1) -> mh_index; + + return blocksize - sizeof (struct mhead) - EXTRA; +} + +static void +morecore (nu) /* ask system for more memory */ + register int nu; /* size index to get more of */ +{ + register char *cp; + register int nblks; + register unsigned int siz; + + /* Block all signals in case we are executed from a signal handler. */ +#if defined (HAVE_BSD_SIGNALS) + int oldmask; + oldmask = sigsetmask (-1); +#else +# if defined (HAVE_POSIX_SIGNALS) + sigset_t set, oset; + sigfillset (&set); + sigemptyset (&oset); + sigprocmask (SIG_BLOCK, &set, &oset); +# endif /* HAVE_POSIX_SIGNALS */ +#endif /* HAVE_BSD_SIGNALS */ + + if (!data_space_start) + { + data_space_start = start_of_data (); + } + + if (lim_data == 0) + get_lim_data (); + + /* On initial startup, get two blocks of each size up to 1k bytes */ + if (!gotpool) + { getpool (); getpool (); gotpool = 1; } + + /* Find current end of memory and issue warning if getting near max */ + + cp = sbrk (0); + siz = cp - data_space_start; + malloc_sbrk_used = siz; + malloc_sbrk_unused = lim_data - siz; + + if (warnfunction) + switch (warnlevel) + { + case 0: + if (siz > (lim_data / 4) * 3) + { + warnlevel++; + (*warnfunction) ("Warning: past 75% of memory limit"); + } + break; + case 1: + if (siz > (lim_data / 20) * 17) + { + warnlevel++; + (*warnfunction) ("Warning: past 85% of memory limit"); + } + break; + case 2: + if (siz > (lim_data / 20) * 19) + { + warnlevel++; + (*warnfunction) ("Warning: past 95% of memory limit"); + } + break; + } + + if ((int) cp & 0x3ff) /* land on 1K boundaries */ + sbrk (1024 - ((int) cp & 0x3ff)); + + /* Take at least 2k, and figure out how many blocks of the desired size + we're about to get */ + nblks = 1; + if ((siz = nu) < 8) + nblks = 1 << ((siz = 8) - nu); + + if ((cp = sbrk (1 << (siz + 3))) == (char *) -1) + return; /* no more room! */ + + if ((int) cp & 7) + { /* shouldn't happen, but just in case */ + cp = (char *) (((int) cp + 8) & ~7); + nblks--; + } + + /* save new header and link the nblks blocks together */ + nextf[nu] = (struct mhead *) cp; + siz = 1 << (nu + 3); + while (1) + { + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = nu; + if (--nblks <= 0) break; + CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz); + cp += siz; + } + CHAIN ((struct mhead *) cp) = 0; + +#if defined (HAVE_BSD_SIGNALS) + sigsetmask (oldmask); +#else +# if defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); +# endif +#endif /* HAVE_BSD_SIGNALS */ +} + +static void +getpool () +{ + register int nu; + register char *cp = sbrk (0); + + if ((int) cp & 0x3ff) /* land on 1K boundaries */ + sbrk (1024 - ((int) cp & 0x3ff)); + + /* Record address of start of space allocated by malloc. */ + if (_malloc_base == 0) + _malloc_base = cp; + + /* Get 2k of storage */ + + cp = sbrk (04000); + if (cp == (char *) -1) + return; + + /* Divide it into an initial 8-word block + plus one block of size 2**nu for nu = 3 ... 10. */ + + CHAIN (cp) = nextf[0]; + nextf[0] = (struct mhead *) cp; + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = 0; + cp += 8; + + for (nu = 0; nu < 7; nu++) + { + CHAIN (cp) = nextf[nu]; + nextf[nu] = (struct mhead *) cp; + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = nu; + cp += 8 << nu; + } +} + +#if defined (MEMSCRAMBLE) || !defined (NO_CALLOC) +static char * +zmemset (s, c, n) + char *s; + int c; + register int n; +{ + register char *sp; + + sp = s; + while (--n >= 0) + *sp++ = c; + return (s); +} +#endif /* MEMSCRAMBLE || !NO_CALLOC */ + +char * +malloc (n) /* get a block */ + unsigned int n; +{ + register struct mhead *p; + register unsigned int nbytes; + register int nunits = 0; + + /* Figure out how many bytes are required, rounding up to the nearest + multiple of 4, then figure out which nextf[] area to use */ + nbytes = (n + sizeof *p + EXTRA + 3) & ~3; + { + register unsigned int shiftr = (nbytes - 1) >> 2; + + while (shiftr >>= 1) + nunits++; + } + + /* In case this is reentrant use of malloc from signal handler, + pick a block size that no other malloc level is currently + trying to allocate. That's the easiest harmless way not to + interfere with the other level of execution. */ + while (busy[nunits]) nunits++; + busy[nunits] = 1; + + /* If there are no blocks of the appropriate size, go get some */ + /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */ + if (nextf[nunits] == 0) + morecore (nunits); + + /* Get one block off the list, and set the new list head */ + if ((p = nextf[nunits]) == 0) + { + busy[nunits] = 0; + return 0; + } + nextf[nunits] = CHAIN (p); + busy[nunits] = 0; + + /* Check for free block clobbered */ + /* If not for this check, we would gobble a clobbered free chain ptr */ + /* and bomb out on the NEXT allocate of this size block */ + if (p -> mh_alloc != ISFREE || p -> mh_index != nunits) +#ifdef RCHECK + botch ("block on free list clobbered"); +#else /* not RCHECK */ + abort (); +#endif /* not RCHECK */ + + /* Fill in the info, and if range checking, set up the magic numbers */ + p -> mh_alloc = ISALLOC; +#ifdef RCHECK + p -> mh_nbytes = n; + p -> mh_magic4 = MAGIC4; + { + register char *m = (char *) (p + 1) + n; + + *m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1; + } +#else /* not RCHECK */ + p -> mh_size = n; +#endif /* not RCHECK */ +#ifdef MEMSCRAMBLE + zmemset ((char *)(p + 1), 0xdf, n); /* scramble previous contents */ +#endif +#ifdef MSTATS + nmalloc[nunits]++; + nmal++; +#endif /* MSTATS */ + return (char *) (p + 1); +} + +void +free (mem) + char *mem; +{ + register struct mhead *p; + { + register char *ap = mem; + + if (ap == 0) + return; + + p = (struct mhead *) ap - 1; + + if (p -> mh_alloc == ISMEMALIGN) + { +#ifdef RCHECK + ap -= p->mh_nbytes; +#else + ap -= p->mh_size; /* XXX */ +#endif + p = (struct mhead *) ap - 1; + } + +#ifndef RCHECK + if (p -> mh_alloc != ISALLOC) + abort (); + +#else /* RCHECK */ + if (p -> mh_alloc != ISALLOC) + { + if (p -> mh_alloc == ISFREE) + botch ("free: Called with already freed block argument\n"); + else + botch ("free: Called with unallocated block argument\n"); + } + + ASSERT (p -> mh_magic4 == MAGIC4); + ap += p -> mh_nbytes; + ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1); + ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1); +#endif /* RCHECK */ + } +#ifdef MEMSCRAMBLE + { + register int n; + +#ifdef RCHECK + n = p->mh_nbytes; +#else /* not RCHECK */ + n = p->mh_size; +#endif /* not RCHECK */ + zmemset (mem, 0xcf, n); + } +#endif + { + register int nunits = p -> mh_index; + + ASSERT (nunits <= 29); + p -> mh_alloc = ISFREE; + + /* Protect against signal handlers calling malloc. */ + busy[nunits] = 1; + /* Put this block on the free list. */ + CHAIN (p) = nextf[nunits]; + nextf[nunits] = p; + busy[nunits] = 0; + +#ifdef MSTATS + nmalloc[nunits]--; + nfre++; +#endif /* MSTATS */ + } +} + +char * +realloc (mem, n) + char *mem; + register unsigned int n; +{ + register struct mhead *p; + register unsigned int tocopy; + register unsigned int nbytes; + register int nunits; + + if ((p = (struct mhead *) mem) == 0) + return malloc (n); + p--; + nunits = p -> mh_index; + ASSERT (p -> mh_alloc == ISALLOC); +#ifdef RCHECK + ASSERT (p -> mh_magic4 == MAGIC4); + { + register char *m = mem + (tocopy = p -> mh_nbytes); + ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1); + ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1); + } +#else /* not RCHECK */ + if (p -> mh_index >= 13) + tocopy = (1 << (p -> mh_index + 3)) - sizeof *p; + else + tocopy = p -> mh_size; +#endif /* not RCHECK */ + + /* See if desired size rounds to same power of 2 as actual size. */ + nbytes = (n + sizeof *p + EXTRA + 7) & ~7; + + /* If ok, use the same block, just marking its size as changed. */ + if (nbytes > (4 << nunits) && nbytes <= (8 << nunits)) + { +#ifdef RCHECK + register char *m = mem + tocopy; + *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0; + p-> mh_nbytes = n; + m = mem + n; + *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; +#else /* not RCHECK */ + p -> mh_size = n; +#endif /* not RCHECK */ + return mem; + } + + if (n < tocopy) + tocopy = n; + { + register char *new; + + if ((new = malloc (n)) == 0) + return 0; + FASTCOPY (mem, new, tocopy); + free (mem); + return new; + } +} + +char * +memalign (alignment, size) + unsigned int alignment, size; +{ + register char *ptr; + register char *aligned; + register struct mhead *p; + + ptr = malloc (size + alignment); + + if (ptr == 0) + return 0; + /* If entire block has the desired alignment, just accept it. */ + if (((int) ptr & (alignment - 1)) == 0) + return ptr; + /* Otherwise, get address of byte in the block that has that alignment. */ + aligned = (char *) (((int) ptr + alignment - 1) & -alignment); + + /* Store a suitable indication of how to free the block, + so that free can find the true beginning of it. */ + p = (struct mhead *) aligned - 1; + p -> mh_size = aligned - ptr; + p -> mh_alloc = ISMEMALIGN; + return aligned; +} + +#if !defined (HPUX) +/* This runs into trouble with getpagesize on HPUX, and Multimax machines. + Patching out seems cleaner than the ugly fix needed. */ +#if defined (__STDC__) +void * +#else +char * +#endif +valloc (size) + size_t size; +{ + return memalign (getpagesize (), size); +} +#endif /* !HPUX */ + +#ifndef NO_CALLOC +char * +calloc (n, s) + size_t n, s; +{ + size_t total; + char *result; + + total = n * s; + result = malloc (total); + if (result) + zmemset (result, 0, total); + return result; +} + +void +cfree (p) + char *p; +{ + free (p); +} +#endif /* !NO_CALLOC */ + +#ifdef MSTATS +/* Return statistics describing allocation of blocks of size 2**n. */ + +struct mstats_value + { + int blocksize; + int nfree; + int nused; + }; + +struct mstats_value +malloc_stats (size) + int size; +{ + struct mstats_value v; + register int i; + register struct mhead *p; + + v.nfree = 0; + + if (size < 0 || size >= 30) + { + v.blocksize = 0; + v.nused = 0; + return v; + } + + v.blocksize = 1 << (size + 3); + v.nused = nmalloc[size]; + + for (p = nextf[size]; p; p = CHAIN (p)) + v.nfree++; + + return v; +} +#endif /* MSTATS */ + +/* + * This function returns the total number of bytes that the process + * will be allowed to allocate via the sbrk(2) system call. On + * BSD systems this is the total space allocatable to stack and + * data. On USG systems this is the data space only. + */ + +#if !defined (HAVE_RESOURCE) +extern long ulimit (); + +static void +get_lim_data () +{ + lim_data = ulimit (3, 0); + lim_data -= (long) data_space_start; +} + +#else /* HAVE_RESOURCE */ +static void +get_lim_data () +{ + struct rlimit XXrlimit; + + getrlimit (RLIMIT_DATA, &XXrlimit); +#ifdef RLIM_INFINITY + lim_data = XXrlimit.rlim_cur & RLIM_INFINITY; /* soft limit */ +#else + lim_data = XXrlimit.rlim_cur; /* soft limit */ +#endif +} + +#endif /* HAVE_RESOURCE */ diff --git a/lib/readline/Makefile.in b/lib/readline/Makefile.in index 01ff0cb4..31eddd61 100644 --- a/lib/readline/Makefile.in +++ b/lib/readline/Makefile.in @@ -190,7 +190,7 @@ rltty.o: readline.h keymaps.h chardefs.h tilde.h search.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h search.o: readline.h keymaps.h chardefs.h tilde.h search.o: ansi_stdlib.h history.h -shell.o: ${BUILD_DIR}/config.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 chardefs.h tilde.h signals.o: history.h diff --git a/lib/readline/bind.c b/lib/readline/bind.c index 24c8c48c..300530a0 100644 --- a/lib/readline/bind.c +++ b/lib/readline/bind.c @@ -70,6 +70,8 @@ extern int _rl_convert_meta_chars_to_ascii; extern int _rl_output_meta_chars; extern int _rl_complete_show_all; extern int _rl_complete_mark_directories; +extern int _rl_print_completions_horizontally; +extern int _rl_completion_case_fold; extern int _rl_enable_keypad; #if defined (PAREN_MATCHING) extern int rl_blink_matching_paren; @@ -105,6 +107,7 @@ Keymap rl_binding_keymap; /* Forward declarations */ void rl_set_keymap_from_edit_mode (); +static int _rl_read_init_file (); static int glean_key_from_name (); static int substring_member_of_array (); @@ -198,6 +201,35 @@ rl_unbind_key_in_map (key, map) return (rl_bind_key_in_map (key, (Function *)NULL, map)); } +/* Unbind all keys bound to FUNCTION in MAP. */ +int +rl_unbind_function_in_map (func, map) + Function *func; + Keymap map; +{ + register int i; + + for (i = 0; i < KEYMAP_SIZE; i++) + { + if (map[i].type == ISFUNC && map[i].function == func) + map[i].function = (Function *)NULL; + } +} + +int +rl_unbind_command_in_map (command, map) + char *command; + Keymap map; +{ + Function *func; + register int i; + + 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. This makes new keymaps as necessary. The initial place to do bindings is in MAP. */ @@ -313,7 +345,7 @@ rl_translate_keyseq (seq, array, len) char *seq, *array; int *len; { - register int i, c, l; + register int i, c, l, temp; for (i = l = 0; c = seq[i]; i++) { @@ -324,7 +356,8 @@ rl_translate_keyseq (seq, array, len) if (c == 0) break; - if (((c == 'C' || c == 'M') && seq[i + 1] == '-') || (c == 'e')) + /* 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) @@ -332,31 +365,83 @@ rl_translate_keyseq (seq, array, len) array[l++] = ESC; i += 5; array[l++] = CTRL (_rl_to_upper (seq[i])); - if (!seq[i]) + if (seq[i] == '\0') i--; - continue; } - - switch (c) + else if (c == 'M') { - case 'M': i++; array[l++] = ESC; /* XXX */ - break; - - case 'C': + } + else if (c == 'C') + { i += 2; /* Special hack for C-?... */ array[l++] = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i])); - break; - - case 'e': - array[l++] = ESC; } - 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 + 1); + break; + case 'x': + i++; + for (temp = 3, c = 0; isxdigit (seq[i]) && temp--; i++) + c = (c * 16) + HEXVALUE (seq[i]); + if (temp == 3) + c = 'x'; + i--; /* auto-increment in for loop */ + array[l++] = c % (largest_char + 1); + break; + default: /* backslashes before non-special chars just add the char */ + array[l++] = c; + break; /* the backslash is stripped */ } + continue; } + array[l++] = c; } @@ -541,8 +626,55 @@ static char *last_readline_init_file = (char *)NULL; /* The file we're currently reading key bindings from. */ static char *current_readline_init_file; +static int current_readline_init_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 < file_size) + { + free (buffer); + return ((char *)NULL); + } + + buffer[file_size] = '\0'; + if (sizep) + *sizep = file_size; + return (buffer); +} + /* Re-read the current keybindings file. */ int rl_re_read_init_file (count, ignore) @@ -565,11 +697,6 @@ int rl_read_init_file (filename) char *filename; { - register int i; - char *buffer, *openname, *line, *end; - struct stat finfo; - int file; - /* Default the filename. */ if (filename == 0) { @@ -583,39 +710,37 @@ rl_read_init_file (filename) if (*filename == 0) filename = DEFAULT_INPUTRC; - current_readline_init_file = filename; - openname = tilde_expand (filename); + return (_rl_read_init_file (filename, 0)); +} - if ((stat (openname, &finfo) < 0) || - (file = open (openname, O_RDONLY, 0666)) < 0) - { - free (openname); - return (errno); - } - else - free (openname); +static int +_rl_read_init_file (filename, include_level) + char *filename; + int include_level; +{ + register int i; + char *buffer, *openname, *line, *end; + size_t file_size; - if (filename != last_readline_init_file) - { - if (last_readline_init_file) - free (last_readline_init_file); + current_readline_init_file = filename; + current_readline_init_include_level = include_level; + openname = tilde_expand (filename); + buffer = _rl_read_file (openname, &file_size); + 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); } - /* Read the file into BUFFER. */ - buffer = (char *)xmalloc ((int)finfo.st_size + 1); - i = read (file, buffer, finfo.st_size); - close (file); - - if (i != finfo.st_size) - return (errno); - /* Loop over the lines in the file. Lines that start with `#' are comments; all other lines are commands for readline initialization. */ current_readline_init_lineno = 1; line = buffer; - end = buffer + finfo.st_size; + end = buffer + file_size; while (line < end) { /* Find the end of this line. */ @@ -639,6 +764,7 @@ rl_read_init_file (filename) line += i + 1; current_readline_init_lineno++; } + free (buffer); return (0); } @@ -697,7 +823,7 @@ parser_if (args) if (args[i]) args[i++] = '\0'; - /* Handle "if term=foo" and "if mode=emacs" constructs. If this + /* 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) @@ -749,9 +875,9 @@ parser_else (args) { register int i; - if (!if_stack_depth) + if (if_stack_depth == 0) { - /* Error message? */ + _rl_init_file_error ("$else found without matching $if"); return 0; } @@ -775,12 +901,36 @@ parser_endif (args) if (if_stack_depth) _rl_parsing_conditionalized_out = if_stack[--if_stack_depth]; else - { - /* *** What, no error message? *** */ - } + _rl_init_file_error ("$endif without matching $if"); return 0; } +static int +parser_include (args) + char *args; +{ + char *old_init_file, *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 (args, old_include_level + 1); + + current_readline_init_file = old_init_file; + current_readline_init_lineno = old_line_number; + current_readline_init_include_level = old_include_level; + + return r; +} + /* Associate textual names with actual functions. */ static struct { char *name; @@ -789,6 +939,7 @@ static struct { { "if", parser_if }, { "endif", parser_endif }, { "else", parser_else }, + { "include", parser_include }, { (char *)0x0, (Function *)0x0 } }; @@ -825,7 +976,8 @@ handle_parser_directive (statement) return (0); } - /* *** Should an error message be output? */ + /* display an error message about the unknown parser directive */ + _rl_init_file_error ("unknown parser directive"); return (1); } @@ -940,10 +1092,9 @@ rl_parse_and_bind (string) the quoted string delimiter, like the shell. */ if (*funname == '\'' || *funname == '"') { - int delimiter = string[i++]; - int passc = 0; + int delimiter = string[i++], passc; - for (; c = string[i]; i++) + for (passc = 0; c = string[i]; i++) { if (passc) { @@ -981,11 +1132,11 @@ rl_parse_and_bind (string) rl_set_key (). Otherwise, let the older code deal with it. */ if (*string == '"') { - char *seq = xmalloc (1 + strlen (string)); - register int j, k = 0; - int passc = 0; + char *seq; + register int j, k, passc; - for (j = 1; string[j]; j++) + seq = 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 @@ -1078,6 +1229,7 @@ static struct { #if defined (PAREN_MATCHING) { "blink-matching-paren", &rl_blink_matching_paren }, #endif + { "completion-ignore-case", &_rl_completion_case_fold }, { "convert-meta", &_rl_convert_meta_chars_to_ascii }, { "disable-completion", &rl_inhibit_completion }, { "enable-keypad", &_rl_enable_keypad }, @@ -1088,6 +1240,7 @@ static struct { { "mark-modified-lines", &_rl_mark_modified_lines }, { "meta-flag", &_rl_meta_flag }, { "output-meta", &_rl_output_meta_chars }, + { "print-completions-horizontally", &_rl_print_completions_horizontally }, { "show-all-if-ambiguous", &_rl_complete_show_all }, #if defined (VISIBLE_STATS) { "visible-stats", &rl_visible_stats }, @@ -1186,6 +1339,7 @@ rl_variable_bind (name, value) _rl_bell_preference = AUDIBLE_BELL; } + /* For the time being, unknown variable names are simply ignored. */ return 0; } @@ -1338,7 +1492,7 @@ _rl_get_keyname (key) int key; { char *keyname; - int i, c; + int i, c, v; keyname = (char *)xmalloc (8); @@ -1383,6 +1537,18 @@ _rl_get_keyname (key) 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++] = '\\'; @@ -1692,10 +1858,13 @@ rl_variable_dumper (print_readably) /* bell-style */ switch (_rl_bell_preference) { - case NO_BELL: kname = "none"; break; - case VISIBLE_BELL: kname = "visible"; break; + case NO_BELL: + kname = "none"; break; + case VISIBLE_BELL: + kname = "visible"; break; case AUDIBLE_BELL: - default: kname = "audible"; break; + default: + kname = "audible"; break; } if (print_readably) fprintf (rl_outstream, "set bell-style %s\n", kname); diff --git a/lib/readline/callback.c b/lib/readline/callback.c index 04c5bbd0..34dbc724 100644 --- a/lib/readline/callback.c +++ b/lib/readline/callback.c @@ -55,10 +55,10 @@ extern int rl_visible_prompt_length; things to handle at once, and dispatches them via select(). Call rl_callback_handler_install() with the prompt and a function to call whenever a complete line of input is ready. The user must then - call readline_char() every time some input is available, and - readline_char() will call the user's function with the complete text - read in at each end of line. The terminal is kept prepped and signals - handled all the time, except during calls to the user's function. */ + 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. */ VFunction *rl_linefunc; /* user callback function */ static int in_handler; /* terminal_prepped and signals set? */ diff --git a/lib/readline/chardefs.h b/lib/readline/chardefs.h index 8e6f0efe..3e9e2737 100644 --- a/lib/readline/chardefs.h +++ b/lib/readline/chardefs.h @@ -121,7 +121,20 @@ #ifdef ESC #undef ESC #endif - #define ESC CTRL('[') +#ifndef ISOCTAL +#define ISOCTAL(c) ((c) >= '0' && (c) <= '7') +#endif +#define OCTVALUE(c) ((c) - '0') + +#ifndef isxdigit +# define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) +#endif + +#define HEXVALUE(c) \ + (((c) >= 'a' && (c) <= 'f') \ + ? (c)-'a'+10 \ + : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0') + #endif /* _CHARDEFS_H_ */ diff --git a/lib/readline/complete.c b/lib/readline/complete.c index 552cb6c6..985e8981 100644 --- a/lib/readline/complete.c +++ b/lib/readline/complete.c @@ -75,6 +75,7 @@ extern char *tilde_expand (); extern char *rl_copy_text (); extern void _rl_abort_internal (); extern int _rl_qsort_string_compare (); +extern void _rl_replace_text (); extern Function *rl_last_func; extern int rl_editing_mode; @@ -88,26 +89,32 @@ extern int rl_display_fixed; char *filename_completion_function (); char **completion_matches (); +#if defined (VISIBLE_STATS) +# if !defined (X_OK) +# define X_OK 1 +# endif +static int stat_char (); +#endif + static char *rl_quote_filename (); static char *rl_strpbrk (); static char **remove_duplicate_matches (); -static void insert_text (); static void insert_match (); -static void append_to_match (); +static int append_to_match (); static void insert_all_matches (); static void display_matches (); static int compute_lcd_of_matches (); extern char *xmalloc (), *xrealloc (); -/* If non-zero, then this is the address of a function to call when - completing on a directory name. The function is called with - the address of a string (the current directory name) as an arg. */ -Function *rl_directory_completion_hook = (Function *)NULL; +/* **************************************************************** */ +/* */ +/* Completion matching, from readline's point of view. */ +/* */ +/* **************************************************************** */ -/* Non-zero means readline completion functions perform tilde expansion. */ -int rl_complete_with_tilde_expansion = 0; +/* 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; @@ -115,27 +122,29 @@ int _rl_complete_show_all = 0; /* If non-zero, completed directory names have a slash appended. */ int _rl_complete_mark_directories = 1; -#if defined (VISIBLE_STATS) -# if !defined (X_OK) -# define X_OK 1 -# endif +/* If non-zero, completions are printed horizontally in alphabetical order, + like `ls -x'. */ +int _rl_print_completions_horizontally; -static int stat_char (); +/* Non-zero means that case is not significant in filename completion. */ +int _rl_completion_case_fold; + +/* 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 */ -/* **************************************************************** */ -/* */ -/* Completion matching, from readline's point of view. */ -/* */ -/* **************************************************************** */ +/* If non-zero, then this is the address of a function to call when + completing on a directory name. The function is called with + the address of a string (the current directory name) as an arg. */ +Function *rl_directory_completion_hook = (Function *)NULL; -/* Local variable states what happened during the last completion attempt. */ -static int completion_changed_buffer; +/* 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 filename_completion_function (), the default filename @@ -242,6 +251,17 @@ int rl_completion_append_character = ' '; /* If non-zero, inhibit completion (temporarily). */ int rl_inhibit_completion; +/* Variables local to this file. */ + +/* Local variable states what happened during the last completion attempt. */ +static int completion_changed_buffer; + +/*************************************/ +/* */ +/* Bindable completion functions */ +/* */ +/*************************************/ + /* Complete the word at or before point. You have supplied the function that does the initial simple matching selection algorithm (see completion_matches ()). The default is to do filename completion. */ @@ -274,6 +294,33 @@ rl_insert_completions (ignore, invoking_key) return (rl_complete_internal ('*')); } +/************************************/ +/* */ +/* Completion utility functions */ +/* */ +/************************************/ + +/* Find the first occurrence in STRING1 of any character from STRING2. + Return a pointer to the character in STRING1. */ +static char * +rl_strpbrk (string1, string2) + char *string1, *string2; +{ + register char *scan; + + for (; *string1; string1++) + { + for (scan = string2; *scan; scan++) + { + if (*string1 == *scan) + { + return (string1); + } + } + } + return ((char *)NULL); +} + /* The user must press "y" or "n". Non-zero return means "y" pressed. */ static int get_y_or_n () @@ -293,6 +340,63 @@ get_y_or_n () } } +#if defined (VISIBLE_STATS) +/* Return the character which best describes FILENAME. + `@' for symbolic links + `/' for directories + `*' for executables + `=' for sockets + `|' for FIFOs + `%' for character special devices + `#' for block special devices */ +static int +stat_char (filename) + char *filename; +{ + struct stat finfo; + int character, r; + +#if defined (HAVE_LSTAT) && defined (S_ISLNK) + r = lstat (filename, &finfo); +#else + r = stat (filename, &finfo); +#endif + + if (r == -1) + return (0); + + character = 0; + if (S_ISDIR (finfo.st_mode)) + character = '/'; +#if defined (S_ISCHR) + else if (S_ISCHR (finfo.st_mode)) + character = '%'; +#endif /* S_ISCHR */ +#if defined (S_ISBLK) + else if (S_ISBLK (finfo.st_mode)) + character = '#'; +#endif /* S_ISBLK */ +#if defined (S_ISLNK) + else if (S_ISLNK (finfo.st_mode)) + character = '@'; +#endif /* S_ISLNK */ +#if defined (S_ISSOCK) + else if (S_ISSOCK (finfo.st_mode)) + character = '='; +#endif /* S_ISSOCK */ +#if defined (S_ISFIFO) + else if (S_ISFIFO (finfo.st_mode)) + character = '|'; +#endif + else if (S_ISREG (finfo.st_mode)) + { + if (access (filename, X_OK) == 0) + character = '*'; + } + return (character); +} +#endif /* VISIBLE_STATS */ + /* Return the portion of PATHNAME that should be output when listing possible completions. If we are hacking filename completion, we are only interested in the basename, the portion following the @@ -309,26 +413,34 @@ printable_part (pathname) /* Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we are using it, check for and output a single character for `special' - filenames. Return 1 if we printed an extension character, 0 if not. */ + filenames. Return the number of characters we output. */ #define PUTX(c) \ + do { \ if (CTRL_CHAR (c)) \ { \ putc ('^', rl_outstream); \ putc (UNCTRL (c), rl_outstream); \ + printed_len += 2; \ } \ else if (c == RUBOUT) \ { \ putc ('^', rl_outstream); \ putc ('?', rl_outstream); \ + printed_len += 2; \ } \ else \ - putc (c, rl_outstream) + { \ + putc (c, rl_outstream); \ + printed_len++; \ + } \ + } while (0) static int print_filename (to_print, full_pathname) char *to_print, *full_pathname; { + int printed_len = 0; #if !defined (VISIBLE_STATS) char *s; @@ -336,7 +448,6 @@ print_filename (to_print, full_pathname) { PUTX (*s); } - return 0; #else char *s, c, *new_full_pathname; int extension_char, slen, tlen; @@ -381,12 +492,13 @@ print_filename (to_print, full_pathname) free (s); if (extension_char) - putc (extension_char, rl_outstream); - return (extension_char != 0); + { + putc (extension_char, rl_outstream); + printed_len++; + } } - else - return 0; #endif /* VISIBLE_STATS */ + return printed_len; } static char * @@ -636,6 +748,125 @@ remove_duplicate_matches (matches) 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; + char *text; +{ + register int i, c1, c2, si; + int low; /* Count of max-matched characters. */ + + /* If only one match, just use that. Otherwise, compare each + member of the list with the next, finding out where they + stop matching. */ + if (matches == 1) + { + match_list[0] = match_list[1]; + match_list[1] = (char *)NULL; + return 1; + } + + for (i = 1, low = 100000; i < matches; i++) + { + if (_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 (c1 != c2) + break; + } + else + { + for (si = 0; + (c1 = match_list[i][si]) && + (c2 = match_list[i + 1][si]); + si++) + if (c1 != c2) + break; + } + + if (low > si) + low = si; + } + + /* If there were multiple matches, but none matched up to even the + first character, and the user typed something, use that as the + value of matches[0]. */ + if (low == 0 && text && *text) + { + match_list[0] = xmalloc (strlen (text) + 1); + strcpy (match_list[0], text); + } + else + { + match_list[0] = xmalloc (low + 1); + strncpy (match_list[0], match_list[1], low); + match_list[0][low] = '\0'; + } + + return matches; +} + +static int +postprocess_matches (text, matchesp, matching_filenames) + char *text; + char ***matchesp; + int matching_filenames; +{ + char *t, **matches, **temp_matches; + int nmatch, i; + + matches = *matchesp; + + /* 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); + ding (); + *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, text); + FREE (t); + } + } + } + + *matchesp = matches; + return (1); +} + static void display_matches (matches) char **matches; @@ -718,25 +949,47 @@ display_matches (matches) if (rl_ignore_completion_duplicates == 0) qsort (matches + 1, len, sizeof (char *), _rl_qsort_string_compare); - /* Print the sorted items, up-and-down alphabetically, like ls. */ crlf (); - for (i = 1; i <= count; i++) + if (_rl_print_completions_horizontally == 0) { - for (j = 0, l = i; j < limit; j++) + /* Print the sorted items, up-and-down alphabetically, like ls. */ + for (i = 1; i <= count; i++) { - if (l > len || matches[l] == 0) - break; - else + for (j = 0, l = i; j < limit; j++) { - temp = printable_part (matches[l]); - printed_len = strlen (temp) + print_filename (temp, matches[l]); + if (l > len || matches[l] == 0) + break; + else + { + temp = printable_part (matches[l]); + printed_len = print_filename (temp, matches[l]); - if (j + 1 < limit) + if (j + 1 < limit) + for (k = 0; k < max - printed_len; k++) + putc (' ', rl_outstream); + } + l += count; + } + crlf (); + } + } + else + { + /* Print the sorted items, across alphabetically, like ls -x. */ + for (i = 1; matches[i]; i++) + { + temp = printable_part (matches[i]); + printed_len = print_filename (temp, matches[i]); + /* Have we reached the end of this line? */ + if (matches[i+1]) + { + if (i && (limit > 1) && (i % limit) == 0) + crlf (); + else for (k = 0; k < max - printed_len; k++) putc (' ', rl_outstream); } - l += count; } crlf (); } @@ -749,18 +1002,6 @@ display_matches (matches) #endif } -static void -insert_text (text, start, end) - char *text; - int start, end; -{ - rl_begin_undo_group (); - rl_delete_text (start, end + 1); - rl_point = start; - rl_insert_text (text); - rl_end_undo_group (); -} - static char * make_quoted_replacement (match, mtype, qc) char *match; @@ -833,7 +1074,7 @@ insert_match (match, start, mtype, qc) else if (qc && (*qc != oqc) && start && rl_line_buffer[start - 1] == oqc && replacement[0] != oqc) start--; - insert_text (replacement, start, rl_point - 1); + _rl_replace_text (replacement, start, rl_point - 1); if (replacement != match) free (replacement); } @@ -842,8 +1083,9 @@ insert_match (match, start, mtype, qc) /* Append any necessary closing quote and a separator character to the just-inserted match. If the user has specified that directories should be marked by a trailing `/', append one of those instead. The - default trailing character */ -static void + default trailing character is a space. Returns the number of characters + appended. */ +static int append_to_match (text, delimiter, quote_char) char *text; int delimiter, quote_char; @@ -883,6 +1125,8 @@ append_to_match (text, delimiter, quote_char) if (rl_point == rl_end) rl_insert_text (temp_string); } + + return (temp_string_index); } static void @@ -935,27 +1179,24 @@ int rl_complete_internal (what_to_do) int what_to_do; { - char **matches, **temp_matches; + char **matches; Function *our_func; - int start, end, delimiter, found_quote, nmatch, i; - char *text, *saved_line_buffer, *t; + int start, end, delimiter, found_quote, i; + char *text, *saved_line_buffer; char quote_char; - saved_line_buffer = rl_line_buffer ? savestring (rl_line_buffer) : (char *)NULL; - - our_func = rl_completion_entry_function - ? rl_completion_entry_function - : (Function *)filename_completion_function; - /* Only the completion entry function can change these. */ rl_filename_completion_desired = 0; rl_filename_quoting_desired = 1; - rl_completion_type = what_to_do; + saved_line_buffer = rl_line_buffer ? savestring (rl_line_buffer) : (char *)NULL; + our_func = rl_completion_entry_function + ? rl_completion_entry_function + : (Function *)filename_completion_function; + /* We now look backwards for the start of a filename/variable word. */ end = rl_point; - found_quote = delimiter = 0; quote_char = '\0'; @@ -975,50 +1216,19 @@ rl_complete_internal (what_to_do) ding (); FREE (saved_line_buffer); free (text); - 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; + return (0); } - /* If we are matching filenames, then here is our chance to - do clever processing by re-examining the list. Call the - ignore function with the array as a parameter. It can - munge the array, deleting matches as it desires. */ - if (rl_ignore_some_completions_function && - our_func == (Function *)filename_completion_function) + /* If we are matching filenames, our_func will have been set to + filename_completion_function */ + i = our_func == (Function *)filename_completion_function; + if (postprocess_matches (text, &matches, i) == 0) { - for (nmatch = 1; matches[nmatch]; nmatch++) - ; - (void)(*rl_ignore_some_completions_function) (matches); - if (matches == 0 || matches[0] == 0) - { - FREE (matches); - ding (); - FREE (saved_line_buffer); - FREE (text); - 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, text); - FREE (t); - } - } + FREE (saved_line_buffer); + free (text); + return (0); } + free (text); switch (what_to_do) @@ -1081,62 +1291,67 @@ rl_complete_internal (what_to_do) return 0; } -#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; +/***************************************************************/ +/* */ +/* 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 ** +completion_matches (text, entry_function) + char *text; + CPFunction *entry_function; { - struct stat finfo; - int character, r; + /* Number of slots in match_list. */ + int match_list_size; -#if defined (HAVE_LSTAT) && defined (S_ISLNK) - r = lstat (filename, &finfo); -#else - r = stat (filename, &finfo); -#endif + /* The list of matches. */ + char **match_list; - if (r == -1) - return (0); + /* Number of matches actually found. */ + int matches; - 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)) + /* 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 (access (filename, X_OK) == 0) - character = '*'; + 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; } - return (character); + + /* 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); } -#endif /* VISIBLE_STATS */ /* A completion function for usernames. TEXT contains a partial username preceded by a random @@ -1194,135 +1409,6 @@ username_completion_function (text, state) #endif /* !__GO32__ */ } -/* **************************************************************** */ -/* */ -/* Completion */ -/* */ -/* **************************************************************** */ - -/* Non-zero means that case is not significant in completion. */ -int completion_case_fold = 0; - -/* Find the common prefix of the list of matches, and put it into - matches[0]. */ -static int -compute_lcd_of_matches (match_list, matches, text) - char **match_list; - int matches; - char *text; -{ - register int i, c1, c2, si; - int low; /* Count of max-matched characters. */ - - /* If only one match, just use that. Otherwise, compare each - member of the list with the next, finding out where they - stop matching. */ - if (matches == 1) - { - match_list[0] = match_list[1]; - match_list[1] = (char *)NULL; - return 1; - } - - for (i = 1, low = 100000; i < matches; i++) - { - if (completion_case_fold) - { - for (si = 0; - (c1 = _rl_to_lower(match_list[i][si])) && - (c2 = _rl_to_lower(match_list[i + 1][si])); - si++) - if (c1 != c2) - break; - } - else - { - for (si = 0; - (c1 = match_list[i][si]) && - (c2 = match_list[i + 1][si]); - si++) - if (c1 != c2) - break; - } - - if (low > si) - low = si; - } - - /* If there were multiple matches, but none matched up to even the - first character, and the user typed something, use that as the - value of matches[0]. */ - if (low == 0 && text && *text) - { - match_list[0] = xmalloc (strlen (text) + 1); - strcpy (match_list[0], text); - } - else - { - match_list[0] = xmalloc (low + 1); - strncpy (match_list[0], match_list[1], low); - match_list[0][low] = '\0'; - } - - return matches; -} - -/* Return an array of (char *) which is a list of completions for TEXT. - If there are no completions, return a NULL pointer. - The first entry in the returned array is the substitution for TEXT. - The remaining entries are the possible completions. - The array is terminated with a NULL pointer. - - ENTRY_FUNCTION is a function of two args, and returns a (char *). - The first argument is TEXT. - The second is a state argument; it should be zero on the first call, and - non-zero on subsequent calls. It returns a NULL pointer to the caller - when there are no more matches. - */ -char ** -completion_matches (text, entry_function) - char *text; - CPFunction *entry_function; -{ - /* Number of slots in match_list. */ - int match_list_size; - - /* The list of matches. */ - char **match_list; - - /* 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); -} - /* 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 @@ -1421,10 +1507,20 @@ filename_completion_function (text, state) { /* Otherwise, if these match up to the length of filename, then it is a match. */ - if ((entry->d_name[0] == filename[0]) && - (((int)D_NAMLEN (entry)) >= filename_len) && - (strncmp (filename, entry->d_name, filename_len) == 0)) - break; + if (_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; + } } } @@ -1487,74 +1583,120 @@ filename_completion_function (text, state) } } -/* A function for simple tilde expansion. */ +/* 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_tilde_expand (ignore, key) - int ignore, key; +rl_menu_complete (count, ignore) + int count, ignore; { - register int start, end; - char *homedir, *temp; - int len; + Function *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) + { + for (match_list_index = 0; matches[match_list_index]; match_list_index++) + free (matches[match_list_index]); + free (matches); + } - end = rl_point; - start = end - 1; + match_list_index = match_list_size = 0; + matches = (char **)NULL; - if (rl_point == rl_end && rl_line_buffer[rl_point] == '~') - { - homedir = tilde_expand ("~"); - insert_text (homedir, start, end); - return (0); - } - else if (rl_line_buffer[start] != '~') - { - for (; !whitespace (rl_line_buffer[start]) && start >= 0; start--) + /* Only the completion entry function can change these. */ + rl_filename_completion_desired = 0; + rl_filename_quoting_desired = 1; + rl_completion_type = '%'; + + our_func = rl_completion_entry_function + ? rl_completion_entry_function + : (Function *)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 = 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, our_func will have been set to + filename_completion_function */ + matching_filenames = our_func == (Function *)filename_completion_function; + if (matches == 0 || postprocess_matches (orig_text, &matches, matching_filenames) == 0) + { + 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++) ; - start++; + /* matches[0] is lcd if match_list_size > 1, but the circular buffer + code below should take care of it. */ } - end = start; - do - end++; - while (whitespace (rl_line_buffer[end]) == 0 && end < rl_end); - - if (whitespace (rl_line_buffer[end]) || end >= rl_end) - end--; + /* 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 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] == '~') + if (matches == 0 || match_list_size == 0) { - len = end - start + 1; - temp = xmalloc (len + 1); - strncpy (temp, rl_line_buffer + start, len); - temp[len] = '\0'; - homedir = tilde_expand (temp); - free (temp); - - insert_text (homedir, start, end); + ding (); + FREE (matches); + matches = (char **)0; + completion_changed_buffer = 0; + return (0); } - return (0); -} - -/* Find the first occurrence in STRING1 of any character from STRING2. - Return a pointer to the character in STRING1. */ -static char * -rl_strpbrk (string1, string2) - char *string1, *string2; -{ - register char *scan; + match_list_index = (match_list_index + count) % match_list_size; + if (match_list_index < 0) + match_list_index += match_list_size; - for (; *string1; string1++) + if (match_list_index == 0) { - for (scan = string2; *scan; scan++) - { - if (*string1 == *scan) - { - return (string1); - } - } + ding (); + insert_match (orig_text, orig_start, MULT_MATCH, "e_char); } - return ((char *)NULL); + else + { + insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char); + append_to_match (matches[match_list_index], delimiter, quote_char); + } + + completion_changed_buffer = 1; + return (0); } diff --git a/lib/readline/display.c b/lib/readline/display.c index 609d827f..edb5b20d 100644 --- a/lib/readline/display.c +++ b/lib/readline/display.c @@ -72,7 +72,11 @@ extern int _rl_prefer_visible_bell; /* Variables and functions imported from terminal.c */ extern void _rl_output_some_chars (); +#ifdef _MINIX +extern void _rl_output_character_function (); +#else extern int _rl_output_character_function (); +#endif extern int _rl_backspace (); extern char *term_clreol, *term_clrpag; diff --git a/lib/readline/doc/hist.texinfo b/lib/readline/doc/hist.texinfo index aa045535..be8742f5 100644 --- a/lib/readline/doc/hist.texinfo +++ b/lib/readline/doc/hist.texinfo @@ -7,20 +7,25 @@ @setchapternewpage odd @ignore -last change: Thu Mar 21 16:07:29 EST 1996 +last change: Thu Apr 2 14:38:22 EST 1998 @end ignore -@set EDITION 2.1 -@set VERSION 2.1 -@set UPDATED 21 March 1996 -@set UPDATE-MONTH March 1996 +@set EDITION 2.2 +@set VERSION 2.2 +@set UPDATED 2 April 1998 +@set UPDATE-MONTH April 1998 + +@dircategory Libraries +@direntry +* History: (history). The GNU history library API +@end direntry @ifinfo This document describes the GNU History library, a programming tool that provides a consistent user interface for recalling lines of previously typed input. -Copyright (C) 1988, 1991, 1993, 1995, 1996 Free Software Foundation, Inc. +Copyright (C) 1988, 1991, 1993, 1995, 1996, 1998 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice diff --git a/lib/readline/doc/hsuser.texinfo b/lib/readline/doc/hsuser.texinfo index 6e956494..76cb63b1 100644 --- a/lib/readline/doc/hsuser.texinfo +++ b/lib/readline/doc/hsuser.texinfo @@ -29,7 +29,7 @@ into another language, under the above conditions for modified versions. @ifset BashFeatures This chapter describes how to use the GNU History Library interactively, from a user's standpoint. It should be considered a user's guide. For -information on using the GNU History Library in your own programs, +information on using the GNU History Library in other programs, see the GNU Readline Library Manual. @end ifset @ifclear BashFeatures @@ -43,6 +43,8 @@ information on using the GNU History Library in your own programs, @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 @@ -84,11 +86,10 @@ not saved. After saving the history, the history file is truncated to contain no more than @code{$HISTFILESIZE} lines. If @code{HISTFILESIZE} is not set, no truncation is performed. -The builtin command @code{fc} (@pxref{Korn Shell Builtins}) -may be used to list or edit and re-execute a portion of -the history list. The @code{history} builtin (@pxref{C Shell Builtins}) -can be used to display or modify the history list and -manipulate the history file. +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 can be used to display or modify the history +list and manipulate the history file. When using the command-line editing, search commands are available in each editing mode that provide access to the history list. @@ -104,11 +105,103 @@ semicolons where necessary to preserve syntactic correctness. The @code{lithist} shell option causes the shell to save the command with embedded newlines instead of semicolons. -@xref{Bash Builtins} for a description of @code{shopt}. +@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 that allow you to manipulate the +history list and history file. + +@table @code + +@item fc +@btindex fc +@example +@code{fc [-e @var{ename}] [-nlr] [@var{first}] [@var{last}]} +@code{fc -s [@var{pat}=@var{rep}] [@var{command}]} +@end example + +Fix Command. In the first form, a range of commands from @var{first} to +@var{last} is selected from the history list. Both @var{first} and +@var{last} may be specified as a string (to locate the most recent +command beginning with that string) or as a number (an index into the +history list, where a negative number is used as an offset from the +current command number). If @var{last} is not specified it is set to +@var{first}. If @var{first} is not specified it is set to the previous +command for editing and @minus{}16 for listing. If the @samp{-l} flag is +given, the commands are listed on standard output. The @samp{-n} flag +suppresses the command numbers when listing. The @samp{-r} flag +reverses the order of the listing. Otherwise, the editor given by +@var{ename} is invoked on a file containing those commands. If +@var{ename} is not given, the value of the following variable expansion +is used: @code{$@{FCEDIT:-$@{EDITOR:-vi@}@}}. This says to use the +value of the @code{FCEDIT} variable if set, or the value of the +@code{EDITOR} variable if that is set, or @code{vi} if neither is set. +When editing is complete, the edited commands are echoed and executed. + +In the second form, @var{command} is re-executed after each instance +of @var{pat} in the selected command is replaced by @var{rep}. + +A useful alias to use with the @code{fc} command is @code{r='fc -s'}, so +that typing @samp{r cc} runs the last command beginning with @code{cc} +and typing @samp{r} re-executes the last command (@pxref{Aliases}). + +@item history +@btindex history +@example +history [-c] [@var{n}] +history [-anrw] [@var{filename}] +history -ps @var{arg} +@end example + +Display the history list with line numbers. Lines prefixed with +with a @samp{*} have been modified. An argument of @var{n} says +to list only the last @var{n} lines. Options, if supplied, have +the following meanings: + +@table @code +@item -w +Write out the current history to the history file. + +@item -r +Read the current history file and append its contents to +the history list. + +@item -a +Append the new +history lines (history lines entered since the beginning of the +current Bash session) to the history file. + +@item -n +Append the history lines not already read from the history file +to the current history list. These are lines appended to the history +file since the beginning of the current Bash session. + +@item -c +Clear the history list. This may be combined +with the other options to replace the history list completely. + +@item -s +The @var{arg}s are added to the end of +the history list as a single entry. + +@item -p +Perform history substitution on the @var{arg}s and display the result +on the standard output, without storing the results in the history list. +@end table + +When the @samp{-w}, @samp{-r}, @samp{-a}, or @samp{-n} option is +used, if @var{filename} +is given, then it is used as the history file. If not, then +the value of the @code{HISTFILE} variable is used. + +@end table @end ifset @node History Interaction -@section Interactive History Expansion +@section History Expansion @cindex history expansion The History library provides a history expansion feature that is similar @@ -121,14 +214,14 @@ arguments to a previous command into the current input line, or fix errors in previous commands quickly. History expansion takes place in two parts. The first is to determine -which line from the previous history should be used during substitution. +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 previous history is called 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 English (or Unix) words -surrounded by quotes are considered as one word. +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 @@ -153,6 +246,7 @@ may be used to see what a history expansion will do before using it. The @samp{-s} option to the @code{history} builtin may be used to add commands to the end of the history list without actually executing them, so that they are available for subsequent recall. +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. @@ -176,7 +270,7 @@ history list. @item @code{!} Start a history substitution, except when followed by a space, tab, -the end of the line, @key{=} or @key{(}. +the end of the line, @samp{=} or @samp{(}. @item @code{!@var{n}} Refer to command line @var{n}. @@ -210,7 +304,7 @@ The entire command line typed so far. Word designators are used to select desired words from the event. A @samp{:} separates the event specification from the word designator. It -can be omitted if the word designator begins with a @samp{^}, @samp{$}, +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. diff --git a/lib/readline/doc/rlman.texinfo b/lib/readline/doc/rlman.texinfo index 655f3db9..dd6478af 100644 --- a/lib/readline/doc/rlman.texinfo +++ b/lib/readline/doc/rlman.texinfo @@ -7,20 +7,25 @@ @setchapternewpage odd @ignore -last change: Thu Mar 21 16:06:39 EST 1996 +last change: Thu Apr 2 14:39:03 EST 1998 @end ignore -@set EDITION 2.1 -@set VERSION 2.1 -@set UPDATED 21 March 1996 -@set UPDATE-MONTH March 1996 +@set EDITION 2.2 +@set VERSION 2.2 +@set UPDATED 2 April 1998 +@set UPDATE-MONTH April 1998 + +@dircategory Libraries +@direntry +* Readline: (readline). The GNU readline library API +@end direntry @ifinfo This document describes the GNU Readline Library, a utility which aids in the consistency of user interface across discrete programs that need to provide a command line interface. -Copyright (C) 1988, 1991 Free Software Foundation, Inc. +Copyright (C) 1988, 1991, 1993, 1996, 1998 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice diff --git a/lib/readline/doc/rltech.texinfo b/lib/readline/doc/rltech.texinfo index ea0d317d..bce50871 100644 --- a/lib/readline/doc/rltech.texinfo +++ b/lib/readline/doc/rltech.texinfo @@ -454,6 +454,14 @@ 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 (Function *function, Keymap map) +Unbind all keys that execute @var{function} in @var{map}. +@end deftypefun + +@deftypefun int rl_unbind_command_in_map (char *command, Keymap map) +Unbind all keys that are bound to @var{command} in @var{map}. +@end deftypefun + @deftypefun int rl_generic_bind (int type, char *keyseq, char *data, Keymap map) Bind the key sequence represented by the string @var{keyseq} to the arbitrary pointer @var{data}. @var{type} says what kind of data is pointed to by @@ -1034,7 +1042,7 @@ unless they also appear within this list. @deftypevar {char *} rl_filename_quote_characters A list of characters that cause a filename to be quoted by the completer -when they appear in a completed filename. The default is empty. +when they appear in a completed filename. The default is the null string. @end deftypevar @deftypevar {char *} rl_special_prefixes diff --git a/lib/readline/doc/rluser.texinfo b/lib/readline/doc/rluser.texinfo index f7d6fd87..b2fd0603 100644 --- a/lib/readline/doc/rluser.texinfo +++ b/lib/readline/doc/rluser.texinfo @@ -135,7 +135,7 @@ Delete the character underneath the cursor. @item @w{Printing characters} Insert the character into the line at the cursor. @item @key{C-_} -Undo the last thing that you did. You can undo all the way back to an +Undo the last editing command. You can undo all the way back to an empty line. @end table @@ -155,7 +155,7 @@ Move to the start of the line. @item C-e Move to the end of the line. @item M-f -Move forward a word. +Move forward a word, where a word is composed of letters and digits. @item M-b Move backward a word. @item C-l @@ -207,7 +207,7 @@ Kill from the cursor to the previous whitespace. This is different than @end table -And, here is how to @dfn{yank} the text back into the line. Yanking +Here is how to @dfn{yank} the text back into the line. Yanking means to copy the most-recently-killed text from the kill buffer. @table @key @@ -227,10 +227,10 @@ 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 @w{@kbd{M-- C-k}}. +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' you type is a minus +digits before the command. If the first `digit' typed is a minus sign (@key{-}), then the sign of the argument will be negative. Once you have typed one meta digit to get the argument started, you can type the remainder of the digits, and then the command. For example, to give @@ -248,38 +248,38 @@ There are two search modes: @var{incremental} and @var{non-incremental}. Incremental searches begin before the user has finished typing the search string. -As each character of the search string is typed, readline displays +As each character of the search string is typed, Readline displays the next entry from the history matching the string typed so far. An incremental search requires only as many characters as needed to find the desired history entry. -The Escape character is used to terminate an incremental search. -Control-J will also terminate the search. -Control-G will abort an incremental search and restore the original -line. +The @key{ESC} character is used to terminate an incremental search. +@key{C-j} will also terminate the search. +@key{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 Control-S or -Control-R as appropriate. +To find other matching entries in the history list, type @key{C-s} or +@key{C-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 +Any other key sequence bound to a Readline command will terminate the search and execute that command. -For instance, a @code{newline} will terminate the search and accept +For instance, a @key{RET} will terminate the search and accept the line, thereby executing the command from the history list. Non-incremental searches read the entire search string before starting to search for matching history lines. The search string may be -typed by the user or part of the contents of the current line. +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 @code{emacs}-like -keybindings installed by default, -it is possible that you would like to use a different set -of keybindings. You can customize programs that use Readline by putting -commands in an @dfn{inputrc} file in your home directory. The name of this +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 in his home directory. +The name of this @ifset BashFeatures file is taken from the value of the shell variable @code{INPUTRC}. If @end ifset @@ -314,16 +314,18 @@ denote variable settings and key bindings. @table @asis @item Variable Settings -You can change the state of a few variables in Readline by -using the @code{set} command within the init file. Here is how you -would specify that you wish to use @code{vi} line editing commands: +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. Here 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 -Right now, there are only a few variables which can be set; -so few, in fact, that we just list them here: +A great deal of run-time behavior is changeable with the following +variables. @table @code @@ -341,6 +343,11 @@ The string to insert at the beginning of the line when the @code{insert-comment} command is executed. The default value is @code{"#"}. +@item completion-ignore-case +If set to @samp{on}, Readline performs filename matching and completion +in a case-insensitive fashion. +The default value is @samp{off}. + @item completion-query-items @vindex completion-query-items The number of possible completions that determines when the user is @@ -353,26 +360,26 @@ them; otherwise, they are simply listed. The default limit is @item convert-meta @vindex convert-meta If set to @samp{on}, Readline will convert characters with the -eigth bit set to an ASCII key sequence by stripping the eigth +eighth bit set to an ASCII key sequence by stripping the eighth bit and prepending an @key{ESC} character, converting them to a meta-prefixed key sequence. The default value is @samp{on}. @item disable-completion @vindex disable-completion -If set to @samp{On}, readline will inhibit word completion. +If set to @samp{On}, Readline will inhibit word completion. Completion characters will be inserted into the line as if they had been mapped to @code{self-insert}. The default is @samp{off}. @item editing-mode @vindex editing-mode -The @code{editing-mode} variable controls which editing mode you are -using. By default, Readline starts up in Emacs editing mode, where -the keystrokes are most similar to Emacs. This variable can be +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 +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}. @@ -384,7 +391,7 @@ attempts word completion. The default is @samp{off}. @item horizontal-scroll-mode @vindex horizontal-scroll-mode This variable can be set to either @samp{on} or @samp{off}. Setting it -to @samp{on} means that the text of the lines that you edit will scroll +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}. @@ -411,8 +418,8 @@ appended. The default is @samp{on}. @item mark-modified-lines @vindex mark-modified-lines -This variable, when set to @samp{on}, says to display an asterisk -(@samp{*}) at the start of history lines which have been modified. +This variable, 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 input-meta @@ -430,6 +437,11 @@ 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 print-completions-horizontally +If set to @samp{on}, Readline will display completions with matches +sorted horizontally in alphabetical order, rather than down the screen. +The default is @samp{off}. + @item show-all-if-ambiguous @vindex show-all-if-ambiguous This alters the default behavior of the completion functions. If @@ -449,9 +461,9 @@ completions. The default is @samp{off}. @item Key Bindings The syntax for controlling key bindings in the init file is simple. First you have to know the name of the command that you -want to change. The following pages contain tables of the command name, -the default keybinding, and a short description of what the command -does. +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 the name of the key you wish to bind the command to, a colon, and then the name of the @@ -468,8 +480,8 @@ Meta-Rubout: backward-kill-word Control-o: "> output" @end example -In the above example, @samp{C-u} is bound to the function -@code{universal-argument}, and @samp{C-o} is bound to run the macro +In the above example, @key{C-u} is bound to the function +@code{universal-argument}, and @key{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). @@ -486,12 +498,16 @@ special character names are not recognized. "\e[11~": "Function Key 1" @end example -In the above example, @samp{C-u} is bound to the function +In the above example, @key{C-u} is bound to the function @code{universal-argument} (just as it was in the first example), -@samp{C-x C-r} is bound to the function @code{re-read-init-file}, and -@samp{ESC [ 1 1 ~} is bound to insert the text @samp{Function Key 1}. -The following escape sequences are available when specifying key -sequences: +@samp{@key{C-x} @key{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 GNU Emacs style escape sequences are available when +specifying key sequences: @table @code @item @kbd{\C-} @@ -508,11 +524,40 @@ backslash @key{'} @end table -When entering the text of a macro, single or double quotes should -be used to indicate a macro definition. Unquoted text -is assumed to be a function name. Backslash -will quote any character in the macro text, including @samp{"} -and @samp{'}. +In addition to the 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 character whose ASCII code is the octal value @var{nnn} +(one to three digits) +@item \x@var{nnn} +the character whose ASCII code is the hexadecimal value @var{nnn} +(one to three 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{C-x \} insert a single @samp{\} into the line: @example @@ -520,7 +565,6 @@ insert a single @samp{\} into the line: @end example @end table -@end table @node Conditional Init Constructs @subsection Conditional Init Constructs @@ -528,7 +572,7 @@ insert a single @samp{\} into the line: Readline implements a facility similar in spirit to the conditional compilation features of the C preprocessor which allows key bindings and variable settings to be performed as the result -of tests. There are three parser directives used. +of tests. There are four parser directives used. @table @code @item $if @@ -550,8 +594,8 @@ Readline is starting out in @code{emacs} mode. The @code{term=} form may be used to include terminal-specific key bindings, perhaps to bind the key sequences output by the terminal's function keys. The word on the right side of the -@samp{=} is tested against the full name of the terminal and the -portion of the terminal name before the first @samp{-}. This +@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. @@ -571,12 +615,19 @@ $endif @end table @item $endif -This command, as you saw in the previous example, terminates an +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. +@example +$include /etc/inputrc +@end example @end table @node Sample Init File @@ -594,6 +645,11 @@ binding, variable assignment, and conditional syntax. # 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 @@ -738,8 +794,9 @@ Refresh the current line. By default, this is unbound. @ifset BashFeatures Accept the line regardless of where the cursor is. If this line is non-empty, add it to the history list according to the setting of -the @code{HISTCONTROL} variable. If this line was a history -line, then restore the history line to its original state. +the @code{HISTCONTROL} and @code{HISTIGNORE} variables. +If this line was a history line, then restore the history line to its +original state. @end ifset @ifclear BashFeatures Accept the line regardless of where the cursor is. If this line is @@ -757,7 +814,8 @@ Move `down' through the history list. Move to the first line in the history. @item end-of-history (M->) -Move to the end of the input history, i.e., the line you are entering. +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 @@ -780,7 +838,7 @@ for a string supplied by the user. @item history-search-forward () Search forward through the history for the string of characters between the start of the current line and the current cursor -position (the `point'). This is a non-incremental search. By +position (the @var{point}). This is a non-incremental search. By default, this command is unbound. @item history-search-backward () @@ -799,6 +857,8 @@ inserts the @var{n}th word from the end of the previous command. Insert last argument to the previous command (the last word of the previous history entry). With an argument, behave exactly like @code{yank-nth-arg}. +Successive calls to @code{yank-last-arg} move back through the history +list, inserting the last argument of each line in turn. @end ftable @@ -809,18 +869,21 @@ argument, behave exactly like @code{yank-nth-arg}. @item delete-char (C-d) Delete the character under the cursor. If the cursor is at the beginning of the line, there are no characters in the line, and -the last character typed was not @kbd{C-d}, then return @code{EOF}. +the last character typed was not bound to @code{delete-char}, then +return @code{EOF}. @item backward-delete-char (Rubout) -Delete the character behind the cursor. A numeric arg says to kill -the characters instead of deleting them. +Delete the character behind the cursor. A numeric argument means +to kill the characters instead of deleting them. @item quoted-insert (C-q, C-v) -Add the next character that you type to the line verbatim. This is +Add the next character typed to the line verbatim. This is how to insert key sequences like @key{C-q}, for example. +@ifclear BashFeatures @item tab-insert (M-TAB) Insert a tab character. +@end ifclear @item self-insert (a, b, A, 1, !, ...) Insert yourself. @@ -831,7 +894,7 @@ the character at the cursor, moving the cursor forward as well. If the insertion point is at the end of the line, then this transposes the last two characters of the line. -Negative argumentss don't work. +Negative arguments don't work. @item transpose-words (M-t) Drag the word behind the cursor past the word in front of the cursor @@ -839,15 +902,15 @@ moving the cursor over that word as well. @item upcase-word (M-u) Uppercase the current (or following) word. With a negative argument, -do the previous word, but do not move the cursor. +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, -do the previous word, but do not move the cursor. +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, -do the previous word, but do not move the cursor. +capitalize the previous word, but do not move the cursor. @end ftable @@ -864,7 +927,7 @@ Kill backward to the beginning of the line. @item unix-line-discard (C-u) Kill backward from the cursor to the beginning of the current line. -Save the killed text on the kill-ring. +The killed text is saved on the kill-ring. @item kill-whole-line () Kill all characters on the current line, no matter where the @@ -888,19 +951,21 @@ Delete all spaces and tabs around point. By default, this is unbound. @item kill-region () Kill the text between the point and the @emph{mark} (saved -cursor position. This text is referred to as the @var{region}. +cursor position). This text is referred to as the @var{region}. By default, this command is unbound. @item copy-region-as-kill () -Copy the text in the region to the kill buffer, so you can yank it +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) @@ -943,8 +1008,8 @@ By default, this is not bound to a key. Attempt to do completion on the text before the cursor. This is application-specific. Generally, if you are typing a filename argument, you can do filename completion; if you are typing a command, -you can do command completion, if you are typing in a symbol to GDB, you -can do symbol name completion, if you are typing in a variable to Bash, +you can do command completion; if you are typing in a symbol to GDB, you +can do symbol name completion; if you are typing in a variable to Bash, you can do variable name completion, and so on. @ifset BashFeatures Bash attempts completion treating the text as a variable (if the @@ -961,6 +1026,19 @@ List the possible completions of the text before the cursor. 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 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 @code{TAB}, but is unbound +by default. + @ifset BashFeatures @item complete-filename (M-/) Attempt filename completion on the text before point. @@ -997,7 +1075,7 @@ treating it as a hostname. Attempt completion on the text before point, treating it as a command name. Command completion attempts to match the text against aliases, reserved words, shell -functions, builtins, and finally executable filenames, +functions, shell builtins, and finally executable filenames, in that order. @item possible-command-completions (C-x !) @@ -1052,7 +1130,7 @@ If the metafied character @var{x} is lowercase, run the command that is bound to the corresponding uppercase character. @item prefix-meta (ESC) -Make the next character that you type be metafied. This is for people +Make the next character typed be metafied. This is for keyboards without a meta key. Typing @samp{ESC f} is equivalent to typing @samp{M-f}. @@ -1060,7 +1138,7 @@ without a meta key. Typing @samp{ESC f} is equivalent to typing Incremental undo, separately remembered for each line. @item revert-line (M-r) -Undo all changes made to this line. This is like typing the @code{undo} +Undo all changes made to this line. This is like executing the @code{undo} command enough times to get back to the beginning. @item tilde-expand (M-~) @@ -1093,18 +1171,18 @@ This makes the current line a shell comment. @item dump-functions () Print all of the functions and their key bindings to the -readline output stream. If a numeric argument is supplied, +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, +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 +Print all of the Readline key sequences bound to macros and the strings they ouput. If a numeric argument is supplied, the output is formatted in such a way that it can be made part of an @var{inputrc} file. This command is unbound by default. @@ -1116,24 +1194,27 @@ and the list of matching file names is inserted, replacing the word. @item glob-list-expansions (C-x g) The list of expansions that would have been generated by -@code{glob-expand-word} -is inserted into the line, replacing the word before point. +@code{glob-expand-word} is displayed, and the line is redrawn. @item display-shell-version (C-x C-v) Display version information about the current instance of Bash. @item shell-expand-line (M-C-e) -Expand the line the way the shell does when it reads it. This -performs alias and history expansion as well as all of the shell -word expansions. +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 alias-expand-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 +@item history-and-alias-expand-line () Perform history and alias expansion on the current line. @item insert-last-argument (M-., M-_) diff --git a/lib/readline/examples/rltest.c b/lib/readline/examples/rltest.c index ff3ad5cc..453f8ec2 100644 --- a/lib/readline/examples/rltest.c +++ b/lib/readline/examples/rltest.c @@ -19,12 +19,16 @@ #include "readline.h" #include "history.h" +extern HIST_ENTRY **history_list (); + main () { - HIST_ENTRY **history_list (); - char *temp = (char *)NULL; - char *prompt = "readline$ "; - int done = 0; + char *temp, *prompt; + int done; + + temp = (char *)NULL; + prompt = "readline$ "; + done = 0; while (!done) { @@ -47,18 +51,17 @@ main () if (strcmp (temp, "list") == 0) { - HIST_ENTRY **list = history_list (); + HIST_ENTRY **list; register int i; + + list = history_list (); if (list) { for (i = 0; list[i]; i++) - { - fprintf (stderr, "%d: %s\r\n", i, list[i]->line); - free (list[i]->line); - } - free (list); + fprintf (stderr, "%d: %s\r\n", i, list[i]->line); } } free (temp); } + exit (0); } diff --git a/lib/readline/funmap.c b/lib/readline/funmap.c index 702fabd0..3946e0fc 100644 --- a/lib/readline/funmap.c +++ b/lib/readline/funmap.c @@ -94,11 +94,15 @@ static FUNMAP default_funmap[] = { { "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 }, +#ifdef __CYGWIN32__ + { "paste-from-clipboard", rl_paste_from_clipboard }, +#endif { "possible-completions", rl_possible_completions }, { "previous-history", rl_get_previous_history }, { "quoted-insert", rl_quoted_insert }, diff --git a/lib/readline/histexpand.c b/lib/readline/histexpand.c index de71d78a..0dc179ac 100644 --- a/lib/readline/histexpand.c +++ b/lib/readline/histexpand.c @@ -35,6 +35,9 @@ #endif /* HAVE_STDLIB_H */ #if defined (HAVE_UNISTD_H) +# ifndef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -47,6 +50,9 @@ #include "history.h" #include "histlib.h" +#define HISTORY_WORD_DELIMITERS " \t\n;&()|<>" +#define HISTORY_QUOTE_CHARACTERS "\"'`" + static char error_pointer; static char *subst_lhs; @@ -823,8 +829,8 @@ history_expand (hstring, output) only_printing = modified = 0; l = strlen (hstring); - /* Grovel the string. Only backslash can quote the history escape - character. We also handle arg specifiers. */ + /* Grovel the string. Only backslash and single quotes can quote the + history escape character. We also handle arg specifiers. */ /* Before we grovel forever, see if the history_expansion_char appears anywhere within the text. */ @@ -852,7 +858,18 @@ history_expand (hstring, output) for (i = 0; string[i]; i++) { cc = string[i + 1]; - if (string[i] == history_expansion_char) + /* The history_comment_char, if set, appearing that the beginning + of a word signifies that the rest of the line should not have + history expansion performed on it. + Skip the rest of the line and break out of the loop. */ + if (history_comment_char && string[i] == history_comment_char && + (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS))) + { + while (string[i]) + i++; + break; + } + else if (string[i] == history_expansion_char) { if (!cc || member (cc, history_no_expand_chars)) continue; @@ -867,6 +884,8 @@ history_expand (hstring, output) else break; } + /* XXX - at some point, might want to extend this to handle + double quotes as well. */ else if (history_quotes_inhibit_expansion && string[i] == '\'') { /* If this is bash, single quotes inhibit history expansion. */ @@ -904,6 +923,8 @@ history_expand (hstring, output) if (tchar == history_expansion_char) tchar = -3; + else if (tchar == history_comment_char) + tchar = -2; switch (tchar) { @@ -939,6 +960,19 @@ history_expand (hstring, output) break; } + case -2: /* history_comment_char */ + if (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS)) + { + temp = xmalloc (l - i + 1); + strcpy (temp, string + i); + ADD_STRING (temp); + free (temp); + i = l; + } + else + ADD_CHAR (string[i]); + break; + case -3: /* history_expansion_char */ cc = string[i + 1]; @@ -1238,7 +1272,7 @@ history_tokenize_internal (string, wind, indp) /* Get word from string + i; */ - if (member (string[i], "\"'`")) + if (member (string[i], HISTORY_QUOTE_CHARACTERS)) delimiter = string[i++]; for (; string[i]; i++) @@ -1262,10 +1296,10 @@ history_tokenize_internal (string, wind, indp) continue; } - if (!delimiter && (member (string[i], " \t\n;&()|<>"))) + if (!delimiter && (member (string[i], HISTORY_WORD_DELIMITERS))) break; - if (!delimiter && member (string[i], "\"'`")) + if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS)) delimiter = string[i]; } diff --git a/lib/readline/histfile.c b/lib/readline/histfile.c index 9f96f1cd..81dda57d 100644 --- a/lib/readline/histfile.c +++ b/lib/readline/histfile.c @@ -32,7 +32,9 @@ #include <stdio.h> #include <sys/types.h> -#include <sys/file.h> +#ifndef _MINIX +# include <sys/file.h> +#endif #include <sys/stat.h> #include <fcntl.h> @@ -129,19 +131,31 @@ read_history_range (filename, from, to) int from, to; { register int line_start, line_end; - char *input, *buffer = (char *)NULL; + char *input, *buffer; int file, current_line; struct stat finfo; + size_t file_size; + buffer = (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; - buffer = xmalloc ((int)finfo.st_size + 1); + 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 defined (EFBIG) + errno = EFBIG; +#endif + goto error_and_exit; + } - if (read (file, buffer, finfo.st_size) != finfo.st_size) + buffer = xmalloc (file_size + 1); + if (read (file, buffer, file_size) != file_size) { error_and_exit: if (file >= 0) @@ -157,15 +171,15 @@ read_history_range (filename, from, to) /* Set TO to larger than end of file if negative. */ if (to < 0) - to = finfo.st_size; + to = file_size; /* Start at beginning of file, work to end. */ line_start = line_end = current_line = 0; /* Skip lines until we are at FROM. */ - while (line_start < finfo.st_size && current_line < from) + while (line_start < file_size && current_line < from) { - for (line_end = line_start; line_end < finfo.st_size; line_end++) + for (line_end = line_start; line_end < file_size; line_end++) if (buffer[line_end] == '\n') { current_line++; @@ -176,7 +190,7 @@ read_history_range (filename, from, to) } /* If there are lines left to gobble, then gobble them now. */ - for (line_end = line_start; line_end < finfo.st_size; line_end++) + for (line_end = line_start; line_end < file_size; line_end++) if (buffer[line_end] == '\n') { buffer[line_end] = '\0'; @@ -209,6 +223,7 @@ history_truncate_file (fname, lines) int file, chars_read; char *buffer, *filename; struct stat finfo; + size_t file_size; buffer = (char *)NULL; filename = history_filename (fname); @@ -217,8 +232,20 @@ history_truncate_file (fname, lines) if (file == -1 || fstat (file, &finfo) == -1) goto truncate_exit; - buffer = xmalloc ((int)finfo.st_size + 1); - chars_read = read (file, buffer, finfo.st_size); + 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) + errno = EFBIG; +#endif + goto truncate_exit; + } + + buffer = xmalloc (file_size + 1); + chars_read = read (file, buffer, file_size); close (file); if (chars_read <= 0) @@ -248,7 +275,7 @@ history_truncate_file (fname, lines) truncate to. */ if (i && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1)) { - write (file, buffer + i, finfo.st_size - i); + write (file, buffer + i, file_size - i); close (file); } diff --git a/lib/readline/history.c b/lib/readline/history.c index fb9d68e7..24c5a49c 100644 --- a/lib/readline/history.c +++ b/lib/readline/history.c @@ -38,6 +38,9 @@ #endif /* HAVE_STDLIB_H */ #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif diff --git a/lib/readline/histsearch.c b/lib/readline/histsearch.c index a72a68bf..7e98e950 100644 --- a/lib/readline/histsearch.c +++ b/lib/readline/histsearch.c @@ -33,6 +33,9 @@ # include "ansi_stdlib.h" #endif /* HAVE_STDLIB_H */ #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif #if defined (HAVE_STRING_H) diff --git a/lib/readline/isearch.c b/lib/readline/isearch.c index ce2e58ba..7decf959 100644 --- a/lib/readline/isearch.c +++ b/lib/readline/isearch.c @@ -262,7 +262,7 @@ rl_search_history (direction, invoking_key) break; } - if (c >= 0 && (CTRL_CHAR (c) || META_CHAR (c) || c == RUBOUT) && c != CTRL ('g')) + if (c >= 0 && (CTRL_CHAR (c) || META_CHAR (c) || c == RUBOUT) && c != CTRL ('G')) { rl_execute_next (c); break; @@ -298,6 +298,21 @@ rl_search_history (direction, invoking_key) free (lines); return 0; +#if 0 + /* delete character from search string. */ + case -3: + if (search_string_index == 0) + ding (); + else + { + search_string[--search_string_index] = '\0'; + /* 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. */ + } + break; +#endif + default: /* Add character to search string and continue search. */ if (search_string_index + 2 >= search_string_size) diff --git a/lib/readline/keymaps.h b/lib/readline/keymaps.h index f8d0e2ef..f6143f86 100644 --- a/lib/readline/keymaps.h +++ b/lib/readline/keymaps.h @@ -39,9 +39,9 @@ typedef char **CPPFunction (); /* A keymap contains one entry for each key in the ASCII set. Each entry consists of a type and a pointer. - POINTER is the address of a function to run, or the + FUNCTION is the address of a function to run, or the address of a keymap to indirect through. - TYPE says which kind of thing POINTER is. */ + TYPE says which kind of thing FUNCTION is. */ typedef struct _keymap_entry { char type; Function *function; diff --git a/lib/readline/kill.c b/lib/readline/kill.c index 352f37de..a150e3c2 100644 --- a/lib/readline/kill.c +++ b/lib/readline/kill.c @@ -495,17 +495,32 @@ rl_yank_pop (count, key) } } -/* Yank the COUNTth argument from the previous history line. */ -int -rl_yank_nth_arg (count, ignore) - int count, ignore; +/* Yank the COUNTh argument from the previous history line, skipping + HISTORY_SKIP lines before looking for the `previous line'. */ +static int +rl_yank_nth_arg_internal (count, ignore, history_skip) + int count, ignore, history_skip; { register HIST_ENTRY *entry; char *arg; + int i; + + if (history_skip) + { + for (i = 0; i < history_skip; i++) + entry = previous_history (); + } entry = previous_history (); if (entry) - next_history (); + { + if (history_skip) + { + for (i = 0; i < history_skip; i++) + next_history (); + } + next_history (); + } else { ding (); @@ -538,6 +553,14 @@ rl_yank_nth_arg (count, ignore) return 0; } +/* Yank the COUNTth argument from the previous history line. */ +int +rl_yank_nth_arg (count, ignore) + int count, ignore; +{ + return (rl_yank_nth_arg_internal (count, ignore, 0)); +} + /* Yank the last argument from the previous history line. This `knows' how rl_yank_nth_arg treats a count of `$'. With an argument, this behaves the same as rl_yank_nth_arg. */ @@ -545,8 +568,67 @@ int rl_yank_last_arg (count, key) int count, key; { - if (rl_explicit_arg) - return (rl_yank_nth_arg (count, key)); + static int history_skip = 0; + static int explicit_arg_p = 0; + static int count_passed = 1; + static int direction = 1; + + if (rl_last_func != rl_yank_last_arg) + { + history_skip = 0; + explicit_arg_p = rl_explicit_arg; + count_passed = count; + direction = 1; + } + else + { + rl_do_undo (); + if (count < 1) + direction = -direction; + history_skip += direction; + if (history_skip < 0) + history_skip = 0; + count_passed = count; + } + + if (explicit_arg_p) + return (rl_yank_nth_arg_internal (count, key, history_skip)); else - return (rl_yank_nth_arg ('$', key)); + return (rl_yank_nth_arg_internal ('$', key, history_skip)); +} + +/* A special paste command for users of Cygnus's cygwin32. */ +#if defined (__CYGWIN32__) +#include <windows.h> + +int +rl_paste_from_clipboard (count, key) + int count, key; +{ + char *data, *ptr; + int len; + + if (OpenClipboard (NULL) == 0) + return (0); + + data = (char *)GetClipboardData (CF_TEXT); + if (data) + { + ptr = strchr (data, '\r'); + if (ptr) + { + len = ptr - data; + ptr = xmalloc (len + 1); + ptr[len] = '\0'; + strncpy (ptr, data, len); + } + else + ptr = data; + rl_insert_text (ptr); + if (ptr != data) + free (ptr); + CloseClipboard (); + } + return (0); } +#endif /* __CYGWIN32__ */ diff --git a/lib/readline/nls.c b/lib/readline/nls.c index 7a00a5f1..f2d413d5 100644 --- a/lib/readline/nls.c +++ b/lib/readline/nls.c @@ -69,7 +69,8 @@ static char *legal_lang_values[] = "iso88598", "iso88599", "iso885910", - "koi8r", + "koi8r", + "koi8-r", 0 }; diff --git a/lib/readline/parens.c b/lib/readline/parens.c index 50683f95..2c7251fd 100644 --- a/lib/readline/parens.c +++ b/lib/readline/parens.c @@ -101,7 +101,7 @@ rl_insert_close (count, invoking_key) FD_ZERO (&readfds); FD_SET (fileno (rl_instream), &readfds); - timer.tv_sec = 1; + timer.tv_sec = 0; timer.tv_usec = 500; orig_point = rl_point; diff --git a/lib/readline/readline.c b/lib/readline/readline.c index dcd8f817..8ff6e989 100644 --- a/lib/readline/readline.c +++ b/lib/readline/readline.c @@ -64,7 +64,7 @@ #include "history.h" #ifndef RL_LIBRARY_VERSION -# define RL_LIBRARY_VERSION "2.1-bash" +# define RL_LIBRARY_VERSION "2.2-bash" #endif /* Evaluates its arguments multiple times. */ @@ -78,7 +78,11 @@ /* Variables and functions imported from terminal.c */ extern int _rl_init_terminal_io (); extern void _rl_enable_meta_key (); +#ifdef _MINIX +extern void _rl_output_character_function (); +#else extern int _rl_output_character_function (); +#endif extern void _rl_get_screen_size (); extern int _rl_enable_meta; @@ -1027,6 +1031,18 @@ _rl_fix_point (fix_mark_too) } #undef _RL_FIX_POINT +void +_rl_replace_text (text, start, end) + char *text; + int start, end; +{ + rl_begin_undo_group (); + rl_delete_text (start, end + 1); + rl_point = start; + rl_insert_text (text); + rl_end_undo_group (); +} + /* **************************************************************** */ /* */ /* Readline character functions */ diff --git a/lib/readline/readline.h b/lib/readline/readline.h index 99ec055c..280ec32f 100644 --- a/lib/readline/readline.h +++ b/lib/readline/readline.h @@ -73,6 +73,7 @@ extern int rl_forward_word (), rl_tab_insert (), rl_yank_pop (), rl_yank_nth_arg (), rl_backward_kill_word (), rl_backward_kill_line (), rl_transpose_words (), rl_complete (), rl_possible_completions (), rl_insert_completions (), + rl_menu_complete (), rl_do_lowercase_version (), rl_kill_full_line (), rl_digit_argument (), rl_universal_argument (), rl_abort (), rl_undo_command (), rl_revert_line (), rl_beginning_of_history (), @@ -93,13 +94,19 @@ extern void rl_callback_handler_install (); extern void rl_callback_read_char (); extern void rl_callback_handler_remove (); +/* Not available unless __CYGWIN32__ is defined. */ +#ifdef __CYGWIN32__ +extern int rl_paste_from_clipboard (); +#endif + /* These are *both* defined even when VI_MODE is not. */ extern int rl_vi_editing_mode (), rl_emacs_editing_mode (); /* Non incremental history searching. */ -extern int - rl_noninc_forward_search (), rl_noninc_reverse_search (), - rl_noninc_forward_search_again (), rl_noninc_reverse_search_again (); +extern int rl_noninc_forward_search (); +extern int rl_noninc_reverse_search (); +extern int rl_noninc_forward_search_again (); +extern int rl_noninc_reverse_search_again (); /* Things for vi mode. Not available unless readline is compiled -DVI_MODE. */ extern int rl_vi_check (); @@ -153,6 +160,7 @@ extern char *rl_get_keymap_name (); extern int rl_bind_key (), rl_bind_key_in_map (); extern int rl_unbind_key (), rl_unbind_key_in_map (); +extern int rl_unbind_function_in_map (), rl_unbind_command_in_map (); extern int rl_set_key (); extern int rl_generic_bind (); extern int rl_parse_and_bind (); diff --git a/lib/readline/rltty.h b/lib/readline/rltty.h index 3e137047..fe783463 100644 --- a/lib/readline/rltty.h +++ b/lib/readline/rltty.h @@ -42,17 +42,7 @@ # include <sgtty.h> #endif -/* Stuff for `struct winsize' on various systems. */ -#if defined (HAVE_SYS_STREAM_H) -# include <sys/stream.h> -#endif /* HAVE_SYS_STREAM_H */ -#if defined (HAVE_SYS_PTEM_H) -# include <sys/ptem.h> -# define _IO_PTEM_H /* work around SVR4.2 1.1.4 bug */ -#endif /* HAVE_SYS_PTEM_H */ -#if defined (HAVE_SYS_PTE_H) -# include <sys/pte.h> -#endif /* HAVE_SYS_PTE_H */ +#include "rlwinsize.h" /* Define _POSIX_VDISABLE if we are not using the `new' tty driver and it is not already defined. It is used both to determine if a diff --git a/lib/readline/rlwinsize.h b/lib/readline/rlwinsize.h new file mode 100644 index 00000000..92b3de17 --- /dev/null +++ b/lib/readline/rlwinsize.h @@ -0,0 +1,58 @@ +/* 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 1, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_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 <sys/ioctl.h> +#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */ + +#if defined (STRUCT_WINSIZE_IN_TERMIOS) && !defined (STRUCT_WINSIZE_IN_SYS_IOCTL) +# include <termios.h> +#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 <sys/stream.h> +# endif /* HAVE_SYS_STREAM_H */ +# if defined (HAVE_SYS_PTEM_H) /* SVR4.2, at least, has it here */ +# include <sys/ptem.h> +# define _IO_PTEM_H /* work around SVR4.2 1.1.4 bug */ +# endif /* HAVE_SYS_PTEM_H */ +# if defined (HAVE_SYS_PTE_H) /* ??? */ +# include <sys/pte.h> +# endif /* HAVE_SYS_PTE_H */ +#endif /* !STRUCT_WINSIZE_IN_TERMIOS && !STRUCT_WINSIZE_IN_SYS_IOCTL */ + +#endif /* _RL_WINSIZE_H */ + + diff --git a/lib/readline/shell.c b/lib/readline/shell.c index eb99c727..553f3c1c 100644 --- a/lib/readline/shell.c +++ b/lib/readline/shell.c @@ -27,6 +27,9 @@ #endif #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif /* HAVE_UNISTD_H */ @@ -36,6 +39,12 @@ # include "ansi_stdlib.h" #endif /* HAVE_STDLIB_H */ +#if defined (HAVE_STRING_H) +# include <string.h> +#else +# include <strings.h> +#endif /* !HAVE_STRING_H */ + extern char *xmalloc (), *xrealloc (); #if !defined (SHELL) diff --git a/lib/readline/terminal.c b/lib/readline/terminal.c index 5a8df892..c2866965 100644 --- a/lib/readline/terminal.c +++ b/lib/readline/terminal.c @@ -434,13 +434,21 @@ rl_reset_terminal (terminal_name) } /* 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) @@ -519,18 +527,11 @@ ding () /* */ /* **************************************************************** */ -static int -outchar (c) - int c; -{ - return putc (c, rl_outstream); -} - void _rl_enable_meta_key () { if (term_has_meta && term_mm) - tputs (term_mm, 1, outchar); + tputs (term_mm, 1, _rl_output_character_function); } void @@ -538,7 +539,7 @@ _rl_control_keypad (on) int on; { if (on && term_ks) - tputs (term_ks, 1, outchar); + tputs (term_ks, 1, _rl_output_character_function); else if (!on && term_ke) - tputs (term_ke, 1, outchar); + tputs (term_ke, 1, _rl_output_character_function); } diff --git a/lib/readline/tilde.c b/lib/readline/tilde.c index fe263a26..3741f976 100644 --- a/lib/readline/tilde.c +++ b/lib/readline/tilde.c @@ -24,6 +24,9 @@ #endif #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif diff --git a/lib/readline/util.c b/lib/readline/util.c index d96b29e8..fde012ed 100644 --- a/lib/readline/util.c +++ b/lib/readline/util.c @@ -166,6 +166,58 @@ rl_extend_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 = xmalloc (len + 1); + strncpy (temp, rl_line_buffer + start, len); + temp[len] = '\0'; + homedir = tilde_expand (temp); + free (temp); + + _rl_replace_text (homedir, start, end); + } + + return (0); +} + /* **************************************************************** */ /* */ /* String Utility Functions */ @@ -300,3 +352,13 @@ _rl_digit_value (c) { return (isdigit (c) ? c - '0' : c); } + +/* Backwards compatibility, now that savestring has been removed from + all `public' readline header files. */ +#undef _rl_savestring +char * +_rl_savestring (s) + char *s; +{ + return ((char *)strcpy (xmalloc (1 + (int)strlen (s)), (s))); +} diff --git a/lib/readline/vi_mode.c b/lib/readline/vi_mode.c index c730296d..2f62ec3d 100644 --- a/lib/readline/vi_mode.c +++ b/lib/readline/vi_mode.c @@ -615,6 +615,13 @@ _rl_vi_save_insert (up) { int len, start, end; + if (up == 0) + { + if (vi_insert_buffer_size >= 1) + vi_insert_buffer[0] = '\0'; + return; + } + start = up->start; end = up->end; len = end - start + 1; diff --git a/lib/sh/Makefile.in b/lib/sh/Makefile.in new file mode 100644 index 00000000..d98f9c5e --- /dev/null +++ b/lib/sh/Makefile.in @@ -0,0 +1,164 @@ +# +# Makefile for the Bash library +# + +srcdir = @srcdir@ +VPATH = .:@srcdir@ +topdir = @top_srcdir@ +BUILD_DIR = @BUILD_DIR@ + +POSIX_INC = ${topdir}/lib/posixheaders + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ +RANLIB = @RANLIB@ +AR = @AR@ +RM = rm -f +CP = cp +MV = mv + +CFLAGS = @CFLAGS@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ @LOCAL_LDFLAGS@ + +PROFILE_FLAGS = @PROFILE_FLAGS@ + +DEFS = @DEFS@ +LOCAL_DEFS = @LOCAL_DEFS@ + +INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/lib -I$(POSIX_INC) -I$(srcdir) + +CCFLAGS = ${PROFILE_FLAGS} ${INCLUDES} $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) \ + $(CFLAGS) $(CPPFLAGS) + +.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 getcwd.c getenv.c oslib.c setlinebuf.c \ + strcasecmp.c strerror.c strtod.c strtol.c strtoul.c \ + vprint.c itos.c + +# The header files for this library. +HSOURCES = + +# The object files contained in $(LIBRARY_NAME) +OBJECTS = clktck.o getcwd.o getenv.o oslib.o setlinebuf.o \ + strcasecmp.o strerror.o strtod.o strtol.o strtoul.o \ + vprint.o itos.o + +SUPPORT = Makefile + +all: $(LIBRARY_NAME) + +$(LIBRARY_NAME): $(OBJECTS) + $(RM) $@ + $(AR) cr $@ $(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 + +# rules for losing makes, like SunOS +clktck.o: clktck.c +getcwd.o: getcwd.c +getenv.o: getenv.c +itos.o: itos.c +oslib.o: oslib.c +setlinebuf.o: setlinebuf.c +strcasecmp.o: strcasecmp.c +strerror.o: strerror.c +strtod.o: strtod.c +strtol.o: strtol.c +strtoul.o: strtoul.c +vprint.o: vprint.c + +# all files in the library depend on config.h +clktck.o: ${BUILD_DIR}/config.h +getcwd.o: ${BUILD_DIR}/config.h +getenv.o: ${BUILD_DIR}/config.h +itos.o: ${BUILD_DIR}/config.h +oslib.o: ${BUILD_DIR}/config.h +setlinebuf.o: ${BUILD_DIR}/config.h +strcasecmp.o: ${BUILD_DIR}/config.h +strerror.o: ${BUILD_DIR}/config.h +strtod.o: ${BUILD_DIR}/config.h +strtol.o: ${BUILD_DIR}/config.h +strtoul.o: ${BUILD_DIR}/config.h +vprint.o: ${BUILD_DIR}/config.h + +clktck.o: ${topdir}/bashtypes.h + +getcwd.o: ${topdir}/bashtypes.h ${topdir}/bashansi.h ${topdir}/maxpath.h +getcwd.o: ${POSIX_INC}/posixstat.h ${POSIX_INC}/posixdir.h +getcwd.o: ${POSIX_INC}/memalloc.h ${POSIX_INC}/ansi_stdlib.h + +getenv.o: ${topdir}/bashansi.h ${topdir}/ansi_stdlib.h +getenv.o: ${topdir}/shell.h ${topdir}/bashjmp.h ${topdir}/posixjmp.h +getenv.o: ${topdir}/command.h ${topdir}/stdc.h ${topdir}/error.h +getenv.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.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: ${topdir}/pathnames.h ${topdir}/externs.h + +itos.o: ${topdir}/bashansi.h ${topdir}/ansi_stdlib.h +itos.o: ${topdir}/shell.h ${topdir}/bashjmp.h ${topdir}/posixjmp.h +itos.o: ${topdir}/command.h ${topdir}/stdc.h ${topdir}/error.h +itos.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.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: ${topdir}/pathnames.h ${topdir}/externs.h + +oslib.o: ${topdir}/bashtypes.h ${topdir}/bashansi.h ${topdir}/maxpath.h +oslib.o: ${topdir}/shell.h ${topdir}/bashjmp.h ${topdir}/posixjmp.h +oslib.o: ${topdir}/command.h ${topdir}/stdc.h ${topdir}/error.h +oslib.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.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: ${topdir}/pathnames.h ${topdir}/externs.h +oslib.o: ${POSIX_INC}/posixstat.h ${POSIX_INC}/filecntl.h +oslib.o: ${POSIX_INC}/ansi_stdlib.h + +strcasecmp.o: ${topdir}/stdc.h ${topdir}/bashansi.h ${topdir}/ansi_stdlib.h + +strerror.o: ${topdir}/bashtypes.h +strerror.o: ${topdir}/shell.h ${topdir}/bashjmp.h ${topdir}/posixjmp.h +strerror.o: ${topdir}/command.h ${topdir}/stdc.h ${topdir}/error.h +strerror.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.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: ${topdir}/pathnames.h ${topdir}/externs.h + +strtod.o: ${topdir}/bashansi.h +strtod.o: ${POSIX_INC}/ansi_stdlib.h + +strtol.o: ${topdir}/bashansi.h +strtol.o: ${POSIX_INC}/ansi_stdlib.h + +strtoul.o: ${topdir}/bashansi.h +strtoul.o: ${POSIX_INC}/ansi_stdlib.h diff --git a/lib/sh/clktck.c b/lib/sh/clktck.c new file mode 100644 index 00000000..b0b674e2 --- /dev/null +++ b/lib/sh/clktck.c @@ -0,0 +1,55 @@ +/* clktck.c - get the value of CLK_TCK. */ + +/* 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 <bashtypes.h> +#include <sys/param.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#if !defined (HAVE_SYSCONF) || !defined (_SC_CLK_TCK) +# if !defined (CLK_TCK) +# if defined (HZ) +# define CLK_TCK HZ +# else +# define CLK_TCK 60 +# endif +# endif /* !CLK_TCK */ +#endif /* !HAVE_SYSCONF && !_SC_CLK_TCK */ + +long +get_clk_tck () +{ + static long retval = 0; + + if (retval != 0) + return (retval); + +#if defined (HAVE_SYSCONF) && defined (_SC_CLK_TCK) + retval = sysconf (_SC_CLK_TCK); +#else /* !SYSCONF || !_SC_CLK_TCK */ + retval = CLK_TCK; +#endif /* !SYSCONF || !_SC_CLK_TCK */ + + return (retval); +} diff --git a/getcwd.c b/lib/sh/getcwd.c index 529b57d6..9a8b31f7 100644 --- a/getcwd.c +++ b/lib/sh/getcwd.c @@ -18,11 +18,11 @@ not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "config.h" +#include <config.h> #if !defined (HAVE_GETCWD) -#include "bashtypes.h" +#include <bashtypes.h> #include <errno.h> #if defined (HAVE_LIMITS_H) @@ -33,12 +33,12 @@ # include <unistd.h> #endif -#include "posixdir.h" -#include "posixstat.h" -#include "maxpath.h" -#include "memalloc.h" +#include <posixdir.h> +#include <posixstat.h> +#include <maxpath.h> +#include <memalloc.h> -#include "bashansi.h" +#include <bashansi.h> #if !defined (errno) extern int errno; @@ -94,6 +94,7 @@ getcwd (buf, size) char *pathbuf; size_t pathsize; struct stat st; + int saved_errno; if (buf != NULL && size == 0) { @@ -116,6 +117,8 @@ getcwd (buf, size) rootdev = st.st_dev; rootino = st.st_ino; + saved_errno = 0; + dotsize = sizeof (dots) - 1; dotp = &dots[sizeof (dots)]; dotlist = dots; @@ -185,10 +188,14 @@ getcwd (buf, size) 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; @@ -196,7 +203,11 @@ getcwd (buf, size) } if (d == NULL) { +#if 0 int save = errno; +#else + int save = errno ? errno : saved_errno; +#endif (void) closedir (dirstream); errno = save; goto lose; diff --git a/lib/sh/getenv.c b/lib/sh/getenv.c new file mode 100644 index 00000000..63536154 --- /dev/null +++ b/lib/sh/getenv.c @@ -0,0 +1,99 @@ +/* getenv.c - get environment variable value from the shell's variable + list. */ + +/* 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> + +#if defined (CAN_REDEFINE_GETENV) + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#include <bashansi.h> +#include <shell.h> + +extern char **environ; + +/* We supply our own version of getenv () because we want library + routines to get the changed values of exported variables. */ + +/* The NeXT C library has getenv () defined and used in the same file. + This screws our scheme. However, Bash will run on the NeXT using + the C library getenv (), since right now the only environment variable + that we care about is HOME, and that is already defined. */ +static char *last_tempenv_value = (char *)NULL; + +char * +getenv (name) +#if defined (__linux__) || defined (__bsdi__) || defined (convex) + const char *name; +#else + char const *name; +#endif /* !__linux__ && !__bsdi__ && !convex */ +{ + SHELL_VAR *var; + + var = find_tempenv_variable ((char *)name); + if (var) + { + FREE (last_tempenv_value); + + last_tempenv_value = savestring (value_cell (var)); + dispose_variable (var); + return (last_tempenv_value); + } + else if (shell_variables) + { + var = find_variable ((char *)name); + if (var && exported_p (var)) + return (value_cell (var)); + } + else + { + register int i, len; + + /* In some cases, s5r3 invokes getenv() before main(); BSD systems + using gprof also exhibit this behavior. This means that + shell_variables will be 0 when this is invoked. We look up the + variable in the real environment in that case. */ + + for (i = 0, len = strlen (name); environ[i]; i++) + { + if ((STREQN (environ[i], name, len)) && (environ[i][len] == '=')) + return (environ[i] + len + 1); + } + } + + return ((char *)NULL); +} + +/* Some versions of Unix use _getenv instead. */ +char * +_getenv (name) +#if defined (__linux__) || defined (__bsdi__) || defined (convex) + const char *name; +#else + char const *name; +#endif /* !__linux__ && !__bsdi__ && !convex */ +{ + return (getenv (name)); +} +#endif /* CAN_REDEFINE_GETENV */ diff --git a/lib/sh/itos.c b/lib/sh/itos.c new file mode 100644 index 00000000..720e4100 --- /dev/null +++ b/lib/sh/itos.c @@ -0,0 +1,64 @@ +/* itos.c -- Convert integer to string. */ + +/* Copyright (C) 1998, Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + Bash is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with Bash; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <config.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#include "bashansi.h" +#include "shell.h" + +/* Number of characters that can appear in a string representation + of an integer. 32 is larger than the string rep of 2^^31 - 1. */ +#define MAX_INT_LEN 32 + +/* Integer to string conversion. This conses the string; the + caller should free it. */ +char * +itos (i) + int i; +{ + char buf[MAX_INT_LEN], *p, *ret; + int negative = 0; + unsigned int ui; + + if (i < 0) + { + negative++; + i = -i; + } + + ui = (unsigned int) i; + + p = buf + MAX_INT_LEN - 2; + p[1] = '\0'; + + do + *p-- = (ui % 10) + '0'; + while (ui /= 10); + + if (negative) + *p-- = '-'; + + ret = savestring (p + 1); + return (ret); +} diff --git a/oslib.c b/lib/sh/oslib.c index bc49fff3..d92c32e9 100644 --- a/oslib.c +++ b/lib/sh/oslib.c @@ -16,62 +16,33 @@ You should have received a copy of the GNU General Public License along with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ -#include "config.h" +#include <config.h> -#include "bashtypes.h" -#include <sys/param.h> +#include <bashtypes.h> +#ifndef _MINIX +# include <sys/param.h> +#endif #if defined (HAVE_UNISTD_H) # include <unistd.h> #endif -#include "posixstat.h" -#include "filecntl.h" -#include "bashansi.h" +#include <posixstat.h> +#include <filecntl.h> +#include <bashansi.h> #include <stdio.h> #include <errno.h> #include <ctype.h> -#include "shell.h" -#include "maxpath.h" +#include <shell.h> #if !defined (errno) extern int errno; #endif /* !errno */ -/* A standard error message to use when getcwd() returns NULL. */ -char *bash_getcwd_errstr = "getcwd: cannot access parent directories"; - -#if !defined (HAVE_SYSCONF) || !defined (_SC_CLK_TCK) -# if !defined (CLK_TCK) -# if defined (HZ) -# define CLK_TCK HZ -# else -# define CLK_TCK 60 -# endif -# endif /* !CLK_TCK */ -#endif /* !HAVE_SYSCONF && !_SC_CLK_TCK */ - -long -get_clk_tck () -{ - static long retval = 0; - - if (retval != 0) - return (retval); - -#if defined (HAVE_SYSCONF) && defined (_SC_CLK_TCK) - retval = sysconf (_SC_CLK_TCK); -#else /* !SYSCONF || !_SC_CLK_TCK */ - retval = CLK_TCK; -#endif /* !SYSCONF || !_SC_CLK_TCK */ - - return (retval); -} - /* Make the functions strchr and strrchr if they do not exist. */ #if !defined (HAVE_STRCHR) char * @@ -102,87 +73,6 @@ strrchr (string, c) } #endif /* !HAVE_STRCHR */ -#if !defined (HAVE_STRCASECMP) - -#if !defined (to_lower) -# define to_lower(c) (islower(c) ? (c) : tolower(c)) -#endif /* to_lower */ - -/* Compare at most COUNT characters from string1 to string2. Case - doesn't matter. */ -int -strncasecmp (string1, string2, count) - const char *string1, *string2; - int count; -{ - register char *s1, *s2; - register int r; - - if (count > 0) - { - s1 = (char *)string1; - s2 = (char *)string2; - do - { - if ((r = to_lower (*s1) - to_lower (*s2)) != 0) - return r; - if (*s1++ == '\0') - break; - s2++; - } - while (--count != 0); - } - return (0); -} - -/* strcmp (), but caseless. */ -int -strcasecmp (string1, string2) - const char *string1, *string2; -{ - register char *s1, *s2; - register int r; - - s1 = (char *)string1; - s2 = (char *)string2; - - while ((r = to_lower (*s1) - to_lower (*s2)) == 0) - { - if (*s1++ == '\0') - return 0; - s2++; - } - return (r); -} -#endif /* !HAVE_STRCASECMP */ - -/* Return a string corresponding to the error number E. From - the ANSI C spec. */ -#if defined (strerror) -# undef strerror -#endif - -#if !defined (HAVE_STRERROR) -char * -strerror (e) - int e; -{ - static char emsg[40]; -#if defined (HAVE_SYS_ERRLIST) - extern int sys_nerr; - extern char *sys_errlist[]; - - if (e > 0 && e < sys_nerr) - return (sys_errlist[e]); - else -#endif /* HAVE_SYS_ERRLIST */ - { - sprintf (emsg, "Unknown error %d", e); - return (&emsg[0]); - } -} -#endif /* HAVE_STRERROR */ - #if !defined (HAVE_DUP2) || defined (DUP2_BROKEN) /* Replacement for dup2 (), for those systems which either don't have it, or supply one with broken behaviour. */ @@ -328,76 +218,6 @@ killpg (pgrp, sig) } #endif /* !HAVE_KILLPG */ - -/* We supply our own version of getenv () because we want library - routines to get the changed values of exported variables. */ - -/* The NeXT C library has getenv () defined and used in the same file. - This screws our scheme. However, Bash will run on the NeXT using - the C library getenv (), since right now the only environment variable - that we care about is HOME, and that is already defined. */ -#if defined (CAN_REDEFINE_GETENV) -static char *last_tempenv_value = (char *)NULL; -extern char **environ; - -char * -getenv (name) -#if defined (__linux__) || defined (__bsdi__) || defined (convex) - const char *name; -#else - char const *name; -#endif /* !__linux__ && !__bsdi__ && !convex */ -{ - SHELL_VAR *var; - - var = find_tempenv_variable ((char *)name); - if (var) - { - FREE (last_tempenv_value); - - last_tempenv_value = savestring (value_cell (var)); - dispose_variable (var); - return (last_tempenv_value); - } - else if (shell_variables) - { - var = find_variable ((char *)name); - if (var && exported_p (var)) - return (value_cell (var)); - } - else - { - register int i, len; - - /* In some cases, s5r3 invokes getenv() before main(); BSD systems - using gprof also exhibit this behavior. This means that - shell_variables will be 0 when this is invoked. We look up the - variable in the real environment in that case. */ - - for (i = 0, len = strlen (name); environ[i]; i++) - { - if ((STREQN (environ[i], name, len)) && (environ[i][len] == '=')) - return (environ[i] + len + 1); - } - } - - return ((char *)NULL); -} - -/* Some versions of Unix use _getenv instead. */ -char * -_getenv (name) -#if defined (__linux__) || defined (__bsdi__) || defined (convex) - const char *name; -#else - char const *name; -#endif /* !__linux__ && !__bsdi__ && !convex */ -{ - return (getenv (name)); -} - -#endif /* CAN_REDEFINE_GETENV */ - #if !defined (HAVE_MKFIFO) && defined (PROCESS_SUBSTITUTION) int mkfifo (path, mode) @@ -410,21 +230,4 @@ mkfifo (path, mode) return (-1); #endif /* !S_IFIFO */ } -#endif - -#if !defined (HAVE_SETLINEBUF) -/* Cause STREAM to buffer lines as opposed to characters or blocks. */ -int -setlinebuf (stream) - FILE *stream; -{ -#if defined (_IOLBF) -# if defined (SETVBUF_REVERSED) - setvbuf (stream, _IOLBF, (char *)NULL, BUFSIZ); -# else /* !SETVBUF_REVERSED */ - setvbuf (stream, (char *)NULL, _IOLBF, BUFSIZ); -# endif /* !SETVBUF_REVERSED */ -#endif /* _IOLBF */ - return (0); -} -#endif /* !HAVE_SETLINEBUF */ +#endif /* !HAVE_MKFIFO && PROCESS_SUBSTITUTION */ diff --git a/lib/sh/setlinebuf.c b/lib/sh/setlinebuf.c new file mode 100644 index 00000000..05f95793 --- /dev/null +++ b/lib/sh/setlinebuf.c @@ -0,0 +1,41 @@ +/* setlinebuf.c - line-buffer a stdio stream. */ + +/* 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> + +#if !defined (HAVE_SETLINEBUF) + +#include <stdio.h> + +/* Cause STREAM to buffer lines as opposed to characters or blocks. */ +int +setlinebuf (stream) + FILE *stream; +{ +#if defined (_IOLBF) +# if defined (SETVBUF_REVERSED) + setvbuf (stream, _IOLBF, (char *)NULL, BUFSIZ); +# else /* !SETVBUF_REVERSED */ + setvbuf (stream, (char *)NULL, _IOLBF, BUFSIZ); +# endif /* !SETVBUF_REVERSED */ +#endif /* _IOLBF */ + return (0); +} +#endif /* !HAVE_SETLINEBUF */ diff --git a/lib/sh/strcasecmp.c b/lib/sh/strcasecmp.c new file mode 100644 index 00000000..74d98cb5 --- /dev/null +++ b/lib/sh/strcasecmp.c @@ -0,0 +1,88 @@ +/* strcasecmp.c - functions for case-insensitive string comparison. */ + +/* Copyright (C) 1995 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + Bash is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with Bash; see the file COPYING. If not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ + +#include <config.h> + +#if !defined (HAVE_STRCASECMP) + +#include <stdc.h> +#include <bashansi.h> +#include <ctype.h> + +#if !defined (to_lower) +# define to_lower(c) (islower(c) ? (c) : tolower(c)) +#endif /* to_lower */ + +/* Compare at most COUNT characters from string1 to string2. Case + doesn't matter. */ +int +strncasecmp (string1, string2, count) + const char *string1; + const char *string2; + int count; +{ + register const char *s1; + register const char *s2; + register int r; + + if (count <= 0 || (string1 == string2)) + return 0; + + s1 = string1; + s2 = string2; + do + { + if ((r = to_lower (*s1) - to_lower (*s2)) != 0) + return r; + if (*s1++ == '\0') + break; + s2++; + } + while (--count != 0); + + return (0); +} + +/* strcmp (), but caseless. */ +int +strcasecmp (string1, string2) + const char *string1; + const char *string2; +{ + register const char *s1; + register const char *s2; + register int r; + + s1 = string1; + s2 = string2; + + if (s1 == s2) + return (0); + + while ((r = to_lower (*s1) - to_lower (*s2)) == 0) + { + if (*s1++ == '\0') + return 0; + s2++; + } + + return (r); +} +#endif /* !HAVE_STRCASECMP */ diff --git a/lib/sh/strerror.c b/lib/sh/strerror.c new file mode 100644 index 00000000..4990aa7e --- /dev/null +++ b/lib/sh/strerror.c @@ -0,0 +1,74 @@ +/* strerror.c - string corresponding to a particular value of errno. */ + +/* Copyright (C) 1995 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + Bash is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with Bash; see the file COPYING. If not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ + +#include <config.h> + +#if !defined (HAVE_STRERROR) + +#include <bashtypes.h> +#ifndef _MINIX +# include <sys/param.h> +#endif + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#include <stdio.h> +#include <errno.h> + +#include <shell.h> + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +/* Return a string corresponding to the error number E. From + the ANSI C spec. */ +#if defined (strerror) +# undef strerror +#endif + +static char *errbase = "Unknown system error "; + +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 */ + { + char *z; + + z = itos (e); + strcpy (emsg, errbase); + strcat (emsg, z); + free (z); + return (&emsg[0]); + } +} +#endif /* HAVE_STRERROR */ diff --git a/lib/sh/strtod.c b/lib/sh/strtod.c new file mode 100644 index 00000000..fe0f09dc --- /dev/null +++ b/lib/sh/strtod.c @@ -0,0 +1,197 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#ifndef HAVE_STRTOD + +#include <errno.h> +#ifndef errno +extern int errno; +#endif + +#include <ctype.h> +#include <math.h> + +#if HAVE_FLOAT_H +# include <float.h> +#else +# define DBL_MAX 1.7976931348623159e+308 +# define DBL_MIN 2.2250738585072010e-308 +#endif + +#include <bashansi.h> + +#ifndef NULL +# define NULL 0 +#endif + +#ifndef HUGE_VAL +# define HUGE_VAL HUGE +#endif + +/* Convert NPTR to a double. If ENDPTR is not NULL, a pointer to the + character after the last one used in the number is put in *ENDPTR. */ +double +strtod (nptr, endptr) + const char *nptr; + char **endptr; +{ + register const char *s; + short sign; + + /* The number so far. */ + double num; + + int got_dot; /* Found a decimal point. */ + int got_digit; /* Seen any digits. */ + + /* The exponent of the number. */ + long int exponent; + + if (nptr == NULL) + { + errno = EINVAL; + goto noconv; + } + + s = nptr; + + /* Eat whitespace. */ + while (isspace (*s)) + ++s; + + /* Get the sign. */ + sign = *s == '-' ? -1 : 1; + if (*s == '-' || *s == '+') + ++s; + + num = 0.0; + got_dot = 0; + got_digit = 0; + exponent = 0; + for (;; ++s) + { + if (isdigit (*s)) + { + got_digit = 1; + + /* Make sure that multiplication by 10 will not overflow. */ + if (num > DBL_MAX * 0.1) + /* The value of the digit doesn't matter, since we have already + gotten as many digits as can be represented in a `double'. + This doesn't necessarily mean the result will overflow. + The exponent may reduce it to within range. + + We just need to record that there was another + digit so that we can multiply by 10 later. */ + ++exponent; + else + num = (num * 10.0) + (*s - '0'); + + /* Keep track of the number of digits after the decimal point. + If we just divided by 10 here, we would lose precision. */ + if (got_dot) + --exponent; + } + else if (!got_dot && *s == '.') + /* Record that we have found the decimal point. */ + got_dot = 1; + else + /* Any other character terminates the number. */ + break; + } + + if (!got_digit) + goto noconv; + + if (tolower (*s) == 'e') + { + /* Get the exponent specified after the `e' or `E'. */ + int save = errno; + char *end; + long int exp; + + errno = 0; + ++s; + exp = strtol (s, &end, 10); + if (errno == ERANGE) + { + /* The exponent overflowed a `long int'. It is probably a safe + assumption that an exponent that cannot be represented by + a `long int' exceeds the limits of a `double'. */ + if (endptr != NULL) + *endptr = end; + if (exp < 0) + goto underflow; + else + goto overflow; + } + else if (end == s) + /* There was no exponent. Reset END to point to + the 'e' or 'E', so *ENDPTR will be set there. */ + end = (char *) s - 1; + errno = save; + s = end; + exponent += exp; + } + + if (endptr != NULL) + *endptr = (char *) s; + + if (num == 0.0) + return 0.0; + + /* Multiply NUM by 10 to the EXPONENT power, + checking for overflow and underflow. */ + + if (exponent < 0) + { + if (num < DBL_MIN * pow (10.0, (double) -exponent)) + goto underflow; + } + else if (exponent > 0) + { + if (num > DBL_MAX * pow (10.0, (double) -exponent)) + goto overflow; + } + + num *= pow (10.0, (double) exponent); + + return num * sign; + +overflow: + /* Return an overflow error. */ + errno = ERANGE; + return HUGE_VAL * sign; + +underflow: + /* Return an underflow error. */ + if (endptr != NULL) + *endptr = (char *) nptr; + errno = ERANGE; + return 0.0; + +noconv: + /* There was no number. */ + if (endptr != NULL) + *endptr = (char *) nptr; + return 0.0; +} + +#endif /* !HAVE_STRTOD */ diff --git a/lib/sh/strtol.c b/lib/sh/strtol.c new file mode 100644 index 00000000..aed233fd --- /dev/null +++ b/lib/sh/strtol.c @@ -0,0 +1,213 @@ +/* strtol - Convert string representation of a number into an integer value. + Copyright (C) 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <config.h> + +#if !defined (HAVE_STRTOL) + +#include <ctype.h> +#include <errno.h> + +#ifndef errno +extern int errno; +#endif + +#ifndef __set_errno +# define __set_errno(Val) errno = (Val) +#endif + +#ifdef HAVE_LIMITS_H +# include <limits.h> +#endif + +#include <bashansi.h> + +#ifndef NULL +# define NULL 0 +#endif + +/* Nonzero if we are defining `strtoul', operating on unsigned integers. */ +#ifndef UNSIGNED +# define UNSIGNED 0 +# define RETTYPE long +#else +# define RETTYPE unsigned long +#endif + +/* Determine the name. */ +#if UNSIGNED +# define strtol strtoul +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +#ifndef ULONG_MAX +# define ULONG_MAX ((unsigned long) ~(unsigned long) 0) +# define ULONG_MIN ((unsigned long) 0 - ULONG_MAX) +#endif + +#ifndef LONG_MAX +# define LONG_MAX ((long) (ULONG_MAX >> 1)) +# define LONG_MIN ((long) (0 - LONG_MAX)) +#endif + +/* Convert NPTR to an `unsigned long int' or `long int' in base BASE. + If BASE is 0 the base is determined by the presence of a leading + zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal. + If BASE is < 2 or > 36, it is reset to 10. + If ENDPTR is not NULL, a pointer to the character after the last + one converted is stored in *ENDPTR. */ + +RETTYPE +strtol (nptr, endptr, base) + const char *nptr; + char **endptr; + int base; +{ + int negative; + register unsigned long cutoff, i; + register unsigned int cutlim; + register const char *s; + register unsigned char c; + const char *save, *end; + int overflow; + + if (base < 0 || base == 1 || base > 36) + base = 10; + + save = s = nptr; + + /* Skip white space. */ + while (isspace (*s)) + ++s; + if (*s == '\0') + goto noconv; + + /* Check for a sign. */ + if (*s == '-' || *s == '+') + { + negative = (*s == '-'); + ++s; + } + else + negative = 0; + + if (base == 16 && *s == '0' && toupper (s[1]) == 'X') + s += 2; + + /* If BASE is zero, figure it out ourselves. */ + if (base == 0) + if (*s == '0') + { + if (toupper (s[1]) == 'X') + { + s += 2; + base = 16; + } + else + base = 8; + } + else + base = 10; + + /* Save the pointer so we can check later if anything happened. */ + save = s; + + end = NULL; + + cutoff = ULONG_MAX / (unsigned long int) base; + cutlim = ULONG_MAX % (unsigned long int) base; + + overflow = 0; + i = 0; + for (c = *s; c != '\0'; c = *++s) + { + if (s == end) + break; + + if (c >= '0' && c <= '9') + c -= '0'; + else if (isalpha (c)) + c = toupper (c) - 'A' + 10; + else + break; + + if ((int) c >= base) + break; + + /* Check for overflow. */ + if (i > cutoff || (i == cutoff && c > cutlim)) + overflow = 1; + else + { + i *= (unsigned long int) base; + i += c; + } + } + + /* Check if anything actually happened. */ + if (s == save) + goto noconv; + + /* Store in ENDPTR the address of one character + past the last character we converted. */ + if (endptr != NULL) + *endptr = (char *) s; + +#if !UNSIGNED + /* Check for a value that is within the range of + `unsigned long int', but outside the range of `long int'. */ + if (overflow == 0 + && i > (negative + ? -((unsigned long) (LONG_MIN + 1)) + 1 + : (unsigned long) LONG_MAX)) + overflow = 1; +#endif + + if (overflow) + { + __set_errno (ERANGE); +#if UNSIGNED + return ULONG_MAX; +#else + return negative ? LONG_MIN : LONG_MAX; +#endif + } + + /* Return the result with the appropriate sign. */ + return (negative ? -i : i); + +noconv: + /* We must handle a special case here: the base is 0 or 16 and the + first two characters are '0' and 'x', but the rest are no + hexadecimal digits. This is no error case. We return 0 and + ENDPTR points to the `x'. */ + if (endptr != NULL) + { + if (save - nptr >= 2 && toupper (save[-1]) == 'X' && save[-2] == '0') + *endptr = (char *) &save[-1]; + else + /* There was no number to convert. */ + *endptr = (char *) nptr; + } + + return 0L; +} + +#endif /* !HAVE_STRTOL */ diff --git a/lib/sh/strtoul.c b/lib/sh/strtoul.c new file mode 100644 index 00000000..4a75d76e --- /dev/null +++ b/lib/sh/strtoul.c @@ -0,0 +1,26 @@ +/* Copyright (C) 1997 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software Foundation, +Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <config.h> + +#ifndef HAVE_STRTOUL + +#define UNSIGNED 1 +#undef HAVE_STRTOL + +#include <strtol.c> + +#endif /* !HAVE_STRTOUL */ diff --git a/vprint.c b/lib/sh/vprint.c index 431d6869..63ea3bf7 100644 --- a/vprint.c +++ b/lib/sh/vprint.c @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "config.h" +#include <config.h> #if defined (USE_VFPRINTF_EMULATION) diff --git a/lib/termcap/termcap.c b/lib/termcap/termcap.c index 2a270c45..eb690c9f 100644 --- a/lib/termcap/termcap.c +++ b/lib/termcap/termcap.c @@ -21,11 +21,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <config.h> /* Get the O_* definitions for open et al. */ +#ifndef _MINIX #include <sys/file.h> -#ifdef USG5 -#include <fcntl.h> #endif +#include <fcntl.h> + #else /* not HAVE_CONFIG_H */ #ifdef STDC_HEADERS @@ -777,4 +778,3 @@ tprint (cap) } #endif /* TEST */ - diff --git a/lib/tilde/tilde.c b/lib/tilde/tilde.c index fe263a26..3741f976 100644 --- a/lib/tilde/tilde.c +++ b/lib/tilde/tilde.c @@ -24,6 +24,9 @@ #endif #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -22,6 +22,9 @@ #include "config.h" #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -30,6 +33,7 @@ /* A global variable which acts as a sentinel for an `error' list return. */ GENERIC_LIST global_error_list; +#ifdef INCLUDE_UNUSED /* Call FUNCTION on every member of LIST, a generic list. */ void map_over_list (list, function) @@ -49,6 +53,7 @@ map_over_words (words, function) for ( ; words; words = words->next) (*function) (words->word->word); } +#endif /* INCLUDE_UNUSED */ /* Reverse the chain of structures in LIST. Output the new head of the chain. You should always assign the output value of this diff --git a/mailcheck.c b/mailcheck.c index d90e52f3..46a59213 100644 --- a/mailcheck.c +++ b/mailcheck.c @@ -23,7 +23,9 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include "bashtypes.h" #include "posixstat.h" -#include <sys/param.h> +#ifndef _MINIX +# include <sys/param.h> +#endif #if defined (HAVE_UNISTD_H) # include <unistd.h> #endif @@ -44,7 +46,7 @@ typedef struct { char *msg; time_t access_time; time_t mod_time; - long file_size; + off_t file_size; } FILEINFO; /* The list of remembered mail files. */ @@ -117,7 +119,7 @@ find_mail_file (file) do \ { \ mailfiles[i]->access_time = mailfiles[i]->mod_time = 0; \ - mailfiles[i]->file_size = 0L; \ + mailfiles[i]->file_size = 0; \ } \ while (0) @@ -157,7 +159,7 @@ add_mail_file (file, msg) { mailfiles[i]->mod_time = finfo.st_mtime; mailfiles[i]->access_time = finfo.st_atime; - mailfiles[i]->file_size = (long)finfo.st_size; + mailfiles[i]->file_size = finfo.st_size; } free (filename); return i; @@ -248,7 +250,7 @@ static int file_has_grown (i) int i; { - long size; + off_t size; struct stat finfo; char *file; @@ -291,6 +293,7 @@ make_default_mailpath () { char *mp; + get_current_user_info (); mp = xmalloc (2 + sizeof (DEFAULT_MAIL_DIRECTORY) + strlen (current_user.user_name)); strcpy (mp, DEFAULT_MAIL_DIRECTORY); mp[sizeof(DEFAULT_MAIL_DIRECTORY) - 1] = '/'; @@ -23,7 +23,9 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include "bashtypes.h" -#include <sys/file.h> +#ifndef _MINIX +# include <sys/file.h> +#endif #include "filecntl.h" #include "bashansi.h" #if defined (HAVE_UNISTD_H) @@ -100,7 +102,6 @@ make_word (string) return (make_word_flags (temp, string)); } -#ifdef INCLUDE_UNUSED WORD_DESC * make_word_from_token (token) int token; @@ -112,7 +113,6 @@ make_word_from_token (token) return (make_word (tokenizer)); } -#endif WORD_LIST * make_word_list (word, link) @@ -288,6 +288,72 @@ make_until_command (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 + 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; + + return (command); +#else + return ((COMMAND *)NULL); +#endif +} + +COMMAND * make_bare_simple_command () { COMMAND *command; @@ -516,7 +582,7 @@ make_function_def (name, command, lineno, lstart) temp->command = command; temp->name = name; temp->line = lineno; - temp->ignore = 0; + temp->flags = 0; command->line = lstart; return (make_command (cm_function_def, (SIMPLE_COM *)temp)); } @@ -46,8 +46,15 @@ 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 *)); +#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 *connect_async_list __P((COMMAND *, COMMAND *, int)); #endif /* !_MAKE_CMD_H */ @@ -355,8 +355,7 @@ make_child (command, async_p) 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)) + if (default_buffered_input != -1 && (!async_p || default_buffered_input > 0)) sync_buffered_stream (default_buffered_input); #endif /* BUFFERED_INPUT */ @@ -386,11 +385,7 @@ make_child (command, async_p) if (pid == 0) { #if defined (BUFFERED_INPUT) - if (default_buffered_input > 0) - { - close_buffered_fd (default_buffered_input); - default_buffered_input = bash_input.location.buffered_fd = -1; - } + unset_bash_input (0); #endif /* BUFFERED_INPUT */ #if defined (HAVE_POSIX_SIGNALS) @@ -64,9 +64,11 @@ #endif /* ALIAS */ #if defined (PROMPT_STRING_DECODE) -#include <sys/param.h> -#include <time.h> -#include "maxpath.h" +# ifndef _MINIX +# include <sys/param.h> +# endif +# include <time.h> +# include "maxpath.h" #endif /* PROMPT_STRING_DECODE */ #define RE_READ_TOKEN -99 @@ -74,6 +76,13 @@ #define YYDEBUG 0 +#if defined (EXTENDED_GLOB) +#define PATTERN_CHAR(c) \ + ((c) == '@' || (c) == '*' || (c) == '+' || (c) == '?' || (c) == '!') + +extern int extended_glob; +#endif + extern int eof_encountered; extern int no_line_editing, running_under_emacs; extern int current_command_number; @@ -85,7 +94,7 @@ extern int interrupt_immediately; extern char *shell_name, *current_host_name; extern char *dist_version; extern int patch_level; -extern int dump_translatable_strings; +extern int dump_translatable_strings, dump_po_strings; extern Function *last_shell_builtin, *this_shell_builtin; #if defined (BUFFERED_INPUT) extern int bash_input_fd_changed; @@ -103,6 +112,9 @@ static int reserved_word_acceptable (); static int read_token (); static int yylex (); static int parse_arith_cmd (); +#if defined (COND_COMMAND) +static COMMAND *parse_cond_command (); +#endif static int read_token_word (); static void discard_parser_constructs (); @@ -180,13 +192,17 @@ static REDIRECTEE redir; /* Reserved words. Members of the first group are only recognized in the case that they are preceded by a list_terminator. Members - of the second group are recognized only under special circumstances. */ + 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 IN BANG TIME TIMEOPT +%token COND_START COND_END COND_ERROR +%token IN BANG TIME TIMEOPT /* More general tokens. yylex () knows how to make these. */ %token <word> WORD ASSIGNMENT_WORD %token <number> NUMBER +%token <word_list> ARITH_CMD +%token <command> COND_CMD %token AND_AND OR_OR GREATER_GREATER LESS_LESS LESS_AND %token GREATER_AND SEMI_SEMI LESS_LESS_MINUS AND_GREATER LESS_GREATER %token GREATER_BAR @@ -197,6 +213,8 @@ static REDIRECTEE redir; %type <command> list list0 list1 compound_list simple_list simple_list1 %type <command> simple_command shell_command %type <command> for_command select_command case_command group_command +%type <command> arith_command +%type <command> cond_command %type <command> function_def if_command elif_clause subshell %type <redirect> redirection redirection_list %type <element> simple_command_element @@ -479,6 +497,10 @@ shell_command: for_command { $$ = $1; } | group_command { $$ = $1; } + | arith_command + { $$ = $1; } + | cond_command + { $$ = $1; } | function_def { $$ = $1; } ; @@ -559,6 +581,14 @@ group_command: '{' 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 @@ -747,6 +777,8 @@ timespec: TIME #define PST_SUBSHELL 0x020 /* ( ... ) subshell */ #define PST_CMDSUBST 0x040 /* $( ... ) command substitution */ #define PST_CASESTMT 0x080 /* parsing a case statement */ +#define PST_CONDCMD 0x100 /* parsing a [[...]] command */ +#define PST_CONDEXPR 0x200 /* parsing the guts of [[...]] */ /* Initial size to allocate for tokens, and the amount to grow them by. */ @@ -1084,6 +1116,11 @@ typedef struct 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 @@ -1098,10 +1135,8 @@ push_stream (reset_lineno) saver->bstream = (BUFFERED_STREAM *)NULL; /* If we have a buffered stream, clear out buffers[fd]. */ if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0) - { - saver->bstream = buffers[bash_input.location.buffered_fd]; - buffers[bash_input.location.buffered_fd] = (BUFFERED_STREAM *)NULL; - } + saver->bstream = set_buffered_stream (bash_input.location.buffered_fd, + (BUFFERED_STREAM *)NULL); #endif /* BUFFERED_INPUT */ saver->line = line_number; @@ -1147,7 +1182,7 @@ pop_stream () saver->bstream->b_fd = default_buffered_input; } } - buffers[bash_input.location.buffered_fd] = saver->bstream; + set_buffered_stream (bash_input.location.buffered_fd, saver->bstream); } #endif /* BUFFERED_INPUT */ @@ -1180,7 +1215,11 @@ stream_on_stack (type) * everything between a `;;' and the next `)' or `esac' */ -#if defined (ALIAS) +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + +#if !defined (ALIAS) +typedef void *alias_t; +#endif #define END_OF_ALIAS 0 @@ -1197,7 +1236,9 @@ 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; @@ -1224,12 +1265,16 @@ push_string (s, expand, ap) 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); @@ -1263,8 +1308,10 @@ pop_string () 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); } @@ -1278,14 +1325,17 @@ free_string_list () { t1 = t->next; FREE (t->saved_line); - t->expander->flags &= ~AL_BEINGEXPANDED; +#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 */ +#endif /* ALIAS || DPAREN_ARITHMETIC */ /* 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 @@ -1410,6 +1460,10 @@ STRING_INT_ALIST word_token_alist[] = { { "{", '{' }, { "}", '}' }, { "!", BANG }, +#if defined (COND_COMMAND) + { "[[", COND_START }, + { "]]", COND_END }, +#endif { (char *)NULL, 0} }; @@ -1457,16 +1511,16 @@ shell_getc (remove_quoted_newline) QUIT; -#if defined (ALIAS) +#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 */ +#else /* !ALIAS && !DPAREN_ARITHMETIC */ if (!shell_input_line || !shell_input_line[shell_input_line_index]) -#endif /* !ALIAS */ +#endif /* !ALIAS && !DPAREN_ARITHMETIC */ { line_number++; @@ -1617,7 +1671,7 @@ shell_getc (remove_quoted_newline) goto restart_read; } -#if defined (ALIAS) +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) /* If C is NULL, we have reached the end of the current input string. If pushed_string_list is non-empty, it's time to pop to the previous string because we have fully consumed the result of the last alias expansion. @@ -1639,7 +1693,7 @@ shell_getc (remove_quoted_newline) c = ' '; } } -#endif /* ALIAS */ +#endif /* ALIAS || DPAREN_ARITHMETIC */ if (!c && shell_input_line_terminator == EOF) return ((shell_input_line_index != 0) ? '\n' : EOF); @@ -1790,10 +1844,16 @@ static int open_brace_count; { \ if ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \ break; \ + if (word_token_alist[i].token == TIME) \ + 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) \ @@ -1847,6 +1907,27 @@ alias_expand_token (token) } #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 '&': + 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. @@ -1861,6 +1942,14 @@ alias_expand_token (token) before that was FUNCTION. `}' is recognized if there is an unclosed `{' prsent. + + `-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 @@ -1926,9 +2015,21 @@ special_case_tokens (token) return ('}'); } +#if defined (COMMAND_TIMING) /* Handle -p after `time'. */ if (last_read_token == TIME && token[0] == '-' && token[1] == 'p' && !token[2]) return (TIMEOPT); +#endif + +#if defined (COMMAND_TIMING) + if (STREQ (token, "time") && time_command_acceptable ()) + return (TIME); +#endif /* COMMAND_TIMING */ + +#if defined (COND_COMMAND) /* [[ */ + if ((parser_state & PST_CONDEXPR) && token[0] == ']' && token[1] == ']' && token[2] == '\0') + return (COND_END); +#endif return (-1); } @@ -1943,13 +2044,10 @@ reset_parser () parser_state = 0; -#if defined (ALIAS) +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) if (pushed_string_list) - { - free_string_list (); - pushed_string_list = (STRING_SAVER *)NULL; - } -#endif /* ALIAS */ + free_string_list (); +#endif /* ALIAS || DPAREN_ARITHMETIC */ if (shell_input_line) { @@ -1993,6 +2091,26 @@ read_token (command) 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) + { + if (EOF_Reached && cond_token != COND_ERROR) /* [[ */ + parser_error (cond_lineno, "unexpected EOF while looking for `]]'"); + else if (cond_token != COND_ERROR) + parser_error (cond_lineno, "syntax error in conditional expression"); + 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 () */ @@ -2080,17 +2198,17 @@ read_token (command) { int cmdtyp, sline; char *wval; + WORD_DESC *wd; sline = line_number; cmdtyp = parse_arith_cmd (&wval); if (cmdtyp == 1) /* arithmetic command */ { - word_desc_to_read = make_word (wval); - word_desc_to_read->flags = W_QUOTED; - token_to_read = WORD; - free (wval); - yylval.word = make_word ("let"); - return (WORD); + wd = make_word (wval); + wd->flags = W_QUOTED; + yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); + free (wval); /* make_word copies it */ + return (ARITH_CMD); } else if (cmdtyp == 0) /* nested subshell */ { @@ -2362,6 +2480,175 @@ parse_arith_cmd (ep) } #endif /* DPAREN_ARITHMETIC */ +#if defined (COND_COMMAND) +static COND_COM *cond_term (); +static COND_COM *cond_and (); +static COND_COM *cond_or (); +static COND_COM *cond_expr (); + +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 (interactive && (bash_input.type == st_stdin || bash_input.type == st_stream)) + 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; + + /* 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); /* ( */ + 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); + parser_error (line_number, "unexpected argument to conditional unary operator"); + COND_RETURN_ERROR (); + } + + (void)cond_skip_newlines (); + } + else /* 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; + else if (tok == '<' || tok == '>') + op = make_word_from_token (tok); + else if (tok == COND_END || tok == AND_AND || tok == OR_OR) + { + /* Special case. [[ x ]] is equivalent to [[ -n x ]], just like + the test command. Similarly for [[ x && expr ]] or + [[ x || expr ]] */ + op = make_word ("-n"); + term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL); + cond_token = tok; + return (term); + } + 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 + { + parser_error (line_number, "unexpected argument to conditional binary operator"); + dispose_cond_node (tleft); + dispose_word (op); + COND_RETURN_ERROR (); + } + + (void)cond_skip_newlines (); + } + 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 + static int read_token_word (character) int character; @@ -2458,6 +2745,34 @@ read_token_word (character) 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 (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_digits = 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 defined (PROCESS_SUBSTITUTION) @@ -2503,13 +2818,16 @@ read_token_word (character) /* This handles $'...' and $"..." new-style quoted strings. */ else if (character == '$' && (peek_char == '\'' || peek_char == '"')) { + int first_line; + + first_line = line_number; ttok = parse_matched_pair (peek_char, peek_char, peek_char, &ttoklen, 0); if (ttok == &matched_pair_error) return -1; if (peek_char == '\'') ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen); else - ttrans = localeexpand (ttok, 0, ttoklen - 1, &ttranslen); + ttrans = localeexpand (ttok, 0, ttoklen - 1, first_line, &ttranslen); free (ttok); RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 2, token_buffer_size, @@ -2701,9 +3019,9 @@ ansiexpand (string, start, end, lenp) by the caller. The length of the translated string is returned in LENP, if non-null. */ static char * -localeexpand (string, start, end, lenp) +localeexpand (string, start, end, lineno, lenp) char *string; - int start, end, *lenp; + int start, end, lineno, *lenp; { int len, tlen; char *temp, *t; @@ -2716,7 +3034,11 @@ localeexpand (string, start, end, lenp) /* If we're just dumping translatable strings, don't do anything. */ if (dump_translatable_strings) { - printf ("\"%s\"\n", temp); + if (dump_po_strings) + printf ("#: %s:%d\nmsgid \"%s\"\nmsgstr \"\"\n", + (bash_input.name ? bash_input.name : "stdin"), lineno, temp); + else + printf ("\"%s\"\n", temp); if (lenp) *lenp = tlen; return (temp); @@ -2849,6 +3171,8 @@ history_delimiting_chars () else return "; "; /* (...) subshell */ } + else if (token_before_that == WORD && two_tokens_ago == FUNCTION) + return " "; /* function def using `function name' without `()' */ for (i = 0; no_semi_successors[i]; i++) { @@ -3051,6 +3375,12 @@ decode_prompt_string (string) } goto add_string; + case 'r': + temp = xmalloc (2); + temp[0] = '\r'; + temp[1] = '\0'; + goto add_string; + case 'n': temp = xmalloc (3); temp[0] = no_line_editing ? '\n' : '\r'; diff --git a/parser-built b/parser-built index 2acc11ca..affe1206 100644 --- a/parser-built +++ b/parser-built @@ -21,25 +21,30 @@ typedef union { #define DO 269 #define DONE 270 #define FUNCTION 271 -#define IN 272 -#define BANG 273 -#define TIME 274 -#define TIMEOPT 275 -#define WORD 276 -#define ASSIGNMENT_WORD 277 -#define NUMBER 278 -#define AND_AND 279 -#define OR_OR 280 -#define GREATER_GREATER 281 -#define LESS_LESS 282 -#define LESS_AND 283 -#define GREATER_AND 284 -#define SEMI_SEMI 285 -#define LESS_LESS_MINUS 286 -#define AND_GREATER 287 -#define LESS_GREATER 288 -#define GREATER_BAR 289 -#define yacc_EOF 290 +#define COND_START 272 +#define COND_END 273 +#define COND_ERROR 274 +#define IN 275 +#define BANG 276 +#define TIME 277 +#define TIMEOPT 278 +#define WORD 279 +#define ASSIGNMENT_WORD 280 +#define NUMBER 281 +#define ARITH_CMD 282 +#define COND_CMD 283 +#define AND_AND 284 +#define OR_OR 285 +#define GREATER_GREATER 286 +#define LESS_LESS 287 +#define LESS_AND 288 +#define GREATER_AND 289 +#define SEMI_SEMI 290 +#define LESS_LESS_MINUS 291 +#define AND_GREATER 292 +#define LESS_GREATER 293 +#define GREATER_BAR 294 +#define yacc_EOF 295 extern YYSTYPE yylval; @@ -39,6 +39,9 @@ /* Control whether * matches .files in globbing. */ int glob_dot_filenames; +/* Control whether the extended globbing features are enabled. */ +int extended_glob = 0; + /* Return nonzero if STRING has any unquoted special globbing chars in it. */ int unquoted_glob_pattern_p (string) @@ -65,6 +68,13 @@ unquoted_glob_pattern_p (string) return (1); continue; + case '+': + case '@': + case '!': + if (*string == '(') /*)*/ + return (1); + continue; + case CTLESC: case '\\': if (*string++ == '\0') @@ -76,34 +86,42 @@ unquoted_glob_pattern_p (string) /* PATHNAME can contain characters prefixed by CTLESC; this indicates that the character is to be quoted. We quote it here in the style - that the glob library recognizes. If CONVERT_QUOTED_NULLS is non-zero, + 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, CONVERT_QUOTED_NULLS should be 0; if called when quote + 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), CONVERT_QUOTED_NULLS should - be 1. */ + 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, convert_quoted_nulls) +quote_string_for_globbing (pathname, qflags) char *pathname; - int convert_quoted_nulls; + int qflags; { char *temp; - register int i; + register int i, j; - temp = savestring (pathname); + temp = xmalloc (strlen (pathname) + 1); - if (convert_quoted_nulls && QUOTED_NULL (pathname)) + if ((qflags & QGLOB_CVTNULL) && QUOTED_NULL (pathname)) { temp[0] = '\0'; return temp; } - for (i = 0; temp[i]; i++) + for (i = j = 0; pathname[i]; i++) { - if (temp[i] == CTLESC) - temp[i++] = '\\'; + if (pathname[i] == CTLESC) + { + if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/') + continue; + temp[j++] = '\\'; + } + else + temp[j++] = pathname[i]; } + temp[j] = '\0'; return (temp); } @@ -126,6 +144,12 @@ quote_globbing_chars (string) case '\\': *t++ = '\\'; break; + case '+': + case '@': + case '!': + if (s[1] == '(') /*(*/ + *t++ = '\\'; + break; } *t++ = *s++; } @@ -144,7 +168,7 @@ shell_glob_filename (pathname) glob_t filenames; int glob_flags; - temp = quote_string_for_globbing (pathname, 0); + temp = quote_string_for_globbing (pathname, QGLOB_FILENAME); filenames.gl_offs = 0; @@ -159,7 +183,7 @@ shell_glob_filename (pathname) return ((char **)NULL); if (i == GLOB_NOMATCH) - filenames.gl_pathv[0] = (char *)NULL; + filenames.gl_pathv = (char **)NULL; return (filenames.gl_pathv); @@ -169,7 +193,7 @@ shell_glob_filename (pathname) noglob_dot_filenames = glob_dot_filenames == 0; - temp = quote_string_for_globbing (pathname, 0); + temp = quote_string_for_globbing (pathname, QGLOB_FILENAME); results = glob_filename (temp); free (temp); @@ -232,14 +256,16 @@ glob_name_is_acceptable (name) 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 (fnmatch (p->val, name, FNM_PATHNAME) != FNM_NOMATCH) + if (fnmatch (p->val, name, flags) != FNM_NOMATCH) return (0); } return (1); @@ -29,19 +29,33 @@ 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 */ + +#if defined (EXTENDED_GLOB) +/* Flags to OR with other flag args to fnmatch() to enabled the extended + pattern matching. */ +# define FNMATCH_EXTFLAG (extended_glob ? FNM_EXTMATCH : 0) +#else +# define FNMATCH_EXTFLAG 0 +#endif /* !EXTENDED_GLOB */ + extern int glob_dot_filenames; +extern int extended_glob; extern int unquoted_glob_pattern_p __P((char *)); -/* PATHNAME can contain characters prefixed by CTLESC;; this indicates +/* PATHNAME can contain characters prefixed by CTLESC; this indicates that the character is to be quoted. We quote it here in the style - that the glob library recognizes. If CONVERT_QUOTED_NULLS is non-zero, + 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, CONVERT_QUOTED_NULLS should be 0; if called when quote + 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), CONVERT_QUOTED_NULLS should - be 1. */ + 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((char *, int)); extern char *quote_globbing_chars __P((char *)); diff --git a/print_cmd.c b/print_cmd.c index 422d6d9d..44460e93 100644 --- a/print_cmd.c +++ b/print_cmd.c @@ -22,6 +22,9 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -74,6 +77,13 @@ static void print_until_command (); static void print_until_or_while (); static void print_if_command (); static void print_function_def (); +#if defined (DPAREN_ARITHMETIC) +static void print_arith_command (); +#endif +#if defined (COND_COMMAND) +static void print_cond_node (); +static void print_cond_command (); +#endif #define PRINTED_COMMAND_INITIAL_SIZE 64 #define PRINTED_COMMAND_GROW_SIZE 128 @@ -168,6 +178,18 @@ make_command_string_internal (command) print_if_command (command->value.If); break; +#if defined (DPAREN_ARITHMETIC) + case cm_arith: + print_arith_command (command->value.Arith); + 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; @@ -458,6 +480,124 @@ print_if_command (if_command) newline ("fi"); } +#if defined (DPAREN_ARITHMETIC) +static void +print_arith_command (arith_command) + ARITH_COM *arith_command; +{ + cprintf ("(( "); + command_print_word_list (arith_command->exp, " "); + cprintf (" ))"); +} + +#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 (cond->op->word); + cprintf (" "); + print_cond_node (cond->left); + } + else if (cond->type == COND_BINARY) + { + print_cond_node (cond->left); + cprintf (" "); + cprintf (cond->op->word); + cprintf (" "); + print_cond_node (cond->right); + } + else if (cond->type == COND_TERM) + { + cprintf (cond->op->word); /* need to add quoting here */ + } +} + +static void +print_cond_command (cond) + COND_COM *cond; +{ + cprintf ("[[ "); + print_cond_node (cond); + cprintf (" ]]"); +} + +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); +} + +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 */ + +/* 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; diff --git a/redir.c b/redir.c new file mode 100644 index 00000000..f01d4141 --- /dev/null +++ b/redir.c @@ -0,0 +1,828 @@ +/* redir.c -- Functions to perform input and output redirection. */ + +/* 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 1, or (at your option) + any later version. + + Bash is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with Bash; see the file COPYING. If not, write to the Free + Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + +#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) + #pragma alloca +#endif /* _AIX && RISC6000 && !__GNUC__ */ + +#include <stdio.h> +#include "bashtypes.h" +#ifndef _MINIX +# include <sys/file.h> +#endif +#include "filecntl.h" +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#include <errno.h> + +#if !defined (errno) +extern int errno; +#endif + +#include "bashansi.h" + +#include "memalloc.h" +#include "shell.h" +#include "flags.h" +#include "execute_cmd.h" +#include "redir.h" + +#if defined (BUFFERED_INPUT) +# include "input.h" +#endif + +extern int posixly_correct; +extern int interactive, interactive_shell; +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 (); +static void add_exec_redirect (); +static int add_undo_redirect (); +static int do_redirection_internal (); +static int expandable_redirection_filename (); + +/* 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; + + if (expandable_redirection_filename (temp)) + { + if (posixly_correct && !interactive_shell) + disallow_filename_globbing++; + filename = redirection_expand (temp->redirectee.filename); + if (posixly_correct && !interactive_shell) + disallow_filename_globbing--; + if (filename == 0) + filename = savestring (temp->redirectee.filename->word); + if (filename == 0) + { + filename = xmalloc (1); + filename[0] = '\0'; + } + } + else + filename = itos (temp->redirectee.dest); + + switch (error) + { + case AMBIGUOUS_REDIRECT: + internal_error ("%s: ambiguous redirect", filename); + break; + + case NOCLOBBER_REDIRECT: + internal_error ("%s: cannot overwrite existing file", filename); + break; + +#if defined (RESTRICTED_SHELL) + case RESTRICTED_REDIRECT: + internal_error ("%s: restricted: cannot redirect output", filename); + break; +#endif /* RESTRICTED_SHELL */ + + 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 (filename); +} + +/* Perform the redirections on LIST. If FOR_REAL, then actually make + input and output file descriptors, otherwise just do whatever is + neccessary for side effecting. INTERNAL says to remember how to + undo the redirections later, if non-zero. If SET_CLEXEC is non-zero, + file descriptors opened in do_redirection () have their close-on-exec + flag set. */ +int +do_redirections (list, for_real, internal, set_clexec) + REDIRECT *list; + int for_real, internal, set_clexec; +{ + int error; + REDIRECT *temp; + + if (internal) + { + 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, for_real, internal, set_clexec); + 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_input_output: + case r_output_force: + case r_duplicating_input_word: + case r_duplicating_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; + + tlist1 = make_word_list (copy_word (word), (WORD_LIST *)NULL); + tlist2 = expand_words_no_vars (tlist1); + dispose_words (tlist1); + + if (!tlist2 || tlist2->next) + { + /* We expanded to no words, or to more than a single word. + Dispose of the word list and return NULL. */ + if (tlist2) + dispose_words (tlist2); + return ((char *)NULL); + } + result = string_list (tlist2); /* XXX savestring (tlist2->word->word)? */ + dispose_words (tlist2); + return (result); +} + +/* 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); + } + } + fclose (fp); + dispose_words (tlist); + } + 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) + WORD_DESC *redirectee; +{ + char filename[24]; + int r, fd; + static int fnum = 0; + + do + { + /* Make the filename for the temp file. */ + sprintf (filename, "/tmp/t%d-%d-sh", (int)getpid (), fnum++); + + /* Make sure we open it exclusively. */ + fd = open (filename, O_TRUNC | O_WRONLY | O_CREAT | O_EXCL, 0600); + } + while (fd < 0 && errno == EEXIST); + + /* If we failed for some reason other than the file existing, abort */ + if (fd < 0) + return (fd); + + errno = r = 0; /* XXX */ + /* write_here_document returns 0 on success, errno on failure. */ + if (redirectee->word) + r = write_here_document (fd, redirectee); + + close (fd); + if (r) + { + unlink (filename); + errno = r; + return (-1); + } + + /* XXX - this is raceable */ + /* Make the document really temporary. Also make it the input. */ + fd = open (filename, O_RDONLY, 0600); + + if (fd < 0) + { + r = errno; + unlink (filename); + errno = r; + return -1; + } + + if (unlink (filename) < 0) + { + r = errno; + close (fd); + errno = r; + return (-1); + } + + 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, ri) + char *filename; + int flags; + 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, 0666); + return ((fd < 0 && errno == EEXIST) ? NOCLOBBER_REDIRECT : fd); + } + fd = open (filename, flags, 0666); + + /* 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); +} + +/* Do the specific redirection requested. Returns errno or one of the + special redirection errors (*_REDIRECT) in case of error, 0 on success. + If FOR_REAL is zero, then just do whatever is neccessary to produce the + appropriate side effects. REMEMBERING, if non-zero, says to remember + how to undo each redirection. If SET_CLEXEC is non-zero, then + we set all file descriptors > 2 that we open to be close-on-exec. */ +static int +do_redirection_internal (redirect, for_real, remembering, set_clexec) + REDIRECT *redirect; + int for_real, remembering, set_clexec; +{ + WORD_DESC *redirectee; + int redir_fd, fd, redirector, r; + 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 (ri == r_duplicating_input_word || ri == r_duplicating_output_word) + { + /* We have [N]>&WORD or [N]<&WORD. Expand WORD, then translate + the redirection into a new one and continue. */ + redirectee_word = redirection_expand (redirectee); + + if (redirectee_word == 0) + return (AMBIGUOUS_REDIRECT); + else if (redirectee_word[0] == '-' && redirectee_word[1] == '\0') + { + rd.dest = 0L; + new_redirect = make_redirection (redirector, r_close_this, rd); + } + else if (all_digits (redirectee_word)) + { + if (ri == r_duplicating_input_word) + { + rd.dest = atol (redirectee_word); + new_redirect = make_redirection (redirector, r_duplicating_input, rd); + } + else + { + rd.dest = atol (redirectee_word); + new_redirect = make_redirection (redirector, r_duplicating_output, rd); + } + } + else if (ri == r_duplicating_output_word && redirector == 1) + { + if (posixly_correct == 0) + { + rd.filename = make_bare_word (redirectee_word); + new_redirect = make_redirection (1, r_err_and_out, rd); + } + else + new_redirect = copy_redirect (redirect); + } + else + { + free (redirectee_word); + return (AMBIGUOUS_REDIRECT); + } + + free (redirectee_word); + + /* Set up the variables needed by the rest of the function from the + new redirection. */ + if (new_redirect->instruction == r_err_and_out) + { + char *alloca_hack; + + /* Copy the word without allocating any memory that must be + explicitly freed. */ + redirectee = (WORD_DESC *)alloca (sizeof (WORD_DESC)); + xbcopy ((char *)new_redirect->redirectee.filename, + (char *)redirectee, sizeof (WORD_DESC)); + + alloca_hack = (char *) + alloca (1 + strlen (new_redirect->redirectee.filename->word)); + redirectee->word = alloca_hack; + strcpy (redirectee->word, new_redirect->redirectee.filename->word); + } + else + /* It's guaranteed to be an integer, and shouldn't be freed. */ + redirectee = new_redirect->redirectee.filename; + + redir_fd = new_redirect->redirectee.dest; + redirector = new_redirect->redirector; + ri = new_redirect->instruction; + + /* Overwrite the flags element of the old redirect with the new value. */ + redirect->flags = new_redirect->flags; + dispose_redirects (new_redirect); + } + + switch (ri) + { + case r_output_direction: + case r_appending_to: + case r_input_direction: + case r_inputa_direction: + case r_err_and_out: /* command &>filename */ + case r_input_output: + case r_output_force: + if (posixly_correct && !interactive_shell) + disallow_filename_globbing++; + redirectee_word = redirection_expand (redirectee); + if (posixly_correct && !interactive_shell) + disallow_filename_globbing--; + + if (redirectee_word == 0) + return (AMBIGUOUS_REDIRECT); + +#if defined (RESTRICTED_SHELL) + if (restricted && (WRITE_REDIRECT (ri))) + { + free (redirectee_word); + return (RESTRICTED_REDIRECT); + } +#endif /* RESTRICTED_SHELL */ + + /* If we are in noclobber mode, you are not allowed to overwrite + existing files. Check before opening. */ + if (noclobber && OUTPUT_REDIRECT (ri)) + { + fd = noclobber_open (redirectee_word, redirect->flags, ri); + if (fd == NOCLOBBER_REDIRECT) + { + free (redirectee_word); + return (NOCLOBBER_REDIRECT); + } + } + else + { + fd = open (redirectee_word, redirect->flags, 0666); +#if defined (AFS) + if ((fd < 0) && (errno == EACCES)) + fd = open (redirectee_word, redirect->flags & ~O_CREAT, 0666); +#endif /* AFS */ + } + free (redirectee_word); + + if (fd < 0) + return (errno); + + if (for_real) + { + if (remembering) + /* Only setup to undo it if the thing to undo is active. */ + if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1)) + add_undo_redirect (redirector); + else + add_undo_close_redirect (redirector); + +#if defined (BUFFERED_INPUT) + check_bash_input (redirector); +#endif + + if ((fd != redirector) && (dup2 (fd, redirector) < 0)) + return (errno); + +#if defined (BUFFERED_INPUT) + /* Do not change the buffered stream for an implicit redirection + of /dev/null to fd 0 for asynchronous commands without job + control (r_inputa_direction). */ + if (ri == r_input_direction || ri == r_input_output) + duplicate_buffered_stream (fd, redirector); +#endif /* BUFFERED_INPUT */ + + /* + * If we're remembering, then this is the result of a while, for + * or until loop with a loop redirection, or a function/builtin + * executing in the parent shell with a redirection. In the + * function/builtin case, we want to set all file descriptors > 2 + * to be close-on-exec to duplicate the effect of the old + * for i = 3 to NOFILE close(i) loop. In the case of the loops, + * both sh and ksh leave the file descriptors open across execs. + * The Posix standard mentions only the exec builtin. + */ + if (set_clexec && (redirector > 2)) + SET_CLOSE_ON_EXEC (redirector); + } + + if (fd != redirector) + { +#if defined (BUFFERED_INPUT) + if (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) + { + if (for_real) + { + if (remembering) + add_undo_redirect (2); + if (dup2 (1, 2) < 0) + return (errno); + } + } + break; + + case r_reading_until: + case r_deblank_reading_until: + /* REDIRECTEE is a pointer to a WORD_DESC containing the text of + the new input. Place it in a temporary file. */ + if (redirectee) + { + fd = here_document_to_fd (redirectee); + + if (fd < 0) + { + heredoc_errno = errno; + return (HEREDOC_REDIRECT); + } + + if (for_real) + { + if (remembering) + /* Only setup to undo it if the thing to undo is active. */ + if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1)) + add_undo_redirect (redirector); + else + add_undo_close_redirect (redirector); + +#if defined (BUFFERED_INPUT) + check_bash_input (redirector); +#endif + if (fd != redirector && dup2 (fd, redirector) < 0) + { + r = errno; + close (fd); + return (r); + } + +#if defined (BUFFERED_INPUT) + duplicate_buffered_stream (fd, redirector); +#endif + + if (set_clexec && (redirector > 2)) + SET_CLOSE_ON_EXEC (redirector); + } + +#if defined (BUFFERED_INPUT) + close_buffered_fd (fd); +#else + close (fd); +#endif + } + break; + + case r_duplicating_input: + case r_duplicating_output: + if (for_real && (redir_fd != redirector)) + { + if (remembering) + /* Only setup to undo it if the thing to undo is active. */ + if (fcntl (redirector, F_GETFD, 0) != -1) + add_undo_redirect (redirector); + else + add_undo_close_redirect (redirector); + +#if defined (BUFFERED_INPUT) + check_bash_input (redirector); +#endif + /* This is correct. 2>&1 means dup2 (1, 2); */ + if (dup2 (redir_fd, redirector) < 0) + return (errno); + +#if defined (BUFFERED_INPUT) + if (ri == r_duplicating_input) + duplicate_buffered_stream (redir_fd, redirector); +#endif /* BUFFERED_INPUT */ + + /* First duplicate the close-on-exec state of redirectee. dup2 + leaves the flag unset on the new descriptor, which means it + stays open. Only set the close-on-exec bit for file descriptors + greater than 2 in any case, since 0-2 should always be open + unless closed by something like `exec 2<&-'. */ + /* if ((already_set || set_unconditionally) && (ok_to_set)) + set_it () */ + if (((fcntl (redir_fd, F_GETFD, 0) == 1) || set_clexec) && + (redirector > 2)) + SET_CLOSE_ON_EXEC (redirector); + } + break; + + case r_close_this: + if (for_real) + { + if (remembering && (fcntl (redirector, F_GETFD, 0) != -1)) + add_undo_redirect (redirector); + +#if defined (BUFFERED_INPUT) + check_bash_input (redirector); + close_buffered_fd (redirector); +#else /* !BUFFERED_INPUT */ + close (redirector); +#endif /* !BUFFERED_INPUT */ + } + break; + + case r_duplicating_input_word: + case r_duplicating_output_word: + break; + } + return (0); +} + +#define SHELL_FD_BASE 10 + +/* Remember the file descriptor associated with the slot FD, + on REDIRECTION_UNDO_LIST. Note that the list will be reversed + before it is executed. Any redirections that need to be undone + even if REDIRECTION_UNDO_LIST is discarded by the exec builtin + are also saved on EXEC_REDIRECTION_UNDO_LIST. */ +static int +add_undo_redirect (fd) + int fd; +{ + int new_fd, clexec_flag; + REDIRECT *new_redirect, *closer, *dummy_redirect; + + new_fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE); + + if (new_fd < 0) + { + sys_error ("redirection error"); + return (-1); + } + + clexec_flag = fcntl (fd, F_GETFD, 0); + + rd.dest = 0L; + closer = make_redirection (new_fd, r_close_this, rd); + dummy_redirect = copy_redirects (closer); + + rd.dest = (long)new_fd; + new_redirect = make_redirection (fd, r_duplicating_output, rd); + new_redirect->next = closer; + + closer->next = redirection_undo_list; + redirection_undo_list = new_redirect; + + /* Save redirections that need to be undone even if the undo list + is thrown away by the `exec' builtin. */ + add_exec_redirect (dummy_redirect); + + /* File descriptors used only for saving others should always be + marked close-on-exec. Unfortunately, we have to preserve the + close-on-exec state of the file descriptor we are saving, since + fcntl (F_DUPFD) sets the new file descriptor to remain open + across execs. If, however, the file descriptor whose state we + are saving is <= 2, we can just set the close-on-exec flag, + because file descriptors 0-2 should always be open-on-exec, + and the restore above in do_redirection() will take care of it. */ + if (clexec_flag || fd < 3) + SET_CLOSE_ON_EXEC (new_fd); + + return (0); +} + +/* Set up to close FD when we are finished with the current command + and its redirections. */ +static void +add_undo_close_redirect (fd) + int fd; +{ + REDIRECT *closer; + + rd.dest = 0L; + closer = make_redirection (fd, r_close_this, rd); + closer->next = redirection_undo_list; + redirection_undo_list = closer; +} + +static void +add_exec_redirect (dummy_redirect) + REDIRECT *dummy_redirect; +{ + dummy_redirect->next = exec_redirection_undo_list; + exec_redirection_undo_list = dummy_redirect; +} + +/* 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) + switch (rp->instruction) + { + case r_input_direction: + case r_inputa_direction: + case r_input_output: + case r_reading_until: + case r_deblank_reading_until: + n++; + break; + case r_duplicating_input: + case r_duplicating_input_word: + case r_close_this: + n += (rp->redirector == 0); + break; + case r_output_direction: + case r_appending_to: + case r_duplicating_output: + case r_err_and_out: + case r_output_force: + case r_duplicating_output_word: + break; + } + + return n; +} diff --git a/redir.h b/redir.h new file mode 100644 index 00000000..c0cdf73c --- /dev/null +++ b/redir.h @@ -0,0 +1,31 @@ +/* findcmd.h - functions from findcmd.c. */ + +/* 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (_REDIR_H_) +#define _REDIR_H_ + +#include "stdc.h" + +extern void redirection_error __P((REDIRECT *, int)); +extern int do_redirections __P((REDIRECT *, int, int, int)); +extern char *redirection_expand __P((WORD_DESC *)); +extern int stdin_redirs __P((REDIRECT *)); + +#endif /* _REDIR_H_ */ @@ -35,7 +35,9 @@ #include "config.h" #include "bashtypes.h" -#include <sys/file.h> +#ifndef _MINIX +# include <sys/file.h> +#endif #include "posixstat.h" #include "bashansi.h" #include <stdio.h> @@ -61,6 +63,7 @@ #include "input.h" #include "execute_cmd.h" +#include "findcmd.h" #if defined (HISTORY) # include "bashhist.h" @@ -86,6 +89,7 @@ extern int line_number; extern char *primary_prompt, *secondary_prompt; extern int expand_aliases; extern char *this_command_name; +extern int array_needs_making; /* Non-zero means that this shell has already been run; i.e. you should call shell_reinitialize () if you need to start afresh. */ @@ -119,6 +123,10 @@ int interactive = 0; /* Non-zero means that the shell was started as an interactive shell. */ int interactive_shell = 0; +/* Non-zero means to send a SIGHUP to all jobs when an interactive login + shell exits. */ +int hup_on_exit = 0; + /* Tells what state the shell was in when it started: 0 = non-interactive shell script 1 = interactive @@ -177,6 +185,8 @@ static int want_initial_help; /* --help option */ int no_line_editing = 0; /* Don't do fancy line editing. */ int posixly_correct = 0; /* Non-zero means posix.2 superset. */ int dump_translatable_strings; /* Dump strings in $"...", don't execute. */ +int dump_po_strings; /* Dump strings in $"..." in po format */ +int wordexp_only = 0; /* Do word expansion only */ /* Some long-winded argument names. These are obviously new. */ #define Int 1 @@ -188,6 +198,7 @@ struct { char **char_value; } long_args[] = { { "debug", Int, &debugging, (char **)0x0 }, + { "dump-po-strings", Int, &dump_po_strings, (char **)0x0 }, { "dump-strings", Int, &dump_translatable_strings, (char **)0x0 }, { "help", Int, &want_initial_help, (char **)0x0 }, { "login", Int, &make_login_shell, (char **)0x0 }, @@ -201,6 +212,7 @@ struct { #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 } }; @@ -231,6 +243,7 @@ static int bind_args (); static int open_shell_script (); static void set_bash_input (); static int run_one_command (); +static int run_wordexp (); static int uidget (); static int isnetconn (); @@ -242,6 +255,22 @@ static void shell_reinitialize (); static void show_shell_usage (); +#ifdef __CYGWIN32__ +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 /* __CYGWIN32__ */ + int main (argc, argv, env) int argc; @@ -259,6 +288,10 @@ main (argc, argv, env) check_dev_tty (); +#ifdef __CYGWIN32__ + _cygwin32_check_tmp (); +#endif + /* Wait forever if we are debugging a login shell. */ while (debugging_login_shell); @@ -339,6 +372,9 @@ main (argc, argv, env) this_command_name = shell_name; /* for error reporting */ arg_index = parse_shell_options (argv, arg_index, argc); + if (dump_po_strings) + dump_translatable_strings = 1; + if (dump_translatable_strings) read_but_dont_execute = 1; @@ -371,6 +407,7 @@ main (argc, argv, env) if (forced_interactive || /* -i flag */ (!local_pending_command && /* 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 */ @@ -480,13 +517,20 @@ main (argc, argv, env) } #if defined (RESTRICTED_SHELL) - /* Turn on the restrictions after parsing the startup files. This + /* 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; 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 (local_pending_command) { arg_index = bind_args (argv, arg_index, argc, 0); @@ -650,7 +694,7 @@ parse_shell_options (argv, arg_start, arg_end) o_option = argv[next_arg]; if (o_option == 0) { - list_minus_o_opts (-1); + list_minus_o_opts (-1, (on_or_off == '-') ? 0 : 1); break; } if (set_minus_o_option (on_or_off, o_option) != EXECUTION_SUCCESS) @@ -680,7 +724,7 @@ parse_shell_options (argv, arg_start, arg_end) } /* Exit the shell with status S. */ -int +void exit_shell (s) int s; { @@ -699,6 +743,11 @@ exit_shell (s) #endif /* HISTORY */ #if defined (JOB_CONTROL) + /* If the user has run `shopt -s huponexit', hangup all jobs when we exit + an interactive login shell. ksh does this unconditionally. */ + if (interactive_shell && login_shell && hup_on_exit) + hangup_all_jobs (); + /* If this shell is interactive, terminate all stopped jobs and restore the original terminal process group. */ end_job_control (); @@ -763,18 +812,67 @@ run_startup_files () #if defined (JOB_CONTROL) int old_job_control; #endif + int sourced_login, run_by_ssh; + SHELL_VAR *sshvar; - /* get the rshd case out of the way first. */ + /* get the rshd/sshd case out of the way first. */ if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 && - act_like_sh == 0 && local_pending_command && isnetconn (fileno (stdin))) + act_like_sh == 0 && local_pending_command) { + /* Find out if we were invoked by ssh. If so, set RUN_BY_SSH to 1. */ + sshvar = find_variable ("SSH_CLIENT"); + if (sshvar) + { + run_by_ssh = 1; + /* Now that we've tested the variable, we need to unexport it. */ + sshvar->attributes &= ~att_exported; + array_needs_making = 1; + } + else + run_by_ssh = 0; + + /* If we were run by sshd or we think we were run by rshd, execute + ~/.bashrc. */ + if (run_by_ssh || isnetconn (fileno (stdin))) + { #ifdef SYS_BASHRC - maybe_execute_file (SYS_BASHRC, 1); + maybe_execute_file (SYS_BASHRC, 1); #endif - maybe_execute_file (bashrc_file, 1); - return; + 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; + +#if defined (NON_INTERACTIVE_LOGIN_SHELLS) + if (login_shell) + { + /* 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; + } +#endif /* NON_INTERACTIVE_LOGIN_SHELLS */ + /* 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. @@ -787,30 +885,27 @@ run_startup_files () return; } -#if defined (JOB_CONTROL) - /* Startup files should be run without job control enabled. */ - old_job_control = set_job_control (0); -#endif - /* Interactive shell or `-su' shell. */ if (posixly_correct == 0) /* bash, sh */ { - /* We don't execute .bashrc for login shells. */ - if (login_shell) - no_rc++; + 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 (login_shell && no_profile == 0) - { - maybe_execute_file (SYS_PROFILE, 1); + /* 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); - } + 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) @@ -894,6 +989,75 @@ disable_priv_mode () current_user.egid = current_user.gid; } +static int +run_wordexp (words) + char *words; +{ + int code, nw, nb; + WORD_DESC *w; + WORD_LIST *wl, *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 EXITPROG: + return last_command_exit_value; + case DISCARD: + return last_command_exit_value = 1; + default: + programming_error ("run_wordexp: bad jump: code %d", code); + } + } + + /* 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; + 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. */ @@ -1110,6 +1274,31 @@ set_bash_input () #endif /* !BUFFERED_INPUT */ } +/* Close the current shell script input source and forget about it. This is + extern so execute_cmd.c:initialize_subshell() can call it. If CHECK_ZERO + is non-zero, we close default_buffered_input even if it's the standard + input (fd 0). */ +void +unset_bash_input (check_zero) + int check_zero; +{ +#if defined (BUFFERED_INPUT) + if ((check_zero && default_buffered_input >= 0) || + (check_zero == 0 && default_buffered_input > 0)) + { + close_buffered_fd (default_buffered_input); + default_buffered_input = bash_input.location.buffered_fd = -1; + } +#else /* !BUFFERED_INPUT */ + if (default_input) + { + fclose (default_input); + default_input = (FILE *)NULL; + } +#endif /* !BUFFERED_INPUT */ +} + + #if !defined (PROGRAM) # define PROGRAM "bash" #endif @@ -1201,8 +1390,13 @@ shell_initialize () char hostname[256]; /* Line buffer output for stderr and stdout. */ - setlinebuf (stderr); - setlinebuf (stdout); +#if defined (SunOS5) + if (shell_initialized == 0) +#endif + { + setlinebuf (stderr); + setlinebuf (stdout); + } /* Sort the array of shell builtins so that the binary search in find_shell_builtin () works correctly. */ @@ -1254,8 +1448,14 @@ shell_initialize () /* Initialize input streams to null. */ initialize_bash_input (); - /* Initialize the shell options. */ - initialize_shell_options (); + /* 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 @@ -1366,7 +1566,7 @@ isnetconn (fd) struct sockaddr sa; l = sizeof(sa); - rv = getpeername(0, &sa, &l); + rv = getpeername(fd, &sa, &l); /* Solaris 2.5 getpeername() returns EINVAL if the fd is not a socket. */ return ((rv < 0 && (errno == ENOTSOCK || errno == EINVAL)) ? 0 : 1); #else /* !HAVE_GETPEERNAME || SVR4_2 */ @@ -23,6 +23,9 @@ #include "bashtypes.h" #if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif # include <unistd.h> #endif @@ -229,10 +232,10 @@ initialize_terminating_signals () sigaction (XSIG (i), &oact, &act); set_signal_ignored (XSIG (i)); } -#if defined (SIGPROF) +#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 */ +#endif /* SIGPROF && !_MINIX */ } #else /* !HAVE_POSIX_SIGNALS */ @@ -247,8 +250,10 @@ initialize_terminating_signals () 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 */ diff --git a/stringlib.c b/stringlib.c index 71d4268a..3c541656 100644 --- a/stringlib.c +++ b/stringlib.c @@ -38,6 +38,16 @@ # define to_lower(c) (isupper(c) ? tolower(c) : (c)) #endif +#define ISOCTAL(c) ((c) >= '0' && (c) <= '7') +#define OCTVALUE(c) ((c) - '0') + +#ifndef isxdigit +# define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) +#endif + +#define HEXVALUE(c) \ + ((c) >= 'a' && (c) <= 'f' ? (c)-'a'+10 : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0') + /* Convert STRING by expanding the escape sequences specified by the ANSI C standard. If SAWC is non-null, recognize `\c' and use that as a string terminator. If we see \c, set *SAWC to 1 before @@ -47,7 +57,7 @@ ansicstr (string, len, sawc, rlen) char *string; int len, *sawc, *rlen; { - int c; + int c, temp; char *ret, *r, *s; if (string == 0 || *string == '\0') @@ -71,19 +81,26 @@ ansicstr (string, len, sawc, rlen) case 'v': c = (int) 0x0B; break; #endif case 'b': c = '\b'; break; - case 'e': c = '\033'; break; /* ESC -- non-ANSI */ - case 'E': c = '\033'; break; /* ESC -- non-ANSI */ + case 'e': case 'E': /* ESC -- non-ANSI */ + c = '\033'; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': - c -= '0'; - if (*s >= '0' && *s <= '7') - c = c * 8 + (*s++ - '0'); - if (*s >= '0' && *s <= '7') - c = c * 8 + (*s++ - '0'); + for (temp = 2, c -= '0'; ISOCTAL (*s) && temp--; s++) + c = (c * 8) + OCTVALUE (*s); + break; + case 'x': /* Hex digit -- non-ANSI */ + for (temp = 3, c = 0; isxdigit (*s) && temp--; s++) + c = (c * 16) + HEXVALUE (*s); + /* \x followed by non-hex digits is passed through unchanged */ + if (temp == 3) + { + *r++ = '\\'; + c = 'x'; + } break; case '\\': case '\'': @@ -114,6 +131,7 @@ ansicstr (string, len, sawc, rlen) /* */ /* **************************************************************** */ +#ifdef INCLUDE_UNUSED /* Find NAME in ARRAY. Return the index of NAME, or -1 if not present. ARRAY should be NULL terminated. */ int @@ -128,6 +146,7 @@ find_name_in_array (name, array) return (-1); } +#endif /* Return the length of ARRAY, a NULL terminated array of char *. */ int @@ -285,15 +304,16 @@ strsub (string, pat, rep, global) char *string, *pat, *rep; int global; { - int patlen, templen, tempsize, repl, i; + 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)) { - RESIZE_MALLOCED_BUFFER (temp, templen, patlen, tempsize, (patlen * 2)); + RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2)); for (r = rep; *r; ) temp[templen++] = *r++; @@ -50,18 +50,7 @@ #include "builtins/getopt.h" #include "builtins/common.h" -#if defined (READLINE) -# include "bashline.h" -# include <readline/readline.h> -#else -# include <tilde/tilde.h> -#endif - -#if defined (HISTORY) -# include "bashhist.h" -# include <readline/history.h> -#endif - +#include <tilde/tilde.h> #include <glob/fnmatch.h> #if !defined (errno) @@ -82,8 +71,11 @@ extern int errno; #define ST_BACKSL 0x01 #define ST_CTLESC 0x02 -/* How to quote character C. */ -static char *make_quoted_char (); +/* These defs make it easier to use the editor. */ +#define LBRACE '{' +#define RBRACE '}' +#define LPAREN '(' +#define RPAREN ')' /* Process ID of the last command executed within command substitution. */ pid_t last_command_subst_pid = NO_PID; @@ -93,13 +85,9 @@ extern int last_command_exit_value, interactive, interactive_shell; extern int subshell_environment, startup_state; extern int dollar_dollar_pid; extern int posixly_correct; -extern int eof_encountered, eof_encountered_limit, ignoreeof; extern char *this_command_name; extern struct fd_bitmap *current_fds_to_close; -#if defined (READLINE) -extern int no_line_editing; -extern int hostname_list_initialized; -#endif +extern int wordexp_only; extern void getopts_reset (); @@ -116,17 +104,25 @@ static int glob_argv_flags_size; static WORD_LIST expand_word_error, expand_word_fatal; static char expand_param_error, expand_param_fatal; +static char *make_quoted_char (); +static void remove_quoted_nulls (); +static char *param_expand (); +static char *maybe_expand_string (); +static WORD_LIST *call_expand_word_internal (); static WORD_LIST *expand_string_internal (); static WORD_LIST *expand_word_internal (), *expand_word_list_internal (); static WORD_LIST *expand_string_leave_quoted (); static WORD_LIST *expand_string_for_rhs (); static WORD_LIST *word_list_split (); static WORD_LIST *quote_list (), *dequote_list (); +static char *quote_escapes (); +static WORD_LIST *list_quote_escapes (); static int unquoted_substring (), unquoted_member (); static int do_assignment_internal (); static char *string_extract_verbatim (), *string_extract (); static char *string_extract_double_quoted (), *string_extract_single_quoted (); -static int skip_single_quoted (), skip_double_quoted (); +static char *string_list_dollar_at (), *string_list_dollar_star (); +static inline int skip_single_quoted (), skip_double_quoted (); static char *extract_delimited_string (); static char *extract_dollar_brace_string (); @@ -220,87 +216,136 @@ quoted_strchr (s, c, flags) return ((char *)NULL); } -/* Conventions: - - A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. - The parser passes CTLNUL as CTLESC CTLNUL. */ - -/* The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL. - This is necessary to make unquoted CTLESC and CTLNUL characters in the - data stream pass through properly. - Here we remove doubled CTLESC characters inside quoted strings before - quoting the entire string, so we do not double the number of CTLESC - characters. */ -static char * -remove_quoted_escapes (string) +/* Return 1 if CHARACTER appears in an unquoted portion of + STRING. Return 0 otherwise. */ +static int +unquoted_member (character, string) + int character; char *string; { - register char *s; - int docopy; - char *t, *t1; - - if (string == NULL) - return (string); + int sindex, c; - t1 = t = xmalloc (strlen (string) + 1); - for (docopy = 0, s = string; *s; s++, t1++) + for (sindex = 0; c = string[sindex]; ) { - if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL)) + if (c == character) + return (1); + + switch (c) { - s++; - docopy = 1; + default: + sindex++; + break; + + case '\\': + sindex++; + if (string[sindex]) + sindex++; + break; + + case '\'': + sindex = skip_single_quoted (string, ++sindex); + break; + + case '"': + sindex = skip_double_quoted (string, ++sindex); + break; } - *t1 = *s; } - *t1 = '\0'; - if (docopy) - strcpy (string, t); - free (t); - return (string); + return (0); } -/* Quote escape characters in string s, but no other characters. This is - used to protect CTLESC and CTLNUL in variable values from the rest of - the word expansion process after the variable is expanded. */ -static char * -quote_escapes (string) - char *string; +/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */ +static int +unquoted_substring (substr, string) + char *substr, *string; { - register char *s, *t; - char *result; + int sindex, c, sublen; - result = xmalloc ((strlen (string) * 2) + 1); - for (s = string, t = result; *s; ) + if (substr == 0 || *substr == '\0') + return (0); + + sublen = strlen (substr); + for (sindex = 0; c = string[sindex]; ) { - if (*s == CTLESC || *s == CTLNUL) - *t++ = CTLESC; - *t++ = *s++; + if (STREQN (string + sindex, substr, sublen)) + return (1); + + switch (c) + { + case '\\': + sindex++; + + if (string[sindex]) + sindex++; + break; + + case '\'': + sindex = skip_single_quoted (string, ++sindex); + break; + + case '"': + sindex = skip_double_quoted (string, ++sindex); + break; + + default: + sindex++; + break; + } } - *t = '\0'; - return (result); + return (0); } -#ifdef INCLUDE_UNUSED -static char * -dequote_escapes (string) - char *string; -{ - register char *s, *t; - char *result; +/* 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. */ - result = xmalloc (strlen (string) + 1); - for (s = string, t = result; *s; ) +/* 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) { - if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL)) + int srclen, n; + + srclen = STRLEN (source); + if (srclen >= (int)(*size - *indx)) { - s++; - if (*s == '\0') - break; + n = srclen + *indx; + n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE); + target = xrealloc (target, (*size = n)); } - *t++ = *s++; + + FASTCOPY (source, target + *indx, srclen); + *indx += srclen; + target[*indx] = '\0'; + + free (source); } - *t = '\0'; - return result; + 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) + int number, *indx, *size; + char *target; +{ + char *temp; + + temp = itos (number); + return (sub_append_string (temp, target, indx, size)); } #endif @@ -431,11 +476,11 @@ string_extract_double_quoted (string, sindex, stripdq) /* Pass everything between `$(' and the matching `)' or a quoted ${ ... } pair through according to the Posix.2 specification. */ - if (c == '$' && ((string[i + 1] == '(') || (string[i + 1] == '{'))) + if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) { si = i + 2; - if (string[i + 1] == '(') - ret = extract_delimited_string (string, &si, "$(", "(", ")"); + if (string[i + 1] == LPAREN) + ret = extract_delimited_string (string, &si, "$(", "(", ")"); /*)*/ else ret = extract_dollar_brace_string (string, &si, 1); @@ -513,10 +558,10 @@ skip_double_quoted (string, sind) backquote++; continue; } - else if (c == '$' && ((string[i + 1] == '(') || (string[i + 1] == '{'))) + else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE))) { si = i + 2; - if (string[i + 1] == '(') + if (string[i + 1] == LPAREN) ret = extract_delimited_string (string, &si, "$(", "(", ")"); else ret = extract_dollar_brace_string (string, &si, 0); @@ -642,7 +687,7 @@ extract_arithmetic_subst (string, sindex) #if defined (PROCESS_SUBSTITUTION) /* Extract the <( or >( construct in STRING, and return a new string. Start extracting at (SINDEX) as if we had just seen "<(". - Make (SINDEX) get the position of the matching ")". */ + Make (SINDEX) get the position of the matching ")". */ /*))*/ char * extract_process_subst (string, starter, sindex) char *string; @@ -783,19 +828,18 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer) i++; /* move past this character, which was not special. */ } - si = i - *sindex - len_closer + 1; - result = xmalloc (1 + si); - strncpy (result, string + *sindex, si); - result[si] = '\0'; - *sindex = i; - if (c == 0 && nesting_level) { report_error ("bad substitution: no `%s' in %s", closer, string); - free (result); jump_to_top_level (DISCARD); } + si = i - *sindex - len_closer + 1; + result = xmalloc (1 + si); + strncpy (result, string + *sindex, si); + result[si] = '\0'; + *sindex = i; + return (result); } @@ -828,27 +872,21 @@ extract_dollar_brace_string (string, sindex, quoted) continue; } - if (c == CTLESC) + /* CTLESCs and backslashes quote the next character. */ + if (c == CTLESC || c == '\\') { pass_character++; continue; } - /* Backslashes quote the next character. */ - if (c == '\\') - { - pass_character++; - continue; - } - - if (string[i] == '$' && string[i+1] == '{') + if (string[i] == '$' && string[i+1] == LBRACE) { nesting_level++; i++; continue; } - if (c == '}') + if (c == RBRACE) { nesting_level--; if (nesting_level == 0) @@ -867,36 +905,34 @@ extract_dollar_brace_string (string, sindex, quoted) continue; } - /* Pass the contents of new-style command substitutions through - verbatim. */ - if (string[i] == '$' && string[i+1] == '(') + /* 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, "$(", "(", ")"); + t = extract_delimited_string (string, &si, "$(", "(", ")"); /*)*/ i = si; free (t); continue; } - /* Pass the contents of single-quoted strings through verbatim. */ - if (c == '\'') + /* Pass the contents of single-quoted and double-quoted strings + through verbatim. */ + if (c == '\'' || c == '"') { si = i + 1; - i = skip_single_quoted (string, si); - /* skip_single_quoted leaves index one past close quote */ + i = (c == '\'') ? skip_single_quoted (string, si) + : skip_double_quoted (string, si); + /* skip_XXX_quoted leaves index one past close quote */ i--; continue; } + } - /* Pass embedded double-quoted strings through verbatim as well. */ - if (c == '"') - { - si = i + 1; - /* skip_double_quoted leaves index one past close quote */ - i = skip_double_quoted (string, si); - i--; - continue; - } + if (c == 0 && nesting_level) + { + report_error ("bad substitution: no ending `}' in %s", string); + jump_to_top_level (DISCARD); } l = i - *sindex; @@ -905,13 +941,6 @@ extract_dollar_brace_string (string, sindex, quoted) result[l] = '\0'; *sindex = i; - if (c == 0 && nesting_level) - { - report_error ("bad substitution: no ending `}' in %s", string); - free (result); - jump_to_top_level (DISCARD); - } - return (result); } @@ -931,6 +960,7 @@ de_backslash (string) } #if 0 +/*UNUSED*/ /* Replace instances of \! in a string with !. */ void unquote_bang (string) @@ -1051,6 +1081,12 @@ assignment_name (string) } #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. */ static char * @@ -1114,25 +1150,48 @@ string_list (list) expansion [of $*] appears within a double quoted string, it expands to a single field with the value of each parameter separated by the first character of the IFS variable, or by a <space> if IFS is unset." */ -char * +static char * string_list_dollar_star (list) WORD_LIST *list; { char *ifs, sep[2]; ifs = get_string_value ("IFS"); - if (ifs == 0) - sep[0] = ' '; - else if (*ifs == '\0') - sep[0] = '\0'; - else - sep[0] = *ifs; + sep[0] = (ifs == 0) ? ' ' : *ifs; sep[1] = '\0'; return (string_list_internal (list, sep)); } +/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + is non-zero, the $@ appears within double quotes, and we should quote + the list before converting it into a string. If IFS is unset, and the + word is not quoted, we just need to quote CTLESC and CTLNUL characters + in the words in the list, because the default value of $IFS is + <space><tab><newline>, 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. */ +static char * +string_list_dollar_at (list, quoted) + WORD_LIST *list; + int quoted; +{ + char *ifs, sep[2]; + WORD_LIST *tlist; + + ifs = get_string_value ("IFS"); + + sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs; + sep[1] = '\0'; + + tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0)) + ? quote_list (list) + : list_quote_escapes (list); + return (string_list_internal (tlist, sep)); +} + /* Return the list of words present in STRING. Separate the string into words at any of the characters found in SEPARATORS. If QUOTED is non-zero then word in the list will have its quoted flag set, otherwise @@ -1158,54 +1217,6 @@ string_list_dollar_star (list) /* BEWARE! list_string strips null arguments. Don't call it twice and expect to have "" preserved! */ -/* 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. */ -/* -#define remove_quoted_nulls(string) \ - do { if (QUOTED_NULL (string)) string[0] ='\0'; } while (0) -*/ -static void -remove_quoted_nulls (string) - char *string; -{ - char *nstr, *s, *p; - - nstr = savestring (string); - nstr[0] = '\0'; - for (p = nstr, s = string; *s; s++) - { - if (*s == CTLESC) - { - *p++ = *s++; /* CTLESC */ - if (*s == 0) - break; - *p++ = *s; /* quoted char */ - continue; - } - if (*s == CTLNUL) - continue; - *p++ = *s; - } - *p = '\0'; - strcpy (string, nstr); - free (nstr); -} - -/* Perform quoted null character removal on each element of LIST. - This modifies LIST. */ -void -word_list_remove_quoted_nulls (list) - WORD_LIST *list; -{ - register WORD_LIST *t; - - for (t = list; t; t = t->next) - remove_quoted_nulls (t->word->word); -} - /* This performs word splitting and quoted null character removal on STRING. */ #define issep(c) (member ((c), separators)) @@ -1267,7 +1278,11 @@ list_string (string, separators, quoted) /* If we have something, then add it regardless. However, perform quoted null character removal on the current word. */ remove_quoted_nulls (current_word); +#if 0 result = make_word_list (make_word (current_word), result); +#else + result = add_string_to_list (current_word, result); +#endif if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) result->word->flags |= W_QUOTED; } @@ -1381,7 +1396,6 @@ strip_trailing_ifs_whitespace (string, separators, saw_escape) return string; } -#if 0 #if defined (ARRAY_VARS) WORD_LIST * list_string_with_quotes (string) @@ -1419,7 +1433,11 @@ list_string_with_quotes (string) token = xmalloc (len + 1); strncpy (token, s + tokstart, len); token[len] = '\0'; +#if 0 list = make_word_list (make_word (token), list); +#else + list = add_string_to_list (token, list); +#endif free (token); while (spctabnl (s[i])) i++; @@ -1434,76 +1452,12 @@ list_string_with_quotes (string) return (REVERSE_LIST (list, WORD_LIST *)); } #endif /* ARRAY_VARS */ -#endif /* 0 */ - -#if defined (PROCESS_SUBSTITUTION) -#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC) -#else -#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC) -#endif - -/* If there are any characters in STRING that require full expansion, - then call FUNC to expand STRING; otherwise just perform quote - removal if necessary. This returns a new string. */ -static char * -maybe_expand_string (string, quoted, func) - char *string; - int quoted; - WORD_LIST *(*func)(); -{ - WORD_LIST *list; - int i, saw_quote; - char *ret; - - for (i = saw_quote = 0; string[i]; i++) - { - if (EXP_CHAR (string[i])) - break; - else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') - saw_quote = 1; - } - - if (string[i]) - { - list = (*func) (string, quoted); - if (list) - { - ret = string_list (list); - dispose_words (list); - } - else - ret = (char *)NULL; - } - else if (saw_quote && ((quoted & (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 (string, quoted, func) - char *string; - int quoted; - WORD_LIST *(*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); -} +/********************************************************/ +/* */ +/* Functions to perform assignment statements */ +/* */ +/********************************************************/ #if defined (ARRAY_VARS) SHELL_VAR * @@ -1568,7 +1522,7 @@ do_assignment_internal (string, expand) temp = name + offset + 1; #if defined (ARRAY_VARS) - if (expand && temp[0] == '(' && strchr (temp, ')')) + if (expand && temp[0] == LPAREN && strchr (temp, RPAREN)) { assign_list = ni = 1; value = extract_delimited_string (temp, &ni, "(", (char *)NULL, ")"); @@ -1652,59 +1606,11 @@ do_assignment_no_expand (string) return do_assignment_internal (string, 0); } -/* Most of the substitutions must be done in parallel. In order - to avoid using tons of unclear goto's, I have some functions - for manipulating malloc'ed strings. They all take INDX, a - pointer to an integer which is the offset into the string - where manipulation is taking place. They also take SIZE, a - pointer to an integer which is the current length of the - character array for this string. */ - -/* Append SOURCE to TARGET at INDEX. SIZE is the current amount - of space allocated to TARGET. SOURCE can be NULL, in which - case nothing happens. Gets rid of SOURCE by 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 = 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) - int number, *indx, *size; - char *target; -{ - char *temp; - - temp = itos (number); - return (sub_append_string (temp, target, indx, size)); -} -#endif +/*************************************************** + * * + * Functions to manage the positional parameters * + * * + ***************************************************/ /* Return the word list that corresponds to `$*'. */ WORD_LIST * @@ -1736,6 +1642,26 @@ number_of_args () return n; } +/* Return the value of a positional parameter. This handles values > 10. */ +char * +get_dollar_var_value (ind) + int 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. */ @@ -1752,11 +1678,180 @@ string_rest_of_args (dollar_star) return (string); } -/*************************************************** - * * - * Functions to Expand a 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. */ +static char * +pos_params (string, start, end, quoted) + char *string; + int start, end, quoted; +{ + WORD_LIST *save, *params, *h, *t; + char *ret; + int i; + + save = params = list_rest_of_args (); + if (save == 0) + return ((char *)NULL); + + for (i = 1; params && i < start; i++) + params = params->next; + if (params == 0) + return ((char *)NULL); + for (h = t = params; params && i < end; i++) + { + t = params; + params = params->next; + } + + t->next = (WORD_LIST *)NULL; + if (string[0] == '*') + ret = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (h) : string_list (h); + else + ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h); + t->next = params; + + dispose_words (save); + return (ret); +} + +/******************************************************************/ +/* */ +/* Functions to expand strings to strings or WORD_LISTs */ +/* */ +/******************************************************************/ + +#if defined (PROCESS_SUBSTITUTION) +#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC) +#else +#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC) +#endif + +/* If there are any characters in STRING that require full expansion, + then call FUNC to expand STRING; otherwise just perform quote + removal if necessary. This returns a new string. */ +static char * +maybe_expand_string (string, quoted, func) + char *string; + int quoted; + WORD_LIST *(*func)(); +{ + WORD_LIST *list; + int i, saw_quote; + char *ret; + + for (i = saw_quote = 0; string[i]; i++) + { + if (EXP_CHAR (string[i])) + break; + else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"') + saw_quote = 1; + } + + if (string[i]) + { + list = (*func) (string, quoted); + if (list) + { + ret = string_list (list); + dispose_words (list); + } + else + ret = (char *)NULL; + } + else if (saw_quote && ((quoted & (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 (string, quoted, func) + char *string; + int quoted; + WORD_LIST *(*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); +} + +#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 = xmalloc (strlen (string) + 1); + for (s = string; s && *s; ) + { + if (*s == '\\') + s++; + if (*s == 0) + break; + *r++ = *s++; + } + *r = '\0'; + return ret; +} + +/* This needs better error handling. */ +/* Expand W for use as an argument to a unary or binary operator in a + [[...]] expression. If SPECIAL is nonzero, this is the rhs argument + to the != or == operator, and should be treated as a pattern. In + this case, we quote the string specially for the globbing code. The + caller is responsible for removing the backslashes if the unquoted + words is needed later. */ +char * +cond_expand_word (w, special) + WORD_DESC *w; + int special; +{ + char *r, *p; + WORD_LIST *l; + + if (w->word == 0 || w->word[0] == '\0') + return ((char *)NULL); + + l = call_expand_word_internal (w, 0, (int *)0, (int *)0); + if (l) + { + if (special == 0) + { + dequote_list (l); + r = string_list (l); + } + else + { + p = string_list (l); + r = quote_string_for_globbing (p, QGLOB_CVTNULL); + free (p); + } + dispose_words (l); + } + else + r = (char *)NULL; + + return r; +} +#endif + /* Call expand_word_internal to expand W and handle error returns. A convenience function for functions that don't want to handle any errors or free any memory before aborting. */ @@ -1898,6 +1993,106 @@ expand_string (string, quoted) * * ***************************************************/ +/* Conventions: + + A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string. + The parser passes CTLNUL as CTLESC CTLNUL. */ + +/* The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL. + This is necessary to make unquoted CTLESC and CTLNUL characters in the + data stream pass through properly. + Here we remove doubled CTLESC characters inside quoted strings before + quoting the entire string, so we do not double the number of CTLESC + characters. */ +static char * +remove_quoted_escapes (string) + char *string; +{ + register char *s; + int docopy; + char *t, *t1; + + if (string == NULL) + return (string); + + t1 = t = xmalloc (strlen (string) + 1); + for (docopy = 0, s = string; *s; s++, t1++) + { + if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL)) + { + s++; + docopy = 1; + } + *t1 = *s; + } + *t1 = '\0'; + if (docopy) + strcpy (string, t); + free (t); + return (string); +} + +/* Quote escape characters in string s, but no other characters. This is + used to protect CTLESC and CTLNUL in variable values from the rest of + the word expansion process after the variable is expanded. */ +static char * +quote_escapes (string) + char *string; +{ + register char *s, *t; + char *result; + + result = xmalloc ((strlen (string) * 2) + 1); + for (s = string, t = result; *s; ) + { + if (*s == CTLESC || *s == CTLNUL) + *t++ = CTLESC; + *t++ = *s++; + } + *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; +} + +#ifdef INCLUDE_UNUSED +static char * +dequote_escapes (string) + char *string; +{ + register char *s, *t; + char *result; + + result = xmalloc (strlen (string) + 1); + for (s = string, t = result; *s; ) + { + if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL)) + { + s++; + if (*s == '\0') + break; + } + *t++ = *s++; + } + *t = '\0'; + return result; +} +#endif + static WORD_LIST * dequote_list (list) WORD_LIST *list; @@ -2022,9 +2217,57 @@ quote_list (list) return list; } +/* 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. */ +/* +#define remove_quoted_nulls(string) \ + do { if (QUOTED_NULL (string)) string[0] ='\0'; } while (0) +*/ +static void +remove_quoted_nulls (string) + char *string; +{ + char *nstr, *s, *p; + + nstr = savestring (string); + nstr[0] = '\0'; + for (p = nstr, s = string; *s; s++) + { + if (*s == CTLESC) + { + *p++ = *s++; /* CTLESC */ + if (*s == 0) + break; + *p++ = *s; /* quoted char */ + continue; + } + if (*s == CTLNUL) + continue; + *p++ = *s; + } + *p = '\0'; + strcpy (string, nstr); + free (nstr); +} + +/* Perform quoted null character removal on each element of LIST. + This modifies LIST. */ +void +word_list_remove_quoted_nulls (list) + WORD_LIST *list; +{ + register WORD_LIST *t; + + for (t = list; t; t = t->next) + remove_quoted_nulls (t->word->word); +} + /* **************************************************************** */ /* */ -/* Functions for Removing Patterns */ +/* Functions for Matching and Removing Patterns */ /* */ /* **************************************************************** */ @@ -2064,7 +2307,7 @@ remove_pattern (param, pattern, op) for (p = end; p >= param; p--) { c = *p; *p = '\0'; - if (fnmatch (pattern, param, 0) != FNM_NOMATCH) + if (fnmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) { *p = c; return (savestring (p)); @@ -2077,7 +2320,7 @@ remove_pattern (param, pattern, op) for (p = param; p <= end; p++) { c = *p; *p = '\0'; - if (fnmatch (pattern, param, 0) != FNM_NOMATCH) + if (fnmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH) { *p = c; return (savestring (p)); @@ -2089,7 +2332,7 @@ remove_pattern (param, pattern, op) case RP_LONG_RIGHT: /* remove longest match at end */ for (p = param; p <= end; p++) { - if (fnmatch (pattern, p, 0) != FNM_NOMATCH) + if (fnmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) { c = *p; *p = '\0'; ret = savestring (param); @@ -2102,7 +2345,7 @@ remove_pattern (param, pattern, op) case RP_SHORT_RIGHT: /* remove shortest match at end */ for (p = end; p >= param; p--) { - if (fnmatch (pattern, p, 0) != FNM_NOMATCH) + if (fnmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH) { c = *p; *p = '\0'; ret = savestring (param); @@ -2121,11 +2364,6 @@ static int match_pattern_char (pat, string) char *pat, *string; { -#if 0 - register char *np; - int neg; - char c1; -#endif char c; if (*string == 0) @@ -2138,31 +2376,15 @@ match_pattern_char (pat, string) case '\\': return (*string == *pat); case '?': - return (*string != '\0'); + return (*string == LPAREN ? 1 : (*string != '\0')); case '*': return (1); + case '+': + case '!': + case '@': + return (*string == LPAREN ? 1 : (*string == c)); case '[': -#if 0 - for (np = pat; *np != ']'; np++); - if (*np == 0) - return (*string == '['); - if (neg = (*pat == '!' || *pat == '^')) - pat++; - for ( ; (c1 = *pat++) != ']'; ) - { - if (c1 == '\\') - c1 = *pat++; - if (c1 == 0) - return (0); - if (*pat != '-' || pat[1] == '\0' || pat[1] == ']') - return (neg ? *string != c1 : *string == c1); - if (c1 <= *string && *string <= pat[1]) - return (1); - pat += 2; - } -#else return (*string != '\0'); -#endif } } @@ -2197,7 +2419,7 @@ match_pattern (string, pat, mtype, sp, ep) for (p1 = end; p1 >= p; p1--) { c = *p1; *p1 = '\0'; - if (fnmatch (pat, p, 0) == 0) + if (fnmatch (pat, p, FNMATCH_EXTFLAG) == 0) { *p1 = c; *sp = p; @@ -2216,7 +2438,7 @@ match_pattern (string, pat, mtype, sp, ep) for (p = end; p >= string; p--) { c = *p; *p = '\0'; - if (fnmatch (pat, string, 0) == 0) + if (fnmatch (pat, string, FNMATCH_EXTFLAG) == 0) { *p = c; *sp = string; @@ -2229,7 +2451,7 @@ match_pattern (string, pat, mtype, sp, ep) case MATCH_END: for (p = string; p <= end; p++) - if (fnmatch (pat, p, 0) == 0) + if (fnmatch (pat, p, FNMATCH_EXTFLAG) == 0) { *sp = p; *ep = end; @@ -2241,6 +2463,191 @@ match_pattern (string, pat, mtype, sp, ep) return (0); } +static int +getpatspec (c, value) + int c; + char *value; +{ + if (c == '#') + return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT); + else /* c == '%' */ + return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT); +} + +/* Posix.2 says that the WORD should be run through tilde expansion, + parameter expansion, command substitution and arithmetic expansion. + This leaves the result quoted, so quote_string_for_globbing () has + to be called to fix it up for fnmatch (). If QUOTED is non-zero, + it means that the entire expression was enclosed in double quotes. + This means that quoting characters in the pattern do not make any + special pattern characters quoted. For example, the `*' in the + following retains its special meaning: "${foo#'*'}". */ +static char * +getpattern (value, quoted, expandpat) + char *value; + int quoted, expandpat; +{ + char *pat, *tword; + WORD_LIST *l; + int i; + + tword = strchr (value, '~') ? bash_tilde_expand (value) : savestring (value); + + /* expand_string_internal () leaves WORD quoted and does not perform + word splitting. */ + if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword) + { + i = 0; + pat = string_extract_double_quoted (tword, &i, 1); + free (tword); + tword = pat; + } + + /* There is a problem here: how to handle single or double quotes in the + pattern string when the whole expression is between double quotes? */ +#if 0 + l = *tword ? expand_string_for_rhs (tword, quoted, (int *)NULL, (int *)NULL) +#else + l = *tword ? expand_string_for_rhs (tword, + (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_NOQUOTE : quoted, + (int *)NULL, (int *)NULL) +#endif + : (WORD_LIST *)0; + free (tword); + pat = string_list (l); + dispose_words (l); + if (pat) + { + tword = quote_string_for_globbing (pat, QGLOB_CVTNULL); + free (pat); + pat = tword; + } + return (pat); +} + +/* Handle removing a pattern from a string as a result of ${name%[%]value} + or ${name#[#]value}. */ +static char * +parameter_brace_remove_pattern (value, temp, c, quoted) + char *value, *temp; + int c, quoted; +{ + int patspec; + char *pattern, *tword; + + patspec = getpatspec (c, value); + if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) + value++; + + pattern = getpattern (value, quoted, 1); + + tword = remove_pattern (temp, pattern, patspec); + + FREE (pattern); + return (tword); +} + +static char * +list_remove_pattern (list, pattern, patspec, type, quoted) + WORD_LIST *list; + char *pattern; + int patspec, type, quoted; +{ + WORD_LIST *new, *l; + WORD_DESC *w; + char *tword; + + for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) + { + tword = remove_pattern (l->word->word, pattern, patspec); + w = make_bare_word (tword); + free (tword); + new = make_word_list (w, new); + } + + l = REVERSE_LIST (new, WORD_LIST *); + if (type == '*') + tword = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l); + else + tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l); + + dispose_words (l); + return (tword); +} + +static char * +parameter_list_remove_pattern (value, type, c, quoted) + char *value; + int type, c, quoted; +{ + int patspec; + char *pattern, *ret; + WORD_LIST *list; + + patspec = getpatspec (c, value); + if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) + value++; + + pattern = getpattern (value, quoted, 1); + + list = list_rest_of_args (); + ret = list_remove_pattern (list, pattern, patspec, type, quoted); + dispose_words (list); + FREE (pattern); + return (ret); +} + +#if defined (ARRAY_VARS) +static char * +array_remove_pattern (value, aspec, aval, c, quoted) + char *value, *aspec, *aval; /* AVAL == evaluated ASPEC */ + int c, quoted; +{ + SHELL_VAR *var; + int len, patspec; + char *ret, *t, *pattern; + WORD_LIST *l; + + var = array_variable_part (aspec, &t, &len); + if (var == 0) + return ((char *)NULL); + + patspec = getpatspec (c, value); + if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) + value++; + + pattern = getpattern (value, quoted, 1); + + if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') + { + if (array_p (var) == 0) + { + report_error ("%s: bad array subscript", aspec); + FREE (pattern); + return ((char *)NULL); + } + l = array_to_word_list (array_cell (var)); + if (l == 0) + return ((char *)NULL); + ret = list_remove_pattern (l, pattern, patspec, t[0], quoted); + dispose_words (l); + } + else + { + ret = remove_pattern (aval, pattern, patspec); + if (ret) + { + t = quote_escapes (ret); + free (ret); + ret = t; + } + } + + FREE (pattern); + return ret; +} +#endif /* ARRAY_VARS */ + /******************************************* * * * Functions to expand WORD_DESCs * @@ -2288,33 +2695,13 @@ expand_word_leave_quoted (word, quoted) return (call_expand_word_internal (word, quoted, (int *)NULL, (int *)NULL)); } -/* Return the value of a positional parameter. This handles values > 10. */ -char * -get_dollar_var_value (ind) - int 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); -} - #if defined (PROCESS_SUBSTITUTION) -/* **************************************************************** */ -/* */ -/* Hacking Process Substitution */ -/* */ -/* **************************************************************** */ +/*****************************************************************/ +/* */ +/* Hacking Process Substitution */ +/* */ +/*****************************************************************/ #if !defined (HAVE_DEV_FD) /* Named pipes must be removed explicitly with `unlink'. This keeps a list @@ -2484,7 +2871,7 @@ process_substitute (string, open_for_read_in_child) pid_t old_pipeline_pgrp; #endif - if (!string || !*string) + if (!string || !*string || wordexp_only) return ((char *)NULL); #if !defined (HAVE_DEV_FD) @@ -2626,6 +3013,12 @@ process_substitute (string, open_for_read_in_child) } #endif /* PROCESS_SUBSTITUTION */ +/***********************************/ +/* */ +/* Command Substitution */ +/* */ +/***********************************/ + static char * read_comsub (fd, quoted) int fd, quoted; @@ -2713,6 +3106,12 @@ command_substitute (string, quoted) if (!string || !*string || (string[0] == '\n' && !string[1])) return ((char *)NULL); + if (wordexp_only && read_but_dont_execute) + { + last_command_exit_value = 125; + jump_to_top_level (EXITPROG); + } + /* Pipe the output of executing STRING into the current shell. */ if (pipe (fildes) < 0) { @@ -2825,8 +3224,16 @@ command_substitute (string, quoted) kill (getpid (), SIGINT); /* wait_for gives the terminal back to shell_pgrp. If some other - process group should have it, give it away to that group here. */ - if (interactive && pipeline_pgrp != (pid_t)0) + 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) +#endif give_terminal_to (pipeline_pgrp); #endif /* JOB_CONTROL */ @@ -2840,208 +3247,9 @@ command_substitute (string, quoted) * * ********************************************************/ -static int -getpatspec (c, value) - int c; - char *value; -{ - if (c == '#') - return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT); - else /* c == '%' */ - return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT); -} - -/* Posix.2 says that the WORD should be run through tilde expansion, - parameter expansion, command substitution and arithmetic expansion. - This leaves the result quoted, so quote_string_for_globbing () has - to be called to fix it up for fnmatch (). If QUOTED is non-zero, - it means that the entire expression was enclosed in double quotes. - This means that quoting characters in the pattern do not make any - special pattern characters quoted. For example, the `*' in the - following retains its special meaning: "${foo#'*'}". */ -static char * -getpattern (value, quoted, expandpat) - char *value; - int quoted, expandpat; -{ - char *pat, *tword; - WORD_LIST *l; - int i; - - tword = strchr (value, '~') ? bash_tilde_expand (value) : savestring (value); - - /* expand_string_internal () leaves WORD quoted and does not perform - word splitting. */ - if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword) - { - i = 0; - pat = string_extract_double_quoted (tword, &i, 1); - free (tword); - tword = pat; - } - - /* There is a problem here: how to handle single or double quotes in the - pattern string when the whole expression is between double quotes? */ -#if 0 - l = *tword ? expand_string_for_rhs (tword, quoted, (int *)NULL, (int *)NULL) -#else - l = *tword ? expand_string_for_rhs (tword, - (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_NOQUOTE : quoted, - (int *)NULL, (int *)NULL) -#endif - : (WORD_LIST *)0; - free (tword); - pat = string_list (l); - dispose_words (l); - if (pat) - { - tword = quote_string_for_globbing (pat, 1); - free (pat); - pat = tword; - } - return (pat); -} - -/* Handle removing a pattern from a string as a result of ${name%[%]value} - or ${name#[#]value}. */ -static char * -parameter_brace_remove_pattern (value, temp, c, quoted) - char *value, *temp; - int c, quoted; -{ - int patspec; - char *pattern, *tword; - - patspec = getpatspec (c, value); - if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) - value++; - - pattern = getpattern (value, quoted, 1); - - tword = remove_pattern (temp, pattern, patspec); - - FREE (pattern); - return (tword); -} - -static char * -list_remove_pattern (list, pattern, patspec, type, quoted) - WORD_LIST *list; - char *pattern; - int patspec, type, quoted; -{ - WORD_LIST *new, *l; - WORD_DESC *w; - char *tword; - - for (new = (WORD_LIST *)NULL, l = list; l; l = l->next) - { - tword = remove_pattern (l->word->word, pattern, patspec); - w = make_bare_word (tword); - free (tword); - new = make_word_list (w, new); - } - - l = REVERSE_LIST (new, WORD_LIST *); - if (type == '*') - tword = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l); - else - tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l); - - dispose_words (l); - return (tword); -} - -static char * -parameter_list_remove_pattern (value, type, c, quoted) - char *value; - int type, c, quoted; -{ - int patspec; - char *pattern, *ret; - WORD_LIST *list; - - patspec = getpatspec (c, value); - if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) - value++; - - pattern = getpattern (value, quoted, 1); - - list = list_rest_of_args (); - ret = list_remove_pattern (list, pattern, patspec, type, quoted); - dispose_words (list); - FREE (pattern); - return (ret); -} +/* Utility functions to manage arrays and their contents for expansion */ #if defined (ARRAY_VARS) -static char * -array_remove_pattern (value, aspec, aval, c, quoted) - char *value, *aspec, *aval; /* AVAL == evaluated ASPEC */ - int c, quoted; -{ - SHELL_VAR *var; - int len, patspec; -#if 0 - int ind; -#endif - char *ret, *t, *pattern; - WORD_LIST *l; - - var = array_variable_part (aspec, &t, &len); - if (var == 0) - return ((char *)NULL); - - patspec = getpatspec (c, value); - if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) - value++; - - pattern = getpattern (value, quoted, 1); - - if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') - { - if (array_p (var) == 0) - { - report_error ("%s: bad array subscript", aspec); - FREE (pattern); - return ((char *)NULL); - } - l = array_to_word_list (array_cell (var)); - if (l == 0) - return ((char *)NULL); - ret = list_remove_pattern (l, pattern, patspec, t[0], quoted); - dispose_words (l); - } - else - { -#if 0 - ind = array_expand_index (t, len); - if (ind < 0) - { - report_error ("%s: bad array subscript", aspec); - FREE (pattern); - return ((char *)NULL); - } - if (array_p (var) == 0 && ind != 0) - return ((char *)NULL); - - t = array_p (var) ? array_reference (array_cell (var), ind) : value_cell (var); - ret = remove_pattern (t, pattern, patspec); -#else - ret = remove_pattern (aval, pattern, patspec); -#endif - if (ret) - { - t = quote_escapes (ret); - free (ret); - ret = t; - } - } - - FREE (pattern); - return ret; -} - int valid_array_reference (name) char *name; @@ -3129,8 +3337,8 @@ array_value_internal (s, quoted, allow_all) int quoted, allow_all; { int len, ind; - char *retval, *t; - WORD_LIST *l; + char *retval, *t, *temp; + WORD_LIST *l, *list; SHELL_VAR *var; var = array_variable_part (s, &t, &len); @@ -3149,10 +3357,21 @@ array_value_internal (s, quoted, allow_all) if (l == (WORD_LIST *)NULL) return ((char *) NULL); +#if 0 if (t[0] == '*') /* ${name[*]} */ retval = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l); else /* ${name[@]} */ retval = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l); +#else + 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); +#endif dispose_words (l); } @@ -3280,13 +3499,20 @@ parameter_brace_expand_word (name, var_is_special, quoted) } else if (var_is_special) /* ${@} */ { + int sindex; tt = xmalloc (2 + strlen (name)); - tt[0] = '$'; + tt[sindex = 0] = '$'; strcpy (tt + 1, name); +#if 0 l = expand_string_leave_quoted (tt, quoted); free (tt); temp = string_list (l); dispose_words (l); +#else + temp = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL, + (int *)NULL, (int *)NULL, 0); + free (tt); +#endif } #if defined (ARRAY_VARS) else if (valid_array_reference (name)) @@ -3306,6 +3532,9 @@ parameter_brace_expand_word (name, var_is_special, quoted) if (temp) temp = quote_escapes (temp); + + if (tempvar_p (var)) + dispose_variable (var); } else temp = (char *)NULL; @@ -3440,6 +3669,7 @@ valid_length_expression (name) { return (!name[1] || /* ${#} */ ((name[1] == '@' || name[1] == '*') && !name[2]) || /* ${#@}, ${#*} */ + (member (name[1], "-?$!#") && !name[2]) || /* ${#-}, etc. */ (digit (name[1]) && all_digits (name + 1)) || /* ${#11} */ #if defined (ARRAY_VARS) valid_array_reference (name + 1) || /* ${#a[7]} */ @@ -3462,11 +3692,40 @@ parameter_brace_expand_length (name) if (name[1] == '\0') /* ${#} */ number = number_of_args (); + else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0') /* ${#@}, ${#*} */ + number = number_of_args (); + else if (member (name[1], "-?$!#") && 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 ((int)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 if (name[1] != '*' && name[1] != '@') + else { number = 0; @@ -3497,15 +3756,13 @@ parameter_brace_expand_length (name) FREE (t); } } - else /* ${#@} and ${#*} */ - number = number_of_args (); return (number); } /* Verify and limit the start and end of the desired substring. If VTYPE == 0, a regular shell variable is being used; if it is 1, - then the positional paramters are being used; if it is 2, then + 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. */ @@ -3576,45 +3833,8 @@ verify_substring_values (value, substr, vtype, e1p, e2p) return (1); } -/* Return a string containing the positional parameters from START to - END, inclusive. If STRING[0] == '*', we obey the rules for $*, - which only makes a difference if QUOTED is non-zero. */ -static char * -pos_params (string, start, end, quoted) - char *string; - int start, end, quoted; -{ - WORD_LIST *save, *params, *h, *t; - char *ret; - int i; - - save = params = list_rest_of_args (); - if (save == 0) - return ((char *)NULL); - - for (i = 1; params && i < start; i++) - params = params->next; - if (params == 0) - return ((char *)NULL); - for (h = t = params; params && i < end; i++) - { - t = params; - params = params->next; - } - - t->next = (WORD_LIST *)NULL; - if (string[0] == '*') - ret = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (h) : string_list (h); - else - ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h); - t->next = params; - - dispose_words (save); - return (ret); -} - /* Return the type of variable specified by VARNAME (simple variable, - positional param, or array variable. Also return the value specified + positional param, or array variable). Also return the value specified by VARNAME (value of a variable or a reference to an array element). */ static int get_var_and_type (varname, value, varp, valp) @@ -3665,6 +3885,12 @@ get_var_and_type (varname, value, varp, valp) return vtype; } +/******************************************************/ +/* */ +/* Functions to extract substrings of variable values */ +/* */ +/******************************************************/ + /* 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. */ @@ -3714,6 +3940,12 @@ parameter_brace_substring (varname, value, substr, quoted) return temp; } +/****************************************************************/ +/* */ +/* Functions to perform pattern substitution on variable values */ +/* */ +/****************************************************************/ + char * pat_subst (string, pat, rep, mflags) char *string, *pat, *rep; @@ -3794,6 +4026,10 @@ pos_params_pat_subst (string, pat, rep, mflags) 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; @@ -3833,7 +4069,11 @@ parameter_brace_patsub (varname, value, patsub, quoted) /* Expand PAT and REP for command, variable and parameter, arithmetic, and process substitution. Also perform quote removal. Do not perform word splitting or filename generation. */ +#if 0 pat = maybe_expand_string (patsub, quoted, expand_string_unsplit); +#else + pat = maybe_expand_string (patsub, (quoted & ~Q_DOUBLE_QUOTES), expand_string_unsplit); +#endif if (rep) { if ((mflags & MATCH_QUOTED) == 0) @@ -3856,9 +4096,10 @@ parameter_brace_patsub (varname, value, patsub, quoted) else mflags |= MATCH_ANY; - /* OK, we now want to substitute REP for PAT in VAL. If GLOBAL is 1, - the substitution is done everywhere, otherwise only the first - occurrence of PAT is replaced. */ + /* 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. */ switch (vtype) { case VT_VARIABLE: @@ -3884,6 +4125,12 @@ parameter_brace_patsub (varname, value, patsub, quoted) return temp; } +/****************************************************************/ +/* */ +/* Functions to perform parameter expansion on a string */ +/* */ +/****************************************************************/ + /* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */ static char * parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at) @@ -3895,21 +4142,26 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll char *name, *value, *temp, *temp1; int t_index, sindex, c, number; - sindex = *indexp; - t_index = ++sindex; - name = string_extract (string, &t_index, "#%:-=?+/}", 1); value = (char *)NULL; var_is_set = var_is_null = var_is_special = check_nullness = 0; want_substring = want_indir = want_patsub = 0; - /* If the name really consists of a special variable, then - make sure that we have the entire name. Handle indirect - references to special variables here, too. */ - if ((sindex == t_index || - ((sindex == t_index - 1) && string[sindex] == '!')) && + sindex = *indexp; + t_index = ++sindex; + name = string_extract (string, &t_index, "#%:-=?+/}", 1); + + /* 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] == '#')) + 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); @@ -3918,11 +4170,11 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll *name = string[sindex]; if (string[sindex] == '!') { - /* indirect ref. of special variable */ - name[1] = string[sindex + 1]; - strcpy (name + 2, temp1); + /* indirect reference of $#, $?, $@, or $* */ + name[1] = string[sindex + 1]; + strcpy (name + 2, temp1); } - else + else strcpy (name + 1, temp1); free (temp1); } @@ -3943,69 +4195,55 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll if (c = string[sindex]) sindex++; } - else if (c == ':') + else if (c == ':' && string[sindex] != RBRACE) want_substring = 1; - else if (c == '/') + else if (c == '/' && string[sindex] != RBRACE) want_patsub = 1; - want_indir = *name == '!'; + /* 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 && + member (c, "-?#") && string[sindex] == RBRACE) + { + name = 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 (name[1]) || digit (name[1]) || member (name[1], "#?@*")); /* Determine the value of this variable. */ - /* Check for special variables, directly and indirectly - referenced. */ + /* Check for special variables, directly referenced. */ if ((digit (*name) && all_digits (name)) || (name[1] == '\0' && member (*name, "#-?$!@*")) || - (want_indir && name[2] == '\0' && member (name[1], "#-?$!@*"))) + (want_indir && name[2] == '\0' && member (name[1], "#?@*"))) var_is_special++; - /* Check for special expansion things. */ - if (*name == '#') /* length of a parameter */ + /* Check for special expansion things, like the length of a parameter */ + if (*name == '#' && name[1]) { - /* Take the lengths of some of the shell's special - parameters. */ - if (string[sindex] == '}' && name[1] == '\0' && - check_nullness == 0 && member (c, "-?$!#")) - { - free (name); - switch (c) - { - case '-': - temp1 = which_set_flags (); - break; - case '?': - temp1 = itos (last_command_exit_value); - break; - case '$': - temp1 = itos (dollar_dollar_pid); - break; - case '!': - if (last_asynchronous_pid == NO_PID) - temp1 = (char *)NULL; - else - temp1 = itos ((int)last_asynchronous_pid); - break; - case '#': - temp1 = itos (number_of_args ()); - break; - } - number = STRLEN (temp1); - FREE (temp1); - *indexp = ++sindex; /* { string[sindex] == '}' */ - return (itos (number)); - } - - /* Don't allow things like ${#:-foo} to go by; they are - errors. If we are not pointing at the character just - after the closing brace, then we haven't gotten all of - the name. Since it begins with a special character, - this is a bad substitution. Explicitly check for ${#:}, - which the rules do not catch. Also check NAME for - validity before trying to go on. */ - if (string[sindex - 1] != '}' || - member (c, "?-=+") || - (name[1] == '\0' && c == '}' && check_nullness) || - (valid_length_expression (name) == 0)) + /* 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; @@ -4042,7 +4280,11 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll temp = parameter_brace_expand_word (name, var_is_special, quoted); #if defined (ARRAY_VARS) +#if 0 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && valid_array_reference (name)) +#else + if (valid_array_reference (name)) +#endif { temp1 = strchr (name, '['); if (temp1 && temp1[1] == '@' && temp1[2] == ']') @@ -4051,6 +4293,13 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll *quoted_dollar_atp = 1; if (contains_dollar_at) *contains_dollar_at = 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; } } #endif @@ -4059,13 +4308,12 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll var_is_null = check_nullness && (var_is_set == 0 || *temp == 0); /* Get the rest of the stuff inside the braces. */ - if (c && c != '}') + if (c && c != RBRACE) { /* Extract the contents of the ${ ... } expansion according to the Posix.2 rules. */ value = extract_dollar_brace_string (string, &sindex, quoted); - /*{*/ - if (string[sindex] == '}') + if (string[sindex] == RBRACE) sindex++; else goto bad_substitution; @@ -4105,8 +4353,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll free (name); return &expand_param_error; - /*{*/ - case '}': + case RBRACE: if (var_is_set == 0 && unbound_vars_is_error) { report_error ("%s: unbound variable", name); @@ -4194,11 +4441,316 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll return (temp); } -/* Make a word list which is the parameter and variable expansion, - command substitution, arithmetic substitution, and quote removed - expansion of WORD. Return a pointer to a WORD_LIST which is the - result of the expansion. If WORD contains a null word, the word - list returned is also null. +/* Expand a single ${xxx} expansion. The braces are optional. When + the braces are used, parameter_brace_expand() does the work, + possibly calling param_expand recursively. */ +static char * +param_expand (string, sindex, quoted, expanded_something, + contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p, + pflags) + char *string; + int *sindex, quoted, *expanded_something, *contains_dollar_at; + int *quoted_dollar_at_p, *had_quoted_null_p, pflags; +{ + char *temp, *temp1; + int zindex, number, c, t_index, expok; + SHELL_VAR *var; + WORD_LIST *list, *tlist; + + zindex = *sindex; + c = string[++zindex]; + + temp = (char *)NULL; + + /* Do simple cases first. Switch on what follows '$'. */ + switch (c) + { + /* $0 .. $9? */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + temp1 = dollar_vars[digit_value (c)]; + if (unbound_vars_is_error && temp1 == (char *)NULL) + { + report_error ("$%c: unbound variable", c); + last_command_exit_value = EXECUTION_FAILURE; + return (interactive_shell ? &expand_param_error : &expand_param_fatal); + } + temp = temp1 ? savestring (temp1) : (char *)NULL; + break; + + /* $$ -- pid of the invoking shell. */ + case '$': + temp = itos (dollar_dollar_pid); + break; + + /* $# -- number of positional parameters. */ + case '#': + temp = itos (number_of_args ()); + break; + + /* $? -- return value of the last synchronous command. */ + case '?': + temp = itos (last_command_exit_value); + break; + + /* $- -- flags supplied to the shell on invocation or by `set'. */ + case '-': + temp = which_set_flags (); + break; + + /* $! -- Pid of the last asynchronous command. */ + case '!': + /* If no asynchronous pids have been created, expand to nothing. + If `set -u' has been executed, and no async processes have + been created, this is an expansion error. */ + if (last_asynchronous_pid == NO_PID) + { + if (expanded_something) + *expanded_something = 0; + temp = (char *)NULL; + if (unbound_vars_is_error) + { + report_error ("$%c: unbound variable", c); + last_command_exit_value = EXECUTION_FAILURE; + return (interactive_shell ? &expand_param_error : &expand_param_fatal); + } + } + else + temp = itos ((int)last_asynchronous_pid); + break; + + /* The only difference between this and $@ is when the arg is quoted. */ + case '*': /* `$*' */ + list = list_rest_of_args (); + + /* If there are no command-line arguments, this should just + disappear if there are other characters in the expansion, + even if it's quoted. */ + if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0) + temp = (char *)NULL; + else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) + { + /* If we have "$*" we want to make a string of the positional + parameters, separated by the first character of $IFS, and + quote the whole string, including the separators. If IFS + is unset, the parameters are separated by ' '; if $IFS is + null, the parameters are concatenated. */ + temp = string_list_dollar_star (list); + temp1 = quote_string (temp); + free (temp); + temp = temp1; + } + else + { + /* If the $* is not quoted it is identical to $@ */ + temp = string_list_dollar_at (list, quoted); + if (contains_dollar_at) + *contains_dollar_at = 1; + } + + dispose_words (list); + break; + + /* When we have "$@" what we want is "$1" "$2" "$3" ... This + means that we have to turn quoting off after we split into + the individually quoted arguments so that the final split + on the first character of $IFS is still done. */ + case '@': /* `$@' */ + list = list_rest_of_args (); + + /* We want to flag the fact that we saw this. We can't turn + off quoting entirely, because other characters in the + string might need it (consider "\"$@\""), but we need some + way to signal that the final split on the first character + of $IFS should be done, even though QUOTED is 1. */ + if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + *quoted_dollar_at_p = 1; + if (contains_dollar_at) + *contains_dollar_at = 1; + + /* We want to separate the positional parameters with the first + character of $IFS in case $IFS is something other than a space. + We also want to make sure that splitting is done no matter what -- + according to POSIX.2, this expands to a list of the positional + parameters no matter what IFS is set to. */ + temp = string_list_dollar_at (list, quoted); + + dispose_words (list); + break; + + case LBRACE: + temp = parameter_brace_expand (string, &zindex, quoted, + quoted_dollar_at_p, + contains_dollar_at); + if (temp == &expand_param_error || temp == &expand_param_fatal) + return (temp); + + /* XXX */ + /* quoted nulls should be removed if there is anything else + in the string. */ + /* Note that we saw the quoted null so we can add one back at + the end of this function if there are no other characters + in the string, discard TEMP, and go on. */ + if (temp && QUOTED_NULL (temp)) + { + if (had_quoted_null_p) + *had_quoted_null_p = 1; + free (temp); + temp = (char *)NULL; + } + + goto return0; + + /* Do command or arithmetic substitution. */ + case LPAREN: + /* We have to extract the contents of this paren substitution. */ + t_index = zindex + 1; + temp = extract_command_subst (string, &t_index); + zindex = t_index; + + /* For Posix.2-style `$(( ))' arithmetic substitution, + extract the expression and pass it to the evaluator. */ + if (temp && *temp == LPAREN) + { + char *temp2; + temp1 = temp + 1; + temp2 = savestring (temp1); + t_index = strlen (temp2) - 1; + + if (temp2[t_index] != RPAREN) + { + free (temp2); + goto comsub; + } + + /* Cut off ending `)' */ + temp2[t_index] = '\0'; + + /* Expand variables found inside the expression. */ + temp1 = maybe_expand_string (temp2, Q_DOUBLE_QUOTES, expand_string); + free (temp2); + +arithsub: + /* No error messages. */ + this_command_name = (char *)NULL; + number = evalexp (temp1, &expok); + free (temp); + free (temp1); + if (expok == 0) + { + if (interactive_shell == 0 && posixly_correct) + { + last_command_exit_value = EXECUTION_FAILURE; + return (&expand_param_fatal); + } + else + return (&expand_param_error); + } + temp = itos (number); + break; + } + +comsub: + temp1 = command_substitute (temp, quoted); + FREE (temp); + temp = temp1; + break; + + /* Do POSIX.2d9-style arithmetic substitution. This will probably go + away in a future bash release. */ + case '[': + /* We have to 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 = maybe_expand_string (temp, Q_DOUBLE_QUOTES, expand_string); + + goto arithsub; + + default: + /* Find the variable in VARIABLE_LIST. */ + temp = (char *)NULL; + + for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++) + ; + temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL; + + /* If this isn't a variable name, then just output the `$'. */ + if (temp1 == 0 || *temp1 == '\0') + { + FREE (temp1); + temp = 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 && value_cell (var)) + { +#if defined (ARRAY_VARS) + if (array_p (var)) + { + temp = array_reference (array_cell (var), 0); + if (temp) + temp = quote_escapes (temp); + } + else +#endif + temp = quote_escapes (value_cell (var)); + free (temp1); + if (tempvar_p (var)) /* XXX */ + { + dispose_variable (var); /* XXX */ + var = (SHELL_VAR *)NULL; + } + goto return0; + } + + temp = (char *)NULL; + + if (unbound_vars_is_error) + report_error ("%s: unbound variable", temp1); + else + { + free (temp1); + goto return0; + } + + free (temp1); + last_command_exit_value = EXECUTION_FAILURE; + return ((unbound_vars_is_error && interactive_shell == 0) + ? &expand_param_fatal + : &expand_param_error); + } + + if (string[zindex]) + zindex++; + +return0: + *sindex = zindex; + return (temp); +} + +/* Make a word list which is the result of parameter and variable + expansion, command substitution, arithmetic substitution, and + quote removal of WORD. Return a pointer to a WORD_LIST which is + the result of the expansion. If WORD contains a null word, the + word list returned is also null. QUOTED contains flag values defined in shell.h. @@ -4254,6 +4806,7 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) int quoted_state; int had_quoted_null; + int has_dollar_at; int expok; @@ -4263,8 +4816,7 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) istring = xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE); istring[istring_index = 0] = '\0'; - - quoted_dollar_at = had_quoted_null = 0; + quoted_dollar_at = had_quoted_null = has_dollar_at = 0; quoted_state = UNQUOTED; string = word->word; @@ -4292,25 +4844,33 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) temp[1] = c = string[++sindex]; temp[2] = '\0'; +dollar_add_string: if (string[sindex]) sindex++; - goto add_string; +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] != '(' || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct) + if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct) { sindex--; goto add_character; } else - t_index = sindex + 1; /* skip past both '<' and '(' */ + t_index = sindex + 1; /* skip past both '<' and LPAREN */ - temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); + temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/ sindex = t_index; /* If the process substitution specification is `<()', we want to @@ -4325,319 +4885,26 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) } #endif /* PROCESS_SUBSTITUTION */ - /* See about breaking this into a separate function: - char * - param_expand (string, sindex, quoted, expanded_something, - contains_dollar_at, quoted_dollar_at) - char *string; - int *sindex, quoted, *expanded_something, *contains_dollar_at; - int *quoted_dollar_at; - */ case '$': - if (expanded_something) *expanded_something = 1; - c = string[++sindex]; + has_dollar_at = 0; + temp = param_expand (string, &sindex, quoted, expanded_something, + &has_dollar_at, "ed_dollar_at, + &had_quoted_null, 0); - /* Do simple cases first. Switch on what follows '$'. */ - switch (c) + if (temp == &expand_param_error || temp == &expand_param_fatal) { - /* $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[digit_value (c)]; - if (unbound_vars_is_error && temp1 == (char *)NULL) - { - report_error ("$%c: unbound variable", c); - free (string); - free (istring); - last_command_exit_value = EXECUTION_FAILURE; - return (interactive_shell ? &expand_word_error : &expand_word_fatal); - } - temp = temp1 ? savestring (temp1) : (char *)NULL; - goto dollar_add_string; - - /* $$ -- pid of the invoking shell. */ - case '$': - number = dollar_dollar_pid; - - add_number: - temp = itos (number); - dollar_add_string: - if (string[sindex]) sindex++; - - /* Add TEMP to ISTRING. */ - add_string: - if (temp) - { - istring = sub_append_string - (temp, istring, &istring_index, &istring_size); - temp = (char *)0; - } - - break; - - /* $# -- number of positional parameters. */ - case '#': - number = number_of_args (); - goto add_number; - - /* $? -- return value of the last synchronous command. */ - case '?': - number = last_command_exit_value; - goto add_number; - - /* $- -- flags supplied to the shell on invocation or - by `set'. */ - case '-': - temp = which_set_flags (); - goto dollar_add_string; - - /* $! -- Pid of the last asynchronous command. */ - case '!': - number = (int)last_asynchronous_pid; - - /* If no asynchronous pids have been created, expand - to nothing. */ - if (number == (int)NO_PID) - { - if (string[sindex]) - sindex++; - if (expanded_something) - *expanded_something = 0; - break; - } - goto add_number; - - /* The only difference between this and $@ is when the - arg is quoted. */ - case '*': /* `$*' */ - temp = string_rest_of_args (quoted); - - /* If there are no command-line arguments, this should just - disappear if there are other characters in the expansion, - even if it's quoted. */ - if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && temp && *temp == '\0') - { - free (temp); - temp = (char *)NULL; - } - /* In the case of a quoted string, quote the entire arg-list. - "$1 $2 $3". Otherwise quote the special escape characters. */ - if (temp) - { - temp1 = temp; - temp = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - ? quote_string (temp) - : quote_escapes (temp); - free (temp1); - } - goto dollar_add_string; - - /* When we have "$@" what we want is "$1" "$2" "$3" ... This - means that we have to turn quoting off after we split into - the individually quoted arguments so that the final split - on the first character of $IFS is still done. */ - case '@': /* `$@' */ - list = list_rest_of_args (); - - /* We want to flag the fact that we saw this. We can't turn - off quoting entirely, because other characters in the - string might need it (consider "\"$@\""), but we need some - way to signal that the final split on the first character - of $IFS should be done, even though QUOTED is 1. */ - if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) - quoted_dollar_at = 1; - if (contains_dollar_at) - *contains_dollar_at = 1; - temp = string_list (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list) ? quote_list (list) : list); - /* If the expansion is not quoted, protect any special escape - characters in the expansion by quoting them. */ - if (temp && quoted == 0) - { - temp1 = temp; - temp = quote_escapes (temp); - free (temp1); - } - dispose_words (list); - goto dollar_add_string; - - case '{': /*}*/ - temp = parameter_brace_expand (string, &sindex, quoted, - "ed_dollar_at, - contains_dollar_at); - if (temp == &expand_param_error || temp == &expand_param_fatal) - { - free (string); - free (istring); - return (temp == &expand_param_error) ? &expand_word_error - : &expand_word_fatal; - } - /* XXX */ - /* quoted nulls should be removed if there is anything else - in the string. */ - /* Note that we saw the quoted null so we can add one back at - the end of this function if there are no other characters - in the string, discard TEMP, and go on. */ - if (temp && QUOTED_NULL (temp)) - { - had_quoted_null = 1; - free (temp); - break; - } - - goto add_string; - /* break; */ - - /* Do command or arithmetic substitution. */ - case '(': /*)*/ - /* We have to extract the contents of this paren substitution. */ - t_index = sindex + 1; - temp = extract_command_subst (string, &t_index); - sindex = t_index; - - /* For Posix.2-style `$(( ))' arithmetic substitution, - extract the expression and pass it to the evaluator. */ - if (temp && *temp == '(') - { - char *temp2; - temp1 = temp + 1; - temp2 = savestring (temp1); - t_index = strlen (temp2) - 1; - - if (temp2[t_index] != ')') - { - free (temp2); -#if 0 - report_error ("%s: bad arithmetic substitution", temp); - free (temp); - free (string); - free (istring); - return (&expand_word_error); -#else - goto comsub; -#endif - } - - /* Cut off ending `)' */ - temp2[t_index] = '\0'; - - /* Expand variables found inside the expression. */ - temp1 = maybe_expand_string (temp2, Q_DOUBLE_QUOTES, expand_string); - free (temp2); - - /* No error messages. */ - this_command_name = (char *)NULL; - number = evalexp (temp1, &expok); - free (temp); - free (temp1); - if (expok == 0) - { - free (string); - free (istring); - return (&expand_word_error); - } - goto add_number; - } - - comsub: - temp1 = command_substitute (temp, quoted); - FREE (temp); - temp = temp1; - goto dollar_add_string; - - /* Do straight arithmetic substitution. */ - case '[': - /* We have to extract the contents of this - arithmetic substitution. */ - t_index = sindex + 1; - temp = extract_arithmetic_subst (string, &t_index); - sindex = t_index; - - /* Do initial variable expansion. */ - temp1 = maybe_expand_string (temp, Q_DOUBLE_QUOTES, expand_string); - - /* No error messages. */ - this_command_name = (char *)NULL; - number = evalexp (temp1, &expok); - free (temp1); - free (temp); - if (expok == 0) - { - free (string); - free (istring); - return (&expand_word_error); - } - goto add_number; - - default: - /* Find the variable in VARIABLE_LIST. */ - temp = (char *)NULL; - - for (t_index = sindex; - (c = string[sindex]) && legal_variable_char (c); - sindex++); - temp1 = substring (string, t_index, sindex); - - /* If this isn't a variable name, then just output the `$'. */ - if (temp1 == 0 || *temp1 == '\0') - { - FREE (temp1); - temp = xmalloc (2); - temp[0] = '$'; - temp[1] = '\0'; - if (expanded_something) - *expanded_something = 0; - goto add_string; - } - - /* If the variable exists, return its value cell. */ - var = find_variable (temp1); - - if (var && invisible_p (var) == 0 && value_cell (var)) - { -#if defined (ARRAY_VARS) - if (array_p (var)) - { - temp = array_reference (array_cell (var), 0); - if (temp) - temp = quote_escapes (temp); - } - else -#endif - temp = quote_escapes (value_cell (var)); - free (temp1); - goto add_string; - } - - temp = (char *)NULL; - - if (unbound_vars_is_error) - report_error ("%s: unbound variable", temp1); - else - { - free (temp1); - goto add_string; - } - - free (temp1); free (string); - last_command_exit_value = EXECUTION_FAILURE; free (istring); - return ((unbound_vars_is_error && interactive_shell == 0) - ? &expand_word_fatal - : &expand_word_error); + return ((temp == &expand_param_error) ? &expand_word_error + : &expand_word_fatal); } - break; /* End case '$': */ + if (contains_dollar_at && has_dollar_at) + *contains_dollar_at = 1; + goto add_string; + break; case '`': /* Backquoted command substitution. */ { @@ -4698,13 +4965,12 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) if (temp && *temp) { - int dollar_at_flag; - tword = make_word (temp); /* XXX */ free (temp); temp = (char *)NULL; - list = expand_word_internal (tword, Q_DOUBLE_QUOTES, &dollar_at_flag, (int *)NULL); + has_dollar_at = 0; + list = expand_word_internal (tword, Q_DOUBLE_QUOTES, &has_dollar_at, (int *)NULL); if (list == &expand_word_error || list == &expand_word_fatal) { @@ -4722,7 +4988,7 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) /* "$@" (a double-quoted dollar-at) expands into nothing, not even a NULL word, when there are no positional parameters. */ - if (list == 0 && dollar_at_flag) + if (list == 0 && has_dollar_at) { quoted_dollar_at++; break; @@ -4739,7 +5005,7 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) if (list) dequote_list (list); - if (dollar_at_flag) + if (has_dollar_at) { quoted_dollar_at++; if (contains_dollar_at) @@ -4775,6 +5041,18 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) { temp = savestring (list->word->word); dispose_words (list); +#if 1 + /* If the string is not a quoted null string, we want + to remove any embedded unquoted CTLNUL characters. + We do not want to turn quoted null strings back into + the empty string, though. We do this because we + want to remove any quoted nulls from expansions that + contain other characters. For example, if we have + x"$*"y or "x$*y" and there are no positional parameters, + the $* should expand into nothing. */ + if (QUOTED_NULL (temp) == 0) + remove_quoted_nulls (temp); /* XXX */ +#endif } } else @@ -4783,10 +5061,7 @@ expand_word_internal (word, quoted, contains_dollar_at, expanded_something) /* We do not want to add quoted nulls to strings that are only partially quoted; we can throw them away. */ if (temp == 0 && quoted_state == PARTIALLY_QUOTED) - { - FREE (temp); - continue; - } + continue; add_quoted_string: @@ -4921,7 +5196,7 @@ finished_with_string: { char *ifs_chars; - if (quoted_dollar_at) + if (quoted_dollar_at || has_dollar_at) { var = find_variable ("IFS"); ifs_chars = var ? value_cell (var) : " \t\n"; @@ -4929,12 +5204,14 @@ finished_with_string: else ifs_chars = (char *)NULL; - /* According to Posix.2, "$@" expands to a single word if - IFS="" and the positional parameters are not empty. */ - if (quoted_dollar_at && ifs_chars && *ifs_chars) - { - list = list_string (istring, " ", 1); - } + /* 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); @@ -5051,85 +5328,6 @@ word_list_quote_removal (list, quoted) } #endif -/* Return 1 if CHARACTER appears in an unquoted portion of - STRING. Return 0 otherwise. */ -static int -unquoted_member (character, string) - int character; - char *string; -{ - int sindex, c; - - for (sindex = 0; c = string[sindex]; ) - { - if (c == character) - return (1); - - switch (c) - { - default: - sindex++; - break; - - case '\\': - sindex++; - if (string[sindex]) - sindex++; - break; - - case '\'': - sindex = skip_single_quoted (string, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, ++sindex); - break; - } - } - return (0); -} - -/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */ -static int -unquoted_substring (substr, string) - char *substr, *string; -{ - int sindex, c, sublen; - - if (substr == 0 || *substr == '\0') - return (0); - - sublen = strlen (substr); - for (sindex = 0; c = string[sindex]; ) - { - if (STREQN (string + sindex, substr, sublen)) - return (1); - - switch (c) - { - case '\\': - sindex++; - - if (string[sindex]) - sindex++; - break; - - case '\'': - sindex = skip_single_quoted (string, ++sindex); - break; - - case '"': - sindex = skip_double_quoted (string, ++sindex); - break; - - default: - sindex++; - break; - } - } - return (0); -} - /******************************************* * * * Functions to perform word splitting * @@ -5157,6 +5355,9 @@ word_split (w) ifs_chars = ""; result = list_string (w->word, ifs_chars, w->flags & W_QUOTED); + + if (ifs && tempvar_p (ifs)) /* XXX */ + dispose_variable (ifs); /* XXX */ } else result = (WORD_LIST *)NULL; @@ -5182,10 +5383,15 @@ word_list_split (list) /************************************************** * * - * Functions to expand an entire WORD_LIST * + * Functions to expand an entire WORD_LIST * * * **************************************************/ +/* 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) + static WORD_LIST *varlist = (WORD_LIST *)NULL; /* Separate out any initial variable assignments from TLIST. If set -k has @@ -5277,6 +5483,25 @@ separate_out_assignments (tlist) 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. */ @@ -5285,7 +5510,7 @@ WORD_LIST * expand_words (list) WORD_LIST *list; { - return (expand_word_list_internal (list, 1)); + return (expand_word_list_internal (list, WEXP_ALL)); } /* Same as expand_words (), but doesn't hack variable or environment @@ -5294,126 +5519,189 @@ WORD_LIST * expand_words_no_vars (list) WORD_LIST *list; { - return (expand_word_list_internal (list, 0)); + return (expand_word_list_internal (list, WEXP_NOVARS)); } -/* The workhorse for expand_words () and expand_words_no_vars (). - First arg is LIST, a WORD_LIST of words. - Second arg DO_VARS is non-zero if you want to do environment and - variable assignments, else zero. - - This does all of the substitutions: brace expansion, tilde expansion, - parameter expansion, command substitution, arithmetic expansion, - process substitution, word splitting, and pathname expansion. Words - with the W_QUOTED or W_NOSPLIT bits set, or for which no expansion - is done, do not undergo word splitting. Words with the W_ASSIGNMENT - bit set do not undergo pathname expansion. */ -static WORD_LIST * -expand_word_list_internal (list, do_vars) +WORD_LIST * +expand_words_shellexp (list) WORD_LIST *list; - int do_vars; { - WORD_LIST *tlist, *new_list, *next, *temp_list, *orig_list, *disposables; - char *temp_string; - int tint; + return (expand_word_list_internal (list, WEXP_SHELLEXP)); +} - if (list == 0) - return ((WORD_LIST *)NULL); +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; - tlist = copy_word_list (list); + 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 (do_vars) - { - tlist = separate_out_assignments (tlist); - if (tlist == 0) + /* If the word isn't an assignment and contains an unquoted + pattern matching character, then glob it. */ + if ((tlist->word->flags & W_ASSIGNMENT) == 0 && + unquoted_glob_pattern_p (tlist->word->word)) { - if (varlist) + glob_array = shell_glob_filename (tlist->word->word); + + /* Handle error cases. + I don't think we should report errors like "No such file + or directory". However, I would like to report errors + like "Read failed". */ + + if (GLOB_FAILED (glob_array)) { - /* All the words were variable assignments, so they are placed - into the shell's environment. */ - for (new_list = varlist; new_list; new_list = new_list->next) - { - this_command_name = (char *)NULL; /* no arithmetic errors */ - tint = do_assignment (new_list->word->word); - /* Variable assignment errors in non-interactive shells - running in Posix.2 mode cause the shell to exit. */ - if (tint == 0 && interactive_shell == 0 && posixly_correct) - { - last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (FORCE_EOF); - } - } - dispose_words (varlist); - varlist = (WORD_LIST *)NULL; + 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 (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); } - return ((WORD_LIST *)NULL); } + 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); + } + + free_array (glob_array); + glob_array = (char **)NULL; + + tlist = next; } - /* Begin expanding the words that remain. The expansions take place on - things that aren't really variable assignments. */ + if (disposables) + dispose_words (disposables); + + if (output_list) + output_list = REVERSE_LIST (output_list, WORD_LIST *); + + return (output_list); +} #if defined (BRACE_EXPANSION) - /* Do brace expansion on this word if there are any brace characters - in the string. */ - if (brace_expansion && tlist) +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) { - register char **expansions; - WORD_LIST *braces; - WORD_DESC *w; - int eindex; + next = tlist->next; - for (braces = disposables = (WORD_LIST *)NULL; tlist; tlist = next) + /* Only do brace expansion if the word has a brace character. If + not, just add the word list element to BRACES and continue. In + the common case, at least when running shell scripts, this will + degenerate to a bunch of calls to `strchr', and then what is + basically a reversal of TLIST into BRACES, which is corrected + by a call to reverse_list () on BRACES when the end of TLIST + is reached. */ + if (strchr (tlist->word->word, LBRACE)) { - next = tlist->next; - - /* Only do brace expansion if the word has a brace character. If - not, just add the word list element to BRACES and continue. In - the common case, at least when running shell scripts, this will - degenerate to a bunch of calls to `strchr', and then what is - basically a reversal of TLIST into BRACES, which is corrected - by a call to reverse_list () on BRACES when the end of TLIST - is reached. */ - if (strchr (tlist->word->word, '{')) - { - expansions = brace_expand (tlist->word->word); - - for (eindex = 0; 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; - braces = make_word_list (w, braces); - free (expansions[eindex]); - } - free (expansions); + expansions = brace_expand (tlist->word->word); - /* Add TLIST to the list of words to be freed after brace - expansion has been performed. */ - tlist->next = disposables; - disposables = tlist; - } - else + for (eindex = 0; temp_string = expansions[eindex]; eindex++) { - tlist->next = braces; - braces = tlist; + 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); - dispose_words (disposables); - tlist = REVERSE_LIST (braces, WORD_LIST *); + /* 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); } -#endif /* BRACE_EXPANSION */ + + 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. */ - for (orig_list = tlist, new_list = (WORD_LIST *)NULL; tlist; tlist = next) + new_list = (WORD_LIST *)NULL; + for (orig_list = tlist; tlist; tlist = next) { - WORD_LIST *expanded; - int expanded_something, has_dollar_at; - temp_string = tlist->word->word; next = tlist->next; @@ -5470,139 +5758,99 @@ expand_word_list_internal (list, do_vars) temp_list = expanded; } - /* In the most common cases, t will be a list containing only one - element, so the call to reverse_list would be wasted. */ expanded = REVERSE_LIST (temp_list, WORD_LIST *); new_list = (WORD_LIST *)list_append (expanded, new_list); } - new_list = REVERSE_LIST (new_list, WORD_LIST *); + if (orig_list) + dispose_words (orig_list); - dispose_words (orig_list); - - /* Okay, we're almost done. Now let's just do some filename - globbing. */ if (new_list) - { - char **glob_array; - register int glob_index; - WORD_LIST *glob_list; - WORD_DESC *tword; + new_list = REVERSE_LIST (new_list, WORD_LIST *); - orig_list = disposables = (WORD_LIST *)NULL; - tlist = new_list; - - /* orig_list == output list, despite the name. */ - if (disallow_filename_globbing == 0) - { - 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 0 - if ((tlist->word->flags & (W_QUOTED|W_ASSIGNMENT)) == 0 && -#else - if ((tlist->word->flags & W_ASSIGNMENT) == 0 && -#endif - unquoted_glob_pattern_p (tlist->word->word)) - { - glob_array = shell_glob_filename (tlist->word->word); + return (new_list); +} - /* 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". */ +/* The workhorse for expand_words () and expand_words_no_vars (). + First arg is LIST, a WORD_LIST of words. + Second arg DO_VARS is non-zero if you want to do environment and + variable assignments, else zero. - if (GLOB_FAILED (glob_array)) - { - glob_array = (char **) xmalloc (sizeof (char *)); - glob_array[0] = (char *)NULL; - } + 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_ASSIGNMENT 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; - /* 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; - } + if (list == 0) + return ((WORD_LIST *)NULL); - /* 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); - } + new_list = copy_word_list (list); - if (glob_list) - { - orig_list = (WORD_LIST *)list_append (glob_list, orig_list); - tlist->next = disposables; - disposables = tlist; - } - else if (allow_null_glob_expansion == 0) - { - /* Failed glob expressions are left unchanged. */ - tlist->next = orig_list; - orig_list = tlist; - } - else + if (eflags & WEXP_VARASSIGN) + { + new_list = separate_out_assignments (new_list); + if (new_list == 0) + { + if (varlist) + { + /* All the words were variable assignments, so they are placed + into the shell's environment. */ + for (temp_list = varlist; temp_list; temp_list = temp_list->next) + { + this_command_name = (char *)NULL; /* no arithmetic errors */ + tint = do_assignment (temp_list->word->word); + /* Variable assignment errors in non-interactive shells + running in Posix.2 mode cause the shell to exit. */ + if (tint == 0 && interactive_shell == 0 && posixly_correct) { - /* Failed glob expressions are removed. */ - tlist->next = disposables; - disposables = tlist; + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (FORCE_EOF); } } - else - { - /* Dequote the string. */ - temp_string = dequote_string (tlist->word->word); - free (tlist->word->word); - tlist->word->word = temp_string; - tlist->next = orig_list; - orig_list = tlist; - } + dispose_words (varlist); + varlist = (WORD_LIST *)NULL; + } + return ((WORD_LIST *)NULL); + } + } - free_array (glob_array); - glob_array = (char **)NULL; + /* Begin expanding the words that remain. The expansions take place on + things that aren't really variable assignments. */ - tlist = next; - } +#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 */ - if (disposables) - dispose_words (disposables); + /* 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); - new_list = REVERSE_LIST (orig_list, WORD_LIST *); - } + /* 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. */ - for (temp_list = new_list; temp_list; temp_list = temp_list->next) - { - temp_string = dequote_string (temp_list->word->word); - free (temp_list->word->word); - temp_list->word->word = temp_string; - } - } + /* Dequote the words, because we're not performing globbing. */ + new_list = dequote_list (new_list); } - if (do_vars) + if ((eflags & WEXP_VARASSIGN) && varlist) { Function *assign_func; @@ -5629,335 +5877,13 @@ expand_word_list_internal (list, do_vars) 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, tlist = new_list; tlist; tlist = tlist->next) - glob_argv_flags[tint++] = (tlist->word->flags & W_GLOBEXP) ? '1' : '0'; + 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'; - - return (new_list); -} - -/************************************************* - * * - * Functions to manage special variables * - * * - *************************************************/ - -/* An alist of name.function for each special variable. Most of the - functions don't do much, and in fact, this would be faster with a - switch statement, but by the end of this file, I am sick of switch - statements. */ - -#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0 - -struct name_and_function { - char *name; - VFunction *function; -} special_vars[] = { - { "PATH", sv_path }, - { "MAIL", sv_mail }, - { "MAILPATH", sv_mail }, - { "MAILCHECK", sv_mail }, - - { "POSIXLY_CORRECT", sv_strict_posix }, - { "GLOBIGNORE", sv_globignore }, - - /* Variables which only do something special when READLINE is defined. */ -#if defined (READLINE) - { "TERM", sv_terminal }, - { "TERMCAP", sv_terminal }, - { "TERMINFO", sv_terminal }, - { "HOSTFILE", sv_hostfile }, -#endif /* READLINE */ - - /* Variables which only do something special when HISTORY is defined. */ -#if defined (HISTORY) - { "HISTIGNORE", sv_histignore }, - { "HISTSIZE", sv_histsize }, - { "HISTFILESIZE", sv_histsize }, - { "HISTCONTROL", sv_history_control }, -# if defined (BANG_HISTORY) - { "histchars", sv_histchars }, -# endif /* BANG_HISTORY */ -#endif /* HISTORY */ - - { "IGNOREEOF", sv_ignoreeof }, - { "ignoreeof", sv_ignoreeof }, - - { "OPTIND", sv_optind }, - { "OPTERR", sv_opterr }, - - { "TEXTDOMAIN", sv_locale }, - { "TEXTDOMAINDIR", sv_locale }, - { "LC_ALL", sv_locale }, - { "LC_COLLATE", sv_locale }, - { "LC_CTYPE", sv_locale }, - { "LC_MESSAGES", sv_locale }, - { "LANG", sv_locale }, - -#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) - { "TZ", sv_tz }, -#endif - - { (char *)0, (VFunction *)0 } -}; - -/* The variable in NAME has just had its state changed. Check to see if it - is one of the special ones where something special happens. */ -void -stupidly_hack_special_variables (name) - char *name; -{ - int i; - - for (i = 0; special_vars[i].name; i++) - { - if (STREQ (special_vars[i].name, name)) - { - (*(special_vars[i].function)) (name); - return; - } - } -} - -/* What to do just after the PATH variable has changed. */ -void -sv_path (name) - char *name; -{ - /* hash -r */ - flush_hashed_filenames (); -} - -/* What to do just after one of the MAILxxxx variables has changed. NAME - is the name of the variable. This is called with NAME set to one of - MAIL, MAILCHECK, or MAILPATH. */ -void -sv_mail (name) - char *name; -{ - /* If the time interval for checking the files has changed, then - reset the mail timer. Otherwise, one of the pathname vars - to the users mailbox has changed, so rebuild the array of - filenames. */ - if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */ - reset_mail_timer (); - else - { - free_mail_files (); - remember_mail_dates (); - } -} - -/* What to do when GLOBIGNORE changes. */ -void -sv_globignore (name) - char *name; -{ - setup_glob_ignore (name); -} - -#if defined (READLINE) -/* What to do just after one of the TERMxxx variables has changed. - If we are an interactive shell, then try to reset the terminal - information in readline. */ -void -sv_terminal (name) - char *name; -{ - if (interactive_shell && no_line_editing == 0) - rl_reset_terminal (get_string_value ("TERM")); -} - -void -sv_hostfile (name) - char *name; -{ - hostname_list_initialized = 0; -} -#endif /* READLINE */ - -#if defined (HISTORY) -/* What to do after the HISTSIZE or HISTFILESIZE variables change. - If there is a value for this HISTSIZE (and it is numeric), then stifle - the history. Otherwise, if there is NO value for this variable, - unstifle the history. If name is HISTFILESIZE, and its value is - numeric, truncate the history file to hold no more than that many - lines. */ -void -sv_histsize (name) - char *name; -{ - char *temp; - long num; - - temp = get_string_value (name); - - if (temp && *temp) - { - if (legal_number (temp, &num)) - { - if (name[4] == 'S') - { - stifle_history (num); - num = where_history (); - if (history_lines_this_session > num) - history_lines_this_session = num; - } - else - { - history_truncate_file (get_string_value ("HISTFILE"), (int)num); - if (num <= history_lines_in_file) - history_lines_in_file = num; - } - } - } - else if (name[4] == 'S') - unstifle_history (); -} - -/* What to do after the HISTIGNORE variable changes. */ -void -sv_histignore (name) - char *name; -{ - setup_history_ignore (name); -} - -/* What to do after the HISTCONTROL variable changes. */ -void -sv_history_control (name) - char *name; -{ - char *temp; - - history_control = 0; - temp = get_string_value (name); - - if (temp && *temp && STREQN (temp, "ignore", 6)) - { - if (temp[6] == 's') /* ignorespace */ - history_control = 1; - else if (temp[6] == 'd') /* ignoredups */ - history_control = 2; - else if (temp[6] == 'b') /* ignoreboth */ - history_control = 3; - } -} - -#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 */ -#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* */ + return (new_list); } @@ -58,13 +58,6 @@ extern char *assignment_name __P((char *)); each word with a space. */ extern char *string_list __P((WORD_LIST *)); -/* Return a single string of all the words present in LIST, obeying the - quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the - expansion [of $*] appears within a double quoted string, it expands - to a single field with the value of each parameter separated by the - first character of the IFS variable, or by a <space> if IFS is unset." */ -extern char *string_list_dollar_star __P((WORD_LIST *)); - /* Perform quoted null character removal on each element of LIST. This modifies LIST. */ extern void word_list_remove_quoted_nulls __P((WORD_LIST *)); @@ -169,9 +162,10 @@ extern WORD_LIST *expand_words __P((WORD_LIST *)); variables. */ extern WORD_LIST *expand_words_no_vars __P((WORD_LIST *)); -/* 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 *)); +/* 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 char *pat_subst __P((char *, char *, char *, int)); @@ -186,26 +180,11 @@ extern WORD_LIST *list_string_with_quotes __P((char *)); extern char *extract_array_assignment_list __P((char *, int *)); #endif -/* The `special variable' functions that get called when a particular - variable is set. */ -void sv_path (), sv_mail (), sv_ignoreeof (), sv_strict_posix (); -void sv_optind (), sv_opterr (), sv_globignore (), sv_locale (); - -#if defined (READLINE) -void sv_terminal (), sv_hostfile (); +#if defined (COND_COMMAND) +extern char *remove_backslashes __P((char *)); +extern char *cond_expand_word __P((WORD_DESC *, int)); #endif -#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) -void sv_tz (); -#endif - -#if defined (HISTORY) -void sv_histsize (), sv_histignore (), sv_history_control (); -# if defined (BANG_HISTORY) -void sv_histchars (); -# endif -#endif /* HISTORY */ - /* How to determine the quoted state of the character C. */ #define QUOTED_CHAR(c) ((c) == CTLESC) diff --git a/support/Makefile.in b/support/Makefile.in new file mode 100644 index 00000000..8daea28a --- /dev/null +++ b/support/Makefile.in @@ -0,0 +1,58 @@ +# +# 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 +# + +# +# Boilerplate +# +topdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = .:@srcdir@ +BUILD_DIR = @BUILD_DIR@ + +RM = rm -f +SHELL = /bin/sh +CC = @CC@ + +# +# Compiler options: +# +PROFILE_FLAGS = @PROFILE_FLAGS@ +CFLAGS = @CFLAGS@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +DEFS = @DEFS@ +LOCAL_DEFS = @LOCAL_DEFS@ +LDFLAGS = @LDFLAGS@ $(LOCAL_LDFLAGS) $(CFLAGS) +LOCAL_LDFLAGS = @LOCAL_LDFLAGS@ +LIBS = @LIBS@ + +INCLUDES = -I${BUILD_DIR} -I${topdir} + +# +CCFLAGS = ${PROFILE_FLAGS} $(DEFS) $(LOCAL_DEFS) $(SYSTEM_FLAGS) $(CPPFLAGS) \ + ${INCLUDES} $(LOCAL_CFLAGS) $(CFLAGS) + +SRC1 = man2html.c +OBJ1 = man2html.o + +.c.o: + $(RM) $@ + $(CC) -c $(CCFLAGS) $< + +all: man2html + +man2html: $(OBJ1) + $(CC) $(CCFLAGS) $(OBJ1) -o $@ ${LIBS} + +clean: + rm man2html + +man2html.o: man2html.c diff --git a/support/bashbug.sh b/support/bashbug.sh index e12fdac4..06fb93d2 100644 --- a/support/bashbug.sh +++ b/support/bashbug.sh @@ -4,7 +4,7 @@ # # The bug address depends on the release status of the shell. Versions # with status `alpha' or `beta' mail bug reports to chet@po.cwru.edu. -# Other versions send mail to bug-bash@prep.ai.mit.edu. +# Other versions send mail to bug-bash@gnu.org. # # configuration section: # these variables are filled in by the make target in cpp-Makefile @@ -34,7 +34,7 @@ BASHTESTERS="bash-testers@po.cwru.edu" case "$RELSTATUS" in alpha*|beta*) BUGBASH=chet@po.cwru.edu ;; -*) BUGBASH=bug-bash@prep.ai.mit.edu ;; +*) BUGBASH=bug-bash@gnu.org ;; esac case "$RELSTATUS" in @@ -69,6 +69,9 @@ else RMAIL=rmail fi +# this is raceable +rm -f $TEMP + cat > $TEMP <<EOF From: ${USER} To: ${BUGADDR} @@ -98,8 +101,10 @@ Fix: fix for the problem, don't include this section.] EOF -chmod u+w $TEMP +# this is still raceable +rm -f $TEMP.x cp $TEMP $TEMP.x +chmod u+w $TEMP trap '' 2 # ignore interrupts while in editor diff --git a/support/config.guess b/support/config.guess index 698f742b..0e11ad86 100755 --- a/support/config.guess +++ b/support/config.guess @@ -153,11 +153,53 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit 0 ;; # end cases added for Bash alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi # 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 alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//'` + cat <<EOF >dummy.s + .globl main + .ent main +main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]` exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 @@ -171,9 +213,33 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in amiga:OpenBSD:*:*) echo m68k-cbm-openbsd${UNAME_RELEASE} exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; + arm32:NetBSD:*:*) + echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; Pyramid*:OSx*:*:*|MIS*:OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then @@ -209,6 +275,18 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in sun3*:SunOS:*:*|sun:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /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 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; @@ -230,6 +308,18 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in mac68k:OpenBSD:*:*) echo m68k-apple-openbsd${UNAME_RELEASE} exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + Power?Macintosh:Rhapsody:*:*) + echo powerpc-apple-nextstep${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-unknown-nextstep${UNAME_RELEASE} + exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; @@ -242,6 +332,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; + 2020:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) sed 's/^ //' << EOF >dummy.c int main (argc, argv) int argc; char **argv; { @@ -266,7 +359,7 @@ EOF echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerux + echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 @@ -501,6 +594,9 @@ EOF i*:CYGWIN*:*) echo i386-pc-cygwin32 exit 0 ;; + i*:MINGW*:*) + echo i386-pc-mingw32 + exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin32 exit 0 ;; @@ -508,43 +604,127 @@ EOF echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) - echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; *:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. ld_help_string=`ld --help 2>&1` - if echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: elf_i.86"; then - echo "${UNAME_MACHINE}-pc-linux-gnu" ; exit 0 - elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i.86linux"; then - echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 - elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i.86coff"; then - echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 - elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68kelf"; then - echo "${UNAME_MACHINE}-unknown-linux-gnu" ; exit 0 - elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68klinux"; then - echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 - elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: elf32ppc"; then - echo "powerpc-unknown-linux-gnu" ; exit 0 - elif test "${UNAME_MACHINE}" = "alpha" ; then - echo alpha-unknown-linux-gnu ; exit 0 - elif test "${UNAME_MACHINE}" = "sparc" ; then - echo sparc-unknown-linux-gnu ; exit 0 + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;; + i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;; + sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + elf32ppc) echo "powerpc-unknown-linux-gnu" ; exit 0 ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + sed 's/^ //' <<EOF >dummy.s + .globl main + .ent main + main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + LIBC="" + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + + objdump --private-headers dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >dummy.c <<EOF +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __MIPSEB__ + printf ("%s-unknown-linux-gnu\n", argv[1]); +#endif +#ifdef __MIPSEL__ + printf ("%sel-unknown-linux-gnu\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy else - # Either a pre-BFD a.out linker (linux-gnuoldld) or one that does not give us - # useful --help. Gcc wants to distinguish between linux-gnuoldld and linux-gnuaout. - test ! -d /usr/lib/ldscripts/. \ - && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac # Determine whether the default compiler is a.out or elf cat >dummy.c <<EOF +#include <features.h> main(argc, argv) -int argc; -char *argv[]; + int argc; + char *argv[]; { #ifdef __ELF__ - printf ("%s-pc-linux-gnu\n", argv[1]); +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif #else - printf ("%s-pc-linux-gnuaout\n", argv[1]); + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); #endif return 0; } @@ -557,7 +737,15 @@ EOF i?86:DYNIX/ptx:4*:*) echo i386-sequent-sysv4 exit 0 ;; - i?86:*:4.*:* | i?86:SYSTEM_V:4.*:* | i[34]86:UNIX_SV:4.*:*) + 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 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:* | i?86:UNIX_SV:4.*:*) if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} else @@ -578,6 +766,11 @@ EOF echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; + pc:*:*:*) + # 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 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; @@ -629,7 +822,7 @@ EOF SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; - RM*:SINIX-*:*:*) + RM*:SINIX-*:*:* | RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) @@ -640,6 +833,10 @@ EOF echo ns32k-sni-sysv fi exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes <hewes@openmarket.com>. # How about differentiating between stratus architectures? -djm @@ -652,6 +849,9 @@ EOF mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; + news*:NEWS-OS:*:6*) + echo mips-sony-newsos6 + exit 0 ;; R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} @@ -710,7 +910,7 @@ main () #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); exit (0); #endif diff --git a/support/config.sub b/support/config.sub index e800bb63..7541a125 100755 --- a/support/config.sub +++ b/support/config.sub @@ -152,7 +152,7 @@ case $basic_machine in tahoe | i860 | m68k | m68000 | m88k | ns32k | arm \ | arme[lb] | pyramid \ | tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \ - | alpha | we32k | ns16k | clipper | i370 | sh \ + | hppa2.0 | alpha | we32k | ns16k | clipper | i370 | sh \ | powerpc | powerpcle | 1750a | dsp16xx | mips64 | mipsel \ | pdp11 | mips64el | mips64orion | mips64orionel \ | sparc | sparclet | sparclite | sparc64) @@ -174,7 +174,8 @@ case $basic_machine in | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \ | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \ - | hppa-* | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \ + | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* \ + | alpha-* | we32k-* | cydra-* | ns16k-* \ | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \ | pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* | mips64-* | mipsel-* \ | mips64el-* | mips64orion-* | mips64orionel-* | f301-* \ diff --git a/support/man2html.c b/support/man2html.c new file mode 100644 index 00000000..fa644f8b --- /dev/null +++ b/support/man2html.c @@ -0,0 +1,4018 @@ +/* + * This program was written by Richard Verhoeven (NL:5482ZX35) + * at the Eindhoven University of Technology. Email: rcb5@win.tue.nl + * + * Permission is granted to distribute, modify and use this program as long + * as this comment is not removed or changed. + * + * THIS IS A MODIFIED VERSION. IT WAS MODIFIED BY chet@po.cwru.edu FOR + * USE BY BASH. + */ + +/* + * man2html will add links to the converted manpages. The function add_links + * is used for that. At the moment it will add links as follows, where + * indicates what should match to start with: + * ^^^ + * Recognition Item Link + * ---------------------------------------------------------- + * name(*) Manpage ../man?/name.* + * ^ + * name@hostname Email address mailto:name@hostname + * ^ + * method://string URL method://string + * ^^^ + * www.host.name WWW server http://www.host.name + * ^^^^ + * ftp.host.name FTP server ftp://ftp.host.name + * ^^^^ + * <file.h> Include file file:/usr/include/file.h + * ^^^ + * + * Since man2html does not check if manpages, hosts or email addresses exist, + * some links might not work. For manpages, some extra checks are performed + * to make sure not every () pair creates a link. Also out of date pages + * might point to incorrect places. + * + * The program will not allow users to get system specific files, such as + * /etc/passwd. It will check that "man" is part of the specified file and + * that "/../" isn't. Even if someone manages to get such file, man2html will + * handle it like a manpage and will usually not produce any output (or crash). + * + * If you find any bugs when normal manpages are converted, please report + * them to me (rcb5@win.tue.nl) after you have checked that man(1) can handle + * the manpage correct. + * + * Known bugs and missing features: + * + * * Equations are not converted at all. + * * Tables are converted but some features are not possible in html. + * * The tabbing environment is converted by counting characters and adding + * spaces. This might go wrong (outside <PRE>) + * * Some pages look beter if man2html works in troff mode, especially pages + * with tables. You can deside at compile time which made you want to use. + * + * -DNROFF=0 troff mode + * -DNROFF=1 nroff mode (default) + * + * if you install both modes, you should compile with the correct CGIBASE. + * * Some manpages rely on the fact that troff/nroff is used to convert + * them and use features which are not descripted in the man manpages. + * (definitions, calculations, conditionals, requests). I can't guarantee + * that all these features work on all manpages. (I didn't have the + * time to look through all the available manpages.) + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define NROFF 0 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <ctype.h> +#include <sys/types.h> +#include <time.h> +#include <sys/time.h> +#include <errno.h> + +#define NULL_TERMINATED(n) ((n) + 1) + +#define HUGE_STR_MAX 10000 +#define LARGE_STR_MAX 2000 +#define MED_STR_MAX 500 +#define SMALL_STR_MAX 100 +#define TINY_STR_MAX 10 + +#define MAX_MAN_PATHS 100 /* Max number of directories */ +#define MAX_ZCATS 10 /* Max number of zcat style programs */ +#define MAX_WORDLIST 100 + +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#endif +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif +#ifndef EXIT_USAGE +#define EXIT_USAGE 2 +#endif + +static char location_base[NULL_TERMINATED(MED_STR_MAX)] = ""; + +char *signature = "<HR>\n" +"This document was created by man2html\n" +"using the manual pages.<BR>\n" +"Time: %s\n"; + +/* timeformat for signature */ +#define TIMEFORMAT "%T GMT, %B %d, %Y" + +/* BSD mandoc Bl/El lists to HTML list types */ +#define BL_DESC_LIST 1 +#define BL_BULLET_LIST 2 +#define BL_ENUM_LIST 4 + +/* BSD mandoc Bd/Ed example(?) blocks */ +#define BD_LITERAL 1 +#define BD_INDENT 2 + +#ifndef HAVE_STRERROR +static char * +strerror(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 */ + +static char * +strgrow(char *old, int len) +{ + char *new = realloc(old, (strlen(old) + len + 1) * sizeof(char)); + + if (!new) { + fprintf(stderr, "man2html: out of memory"); + exit(EXIT_FAILURE); + } + return new; +} + +static char * +stralloc(int len) +{ + /* allocate enough for len + NULL */ + char *new = malloc((len + 1) * sizeof(char)); + + if (!new) { + fprintf(stderr, "man2html: out of memory"); + exit(EXIT_FAILURE); + } + return new; +} + +/* + * Some systems don't have strdup so lets use our own - which can also + * check for out of memory. + */ +static char * +strduplicate(char *from) +{ + char *new = stralloc(strlen(from)); + + strcpy(new, from); + return new; +} + +/* Assumes space for n plus a null */ +static char * +strmaxcpy(char *to, char *from, int n) +{ + int len = strlen(from); + + strncpy(to, from, n); + to[(len <= n) ? len : n] = '\0'; + return to; +} + +static char * +strmaxcat(char *to, char *from, int n) +{ + int to_len = strlen(to); + + if (to_len < n) { + int from_len = strlen(from); + int cp = (to_len + from_len <= n) ? from_len : n - to_len; + + strncpy(to + to_len, from, cp); + to[to_len + cp] = '\0'; + } + return to; +} + +/* Assumes space for limit plus a null */ +static char * +strlimitcpy(char *to, char *from, int n, int limit) +{ + int len = n > limit ? limit : n; + + strmaxcpy(to, from, len); + to[len] = '\0'; + return to; +} + +/* + * takes string and escapes all metacharacters. should be used before + * including string in system() or similar call. + */ +static char * +escape_input(char *str) +{ + int i, j = 0; + static char new[NULL_TERMINATED(MED_STR_MAX)]; + + if (strlen(str) * 2 + 1 > MED_STR_MAX) { + fprintf(stderr, + "man2html: escape_input - str too long:\n%-80s...\n", + str); + exit(EXIT_FAILURE); + } + for (i = 0; i < strlen(str); i++) { + if (!(((str[i] >= 'A') && (str[i] <= 'Z')) || + ((str[i] >= 'a') && (str[i] <= 'z')) || + ((str[i] >= '0') && (str[i] <= '9')))) { + new[j] = '\\'; + j++; + } + new[j] = str[i]; + j++; + } + new[j] = '\0'; + return new; +} + +static void +usage(void) +{ + fprintf(stderr, "man2html: usage: man2html filename\n"); +} + + + +/* + * below this you should not change anything unless you know a lot + * about this program or about troff. + */ + +typedef struct STRDEF STRDEF; +struct STRDEF { + int nr, slen; + char *st; + STRDEF *next; +}; + +typedef struct INTDEF INTDEF; +struct INTDEF { + int nr; + int val; + int incr; + INTDEF *next; +}; + +static char NEWLINE[2] = "\n"; +static char idxlabel[6] = "ixAAA"; + +#define INDEXFILE "/tmp/manindex.list" + +static char *fname; +static FILE *idxfile; + +static STRDEF *chardef, *strdef, *defdef; +static INTDEF *intdef; + +#define V(A,B) ((A)*256+(B)) + +static INTDEF standardint[] = { + {V('n', ' '), NROFF, 0, NULL}, + {V('t', ' '), 1 - NROFF, 0, NULL}, + {V('o', ' '), 1, 0, NULL}, + {V('e', ' '), 0, 0, NULL}, + {V('.', 'l'), 70, 0, NULL}, + {V('.', '$'), 0, 0, NULL}, + {V('.', 'A'), NROFF, 0, NULL}, + {V('.', 'T'), 1 - NROFF, 0, NULL}, + {V('.', 'V'), 1, 0, NULL}, /* the me package tests for this */ +{0, 0, 0, NULL}}; + +static STRDEF standardstring[] = { + {V('R', ' '), 1, "®", NULL}, + {V('l', 'q'), 2, "``", NULL}, + {V('r', 'q'), 2, "''", NULL}, + {0, 0, NULL, NULL} +}; + + +static STRDEF standardchar[] = { + {V('*', '*'), 1, "*", NULL}, + {V('*', 'A'), 1, "A", NULL}, + {V('*', 'B'), 1, "B", NULL}, + {V('*', 'C'), 2, "Xi", NULL}, + {V('*', 'D'), 5, "Delta", NULL}, + {V('*', 'E'), 1, "E", NULL}, + {V('*', 'F'), 3, "Phi", NULL}, + {V('*', 'G'), 5, "Gamma", NULL}, + {V('*', 'H'), 5, "Theta", NULL}, + {V('*', 'I'), 1, "I", NULL}, + {V('*', 'K'), 1, "K", NULL}, + {V('*', 'L'), 6, "Lambda", NULL}, + {V('*', 'M'), 1, "M", NULL}, + {V('*', 'N'), 1, "N", NULL}, + {V('*', 'O'), 1, "O", NULL}, + {V('*', 'P'), 2, "Pi", NULL}, + {V('*', 'Q'), 3, "Psi", NULL}, + {V('*', 'R'), 1, "P", NULL}, + {V('*', 'S'), 5, "Sigma", NULL}, + {V('*', 'T'), 1, "T", NULL}, + {V('*', 'U'), 1, "Y", NULL}, + {V('*', 'W'), 5, "Omega", NULL}, + {V('*', 'X'), 1, "X", NULL}, + {V('*', 'Y'), 1, "H", NULL}, + {V('*', 'Z'), 1, "Z", NULL}, + {V('*', 'a'), 5, "alpha", NULL}, + {V('*', 'b'), 4, "beta", NULL}, + {V('*', 'c'), 2, "xi", NULL}, + {V('*', 'd'), 5, "delta", NULL}, + {V('*', 'e'), 7, "epsilon", NULL}, + {V('*', 'f'), 3, "phi", NULL}, + {V('*', 'g'), 5, "gamma", NULL}, + {V('*', 'h'), 5, "theta", NULL}, + {V('*', 'i'), 4, "iota", NULL}, + {V('*', 'k'), 5, "kappa", NULL}, + {V('*', 'l'), 6, "lambda", NULL}, + {V('*', 'm'), 1, "µ", NULL}, + {V('*', 'n'), 2, "nu", NULL}, + {V('*', 'o'), 1, "o", NULL}, + {V('*', 'p'), 2, "pi", NULL}, + {V('*', 'q'), 3, "psi", NULL}, + {V('*', 'r'), 3, "rho", NULL}, + {V('*', 's'), 5, "sigma", NULL}, + {V('*', 't'), 3, "tau", NULL}, + {V('*', 'u'), 7, "upsilon", NULL}, + {V('*', 'w'), 5, "omega", NULL}, + {V('*', 'x'), 3, "chi", NULL}, + {V('*', 'y'), 3, "eta", NULL}, + {V('*', 'z'), 4, "zeta", NULL}, + {V('t', 's'), 5, "sigma", NULL}, + {V('+', '-'), 1, "±", NULL}, + {V('1', '2'), 1, "½", NULL}, + {V('1', '4'), 1, "¼", NULL}, + {V('3', '4'), 1, "¾", NULL}, + {V('F', 'i'), 3, "ffi", NULL}, + {V('F', 'l'), 3, "ffl", NULL}, + {V('a', 'a'), 1, "´", NULL}, + {V('a', 'p'), 1, "~", NULL}, + {V('b', 'r'), 1, "|", NULL}, + {V('b', 'u'), 1, "*", NULL}, + {V('b', 'v'), 1, "|", NULL}, + {V('c', 'i'), 1, "o", NULL}, + {V('c', 'o'), 1, "©", NULL}, + {V('c', 't'), 1, "¢", NULL}, + {V('d', 'e'), 1, "°", NULL}, + {V('d', 'g'), 1, "+", NULL}, + {V('d', 'i'), 1, "÷", NULL}, + {V('e', 'm'), 1, "-", NULL}, + {V('e', 'm'), 3, "---", NULL}, + {V('e', 'q'), 1, "=", NULL}, + {V('e', 's'), 1, "Ø", NULL}, + {V('f', 'f'), 2, "ff", NULL}, + {V('f', 'i'), 2, "fi", NULL}, + {V('f', 'l'), 2, "fl", NULL}, + {V('f', 'm'), 1, "´", NULL}, + {V('g', 'a'), 1, "`", NULL}, + {V('h', 'y'), 1, "-", NULL}, + {V('l', 'c'), 2, "|¯", NULL}, + {V('l', 'f'), 2, "|_", NULL}, + {V('l', 'k'), 1, "<FONT SIZE=+2>{</FONT>", NULL}, + {V('m', 'i'), 1, "-", NULL}, + {V('m', 'u'), 1, "×", NULL}, + {V('n', 'o'), 1, "¬", NULL}, + {V('o', 'r'), 1, "|", NULL}, + {V('p', 'l'), 1, "+", NULL}, + {V('r', 'c'), 2, "¯|", NULL}, + {V('r', 'f'), 2, "_|", NULL}, + {V('r', 'g'), 1, "®", NULL}, + {V('r', 'k'), 1, "<FONT SIZE=+2>}</FONT>", NULL}, + {V('r', 'n'), 1, "¯", NULL}, + {V('r', 'u'), 1, "_", NULL}, + {V('s', 'c'), 1, "§", NULL}, + {V('s', 'l'), 1, "/", NULL}, + {V('s', 'q'), 2, "[]", NULL}, + {V('u', 'l'), 1, "_", NULL}, + {0, 0, NULL, NULL} +}; + +/* default: print code */ + + +static char eqndelimopen = 0, eqndelimclose = 0; +static char escapesym = '\\', nobreaksym = '\'', controlsym = '.', fieldsym = 0, padsym = 0; + +static char *buffer = NULL; +static int buffpos = 0, buffmax = 0; +static int scaninbuff = 0; +static int itemdepth = 0; +static int dl_set[20] = {0}; +static int still_dd = 0; +static int tabstops[20] = {8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96}; +static int maxtstop = 12; +static int curpos = 0; + +static char *scan_troff(char *c, int san, char **result); +static char *scan_troff_mandoc(char *c, int san, char **result); + +static char **argument = NULL; + +static char charb[TINY_STR_MAX]; + +static void +print_sig(void) +{ + char datbuf[NULL_TERMINATED(MED_STR_MAX)]; + struct tm *timetm; + time_t clock; + + datbuf[0] = '\0'; + clock = time(NULL); + timetm = gmtime(&clock); + strftime(datbuf, MED_STR_MAX, TIMEFORMAT, timetm); + printf(signature, datbuf); +} + +static char * +expand_char(int nr) +{ + STRDEF *h; + + h = chardef; + if (!nr) + return NULL; + while (h) + if (h->nr == nr) { + curpos += h->slen; + return h->st; + } else + h = h->next; + charb[0] = nr / 256; + charb[1] = nr % 256; + charb[2] = '\0'; + if (charb[0] == '<') { /* Fix up <= */ + charb[4] = charb[1]; + strncpy(charb, "<", 4); + charb[5] = '\0'; + } + curpos += 2; + return charb; +} + +static char * +expand_string(int nr) +{ + STRDEF *h = strdef; + + if (!nr) + return NULL; + while (h) + if (h->nr == nr) { + curpos += h->slen; + return h->st; + } else + h = h->next; + return NULL; +} + +static char * +read_man_page(char *filename) +{ + char *man_buf = NULL; + int i; + FILE *man_stream = NULL; + struct stat stbuf; + int buf_size; + + if (stat(filename, &stbuf) == -1) + return NULL; + + buf_size = stbuf.st_size; + man_buf = stralloc(buf_size + 5); + man_stream = fopen(filename, "r"); + if (man_stream) { + man_buf[0] = '\n'; + if (fread(man_buf + 1, 1, buf_size, man_stream) == buf_size) { + man_buf[buf_size] = '\n'; + man_buf[buf_size + 1] = man_buf[buf_size + 2] = '\0'; + } else { + man_buf = NULL; + } + fclose(man_stream); + } + return man_buf; +} + + +static char outbuffer[NULL_TERMINATED(HUGE_STR_MAX)]; +static int obp = 0; +static int no_newline_output = 0; +static int newline_for_fun = 0; +static int output_possible = 0; +static int out_length = 0; + +/* + * Add the links to the output. At the moment the following are + * recognized: + * +#if 0 + * name(*) -> ../man?/name.* +#endif + * method://string -> method://string + * www.host.name -> http://www.host.name + * ftp.host.name -> ftp://ftp.host.name + * name@host -> mailto:name@host + * <name.h> -> file:/usr/include/name.h (guess) + * + * Other possible links to add in the future: + * + * /dir/dir/file -> file:/dir/dir/file + */ +static void +add_links(char *c) +{ + int i, j, nr; + char *f, *g, *h; + char *idtest[6]; /* url, mailto, www, ftp, manpage */ + + out_length += strlen(c); + /* search for (section) */ + nr = 0; + idtest[0] = strstr(c + 1, "://"); + idtest[1] = strchr(c + 1, '@'); + idtest[2] = strstr(c, "www."); + idtest[3] = strstr(c, "ftp."); +#if 0 + idtest[4] = strchr(c + 1, '('); +#else + idtest[4] = 0; +#endif + idtest[5] = strstr(c + 1, ".h>"); + for (i = 0; i < 6; i++) + nr += (idtest[i] != NULL); + while (nr) { + j = -1; + for (i = 0; i < 6; i++) + if (idtest[i] && (j < 0 || idtest[i] < idtest[j])) + j = i; + switch (j) { + case 5: /* <name.h> */ + f = idtest[5]; + h = f + 2; + g = f; + while (g > c && g[-1] != ';') + g--; + if (g != c) { + char t; + + t = *g; + *g = '\0'; + fputs(c, stdout); + *g = t; + *h = '\0'; + printf("<A HREF=\"file:/usr/include/%s\">%s</A>>", g, g); + c = f + 6; + } else { + f[5] = '\0'; + fputs(c, stdout); + f[5] = ';'; + c = f + 5; + } + break; + case 4: /* manpage */ +#if 0 + f = idtest[j]; + /* check section */ + g = strchr(f, ')'); + if (g && f - g < 6 && (isalnum(f[-1]) || f[-1] == '>') && + ((isdigit(f[1]) && f[1] != '0' && + (f[2] == ')' || (isalpha(f[2]) && f[3] == ')') || f[2] == 'X')) || + (f[2] == ')' && (f[1] == 'n' || f[1] == 'l')))) { + /* this might be a link */ + h = f - 1; + /* skip html makeup */ + while (h > c && *h == '>') { + while (h != c && *h != '<') + h--; + if (h != c) + h--; + } + if (isalnum(*h)) { + char t, sec, subsec, *e; + + e = h + 1; + sec = f[1]; + subsec = f[2]; + if ((subsec == 'X' && f[3] != ')') || subsec == ')') + subsec = '\0'; + while (h > c && (isalnum(h[-1]) || h[-1] == '_' || + h[-1] == '-' || h[-1] == '.')) + h--; + t = *h; + *h = '\0'; + fputs(c, stdout); + *h = t; + t = *e; + *e = '\0'; + if (subsec) + printf("<A HREF=\"" + CGIBASE + "?man%c/%s.%c%c\">%s</A>", + sec, h, sec, tolower(subsec), h); + else + printf("<A HREF=\"" + CGIBASE + "?man%c/%s.%c\">%s</A>", + sec, h, sec, h); + *e = t; + c = e; + } + } + *f = '\0'; + fputs(c, stdout); + *f = '('; + idtest[4] = f - 1; + c = f; +#endif + break; /* manpage */ + case 3: /* ftp */ + case 2: /* www */ + g = f = idtest[j]; + while (*g && (isalnum(*g) || *g == '_' || *g == '-' || *g == '+' || + *g == '.')) + g++; + if (g[-1] == '.') + g--; + if (g - f > 4) { + char t; + + t = *f; + *f = '\0'; + fputs(c, stdout); + *f = t; + t = *g; + *g = '\0'; + printf("<A HREF=\"%s://%s\">%s</A>", (j == 3 ? "ftp" : "http"), + f, f); + *g = t; + c = g; + } else { + f[3] = '\0'; + fputs(c, stdout); + c = f + 3; + f[3] = '.'; + } + break; + case 1: /* mailto */ + g = f = idtest[1]; + while (g > c && (isalnum(g[-1]) || g[-1] == '_' || g[-1] == '-' || + g[-1] == '+' || g[-1] == '.' || g[-1] == '%')) + g--; + h = f + 1; + while (*h && (isalnum(*h) || *h == '_' || *h == '-' || *h == '+' || + *h == '.')) + h++; + if (*h == '.') + h--; + if (h - f > 4 && f - g > 1) { + char t; + + t = *g; + *g = '\0'; + fputs(c, stdout); + *g = t; + t = *h; + *h = '\0'; + printf("<A HREF=\"mailto:%s\">%s</A>", g, g); + *h = t; + c = h; + } else { + *f = '\0'; + fputs(c, stdout); + *f = '@'; + idtest[1] = c; + c = f; + } + break; + case 0: /* url */ + g = f = idtest[0]; + while (g > c && isalpha(g[-1]) && islower(g[-1])) + g--; + h = f + 3; + while (*h && !isspace(*h) && *h != '<' && *h != '>' && *h != '"' && + *h != '&') + h++; + if (f - g > 2 && f - g < 7 && h - f > 3) { + char t; + + t = *g; + *g = '\0'; + fputs(c, stdout); + *g = t; + t = *h; + *h = '\0'; + printf("<A HREF=\"%s\">%s</A>", g, g); + *h = t; + c = h; + } else { + f[1] = '\0'; + fputs(c, stdout); + f[1] = '/'; + c = f + 1; + } + break; + default: + break; + } + nr = 0; + if (idtest[0] && idtest[0] < c) + idtest[0] = strstr(c + 1, "://"); + if (idtest[1] && idtest[1] < c) + idtest[1] = strchr(c + 1, '@'); + if (idtest[2] && idtest[2] < c) + idtest[2] = strstr(c, "www."); + if (idtest[3] && idtest[3] < c) + idtest[3] = strstr(c, "ftp."); + if (idtest[4] && idtest[4] < c) + idtest[4] = strchr(c + 1, '('); + if (idtest[5] && idtest[5] < c) + idtest[5] = strstr(c + 1, ".h>"); + for (i = 0; i < 6; i++) + nr += (idtest[i] != NULL); + } + fputs(c, stdout); +} + +static int current_font = 0; +static int current_size = 0; +static int fillout = 1; + +static void +out_html(char *c) +{ + if (!c) + return; + if (no_newline_output) { + int i = 0; + + no_newline_output = 1; + while (c[i]) { + if (!no_newline_output) + c[i - 1] = c[i]; + if (c[i] == '\n') + no_newline_output = 1; + i++; + } + if (!no_newline_output) + c[i - 1] = 0; + } + if (scaninbuff) { + while (*c) { + if (buffpos >= buffmax) { + char *h; + + h = realloc(buffer, buffmax * 2); + if (!h) + return; + buffer = h; + buffmax *= 2; + } + buffer[buffpos++] = *c++; + } + } else if (output_possible) { + while (*c) { + outbuffer[obp++] = *c; + if (*c == '\n' || obp > HUGE_STR_MAX) { + outbuffer[obp] = '\0'; + add_links(outbuffer); + obp = 0; + } + c++; + } + } +} + +#define FO0 "" +#define FC0 "" +#define FO1 "<I>" +#define FC1 "</I>" +#define FO2 "<B>" +#define FC2 "</B>" +#define FO3 "<TT>" +#define FC3 "</TT>" + +static char *switchfont[16] = { + "", FC0 FO1, FC0 FO2, FC0 FO3, + FC1 FO0, "", FC1 FO2, FC1 FO3, + FC2 FO0, FC2 FO1, "", FC2 FO3, + FC3 FO0, FC3 FO1, FC3 FO2, "" +}; + +static char * +change_to_font(int nr) +{ + int i; + + switch (nr) { + case '0': + nr++; + case '1': + case '2': + case '3': + case '4': + nr = nr - '1'; + break; + case V('C', 'W'): + nr = 3; + break; + case 'L': + nr = 3; + break; + case 'B': + nr = 2; + break; + case 'I': + nr = 1; + break; + case 'P': + case 'R': + nr = 0; + break; + case 0: + case 1: + case 2: + case 3: + break; + default: + nr = 0; + break; + } + i = current_font * 4 + nr % 4; + current_font = nr % 4; + return switchfont[i]; +} + +static char sizebuf[200]; + +static char * +change_to_size(int nr) +{ + int i; + + switch (nr) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + nr = nr - '0'; + break; + case '\0': + break; + default: + nr = current_size + nr; + if (nr > 9) + nr = 9; + if (nr < -9) + nr = -9; + break; + } + if (nr == current_size) + return ""; + i = current_font; + sizebuf[0] = '\0'; + strcat(sizebuf, change_to_font(0)); + if (current_size) + strcat(sizebuf, "</FONT>"); + current_size = nr; + if (nr) { + int l; + + strcat(sizebuf, "<FONT SIZE="); + l = strlen(sizebuf); + if (nr > 0) + sizebuf[l++] = '+'; + else + sizebuf[l++] = '-', nr = -nr; + sizebuf[l++] = nr + '0'; + sizebuf[l++] = '>'; + sizebuf[l] = '\0'; + } + strcat(sizebuf, change_to_font(i)); + return sizebuf; +} + +static int asint = 0; +static int intresult = 0; + +#define SKIPEOL while (*c && *c++!='\n') + +static int skip_escape = 0; +static int single_escape = 0; + +static char * +scan_escape(char *c) +{ + char *h = NULL; + char b[5]; + INTDEF *intd; + int exoutputp, exskipescape; + int i, j; + + intresult = 0; + switch (*c) { + case 'e': + h = "\\"; + curpos++; + break; + case '0': + case ' ': + h = " "; + curpos++; + break; + case '|': + h = ""; + break; + case '"': + SKIPEOL; + c--; + h = ""; + break; + case '$': + if (argument) { + c++; + i = (*c - '1'); + if (!(h = argument[i])) + h = ""; + } + break; + case 'z': + c++; + if (*c == '\\') { + c = scan_escape(c + 1); + c--; + h = ""; + } else { + b[0] = *c; + b[1] = '\0'; + h = ""; + } + break; + case 'k': + c++; + if (*c == '(') + c += 2; + case '^': + case '!': + case '%': + case 'a': + case 'd': + case 'r': + case 'u': + case '\n': + case '&': + h = ""; + break; + case '(': + c++; + i = c[0] * 256 + c[1]; + c++; + h = expand_char(i); + break; + case '*': + c++; + if (*c == '(') { + c++; + i = c[0] * 256 + c[1]; + c++; + } else + i = *c * 256 + ' '; + h = expand_string(i); + break; + case 'f': + c++; + if (*c == '\\') { + c++; + c = scan_escape(c); + c--; + i = intresult; + } else if (*c != '(') + i = *c; + else { + c++; + i = c[0] * 256 + c[1]; + c++; + } + if (!skip_escape) + h = change_to_font(i); + else + h = ""; + break; + case 's': + c++; + j = 0; + i = 0; + if (*c == '-') { + j = -1; + c++; + } else if (*c == '+') { + j = 1; + c++; + } + if (*c == '0') + c++; + else if (*c == '\\') { + c++; + c = scan_escape(c); + i = intresult; + if (!j) + j = 1; + } else + while (isdigit(*c) && (!i || (!j && i < 4))) + i = i * 10 + (*c++) - '0'; + if (!j) { + j = 1; + if (i) + i = i - 10; + } + if (!skip_escape) + h = change_to_size(i * j); + else + h = ""; + c--; + break; + case 'n': + c++; + j = 0; + switch (*c) { + case '+': + j = 1; + c++; + break; + case '-': + j = -1; + c++; + break; + default: + break; + } + if (*c == '(') { + c++; + i = V(c[0], c[1]); + c = c + 1; + } else { + i = V(c[0], ' '); + } + intd = intdef; + while (intd && intd->nr != i) + intd = intd->next; + if (intd) { + intd->val = intd->val + j * intd->incr; + intresult = intd->val; + } else { + switch (i) { + case V('.', 's'): + intresult = current_size; + break; + case V('.', 'f'): + intresult = current_font; + break; + default: + intresult = 0; + break; + } + } + h = ""; + break; + case 'w': + c++; + i = *c; + c++; + exoutputp = output_possible; + exskipescape = skip_escape; + output_possible = 0; + skip_escape = 1; + j = 0; + while (*c != i) { + j++; + if (*c == escapesym) + c = scan_escape(c + 1); + else + c++; + } + output_possible = exoutputp; + skip_escape = exskipescape; + intresult = j; + break; + case 'l': + h = "<HR>"; + curpos = 0; + case 'b': + case 'v': + case 'x': + case 'o': + case 'L': + case 'h': + c++; + i = *c; + c++; + exoutputp = output_possible; + exskipescape = skip_escape; + output_possible = 0; + skip_escape = 1; + while (*c != i) + if (*c == escapesym) + c = scan_escape(c + 1); + else + c++; + output_possible = exoutputp; + skip_escape = exskipescape; + break; + case 'c': + no_newline_output = 1; + break; + case '{': + newline_for_fun++; + h = ""; + break; + case '}': + if (newline_for_fun) + newline_for_fun--; + h = ""; + break; + case 'p': + h = "<BR>\n"; + curpos = 0; + break; + case 't': + h = "\t"; + curpos = (curpos + 8) & 0xfff8; + break; + case '<': + h = "<"; + curpos++; + break; + case '>': + h = ">"; + curpos++; + break; + case '\\': + if (single_escape) { + c--; + break; + } + default: + b[0] = *c; + b[1] = 0; + h = b; + curpos++; + break; + } + c++; + if (!skip_escape) + out_html(h); + return c; +} + +typedef struct TABLEITEM TABLEITEM; + +struct TABLEITEM { + char *contents; + int size, align, valign, colspan, rowspan, font, vleft, vright, space, + width; + TABLEITEM *next; +}; + +static TABLEITEM emptyfield = {NULL, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, NULL}; + +typedef struct TABLEROW TABLEROW; + +struct TABLEROW { + TABLEITEM *first; + TABLEROW *prev, *next; +}; + +static char *tableopt[] = { + "center", "expand", "box", "allbox", "doublebox", + "tab", "linesize", "delim", NULL +}; +static int tableoptl[] = {6, 6, 3, 6, 9, 3, 8, 5, 0}; + +static void +clear_table(TABLEROW * table) +{ + TABLEROW *tr1, *tr2; + TABLEITEM *ti1, *ti2; + + tr1 = table; + while (tr1->prev) + tr1 = tr1->prev; + while (tr1) { + ti1 = tr1->first; + while (ti1) { + ti2 = ti1->next; + if (ti1->contents) + free(ti1->contents); + free(ti1); + ti1 = ti2; + } + tr2 = tr1; + tr1 = tr1->next; + free(tr2); + } +} + +static char *scan_expression(char *c, int *result); + +static char * +scan_format(char *c, TABLEROW ** result, int *maxcol) +{ + TABLEROW *layout, *currow; + TABLEITEM *curfield; + int i, j; + + if (*result) { + clear_table(*result); + } + layout = currow = (TABLEROW *) malloc(sizeof(TABLEROW)); + currow->next = currow->prev = NULL; + currow->first = curfield = (TABLEITEM *) malloc(sizeof(TABLEITEM)); + *curfield = emptyfield; + while (*c && *c != '.') { + switch (*c) { + case 'C': + case 'c': + case 'N': + case 'n': + case 'R': + case 'r': + case 'A': + case 'a': + case 'L': + case 'l': + case 'S': + case 's': + case '^': + case '_': + if (curfield->align) { + curfield->next = (TABLEITEM *) malloc(sizeof(TABLEITEM)); + curfield = curfield->next; + *curfield = emptyfield; + } + curfield->align = toupper(*c); + c++; + break; + case 'i': + case 'I': + case 'B': + case 'b': + curfield->font = toupper(*c); + c++; + break; + case 'f': + case 'F': + c++; + curfield->font = toupper(*c); + c++; + if (!isspace(*c)) + c++; + break; + case 't': + case 'T': + curfield->valign = 't'; + c++; + break; + case 'p': + case 'P': + c++; + i = j = 0; + if (*c == '+') { + j = 1; + c++; + } + if (*c == '-') { + j = -1; + c++; + } + while (isdigit(*c)) + i = i * 10 + (*c++) - '0'; + if (j) + curfield->size = i * j; + else + curfield->size = j - 10; + break; + case 'v': + case 'V': + case 'w': + case 'W': + c = scan_expression(c + 2, &curfield->width); + break; + case '|': + if (curfield->align) + curfield->vleft++; + else + curfield->vright++; + c++; + break; + case 'e': + case 'E': + c++; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + i = 0; + while (isdigit(*c)) + i = i * 10 + (*c++) - '0'; + curfield->space = i; + break; + case ',': + case '\n': + currow->next = (TABLEROW *) malloc(sizeof(TABLEROW)); + currow->next->prev = currow; + currow = currow->next; + currow->next = NULL; + curfield = currow->first = (TABLEITEM *) malloc(sizeof(TABLEITEM)); + *curfield = emptyfield; + c++; + break; + default: + c++; + break; + } + } + if (*c == '.') + while (*c++ != '\n'); + *maxcol = 0; + currow = layout; + while (currow) { + curfield = layout->first; + i = 0; + while (curfield) { + i++; + curfield = curfield->next; + } + if (i > *maxcol) + *maxcol = i; + currow = currow->next; + } + *result = layout; + return c; +} + +static TABLEROW * +next_row(TABLEROW * tr) +{ + if (tr->next) { + tr = tr->next; + if (!tr->next) + next_row(tr); + return tr; + } else { + TABLEITEM *ti, *ti2; + + tr->next = (TABLEROW *) malloc(sizeof(TABLEROW)); + tr->next->prev = tr; + ti = tr->first; + tr = tr->next; + tr->next = NULL; + if (ti) + tr->first = ti2 = (TABLEITEM *) malloc(sizeof(TABLEITEM)); + else + tr->first = ti2 = NULL; + while (ti != ti2) { + *ti2 = *ti; + ti2->contents = NULL; + if ((ti = ti->next)) { + ti2->next = (TABLEITEM *) malloc(sizeof(TABLEITEM)); + } + ti2 = ti2->next; + } + return tr; + } +} + +static char itemreset[20] = "\\fR\\s0"; + +static char * +scan_table(char *c) +{ + char *t, *h, *g; + int center = 0, expand = 0, box = 0, border = 0, linesize = 1; + int i, j, maxcol = 0, finished = 0; + int oldfont, oldsize, oldfillout; + char itemsep = '\t'; + TABLEROW *layout = NULL, *currow, *ftable; + TABLEITEM *curfield; + + while (*c++ != '\n'); + h = c; + if (*h == '.') + return c - 1; + oldfont = current_font; + oldsize = current_size; + oldfillout = fillout; + out_html(change_to_font(0)); + out_html(change_to_size(0)); + if (!fillout) { + fillout = 1; + out_html("</PRE>"); + } + while (*h && *h != '\n') + h++; + if (h[-1] == ';') { + /* scan table options */ + while (c < h) { + while (isspace(*c)) + c++; + for (i = 0; tableopt[i] && strncmp(tableopt[i], c, tableoptl[i]); i++); + c = c + tableoptl[i]; + switch (i) { + case 0: + center = 1; + break; + case 1: + expand = 1; + break; + case 2: + box = 1; + break; + case 3: + border = 1; + break; + case 4: + box = 2; + break; + case 5: + while (*c++ != '('); + itemsep = *c++; + break; + case 6: + while (*c++ != '('); + linesize = 0; + while (isdigit(*c)) + linesize = linesize * 10 + (*c++) - '0'; + break; + case 7: + while (*c != ')') + c++; + default: + break; + } + c++; + } + c = h + 1; + } + /* scan layout */ + c = scan_format(c, &layout, &maxcol); + currow = layout; + next_row(currow); + curfield = layout->first; + i = 0; + while (!finished) { + /* search item */ + h = c; + if ((*c == '_' || *c == '=') && (c[1] == itemsep || c[1] == '\n')) { + if (c[-1] == '\n' && c[1] == '\n') { + if (currow->prev) { + currow->prev->next = (TABLEROW *) malloc(sizeof(TABLEROW)); + currow->prev->next->next = currow; + currow->prev->next->prev = currow->prev; + currow->prev = currow->prev->next; + } else { + currow->prev = layout = (TABLEROW *) malloc(sizeof(TABLEROW)); + currow->prev->prev = NULL; + currow->prev->next = currow; + } + curfield = currow->prev->first = + (TABLEITEM *) malloc(sizeof(TABLEITEM)); + *curfield = emptyfield; + curfield->align = *c; + curfield->colspan = maxcol; + curfield = currow->first; + c = c + 2; + } else { + if (curfield) { + curfield->align = *c; + do { + curfield = curfield->next; + } while (curfield && curfield->align == 'S'); + } + if (c[1] == '\n') { + currow = next_row(currow); + curfield = currow->first; + } + c = c + 2; + } + } else if (*c == 'T' && c[1] == '{') { + h = c + 2; + c = strstr(h, "\nT}"); + c++; + *c = '\0'; + g = NULL; + scan_troff(h, 0, &g); + scan_troff(itemreset, 0, &g); + *c = 'T'; + c += 3; + if (curfield) { + curfield->contents = g; + do { + curfield = curfield->next; + } while (curfield && curfield->align == 'S'); + } else if (g) + free(g); + if (c[-1] == '\n') { + currow = next_row(currow); + curfield = currow->first; + } + } else if (*c == '.' && c[1] == 'T' && c[2] == '&' && c[-1] == '\n') { + TABLEROW *hr; + + while (*c++ != '\n'); + hr = currow; + currow = currow->prev; + hr->prev = NULL; + c = scan_format(c, &hr, &i); + hr->prev = currow; + currow->next = hr; + currow = hr; + next_row(currow); + curfield = currow->first; + } else if (*c == '.' && c[1] == 'T' && c[2] == 'E' && c[-1] == '\n') { + finished = 1; + while (*c++ != '\n'); + if (currow->prev) + currow->prev->next = NULL; + currow->prev = NULL; + clear_table(currow); + } else if (*c == '.' && c[-1] == '\n' && !isdigit(c[1])) { + /* + * skip troff request inside table (usually only .sp + * ) + */ + while (*c++ != '\n'); + } else { + h = c; + while (*c && (*c != itemsep || c[-1] == '\\') && + (*c != '\n' || c[-1] == '\\')) + c++; + i = 0; + if (*c == itemsep) { + i = 1; + *c = '\n'; + } + if (h[0] == '\\' && h[2] == '\n' && + (h[1] == '_' || h[1] == '^')) { + if (curfield) { + curfield->align = h[1]; + do { + curfield = curfield->next; + } while (curfield && curfield->align == 'S'); + } + h = h + 3; + } else { + g = NULL; + h = scan_troff(h, 1, &g); + scan_troff(itemreset, 0, &g); + if (curfield) { + curfield->contents = g; + do { + curfield = curfield->next; + } while (curfield && curfield->align == 'S'); + } else if (g) + free(g); + } + if (i) + *c = itemsep; + c = h; + if (c[-1] == '\n') { + currow = next_row(currow); + curfield = currow->first; + } + } + } + /* calculate colspan and rowspan */ + currow = layout; + while (currow->next) + currow = currow->next; + while (currow) { + TABLEITEM *ti, *ti1 = NULL, *ti2 = NULL; + + ti = currow->first; + if (currow->prev) + ti1 = currow->prev->first; + while (ti) { + switch (ti->align) { + case 'S': + if (ti2) { + ti2->colspan++; + if (ti2->rowspan < ti->rowspan) + ti2->rowspan = ti->rowspan; + } + break; + case '^': + if (ti1) + ti1->rowspan++; + default: + if (!ti2) + ti2 = ti; + else { + do { + ti2 = ti2->next; + } while (ti2 && curfield->align == 'S'); + } + break; + } + ti = ti->next; + if (ti1) + ti1 = ti1->next; + } + currow = currow->prev; + } + /* produce html output */ + if (center) + out_html("<CENTER>"); + if (box == 2) + out_html("<TABLE BORDER><TR><TD>"); + out_html("<TABLE"); + if (box || border) { + out_html(" BORDER"); + if (!border) + out_html("><TR><TD><TABLE"); + if (expand) + out_html(" WIDTH=100%"); + } + out_html(">\n"); + currow = layout; + while (currow) { + j = 0; + out_html("<TR VALIGN=top>"); + curfield = currow->first; + while (curfield) { + if (curfield->align != 'S' && curfield->align != '^') { + out_html("<TD"); + switch (curfield->align) { + case 'N': + curfield->space += 4; + case 'R': + out_html(" ALIGN=right"); + break; + case 'C': + out_html(" ALIGN=center"); + default: + break; + } + if (!curfield->valign && curfield->rowspan > 1) + out_html(" VALIGN=center"); + if (curfield->colspan > 1) { + char buf[5]; + + out_html(" COLSPAN="); + sprintf(buf, "%i", curfield->colspan); + out_html(buf); + } + if (curfield->rowspan > 1) { + char buf[5]; + + out_html(" ROWSPAN="); + sprintf(buf, "%i", curfield->rowspan); + out_html(buf); + } + j = j + curfield->colspan; + out_html(">"); + if (curfield->size) + out_html(change_to_size(curfield->size)); + if (curfield->font) + out_html(change_to_font(curfield->font)); + switch (curfield->align) { + case '=': + out_html("<HR><HR>"); + break; + case '_': + out_html("<HR>"); + break; + default: + if (curfield->contents) + out_html(curfield->contents); + break; + } + if (curfield->space) + for (i = 0; i < curfield->space; i++) + out_html(" "); + if (curfield->font) + out_html(change_to_font(0)); + if (curfield->size) + out_html(change_to_size(0)); + if (j >= maxcol && curfield->align > '@' && curfield->align != '_') + out_html("<BR>"); + out_html("</TD>"); + } + curfield = curfield->next; + } + out_html("</TR>\n"); + currow = currow->next; + } + if (box && !border) + out_html("</TABLE>"); + out_html("</TABLE>"); + if (box == 2) + out_html("</TABLE>"); + if (center) + out_html("</CENTER>\n"); + else + out_html("\n"); + if (!oldfillout) + out_html("<PRE>"); + fillout = oldfillout; + out_html(change_to_size(oldsize)); + out_html(change_to_font(oldfont)); + return c; +} + +static char * +scan_expression(char *c, int *result) +{ + int value = 0, value2, j = 0, sign = 1, opex = 0; + char oper = 'c'; + + if (*c == '!') { + c = scan_expression(c + 1, &value); + value = (!value); + } else if (*c == 'n') { + c++; + value = NROFF; + } else if (*c == 't') { + c++; + value = 1 - NROFF; + } else if (*c == '\'' || *c == '"' || *c < ' ' || (*c == '\\' && c[1] == '(')) { + /* + * ?string1?string2? test if string1 equals string2. + */ + char *st1 = NULL, *st2 = NULL, *h; + char *tcmp = NULL; + char sep; + + sep = *c; + if (sep == '\\') { + tcmp = c; + c = c + 3; + } + c++; + h = c; + while (*c != sep && (!tcmp || strncmp(c, tcmp, 4))) + c++; + *c = '\n'; + scan_troff(h, 1, &st1); + *c = sep; + if (tcmp) + c = c + 3; + c++; + h = c; + while (*c != sep && (!tcmp || strncmp(c, tcmp, 4))) + c++; + *c = '\n'; + scan_troff(h, 1, &st2); + *c = sep; + if (!st1 && !st2) + value = 1; + else if (!st1 || !st2) + value = 0; + else + value = (!strcmp(st1, st2)); + if (st1) + free(st1); + if (st2) + free(st2); + if (tcmp) + c = c + 3; + c++; + } else { + while (*c && !isspace(*c) && *c != ')') { + opex = 0; + switch (*c) { + case '(': + c = scan_expression(c + 1, &value2); + value2 = sign * value2; + opex = 1; + break; + case '.': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9':{ + int num = 0, denum = 1; + + value2 = 0; + while (isdigit(*c)) + value2 = value2 * 10 + ((*c++) - '0'); + if (*c == '.') { + c++; + while (isdigit(*c)) { + num = num * 10 + ((*c++) - '0'); + denum = denum * 10; + } + } + if (isalpha(*c)) { + /* scale indicator */ + switch (*c) { + case 'i': /* inch -> 10pt */ + value2 = value2 * 10 + (num * 10 + denum / 2) / denum; + num = 0; + break; + default: + break; + } + c++; + } + value2 = value2 + (num + denum / 2) / denum; + value2 = sign * value2; + opex = 1; + break; + } + case '\\': + c = scan_escape(c + 1); + value2 = intresult * sign; + if (isalpha(*c)) + c++; /* scale indicator */ + opex = 1; + break; + case '-': + if (oper) { + sign = -1; + c++; + break; + } + case '>': + case '<': + case '+': + case '/': + case '*': + case '%': + case '&': + case '=': + case ':': + if (c[1] == '=') + oper = (*c++) + 16; + else + oper = *c; + c++; + break; + default: + c++; + break; + } + if (opex) { + sign = 1; + switch (oper) { + case 'c': + value = value2; + break; + case '-': + value = value - value2; + break; + case '+': + value = value + value2; + break; + case '*': + value = value * value2; + break; + case '/': + if (value2) + value = value / value2; + break; + case '%': + if (value2) + value = value % value2; + break; + case '<': + value = (value < value2); + break; + case '>': + value = (value > value2); + break; + case '>' + 16: + value = (value >= value2); + break; + case '<' + 16: + value = (value <= value2); + break; + case '=': + case '=' + 16: + value = (value == value2); + break; + case '&': + value = (value && value2); + break; + case ':': + value = (value || value2); + break; + default: + fprintf(stderr, "man2html: unknown operator %c.\n", oper); + } + oper = 0; + } + } + if (*c == ')') + c++; + } + *result = value; + return c; +} + +static void +trans_char(char *c, char s, char t) +{ + char *sl = c; + int slash = 0; + + while (*sl != '\n' || slash) { + if (!slash) { + if (*sl == escapesym) + slash = 1; + else if (*sl == s) + *sl = t; + } else + slash = 0; + sl++; + } +} + +static char * +fill_words(char *c, char *words[], int *n) +{ + char *sl = c; + int slash = 0; + int skipspace = 0; + + *n = 0; + words[*n] = sl; + while (*sl && (*sl != '\n' || slash)) { + if (!slash) { + if (*sl == '"') { + *sl = '\a'; + skipspace = !skipspace; + } else if (*sl == escapesym) + slash = 1; + else if ((*sl == ' ' || *sl == '\t') && !skipspace) { + *sl = '\n'; + if (words[*n] != sl) + (*n)++; + words[*n] = sl + 1; + } + } else { + if (*sl == '"') { + sl--; + *sl = '\n'; + if (words[*n] != sl) + (*n)++; + sl++; + while (*sl && *sl != '\n') + sl++; + words[*n] = sl; + sl--; + } + slash = 0; + } + sl++; + } + if (sl != words[*n]) + (*n)++; + return sl; +} + +static char *abbrev_list[] = { + "GSBG", "Getting Started ", + "SUBG", "Customizing SunOS", + "SHBG", "Basic Troubleshooting", + "SVBG", "SunView User's Guide", + "MMBG", "Mail and Messages", + "DMBG", "Doing More with SunOS", + "UNBG", "Using the Network", + "GDBG", "Games, Demos & Other Pursuits", + "CHANGE", "SunOS 4.1 Release Manual", + "INSTALL", "Installing SunOS 4.1", + "ADMIN", "System and Network Administration", + "SECUR", "Security Features Guide", + "PROM", "PROM User's Manual", + "DIAG", "Sun System Diagnostics", + "SUNDIAG", "Sundiag User's Guide", + "MANPAGES", "SunOS Reference Manual", + "REFMAN", "SunOS Reference Manual", + "SSI", "Sun System Introduction", + "SSO", "System Services Overview", + "TEXT", "Editing Text Files", + "DOCS", "Formatting Documents", + "TROFF", "Using <B>nroff</B> and <B>troff</B>", + "INDEX", "Global Index", + "CPG", "C Programmer's Guide", + "CREF", "C Reference Manual", + "ASSY", "Assembly Language Reference", + "PUL", "Programming Utilities and Libraries", + "DEBUG", "Debugging Tools", + "NETP", "Network Programming", + "DRIVER", "Writing Device Drivers", + "STREAMS", "STREAMS Programming", + "SBDK", "SBus Developer's Kit", + "WDDS", "Writing Device Drivers for the SBus", + "FPOINT", "Floating-Point Programmer's Guide", + "SVPG", "SunView 1 Programmer's Guide", + "SVSPG", "SunView 1 System Programmer's Guide", + "PIXRCT", "Pixrect Reference Manual", + "CGI", "SunCGI Reference Manual", + "CORE", "SunCore Reference Manual", + "4ASSY", "Sun-4 Assembly Language Reference", + "SARCH", "<FONT SIZE=-1>SPARC</FONT> Architecture Manual", + "KR", "The C Programming Language", +NULL, NULL}; + +static char * +lookup_abbrev(char *c) +{ + int i = 0; + + if (!c) + return ""; + while (abbrev_list[i] && strcmp(c, abbrev_list[i])) + i = i + 2; + if (abbrev_list[i]) + return abbrev_list[i + 1]; + else + return c; +} + +static char manidx[NULL_TERMINATED(HUGE_STR_MAX)]; +static int subs = 0; +static int mip = 0; +static char label[5] = "lbAA"; + +static void +add_to_index(int level, char *item) +{ + char *c = NULL; + + label[3]++; + if (label[3] > 'Z') { + label[3] = 'A'; + label[2]++; + } + if (level != subs) { + if (subs) { + strmaxcpy(manidx + mip, "</DL>\n", HUGE_STR_MAX - mip); + mip += 6; + } else { + strmaxcpy(manidx + mip, "<DL>\n", HUGE_STR_MAX - mip); + mip += 5; + } + } + subs = level; + scan_troff(item, 1, &c); + sprintf(manidx + mip, "<DT><A HREF=\"#%s\">%s</A><DD>\n", label, c); + if (c) + free(c); + while (manidx[mip]) + mip++; +} + +static char * +skip_till_newline(char *c) +{ + int lvl = 0; + + while (*c && *c != '\n' || lvl > 0) { + if (*c == '\\') { + c++; + if (*c == '}') + lvl--; + else if (*c == '{') + lvl++; + } + c++; + } + c++; + if (lvl < 0 && newline_for_fun) { + newline_for_fun = newline_for_fun + lvl; + if (newline_for_fun < 0) + newline_for_fun = 0; + } + return c; +} + +static int ifelseval = 0; + +static char * +scan_request(char *c) +{ + /* BSD Mandoc stuff */ + static int mandoc_synopsis = 0; /* True if we are in the synopsis + * section */ + static int mandoc_command = 0; /* True if this is mandoc page */ + static int mandoc_bd_options; /* Only copes with non-nested Bd's */ + + int i, j, mode = 0; + char *h; + char *wordlist[MAX_WORDLIST]; + int words; + char *sl; + STRDEF *owndef; + + while (*c == ' ' || *c == '\t') + c++; + if (c[0] == '\n') + return c + 1; + if (c[1] == '\n') + j = 1; + else + j = 2; + while (c[j] == ' ' || c[j] == '\t') + j++; + if (c[0] == escapesym) { + /* some pages use .\" .\$1 .\} */ + /* .\$1 is too difficult/stuppid */ + if (c[1] == '$') + c = skip_till_newline(c); + else + c = scan_escape(c + 1); + } else { + i = V(c[0], c[1]); + switch (i) { + case V('a', 'b'): + h = c + j; + while (*h && *h != '\n') + h++; + *h = '\0'; + if (scaninbuff && buffpos) { + buffer[buffpos] = '\0'; + puts(buffer); + } + /* fprintf(stderr, "%s\n", c+2); */ + exit(0); + break; + case V('d', 'i'): + { + STRDEF *de; + int oldcurpos = curpos; + + c = c + j; + i = V(c[0], c[1]); + if (*c == '\n') { + c++; + break; + } + while (*c && *c != '\n') + c++; + c++; + h = c; + while (*c && strncmp(c, ".di", 3)) + while (*c && *c++ != '\n'); + *c = '\0'; + de = strdef; + while (de && de->nr != i) + de = de->next; + if (!de) { + de = (STRDEF *) malloc(sizeof(STRDEF)); + de->nr = i; + de->slen = 0; + de->next = strdef; + de->st = NULL; + strdef = de; + } else { + if (de->st) + free(de->st); + de->slen = 0; + de->st = NULL; + } + scan_troff(h, 0, &de->st); + *c = '.'; + while (*c && *c++ != '\n'); + break; + } + case V('d', 's'): + mode = 1; + case V('a', 's'): + { + STRDEF *de; + int oldcurpos = curpos; + + c = c + j; + i = V(c[0], c[1]); + j = 0; + while (c[j] && c[j] != '\n') + j++; + if (j < 3) { + c = c + j; + break; + } + if (c[1] == ' ') + c = c + 1; + else + c = c + 2; + while (isspace(*c)) + c++; + if (*c == '"') + c++; + de = strdef; + while (de && de->nr != i) + de = de->next; + single_escape = 1; + curpos = 0; + if (!de) { + char *h; + + de = (STRDEF *) malloc(sizeof(STRDEF)); + de->nr = i; + de->slen = 0; + de->next = strdef; + de->st = NULL; + strdef = de; + h = NULL; + c = scan_troff(c, 1, &h); + de->st = h; + de->slen = curpos; + } else { + if (mode) { + char *h = NULL; + + c = scan_troff(c, 1, &h); + free(de->st); + de->slen = 0; + de->st = h; + } else + c = scan_troff(c, 1, &de->st); + de->slen += curpos; + } + single_escape = 0; + curpos = oldcurpos; + } + break; + case V('b', 'r'): + if (still_dd) + out_html("<DD>"); + else + out_html("<BR>\n"); + curpos = 0; + c = c + j; + if (c[0] == escapesym) { + c = scan_escape(c + 1); + } + c = skip_till_newline(c); + break; + case V('c', '2'): + c = c + j; + if (*c != '\n') { + nobreaksym = *c; + } else + nobreaksym = '\''; + c = skip_till_newline(c); + break; + case V('c', 'c'): + c = c + j; + if (*c != '\n') { + controlsym = *c; + } else + controlsym = '.'; + c = skip_till_newline(c); + break; + case V('c', 'e'): + c = c + j; + if (*c == '\n') { + i = 1; + } else { + i = 0; + while ('0' <= *c && *c <= '9') { + i = i * 10 + *c - '0'; + c++; + } + } + c = skip_till_newline(c); + /* center next i lines */ + if (i > 0) { + out_html("<CENTER>\n"); + while (i && *c) { + char *line = NULL; + + c = scan_troff(c, 1, &line); + if (line && strncmp(line, "<BR>", 4)) { + out_html(line); + out_html("<BR>\n"); + i--; + } + } + out_html("</CENTER>\n"); + curpos = 0; + } + break; + case V('e', 'c'): + c = c + j; + if (*c != '\n') { + escapesym = *c; + } else + escapesym = '\\'; + break; + c = skip_till_newline(c); + case V('e', 'o'): + escapesym = '\0'; + c = skip_till_newline(c); + break; + case V('e', 'x'): + exit(0); + break; + case V('f', 'c'): + c = c + j; + if (*c == '\n') { + fieldsym = padsym = '\0'; + } else { + fieldsym = c[0]; + padsym = c[1]; + } + c = skip_till_newline(c); + break; + case V('f', 'i'): + if (!fillout) { + out_html(change_to_font(0)); + out_html(change_to_size('0')); + out_html("</PRE>\n"); + } + curpos = 0; + fillout = 1; + c = skip_till_newline(c); + break; + case V('f', 't'): + c = c + j; + if (*c == '\n') { + out_html(change_to_font(0)); + } else { + if (*c == escapesym) { + int fn; + + c = scan_expression(c, &fn); + c--; + out_html(change_to_font(fn)); + } else { + out_html(change_to_font(*c)); + c++; + } + } + c = skip_till_newline(c); + break; + case V('e', 'l'): + /* .el anything : else part of if else */ + if (ifelseval) { + c = c + j; + c[-1] = '\n'; + c = scan_troff(c, 1, NULL); + } else + c = skip_till_newline(c + j); + break; + case V('i', 'e'): + /* .ie c anything : then part of if else */ + case V('i', 'f'): + /* + * .if c anything .if !c anything .if N anything .if + * !N anything .if 'string1'string2' anything .if + * !'string1'string2' anything + */ + c = c + j; + c = scan_expression(c, &i); + ifelseval = !i; + if (i) { + *c = '\n'; + c++; + c = scan_troff(c, 1, NULL); + } else + c = skip_till_newline(c); + break; + case V('i', 'g'): + { + char *endwith = "..\n"; + + i = 3; + c = c + j; + if (*c != '\n') { + endwith = c - 1; + i = 1; + c[-1] = '.'; + while (*c && *c != '\n') + c++, i++; + } + c++; + while (*c && strncmp(c, endwith, i)) + while (*c++ != '\n'); + while (*c++ != '\n'); + break; + } + case V('n', 'f'): + if (fillout) { + out_html(change_to_font(0)); + out_html(change_to_size('0')); + out_html("<PRE>\n"); + } + curpos = 0; + fillout = 0; + c = skip_till_newline(c); + break; + case V('p', 's'): + c = c + j; + if (*c == '\n') { + out_html(change_to_size('0')); + } else { + j = 0; + i = 0; + if (*c == '-') { + j = -1; + c++; + } else if (*c == '+') { + j = 1; + c++; + } + c = scan_expression(c, &i); + if (!j) { + j = 1; + if (i > 5) + i = i - 10; + } + out_html(change_to_size(i * j)); + } + c = skip_till_newline(c); + break; + case V('s', 'p'): + c = c + j; + if (fillout) + out_html("<P>"); + else { + out_html(NEWLINE); + NEWLINE[0] = '\n'; + } + curpos = 0; + c = skip_till_newline(c); + break; + case V('s', 'o'): + { + FILE *f; + struct stat stbuf; + int l = 0; + char *buf; + char *name = NULL; + + curpos = 0; + c = c + j; + if (*c == '/') { + h = c; + } else { + h = c - 3; + h[0] = '.'; + h[1] = '.'; + h[2] = '/'; + } + while (*c != '\n') + c++; + *c = '\0'; + scan_troff(h, 1, &name); + if (name[3] == '/') + h = name + 3; + else + h = name; + if (stat(h, &stbuf) != -1) + l = stbuf.st_size; + buf = stralloc(l + 4); +#if NOCGI + if (!out_length) { + char *t, *s; + + t = strrchr(fname, '/'); + if (!t) + t = fname; + fprintf(stderr, "ln -s %s.html %s.html\n", h, t); + s = strrchr(t, '.'); + if (!s) + s = t; + printf("<HTML><HEAD><TITLE> Manpage of %s</TITLE>\n" + "</HEAD><BODY>\n" + "See the manpage for <A HREF=\"%s.html\">%s</A>.\n" + "</BODY></HTML>\n", + s, h, h); + } else +#endif + { + /* + * this works alright, except for + * section 3 + */ + buf = read_man_page(h); + if (!buf) { + + fprintf(stderr, "man2html: unable to open or read file %s.\n", + h); + out_html("<BLOCKQUOTE>" + "man2html: unable to open or read file.\n"); + out_html(h); + out_html("</BLOCKQUOTE>\n"); + } else { + buf[0] = buf[l] = '\n'; + buf[l + 1] = buf[l + 2] = '\0'; + scan_troff(buf + 1, 0, NULL); + } + if (buf) + free(buf); + } + *c++ = '\n'; + break; + } + case V('t', 'a'): + c = c + j; + j = 0; + while (*c != '\n') { + sl = scan_expression(c, &tabstops[j]); + if (*c == '-' || *c == '+') + tabstops[j] += tabstops[j - 1]; + c = sl; + while (*c == ' ' || *c == '\t') + c++; + j++; + } + maxtstop = j; + curpos = 0; + break; + case V('t', 'i'): + /* + * while (itemdepth || dl_set[itemdepth]) { + * out_html("</DL>\n"); if (dl_set[itemdepth]) + * dl_set[itemdepth]=0; else itemdepth--; } + */ + out_html("<BR>\n"); + c = c + j; + c = scan_expression(c, &j); + for (i = 0; i < j; i++) + out_html(" "); + curpos = j; + c = skip_till_newline(c); + break; + case V('t', 'm'): + c = c + j; + h = c; + while (*c != '\n') + c++; + *c = '\0'; + /* fprintf(stderr,"%s\n", h); */ + *c = '\n'; + break; + case V('B', ' '): + case V('B', '\n'): + case V('I', ' '): + case V('I', '\n'): + /* parse one line in a certain font */ + out_html(change_to_font(*c)); + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + c = scan_troff(c, 1, NULL); + out_html(change_to_font('R')); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('O', 'P'): /* groff manpages use this + * construction */ + /* .OP a b : [ <B>a</B> <I>b</I> ] */ + mode = 1; + c[0] = 'B'; + c[1] = 'I'; + out_html(change_to_font('R')); + out_html("["); + curpos++; + case V('B', 'R'): + case V('B', 'I'): + case V('I', 'B'): + case V('I', 'R'): + case V('R', 'B'): + case V('R', 'I'): + { + char font[2]; + + font[0] = c[0]; + font[1] = c[1]; + c = c + j; + if (*c == '\n') + c++; + sl = fill_words(c, wordlist, &words); + c = sl + 1; + /* + * .BR name (section) indicates a link. It + * will be added in the output routine. + */ + for (i = 0; i < words; i++) { + if (mode) { + out_html(" "); + curpos++; + } + wordlist[i][-1] = ' '; + out_html(change_to_font(font[i & 1])); + scan_troff(wordlist[i], 1, NULL); + } + out_html(change_to_font('R')); + if (mode) { + out_html(" ]"); + curpos++; + } + out_html(NEWLINE); + if (!fillout) + curpos = 0; + else + curpos++; + } + break; + case V('D', 'T'): + for (j = 0; j < 20; j++) + tabstops[j] = (j + 1) * 8; + maxtstop = 20; + c = skip_till_newline(c); + break; + case V('I', 'P'): + sl = fill_words(c + j, wordlist, &words); + c = sl + 1; + if (!dl_set[itemdepth]) { + out_html("<DL COMPACT>\n"); + dl_set[itemdepth] = 1; + } + out_html("<DT>"); + if (words) { + scan_troff(wordlist[0], 1, NULL); + } + out_html("<DD>"); + curpos = 0; + break; + case V('T', 'P'): + if (!dl_set[itemdepth]) { + out_html("<DL COMPACT>\n"); + dl_set[itemdepth] = 1; + } + out_html("<DT>"); + c = skip_till_newline(c); + /* somewhere a definition ends with '.TP' */ + if (!*c) + still_dd = 1; + else { + c = scan_troff(c, 1, NULL); + out_html("<DD>"); + } + curpos = 0; + break; + case V('I', 'X'): + /* general index */ + sl = fill_words(c + j, wordlist, &words); + c = sl + 1; + j = 4; + while (idxlabel[j] == 'Z') + idxlabel[j--] = 'A'; + idxlabel[j]++; +#ifdef MAKEINDEX + fprintf(idxfile, "%s@%s@", fname, idxlabel); + for (j = 0; j < words; j++) { + h = NULL; + scan_troff(wordlist[j], 1, &h); + fprintf(idxfile, "_\b@%s", h); + free(h); + } + fprintf(idxfile, "\n"); +#endif + out_html("<A NAME=\""); + out_html(idxlabel); + /* + * this will not work in mosaic (due to a bug). + * Adding ' ' between '>' and '<' solves it, but + * creates some space. A normal space does not work. + */ + out_html("\"></A>"); + break; + case V('L', 'P'): + case V('P', 'P'): + if (dl_set[itemdepth]) { + out_html("</DL>\n"); + dl_set[itemdepth] = 0; + } + if (fillout) + out_html("<P>\n"); + else { + out_html(NEWLINE); + NEWLINE[0] = '\n'; + } + curpos = 0; + c = skip_till_newline(c); + break; + case V('H', 'P'): + if (!dl_set[itemdepth]) { + out_html("<DL COMPACT>"); + dl_set[itemdepth] = 1; + } + out_html("<DT>\n"); + still_dd = 1; + c = skip_till_newline(c); + curpos = 0; + break; + case V('P', 'D'): + c = skip_till_newline(c); + break; + case V('R', 's'): /* BSD mandoc */ + case V('R', 'S'): + sl = fill_words(c + j, wordlist, &words); + j = 1; + if (words > 0) + scan_expression(wordlist[0], &j); + if (j >= 0) { + itemdepth++; + dl_set[itemdepth] = 0; + out_html("<DL COMPACT><DT><DD>"); + c = skip_till_newline(c); + curpos = 0; + break; + } + case V('R', 'e'): /* BSD mandoc */ + case V('R', 'E'): + if (itemdepth > 0) { + if (dl_set[itemdepth]) + out_html("</DL>"); + out_html("</DL>\n"); + itemdepth--; + } + c = skip_till_newline(c); + curpos = 0; + break; + case V('S', 'B'): + out_html(change_to_size(-1)); + out_html(change_to_font('B')); + c = scan_troff(c + j, 1, NULL); + out_html(change_to_font('R')); + out_html(change_to_size('0')); + break; + case V('S', 'M'): + c = c + j; + if (*c == '\n') + c++; + out_html(change_to_size(-1)); + trans_char(c, '"', '\a'); + c = scan_troff(c, 1, NULL); + out_html(change_to_size('0')); + break; + case V('S', 's'): /* BSD mandoc */ + mandoc_command = 1; + case V('S', 'S'): + mode = 1; + case V('S', 'h'): /* BSD mandoc */ + /* hack for fallthru from above */ + mandoc_command = !mode || mandoc_command; + case V('S', 'H'): + c = c + j; + if (*c == '\n') + c++; + while (itemdepth || dl_set[itemdepth]) { + out_html("</DL>\n"); + if (dl_set[itemdepth]) + dl_set[itemdepth] = 0; + else if (itemdepth > 0) + itemdepth--; + } + out_html(change_to_font(0)); + out_html(change_to_size(0)); + if (!fillout) { + fillout = 1; + out_html("</PRE>"); + } + trans_char(c, '"', '\a'); + add_to_index(mode, c); + out_html("<A NAME=\""); + out_html(label); + /* for mosaic users */ + if (mode) + out_html("\"> </A>\n<H3>"); + else + out_html("\"> </A>\n<H2>"); + mandoc_synopsis = strncmp(c, "SYNOPSIS", 8) == 0; + c = mandoc_command ? scan_troff_mandoc(c, 1, NULL) : scan_troff(c, 1, NULL); + if (mode) + out_html("</H3>\n"); + else + out_html("</H2>\n"); + curpos = 0; + break; + case V('T', 'S'): + c = scan_table(c); + break; + case V('D', 't'): /* BSD mandoc */ + mandoc_command = 1; + case V('T', 'H'): + if (!output_possible) { + sl = fill_words(c + j, wordlist, &words); + if (words > 1) { + char page_and_sec[128]; + + for (i = 1; i < words; i++) + wordlist[i][-1] = '\0'; + *sl = '\0'; + output_possible = 1; + sprintf(page_and_sec, "%s(%s)", wordlist[0], wordlist[1]); + out_html("<HTML><HEAD>\n<TITLE>"); + out_html(page_and_sec); + out_html(" Manual Page"); + out_html("</TITLE>\n</HEAD>\n<BODY>"); + out_html("<TABLE WIDTH=100%>\n"); + out_html("<TH ALIGN=LEFT>"); + out_html(page_and_sec); + out_html("<TH ALIGN=CENTER>"); + out_html(wordlist[2]); + out_html("<TH ALIGN=RIGHT>"); + out_html(page_and_sec); + out_html("\n</TABLE>\n"); + out_html("<BR><A HREF=\"#index\">Index</A>\n"); + *sl = '\n'; + out_html("<HR>\n"); + if (mandoc_command) + out_html("<BR>BSD mandoc<BR>"); + } + c = sl + 1; + } else + c = skip_till_newline(c); + curpos = 0; + break; + case V('T', 'X'): + sl = fill_words(c + j, wordlist, &words); + *sl = '\0'; + out_html(change_to_font('I')); + if (words > 1) + wordlist[1][-1] = '\0'; + c = lookup_abbrev(wordlist[0]); + curpos += strlen(c); + out_html(c); + out_html(change_to_font('R')); + if (words > 1) + out_html(wordlist[1]); + *sl = '\n'; + c = sl + 1; + break; + case V('r', 'm'): + /* .rm xx : Remove request, macro or string */ + case V('r', 'n'): + /* + * .rn xx yy : Rename request, macro or string xx to + * yy + */ + { + STRDEF *de; + + c = c + j; + i = V(c[0], c[1]); + c = c + 2; + while (isspace(*c) && *c != '\n') + c++; + j = V(c[0], c[1]); + while (*c && *c != '\n') + c++; + c++; + de = strdef; + while (de && de->nr != j) + de = de->next; + if (de) { + if (de->st) + free(de->st); + de->nr = 0; + } + de = strdef; + while (de && de->nr != i) + de = de->next; + if (de) + de->nr = j; + break; + } + case V('n', 'x'): + /* .nx filename : next file. */ + case V('i', 'n'): + /* .in +-N : Indent */ + c = skip_till_newline(c); + break; + case V('n', 'r'): + /* + * .nr R +-N M: define and set number register R by + * +-N; auto-increment by M + */ + { + INTDEF *intd; + + c = c + j; + i = V(c[0], c[1]); + c = c + 2; + intd = intdef; + while (intd && intd->nr != i) + intd = intd->next; + if (!intd) { + intd = (INTDEF *) malloc(sizeof(INTDEF)); + intd->nr = i; + intd->val = 0; + intd->incr = 0; + intd->next = intdef; + intdef = intd; + } + while (*c == ' ' || *c == '\t') + c++; + c = scan_expression(c, &intd->val); + if (*c != '\n') { + while (*c == ' ' || *c == '\t') + c++; + c = scan_expression(c, &intd->incr); + } + c = skip_till_newline(c); + break; + } + case V('a', 'm'): + /* .am xx yy : append to a macro. */ + /* define or handle as .ig yy */ + mode = 1; + case V('d', 'e'): + /* + * .de xx yy : define or redefine macro xx; end at + * .yy (..) + */ + /* define or handle as .ig yy */ + { + STRDEF *de; + int olen = 0; + + c = c + j; + sl = fill_words(c, wordlist, &words); + i = V(c[0], c[1]); + j = 2; + if (words == 1) + wordlist[1] = ".."; + else { + wordlist[1]--; + wordlist[1][0] = '.'; + j = 3; + } + c = sl + 1; + sl = c; + while (*c && strncmp(c, wordlist[1], j)) + c = skip_till_newline(c); + de = defdef; + while (de && de->nr != i) + de = de->next; + if (mode && de) + olen = strlen(de->st); + j = olen + c - sl; + h = stralloc(j * 2 + 4); + if (h) { + for (j = 0; j < olen; j++) + h[j] = de->st[j]; + if (!j || h[j - 1] != '\n') + h[j++] = '\n'; + while (sl != c) { + if (sl[0] == '\\' && sl[1] == '\\') { + h[j++] = '\\'; + sl++; + } else + h[j++] = *sl; + sl++; + } + h[j] = '\0'; + if (de) { + if (de->st) + free(de->st); + de->st = h; + } else { + de = (STRDEF *) malloc(sizeof(STRDEF)); + de->nr = i; + de->next = defdef; + de->st = h; + defdef = de; + } + } + } + c = skip_till_newline(c); + break; + case V('B', 'l'): /* BSD mandoc */ + { + char list_options[NULL_TERMINATED(MED_STR_MAX)]; + char *nl = strchr(c, '\n'); + + c = c + j; + if (dl_set[itemdepth]) { /* These things can + * nest. */ + itemdepth++; + } + if (nl) { /* Parse list options */ + strlimitcpy(list_options, c, nl - c, MED_STR_MAX); + } + if (strstr(list_options, "-bullet")) { /* HTML Unnumbered List */ + dl_set[itemdepth] = BL_BULLET_LIST; + out_html("<UL>\n"); + } else if (strstr(list_options, "-enum")) { /* HTML Ordered List */ + dl_set[itemdepth] = BL_ENUM_LIST; + out_html("<OL>\n"); + } else { /* HTML Descriptive List */ + dl_set[itemdepth] = BL_DESC_LIST; + out_html("<DL COMPACT>\n"); + } + if (fillout) + out_html("<P>\n"); + else { + out_html(NEWLINE); + NEWLINE[0] = '\n'; + } + curpos = 0; + c = skip_till_newline(c); + break; + } + case V('E', 'l'): /* BSD mandoc */ + c = c + j; + if (dl_set[itemdepth] & BL_DESC_LIST) { + out_html("</DL>\n"); + } else if (dl_set[itemdepth] & BL_BULLET_LIST) { + out_html("</UL>\n"); + } else if (dl_set[itemdepth] & BL_ENUM_LIST) { + out_html("</OL>\n"); + } + dl_set[itemdepth] = 0; + if (itemdepth > 0) + itemdepth--; + if (fillout) + out_html("<P>\n"); + else { + out_html(NEWLINE); + NEWLINE[0] = '\n'; + } + curpos = 0; + c = skip_till_newline(c); + break; + case V('I', 't'): /* BSD mandoc */ + c = c + j; + if (strncmp(c, "Xo", 2) == 0 && isspace(*(c + 2))) { + c = skip_till_newline(c); + } + if (dl_set[itemdepth] & BL_DESC_LIST) { + out_html("<DT>"); + out_html(change_to_font('B')); + if (*c == '\n') { /* Don't allow embedded + * comms after a newline */ + c++; + c = scan_troff(c, 1, NULL); + } else { /* Do allow embedded comms on + * the same line. */ + c = scan_troff_mandoc(c, 1, NULL); + } + out_html(change_to_font('R')); + out_html(NEWLINE); + out_html("<DD>"); + } else if (dl_set[itemdepth] & (BL_BULLET_LIST | BL_ENUM_LIST)) { + out_html("<LI>"); + c = scan_troff_mandoc(c, 1, NULL); + out_html(NEWLINE); + } + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('B', 'k'): /* BSD mandoc */ + case V('E', 'k'): /* BSD mandoc */ + case V('D', 'd'): /* BSD mandoc */ + case V('O', 's'): /* BSD mandoc */ + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + c = scan_troff_mandoc(c, 1, NULL); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('B', 't'): /* BSD mandoc */ + trans_char(c, '"', '\a'); + c = c + j; + out_html(" is currently in beta test."); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('B', 'x'): /* BSD mandoc */ + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + out_html("BSD "); + c = scan_troff_mandoc(c, 1, NULL); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('D', 'l'): /* BSD mandoc */ + c = c + j; + out_html(NEWLINE); + out_html("<BLOCKQUOTE>"); + out_html(change_to_font('L')); + if (*c == '\n') + c++; + c = scan_troff_mandoc(c, 1, NULL); + out_html(change_to_font('R')); + out_html("</BLOCKQUOTE>"); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('B', 'd'): /* BSD mandoc */ + { /* Seems like a kind of example/literal mode */ + char bd_options[NULL_TERMINATED(MED_STR_MAX)]; + char *nl = strchr(c, '\n'); + + c = c + j; + if (nl) { + strlimitcpy(bd_options, c, nl - c, MED_STR_MAX); + } + out_html(NEWLINE); + mandoc_bd_options = 0; /* Remember options for + * terminating Bl */ + if (strstr(bd_options, "-offset indent")) { + mandoc_bd_options |= BD_INDENT; + out_html("<BLOCKQUOTE>\n"); + } + if (strstr(bd_options, "-literal") + || strstr(bd_options, "-unfilled")) { + if (fillout) { + mandoc_bd_options |= BD_LITERAL; + out_html(change_to_font(0)); + out_html(change_to_size('0')); + out_html("<PRE>\n"); + } + curpos = 0; + fillout = 0; + } + c = skip_till_newline(c); + break; + } + case V('E', 'd'): /* BSD mandoc */ + if (mandoc_bd_options & BD_LITERAL) { + if (!fillout) { + out_html(change_to_font(0)); + out_html(change_to_size('0')); + out_html("</PRE>\n"); + } + } + if (mandoc_bd_options & BD_INDENT) + out_html("</BLOCKQUOTE>\n"); + curpos = 0; + fillout = 1; + c = skip_till_newline(c); + break; + case V('B', 'e'): /* BSD mandoc */ + c = c + j; + if (fillout) + out_html("<P>"); + else { + out_html(NEWLINE); + NEWLINE[0] = '\n'; + } + curpos = 0; + c = skip_till_newline(c); + break; + case V('X', 'r'): /* BSD mandoc */ + { + /* + * Translate xyz 1 to xyz(1) Allow for + * multiple spaces. Allow the section to be + * missing. + */ + char buff[NULL_TERMINATED(MED_STR_MAX)]; + char *bufptr; + + trans_char(c, '"', '\a'); + bufptr = buff; + c = c + j; + if (*c == '\n') + c++; /* Skip spaces */ + while (isspace(*c) && *c != '\n') + c++; + while (isalnum(*c)) { /* Copy the xyz part */ + *bufptr = *c; + bufptr++; + if (bufptr >= buff + MED_STR_MAX) + break; + c++; + } + while (isspace(*c) && *c != '\n') + c++; /* Skip spaces */ + if (isdigit(*c)) { /* Convert the number if + * there is one */ + *bufptr = '('; + bufptr++; + if (bufptr < buff + MED_STR_MAX) { + while (isalnum(*c)) { + *bufptr = *c; + bufptr++; + if (bufptr >= buff + MED_STR_MAX) + break; + c++; + } + if (bufptr < buff + MED_STR_MAX) { + *bufptr = ')'; + bufptr++; + } + } + } + while (*c != '\n') { /* Copy the remainder */ + if (!isspace(*c)) { + *bufptr = *c; + bufptr++; + if (bufptr >= buff + MED_STR_MAX) + break; + } + c++; + } + *bufptr = '\n'; + scan_troff_mandoc(buff, 1, NULL); + + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + } + break; + case V('F', 'l'): /* BSD mandoc */ + trans_char(c, '"', '\a'); + c = c + j; + out_html("-"); + if (*c != '\n') { + out_html(change_to_font('B')); + c = scan_troff_mandoc(c, 1, NULL); + out_html(change_to_font('R')); + } + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('P', 'a'): /* BSD mandoc */ + case V('P', 'f'): /* BSD mandoc */ + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + c = scan_troff_mandoc(c, 1, NULL); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('P', 'p'): /* BSD mandoc */ + if (fillout) + out_html("<P>\n"); + else { + out_html(NEWLINE); + NEWLINE[0] = '\n'; + } + curpos = 0; + c = skip_till_newline(c); + break; + case V('D', 'q'): /* BSD mandoc */ + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + out_html("``"); + c = scan_troff_mandoc(c, 1, NULL); + out_html("''"); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('O', 'p'): /* BSD mandoc */ + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + out_html(change_to_font('R')); + out_html("["); + c = scan_troff_mandoc(c, 1, NULL); + out_html(change_to_font('R')); + out_html("]"); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('O', 'o'): /* BSD mandoc */ + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + out_html(change_to_font('R')); + out_html("["); + c = scan_troff_mandoc(c, 1, NULL); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('O', 'c'): /* BSD mandoc */ + trans_char(c, '"', '\a'); + c = c + j; + c = scan_troff_mandoc(c, 1, NULL); + out_html(change_to_font('R')); + out_html("]"); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('P', 'q'): /* BSD mandoc */ + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + out_html("("); + c = scan_troff_mandoc(c, 1, NULL); + out_html(")"); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('Q', 'l'): /* BSD mandoc */ + { /* Single quote first word in the line */ + char *sp; + + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + sp = c; + do { /* Find first whitespace after the + * first word that isn't a mandoc + * macro */ + while (*sp && isspace(*sp)) + sp++; + while (*sp && !isspace(*sp)) + sp++; + } while (*sp && isupper(*(sp - 2)) && islower(*(sp - 1))); + + /* + * Use a newline to mark the end of text to + * be quoted + */ + if (*sp) + *sp = '\n'; + out_html("`"); /* Quote the text */ + c = scan_troff_mandoc(c, 1, NULL); + out_html("'"); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + } + case V('S', 'q'): /* BSD mandoc */ + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + out_html("`"); + c = scan_troff_mandoc(c, 1, NULL); + out_html("'"); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('A', 'r'): /* BSD mandoc */ + /* parse one line in italics */ + out_html(change_to_font('I')); + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') { /* An empty Ar means "file + * ..." */ + out_html("file ..."); + } else { + c = scan_troff_mandoc(c, 1, NULL); + } + out_html(change_to_font('R')); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('A', 'd'): /* BSD mandoc */ + case V('E', 'm'): /* BSD mandoc */ + case V('V', 'a'): /* BSD mandoc */ + case V('X', 'c'): /* BSD mandoc */ + /* parse one line in italics */ + out_html(change_to_font('I')); + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + c = scan_troff_mandoc(c, 1, NULL); + out_html(change_to_font('R')); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('N', 'd'): /* BSD mandoc */ + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + out_html(" - "); + c = scan_troff_mandoc(c, 1, NULL); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('N', 'm'): /* BSD mandoc */ + { + static char mandoc_name[NULL_TERMINATED(SMALL_STR_MAX)] = ""; + + trans_char(c, '"', '\a'); + c = c + j; + if (mandoc_synopsis) { /* Break lines only in + * the Synopsis. The + * Synopsis section + * seems to be treated + * as a special case - + * Bummer! */ + static int count = 0; /* Don't break on the + * first Nm */ + + if (count) { + out_html("<BR>"); + } else { + char *end = strchr(c, '\n'); + + if (end) { /* Remember the name for + * later. */ + strlimitcpy(mandoc_name, c, end - c, SMALL_STR_MAX); + } + } + count++; + } + out_html(change_to_font('B')); + while (*c == ' ' || *c == '\t') + c++; + if (*c == '\n') { /* If Nm has no + * argument, use one + * from an earlier Nm + * command that did have + * one. Hope there + * aren't too many + * commands that do + * this. */ + out_html(mandoc_name); + } else { + c = scan_troff_mandoc(c, 1, NULL); + } + out_html(change_to_font('R')); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + } + case V('C', 'd'): /* BSD mandoc */ + case V('C', 'm'): /* BSD mandoc */ + case V('I', 'c'): /* BSD mandoc */ + case V('M', 's'): /* BSD mandoc */ + case V('O', 'r'): /* BSD mandoc */ + case V('S', 'y'): /* BSD mandoc */ + /* parse one line in bold */ + out_html(change_to_font('B')); + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + c = scan_troff_mandoc(c, 1, NULL); + out_html(change_to_font('R')); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('D', 'v'): /* BSD mandoc */ + case V('E', 'v'): /* BSD mandoc */ + case V('F', 'r'): /* BSD mandoc */ + case V('L', 'i'): /* BSD mandoc */ + case V('N', 'o'): /* BSD mandoc */ + case V('N', 's'): /* BSD mandoc */ + case V('T', 'n'): /* BSD mandoc */ + case V('n', 'N'): /* BSD mandoc */ + trans_char(c, '"', '\a'); + c = c + j; + if (*c == '\n') + c++; + out_html(change_to_font('B')); + c = scan_troff_mandoc(c, 1, NULL); + out_html(change_to_font('R')); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('%', 'A'): /* BSD mandoc biblio stuff */ + case V('%', 'D'): + case V('%', 'N'): + case V('%', 'O'): + case V('%', 'P'): + case V('%', 'Q'): + case V('%', 'V'): + c = c + j; + if (*c == '\n') + c++; + c = scan_troff(c, 1, NULL); /* Don't allow embedded + * mandoc coms */ + if (fillout) + curpos++; + else + curpos = 0; + break; + case V('%', 'B'): + case V('%', 'J'): + case V('%', 'R'): + case V('%', 'T'): + c = c + j; + out_html(change_to_font('I')); + if (*c == '\n') + c++; + c = scan_troff(c, 1, NULL); /* Don't allow embedded + * mandoc coms */ + out_html(change_to_font('R')); + if (fillout) + curpos++; + else + curpos = 0; + break; + default: + /* search macro database of self-defined macros */ + owndef = defdef; + while (owndef && owndef->nr != i) + owndef = owndef->next; + if (owndef) { + char **oldargument; + int deflen; + int onff; + + sl = fill_words(c + j, wordlist, &words); + c = sl + 1; + *sl = '\0'; + for (i = 1; i < words; i++) + wordlist[i][-1] = '\0'; + for (i = 0; i < words; i++) { + char *h = NULL; + + if (mandoc_command) { + scan_troff_mandoc(wordlist[i], 1, &h); + } else { + scan_troff(wordlist[i], 1, &h); + } + wordlist[i] = h; + } + for (i = words; i < 20; i++) + wordlist[i] = NULL; + deflen = strlen(owndef->st); + for (i = 0; owndef->st[deflen + 2 + i] = owndef->st[i]; i++); + oldargument = argument; + argument = wordlist; + onff = newline_for_fun; + if (mandoc_command) { + scan_troff_mandoc(owndef->st + deflen + 2, 0, NULL); + } else { + scan_troff(owndef->st + deflen + 2, 0, NULL); + } + newline_for_fun = onff; + argument = oldargument; + for (i = 0; i < words; i++) + if (wordlist[i]) + free(wordlist[i]); + *sl = '\n'; + } else if (mandoc_command && + ((isupper(*c) && islower(*(c + 1))) + || (islower(*c) && isupper(*(c + 1)))) + ) { /* Let through any BSD mandoc + * commands that haven't been delt + * with. I don't want to miss + * anything out of the text. */ + char buf[4]; + + strncpy(buf, c, 2); + buf[2] = ' '; + buf[3] = '\0'; + out_html(buf); /* Print the command (it + * might just be text). */ + c = c + j; + trans_char(c, '"', '\a'); + if (*c == '\n') + c++; + out_html(change_to_font('R')); + c = scan_troff(c, 1, NULL); + out_html(NEWLINE); + if (fillout) + curpos++; + else + curpos = 0; + } else { + c = skip_till_newline(c); + } + break; + } + } + if (fillout) { + out_html(NEWLINE); + curpos++; + } + NEWLINE[0] = '\n'; + return c; +} + +static void +flush(void) +{ +} + +static int contained_tab = 0; +static int mandoc_line = 0; /* Signals whether to look for embedded + * mandoc commands. */ + +/* san : stop at newline */ +static char * +scan_troff(char *c, int san, char **result) +{ + char *h; + char intbuff[NULL_TERMINATED(MED_STR_MAX)]; + int ibp = 0; + int i; + char *exbuffer; + int exbuffpos, exbuffmax, exscaninbuff, exnewline_for_fun; + int usenbsp = 0; + +#define FLUSHIBP if (ibp) { intbuff[ibp]=0; out_html(intbuff); ibp=0; } + + exbuffer = buffer; + exbuffpos = buffpos; + exbuffmax = buffmax; + exnewline_for_fun = newline_for_fun; + exscaninbuff = scaninbuff; + newline_for_fun = 0; + if (result) { + if (*result) { + buffer = *result; + buffpos = strlen(buffer); + buffmax = buffpos; + } else { + buffer = stralloc(LARGE_STR_MAX); + buffpos = 0; + buffmax = LARGE_STR_MAX; + } + scaninbuff = 1; + } + h = c; + /* start scanning */ + + while (*h && (!san || newline_for_fun || *h != '\n')) { + + if (*h == escapesym) { + h++; + FLUSHIBP; + h = scan_escape(h); + } else if (*h == controlsym && h[-1] == '\n') { + h++; + FLUSHIBP; + h = scan_request(h); + if (san && h[-1] == '\n') + h--; + } else if (mandoc_line + && *(h) && isupper(*(h)) + && *(h + 1) && islower(*(h + 1)) + && *(h + 2) && isspace(*(h + 2))) { + /* + * BSD imbedded command eg ".It Fl Ar arg1 Fl Ar + * arg2" + */ + FLUSHIBP; + h = scan_request(h); + if (san && h[-1] == '\n') + h--; + } else if (*h == nobreaksym && h[-1] == '\n') { + h++; + FLUSHIBP; + h = scan_request(h); + if (san && h[-1] == '\n') + h--; + } else { + int mx; + + if (h[-1] == '\n' && still_dd && isalnum(*h)) { + /* + * sometimes a .HP request is not followed by + * a .br request + */ + FLUSHIBP; + out_html("<DD>"); + curpos = 0; + still_dd = 0; + } + switch (*h) { + case '&': + intbuff[ibp++] = '&'; + intbuff[ibp++] = 'a'; + intbuff[ibp++] = 'm'; + intbuff[ibp++] = 'p'; + intbuff[ibp++] = ';'; + curpos++; + break; + case '<': + intbuff[ibp++] = '&'; + intbuff[ibp++] = 'l'; + intbuff[ibp++] = 't'; + intbuff[ibp++] = ';'; + curpos++; + break; + case '>': + intbuff[ibp++] = '&'; + intbuff[ibp++] = 'g'; + intbuff[ibp++] = 't'; + intbuff[ibp++] = ';'; + curpos++; + break; + case '"': + intbuff[ibp++] = '&'; + intbuff[ibp++] = 'q'; + intbuff[ibp++] = 'u'; + intbuff[ibp++] = 'o'; + intbuff[ibp++] = 't'; + intbuff[ibp++] = ';'; + curpos++; + break; + case '\n': + if (h[-1] == '\n' && fillout) { + intbuff[ibp++] = '<'; + intbuff[ibp++] = 'P'; + intbuff[ibp++] = '>'; + } + if (contained_tab && fillout) { + intbuff[ibp++] = '<'; + intbuff[ibp++] = 'B'; + intbuff[ibp++] = 'R'; + intbuff[ibp++] = '>'; + } + contained_tab = 0; + curpos = 0; + usenbsp = 0; + intbuff[ibp++] = '\n'; + break; + case '\t': + { + int curtab = 0; + + contained_tab = 1; + FLUSHIBP; + /* like a typewriter, not like TeX */ + tabstops[19] = curpos + 1; + while (curtab < maxtstop && tabstops[curtab] <= curpos) + curtab++; + if (curtab < maxtstop) { + if (!fillout) { + while (curpos < tabstops[curtab]) { + intbuff[ibp++] = ' '; + if (ibp > 480) { + FLUSHIBP; + } + curpos++; + } + } else { + out_html("<TT>"); + while (curpos < tabstops[curtab]) { + out_html(" "); + curpos++; + } + out_html("</TT>"); + } + } + } + break; + default: + if (*h == ' ' && (h[-1] == '\n' || usenbsp)) { + FLUSHIBP; + if (!usenbsp && fillout) { + out_html("<BR>"); + curpos = 0; + } + usenbsp = fillout; + if (usenbsp) + out_html(" "); + else + intbuff[ibp++] = ' '; + } else if (*h > 31 && *h < 127) + intbuff[ibp++] = *h; + else if (((unsigned char) (*h)) > 127) { + intbuff[ibp++] = '&'; + intbuff[ibp++] = '#'; + intbuff[ibp++] = '0' + ((unsigned char) (*h)) / 100; + intbuff[ibp++] = '0' + (((unsigned char) (*h)) % 100) / 10; + intbuff[ibp++] = '0' + ((unsigned char) (*h)) % 10; + intbuff[ibp++] = ';'; + } + curpos++; + break; + } + if (ibp > (MED_STR_MAX - 20)) + FLUSHIBP; + h++; + } + } + FLUSHIBP; + if (buffer) + buffer[buffpos] = '\0'; + if (san && *h) + h++; + newline_for_fun = exnewline_for_fun; + if (result) { + *result = buffer; + buffer = exbuffer; + buffpos = exbuffpos; + buffmax = exbuffmax; + scaninbuff = exscaninbuff; + } + return h; +} + + +static char * +scan_troff_mandoc(char *c, int san, char **result) +{ + char *ret, *end = c; + int oldval = mandoc_line; + + mandoc_line = 1; + while (*end && *end != '\n') { + end++; + } + + if (end > c + 2 + && ispunct(*(end - 1)) + && isspace(*(end - 2)) && *(end - 2) != '\n') { + /* + * Don't format lonely punctuation E.g. in "xyz ," format the + * xyz and then append the comma removing the space. + */ + *(end - 2) = '\n'; + ret = scan_troff(c, san, result); + *(end - 2) = *(end - 1); + *(end - 1) = ' '; + } else { + ret = scan_troff(c, san, result); + } + mandoc_line = oldval; + return ret; +} + +main(int argc, char **argv) +{ + FILE *f; + char *t; + int l, i; + char *buf; + char *h, *fullname; + STRDEF *stdf; + + t = NULL; + while ((i = getopt(argc, argv, "")) != EOF) { + switch (i) { + default: + usage(); + exit(EXIT_USAGE); + } + } + + if (argc != 2) { + usage(); + exit(EXIT_USAGE); + } + h = t = argv[1]; + i = 0; + + buf = read_man_page(h); + if (!buf) { + fprintf(stderr, "man2html: cannot read %s: %s\n", h, strerror(errno)); + exit(1); + } +#ifdef MAKEINDEX + idxfile = fopen(INDEXFILE, "a"); +#endif + stdf = &standardchar[0]; + i = 0; + while (stdf->nr) { + stdf->next = &standardchar[i]; + stdf = stdf->next; + i++; + } + chardef = &standardchar[0]; + + stdf = &standardstring[0]; + i = 0; + while (stdf->nr) { + stdf->next = &standardstring[i]; + stdf = stdf->next; + i++; + } + strdef = &standardstring[0]; + + intdef = &standardint[0]; + i = 0; + while (intdef->nr) { + intdef->next = &standardint[i]; + intdef = intdef->next; + i++; + } + intdef = &standardint[0]; + + defdef = NULL; + + scan_troff(buf + 1, 0, NULL); + + while (itemdepth || dl_set[itemdepth]) { + out_html("</DL>\n"); + if (dl_set[itemdepth]) + dl_set[itemdepth] = 0; + else if (itemdepth > 0) + itemdepth--; + } + + out_html(change_to_font(0)); + out_html(change_to_size(0)); + if (!fillout) { + fillout = 1; + out_html("</PRE>"); + } + out_html(NEWLINE); + + if (output_possible) { + /* for mosaic users */ + fputs("<HR>\n<A NAME=\"index\"> </A><H2>Index</H2>\n<DL>\n", stdout); + manidx[mip] = 0; + fputs(manidx, stdout); + if (subs) + fputs("</DL>\n", stdout); + fputs("</DL>\n", stdout); + print_sig(); + fputs("</BODY>\n</HTML>\n", stdout); + } else + fprintf(stderr, "man2html: no output produced\n"); +#ifdef MAKEINDEX + if (idxfile) + fclose(idxfile); +#endif + exit(EXIT_SUCCESS); +} diff --git a/support/texi2html b/support/texi2html index 2c61aa93..cc751785 100755 --- a/support/texi2html +++ b/support/texi2html @@ -1,4 +1,4 @@ -#!/usr/local/bin/perl +#!/usr/bin/perl 'di '; 'ig 00 '; #+############################################################################## @@ -54,8 +54,12 @@ extern int errno; #include "filecntl.h" #include "shell.h" +#include "pathexp.h" +#include "test.h" #include "builtins/common.h" +#include <glob/fnmatch.h> + #if !defined (STRLEN) # define STRLEN(s) ((s)[0] ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0) #endif @@ -99,10 +103,10 @@ static int test_error_return; #define test_exit(val) \ do { test_error_return = val; longjmp (test_exit_buf, 1); } while (0) +/* We have to use access(2) for machines running AFS, because it's + not a Unix file system. This may produce incorrect answers for + non-AFS files. I hate AFS. */ #if defined (AFS) - /* We have to use access(2) for machines running AFS, because it's - not a Unix file system. This may produce incorrect answers for - non-AFS files. I hate AFS. */ # define EACCESS(path, mode) access(path, mode) #else # define EACCESS(path, mode) test_eaccess(path, mode) @@ -113,8 +117,6 @@ static int argc; /* The number of arguments present in ARGV. */ static char **argv; /* The argument list. */ static int noeval; -static int unop (); -static int binop (); static int unary_operator (); static int binary_operator (); static int two_arguments (); @@ -143,6 +145,25 @@ test_syntax_error (format, arg) test_exit (SHELL_BOOLEAN (FALSE)); } +/* + * 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); +} + /* A wrapper for stat () which disallows pathnames that are empty strings and handles /dev/fd emulation on systems that don't have it. */ static int @@ -183,7 +204,7 @@ test_stat (path, finfo) /* Do the same thing access(2) does, but use the effective uid and gid, and don't make the mistake of telling root that any file is executable. */ -static int +int test_eaccess (path, mode) char *path; int mode; @@ -213,6 +234,7 @@ test_eaccess (path, mode) if (st.st_mode & mode) return (0); + errno = EACCES; return (-1); } @@ -223,22 +245,57 @@ test_eaccess (path, mode) #define unary_advance() do { advance (1); ++pos; } while (0) /* - * beyond - call when we're beyond the end of the argument list (an - * error condition) + * expr: + * or */ -static void -beyond () +static int +expr () { - test_syntax_error ("argument expected", (char *)NULL); + if (pos >= argc) + beyond (); + + return (FALSE ^ or ()); /* Same with this. */ } -/* Syntax error for when an integer argument was expected, but - something else was found. */ -static void -integer_expected_error (pch) - char *pch; +/* + * or: + * and + * and '-o' or + */ +static int +or () { - test_syntax_error ("%s: integer expression expected", pch); + int value, v2; + + value = and (); + while (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 (); + while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'a' && !argv[pos][2]) + { + advance (0); + v2 = and (); + return (value && v2); + } + return (value); } /* @@ -246,10 +303,11 @@ integer_expected_error (pch) * evaluates to true or false, respectively. * * term ::= - * '-'('a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'p'|'r'|'s'|'u'|'w'|'x') filename - * '-'('G'|'L'|'O'|'S') filename + * '-'('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 * <int> '-'(eq|ne|le|lt|ge|gt) <int> @@ -292,26 +350,14 @@ term () return (value); } -#if 1 /* are there enough arguments left that this could be dyadic? */ - if ((pos + 3 <= argc) && binop (argv[pos + 1])) + if ((pos + 3 <= argc) && test_binop (argv[pos + 1])) value = binary_operator (); -#else - /* If this is supposed to be a binary operator, make sure there are - enough arguments and fail if there are not. */ - if ((pos + 1 < argc) && binop (argv[pos+1])) - { - if (pos + 3 <= argc) - value = binary_operator (); - else - beyond (); - } -#endif /* Might be a switch type argument */ else if (argv[pos][0] == '-' && argv[pos][2] == '\0') { - if (unop (argv[pos][1])) + if (test_unop (argv[pos])) value = unary_operator (); else test_syntax_error ("%s: unary operator expected", argv[pos]); @@ -344,16 +390,30 @@ filecomp (s, t, op) } static int -arithcomp (s, t, op) +arithcomp (s, t, op, flags) char *s, *t; - int op; + int op, flags; { long 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); + } - 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); @@ -363,10 +423,10 @@ arithcomp (s, t, op) case LE: return (l <= r); case GE: return (l >= r); } + return (FALSE); } -#if defined (PATTERN_MATCHING) static int patcomp (string, pat, op) char *string, *pat; @@ -374,14 +434,59 @@ patcomp (string, pat, op) { int m; - m = fnmatch (pat, string, 0); - switch (op) + m = fnmatch (pat, string, FNMATCH_EXTFLAG); + 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') { - case EQ: return (m == 0); - case NE: return (m != 0); + 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 */ } -#endif /* PATTERN_MATCHING */ + static int binary_operator () @@ -390,19 +495,15 @@ binary_operator () char *w; w = argv[pos + 1]; - if (w[0] == '=' && (w[1] == '\0' || (w[1] == '=' && w[2] == '\0'))) - { - value = STREQ (argv[pos], argv[pos + 2]); - pos += 3; - return (value); - } - if ((w[0] == '>' || w[0] == '<') && w[1] == '\0') + 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 = (w[0] == '>') ? strcmp (argv[pos], argv[pos + 2]) > 0 - : strcmp (argv[pos], argv[pos + 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') { @@ -411,54 +512,15 @@ binary_operator () return (value); } #endif - if (w[0] == '!' && w[1] == '=' && w[2] == '\0') - { - value = STREQ (argv[pos], argv[pos + 2]) == 0; - pos += 3; - return (value); - } - if (w[0] != '-' || w[3] != '\0') + if ((w[0] != '-' || w[3] != '\0') || test_binop (w) == 0) { test_syntax_error ("%s: binary operator expected", w); /* NOTREACHED */ return (FALSE); } - w++; - if (w[1] == 't') - { - switch (w[0]) - { - case 'n': value = filecomp (argv[pos], argv[pos + 2], NT); break; - case 'o': value = filecomp (argv[pos], argv[pos + 2], OT); break; - case 'l': value = arithcomp (argv[pos], argv[pos + 2], LT); break; - case 'g': value = arithcomp (argv[pos], argv[pos + 2], GT); break; - default: test_syntax_error ("-%s: binary operator expected", w); - } - } - else if (w[0] == 'e') - { - switch (w[1]) - { - case 'q': value = arithcomp (argv[pos], argv[pos + 2], EQ); break; - case 'f': value = filecomp (argv[pos], argv[pos + 2], EF); break; - default: test_syntax_error ("-%s: binary operator expected", w); - } - } - else if (w[1] == 'e') - { - switch (w[0]) - { - case 'n': value = arithcomp (argv[pos], argv[pos + 2], NE); break; - case 'g': value = arithcomp (argv[pos], argv[pos + 2], GE); break; - case 'l': value = arithcomp (argv[pos], argv[pos + 2], LE); break; - default: test_syntax_error ("-%s: binary operator expected", w); - } - } - else - test_syntax_error ("-%s: binary operator expected", w); - + value = binary_test (w, argv[pos], argv[pos + 2], 0); pos += 3; return value; } @@ -466,49 +528,70 @@ binary_operator () static int unary_operator () { + char *op, *arg; long r; - struct stat stat_buf; - switch (argv[pos][1]) + 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') { - default: - return (FALSE); + advance (0); + if (pos < argc && legal_number (argv[pos], &r)) + { + advance (0); + return (unary_test (op, argv[pos - 1])); + } + else + return (unary_test (op, "1")); + } - /* All of the following unary operators use unary_advance (), which - checks to make sure that there is an argument, and then advances - pos right past it. This means that pos - 1 is the location of the - argument. */ + /* 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; +{ + long r; + struct stat stat_buf; + + switch (op[1]) + { case 'a': /* file exists in the file system? */ case 'e': - unary_advance (); - return (test_stat (argv[pos - 1], &stat_buf) == 0); + return (test_stat (arg, &stat_buf) == 0); case 'r': /* file is readable? */ - unary_advance (); - return (EACCESS (argv[pos - 1], R_OK) == 0); + return (EACCESS (arg, R_OK) == 0); case 'w': /* File is writeable? */ - unary_advance (); - return (EACCESS (argv[pos - 1], W_OK) == 0); + return (EACCESS (arg, W_OK) == 0); case 'x': /* File is executable? */ - unary_advance (); - return (EACCESS (argv[pos - 1], X_OK) == 0); + return (EACCESS (arg, X_OK) == 0); case 'O': /* File is owned by you? */ - unary_advance (); - return (test_stat (argv[pos - 1], &stat_buf) == 0 && + return (test_stat (arg, &stat_buf) == 0 && (uid_t) current_user.euid == (uid_t) stat_buf.st_uid); case 'G': /* File is owned by your group? */ - unary_advance (); - return (test_stat (argv[pos - 1], &stat_buf) == 0 && + return (test_stat (arg, &stat_buf) == 0 && (gid_t) current_user.egid == (gid_t) stat_buf.st_gid); + case 'N': + return (test_stat (arg, &stat_buf) == 0 && + stat_buf.st_atime <= stat_buf.st_mtime); + case 'f': /* File is a file? */ - unary_advance (); - if (test_stat (argv[pos - 1], &stat_buf) < 0) + if (test_stat (arg, &stat_buf) < 0) return (FALSE); /* -f is true if the given file exists and is a regular file. */ @@ -519,202 +602,118 @@ unary_operator () #endif /* !S_IFMT */ case 'd': /* File is a directory? */ - unary_advance (); - return (test_stat (argv[pos - 1], &stat_buf) == 0 && - (S_ISDIR (stat_buf.st_mode))); + return (test_stat (arg, &stat_buf) == 0 && (S_ISDIR (stat_buf.st_mode))); case 's': /* File has something in it? */ - unary_advance (); - return (test_stat (argv[pos - 1], &stat_buf) == 0 && - stat_buf.st_size > (off_t) 0); + return (test_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 - unary_advance (); - return (test_stat (argv[pos - 1], &stat_buf) == 0 && - S_ISSOCK (stat_buf.st_mode)); + return (test_stat (arg, &stat_buf) == 0 && S_ISSOCK (stat_buf.st_mode)); #endif /* S_ISSOCK */ case 'c': /* File is character special? */ - unary_advance (); - return (test_stat (argv[pos - 1], &stat_buf) == 0 && - S_ISCHR (stat_buf.st_mode)); + return (test_stat (arg, &stat_buf) == 0 && S_ISCHR (stat_buf.st_mode)); case 'b': /* File is block special? */ - unary_advance (); - return (test_stat (argv[pos - 1], &stat_buf) == 0 && - S_ISBLK (stat_buf.st_mode)); + return (test_stat (arg, &stat_buf) == 0 && S_ISBLK (stat_buf.st_mode)); case 'p': /* File is a named pipe? */ - unary_advance (); #ifndef S_ISFIFO return (FALSE); #else - return (test_stat (argv[pos - 1], &stat_buf) == 0 && - S_ISFIFO (stat_buf.st_mode)); + return (test_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? */ - unary_advance (); #if !defined (S_ISLNK) || !defined (HAVE_LSTAT) return (FALSE); #else - return ((argv[pos - 1][0] != '\0') && - (lstat (argv[pos - 1], &stat_buf) == 0) && - S_ISLNK (stat_buf.st_mode)); + 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? */ - unary_advance (); - return (test_stat (argv[pos - 1], &stat_buf) == 0 && - (stat_buf.st_mode & S_ISUID) != 0); + return (test_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISUID) != 0); case 'g': /* File is setgid? */ - unary_advance (); - return (test_stat (argv[pos - 1], &stat_buf) == 0 && - (stat_buf.st_mode & S_ISGID) != 0); + return (test_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISGID) != 0); case 'k': /* File has sticky bit set? */ - unary_advance (); #if !defined (S_ISVTX) /* This is not Posix, and is not defined on some Posix systems. */ return (FALSE); #else - return (test_stat (argv[pos - 1], &stat_buf) == 0 && - (stat_buf.st_mode & S_ISVTX) != 0); + return (test_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISVTX) != 0); #endif - case 't': /* File fd is a terminal? fd defaults to stdout. */ - advance (0); - if (pos < argc && legal_number (argv[pos], &r)) - { - advance (0); - return (isatty ((int)r)); - } - return (isatty (1)); + case 't': /* File fd is a terminal? */ + if (legal_number (arg, &r) == 0) + return (FALSE); + return (isatty ((int)r)); case 'n': /* True if arg has some length. */ - unary_advance (); - return (argv[pos - 1][0] != '\0'); + return (arg[0] != '\0'); case 'z': /* True if arg has no length. */ - unary_advance (); - return (argv[pos - 1][0] == '\0'); + return (arg[0] == '\0'); - case 'o': - unary_advance (); - return (minus_o_option_value (argv[pos - 1]) == 1); + case 'o': /* True if option `arg' is set. */ + return (minus_o_option_value (arg) == 1); } } -/* - * and: - * term - * term '-a' and - */ -static int -and () -{ - int value, v2; - - value = term (); - while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'a' && !argv[pos][2]) - { - advance (0); - v2 = and (); - return (value && v2); - } - return (value); -} - -/* - * or: - * and - * and '-o' or - */ -static int -or () -{ - int value, v2; - - value = and (); - while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'o' && !argv[pos][2]) - { - advance (0); - v2 = or (); - return (value || v2); - } - - return (value); -} - -/* - * expr: - * or - */ -static int -expr () -{ - if (pos >= argc) - beyond (); - - return (FALSE ^ or ()); /* Same with this. */ -} - -/* Return TRUE if S is one of the test command's binary operators. */ -static int -binop (s) - char *s; +/* Return TRUE if OP is one of the test command's binary operators. */ +int +test_binop (op) + char *op; { - char *t; - - if (s[0] == '=' && s[1] == '\0') + if (op[0] == '=' && op[1] == '\0') return (1); /* '=' */ - else if ((s[0] == '<' || s[0] == '>') && s[1] == '\0') /* string <, > */ + else if ((op[0] == '<' || op[0] == '>') && op[1] == '\0') /* string <, > */ return (1); - else if ((s[0] == '=' || s[0] == '!') && s[1] == '=' && s[2] == '\0') + else if ((op[0] == '=' || op[0] == '!') && op[1] == '=' && op[2] == '\0') return (1); /* `==' and `!=' */ #if defined (PATTERN_MATCHING) - else if (s[2] == '\0' && s[1] == '~' && (s[0] == '=' || s[0] == '!')) + else if (op[2] == '\0' && op[1] == '~' && (op[0] == '=' || op[0] == '!')) return (1); #endif - else if (s[0] != '-' || s[2] == '\0' || s[3] != '\0') + else if (op[0] != '-' || op[2] == '\0' || op[3] != '\0') return (0); else { - t = s + 1; - if (t[1] == 't') - switch (t[0]) + if (op[2] == 't') + switch (op[1]) { - case 'n': /* -nt */ - case 'o': /* -ot */ - case 'l': /* -lt */ - case 'g': /* -gt */ - return (1); - default: - return (0); + case 'n': /* -nt */ + case 'o': /* -ot */ + case 'l': /* -lt */ + case 'g': /* -gt */ + return (1); + default: + return (0); } - else if (t[0] == 'e') - switch (t[1]) + else if (op[1] == 'e') + switch (op[2]) { - case 'q': /* -eq */ - case 'f': /* -ef */ - return (1); - default: - return (0); + case 'q': /* -eq */ + case 'f': /* -ef */ + return (1); + default: + return (0); } - else if (t[1] == 'e') - switch (t[0]) + else if (op[2] == 'e') + switch (op[1]) { - case 'n': /* -ne */ - case 'l': /* -le */ - case 'g': /* -ge */ - return (1); - default: - return (0); + case 'n': /* -ne */ + case 'g': /* -ge */ + case 'l': /* -le */ + return (1); + default: + return (0); } else return (0); @@ -722,20 +721,23 @@ binop (s) } /* Return non-zero if OP is one of the test command's unary operators. */ -static int -unop (op) - int op; +int +test_unop (op) + char *op; { - switch (op) + if (op[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 'p': case 'r': case 's': case 't': case 'u': - case 'w': case 'x': case 'z': - case 'G': case 'L': case 'O': case 'S': - case 'o': + 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); } @@ -746,7 +748,7 @@ two_arguments () return (argv[pos + 1][0] == '\0'); else if (argv[pos][0] == '-' && argv[pos][2] == '\0') { - if (unop (argv[pos][1])) + if (test_unop (argv[pos])) return (unary_operator ()); else test_syntax_error ("%s: unary operator expected", argv[pos]); @@ -766,7 +768,7 @@ three_arguments () { int value; - if (binop (argv[pos+1])) + if (test_binop (argv[pos+1])) { value = binary_operator (); pos = argc; @@ -779,7 +781,7 @@ three_arguments () value = ONE_ARG_TEST(argv[pos]) || ONE_ARG_TEST(argv[pos+2]); pos = argc; } - else if (argv[pos][0] == '!' && !argv[pos][1]) + else if (argv[pos][0] == '!' && argv[pos][1] == '\0') { advance (1); value = !two_arguments (); @@ -0,0 +1,40 @@ +/* test.h -- external interface to the conditional command code. */ + +/* 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-1307, USA. */ + +#ifndef _TEST_H_ +#define _TEST_H_ + +#include "stdc.h" + +/* Values for the flags argument to binary_test */ +#define TEST_PATMATCH 0x01 +#define TEST_ARITHEXP 0x02 + +extern int test_eaccess __P((char *, int)); + +extern int test_unop __P((char *)); +extern int test_binop __P((char *)); + +extern int unary_test __P((char *, char *)); +extern int binary_test __P((char *, char *, char *, int)); + +extern int test_command __P((int, char **)); + +#endif /* _TEST_H_ */ diff --git a/tests/arith.right b/tests/arith.right index 54c087d2..c94da8b3 100644 --- a/tests/arith.right +++ b/tests/arith.right @@ -115,3 +115,8 @@ ok 7 7 4 +32767 +32768 +131072 +2147483647 +1 diff --git a/tests/arith.tests b/tests/arith.tests index 5f6298ca..d37e77f7 100644 --- a/tests/arith.tests +++ b/tests/arith.tests @@ -213,3 +213,10 @@ do done echo $x + +# exponentiation +echo $(( 2**15 - 1)) +echo $(( 2**(16-1))) +echo $(( 2**16*2 )) +echo $(( 2**31-1)) +echo $(( 2**0 )) diff --git a/tests/array-at-star b/tests/array-at-star new file mode 100755 index 00000000..80f039d2 --- /dev/null +++ b/tests/array-at-star @@ -0,0 +1,120 @@ +# test the expansion of ${array[@]} and ${array[*]}, both quoted and +# unquoted. the expansions should be exactly analogous to the +# expansions of $@ and $* quoted and unquoted +A=(a b) + +recho "${A[*]}" + +# If IFS is null, the parameters are joined without separators +IFS='' +recho "${A[*]}" + +# If IFS is unset, the parameters are separated by spaces +unset IFS +recho "${A[*]}" + +recho "${A[@]}" +recho ${A[@]} + +IFS='/' +A=(bob 'tom dick harry' joe) +set ${A[*]} +recho $# +recho $1 +recho $2 +recho $3 + +A=(bob 'tom dick harry' joe) +set ${A[*]} +recho $# +recho $1 +recho $2 +recho $3 + +A=(bob 'tom dick harry' joe) +set ${A[@]} +recho $# +recho $1 +recho $2 +recho $3 + +A=(bob 'tom dick harry' joe) +set ${A[@]} +recho $# +recho $1 +recho $2 +recho $3 + +# according to POSIX.2, unquoted $* should expand to multiple words if +# $IFS is null, just like unquoted $@ +IFS='' +A=(bob 'tom dick harry' joe) +set "${A[*]}" +recho $# +recho $1 +recho $2 +recho $3 + +A=(bob 'tom dick harry' joe) +set ${A[*]} +recho $# +recho $1 +recho $2 +recho $3 + +A=(bob 'tom dick harry' joe) +set ${A[@]} +recho $# +recho $1 +recho $2 +recho $3 + +# if IFS is unset, the individual positional parameters are split on +# " \t\n" if $* or $@ are unquoted +unset IFS +A=(bob 'tom dick harry' joe) +set ${A[*]} +recho $# +recho $1 +recho $2 +recho $3 + +A=(bob 'tom dick harry' joe) +set ${A[@]} +recho $# +recho $1 +recho $2 +recho $3 + +# but not for "$@" or "$*" +A=(bob 'tom dick harry' joe) +set "${A[*]}" +recho $# +recho $1 +recho $2 +recho $3 + +A=(bob 'tom dick harry' joe) +set "${A[@]}" +recho $# +recho $1 +recho $2 +recho $3 + +# these should both expand the value of A to multiple words +A=(a b c d e) +IFS="" +recho ${A[@]} +recho "${A[@]}" + +# this example is straight from the POSIX.2 rationale and adapted to arrays +A=(foo bar bam) + +recho "${A[@]}" +recho "${A[*]}" + +unset IFS + +recho "${A[@]}" +recho ${A[@]} +recho "${A[*]}" diff --git a/tests/array.right b/tests/array.right index 73674589..65fb3c9f 100644 --- a/tests/array.right +++ b/tests/array.right @@ -22,6 +22,8 @@ declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression")' declare -ar c='()' declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression")' declare -ar c='()' +readonly -a a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression")' +readonly -a c='()' ./array.tests: declare: e: cannot assign to array variables in this way a test declare -a DIRSTACK='()' @@ -52,6 +54,8 @@ declare -a f='([0]="" [1]="bdef" [2]="hello world" [3]="test" [4]="ninth element ./array.tests: declare: c: cannot destroy array variables in this way this of this is a test of read using arrays +this test +this is a test of arrays declare -a DIRSTACK='()' declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression")' declare -a b='([0]="this" [1]="is" [2]="a" [3]="test" [4]="" [5]="/etc/passwd")' @@ -94,4 +98,6 @@ bin grep [ 123 ] * 6 7 9 6 7 9 5 +length = 3 +value = new1 new2 new3 ./array.tests: narray: unbound variable diff --git a/tests/array.tests b/tests/array.tests index 0b030805..6e56d5a9 100644 --- a/tests/array.tests +++ b/tests/array.tests @@ -62,8 +62,13 @@ 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" @@ -112,6 +117,15 @@ this is a test of read using arrays echo ${rv[0]} ${rv[4]} echo ${rv[@]} +# the variable should be converted to an array when `read -a' is done +vv=1 +read -a vv <<! +this is a test of arrays +! +echo ${vv[0]} ${vv[3]} +echo ${vv[@]} +unset vv + declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)' export rv @@ -196,6 +210,13 @@ echo ${iarray[@]} iarray[4]=4+1 echo ${iarray[@]} +# make sure assignment using the compound assignment syntax removes all +# of the old elements from the array value +barray=(old1 old2 old3 old4 old5) +barray=(new1 new2 new3) +echo "length = ${#barray[@]}" +echo "value = ${barray[*]}" + # make sure the array code behaves correctly with respect to unset variables set -u ( echo ${#narray[4]} ) diff --git a/tests/array2.right b/tests/array2.right new file mode 100644 index 00000000..b5145c25 --- /dev/null +++ b/tests/array2.right @@ -0,0 +1,74 @@ +argv[1] = <a b> +argv[1] = <ab> +argv[1] = <a b> +argv[1] = <a> +argv[2] = <b> +argv[1] = <a> +argv[2] = <b> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom dick harry> +argv[1] = <joe> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom dick harry> +argv[1] = <joe> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom dick harry> +argv[1] = <joe> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom dick harry> +argv[1] = <joe> +argv[1] = <1> +argv[1] = <bobtom dick harryjoe> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom dick harry> +argv[1] = <joe> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom dick harry> +argv[1] = <joe> +argv[1] = <5> +argv[1] = <bob> +argv[1] = <tom> +argv[1] = <dick> +argv[1] = <5> +argv[1] = <bob> +argv[1] = <tom> +argv[1] = <dick> +argv[1] = <1> +argv[1] = <bob> +argv[2] = <tom> +argv[3] = <dick> +argv[4] = <harry> +argv[5] = <joe> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom> +argv[2] = <dick> +argv[3] = <harry> +argv[1] = <joe> +argv[1] = <a> +argv[2] = <b> +argv[3] = <c> +argv[4] = <d> +argv[5] = <e> +argv[1] = <a> +argv[2] = <b> +argv[3] = <c> +argv[4] = <d> +argv[5] = <e> +argv[1] = <foo> +argv[2] = <bar> +argv[3] = <bam> +argv[1] = <foobarbam> +argv[1] = <foo> +argv[2] = <bar> +argv[3] = <bam> +argv[1] = <foo> +argv[2] = <bar> +argv[3] = <bam> +argv[1] = <foo bar bam> diff --git a/tests/builtins.right b/tests/builtins.right index 5cf5875e..5ed2b15f 100644 --- a/tests/builtins.right +++ b/tests/builtins.right @@ -1,3 +1,5 @@ +alias: 0 +alias: 0 a end-1 a @@ -47,6 +49,8 @@ xxx u=rwx,g=rx,o=rx 002 u=rwx,g=rwx,o=rx +umask 002 +umask -S u=rwx,g=rwx,o=rx u=rwx,g=rwx,o=rwx enable . enable : @@ -81,9 +85,11 @@ enable unset enable -n test worked enable test worked specialname +-specialname FOO=BAR FOO=BAR hash: hash table empty +0 AVAR foo in source.sub2, calling return @@ -99,6 +105,9 @@ m n o p /tmp/bash-dir-a /tmp/bash-dir-a /tmp/bash-dir-a +./source5.sub: /tmp/source-notthere: No such file or directory +after bad source 1 +./source5.sub: /tmp/source-notthere: No such file or directory AVAR foo foo @@ -107,7 +116,12 @@ foo foo AVAR foo +declare -x foo="" +declare -x FOO="\$\$" +./builtins.tests: declare: FOO: not found +declare -x FOO="\$\$" ok ok ./builtins.tests: kill: bad signal number: 4096 1 +./builtins.tests: exit: bad non-numeric arg `status' diff --git a/tests/builtins.tests b/tests/builtins.tests index 0d80239b..9073ed55 100644 --- a/tests/builtins.tests +++ b/tests/builtins.tests @@ -4,6 +4,18 @@ set +o posix ulimit -c 0 2>/dev/null +# alias/unalias tests + +unalias -a +# this should return success, according to POSIX.2 +alias +echo alias: $? +alias foo=bar +unalias foo +# this had better return success, according to POSIX.2 +alias +echo alias: $? + # check that break breaks loops for i in a b c; do echo $i; break; echo bad-$i; done echo end-1 @@ -80,6 +92,8 @@ umask -S umask -S u=rwx,g=rwx,o=rx >/dev/null # 002 umask umask -S +umask -p +umask -p -S umask 0 umask -S umask ${mask} # restore original mask @@ -107,10 +121,11 @@ esac # test options to exec (exec -a specialname ${THIS_SH} -c 'echo $0' ) +(exec -l -a specialname ${THIS_SH} -c 'echo $0' ) # test `clean' environment. if /bin/sh is bash, and the script version of # printenv is run, there will be variables in the environment that bash -# sets on startup. -(export FOO=BAR ; exec -c printenv ) | grep FOO +# sets on startup. Also test code that prefixes argv[0] with a dash. +(export FOO=BAR ; exec -c -l printenv ) | grep FOO (FOO=BAR exec -c printenv ) | grep FOO (export FOO=BAR ; exec printenv ) | grep FOO @@ -120,24 +135,35 @@ esac hash -r hash +# this had better succeed, since command -p guarantees we will find the +# standard utilties +command -p hash rm + # check out source/. +# sourcing a zero-length-file had better not be an error +rm -f /tmp/zero-length-file +cp /dev/null /tmp/zero-length-file +. /tmp/zero-length-file +echo $? +rm /tmp/zero-length-file + AVAR=AVAR -. ./source.sub1 -AVAR=foo . ./source.sub1 +. ./source1.sub +AVAR=foo . ./source1.sub -. ./source.sub2 +. ./source2.sub echo $? set -- a b c -. ./source.sub3 +. ./source3.sub # make sure source with arguments does not change the shell's positional # parameters, but that the sourced file sees the arguments as its # positional parameters echo "$@" -. ./source.sub3 x y z +. ./source3.sub x y z echo "$@" # but if the sourced script sets the positional parameters explicitly, they @@ -146,25 +172,28 @@ echo "$@" # find the script echo "$@" shopt -u sourcepath -. source.sub4 +. source4.sub echo "$@" # this is complicated when the sourced scripts gets its own positional # parameters from arguments to `.' set -- a b c echo "$@" -. source.sub4 x y z +. source4.sub x y z echo "$@" # test out cd and $CDPATH ${THIS_SH} ./builtins.sub1 +# test behavior of `.' when given a non-existant file argument +${THIS_SH} ./source5.sub + # in posix mode, assignment statements preceding special builtins are # reflected in the shell environment. `.' and `eval' need special-case # code. set -o posix echo $AVAR -AVAR=foo . ./source.sub1 +AVAR=foo . ./source1.sub echo $AVAR AVAR=AVAR @@ -176,9 +205,26 @@ AVAR=AVAR echo $AVAR AVAR=foo : echo $AVAR +set +o posix + +# but assignment statements preceding `export' are always reflected in +# the environment +foo="" export foo +declare -p foo +unset foo + +# assignment statements preceding `declare' should be displayed correctly, +# but not persist after the command +FOO='$$' declare -p FOO +declare -p FOO +unset FOO + +# except for `declare -x', which should be equivalent to `export' +FOO='$$' declare -x FOO +declare -p FOO +unset FOO # test out kill -l. bash versions prior to 2.01 did `kill -l num' wrong -set +o posix sigone=$(kill -l | sed -n 's:^ 1) *\([^ ]*\)[ ].*$:\1:p') case "$(kill -l 1)" in @@ -186,6 +232,13 @@ ${sigone/SIG/}) echo ok;; *) echo oops -- kill -l failure;; esac +# kill -l and trap -l should display exactly the same output +sigonea=$(trap -l | sed -n 's:^ 1) *\([^ ]*\)[ ].*$:\1:p') + +if [ "$sigone" != "$sigonea" ]; then + echo oops -- kill -l and trap -l differ +fi + # POSIX.2 says that exit statuses > 128 are mapped to signal names by # subtracting 128 so you can find out what signal killed a process case "$(kill -l $(( 128 + 1)) )" in @@ -199,3 +252,8 @@ kill -l 4096 # kill -l NAME should return the signal number kill -l ${sigone/SIG/} + +# this must be last -- it is a fatal error +exit status + +echo after bad exit diff --git a/tests/cond.right b/tests/cond.right new file mode 100644 index 00000000..4e2a07a6 --- /dev/null +++ b/tests/cond.right @@ -0,0 +1,31 @@ +returns: 0 +returns: 0 +returns: 1 +returns: 0 +returns: 1 +returns: 0 +returns: 0 +returns: 1 +returns: 1 +returns: 1 +returns: 1 +returns: 0 +returns: 0 +returns: 0 +returns: 1 +returns: 0 +returns: 1 +returns: 0 +returns: 1 +returns: 1 +returns: 0 +./cond.tests: [[: 4+: syntax error: operand expected (error token is "+") +returns: 1 +returns: 0 +returns: 0 +returns: 1 +returns: 0 +returns: 0 +returns: 1 +returns: 0 +ok diff --git a/tests/cond.tests b/tests/cond.tests new file mode 100755 index 00000000..4f3cbdff --- /dev/null +++ b/tests/cond.tests @@ -0,0 +1,142 @@ +# +# the test/[ code is tested elsewhere, and the [[...]] just uses the same +# code. this tests the special features of [[...]] +# +TDIR=/usr/homes/chet + +# this one is straight out of the ksh88 book +[[ foo > 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: $? + +# 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 diff --git a/tests/dirstack.right b/tests/dirstack.right deleted file mode 100644 index b5803d5e..00000000 --- a/tests/dirstack.right +++ /dev/null @@ -1,51 +0,0 @@ -./dirstack.tests: pushd: no other directory -./dirstack.tests: popd: directory stack empty -./dirstack.tests: pushd: -m: bad argument -pushd: usage: pushd [dir | +N | -N] [-n] -./dirstack.tests: popd: -m: bad argument -popd: usage: popd [+N | -N] [-n] -./dirstack.tests: dirs: -m: bad argument -dirs: usage: dirs [-clpv] [+N] [-N] -ok -/usr / -/usr / -/usr / -/usr / -/usr / -/ -/usr / -/etc /usr / -/etc /usr / -/etc /usr / - 0 /etc - 1 /usr - 2 / -/usr /etc / -/etc /usr / -/tmp /etc /usr / -/tmp -/tmp -/usr -/usr -./dirstack.tests: dirs: 9: bad directory stack index -./dirstack.tests: dirs: 9: bad directory stack index -./dirstack.tests: pushd: +9: bad directory stack index -./dirstack.tests: pushd: -9: bad directory stack index -./dirstack.tests: popd: +9: bad directory stack index -./dirstack.tests: popd: -9: bad directory stack index -/tmp /etc / -/tmp /etc / -/tmp /etc / -/tmp /usr /etc / -/tmp -/tmp /usr /etc / -/tmp /usr /etc / -/tmp -/tmp /bin /etc / -/tmp -/tmp /bin / -/tmp -/bin / /tmp -/bin / /tmp -/bin -/bin diff --git a/tests/dollar-at-star b/tests/dollar-at-star new file mode 100755 index 00000000..307bf311 --- /dev/null +++ b/tests/dollar-at-star @@ -0,0 +1,119 @@ +# first, let's start with the basics + +recho "$@" +recho "$*" + +recho $@ +recho $* + +set a b + +recho "$*" + +# If IFS is null, the parameters are joined without separators +IFS='' +recho "$*" + +# If IFS is unset, the parameters are separated by spaces +unset IFS +recho "${*}" + +recho "$@" +recho $@ + +IFS='/' +set bob 'tom dick harry' joe +set $* +recho $# +recho $1 +recho $2 +recho $3 + +set bob 'tom dick harry' joe +set ${*} +recho $# +recho $1 +recho $2 +recho $3 + +set bob 'tom dick harry' joe +set $@ +recho $# +recho $1 +recho $2 +recho $3 + +set bob 'tom dick harry' joe +set ${@} +recho $# +recho $1 +recho $2 +recho $3 + +# according to POSIX.2, unquoted $* should expand to multiple words if +# $IFS is null, just like unquoted $@ +IFS='' +set bob 'tom dick harry' joe +set $* +recho $# +recho $1 +recho $2 +recho $3 + +set bob 'tom dick harry' joe +set $@ +recho $# +recho $1 +recho $2 +recho $3 + +# if IFS is unset, the individual positional parameters are split on +# " \t\n" if $* or $@ are unquoted +unset IFS +set bob 'tom dick harry' joe +set $* +recho $# +recho $1 +recho $2 +recho $3 + +set bob 'tom dick harry' joe +set $@ +recho $# +recho $1 +recho $2 +recho $3 + +# but not for "$@" or "$*" +set bob 'tom dick harry' joe +set "$*" +recho $# +recho $1 +recho $2 +recho $3 + +set bob 'tom dick harry' joe +set "$@" +recho $# +recho $1 +recho $2 +recho $3 + +# POSIX.2 says these should both expand the positional parameters +# to multiple words +set a b c d e +IFS="" +recho $@ +recho "$@" + +# this example is straight from the POSIX.2 rationale +set foo bar bam + +recho "$@" +recho "$*" + +unset IFS + +recho "$@" +recho $@ +recho "$*" diff --git a/tests/dollar-at.sh b/tests/dollar-at.sh deleted file mode 100755 index c3004d50..00000000 --- a/tests/dollar-at.sh +++ /dev/null @@ -1 +0,0 @@ -recho "$@" diff --git a/tests/dollar-star.sh b/tests/dollar-star.sh deleted file mode 100755 index 8f8372e4..00000000 --- a/tests/dollar-star.sh +++ /dev/null @@ -1,9 +0,0 @@ -recho "$*" - -# If IFS is null, the parameters are joined without separators -IFS='' -recho "$*" - -# If IFS is unset, the parameters are separated by spaces -unset IFS -recho "${*}" diff --git a/tests/dollar.right b/tests/dollar.right index 84609ec6..d7cb9148 100644 --- a/tests/dollar.right +++ b/tests/dollar.right @@ -1,5 +1,73 @@ +argv[1] = <> argv[1] = <a b> argv[1] = <ab> argv[1] = <a b> argv[1] = <a> argv[2] = <b> +argv[1] = <a> +argv[2] = <b> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom dick harry> +argv[1] = <joe> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom dick harry> +argv[1] = <joe> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom dick harry> +argv[1] = <joe> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom dick harry> +argv[1] = <joe> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom dick harry> +argv[1] = <joe> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom dick harry> +argv[1] = <joe> +argv[1] = <5> +argv[1] = <bob> +argv[1] = <tom> +argv[1] = <dick> +argv[1] = <5> +argv[1] = <bob> +argv[1] = <tom> +argv[1] = <dick> +argv[1] = <1> +argv[1] = <bob> +argv[2] = <tom> +argv[3] = <dick> +argv[4] = <harry> +argv[5] = <joe> +argv[1] = <3> +argv[1] = <bob> +argv[1] = <tom> +argv[2] = <dick> +argv[3] = <harry> +argv[1] = <joe> +argv[1] = <a> +argv[2] = <b> +argv[3] = <c> +argv[4] = <d> +argv[5] = <e> +argv[1] = <a> +argv[2] = <b> +argv[3] = <c> +argv[4] = <d> +argv[5] = <e> +argv[1] = <foo> +argv[2] = <bar> +argv[3] = <bam> +argv[1] = <foobarbam> +argv[1] = <foo> +argv[2] = <bar> +argv[3] = <bam> +argv[1] = <foo> +argv[2] = <bar> +argv[3] = <bam> +argv[1] = <foo bar bam> diff --git a/tests/dstack.right b/tests/dstack.right new file mode 100644 index 00000000..fcd04b87 --- /dev/null +++ b/tests/dstack.right @@ -0,0 +1,55 @@ +./dstack.tests: pushd: /tmp/xxx-notthere: No such file or directory +./dstack.tests: pushd: no other directory +./dstack.tests: popd: directory stack empty +./dstack.tests: pushd: -m: bad argument +pushd: usage: pushd [dir | +N | -N] [-n] +./dstack.tests: popd: -m: bad argument +popd: usage: popd [+N | -N] [-n] +./dstack.tests: dirs: -m: bad argument +dirs: usage: dirs [-clpv] [+N] [-N] +./dstack.tests: dirs: unknown option: 7 +dirs: usage: dirs [-clpv] [+N] [-N] +/ +ok +/usr / +/usr / +/usr / +/usr / +/usr / +/ +/usr / +/etc /usr / +/etc /usr / +/etc /usr / + 0 /etc + 1 /usr + 2 / +/usr /etc / +/etc /usr / +/tmp /etc /usr / +/tmp +/tmp +/usr +/usr +./dstack.tests: dirs: 9: bad directory stack index +./dstack.tests: dirs: 9: bad directory stack index +./dstack.tests: pushd: +9: bad directory stack index +./dstack.tests: pushd: -9: bad directory stack index +./dstack.tests: popd: +9: bad directory stack index +./dstack.tests: popd: -9: bad directory stack index +/tmp /etc / +/tmp /etc / +/tmp /etc / +/tmp /usr /etc / +/tmp +/tmp /usr /etc / +/tmp /usr /etc / +/tmp +/tmp /bin /etc / +/tmp +/tmp /bin / +/tmp +/bin / /tmp +/bin / /tmp +/bin +/bin diff --git a/tests/dirstack.tests b/tests/dstack.tests index e384615d..6c4cef14 100644 --- a/tests/dirstack.tests +++ b/tests/dstack.tests @@ -1,4 +1,10 @@ +export LC_ALL=C +export LANG=C + dirs -c +# error -- nonexistant directory +pushd /tmp/xxx-notthere + # errors -- empty stack pushd popd @@ -7,6 +13,7 @@ popd pushd -m popd -m dirs -m +dirs 7 MYDIR=$PWD unalias cd 2>/dev/null @@ -14,6 +21,7 @@ unalias cd 2>/dev/null unalias -a command cd -P / +command pwd -P # better be `/' case "$OLDPWD" in $MYDIR) echo ok ;; diff --git a/tests/dstack2.right b/tests/dstack2.right new file mode 100644 index 00000000..d682a27f --- /dev/null +++ b/tests/dstack2.right @@ -0,0 +1,24 @@ +expect ~1 +~1 +/usr / +/tmp /usr / +/tmp /usr / +these lines should be the same +/tmp +/tmp /tmp +these lines should be the same +/usr +/usr /usr +these lines should be the same +/ +/ / +these lines should be the same +/tmp +/tmp /tmp +these lines should be the same +/usr +/usr /usr + 1 /usr +these lines should be the same +/ +/ / diff --git a/tests/dstack2.tests b/tests/dstack2.tests new file mode 100644 index 00000000..d902bffb --- /dev/null +++ b/tests/dstack2.tests @@ -0,0 +1,33 @@ +cd / + +echo expect '~1' +echo ~1 + +pushd /usr +pushd /tmp +dirs + +echo these lines should be the same +dirs +0 +echo ~0 ${DIRSTACK[0]} +echo these lines should be the same +dirs +1 +echo ~1 ${DIRSTACK[1]} +echo these lines should be the same +dirs +2 +echo ~2 ${DIRSTACK[2]} + +NDIRS=$(( ${#DIRSTACK[@]} - 1 )) + +echo these lines should be the same +dirs -2 +echo ~-2 ${DIRSTACK[NDIRS-2]} + +echo these lines should be the same +dirs -1 +echo ~-1 ${DIRSTACK[NDIRS-1]} +dirs -v -1 + +echo these lines should be the same +dirs -0 +echo ~-0 ${DIRSTACK[NDIRS]} diff --git a/tests/errors.right b/tests/errors.right index 41da642b..4c49ec92 100644 --- a/tests/errors.right +++ b/tests/errors.right @@ -1,15 +1,26 @@ +./errors.tests: alias: illegal option: -x +alias: usage: alias [-p] [name[=value] ... ] +./errors.tests: unalias: illegal option: -x +unalias: usage: unalias [-a] [name ...] +./errors.tests: alias: `hoowah' not found +./errors.tests: unalias: `hoowah': not an alias ./errors.tests: `1': not a valid identifier declare -fr func ./errors.tests: func: readonly function +./errors.tests: unset: illegal option: -x +unset: usage: unset [-f] [-v] [name ...] ./errors.tests: unset: func: cannot unset: readonly function ./errors.tests: declare: func: readonly function ./errors.tests: unset: XPATH: cannot unset: readonly variable ./errors.tests: unset: `/bin/sh': not a valid identifier +./errors.tests: unset: cannot simultaneously unset a function and a variable ./errors.tests: declare: unknown option: `-z' declare: usage: declare [-afFrxi] [-p] name[=value] ... ./errors.tests: declare: `-z': not a valid identifier ./errors.tests: declare: `/bin/sh': not a valid identifier ./errors.tests: declare: cannot use `-f' to make functions +./errors.tests: exec: illegal option: -i +exec: usage: exec [-cl] [-a name] file [redirection ...] ./errors.tests: export: XPATH: not a function ./errors.tests: break: only meaningful in a `for', `while', or `until' loop ./errors.tests: continue: only meaningful in a `for', `while', or `until' loop @@ -17,12 +28,17 @@ declare: usage: declare [-afFrxi] [-p] name[=value] ... ./errors.tests: shift: too many arguments ./errors.tests: let: expression expected ./errors.tests: local: can only be used in a function +./errors.tests: logout: not login shell: use `exit' ./errors.tests: hash: notthere: not found +./errors.tests: hash: illegal option: -v +hash: usage: hash [-r] [-p pathname] [name ...] ./errors.tests: hash: hashing disabled ./errors.tests: export: `AA[4]': not a valid identifier ./errors.tests: readonly: `AA[4]': not a valid identifier ./errors.tests: [-2]: bad array subscript ./errors.tests: AA: readonly variable +./errors.tests: AA: readonly variable +./errors.tests: readonly: ZZZ: cannot assign to array variables in this way ./errors.tests: shift: shift count must be <= $# ./errors.tests: shift: shift count must be >= 0 ./errors.tests: shopt: no_such_option: unknown shell option name @@ -30,8 +46,8 @@ declare: usage: declare [-afFrxi] [-p] name[=value] ... ./errors.tests: umask: `09' is not an octal number from 000 to 777 ./errors.tests: umask: bad character in symbolic mode: : ./errors.tests: umask: bad symbolic mode operator: : -./errors.tests: umask: illegal option: -p -umask: usage: umask [-S] [mode] +./errors.tests: umask: illegal option: -i +umask: usage: umask [-p] [-S] [mode] ./errors.tests: VAR: readonly variable ./errors.tests: declare: VAR: readonly variable ./errors.tests: declare: VAR: readonly variable @@ -41,7 +57,10 @@ umask: usage: umask [-S] [mode] ./errors.tests: command substitution: line 1: syntax error near unexpected token `done' ./errors.tests: command substitution: line 1: ` for z in 1 2 3; done ' ./errors.tests: cd: HOME not set +./errors.tests: cd: /tmp/xyz.bash: No such file or directory ./errors.tests: cd: OLDPWD not set +./errors.tests: cd: /bin/sh: Not a directory +./errors.tests: cd: /tmp/cd-notthere: No such file or directory ./errors.tests: .: filename argument required .: usage: . filename ./errors.tests: source: filename argument required @@ -52,12 +71,18 @@ source: usage: source filename ./errors.tests: enable: sh: not a shell builtin ./errors.tests: enable: bash: not a shell builtin ./errors.tests: shopt: cannot set and unset shell options simultaneously +./errors.tests: read: illegal option: -t +read: usage: read [-r] [-p prompt] [-a array] [-e] [name ...] ./errors.tests: read: `/bin/sh': not a valid identifier ./errors.tests: VAR: readonly variable +./errors.tests: readonly: illegal option: -x +readonly: usage: readonly [-anf] [name ...] or readonly -p ./errors.tests: eval: illegal option: -i eval: usage: eval [arg ...] ./errors.tests: command: illegal option: -i command: usage: command [-pVv] command [arg ...] +./errors.tests: /bin/sh + 0: syntax error: operand expected (error token is "/bin/sh + 0") +./errors.tests: /bin/sh + 0: syntax error: operand expected (error token is "/bin/sh + 0") ./errors.tests: trap: NOSIG: not a signal specification ./errors.tests: trap: illegal option: -s trap: usage: trap [arg] [signal_spec ...] or trap -l @@ -70,4 +95,7 @@ trap: usage: trap [arg] [signal_spec ...] or trap -l ./errors.tests: fg: no job control ./errors.tests: kill: -s requires an argument ./errors.tests: kill: bad signal spec `S' +./errors.tests: kill: `': not a pid or valid job spec +kill: usage: kill [-s sigspec | -n signum | -sigspec] [pid | job]... or kill -l [sigspec] +./errors.tests: set: trackall: unknown option name ./errors.tests: `!!': not a valid identifier diff --git a/tests/errors.tests b/tests/errors.tests index 61751f56..ec0c31c2 100644 --- a/tests/errors.tests +++ b/tests/errors.tests @@ -10,6 +10,15 @@ LC_MESSAGES=C set +e set +o posix +# various alias/unalias errors + +# at some point, this may mean to `export' an alias, like ksh, but +# for now it is an error +alias -x foo=barz +unalias -x fooaha +alias hoowah +unalias hoowah + # the iteration variable must be a valid identifier for 1 in a b c; do echo $1; done @@ -26,6 +35,9 @@ func() echo bar } +# bad option +unset -x func + # cannot unset readonly functions or variables unset -f func # or make them not readonly @@ -39,6 +51,9 @@ unset -v XPATH # cannot unset invalid identifiers unset /bin/sh +# cannot unset function and variable at the same time +unset -f -v SHELL + # bad option declare -z # cannot declare invalid identifiers @@ -49,6 +64,9 @@ declare /bin/sh # it cannot be used with `declare' declare -f func='() { echo "this is func"; }' +# bad option to exec -- this should not exit the script +exec -i /bin/sh + # try to export -f something that is not a function -- this should be # an error, not create an `invisible function' export -f XPATH @@ -74,9 +92,15 @@ let # local outside a function is an error local +# logout of a non-login shell is an error +logout + # try to hash a non-existant command hash notthere +# bad option to hash, although it may mean `verbose' at some future point +hash -v + # turn off hashing, then try to hash something set +o hashall hash -p ${THIS_SH} ${THIS_SH##*/} @@ -92,6 +116,13 @@ unset AA[-2] declare -r AA AA=( one two three ) +# make sure `readonly -n' doesn't turn off readonly status +readonly -n AA +AA=(one two three) + +# try to assign a readonly array with bad assignment syntax +readonly -a ZZZ=bbb + # bad counts to `shift' shopt -s shift_verbose shift $(( $# + 5 )) @@ -105,9 +136,9 @@ shopt no_such_option umask 09 umask -S u=rwx:g=rwx:o=rx >/dev/null # 002 umask -S u:rwx,g:rwx,o:rx >/dev/null # 002 -# this may behave identically to umask without arguments in the future, -# but for now it is an error -umask -p + +# at some point, this may mean `invert', but for now it is an error +umask -i # assignment to a readonly variable in environment VAR=4 @@ -129,7 +160,12 @@ for VAR in 1 2 3 ; do echo $VAR; done # various `cd' errors ( unset HOME ; cd ) -( unset OLDPWD ; cd - ) +( HOME=/tmp/xyz.bash ; cd ) +# errors from cd +cd - +cd /bin/sh # error - not a directory +OLDPWD=/tmp/cd-notthere +cd - # various `source/.' errors . @@ -147,16 +183,26 @@ enable sh bash # try to set and unset shell options simultaneously shopt -s -u checkhash +# someday, this may give `read' a timeout, but for now it is an error +read -t var < /dev/null + # try to read into an invalid identifier read /bin/sh < /dev/null # try to read into a readonly variable read VAR < /dev/null +# bad option to readonly/export +readonly -x foo + # someday these may mean something, but for now they're errors eval -i "echo $-" command -i "echo $-" +# this caused a core dump in bash-2.01 (fixed in bash-2.01.1) +eval echo \$[/bin/sh + 0] +eval echo '$((/bin/sh + 0))' + # error to list trap for an unknown signal trap -p NOSIG @@ -191,6 +237,13 @@ fg kill -s # bad argument kill -S +# null argument +kill -INT '' +# argument required +kill -INT + +# bad shell option names +set -o trackall # bash is not ksh # this must be last! # in posix mode, a function name must be a valid identifier diff --git a/tests/execscript.right b/tests/exec.right index 1b64033d..bd447c30 100644 --- a/tests/execscript.right +++ b/tests/exec.right @@ -1,9 +1,9 @@ -before execscript.sub: one two three -calling execscript.sub +before exec1.sub: one two three +calling exec1.sub aa bb cc dd ee -after execscript.sub with args: 0 +after exec1.sub with args: 0 -after execscript.sub without args: 0 +after exec1.sub without args: 0 ./execscript: notthere: command not found 127 notthere: notthere: No such file or directory @@ -20,8 +20,8 @@ notthere: notthere: No such file or directory ./execscript: .: /dev/null: not a regular file 1 this is bashenv -./execscript.sub3: /tmp/bash-notthere: No such file or directory -./execscript.sub3: exec: /tmp/bash-notthere: cannot execute: No such file or directory +./exec3.sub: /tmp/bash-notthere: No such file or directory +./exec3.sub: exec: /tmp/bash-notthere: cannot execute: No such file or directory 126 ./execscript: notthere: No such file or directory 127 @@ -34,3 +34,6 @@ this is sh unset ok 5 +./exec5.sub: exec: bash-notthere: not found +127 +this is ohio-state diff --git a/tests/execscript.sub b/tests/exec1.sub index 4a12501f..4a12501f 100755 --- a/tests/execscript.sub +++ b/tests/exec1.sub diff --git a/tests/execscript.sub2 b/tests/exec2.sub index c1caaead..c1caaead 100644 --- a/tests/execscript.sub2 +++ b/tests/exec2.sub diff --git a/tests/execscript.sub3 b/tests/exec3.sub index 4f2f8e21..4f2f8e21 100644 --- a/tests/execscript.sub3 +++ b/tests/exec3.sub diff --git a/tests/execscript.sub4 b/tests/exec4.sub index a60d8b32..a60d8b32 100644 --- a/tests/execscript.sub4 +++ b/tests/exec4.sub diff --git a/tests/exec5.sub b/tests/exec5.sub new file mode 100644 index 00000000..1462f9e5 --- /dev/null +++ b/tests/exec5.sub @@ -0,0 +1,9 @@ +# try exec'ing a command that cannot be found in $PATH +shopt -s execfail + +exec bash-notthere +# make sure we're still around +echo $? + +# now we need to go away, but this should echo 'this is ohio-state' +exec -a ohio-state ${THIS_SH} -c 'echo this is $0' diff --git a/tests/execscript b/tests/execscript index 49c4c337..0a13d72f 100644 --- a/tests/execscript +++ b/tests/execscript @@ -2,12 +2,12 @@ export LC_ALL=C export LANG=C set -- one two three -echo before execscript.sub: "$@" -echo calling execscript.sub -./execscript.sub aa bb cc dd ee -echo after execscript.sub with args: $? -./execscript.sub -echo after execscript.sub without args: $? +echo before exec1.sub: "$@" +echo calling exec1.sub +./exec1.sub aa bb cc dd ee +echo after exec1.sub with args: $? +./exec1.sub +echo after exec1.sub without args: $? # set up a fixed path so we know notthere will not be found PATH=/usr/bin:/bin:/usr/local/bin: @@ -44,7 +44,7 @@ echo $? # kill two birds with one test -- test out the BASH_ENV code echo echo this is bashenv > /tmp/bashenv export BASH_ENV=/tmp/bashenv -${THIS_SH} ./execscript.sub3 +${THIS_SH} ./exec3.sub rm -f /tmp/bashenv unset BASH_ENV @@ -72,7 +72,10 @@ echo ${PATH-unset} echo "echo ok" | ${THIS_SH} -t -${THIS_SH} ./execscript.sub2 +${THIS_SH} ./exec2.sub echo $? -${THIS_SH} ./execscript.sub4 +${THIS_SH} ./exec4.sub + +# try exec'ing a command that cannot be found in $PATH +${THIS_SH} ./exec5.sub diff --git a/tests/extglob.right b/tests/extglob.right new file mode 100644 index 00000000..190f5ad2 --- /dev/null +++ b/tests/extglob.right @@ -0,0 +1,59 @@ +ok 1 +ok 2 +ok 3 +ok 4 +ok 5 +ok 6 +ok 7 +ok 8 +ok 9 +ok 10 +ok 11 +ok 12 +ok 13 +ok 14 +ok 15 +ok 16 +ok 17 +ok 18 +ok 19 +ok 20 +ok 21 +ok 22 +ok 23 +ok 24 +ok 25 +ok 26 +ok 27 +ok 28 +ok 29 +ok 30 +ok 31 +ok 32 +ok 33 +ok 34 +ok 35 +ok 36 +!([*)* ++(a|b[)* +[a*(]*)z ++()c ++()x +abc ++(*)x +abc +no-file+(a|b)stuff +no-file+(a*(c)|b)stuff +abd acd +acd +abd +no +yes +yes +1: bcdef +2: def +3: abcde +4: abc +5: ef +6: ef +7: abcdef diff --git a/tests/extglob.tests b/tests/extglob.tests new file mode 100644 index 00000000..4747eb5c --- /dev/null +++ b/tests/extglob.tests @@ -0,0 +1,286 @@ +# 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"} + +# clean up and exit + +builtin cd / +rm -rf $TESTDIR + +# this is for the benefit of pure coverage, so it writes the pcv file +# in the right place +builtin cd $MYDIR + +exit 0 diff --git a/tests/getopts.right b/tests/getopts.right index b90b6558..24d7d485 100644 --- a/tests/getopts.right +++ b/tests/getopts.right @@ -10,8 +10,8 @@ remaining args: one two three -a specified -b bval specified remaining args: one two three four five six seven eight nine ten eleven twelve -./getopts.sub1: option requires an argument -- b -Usage: ./getopts.sub1 [-a] [-b value] args +./getopts1.sub: option requires an argument -- b +Usage: ./getopts1.sub [-a] [-b value] args -a specified -c cval specified -d specified @@ -24,10 +24,10 @@ remaining args: one two three -a specified -b bval specified remaining args: one two three -./getopts.sub4: error: option `b' requires an argument -Usage: ./getopts.sub4 [-a] [-b value] args -./getopts.sub4: error: illegal option character `c' -Usage: ./getopts.sub4 [-a] [-b value] args +./getopts4.sub: error: option `b' requires an argument +Usage: ./getopts4.sub [-a] [-b value] args +./getopts4.sub: error: illegal option character `c' +Usage: ./getopts4.sub [-a] [-b value] args -a specified remaining args: -b bval one two three OPTERR=0 @@ -36,11 +36,11 @@ something else here OPTIND=3 getop: OPTERR=1 a here -./getopts.sub5: illegal option -- c +./getopts5.sub: illegal option -- c something else here -./getopts.sub5: illegal option -- d +./getopts5.sub: illegal option -- d something else here -./getopts.sub5: illegal option -- e +./getopts5.sub: illegal option -- e something else here getop: OPTIND=5 OPTIND=3 @@ -52,5 +52,5 @@ remaining args: -a specified remaining args: 0 -./getopts.sub7: getopts: `opt-var': not a valid identifier +./getopts7.sub: getopts: `opt-var': not a valid identifier remaining args: diff --git a/tests/getopts.tests b/tests/getopts.tests index af1ee4fb..1814d786 100644 --- a/tests/getopts.tests +++ b/tests/getopts.tests @@ -9,30 +9,30 @@ echo $? # used in error messages, but not yet getopts -a opts name -${THIS_SH} ./getopts.sub1 -a -b bval one two three +${THIS_SH} ./getopts1.sub -a -b bval one two three # make sure getopts works when there are more than 9 positional parameters -${THIS_SH} ./getopts.sub1 -a -b bval one two three four five six seven eight nine ten eleven twelve -${THIS_SH} ./getopts.sub1 -a -b +${THIS_SH} ./getopts1.sub -a -b bval one two three four five six seven eight nine ten eleven twelve +${THIS_SH} ./getopts1.sub -a -b -${THIS_SH} ./getopts.sub2 -ad -c cval three four five +${THIS_SH} ./getopts2.sub -ad -c cval three four five -${THIS_SH} ./getopts.sub3 +${THIS_SH} ./getopts3.sub # make sure that `-b bval' and `-bbval' are equivalent -${THIS_SH} ./getopts.sub4 -a -b bval one two three -${THIS_SH} ./getopts.sub4 -a -bbval one two three +${THIS_SH} ./getopts4.sub -a -b bval one two three +${THIS_SH} ./getopts4.sub -a -bbval one two three # this tests `silent' error reporting -${THIS_SH} ./getopts.sub4 -a -b -${THIS_SH} ./getopts.sub4 -a -c +${THIS_SH} ./getopts4.sub -a -b +${THIS_SH} ./getopts4.sub -a -c # make sure that `--' can be used to end the list of options -${THIS_SH} ./getopts.sub4 -a -- -b bval one two three +${THIS_SH} ./getopts4.sub -a -- -b bval one two three -${THIS_SH} ./getopts.sub5 -a -c +${THIS_SH} ./getopts5.sub -a -c -${THIS_SH} ./getopts.sub6 -a -${THIS_SH} ./getopts.sub6 -a -c -${THIS_SH} ./getopts.sub6 -ac +${THIS_SH} ./getopts6.sub -a +${THIS_SH} ./getopts6.sub -a -c +${THIS_SH} ./getopts6.sub -ac echo $? # this should be 2 -${THIS_SH} ./getopts.sub7 -a +${THIS_SH} ./getopts7.sub -a diff --git a/tests/getopts.sub1 b/tests/getopts1.sub index df0a342e..df0a342e 100644 --- a/tests/getopts.sub1 +++ b/tests/getopts1.sub diff --git a/tests/getopts.sub2 b/tests/getopts2.sub index d91fd26a..d91fd26a 100644 --- a/tests/getopts.sub2 +++ b/tests/getopts2.sub diff --git a/tests/getopts.sub3 b/tests/getopts3.sub index 2d8b3162..2d8b3162 100644 --- a/tests/getopts.sub3 +++ b/tests/getopts3.sub diff --git a/tests/getopts.sub4 b/tests/getopts4.sub index 9cd5aef4..9cd5aef4 100644 --- a/tests/getopts.sub4 +++ b/tests/getopts4.sub diff --git a/tests/getopts.sub5 b/tests/getopts5.sub index c6e38881..c6e38881 100644 --- a/tests/getopts.sub5 +++ b/tests/getopts5.sub diff --git a/tests/getopts.sub6 b/tests/getopts6.sub index 75d768c6..75d768c6 100644 --- a/tests/getopts.sub6 +++ b/tests/getopts6.sub diff --git a/tests/getopts.sub7 b/tests/getopts7.sub index a20a6df1..a20a6df1 100644 --- a/tests/getopts.sub7 +++ b/tests/getopts7.sub diff --git a/tests/glob-test b/tests/glob-test index 492cfb8b..88ffe0cb 100644 --- a/tests/glob-test +++ b/tests/glob-test @@ -7,6 +7,9 @@ expect() echo expect "$@" } +# First, a test that bash-2.01.1 fails +${THIS_SH} ./glob1.sub + MYDIR=$PWD # save where we are TESTDIR=/tmp/glob-test @@ -14,7 +17,7 @@ mkdir $TESTDIR builtin cd $TESTDIR || { echo $0: cannot cd to $TESTDIR >&2 ; exit 1; } rm -rf * -touch a b c d abc abd abe bb bcd ca cb dd de +touch a b c d abc abd abe bb bcd ca cb dd de Beware mkdir bdir # see if `regular' globbing works right @@ -81,7 +84,7 @@ expect '<a-b> <aXb>' recho a[X-]b touch .x .y -expect '<d> <dd> <de>' +expect '<Beware> <d> <dd> <de>' recho [^a-c]* # Make sure that filenames with embedded globbing characters are handled @@ -288,6 +291,11 @@ case '-' in []-]) echo ok 35 ;; esac +# a backslash should just escape the next character in this context +case p in +[a-\z]) echo ok 36 ;; +esac + # none of these should output anything case abc in @@ -322,6 +330,14 @@ case '[' in [abc) echo bad 8;; esac +# let's start testing the case-insensitive globbing code +recho b* + +shopt -s nocaseglob +recho b* + +recho [b]* +shopt -u nocaseglob # make sure set -f works right set -f diff --git a/tests/glob.right b/tests/glob.right index 2fcace18..c9bdbfee 100644 --- a/tests/glob.right +++ b/tests/glob.right @@ -1,3 +1,4 @@ +foo/bar foobar/bar argv[1] = <a> argv[2] = <abc> argv[3] = <abd> @@ -43,9 +44,10 @@ argv[1] = <abd> argv[2] = <abe> argv[1] = <a-b> argv[2] = <aXb> -argv[1] = <d> -argv[2] = <dd> -argv[3] = <de> +argv[1] = <Beware> +argv[2] = <d> +argv[3] = <dd> +argv[4] = <de> argv[1] = <a*b/ooo> argv[1] = <a*b/ooo> no match @@ -91,6 +93,21 @@ ok 32 ok 33 ok 34 ok 35 +ok 36 +argv[1] = <b> +argv[2] = <bb> +argv[3] = <bcd> +argv[4] = <bdir> +argv[1] = <Beware> +argv[2] = <b> +argv[3] = <bb> +argv[4] = <bcd> +argv[5] = <bdir> +argv[1] = <Beware> +argv[2] = <b> +argv[3] = <bb> +argv[4] = <bcd> +argv[5] = <bdir> argv[1] = <*> argv[1] = <a*b> argv[2] = <a-b> @@ -103,12 +120,13 @@ argv[8] = <ca> argv[9] = <cb> argv[10] = <dd> argv[11] = <man> -argv[1] = <abc> -argv[2] = <abe> -argv[3] = <bdir> -argv[4] = <ca> -argv[5] = <de> -argv[6] = <man> +argv[1] = <Beware> +argv[2] = <abc> +argv[3] = <abe> +argv[4] = <bdir> +argv[5] = <ca> +argv[6] = <de> +argv[7] = <man> argv[1] = <*> argv[1] = <man/man1/bash.1> argv[1] = <man/man1/bash.1> diff --git a/tests/glob1.sub b/tests/glob1.sub new file mode 100644 index 00000000..8745cd99 --- /dev/null +++ b/tests/glob1.sub @@ -0,0 +1,14 @@ +# bash-2.01.1 failed this test +FN=/tmp/bash-glob.$$ +mkdir $FN +cd $FN +mkdir foo +mkdir foobar +touch foo/bar +touch foobar/bar +chmod 311 foo foobar +echo f*/bar + +chmod 777 foo foobar +cd / +rm -rf $FN diff --git a/tests/histexpand.right b/tests/histexp.right index 3c20d1c1..b270a5fa 100644 --- a/tests/histexpand.right +++ b/tests/histexp.right @@ -1,4 +1,5 @@ echo $BASH_VERSION +./histexp.tests: history: !!:z: history expansion failed 1 for i in one two three; do echo $i; done 2 /bin/sh -c 'echo this is $0' 3 ls @@ -125,3 +126,4 @@ echo '!!' \!\! !! !! ok 1 ok 2 +ok 3 diff --git a/tests/histexpand.tests b/tests/histexp.tests index f48c00fe..11596ddd 100644 --- a/tests/histexpand.tests +++ b/tests/histexp.tests @@ -1,6 +1,9 @@ +LC_ALL=C +LANG=C trap 'rm /tmp/newhistory' 0 file=bax +histchars='!^#' # make sure history comment char is set correctly history -c @@ -15,6 +18,9 @@ set -o history history -p '!!' +# this should result in a failed history expansion error +history -p '!!:z' + history HISTFILE=/tmp/newhistory @@ -110,3 +116,7 @@ var1='ok 2' var2=var1 echo ${!var2} + +# Bash-2.01[.1] fails this test -- it attempts history expansion after the +# history_expansion_char +echo ok 3 # !1200 diff --git a/tests/history.right b/tests/history.right index 331cc034..7110223f 100644 --- a/tests/history.right +++ b/tests/history.right @@ -1,3 +1,8 @@ +./history.tests: history: illegal option: -x +history: usage: history [-c] [n] or history -awrn [filename] or history -ps arg [arg...] +./history.tests: history: cannot use more than one of -anrw +./history.tests: fc: illegal option: -v +fc: usage: fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [cmd] 1 for i in one two three; do echo $i; done 2 /bin/sh -c 'echo this is $0' 3 ls @@ -93,6 +98,7 @@ line 2 for history 7 echo displaying \$HISTFILE after history -a 8 cat $HISTFILE ./history.tests: fc: history specification out of range +./history.tests: fc: history specification out of range 14 set -H 15 echo line 2 for history 16 unset HISTSIZE @@ -100,5 +106,7 @@ line 2 for history aa ab ac echo xx xb xc xx xb xc +echo 44 48 4c +44 48 4c ./history.tests: fc: no command found 1 diff --git a/tests/history.tests b/tests/history.tests index 2bc09b44..4a218c30 100644 --- a/tests/history.tests +++ b/tests/history.tests @@ -1,5 +1,17 @@ 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 @@ -59,6 +71,7 @@ fc -l 4 fc -l 4 8 fc -l 502 +fc -l one=two three=four 502 history 4 @@ -70,6 +83,7 @@ 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 diff --git a/tests/ifs.1.right b/tests/ifs-1.right index af0abb2c..af0abb2c 100644 --- a/tests/ifs.1.right +++ b/tests/ifs-1.right diff --git a/tests/ifs-test-1.sh b/tests/ifs-1.test index a153ce94..a153ce94 100644 --- a/tests/ifs-test-1.sh +++ b/tests/ifs-1.test diff --git a/tests/ifs.2.right b/tests/ifs-2.right index af0abb2c..af0abb2c 100644 --- a/tests/ifs.2.right +++ b/tests/ifs-2.right diff --git a/tests/ifs-test-2.sh b/tests/ifs-2.test index 3249f1bf..3249f1bf 100644 --- a/tests/ifs-test-2.sh +++ b/tests/ifs-2.test diff --git a/tests/ifs.3.right b/tests/ifs-3.right index af0abb2c..af0abb2c 100644 --- a/tests/ifs.3.right +++ b/tests/ifs-3.right diff --git a/tests/ifs-test-3.sh b/tests/ifs-3.test index 4693792a..4693792a 100644 --- a/tests/ifs-test-3.sh +++ b/tests/ifs-3.test diff --git a/tests/jobs.right b/tests/jobs.right index f67579d5..830c3973 100644 --- a/tests/jobs.right +++ b/tests/jobs.right @@ -1,4 +1,8 @@ +./jobs2.sub: fg: job %1 started without job control +fg: 1 0 +./jobs.tests: wait: job control not enabled +./jobs.tests: fg: no job control wait-for-pid wait-errors ./jobs.tests: wait: `1-1' is not a pid or valid job spec @@ -29,38 +33,44 @@ fg-bg 6 fg: usage: fg [job_spec] ./jobs.tests: bg: illegal option: -s bg: usage: bg [job_spec] -./jobs.tests: disown: illegal option: -r -disown: usage: disown [-h] [jobspec ...] +./jobs.tests: disown: illegal option: -s +disown: usage: disown [-h] [-ar] [jobspec ...] ./jobs.tests: disown: %1: no such job +./jobs.tests: disown: %2: no such job wait-for-non-child ./jobs.tests: wait: pid 1 is not a child of this shell 127 3 -- 1 2 3 -- 1 - 2 - 3 -[1] Running sleep 300 &
-[2]- Running sleep 350 &
-[3]+ Running sleep 400 &
+[1] Running sleep 300 & +[2]- Running sleep 350 & +[3]+ Running sleep 400 & running jobs: -[1] Running sleep 300 &
-[2]- Running sleep 350 &
-[3]+ Running sleep 400 &
+[1] Running sleep 300 & +[2]- Running sleep 350 & +[3]+ Running sleep 400 & ./jobs.tests: kill: %4: no such job +./jobs.tests: jobs: no such job %4 +current job: +[3]+ Running sleep 400 & +previous job: +[2]- Running sleep 350 & after kill -STOP running jobs: -[1] Running sleep 300 &
-[3]- Running sleep 400 &
+[1] Running sleep 300 & +[3]- Running sleep 400 & stopped jobs: -[2]+ Stopped sleep 350
+[2]+ Stopped sleep 350 after disown -[2]+ Stopped sleep 350
-[3]- Running sleep 400 &
+[2]+ Stopped sleep 350 +[3]- Running sleep 400 & running jobs: -[3]- Running sleep 400 &
+[3]- Running sleep 400 & stopped jobs: -[2]+ Stopped sleep 350
+[2]+ Stopped sleep 350 after kill -s CONT running jobs: -[2]+ Running sleep 350 &
-[3]- Running sleep 400 &
+[2]+ Running sleep 350 & +[3]- Running sleep 400 & stopped jobs: after kill -STOP, backgrounding %3: [3]+ sleep 400 & diff --git a/tests/jobs.tests b/tests/jobs.tests index cd044f15..26adfe09 100644 --- a/tests/jobs.tests +++ b/tests/jobs.tests @@ -1,6 +1,26 @@ +# test out %+, jobs -p, and $! agreement in a subshell first +${THIS_SH} ./jobs1.sub + +# test out fg/bg failure in a subshell +${THIS_SH} ./jobs2.sub + jobs echo $? +# should be a job-control-not-enabled error +wait %1 + +# make sure we can't fg a job started when job control was not active +sleep 30 & +pid=$! +fg %1 +# make sure the killed processes don't cause a message +exec 5>&2 +exec 2>/dev/null +kill -n 9 $pid +wait # make sure we reap the processes while stderr is still redirected +exec 2>&5 + echo wait-for-pid sleep 10 & wait $! @@ -68,13 +88,17 @@ fg -s %1 bg -s %1 wait -# someday this may mean to disown all running jobs, but for now it is +# someday this may mean to disown all stopped jobs, but for now it is # an error -disown -r +disown -s -# this is an error +# this is an error -- the job with the pid that is the value of $! is +# retained only until a `wait' is performed disown %1 +# this, however, is an error +disown %2 + echo wait-for-non-child wait 1 echo $? @@ -93,6 +117,12 @@ jobs -r # should be an error kill -n 1 %4 +# should be an error +jobs %4 +echo current job: +jobs %+ +echo previous job: +jobs %- kill -STOP %2 sleep 5 # give time for the shell to get the stop notification diff --git a/tests/jobs1.sub b/tests/jobs1.sub new file mode 100644 index 00000000..aa9a3726 --- /dev/null +++ b/tests/jobs1.sub @@ -0,0 +1,17 @@ +# make sure that jobs -p, %+, and $! all agree +set -m +sleep 60 & + +FN=/tmp/jobs-pid.$$ + +pid1=$! +jobs -p %+ > $FN +pid2=$(< $FN) +rm $FN + +if [ $pid1 -ne $pid2 ]; then + echo 'oops - $! and jobs -p %+ disagree!' +fi + +exec 2>/dev/null +kill -9 $pid1 diff --git a/tests/jobs2.sub b/tests/jobs2.sub new file mode 100644 index 00000000..496519b0 --- /dev/null +++ b/tests/jobs2.sub @@ -0,0 +1,13 @@ +# make sure fg and bg don't work on jobs started without job control, +# even if they are executed when job control is active +set +o monitor + +sleep 30 & +pid=$! + +set -m +fg %1 +echo fg: $? + +exec 2>/dev/null +kill -9 $pid diff --git a/tests/misc/haertel.perftest b/tests/misc/perftest index 04910c89..ee3f2c66 100644 --- a/tests/misc/haertel.perftest +++ b/tests/misc/perftest @@ -1,3 +1,4 @@ +# originally from Mike Haertel foo() { case $1 in a*) ;; *) ;; esac ;} bar() { case $1 in [abc]*) ;; *);; esac ;} baz() { case $1 in xyzzy) ;; *) ;; esac ;} diff --git a/tests/misc/redir.t2.sh b/tests/misc/redir-t2.sh index 44b2624e..44b2624e 100644 --- a/tests/misc/redir.t2.sh +++ b/tests/misc/redir-t2.sh diff --git a/tests/misc/run-r2.sh b/tests/misc/run-r2.sh new file mode 100755 index 00000000..0321a1bd --- /dev/null +++ b/tests/misc/run-r2.sh @@ -0,0 +1 @@ +../../bash ./redir-t2.sh < /etc/passwd diff --git a/tests/misc/run.r2.sh b/tests/misc/run.r2.sh deleted file mode 100755 index 3b247018..00000000 --- a/tests/misc/run.r2.sh +++ /dev/null @@ -1 +0,0 @@ -../../bash ./redir.t2.sh < /etc/passwd diff --git a/tests/misc/sigint.t1.sh b/tests/misc/sigint-1.sh index 7b74c307..7b74c307 100755 --- a/tests/misc/sigint.t1.sh +++ b/tests/misc/sigint-1.sh diff --git a/tests/misc/sigint.t2.sh b/tests/misc/sigint-2.sh index 69eaf56a..69eaf56a 100755 --- a/tests/misc/sigint.t2.sh +++ b/tests/misc/sigint-2.sh diff --git a/tests/misc/sigint.t3.sh b/tests/misc/sigint-3.sh index 2627fe6c..2627fe6c 100755 --- a/tests/misc/sigint.t3.sh +++ b/tests/misc/sigint-3.sh diff --git a/tests/misc/sigint.t4.sh b/tests/misc/sigint-4.sh index 587dd265..587dd265 100755 --- a/tests/misc/sigint.t4.sh +++ b/tests/misc/sigint-4.sh diff --git a/tests/more-exp.right b/tests/more-exp.right index 9e689cbb..63e44dfc 100644 --- a/tests/more-exp.right +++ b/tests/more-exp.right @@ -71,6 +71,17 @@ argv[3] = <-> argv[1] = <xy> argv[1] = <xy> argv[1] = <xy> +argv[1] = <xy> +argv[1] = <xy> +argv[1] = <xy> +argv[1] = <> +argv[1] = <> +argv[1] = <xy> +argv[1] = <xy> +argv[1] = <xy> +argv[1] = <xy> +argv[1] = <xy> +argv[1] = <xy> argv[1] = <> argv[1] = <> argv[1] = <x> @@ -144,3 +155,40 @@ argv[1] = <hi> argv[2] = <K> argv[3] = <}> argv[1] = <a*> +Number of args: 0 +<${*-x}>: <x> +<${@-x}>: <x> +Number of args: 1 +<${*-x}>: <> +<${@-x}>: <> +Number of args: 2 +<${*-x}>: < > +<${@-x}>: < > +argv[1] = <5> +argv[1] = <5> +argv[1] = <5> +argv[1] = <5> +argv[1] = <5> +argv[1] = <0> +argv[1] = <0> +argv[1] = <0> +argv[1] = <0> +argv[1] = <0> +argv[1] = <0> +argv[1] = <posparams> +argv[1] = <posparams> +argv[1] = <2> +argv[1] = <0> +argv[1] = <0> +argv[1] = <1> +argv[1] = <5> +argv[1] = <5> +argv[1] = <0> +./more-exp.tests: ${#:}: bad substitution +./more-exp.tests: ${#/}: bad substitution +./more-exp.tests: ${#%}: bad substitution +./more-exp.tests: ${#=}: bad substitution +./more-exp.tests: ${#+}: bad substitution +./more-exp.tests: ${#1xyz}: bad substitution +./more-exp.tests: #: %: syntax error: operand expected (error token is "%") +argv[1] = <0> diff --git a/tests/more-exp.tests b/tests/more-exp.tests index 7f8ae50d..d01d9686 100644 --- a/tests/more-exp.tests +++ b/tests/more-exp.tests @@ -189,6 +189,12 @@ expect '<xy>' recho "x$*y" expect '<xy>' recho "xy$*" +expect '<xy>' +recho x"$*"y +expect '<xy>' +recho xy"$*" +expect '<xy>' +recho "$*"xy expect '<>' recho "$*" expect nothing @@ -196,15 +202,44 @@ recho $* unset undef ; set "" +expect '<>' +recho ${undef-"$*"} +expect '<xy>' +recho ${undef-"x$*y"} +expect '<xy>' +recho ${undef-"$*xy"} +expect '<xy>' +recho ${undef-"xy$*"} +expect '<xy>' +recho ${undef-x"$*"y} +expect '<xy>' +recho ${undef-xy"$*"} +expect '<xy>' +recho ${undef-"$*"xy} +expect '<>' +recho "${undef-$*}" +expect nothing +recho ${undef-$*} + +expect '<>' recho ${undef-"$zzz"} +expect '<x>' recho x${undef-"$zzz"} +expect '<x>' recho x${undef-"$@"} +expect nothing recho ${undef-"$@"} +expect '<x>' recho ${undef-"$zzz"}x +expect '<x>' recho ${undef-"$@"}x +expect '<x>' recho "$@"x +expect '<x>' recho "$zzz"x +expect '<^?>' recho ${undef-} +expect '<^?>' recho ${undef-""} yyy="" @@ -301,3 +336,101 @@ recho ${abc:-G { I } K } # should echo a* unset foo recho "${foo:-"a"}*" + +f () +{ + echo "Number of args: $#" + echo "<\${*-x}>: <${*-x}>" + echo "<\${@-x}>: <${@-x}>" +} + +f +f '' +f '' '' + +set 1 2 3 4 5 + +expect '<5>' +recho ${#} +expect '<5>' +recho ${#:foo} +expect '<5>' +recho ${#:-foo} +expect '<5>' +recho ${#-posparams} +expect '<5>' +recho ${#:-posparams} + +expect '<0>' +recho ${#!} + +expect nothing +recho $! +expect nothing +recho ${!} + +expect nothing +recho $8 +expect nothing +recho ${8} + +shift $# + +expect '<0>' +recho ${#} +expect '<0>' +recho ${#:foo} +expect '<0>' +recho ${#:-foo} +expect '<0>' +recho ${#-posparams} +expect '<0>' +recho ${#:-posparams} + +expect '<posparams>' +recho ${!-posparams} +expect '<posparams>' +recho ${!:-posparams} + +expect '<2>' +recho ${#-} + +expect '<0>' +recho ${#-posparams} + +expect '<0>' +recho ${#?:-xyz} + +expect '<1>' +recho ${#?} + +set a b c d e + +expect '<5>' +recho ${#} +expect '<5>' +recho ${#?:-xyz} + +shift $# + +expect '<0>' +recho ${#:-foo} + +expect a bad substitution error +recho ${#:} +expect a bad substitution error +recho ${#/} +expect a bad substitution error +recho ${#%} +expect a bad substitution error +recho ${#=} +expect a bad substitution error +recho ${#+} +expect a bad substitution error +recho ${#1xyz} + +expect a math syntax error +recho ${#:%} + +expect '<0>' +recho ${#:-} diff --git a/tests/new-exp.right b/tests/new-exp.right index f7d9b63e..7f013dec 100644 --- a/tests/new-exp.right +++ b/tests/new-exp.right @@ -22,7 +22,6 @@ argv[2] = <-> argv[1] = <-abcd> argv[2] = <-> argv[1] = <-abcd-> -argv[1] = <a b c d e> bar foo bar foo bar foo @@ -151,7 +150,10 @@ argv[6] = <uvwyyy> this is a test of proc subst this is test 2 -./new-exp.tests: ${#:-foo}: bad substitution +./new-exp2.sub: /tmp/bashtmp.x*: No such file or directory +./new-exp2.sub: /tmp/redir-notthere: No such file or directory +1 +argv[1] = <6> ./new-exp.tests: ${#:}: bad substitution argv[1] = <'> argv[1] = <"> @@ -384,4 +386,8 @@ argv[9] = <z> ./new-exp.tests: UNSET: unbound variable ./new-exp.tests: UNSET: unbound variable ./new-exp.tests: UNSET: unbound variable +argv[1] = <5> +argv[1] = <#> +argv[1] = <#> +argv[1] = <> ./new-exp.tests: ABXD: parameter unset diff --git a/tests/new-exp.tests b/tests/new-exp.tests index cae732e3..f2d50d83 100644 --- a/tests/new-exp.tests +++ b/tests/new-exp.tests @@ -25,7 +25,7 @@ recho "${HOME:`echo }`}" # should be a math error -- bad substring substitution expect unset _ENV=oops -x=${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]} # memory leak +x=${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]} echo ${x:-unset} expect "<$HOME>" @@ -64,13 +64,6 @@ recho -${foo% *}- # should be -abcd - expect '<-abcd->' recho -${foo%% *}- # should be -abcd- -set a b c d e -expect '<a b c d e>' -IFS="" -recho "$@" -IFS=' -' - foo=bar expect '<bar foo>' echo -n $foo' ' ; echo foo @@ -237,10 +230,14 @@ echo $abmcde # 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-exp.sub1 +${THIS_SH} ./new-exp1.sub -expect $0: '${#:-foo}: bad substitution' -echo ${#:-foo} +# run the tests of $(<filename) in a subshell to avoid cluttering up +# this script +${THIS_SH} ./new-exp2.sub + +expect '<6>' +recho ${#:-foo} expect $0: '${#:}: bad substitution' echo ${#:} @@ -449,6 +446,15 @@ set -u ( 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}" + # this must be last! expect $0: 'ABXD: parameter unset' recho ${ABXD:?"parameter unset"} diff --git a/tests/new-exp.sub1 b/tests/new-exp1.sub index c015c223..c015c223 100644 --- a/tests/new-exp.sub1 +++ b/tests/new-exp1.sub diff --git a/tests/new-exp2.sub b/tests/new-exp2.sub new file mode 100644 index 00000000..5e922aac --- /dev/null +++ b/tests/new-exp2.sub @@ -0,0 +1,36 @@ +export LC_ALL=C +export LANG=C + +# test out the new $(< filename) code +# it should be exactly equivalent to $(cat filename) + +FILENAME=/tmp/bashtmp.x$$ + +trap 'rm -f $FILENAME' 0 + +cat >$FILENAME << EOF +line 1 +line 2 +line 3 +EOF + +LINES1=$(cat $FILENAME) +LINES2=$(< $FILENAME) + +if [[ $LINES1 != $LINES2 ]]; then + echo 'whoops: $(< filename) failed' +fi + +LINES2=$(< /tmp/bashtmp.x*) +if [[ $LINES1 != $LINES2 ]]; then + echo 'whoops: $(< filename) with glob expansion failed' +fi + +# but the glob expansion in the redirection should fail in posix mode +set -o posix +LINES2=$(< /tmp/bashtmp.x*) +set +o posix + +# now see what happens when we try it with a non-existant file +LINES3=$(< /tmp/redir-notthere) +echo $? diff --git a/tests/posix2.tests b/tests/posix2.tests index 5eea7e0e..e6d24792 100644 --- a/tests/posix2.tests +++ b/tests/posix2.tests @@ -140,6 +140,35 @@ if [ "$OPTIND" != 3 ] || [ "$store" != a ] || [ "$OPTARG" != aoptval ]; then testfail "getopts" fi +newtest +SQUOTE="'" +val1=$(set | sed -n 's:^SQUOTE=::p') +# if I change the default quoting style for variable values, this must change +if [ "$val1" != "''\'''" ]; then + testfail "variable quoting 1" +fi + +newtest +VTILDE='~' +val1=$(set | sed -n 's:^VTILDE=::p') +if [ "$val1" != "'~'" ]; then + testfail "variable quoting 2" +fi + +newtest +VHASH=ab#cd +val1=$(set | sed -n 's:^VHASH=::p') +if [ "$val1" != "ab#cd" ]; then + testfail "variable quoting 3" +fi + +newtest +VHASH2=#abcd +val1=$(set | sed -n 's:^VHASH2=::p') +if [ "$val1" != "'#abcd'" ]; then + testfail "variable quoting 4" +fi + if [ $exitval = 0 ]; then echo "All tests passed" else diff --git a/tests/posixpat.right b/tests/posixpat.right new file mode 100644 index 00000000..deb01bf2 --- /dev/null +++ b/tests/posixpat.right @@ -0,0 +1,42 @@ +ok 1 +ok 2 +ok 3 +ok 4 +ok 5 +ok 6 +ok 7 +ok 8 +ok 9 +ok 10 +ok 11 +ok 12 +ok 13 +ok 14 +ok 15 +ok 16 +ok 17 +ok 18 +ok 19 +ok 20 +ok 21 +ok -- space +ok -- blank +ok 1 +ok 2 +ok 3 +ok 4 +ok 5 +ok 6 +ok 7 +ok 8 +ok 9 +ok 10 +ok 11 +ok 12 +ok 13 +ok 14 +ok 15 +ok 16 +ok 1 +ok 2 +ok 3 diff --git a/tests/posixpat.tests b/tests/posixpat.tests new file mode 100644 index 00000000..91fac3b8 --- /dev/null +++ b/tests/posixpat.tests @@ -0,0 +1,233 @@ +# A test suite for the POSIX.2 (BRE) pattern matching code +LC_ALL=C +LANG=C + +# First, test POSIX.2 character classes + +case e in +[[:xdigit:]]) echo ok 1;; +esac + +case a in +[[:alpha:]123]) echo ok 2;; +esac + +case 1 in +[[:alpha:]123]) echo ok 3;; +esac + +case 9 in +[![:alpha:]]) echo ok 4;; +esac + +# invalid character class expressions are just characters to be matched +case a in +[:al:]) echo ok 5;; +esac + +case a in +[[:al:]) echo ok 6;; +esac + +case '!' in +[abc[:punct:][0-9]) echo ok 7;; +esac + +# let's try to match the start of a valid sh identifier +case 'PATH' in +[_[:alpha:]]*) echo ok 8;; +esac + +# let's try to match the first two characters of a valid sh identifier +case PATH in +[_[:alpha:]][_[:alnum:]]*) echo ok 9;; +esac + +# is ^C a cntrl character? +case $'\003' in +[[:cntrl:]]) echo ok 10;; +esac + +# how about A? +case A in +[[:cntrl:]]) echo oops -- cntrl ;; +*) echo ok 11;; +esac + +case 9 in +[[:digit:]]) echo ok 12;; +esac + +case X in +[[:digit:]]) echo oops -- digit;; +*) echo ok 13;; +esac + +case $'\033' in +[[:graph:]]) echo oops -- graph;; +*) echo ok 14;; +esac + +case $'\040' in +[[:graph:]]) echo oops -- graph 2;; +*) echo ok 15;; +esac + +case ' ' in +[[:graph:]]) echo oops -- graph 3;; +*) echo ok 16;; +esac + +case 'aB' in +[[:lower:]][[:upper:]]) echo ok 17;; +esac + +case $'\040' in +[[:print:]]) echo ok 18;; +*) echo oops -- print;; +esac + +case PS3 in +[_[:alpha:]][_[:alnum:]][_[:alnum:]]*) echo ok 19;; +esac + +case a in +[[:alpha:][:digit:]]) echo ok 20;; +*) echo oops - skip brackpat ;; +esac + +case a in +[[:alpha:]\]) echo oops -- dangling backslash in brackpat ;; +*) echo ok 21 ;; +esac + +# what's a newline? is it a blank? a space? +case $'\n' in +[[:blank:]]) echo ok -- blank ;; +[[:space:]]) echo ok -- space ;; +*) echo oops newline ;; +esac + +# OK, what's a tab? is it a blank? a space? +case $'\t' in +[[:blank:]]) echo ok -- blank ;; +[[:space:]]) echo ok -- space ;; +*) echo oops newline ;; +esac + +# let's check out characters in the ASCII range +case $'\377' in +[[:ascii:]]) echo oops -- ascii\?;; +esac + +case 9 in +[1[:alpha:]123]) echo oops 1;; +esac + +# however, an unterminated brace expression containing a valid char class +# that matches had better fail +case a in +[[:alpha:]) echo oops 2;; +esac + +case $'\b' in +[[:graph:]]) echo oops 3;; +esac + +case $'\b' in +[[:print:]]) echo oops 4;; +esac + +case $' ' in +[[:punct:]]) echo oops 5;; +esac + +# Next, test POSIX.2 collating symbols + +case 'a' in +[[.a.]]) echo ok 1;; +esac + +case '-' in +[[.hyphen.]-9]) echo ok 2;; +esac + +case 'p' in +[[.a.]-[.z.]]) echo ok 3;; +esac + +case '-' in +[[.-.]]) echo ok 4;; +esac + +case ' ' in +[[.space.]]) echo ok 5;; +esac + +case ' ' in +[[.grave-accent.]]) echo oops - grave;; +*) echo ok 6;; +esac + +case '4' in +[[.-.]-9]) echo ok 7;; +esac + +# an invalid collating symbol cannot be the first part of a range +case 'c' in +[[.yyz.]-[.z.]]) echo oops - yyz;; +*) echo ok 8;; +esac + +case 'c' in +[[.yyz.][.a.]-z]) echo ok 9;; +esac + +# but when not part of a range is not an error +case 'c' in +[[.yyz.][.a.]-[.z.]]) echo ok 10 ;; +esac + +case 'p' in +[[.a.]-[.Z.]]) echo oops -- bad range ;; +*) echo ok 11;; +esac + +case p in +[[.a.]-[.zz.]p]) echo ok 12;; +*) echo oops -- bad range 2;; +esac + +case p in +[[.aa.]-[.z.]p]) echo ok 13;; +*) echo oops -- bad range 3;; +esac + +case c in +[[.yyz.]cde]) echo ok 14;; +esac + +case abc in +[[.cb.]a-Za]*) echo ok 15;; +esac + +case $'\t' in +[[.space.][.tab.][.newline.]]) echo ok 16;; +esac + +# and finally, test POSIX.2 equivalence classes + +case "abc" in +[[:alpha:]][[=b=]][[:ascii:]]) echo ok 1;; +esac + +case "abc" in +[[:alpha:]][[=B=]][[:ascii:]]) echo oops -- =B=;; +*) echo ok 2 ;; +esac + +case a in +[[=b=]) echo oops;; # an incomplete equiv class is just a string +*) echo ok 3;; +esac + diff --git a/tests/printf.right b/tests/printf.right Binary files differnew file mode 100644 index 00000000..0e6ab14c --- /dev/null +++ b/tests/printf.right diff --git a/tests/printf.tests b/tests/printf.tests new file mode 100644 index 00000000..d21eb4e7 --- /dev/null +++ b/tests/printf.tests @@ -0,0 +1,176 @@ +LC_ALL=C + +# these should output error messages -- the format is required +printf +printf -- + +# these should output nothing +printf "" +printf -- "" + +# 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" + +# 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 "\1017" +echo -e "\x0417" + +printf "%b\n" '\01017' +printf "%b\n" '\1017' +printf "%b\n" '\x0417' + +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" + +# 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 + +# 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 + +# in the future this may mean to put the output into VAR, but for +# now it is an error +printf -v var "%10d" $RANDOM + +printf "%10" +printf "ab%Mcd\n" + +# this caused an infinite loop in older versions of printf +printf "%y" 0 + +printf "%d\n" GNU +printf "%o\n" GNU diff --git a/tests/read.right b/tests/read.right index 5a7be60d..32ce2630 100644 --- a/tests/read.right +++ b/tests/read.right @@ -9,6 +9,11 @@ a. -\ a b\- -\-a b\- -\ a b\- +argv[1] = <^A> +argv[1] = <^A> +argv[1] = <^?> +argv[1] = <^?> +argv[1] = <abcd> 1: x[A] y[B] z[] 1a: 2: x[A B] diff --git a/tests/read.tests b/tests/read.tests index fd592846..83ef028a 100644 --- a/tests/read.tests +++ b/tests/read.tests @@ -13,6 +13,18 @@ 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 @@ -66,4 +78,3 @@ echo " foo" | { IFS=$' \n' ; read line; recho "$line"; } echo " foo" | { IFS=$' \t\n' ; read line; recho "$line"; } echo " foo" | { IFS=$':' ; read line; recho "$line"; } - diff --git a/tests/rsh.right b/tests/rsh.right index 2c48ef41..d5c37ec3 100644 --- a/tests/rsh.right +++ b/tests/rsh.right @@ -8,5 +8,6 @@ ./rsh.tests: command: restricted: cannot use -p ./rsh.tests: set: unknown option: +r set: usage: set [--abefhkmnptuvxBCHP] [-o option] [arg ...] +./rsh.tests: set: restricted: unknown option name ./rsh.tests: exec: restricted ./rsh.tests: after exec diff --git a/tests/rsh.tests b/tests/rsh.tests index bd22e9f0..ffdf6e55 100644 --- a/tests/rsh.tests +++ b/tests/rsh.tests @@ -26,6 +26,7 @@ fi command -p date set +r +set +o restricted exec /bin/date diff --git a/tests/run-array b/tests/run-array index 57a271f1..44207d9c 100644 --- a/tests/run-array +++ b/tests/run-array @@ -1,2 +1,4 @@ +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-array2 b/tests/run-array2 new file mode 100644 index 00000000..dd94ec82 --- /dev/null +++ b/tests/run-array2 @@ -0,0 +1,4 @@ +echo "warning: all of these tests will fail if arrays have not" >&2 +echo "warning: been compiled into the shell" >&2 +${THIS_SH} ./array-at-star > /tmp/xx 2>&1 +diff /tmp/xx array2.right && rm -f /tmp/xx diff --git a/tests/run-cond b/tests/run-cond new file mode 100644 index 00000000..6b119a62 --- /dev/null +++ b/tests/run-cond @@ -0,0 +1,7 @@ +echo "warning: all of these tests will fail if the conditional command has not" >&2 +echo "warning: been compiled into the shell" >&2 +echo "warning: some of these tests will fail if extended pattern matching has not" >&2 +echo "warning: been compiled into the shell" >&2 + +${THIS_SH} ./cond.tests > /tmp/xx 2>&1 +diff /tmp/xx cond.right && rm -f /tmp/xx diff --git a/tests/run-dirstack b/tests/run-dirstack index a2f2761d..6390d1b7 100644 --- a/tests/run-dirstack +++ b/tests/run-dirstack @@ -1,2 +1,5 @@ -${THIS_SH} ./dirstack.tests > /tmp/xx 2>&1 -diff /tmp/xx dirstack.right && rm -f /tmp/xx +${THIS_SH} ./dstack.tests > /tmp/xx 2>&1 +diff /tmp/xx dstack.right && rm -f /tmp/xx + +${THIS_SH} ./dstack2.tests > /tmp/xx 2>&1 +diff /tmp/xx dstack2.right && rm -f /tmp/xx diff --git a/tests/run-dollars b/tests/run-dollars index e2300267..0ced4145 100644 --- a/tests/run-dollars +++ b/tests/run-dollars @@ -1,3 +1,2 @@ -${THIS_SH} ./dollar-star.sh a b > /tmp/xx 2>&1 -${THIS_SH} ./dollar-at.sh a b >>/tmp/xx 2>&1 +${THIS_SH} ./dollar-at-star > /tmp/xx 2>&1 diff /tmp/xx dollar.right && rm -f /tmp/xx diff --git a/tests/run-execscript b/tests/run-execscript index fdac1eb1..042880c8 100644 --- a/tests/run-execscript +++ b/tests/run-execscript @@ -4,4 +4,4 @@ echo "warning: if the text of the error messages concerning \`notthere' or" >&2 echo "warning: \`/tmp/bash-notthere' not being found or \`/' being a directory" >&2 echo "warning: produce diff output, please do not consider this a test failure" >&2 ${THIS_SH} ./execscript > /tmp/xx 2>&1 -diff /tmp/xx execscript.right && rm -f /tmp/xx +diff /tmp/xx exec.right && rm -f /tmp/xx diff --git a/tests/run-extglob b/tests/run-extglob new file mode 100644 index 00000000..06316ad3 --- /dev/null +++ b/tests/run-extglob @@ -0,0 +1,4 @@ +PATH=$PATH:`pwd` +export PATH +${THIS_SH} ./extglob.tests | grep -v '^expect' > /tmp/xx +diff /tmp/xx extglob.right && rm -f /tmp/xx diff --git a/tests/run-histexpand b/tests/run-histexpand index a9d0bcee..06a415bd 100644 --- a/tests/run-histexpand +++ b/tests/run-histexpand @@ -1,4 +1,4 @@ echo "warning: all of these tests will fail if history has not been compiled" >&2 echo "warning: into the shell" >&2 -${THIS_SH} ./histexpand.tests > /tmp/xx 2>&1 -diff /tmp/xx histexpand.right && rm -f /tmp/xx +${THIS_SH} ./histexp.tests > /tmp/xx 2>&1 +diff /tmp/xx histexp.right && rm -f /tmp/xx diff --git a/tests/run-ifs-tests b/tests/run-ifs-tests index 3d5fc509..a1c6149b 100644 --- a/tests/run-ifs-tests +++ b/tests/run-ifs-tests @@ -1,13 +1,13 @@ # # show that IFS is only applied to the result of expansions # -${THIS_SH} ifs-test-1.sh > /tmp/xx -diff /tmp/xx ./ifs.1.right +${THIS_SH} ifs-1.test > /tmp/xx +diff /tmp/xx ./ifs-1.right -${THIS_SH} ifs-test-2.sh > /tmp/xx -diff /tmp/xx ./ifs.2.right +${THIS_SH} ifs-2.test > /tmp/xx +diff /tmp/xx ./ifs-2.right -${THIS_SH} ifs-test-3.sh > /tmp/xx -diff /tmp/xx ./ifs.3.right +${THIS_SH} ifs-3.test > /tmp/xx +diff /tmp/xx ./ifs-3.right rm -f /tmp/xx diff --git a/tests/run-minimal b/tests/run-minimal index dfe392f8..018916a2 100644 --- a/tests/run-minimal +++ b/tests/run-minimal @@ -25,6 +25,7 @@ do *.orig|*~) ;; run-dollars|run-execscript|run-func|run-getopts|run-heredoc) echo $x ; sh $x ;; run-ifs-tests|run-input-test|run-more-exp|run-nquote|run-posix2) echo $x ; sh $x ;; + run-posixpat) echo $x ; sh $x ;; run-precedence|run-quote|run-read|run-rhs-exp|run-strip|run-tilde) echo $x ; sh $x ;; *) ;; esac diff --git a/tests/run-new-exp b/tests/run-new-exp index a000b6b5..56dff720 100644 --- a/tests/run-new-exp +++ b/tests/run-new-exp @@ -1,2 +1,7 @@ +echo "warning: two of these tests will fail if your OS does not support" >&2 +echo "warning: named pipes or the /dev/fd filesystem. If the tests of the" >&2 +echo "warning: process substitution mechanism fail, please do not consider" >&2 +echo "warning: this a test failure" >&2 + ${THIS_SH} ./new-exp.tests 2>&1 | grep -v '^expect' > /tmp/xx diff /tmp/xx new-exp.right && rm -f /tmp/xx diff --git a/tests/run-posixpat b/tests/run-posixpat new file mode 100644 index 00000000..ef2b140d --- /dev/null +++ b/tests/run-posixpat @@ -0,0 +1,2 @@ +${THIS_SH} ./posixpat.tests > /tmp/xx +diff /tmp/xx posixpat.right && rm -f /tmp/xx diff --git a/tests/run-printf b/tests/run-printf new file mode 100644 index 00000000..10361bce --- /dev/null +++ b/tests/run-printf @@ -0,0 +1,2 @@ +${THIS_SH} ./printf.tests > /tmp/xx 2>&1 +diff /tmp/xx printf.right && rm -f /tmp/xx diff --git a/tests/run-set-e-test b/tests/run-set-e index cca61cd4..cca61cd4 100644 --- a/tests/run-set-e-test +++ b/tests/run-set-e diff --git a/tests/run-shopt b/tests/run-shopt new file mode 100644 index 00000000..100a3de0 --- /dev/null +++ b/tests/run-shopt @@ -0,0 +1,2 @@ +${THIS_SH} ./shopt.tests > /tmp/xx 2>&1 +diff /tmp/xx shopt.right && rm -f /tmp/xx diff --git a/tests/run-trap b/tests/run-trap index 78a164e7..b4484435 100644 --- a/tests/run-trap +++ b/tests/run-trap @@ -1,2 +1,6 @@ +echo "warning: UNIX versions number signals differently. If output differing" >&2 +echo "warning: only in line numbers is produced, please do not consider this" >&2 +echo "warning: a test failure." >&2 + ${THIS_SH} ./trap.tests > /tmp/xx 2>&1 diff /tmp/xx trap.right && rm -f /tmp/xx diff --git a/tests/shopt.right b/tests/shopt.right new file mode 100644 index 00000000..845ee901 --- /dev/null +++ b/tests/shopt.right @@ -0,0 +1,189 @@ +./shopt.tests: shopt: illegal option: -z +shopt: usage: shopt [-pqsu] [-o long-option] optname [optname...] +-- +shopt -u cdable_vars +shopt -s cdspell +shopt -u checkhash +shopt -u checkwinsize +shopt -s cmdhist +shopt -u dotglob +shopt -u execfail +shopt -s expand_aliases +shopt -u extglob +shopt -u histreedit +shopt -u histappend +shopt -u histverify +shopt -s hostcomplete +shopt -u huponexit +shopt -s interactive_comments +shopt -u lithist +shopt -u mailwarn +shopt -u nocaseglob +shopt -u nullglob +shopt -s promptvars +shopt -u shift_verbose +shopt -s sourcepath +-- +shopt -u huponexit +shopt -u checkwinsize +shopt -s sourcepath +-- +shopt -s cdspell +shopt -s cmdhist +shopt -s expand_aliases +shopt -s hostcomplete +shopt -s interactive_comments +shopt -s promptvars +shopt -s sourcepath +-- +shopt -u cdable_vars +shopt -u checkhash +shopt -u checkwinsize +shopt -u dotglob +shopt -u execfail +shopt -u extglob +shopt -u histreedit +shopt -u histappend +shopt -u histverify +shopt -u huponexit +shopt -u lithist +shopt -u mailwarn +shopt -u nocaseglob +shopt -u nullglob +shopt -u shift_verbose +-- +cdable_vars off +checkhash off +checkwinsize off +dotglob off +execfail off +extglob off +histreedit off +histappend off +histverify off +huponexit off +lithist off +mailwarn off +nocaseglob off +nullglob off +shift_verbose off +-- +set +o allexport +set -o braceexpand +set +o errexit +set -o hashall +set -o histexpand +set +o keyword +set -o monitor +set +o noclobber +set +o noexec +set +o noglob +set +o notify +set +o nounset +set +o onecmd +set +o physical +set -o privileged +set +o verbose +set +o xtrace +set -o history +set +o ignoreeof +set +o interactive-comments +set +o posix +set -o emacs +set +o vi +-- +allexport off +braceexpand on +errexit off +hashall on +histexpand on +keyword off +monitor on +noclobber off +noexec off +noglob off +notify off +nounset off +onecmd off +physical off +privileged on +verbose off +xtrace off +history on +ignoreeof off +interactive-comments off +posix off +emacs on +vi off +-- +set +o allexport +set -o braceexpand +set +o errexit +set -o hashall +set -o histexpand +set +o keyword +set -o monitor +set +o noclobber +set +o noexec +set +o noglob +set +o notify +set +o nounset +set +o onecmd +set +o physical +set -o privileged +set +o verbose +set +o xtrace +set -o history +set +o ignoreeof +set +o interactive-comments +set +o posix +set -o emacs +set +o vi +-- +set -o history +set +o verbose +-- +set -o braceexpand +set -o hashall +set -o histexpand +set -o monitor +set -o privileged +set -o history +set -o emacs +-- +set +o allexport +set +o errexit +set +o keyword +set +o noclobber +set +o noexec +set +o noglob +set +o notify +set +o nounset +set +o onecmd +set +o physical +set +o verbose +set +o xtrace +set +o ignoreeof +set +o interactive-comments +set +o posix +set +o vi +-- +allexport off +errexit off +keyword off +noclobber off +noexec off +noglob off +notify off +nounset off +onecmd off +physical off +verbose off +xtrace off +ignoreeof off +interactive-comments off +posix off +vi off +-- +./shopt.tests: shopt: xyz1: unknown shell option name +./shopt.tests: shopt: xyz1: unknown option name diff --git a/tests/shopt.tests b/tests/shopt.tests new file mode 100644 index 00000000..00170a97 --- /dev/null +++ b/tests/shopt.tests @@ -0,0 +1,93 @@ +# let's try an error message first +shopt -z + +# first, set up a known environment +shopt -u cdable_vars +shopt -s cdspell +shopt -u checkhash +shopt -u checkwinsize +shopt -s cmdhist +shopt -u dotglob +shopt -u execfail +shopt -s expand_aliases +shopt -u extglob +shopt -u histreedit +shopt -u histappend +shopt -u histverify +shopt -s hostcomplete +shopt -u huponexit +shopt -s interactive_comments +shopt -u lithist +shopt -u mailwarn +shopt -u nocaseglob +shopt -u nullglob +shopt -s promptvars +shopt -u shift_verbose +shopt -s sourcepath + +# Now, start checking the output +builtin printf -- "--\n" +shopt -p # list 'em all +builtin printf -- "--\n" +# test specific variables +shopt -p huponexit +shopt -p checkwinsize +shopt -p sourcepath + +builtin printf -- "--\n" +shopt -s -p +builtin printf -- "--\n" +shopt -u -p +builtin printf -- "--\n" +shopt -u + +# Now set up another known environment +set +o allexport +set -o braceexpand +set +o errexit +set -o hashall +set -o histexpand +set +o keyword +set -o monitor +set +o noclobber +set +o noexec +set +o noglob +set +o notify +set +o nounset +set +o onecmd +set +o physical +set -o privileged +set +o verbose +set +o xtrace +set -o history +set +o ignoreeof +set -o interactive-comments +set +o posix +set -o emacs +set +o vi + +# list 'em all +builtin printf -- "--\n" +shopt -o -p + +builtin printf -- "--\n" +set -o +builtin printf -- "--\n" +set +o + +# test specific variables +builtin printf -- "--\n" +shopt -p -o history +shopt -p -o verbose + +builtin printf -- "--\n" +shopt -s -p -o +builtin printf -- "--\n" +shopt -u -p -o +builtin printf -- "--\n" +shopt -u -o + +# errors +builtin printf -- "--\n" +shopt -p xyz1 +shopt -o -p xyz1 diff --git a/tests/source.sub1 b/tests/source1.sub index 8b8586f1..8b8586f1 100644 --- a/tests/source.sub1 +++ b/tests/source1.sub diff --git a/tests/source.sub2 b/tests/source2.sub index 7a031a11..7a031a11 100644 --- a/tests/source.sub2 +++ b/tests/source2.sub diff --git a/tests/source.sub3 b/tests/source3.sub index 4a12501f..4a12501f 100644 --- a/tests/source.sub3 +++ b/tests/source3.sub diff --git a/tests/source.sub4 b/tests/source4.sub index 717c1ab9..717c1ab9 100644 --- a/tests/source.sub4 +++ b/tests/source4.sub diff --git a/tests/source5.sub b/tests/source5.sub new file mode 100644 index 00000000..813ffaed --- /dev/null +++ b/tests/source5.sub @@ -0,0 +1,19 @@ +LC_ALL=en_US +unset LC_ALL +unset LANG +export LC_ALL=C +export LANG=C + +set +o posix + +# attempting to source a non-existant file is not an error... +. /tmp/source-notthere + +echo after bad source 1 + +set -o posix + +# ...unless you're in posix mode +. /tmp/source-notthere + +echo after bad source 2 diff --git a/tests/test-tests b/tests/test-tests index 9b813590..d0194d26 100644 --- a/tests/test-tests +++ b/tests/test-tests @@ -161,6 +161,16 @@ echo 't -O /tmp/test.owner' t -O /tmp/test.owner rm -f /tmp/test.owner +touch /tmp/test.socket +echo 't -S /tmp/test.socket' +t -S /tmp/test.socket # false +rm -f /tmp/test.socket + +touch /tmp/test.newer +echo 't -N /tmp/test.newer' +t -N /tmp/test.newer +rm -f /tmp/test.newer + echo 't "hello" = "hello"' t "hello" = "hello" echo 't "hello" = "goodbye"' diff --git a/tests/test.right b/tests/test.right index 4a1fcab2..e534c17b 100644 --- a/tests/test.right +++ b/tests/test.right @@ -84,6 +84,10 @@ t "" 1 t -O /tmp/test.owner 0 +t -S /tmp/test.socket +1 +t -N /tmp/test.newer +0 t "hello" = "hello" 0 t "hello" = "goodbye" diff --git a/tests/trap.right b/tests/trap.right index 442a864b..6fa6ba5b 100644 --- a/tests/trap.right +++ b/tests/trap.right @@ -48,4 +48,8 @@ caught a child death caught a child death caught a child death trap -- 'echo caught a child death' SIGCHLD +trap -- 'echo exiting' EXIT +trap -- 'echo aborting' SIGABRT +trap -- 'echo caught a child death' SIGCHLD +trap -- '' SIGUSR2 exiting diff --git a/tests/trap.tests b/tests/trap.tests index 66337bac..bcf16e52 100644 --- a/tests/trap.tests +++ b/tests/trap.tests @@ -42,7 +42,7 @@ trap # hmmm...should this set the handling to SIG_IGN for children, too? trap '' USR2 -./trap.sub1 +./trap1.sub # # show that setting a trap on SIGCHLD is not disastrous. @@ -56,3 +56,9 @@ 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/trap.sub1 b/tests/trap1.sub index 48f85302..48f85302 100755 --- a/tests/trap.sub1 +++ b/tests/trap1.sub diff --git a/tests/type.right b/tests/type.right index f1c1bcf4..fe2c196e 100644 --- a/tests/type.right +++ b/tests/type.right @@ -8,6 +8,7 @@ alias builtin file file +file func is a function func () { @@ -39,3 +40,7 @@ builtin is a shell builtin /bin/sh /tmp/bash bash is hashed (/tmp/bash) +file +hits command + 1 /bin/sh + 3 /tmp/bash diff --git a/tests/type.tests b/tests/type.tests index 360f9ef3..baf55fc5 100644 --- a/tests/type.tests +++ b/tests/type.tests @@ -23,6 +23,7 @@ type -t m type -t builtin type -t /bin/sh type -t ${THIS_SH} +type -t mv type func # the following two should produce identical output @@ -51,6 +52,8 @@ type func unalias m type m +hash -r + hash -p /bin/sh sh type -p sh @@ -58,3 +61,8 @@ SHBASE=${THIS_SH##*/} hash -p /tmp/$SHBASE $SHBASE type -p $SHBASE type $SHBASE + +type -t $SHBASE + +# make sure the hash table looks right +hash diff --git a/tests/varenv.right b/tests/varenv.right index aa730cfd..771ee640 100644 --- a/tests/varenv.right +++ b/tests/varenv.right @@ -32,3 +32,4 @@ hB braceexpand:hashall hPB braceexpand:hashall:physical +declare -r SHELLOPTS="braceexpand:hashall:physical" diff --git a/tests/varenv.sh b/tests/varenv.sh index e7736a7a..8f5a7163 100644 --- a/tests/varenv.sh +++ b/tests/varenv.sh @@ -157,13 +157,30 @@ echo ${ivar-unset} ivar=42 declare -p ivar +# make sure set [-+]o ignoreeof and $IGNOREEOF are reflected +unset IGNOREEOF +set +o ignoreeof +set -o ignoreeof +if [ "$IGNOREEOF" -ne 10 ]; then + echo "./varenv.sh: set -o ignoreeof is not reflected in IGNOREEOF" >&2 +fi +unset IGNOREEOF +set +o ignoreeof + +# older versions of bash used to not reset RANDOM in subshells correctly +[[ $RANDOM -eq $(echo $RANDOM) ]] && echo "RANDOM: problem with subshells" + # make sure that shopt -o is reflected in $SHELLOPTS # first, get rid of things that might be set automatically via shell # variables set +o posix set +o ignoreeof +set +o monitor echo $- echo ${SHELLOPTS} shopt -so physical echo $- echo ${SHELLOPTS} + +# and make sure it is readonly +readonly -p | grep SHELLOPTS @@ -21,17 +21,17 @@ #include "config.h" -#include <stdio.h> - #if defined (HAVE_UNISTD_H) # include <unistd.h> #endif #include "bashtypes.h" -#include "trap.h" - #include "bashansi.h" +#include <stdio.h> + +#include "trap.h" + #include "shell.h" #include "signames.h" #include "builtins/common.h" @@ -135,7 +135,13 @@ char * signal_name (sig) int sig; { - return ((sig > NSIG || sig < 0) ? "bad signal number" : signal_names[sig]); + char *ret; + + /* on cygwin32, signal_names[sig] could be null */ + ret = (sig > NSIG || sig < 0) ? "bad signal number" : signal_names[sig]; + if (ret == NULL) + ret = "unrecognized signal number"; + return ret; } /* Turn a string into a signal number, or a number into @@ -246,6 +252,8 @@ trap_handler (sig) } #if defined (JOB_CONTROL) && defined (SIGCHLD) + +#ifdef INCLUDE_UNUSED /* Make COMMAND_STRING be executed when SIGCHLD is caught. */ void set_sigchld_trap (command_string) @@ -253,6 +261,7 @@ set_sigchld_trap (command_string) { set_signal (SIGCHLD, command_string); } +#endif /* Make COMMAND_STRING be executed when SIGCHLD is caught iff the current SIGCHLD trap handler is DEFAULT_SIG. */ @@ -272,12 +281,14 @@ set_debug_trap (command) set_signal (DEBUG_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 @@ -515,7 +526,10 @@ run_exit_trap () code = setjmp (top_level); if (code == 0) - parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST); + { + reset_parser (); + parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST); + } else if (code == EXITPROG) return (last_command_exit_value); else @@ -587,6 +601,7 @@ 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 @@ -602,6 +617,7 @@ free_trap_strings () } trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = (char *)NULL; } +#endif /* Reset the handler for SIG to the original value. */ static void diff --git a/variables.c b/variables.c index 212724e9..b72fc4f8 100644 --- a/variables.c +++ b/variables.c @@ -39,15 +39,23 @@ #include "shell.h" #include "flags.h" #include "execute_cmd.h" +#include "findcmd.h" #include "mailcheck.h" #include "input.h" #include "builtins/getopt.h" #include "builtins/common.h" -#include <tilde/tilde.h> + +#if defined (READLINE) +# include "bashline.h" +# include <readline/readline.h> +#else +# include <tilde/tilde.h> +#endif #if defined (HISTORY) # include "bashhist.h" +# include <readline/history.h> #endif /* HISTORY */ /* Variables used here and defined in other files. */ @@ -129,20 +137,22 @@ static int qsort_var_comp (); #define set_auto_export(var) \ do { var->attributes |= att_exported; array_needs_making = 1; } while (0) -/* Initialize the shell variables from the current environment. */ +/* 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, no_functions) +initialize_shell_variables (env, privmode) char **env; - int no_functions; /* If set, don't import functions from ENV. */ + int privmode; { char *name, *string, *temp_string; int c, char_index, string_index, string_length; SHELL_VAR *temp_var; - if (!shell_variables) + if (shell_variables == 0) shell_variables = make_hash_table (0); - if (!shell_functions) + if (shell_functions == 0) shell_functions = make_hash_table (0); for (string_index = 0; string = env[string_index++]; ) @@ -165,7 +175,7 @@ initialize_shell_variables (env, no_functions) char_index == strlen (name) */ /* If exported function, define it now. */ - if (no_functions == 0 && STREQN ("() {", string, 4)) + if (privmode == 0 && STREQN ("() {", string, 4)) { string_length = strlen (string); temp_string = xmalloc (3 + string_length + char_index); @@ -233,7 +243,8 @@ initialize_shell_variables (env, no_functions) temp_string = get_working_directory ("shell-init"); if (temp_string) { - bind_variable ("PWD", temp_string); + temp_var = bind_variable ("PWD", temp_string); + set_auto_export (temp_var); free (temp_string); } } @@ -500,7 +511,7 @@ adjust_shell_level (change) shell_level = 0; else if (shell_level > 1000) { - internal_error ("warning: shell level (%d) too high, resetting to 1", shell_level); + internal_warning ("shell level (%d) too high, resetting to 1", shell_level); shell_level = 1; } @@ -626,7 +637,7 @@ set_if_not (name, value) SHELL_VAR *v; v = find_variable (name); - if (!v) + if (v == 0) v = bind_variable (name, value); return (v); } @@ -873,7 +884,7 @@ assign_seconds (self, value) SHELL_VAR *self; char *value; { - seconds_value_assigned = string_to_long (value); + seconds_value_assigned = strtol (value, (char **)NULL, 10); shell_start_time = NOW; return (self); } @@ -900,18 +911,15 @@ static unsigned long rseed = 1; static unsigned long last_random_value; /* A linear congruential random number generator based on the ANSI - C standard. A more complicated one is overkill. */ + C standard. This one isn't very good (the values are alternately + odd and even, for example), but a more complicated one is overkill. */ /* Returns a pseudo-random number between 0 and 32767. */ static int brand () { rseed = rseed * 1103515245 + 12345; -#if 0 - return ((unsigned int)(rseed / 65536) % 32768); -#else - return ((unsigned int)(rseed % 32768)); -#endif + return ((unsigned int)(rseed & 32767)); /* was % 32768 */ } /* Set the random number generator seed to SEED. */ @@ -1143,7 +1151,8 @@ find_function (name) /* Return the string value of a variable. Return NULL if the variable doesn't exist, or only has a function as a value. Don't cons a new - string. */ + string. This is a potential memory leak if the variable is found + in the temporary environment. */ char * get_string_value (var_name) char *var_name; @@ -1451,6 +1460,8 @@ bind_array_variable (name, ind, value) return (entry); } +/* 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) char *name, *value; @@ -1467,10 +1478,6 @@ assign_array_from_string (name, value) } else if (array_p (var) == 0) var = convert_var_to_array (var); -#if 0 - else - empty_array (array_cell (var)); -#endif return (assign_array_var_from_string (var, value)); } @@ -1492,6 +1499,8 @@ assign_array_var_from_word_list (var, list) return var; } +/* 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) SHELL_VAR *var; @@ -1502,28 +1511,45 @@ assign_array_var_from_string (var, value) char *w, *val, *nval; int ni, len, ind, last_ind; - a = array_cell (var); + if (value == 0) + return var; - /* Expand the value string into a list of words, performing all the - shell expansions including word splitting. */ - if (*value == '(') + /* If this is called from declare_builtin, value[0] == '(' and + strchr(value, ')') != 0. In this case, we need to extract + the value from between the parens before going on. */ + if (*value == '(') /*)*/ { ni = 1; val = extract_array_assignment_list (value, &ni); if (val == 0) - return var; - nlist = expand_string (val, 0); - free (val); + return var; } else - nlist = expand_string (value, 0); + val = value; + /* Expand the value string into a list of words, performing all the + shell expansions including word splitting. */ #if 1 + /* First we split the string on whitespace, using the shell parser + (ksh93 seems to do this). */ + list = parse_string_to_word_list (val, "array assign"); + /* Now that we've split it, perform the shell expansions on each + word in the list. */ + nlist = list ? expand_words_shellexp (list) : (WORD_LIST *)NULL; + dispose_words (list); +#else + nlist = expand_string (val, 0); +#endif + + if (val != value) + free (val); + + a = array_cell (var); + /* Now that we are ready to assign values to the array, kill the existing value. */ if (a) empty_array (a); -#endif for (last_ind = 0, list = nlist; list; list = list->next) { @@ -1656,8 +1682,9 @@ int unbind_variable (name) char *name; { - SHELL_VAR *var = find_variable (name); + SHELL_VAR *var; + var = find_variable (name); if (!var) return (-1); @@ -1947,6 +1974,7 @@ set_var_read_only (name) entry->attributes |= 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 @@ -1983,6 +2011,7 @@ set_func_auto_export (name) if (entry) set_auto_export (entry); } +#endif #if defined (ARRAY_VARS) /* This function assumes s[i] == '['; returns with s[ret] == ']' if @@ -2045,6 +2074,8 @@ assignment (string) return (0); } +#ifdef READLINE + static int visible_var (var) SHELL_VAR *var; @@ -2078,6 +2109,8 @@ all_visible_functions () return (_visible_names (shell_functions)); } +#endif /* READLINE */ + /* Return non-zero if the variable VAR is visible and exported. Array variables cannot be exported. */ static int @@ -2161,7 +2194,6 @@ assign_in_env (string) name = savestring (string); value = (char *)NULL; -#define freetemp nlen if (name[offset] == '=') { name[offset] = 0; @@ -2174,9 +2206,7 @@ assign_in_env (string) return (0); } temp = name + offset + 1; - freetemp = strchr (temp, '~') != 0; - if (freetemp) - temp = bash_tilde_expand (temp); + temp = (strchr (temp, '~') != 0) ? bash_tilde_expand (temp) : savestring (temp); list = expand_string_unsplit (temp, 0); value = string_list (list); @@ -2184,10 +2214,8 @@ assign_in_env (string) if (list) dispose_words (list); - if (freetemp) - free (temp); + free (temp); } -#undef freetemp nlen = strlen (name); vlen = value ? strlen (value) : 0; @@ -2248,12 +2276,15 @@ find_name_in_env_array (name, array) SHELL_VAR *temp; char *w; - temp = new_shell_variable (name); /* XXX memory leak here */ + /* This is a potential memory leak. The code should really save + the created variables in some auxiliary data structure, which + can be disposed of at the appropriate time. */ + temp = new_shell_variable (name); w = array[i] + l + 1; temp->value = *w ? savestring (w) : (char *)NULL; - temp->attributes = att_exported; + temp->attributes = att_exported|att_tempvar; temp->context = 0; temp->prev_context = (SHELL_VAR *)NULL; @@ -2275,7 +2306,9 @@ SHELL_VAR * find_tempenv_variable (name) char *name; { - SHELL_VAR *var = (SHELL_VAR *)NULL; + SHELL_VAR *var; + + var = (SHELL_VAR *)NULL; if (temporary_env) var = find_name_in_env_array (name, temporary_env); @@ -2379,7 +2412,7 @@ do \ export_env[export_env_index] = (char *)NULL; \ } while (0) -#define ISFUNC(s, o) ((s[o + 1] == '(') && (s[o + 2] == ')')) +#define ISFUNCTION(s, o) ((s[o + 1] == '(') && (s[o + 2] == ')')) /* Add ASSIGN to EXPORT_ENV, or supercede a previous assignment in the array with the same left-hand side. Return the new EXPORT_ENV. */ @@ -2492,6 +2525,7 @@ put_command_name_into_env (command_name) export_env = add_or_supercede_exported_var (dummy, 0); } +#if 0 /* UNUSED -- it caused too many problems */ void put_gnu_argv_flags_into_env (pid, flags_string) int pid; @@ -2516,6 +2550,7 @@ put_gnu_argv_flags_into_env (pid, flags_string) export_env = add_or_supercede_exported_var (dummy, 0); } +#endif /* Return a string denoting what our indirection level is. */ static char indirection_string[100]; @@ -2544,3 +2579,374 @@ indirection_level_string () free (ps4); return (indirection_string); } + +/************************************************* + * * + * Functions to manage special variables * + * * + *************************************************/ + +/* Extern declarations for variables this code has to manage. */ +extern int eof_encountered, eof_encountered_limit, ignoreeof; + +#if defined (READLINE) +extern int no_line_editing; +extern int hostname_list_initialized; +#endif + +/* An alist of name.function for each special variable. Most of the + functions don't do much, and in fact, this would be faster with a + switch statement, but by the end of this file, I am sick of switch + statements. */ + +#define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0 + +struct name_and_function { + char *name; + VFunction *function; +} special_vars[] = { + { "PATH", sv_path }, + { "MAIL", sv_mail }, + { "MAILPATH", sv_mail }, + { "MAILCHECK", sv_mail }, + + { "POSIXLY_CORRECT", sv_strict_posix }, + { "GLOBIGNORE", sv_globignore }, + + /* Variables which only do something special when READLINE is defined. */ +#if defined (READLINE) + { "TERM", sv_terminal }, + { "TERMCAP", sv_terminal }, + { "TERMINFO", sv_terminal }, + { "HOSTFILE", sv_hostfile }, +#endif /* READLINE */ + + /* Variables which only do something special when HISTORY is defined. */ +#if defined (HISTORY) + { "HISTIGNORE", sv_histignore }, + { "HISTSIZE", sv_histsize }, + { "HISTFILESIZE", sv_histsize }, + { "HISTCONTROL", sv_history_control }, +# if defined (BANG_HISTORY) + { "histchars", sv_histchars }, +# endif /* BANG_HISTORY */ +#endif /* HISTORY */ + + { "IGNOREEOF", sv_ignoreeof }, + { "ignoreeof", sv_ignoreeof }, + + { "OPTIND", sv_optind }, + { "OPTERR", sv_opterr }, + + { "TEXTDOMAIN", sv_locale }, + { "TEXTDOMAINDIR", sv_locale }, + { "LC_ALL", sv_locale }, + { "LC_COLLATE", sv_locale }, + { "LC_CTYPE", sv_locale }, + { "LC_MESSAGES", sv_locale }, + { "LANG", sv_locale }, + +#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) + { "TZ", sv_tz }, +#endif + + { (char *)0, (VFunction *)0 } +}; + +/* The variable in NAME has just had its state changed. Check to see if it + is one of the special ones where something special happens. */ +void +stupidly_hack_special_variables (name) + char *name; +{ + int i; + + for (i = 0; special_vars[i].name; i++) + { + if (STREQ (special_vars[i].name, name)) + { + (*(special_vars[i].function)) (name); + return; + } + } +} + +/* What to do just after the PATH variable has changed. */ +void +sv_path (name) + char *name; +{ + /* hash -r */ + flush_hashed_filenames (); +} + +/* What to do just after one of the MAILxxxx variables has changed. NAME + is the name of the variable. This is called with NAME set to one of + MAIL, MAILCHECK, or MAILPATH. */ +void +sv_mail (name) + char *name; +{ + /* If the time interval for checking the files has changed, then + reset the mail timer. Otherwise, one of the pathname vars + to the users mailbox has changed, so rebuild the array of + filenames. */ + if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */ + reset_mail_timer (); + else + { + free_mail_files (); + remember_mail_dates (); + } +} + +/* What to do when GLOBIGNORE changes. */ +void +sv_globignore (name) + char *name; +{ + setup_glob_ignore (name); +} + +#if defined (READLINE) +/* What to do just after one of the TERMxxx variables has changed. + If we are an interactive shell, then try to reset the terminal + information in readline. */ +void +sv_terminal (name) + char *name; +{ + if (interactive_shell && no_line_editing == 0) + rl_reset_terminal (get_string_value ("TERM")); +} + +void +sv_hostfile (name) + char *name; +{ + hostname_list_initialized = 0; +} +#endif /* READLINE */ + +#if defined (HISTORY) +/* What to do after the HISTSIZE or HISTFILESIZE variables change. + If there is a value for this HISTSIZE (and it is numeric), then stifle + the history. Otherwise, if there is NO value for this variable, + unstifle the history. If name is HISTFILESIZE, and its value is + numeric, truncate the history file to hold no more than that many + lines. */ +void +sv_histsize (name) + char *name; +{ + char *temp; + long num; + + temp = get_string_value (name); + + if (temp && *temp) + { + if (legal_number (temp, &num)) + { + if (name[4] == 'S') + { + stifle_history (num); + num = where_history (); + if (history_lines_this_session > num) + history_lines_this_session = num; + } + else + { + history_truncate_file (get_string_value ("HISTFILE"), (int)num); + if (num <= history_lines_in_file) + history_lines_in_file = num; + } + } + } + else if (name[4] == 'S') + unstifle_history (); +} + +/* What to do after the HISTIGNORE variable changes. */ +void +sv_histignore (name) + char *name; +{ + setup_history_ignore (name); +} + +/* What to do after the HISTCONTROL variable changes. */ +void +sv_history_control (name) + char *name; +{ + char *temp; + + history_control = 0; + temp = get_string_value (name); + + if (temp && *temp && STREQN (temp, "ignore", 6)) + { + if (temp[6] == 's') /* ignorespace */ + history_control = 1; + else if (temp[6] == 'd') /* ignoredups */ + history_control = 2; + else if (temp[6] == 'b') /* ignoreboth */ + history_control = 3; + } +} + +#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 */ +#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) + int *ps; +{ + SHELL_VAR *v; + ARRAY *a; + register int i; + char *t; + + v = find_variable ("PIPESTATUS"); + if (v == 0) + v = make_new_array_variable ("PIPESTATUS"); + if (array_p (v) == 0) + return; /* Do nothing if not an array variable. */ + a = array_cell (v); + if (a) + empty_array (a); + for (i = 0; ps[i] != -1; i++) + { + t = itos (ps[i]); + array_add_element (a, i, t); + free (t); + } +} +#endif + +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); +#endif +} diff --git a/variables.h b/variables.h index b142c3c0..58ad9b35 100644 --- a/variables.h +++ b/variables.h @@ -27,17 +27,17 @@ typedef struct variable { struct variable *prev_context; /* Value from previous context or NULL. */ } SHELL_VAR; -/* The various attributes that a given variable can have. - We only reserve one byte of the INT. */ -#define att_exported 0x01 /* export to environment */ -#define att_readonly 0x02 /* cannot change */ -#define att_invisible 0x04 /* cannot see */ -#define att_array 0x08 /* value is an array */ -#define att_nounset 0x10 /* cannot unset */ -#define att_function 0x20 /* value is a function */ -#define att_integer 0x40 /* internal representation is int */ -#define att_imported 0x80 /* came from environment */ +/* The various attributes that a given variable can have. */ +#define att_exported 0x001 /* export to environment */ +#define att_readonly 0x002 /* cannot change */ +#define att_invisible 0x004 /* cannot see */ +#define att_array 0x008 /* value is an array */ +#define att_nounset 0x010 /* cannot unset */ +#define att_function 0x020 /* value is a function */ +#define att_integer 0x040 /* internal representation is int */ +#define att_imported 0x080 /* came from environment */ #define att_local 0x100 /* variable is local to a function */ +#define att_tempvar 0x200 /* variable came from the temp environment */ #define exported_p(var) ((((var)->attributes) & (att_exported))) #define readonly_p(var) ((((var)->attributes) & (att_readonly))) @@ -48,6 +48,7 @@ typedef struct variable { #define integer_p(var) ((((var)->attributes) & (att_integer))) #define imported_p(var) ((((var)->attributes) & (att_imported))) #define local_p(var) ((((var)->attributes) & (att_local))) +#define tempvar_p(var) ((((var)->attributes) & (att_tempvar))) #define value_cell(var) ((var)->value) #define function_cell(var) (COMMAND *)((var)->value) @@ -131,6 +132,34 @@ extern SHELL_VAR *assign_array_var_from_string __P((SHELL_VAR *, char *)); extern int unbind_array_element __P((SHELL_VAR *, char *)); extern int skipsubscript __P((char *, int)); extern void print_array_assignment __P((SHELL_VAR *, int)); + +extern void set_pipestatus_array __P((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 *)); + +/* The `special variable' functions that get called when a particular + variable is set. */ +void sv_path (), sv_mail (), sv_ignoreeof (), sv_strict_posix (); +void sv_optind (), sv_opterr (), sv_globignore (), sv_locale (); + +#if defined (READLINE) +void sv_terminal (), sv_hostfile (); +#endif + +#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) +void sv_tz (); +#endif + +#if defined (HISTORY) +void sv_histsize (), sv_histignore (), sv_history_control (); +# if defined (BANG_HISTORY) +void sv_histchars (); +# endif +#endif /* HISTORY */ + #endif /* !_VARIABLES_H_ */ @@ -63,5 +63,5 @@ show_shell_version (extended) { printf ("GNU bash, version %s (%s)\n", shell_version_string (), MACHTYPE); if (extended) - printf ("Copyright 1997 Free Software Foundation, Inc.\n"); + printf ("Copyright 1998 Free Software Foundation, Inc.\n"); } @@ -1,5 +1,5 @@ -/* A Bison parser, made from /usr/homes/chet/src/bash/bash-2.01.1/parse.y +/* A Bison parser, made from /usr/homes/chet/src/bash/src/parse.y by GNU Bison version 1.25 */ @@ -19,27 +19,32 @@ #define DO 269 #define DONE 270 #define FUNCTION 271 -#define IN 272 -#define BANG 273 -#define TIME 274 -#define TIMEOPT 275 -#define WORD 276 -#define ASSIGNMENT_WORD 277 -#define NUMBER 278 -#define AND_AND 279 -#define OR_OR 280 -#define GREATER_GREATER 281 -#define LESS_LESS 282 -#define LESS_AND 283 -#define GREATER_AND 284 -#define SEMI_SEMI 285 -#define LESS_LESS_MINUS 286 -#define AND_GREATER 287 -#define LESS_GREATER 288 -#define GREATER_BAR 289 -#define yacc_EOF 290 - -#line 21 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#define COND_START 272 +#define COND_END 273 +#define COND_ERROR 274 +#define IN 275 +#define BANG 276 +#define TIME 277 +#define TIMEOPT 278 +#define WORD 279 +#define ASSIGNMENT_WORD 280 +#define NUMBER 281 +#define ARITH_CMD 282 +#define COND_CMD 283 +#define AND_AND 284 +#define OR_OR 285 +#define GREATER_GREATER 286 +#define LESS_LESS 287 +#define LESS_AND 288 +#define GREATER_AND 289 +#define SEMI_SEMI 290 +#define LESS_LESS_MINUS 291 +#define AND_GREATER 292 +#define LESS_GREATER 293 +#define GREATER_BAR 294 +#define yacc_EOF 295 + +#line 21 "/usr/homes/chet/src/bash/src/parse.y" #include "config.h" @@ -86,9 +91,11 @@ #endif /* ALIAS */ #if defined (PROMPT_STRING_DECODE) -#include <sys/param.h> -#include <time.h> -#include "maxpath.h" +# ifndef _MINIX +# include <sys/param.h> +# endif +# include <time.h> +# include "maxpath.h" #endif /* PROMPT_STRING_DECODE */ #define RE_READ_TOKEN -99 @@ -96,6 +103,13 @@ #define YYDEBUG 0 +#if defined (EXTENDED_GLOB) +#define PATTERN_CHAR(c) \ + ((c) == '@' || (c) == '*' || (c) == '+' || (c) == '?' || (c) == '!') + +extern int extended_glob; +#endif + extern int eof_encountered; extern int no_line_editing, running_under_emacs; extern int current_command_number; @@ -107,7 +121,7 @@ extern int interrupt_immediately; extern char *shell_name, *current_host_name; extern char *dist_version; extern int patch_level; -extern int dump_translatable_strings; +extern int dump_translatable_strings, dump_po_strings; extern Function *last_shell_builtin, *this_shell_builtin; #if defined (BUFFERED_INPUT) extern int bash_input_fd_changed; @@ -125,6 +139,9 @@ static int reserved_word_acceptable (); static int read_token (); static int yylex (); static int parse_arith_cmd (); +#if defined (COND_COMMAND) +static COMMAND *parse_cond_command (); +#endif static int read_token_word (); static void discard_parser_constructs (); @@ -189,7 +206,7 @@ static int function_bstart; static REDIRECTEE redir; -#line 171 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 183 "/usr/homes/chet/src/bash/src/parse.y" typedef union { WORD_DESC *word; /* the word that we read. */ int number; /* the number that we read. */ @@ -209,26 +226,26 @@ typedef union { -#define YYFINAL 263 +#define YYFINAL 269 #define YYFLAG -32768 -#define YYNTBASE 47 +#define YYNTBASE 52 -#define YYTRANSLATE(x) ((unsigned)(x) <= 290 ? yytranslate[x] : 78) +#define YYTRANSLATE(x) ((unsigned)(x) <= 295 ? yytranslate[x] : 85) static const char yytranslate[] = { 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 37, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 35, 2, 45, - 46, 2, 2, 2, 42, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 36, 41, - 2, 40, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 40, 2, 50, + 51, 2, 2, 2, 47, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 41, 46, + 2, 45, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 43, 39, 44, 2, 2, 2, 2, 2, + 2, 2, 48, 44, 49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -244,7 +261,8 @@ static const char yytranslate[] = { 0, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 38 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 43 }; #if YYDEBUG != 0 @@ -254,67 +272,68 @@ static const short yyprhs[] = { 0, 64, 67, 71, 74, 78, 81, 85, 88, 92, 95, 99, 102, 105, 109, 111, 113, 115, 117, 120, 122, 125, 127, 129, 132, 134, 136, 142, 148, 150, 152, - 154, 156, 158, 165, 172, 180, 188, 199, 210, 217, - 224, 232, 240, 251, 262, 269, 277, 284, 290, 297, - 302, 306, 312, 320, 327, 331, 336, 343, 349, 351, - 354, 359, 364, 370, 376, 379, 383, 385, 389, 392, - 394, 397, 401, 405, 409, 414, 419, 424, 429, 434, - 436, 438, 440, 442, 443, 446, 448, 451, 454, 459, - 464, 468, 472, 474, 476, 479, 482, 486, 490, 495, - 497, 499 + 154, 156, 158, 160, 162, 169, 176, 184, 192, 203, + 214, 221, 228, 236, 244, 255, 266, 273, 281, 288, + 294, 301, 306, 310, 316, 324, 331, 335, 337, 341, + 346, 353, 359, 361, 364, 369, 374, 380, 386, 389, + 393, 395, 399, 402, 404, 407, 411, 415, 419, 424, + 429, 434, 439, 444, 446, 448, 450, 452, 453, 456, + 458, 461, 464, 469, 474, 478, 482, 484, 486, 489, + 492, 496, 500, 505, 507, 509 }; -static const short yyrhs[] = { 73, - 37, 0, 37, 0, 1, 37, 0, 38, 0, 21, - 0, 48, 21, 0, 40, 21, 0, 41, 21, 0, - 23, 40, 21, 0, 23, 41, 21, 0, 26, 21, - 0, 23, 26, 21, 0, 27, 21, 0, 23, 27, - 21, 0, 28, 23, 0, 23, 28, 23, 0, 29, - 23, 0, 23, 29, 23, 0, 28, 21, 0, 23, - 28, 21, 0, 29, 21, 0, 23, 29, 21, 0, - 31, 21, 0, 23, 31, 21, 0, 29, 42, 0, - 23, 29, 42, 0, 28, 42, 0, 23, 28, 42, - 0, 32, 21, 0, 23, 33, 21, 0, 33, 21, - 0, 34, 21, 0, 23, 34, 21, 0, 21, 0, - 22, 0, 49, 0, 49, 0, 51, 49, 0, 50, - 0, 52, 50, 0, 52, 0, 54, 0, 54, 51, - 0, 55, 0, 57, 0, 12, 68, 14, 68, 15, - 0, 13, 68, 14, 68, 15, 0, 56, 0, 60, - 0, 59, 0, 61, 0, 58, 0, 10, 21, 72, - 14, 68, 15, 0, 10, 21, 72, 43, 68, 44, - 0, 10, 21, 36, 72, 14, 68, 15, 0, 10, - 21, 36, 72, 43, 68, 44, 0, 10, 21, 72, - 17, 48, 71, 72, 14, 68, 15, 0, 10, 21, - 72, 17, 48, 71, 72, 43, 68, 44, 0, 11, - 21, 72, 14, 67, 15, 0, 11, 21, 72, 43, - 67, 44, 0, 11, 21, 36, 72, 14, 67, 15, - 0, 11, 21, 36, 72, 43, 67, 44, 0, 11, - 21, 72, 17, 48, 71, 72, 14, 67, 15, 0, - 11, 21, 72, 17, 48, 71, 72, 43, 67, 44, - 0, 8, 21, 72, 17, 72, 9, 0, 8, 21, - 72, 17, 65, 72, 9, 0, 8, 21, 72, 17, - 63, 9, 0, 21, 45, 46, 72, 61, 0, 16, - 21, 45, 46, 72, 61, 0, 16, 21, 72, 61, - 0, 45, 68, 46, 0, 3, 68, 4, 68, 7, - 0, 3, 68, 4, 68, 5, 68, 7, 0, 3, - 68, 4, 68, 62, 7, 0, 43, 67, 44, 0, - 6, 68, 4, 68, 0, 6, 68, 4, 68, 5, - 68, 0, 6, 68, 4, 68, 62, 0, 64, 0, - 65, 64, 0, 72, 66, 46, 68, 0, 72, 66, - 46, 72, 0, 72, 45, 66, 46, 68, 0, 72, - 45, 66, 46, 72, 0, 64, 30, 0, 65, 64, - 30, 0, 21, 0, 66, 39, 21, 0, 72, 69, - 0, 67, 0, 72, 70, 0, 70, 37, 72, 0, - 70, 35, 72, 0, 70, 36, 72, 0, 70, 24, - 72, 70, 0, 70, 25, 72, 70, 0, 70, 35, - 72, 70, 0, 70, 36, 72, 70, 0, 70, 37, - 72, 70, 0, 75, 0, 37, 0, 36, 0, 38, - 0, 0, 72, 37, 0, 74, 0, 74, 35, 0, - 74, 36, 0, 74, 24, 72, 74, 0, 74, 25, - 72, 74, 0, 74, 35, 74, 0, 74, 36, 74, - 0, 75, 0, 76, 0, 18, 76, 0, 77, 76, - 0, 77, 18, 76, 0, 18, 77, 76, 0, 76, - 39, 72, 76, 0, 53, 0, 19, 0, 19, 20, +static const short yyrhs[] = { 80, + 42, 0, 42, 0, 1, 42, 0, 43, 0, 24, + 0, 53, 24, 0, 45, 24, 0, 46, 24, 0, + 26, 45, 24, 0, 26, 46, 24, 0, 31, 24, + 0, 26, 31, 24, 0, 32, 24, 0, 26, 32, + 24, 0, 33, 26, 0, 26, 33, 26, 0, 34, + 26, 0, 26, 34, 26, 0, 33, 24, 0, 26, + 33, 24, 0, 34, 24, 0, 26, 34, 24, 0, + 36, 24, 0, 26, 36, 24, 0, 34, 47, 0, + 26, 34, 47, 0, 33, 47, 0, 26, 33, 47, + 0, 37, 24, 0, 26, 38, 24, 0, 38, 24, + 0, 39, 24, 0, 26, 39, 24, 0, 24, 0, + 25, 0, 54, 0, 54, 0, 56, 54, 0, 55, + 0, 57, 55, 0, 57, 0, 59, 0, 59, 56, + 0, 60, 0, 62, 0, 12, 75, 14, 75, 15, + 0, 13, 75, 14, 75, 15, 0, 61, 0, 65, + 0, 64, 0, 66, 0, 67, 0, 68, 0, 63, + 0, 10, 24, 79, 14, 75, 15, 0, 10, 24, + 79, 48, 75, 49, 0, 10, 24, 41, 79, 14, + 75, 15, 0, 10, 24, 41, 79, 48, 75, 49, + 0, 10, 24, 79, 20, 53, 78, 79, 14, 75, + 15, 0, 10, 24, 79, 20, 53, 78, 79, 48, + 75, 49, 0, 11, 24, 79, 14, 74, 15, 0, + 11, 24, 79, 48, 74, 49, 0, 11, 24, 41, + 79, 14, 74, 15, 0, 11, 24, 41, 79, 48, + 74, 49, 0, 11, 24, 79, 20, 53, 78, 79, + 14, 74, 15, 0, 11, 24, 79, 20, 53, 78, + 79, 48, 74, 49, 0, 8, 24, 79, 20, 79, + 9, 0, 8, 24, 79, 20, 72, 79, 9, 0, + 8, 24, 79, 20, 70, 9, 0, 24, 50, 51, + 79, 66, 0, 16, 24, 50, 51, 79, 66, 0, + 16, 24, 79, 66, 0, 50, 75, 51, 0, 3, + 75, 4, 75, 7, 0, 3, 75, 4, 75, 5, + 75, 7, 0, 3, 75, 4, 75, 69, 7, 0, + 48, 74, 49, 0, 27, 0, 17, 28, 18, 0, + 6, 75, 4, 75, 0, 6, 75, 4, 75, 5, + 75, 0, 6, 75, 4, 75, 69, 0, 71, 0, + 72, 71, 0, 79, 73, 51, 75, 0, 79, 73, + 51, 79, 0, 79, 50, 73, 51, 75, 0, 79, + 50, 73, 51, 79, 0, 71, 35, 0, 72, 71, + 35, 0, 24, 0, 73, 44, 24, 0, 79, 76, + 0, 74, 0, 79, 77, 0, 77, 42, 79, 0, + 77, 40, 79, 0, 77, 41, 79, 0, 77, 29, + 79, 77, 0, 77, 30, 79, 77, 0, 77, 40, + 79, 77, 0, 77, 41, 79, 77, 0, 77, 42, + 79, 77, 0, 82, 0, 42, 0, 41, 0, 43, + 0, 0, 79, 42, 0, 81, 0, 81, 40, 0, + 81, 41, 0, 81, 29, 79, 81, 0, 81, 30, + 79, 81, 0, 81, 40, 81, 0, 81, 41, 81, + 0, 82, 0, 83, 0, 21, 83, 0, 84, 83, + 0, 84, 21, 83, 0, 21, 84, 83, 0, 83, + 44, 79, 83, 0, 58, 0, 22, 0, 22, 23, 0 }; @@ -322,19 +341,19 @@ static const short yyrhs[] = { 73, #if YYDEBUG != 0 static const short yyrline[] = { 0, - 214, 223, 230, 245, 255, 257, 261, 266, 271, 276, - 281, 286, 291, 297, 303, 308, 313, 318, 323, 328, - 333, 338, 343, 350, 357, 362, 367, 372, 377, 382, - 387, 392, 397, 404, 406, 408, 412, 416, 427, 429, - 433, 435, 437, 466, 468, 470, 472, 474, 476, 478, - 480, 482, 486, 488, 490, 492, 494, 496, 500, 504, - 508, 512, 516, 520, 526, 528, 530, 534, 538, 541, - 545, 549, 551, 553, 558, 562, 564, 566, 570, 571, - 575, 577, 579, 581, 585, 586, 590, 592, 601, 609, - 610, 616, 617, 624, 628, 630, 632, 639, 641, 643, - 647, 648, 649, 652, 653, 662, 668, 677, 685, 687, - 689, 696, 699, 703, 705, 710, 715, 720, 727, 730, - 734, 736 + 232, 241, 248, 263, 273, 275, 279, 284, 289, 294, + 299, 304, 309, 315, 321, 326, 331, 336, 341, 346, + 351, 356, 361, 368, 375, 380, 385, 390, 395, 400, + 405, 410, 415, 422, 424, 426, 430, 434, 445, 447, + 451, 453, 455, 484, 486, 488, 490, 492, 494, 496, + 498, 500, 502, 504, 508, 510, 512, 514, 516, 518, + 522, 526, 530, 534, 538, 542, 548, 550, 552, 556, + 560, 563, 567, 571, 573, 575, 580, 584, 588, 592, + 594, 596, 600, 601, 605, 607, 609, 611, 615, 616, + 620, 622, 631, 639, 640, 646, 647, 654, 658, 660, + 662, 669, 671, 673, 677, 678, 679, 682, 683, 692, + 698, 707, 715, 717, 719, 726, 729, 733, 735, 740, + 745, 750, 757, 760, 764, 766 }; #endif @@ -343,32 +362,33 @@ static const short yyrline[] = { 0, static const char * const yytname[] = { "$","error","$undefined.","IF","THEN", "ELSE","ELIF","FI","CASE","ESAC","FOR","SELECT","WHILE","UNTIL","DO","DONE", -"FUNCTION","IN","BANG","TIME","TIMEOPT","WORD","ASSIGNMENT_WORD","NUMBER","AND_AND", -"OR_OR","GREATER_GREATER","LESS_LESS","LESS_AND","GREATER_AND","SEMI_SEMI","LESS_LESS_MINUS", -"AND_GREATER","LESS_GREATER","GREATER_BAR","'&'","';'","'\\n'","yacc_EOF","'|'", -"'>'","'<'","'-'","'{'","'}'","'('","')'","inputunit","word_list","redirection", -"simple_command_element","redirection_list","simple_command","command","shell_command", -"for_command","select_command","case_command","function_def","subshell","if_command", -"group_command","elif_clause","case_clause","pattern_list","case_clause_sequence", +"FUNCTION","COND_START","COND_END","COND_ERROR","IN","BANG","TIME","TIMEOPT", +"WORD","ASSIGNMENT_WORD","NUMBER","ARITH_CMD","COND_CMD","AND_AND","OR_OR","GREATER_GREATER", +"LESS_LESS","LESS_AND","GREATER_AND","SEMI_SEMI","LESS_LESS_MINUS","AND_GREATER", +"LESS_GREATER","GREATER_BAR","'&'","';'","'\\n'","yacc_EOF","'|'","'>'","'<'", +"'-'","'{'","'}'","'('","')'","inputunit","word_list","redirection","simple_command_element", +"redirection_list","simple_command","command","shell_command","for_command", +"select_command","case_command","function_def","subshell","if_command","group_command", +"arith_command","cond_command","elif_clause","case_clause","pattern_list","case_clause_sequence", "pattern","list","compound_list","list0","list1","list_terminator","newline_list", "simple_list","simple_list1","pipeline_command","pipeline","timespec", NULL }; #endif static const short yyr1[] = { 0, - 47, 47, 47, 47, 48, 48, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 50, 50, 50, 51, 51, 52, 52, - 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 55, 55, 55, 55, 55, 55, 56, 56, - 56, 56, 56, 56, 57, 57, 57, 58, 58, 58, - 59, 60, 60, 60, 61, 62, 62, 62, 63, 63, - 64, 64, 64, 64, 65, 65, 66, 66, 67, 68, - 68, 69, 69, 69, 70, 70, 70, 70, 70, 70, - 71, 71, 71, 72, 72, 73, 73, 73, 74, 74, - 74, 74, 74, 75, 75, 75, 75, 75, 76, 76, - 77, 77 + 52, 52, 52, 52, 53, 53, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 55, 55, 55, 56, 56, 57, 57, + 58, 58, 58, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, + 61, 61, 61, 61, 61, 61, 62, 62, 62, 63, + 63, 63, 64, 65, 65, 65, 66, 67, 68, 69, + 69, 69, 70, 70, 71, 71, 71, 71, 72, 72, + 73, 73, 74, 75, 75, 76, 76, 76, 77, 77, + 77, 77, 77, 77, 78, 78, 78, 79, 79, 80, + 80, 80, 81, 81, 81, 81, 81, 82, 82, 82, + 82, 82, 83, 83, 84, 84 }; static const short yyr2[] = { 0, @@ -377,203 +397,217 @@ static const short yyr2[] = { 0, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 5, 5, 1, 1, 1, - 1, 1, 6, 6, 7, 7, 10, 10, 6, 6, - 7, 7, 10, 10, 6, 7, 6, 5, 6, 4, - 3, 5, 7, 6, 3, 4, 6, 5, 1, 2, - 4, 4, 5, 5, 2, 3, 1, 3, 2, 1, - 2, 3, 3, 3, 4, 4, 4, 4, 4, 1, - 1, 1, 1, 0, 2, 1, 2, 2, 4, 4, - 3, 3, 1, 1, 2, 2, 3, 3, 4, 1, - 1, 2 + 1, 1, 1, 1, 6, 6, 7, 7, 10, 10, + 6, 6, 7, 7, 10, 10, 6, 7, 6, 5, + 6, 4, 3, 5, 7, 6, 3, 1, 3, 4, + 6, 5, 1, 2, 4, 4, 5, 5, 2, 3, + 1, 3, 2, 1, 2, 3, 3, 3, 4, 4, + 4, 4, 4, 1, 1, 1, 1, 0, 2, 1, + 2, 2, 4, 4, 3, 3, 1, 1, 2, 2, + 3, 3, 4, 1, 1, 2 }; static const short yydefact[] = { 0, - 0, 104, 0, 0, 0, 104, 104, 0, 0, 121, - 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2, 4, 0, 0, 104, 104, 36, 39, 41, - 120, 42, 44, 48, 45, 52, 50, 49, 51, 0, - 106, 113, 114, 0, 3, 90, 0, 0, 104, 104, - 104, 0, 0, 104, 115, 0, 122, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 11, 13, 19, - 15, 27, 21, 17, 25, 23, 29, 31, 32, 7, - 8, 0, 0, 0, 34, 40, 37, 43, 1, 104, - 104, 107, 108, 104, 0, 116, 104, 105, 89, 91, - 100, 0, 104, 0, 104, 0, 104, 104, 0, 0, - 118, 104, 12, 14, 20, 16, 28, 22, 18, 26, - 24, 30, 33, 9, 10, 75, 0, 71, 38, 0, - 0, 111, 112, 0, 117, 0, 104, 104, 104, 104, - 104, 104, 0, 104, 0, 104, 0, 104, 0, 104, - 0, 0, 104, 70, 0, 109, 110, 0, 0, 119, - 104, 104, 72, 0, 0, 0, 93, 94, 92, 0, - 79, 104, 0, 104, 104, 0, 5, 0, 0, 104, - 104, 0, 0, 0, 46, 47, 0, 68, 0, 0, - 74, 95, 96, 97, 98, 99, 67, 85, 80, 0, - 65, 87, 0, 0, 0, 0, 53, 6, 102, 101, - 103, 104, 54, 0, 0, 59, 104, 60, 69, 73, - 104, 104, 104, 104, 86, 66, 0, 0, 104, 55, - 56, 0, 61, 62, 0, 76, 0, 0, 0, 104, - 88, 81, 82, 104, 104, 104, 104, 104, 78, 83, - 84, 0, 0, 0, 0, 77, 57, 58, 63, 64, - 0, 0, 0 + 0, 108, 0, 0, 0, 108, 108, 0, 0, 0, + 125, 34, 35, 0, 78, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 4, 0, 0, 108, 108, 36, + 39, 41, 124, 42, 44, 48, 45, 54, 50, 49, + 51, 52, 53, 0, 110, 117, 118, 0, 3, 94, + 0, 0, 108, 108, 108, 0, 0, 108, 0, 119, + 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 11, 13, 19, 15, 27, 21, 17, 25, + 23, 29, 31, 32, 7, 8, 0, 0, 0, 34, + 40, 37, 43, 1, 108, 108, 111, 112, 108, 0, + 120, 108, 109, 93, 95, 104, 0, 108, 0, 108, + 0, 108, 108, 0, 0, 79, 122, 108, 12, 14, + 20, 16, 28, 22, 18, 26, 24, 30, 33, 9, + 10, 77, 0, 73, 38, 0, 0, 115, 116, 0, + 121, 0, 108, 108, 108, 108, 108, 108, 0, 108, + 0, 108, 0, 108, 0, 108, 0, 0, 108, 72, + 0, 113, 114, 0, 0, 123, 108, 108, 74, 0, + 0, 0, 97, 98, 96, 0, 83, 108, 0, 108, + 108, 0, 5, 0, 0, 108, 108, 0, 0, 0, + 46, 47, 0, 70, 0, 0, 76, 99, 100, 101, + 102, 103, 69, 89, 84, 0, 67, 91, 0, 0, + 0, 0, 55, 6, 106, 105, 107, 108, 56, 0, + 0, 61, 108, 62, 71, 75, 108, 108, 108, 108, + 90, 68, 0, 0, 108, 57, 58, 0, 63, 64, + 0, 80, 0, 0, 0, 108, 92, 85, 86, 108, + 108, 108, 108, 108, 82, 87, 88, 0, 0, 0, + 0, 81, 59, 60, 65, 66, 0, 0, 0 }; -static const short yydefgoto[] = { 261, - 178, 28, 29, 88, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 164, 170, 171, 172, 204, 46, - 47, 99, 100, 212, 48, 40, 132, 101, 43, 44 +static const short yydefgoto[] = { 267, + 184, 30, 31, 93, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 170, 176, 177, 178, + 210, 50, 51, 104, 105, 218, 52, 44, 138, 106, + 47, 48 }; -static const short yypact[] = { 240, - -25,-32768, -4, 41, 44,-32768,-32768, 49, 348, 0, - -31,-32768, 476, 53, 55, 3, 29, 61, 63, 66, - 71,-32768,-32768, 76, 79,-32768,-32768,-32768,-32768, 165, --32768, 120,-32768,-32768,-32768,-32768,-32768,-32768,-32768, -12, - 89,-32768, 12, 384,-32768,-32768, 99, 276,-32768, 93, - 103, 98, 143, 126, 12, 456,-32768, 127, 151, 153, - 35, 43, 154, 155, 159, 160, 161,-32768,-32768,-32768, +static const short yypact[] = { 246, + -34,-32768, 11, 20, 24,-32768,-32768, 33, -10, 369, + 29, 19,-32768, 529,-32768, 42, 47, 30, 36, 64, + 66, 78, 81,-32768,-32768, 84, 92,-32768,-32768,-32768, +-32768, 155,-32768, 513,-32768,-32768,-32768,-32768,-32768,-32768, +-32768,-32768,-32768, 89, -15,-32768, 77, 410,-32768,-32768, + 130, 287,-32768, 95, 99, 127, 131, 97, 132, 77, + 492,-32768, 100, 128, 129, 44, 56, 134, 135, 136, + 139, 140,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, +-32768,-32768,-32768,-32768,-32768,-32768, 105, 287, 104,-32768, +-32768,-32768, 513,-32768,-32768,-32768, 328, 328,-32768, 492, + 77,-32768,-32768,-32768, 88,-32768, 1,-32768, -1,-32768, + 16,-32768,-32768, 116, -32,-32768, 77,-32768,-32768,-32768, -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, --32768, 140, 276, 137,-32768,-32768,-32768, 120,-32768,-32768, --32768, 312, 312,-32768, 456, 12,-32768,-32768,-32768, 86, --32768, 38,-32768, -1,-32768, 16,-32768,-32768, 157, -28, - 12,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, --32768,-32768,-32768,-32768,-32768,-32768, 86,-32768,-32768, 276, - 276, 15, 15, 420, 12, 128,-32768,-32768,-32768,-32768, --32768,-32768, 4,-32768, 164,-32768, 17,-32768, 164,-32768, - 174, 189,-32768,-32768, -28,-32768,-32768, 312, 312, 12, --32768,-32768,-32768, 201, 276, 276, 276, 276, 276, 200, - 180,-32768, -2,-32768,-32768, 196,-32768, 57, 168,-32768, --32768, 198, 57, 170,-32768,-32768, -28,-32768, 209, 213, --32768,-32768,-32768, 142, 142, 142,-32768,-32768, 190, 1, --32768,-32768, 205, 40, 204, 177,-32768,-32768,-32768,-32768, --32768,-32768,-32768, 207, 183,-32768,-32768,-32768,-32768,-32768, --32768,-32768,-32768,-32768,-32768,-32768, 50, 210,-32768,-32768, --32768, 20,-32768,-32768, 30, 139, 276, 276, 276,-32768, --32768,-32768, 276,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - 276, 215, 188, 218, 191,-32768,-32768,-32768,-32768,-32768, - 236, 237,-32768 +-32768,-32768, 88,-32768,-32768, 287, 287, 69, 69, 451, + 77, 79,-32768,-32768,-32768,-32768,-32768,-32768, 3,-32768, + 144,-32768, 13,-32768, 144,-32768, 141, 157,-32768,-32768, + -32,-32768,-32768, 328, 328, 77,-32768,-32768,-32768, 166, + 287, 287, 287, 287, 287, 169, 147,-32768, -4,-32768, +-32768, 175,-32768, 52, 146,-32768,-32768, 181, 52, 149, +-32768,-32768, -32,-32768, 192, 199,-32768,-32768,-32768, 71, + 71, 71,-32768,-32768, 170, 0,-32768,-32768, 180, -22, + 191, 161,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 196, + 163,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, +-32768,-32768, 28, 189,-32768,-32768,-32768, 17,-32768,-32768, + 25, 114, 287, 287, 287,-32768,-32768,-32768, 287,-32768, +-32768,-32768,-32768,-32768,-32768,-32768, 287, 200, 167, 202, + 171,-32768,-32768,-32768,-32768,-32768, 218, 219,-32768 }; static const short yypgoto[] = {-32768, - 91, -27, 214,-32768,-32768,-32768,-32768,-32768,-32768,-32768, --32768,-32768,-32768, -107, 9,-32768, 74,-32768, 46, -18, - -6,-32768, -60, 64, -22,-32768, 11, 6, -7, 245 + 67, -30, 194,-32768,-32768,-32768,-32768,-32768,-32768,-32768, +-32768,-32768,-32768, -112,-32768,-32768, -19,-32768, 46,-32768, + 18, -17, -6,-32768, -60, 39, -21,-32768, 6, 12, + -8, 220 }; -#define YYLAST 517 - - -static const short yytable[] = { 52, - 53, 55, 154, 83, 87, 42, 201, 82, 98, 226, - 41, 45, 144, 58, 26, 145, 49, 174, 202, 57, - 84, 202, 127, 70, 89, 71, 102, 104, 106, 148, - 180, 110, 149, 244, 98, 98, 96, 98, 90, 91, - 98, 146, 203, 246, 72, 203, 175, 188, 111, 73, - 94, 74, 98, 98, 142, 115, 98, 116, 150, 181, - 129, 50, 245, 118, 51, 119, 98, 130, 131, 54, - 75, 134, 247, 68, 98, 69, 117, 208, 228, 219, - 143, 76, 147, 77, 120, 229, 78, 135, 228, 155, - 136, 79, 209, 210, 211, 240, 80, 42, 42, 81, - 151, 152, 97, 133, 192, 193, 194, 195, 196, 137, - 138, 107, 90, 91, 165, 166, 167, 168, 169, 173, - 139, 140, 141, 92, 93, 83, 160, 83, 103, 182, - 187, 184, 161, 162, 163, 42, 42, 176, 105, 179, - 156, 157, 13, 248, 162, 14, 15, 16, 17, 200, - 18, 19, 20, 21, 189, 190, 108, 83, 83, 24, - 25, 214, 215, 42, 42, 137, 138, 205, 206, 133, - 109, 113, 112, 114, 121, 122, 194, 195, 196, 123, - 124, 125, 128, 126, 177, 85, 12, 13, 185, 232, - 14, 15, 16, 17, 235, 18, 19, 20, 21, 237, - 238, 239, 153, 186, 24, 25, 243, 191, 197, 198, - 207, 213, 216, 218, 236, 220, 221, 251, 230, 225, - 231, 233, 242, 83, 83, 202, 234, 254, 255, 257, - 241, 258, 259, 250, 260, 262, 263, 252, 253, 183, - 1, 256, 2, 86, 249, 199, 217, 3, 227, 4, - 5, 6, 7, 56, 0, 8, 0, 9, 10, 0, - 11, 12, 13, 0, 0, 14, 15, 16, 17, 0, - 18, 19, 20, 21, 0, 0, 22, 23, 2, 24, - 25, 0, 26, 3, 27, 4, 5, 6, 7, 0, - 0, 8, 0, 9, 10, 0, 11, 12, 13, 0, - 0, 14, 15, 16, 17, 0, 18, 19, 20, 21, - 0, 0, 98, 0, 2, 24, 25, 0, 26, 3, - 27, 4, 5, 6, 7, 0, 0, 8, 0, 9, - 10, 0, 11, 12, 13, 0, 0, 14, 15, 16, - 17, 0, 18, 19, 20, 21, 0, 0, 0, 0, - 2, 24, 25, 0, 26, 3, 27, 4, 5, 6, - 7, 0, 0, 8, 0, 0, 10, 0, 11, 12, - 13, 0, 0, 14, 15, 16, 17, 0, 18, 19, - 20, 21, 0, 0, 0, 0, 2, 24, 25, 0, - 26, 3, 27, 4, 5, 6, 7, 0, 0, 8, - 0, 95, 0, 0, 11, 12, 13, 0, 0, 14, - 15, 16, 17, 0, 18, 19, 20, 21, 0, 0, - 0, 0, 2, 24, 25, 0, 26, 3, 27, 4, - 5, 6, 7, 0, 0, 8, 0, 0, 0, 0, - 11, 12, 13, 0, 0, 14, 15, 16, 17, 0, - 18, 19, 20, 21, 0, 0, 98, 0, 2, 24, - 25, 0, 26, 3, 27, 4, 5, 6, 7, 0, - 0, 8, 0, 0, 0, 0, 11, 12, 13, 0, - 0, 14, 15, 16, 17, 0, 18, 19, 20, 21, - 0, 0, 0, 0, 0, 24, 25, 0, 26, 0, - 27, 59, 60, 61, 62, 0, 63, 0, 64, 65, - 0, 0, 0, 0, 0, 66, 67 +#define YYLAST 575 + + +static const short yytable[] = { 56, + 57, 60, 160, 92, 207, 45, 88, 49, 232, 103, + 87, 46, 150, 95, 96, 28, 180, 59, 151, 208, + 148, 234, 89, 208, 97, 98, 186, 133, 235, 154, + 250, 107, 109, 111, 53, 155, 115, 103, 252, 101, + 103, 103, 103, 54, 103, 209, 152, 55, 194, 209, + 181, 62, 117, 75, 103, 76, 58, 103, 103, 78, + 187, 79, 135, 156, 251, 73, 103, 121, 63, 122, + 74, 234, 253, 136, 137, 214, 77, 140, 246, 124, + 225, 125, 80, 167, 168, 169, 149, 81, 153, 82, + 123, 141, 215, 216, 217, 142, 161, 95, 96, 143, + 144, 83, 126, 139, 84, 157, 158, 85, 46, 46, + 198, 199, 200, 201, 202, 86, 143, 144, 254, 168, + 99, 171, 172, 173, 174, 175, 179, 145, 146, 147, + 94, 166, 88, 102, 88, 108, 188, 193, 190, 110, + 112, 162, 163, 182, 113, 185, 114, 46, 46, 116, + 118, 119, 120, 132, 134, 191, 206, 127, 128, 129, + 195, 196, 130, 131, 88, 88, 159, 183, 220, 221, + 139, 192, 197, 211, 212, 46, 46, 203, 90, 13, + 14, 204, 200, 201, 202, 16, 17, 18, 19, 213, + 20, 21, 22, 23, 219, 222, 238, 224, 226, 26, + 27, 241, 227, 208, 231, 236, 243, 244, 245, 237, + 239, 240, 247, 249, 263, 264, 265, 268, 269, 266, + 242, 189, 255, 205, 257, 91, 233, 223, 248, 61, + 88, 88, 0, 0, 260, 261, 0, 0, 0, 256, + 0, 0, 0, 258, 259, 0, 1, 262, 2, 0, + 0, 0, 0, 3, 0, 4, 5, 6, 7, 0, + 0, 8, 9, 0, 0, 0, 10, 11, 0, 12, + 13, 14, 15, 0, 0, 0, 16, 17, 18, 19, + 0, 20, 21, 22, 23, 0, 0, 24, 25, 2, + 26, 27, 0, 28, 3, 29, 4, 5, 6, 7, + 0, 0, 8, 9, 0, 0, 0, 10, 11, 0, + 12, 13, 14, 15, 0, 0, 0, 16, 17, 18, + 19, 0, 20, 21, 22, 23, 0, 0, 103, 0, + 2, 26, 27, 0, 28, 3, 29, 4, 5, 6, + 7, 0, 0, 8, 9, 0, 0, 0, 10, 11, + 0, 12, 13, 14, 15, 0, 0, 0, 16, 17, + 18, 19, 0, 20, 21, 22, 23, 0, 0, 0, + 0, 2, 26, 27, 0, 28, 3, 29, 4, 5, + 6, 7, 0, 0, 8, 9, 0, 0, 0, 0, + 11, 0, 12, 13, 14, 15, 0, 0, 0, 16, + 17, 18, 19, 0, 20, 21, 22, 23, 0, 0, + 0, 0, 2, 26, 27, 0, 28, 3, 29, 4, + 5, 6, 7, 0, 0, 8, 9, 0, 0, 0, + 100, 0, 0, 12, 13, 14, 15, 0, 0, 0, + 16, 17, 18, 19, 0, 20, 21, 22, 23, 0, + 0, 0, 0, 2, 26, 27, 0, 28, 3, 29, + 4, 5, 6, 7, 0, 0, 8, 9, 0, 0, + 0, 0, 0, 0, 12, 13, 14, 15, 0, 0, + 0, 16, 17, 18, 19, 0, 20, 21, 22, 23, + 0, 0, 103, 0, 2, 26, 27, 0, 28, 3, + 29, 4, 5, 6, 7, 0, 0, 8, 9, 0, + 0, 0, 0, 0, 0, 12, 13, 14, 15, 0, + 0, 0, 16, 17, 18, 19, 0, 20, 21, 22, + 23, 0, 0, 0, 0, 0, 26, 27, 14, 28, + 0, 29, 0, 16, 17, 18, 19, 0, 20, 21, + 22, 23, 0, 0, 0, 0, 0, 26, 27, 64, + 65, 66, 67, 0, 68, 0, 69, 70, 0, 0, + 0, 0, 0, 71, 72 }; static const short yycheck[] = { 6, - 7, 9, 110, 26, 32, 0, 9, 26, 37, 9, - 0, 37, 14, 45, 43, 17, 21, 14, 21, 20, - 27, 21, 83, 21, 37, 23, 49, 50, 51, 14, - 14, 54, 17, 14, 37, 37, 44, 37, 24, 25, - 37, 43, 45, 14, 42, 45, 43, 155, 56, 21, - 39, 23, 37, 37, 17, 21, 37, 23, 43, 43, - 88, 21, 43, 21, 21, 23, 37, 90, 91, 21, - 42, 94, 43, 21, 37, 21, 42, 21, 39, 187, - 103, 21, 105, 21, 42, 46, 21, 95, 39, 112, - 97, 21, 36, 37, 38, 46, 21, 92, 93, 21, - 107, 108, 4, 93, 165, 166, 167, 168, 169, 24, - 25, 14, 24, 25, 137, 138, 139, 140, 141, 142, - 35, 36, 37, 35, 36, 148, 134, 150, 36, 148, - 153, 150, 5, 6, 7, 130, 131, 144, 36, 146, - 130, 131, 23, 5, 6, 26, 27, 28, 29, 172, - 31, 32, 33, 34, 161, 162, 14, 180, 181, 40, - 41, 180, 181, 158, 159, 24, 25, 174, 175, 159, - 45, 21, 46, 21, 21, 21, 237, 238, 239, 21, - 21, 21, 46, 44, 21, 21, 22, 23, 15, 212, - 26, 27, 28, 29, 217, 31, 32, 33, 34, 222, - 223, 224, 46, 15, 40, 41, 229, 7, 9, 30, - 15, 44, 15, 44, 221, 7, 4, 240, 15, 30, - 44, 15, 229, 246, 247, 21, 44, 246, 247, 15, - 21, 44, 15, 240, 44, 0, 0, 244, 245, 149, - 1, 248, 3, 30, 236, 172, 183, 8, 203, 10, - 11, 12, 13, 9, -1, 16, -1, 18, 19, -1, - 21, 22, 23, -1, -1, 26, 27, 28, 29, -1, - 31, 32, 33, 34, -1, -1, 37, 38, 3, 40, - 41, -1, 43, 8, 45, 10, 11, 12, 13, -1, - -1, 16, -1, 18, 19, -1, 21, 22, 23, -1, - -1, 26, 27, 28, 29, -1, 31, 32, 33, 34, - -1, -1, 37, -1, 3, 40, 41, -1, 43, 8, - 45, 10, 11, 12, 13, -1, -1, 16, -1, 18, - 19, -1, 21, 22, 23, -1, -1, 26, 27, 28, - 29, -1, 31, 32, 33, 34, -1, -1, -1, -1, - 3, 40, 41, -1, 43, 8, 45, 10, 11, 12, - 13, -1, -1, 16, -1, -1, 19, -1, 21, 22, - 23, -1, -1, 26, 27, 28, 29, -1, 31, 32, - 33, 34, -1, -1, -1, -1, 3, 40, 41, -1, - 43, 8, 45, 10, 11, 12, 13, -1, -1, 16, - -1, 18, -1, -1, 21, 22, 23, -1, -1, 26, - 27, 28, 29, -1, 31, 32, 33, 34, -1, -1, - -1, -1, 3, 40, 41, -1, 43, 8, 45, 10, - 11, 12, 13, -1, -1, 16, -1, -1, -1, -1, - 21, 22, 23, -1, -1, 26, 27, 28, 29, -1, - 31, 32, 33, 34, -1, -1, 37, -1, 3, 40, - 41, -1, 43, 8, 45, 10, 11, 12, 13, -1, - -1, 16, -1, -1, -1, -1, 21, 22, 23, -1, - -1, 26, 27, 28, 29, -1, 31, 32, 33, 34, - -1, -1, -1, -1, -1, 40, 41, -1, 43, -1, - 45, 26, 27, 28, 29, -1, 31, -1, 33, 34, - -1, -1, -1, -1, -1, 40, 41 + 7, 10, 115, 34, 9, 0, 28, 42, 9, 42, + 28, 0, 14, 29, 30, 48, 14, 28, 20, 24, + 20, 44, 29, 24, 40, 41, 14, 88, 51, 14, + 14, 53, 54, 55, 24, 20, 58, 42, 14, 48, + 42, 42, 42, 24, 42, 50, 48, 24, 161, 50, + 48, 23, 61, 24, 42, 26, 24, 42, 42, 24, + 48, 26, 93, 48, 48, 24, 42, 24, 50, 26, + 24, 44, 48, 95, 96, 24, 47, 99, 51, 24, + 193, 26, 47, 5, 6, 7, 108, 24, 110, 24, + 47, 100, 41, 42, 43, 102, 118, 29, 30, 29, + 30, 24, 47, 98, 24, 112, 113, 24, 97, 98, + 171, 172, 173, 174, 175, 24, 29, 30, 5, 6, + 44, 143, 144, 145, 146, 147, 148, 40, 41, 42, + 42, 140, 154, 4, 156, 41, 154, 159, 156, 41, + 14, 136, 137, 150, 14, 152, 50, 136, 137, 18, + 51, 24, 24, 49, 51, 15, 178, 24, 24, 24, + 167, 168, 24, 24, 186, 187, 51, 24, 186, 187, + 165, 15, 7, 180, 181, 164, 165, 9, 24, 25, + 26, 35, 243, 244, 245, 31, 32, 33, 34, 15, + 36, 37, 38, 39, 49, 15, 218, 49, 7, 45, + 46, 223, 4, 24, 35, 15, 228, 229, 230, 49, + 15, 49, 24, 235, 15, 49, 15, 0, 0, 49, + 227, 155, 242, 178, 246, 32, 209, 189, 235, 10, + 252, 253, -1, -1, 252, 253, -1, -1, -1, 246, + -1, -1, -1, 250, 251, -1, 1, 254, 3, -1, + -1, -1, -1, 8, -1, 10, 11, 12, 13, -1, + -1, 16, 17, -1, -1, -1, 21, 22, -1, 24, + 25, 26, 27, -1, -1, -1, 31, 32, 33, 34, + -1, 36, 37, 38, 39, -1, -1, 42, 43, 3, + 45, 46, -1, 48, 8, 50, 10, 11, 12, 13, + -1, -1, 16, 17, -1, -1, -1, 21, 22, -1, + 24, 25, 26, 27, -1, -1, -1, 31, 32, 33, + 34, -1, 36, 37, 38, 39, -1, -1, 42, -1, + 3, 45, 46, -1, 48, 8, 50, 10, 11, 12, + 13, -1, -1, 16, 17, -1, -1, -1, 21, 22, + -1, 24, 25, 26, 27, -1, -1, -1, 31, 32, + 33, 34, -1, 36, 37, 38, 39, -1, -1, -1, + -1, 3, 45, 46, -1, 48, 8, 50, 10, 11, + 12, 13, -1, -1, 16, 17, -1, -1, -1, -1, + 22, -1, 24, 25, 26, 27, -1, -1, -1, 31, + 32, 33, 34, -1, 36, 37, 38, 39, -1, -1, + -1, -1, 3, 45, 46, -1, 48, 8, 50, 10, + 11, 12, 13, -1, -1, 16, 17, -1, -1, -1, + 21, -1, -1, 24, 25, 26, 27, -1, -1, -1, + 31, 32, 33, 34, -1, 36, 37, 38, 39, -1, + -1, -1, -1, 3, 45, 46, -1, 48, 8, 50, + 10, 11, 12, 13, -1, -1, 16, 17, -1, -1, + -1, -1, -1, -1, 24, 25, 26, 27, -1, -1, + -1, 31, 32, 33, 34, -1, 36, 37, 38, 39, + -1, -1, 42, -1, 3, 45, 46, -1, 48, 8, + 50, 10, 11, 12, 13, -1, -1, 16, 17, -1, + -1, -1, -1, -1, -1, 24, 25, 26, 27, -1, + -1, -1, 31, 32, 33, 34, -1, 36, 37, 38, + 39, -1, -1, -1, -1, -1, 45, 46, 26, 48, + -1, 50, -1, 31, 32, 33, 34, -1, 36, 37, + 38, 39, -1, -1, -1, -1, -1, 45, 46, 31, + 32, 33, 34, -1, 36, -1, 38, 39, -1, -1, + -1, -1, -1, 45, 46 }; /* -*-C-*- Note some compilers choke on comments on `#line' lines. */ -#line 3 "/usr/local/lib/bison.simple" +#line 3 "/usr/share/misc/bison.simple" /* Skeleton output parser for bison, Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. @@ -766,7 +800,7 @@ __yy_memcpy (char *to, char *from, int count) #endif #endif -#line 196 "/usr/local/lib/bison.simple" +#line 196 "/usr/share/misc/bison.simple" /* The user can define YYPARSE_PARAM as the name of an argument to be passed into yyparse. The argument should have type void *. @@ -1071,7 +1105,7 @@ yyreduce: switch (yyn) { case 1: -#line 215 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 233 "/usr/homes/chet/src/bash/src/parse.y" { /* Case of regular command. Discard the error safety net,and return the command just parsed. */ @@ -1082,7 +1116,7 @@ case 1: ; break;} case 2: -#line 224 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 242 "/usr/homes/chet/src/bash/src/parse.y" { /* Case of regular command, but not a very interesting one. Return a NULL command. */ @@ -1091,7 +1125,7 @@ case 2: ; break;} case 3: -#line 231 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 249 "/usr/homes/chet/src/bash/src/parse.y" { /* Error during parsing. Return NULL command. */ global_command = (COMMAND *)NULL; @@ -1108,7 +1142,7 @@ case 3: ; break;} case 4: -#line 246 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 264 "/usr/homes/chet/src/bash/src/parse.y" { /* Case of EOF seen by itself. Do ignoreeof or not. */ @@ -1118,57 +1152,57 @@ case 4: ; break;} case 5: -#line 256 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 274 "/usr/homes/chet/src/bash/src/parse.y" { yyval.word_list = make_word_list (yyvsp[0].word, (WORD_LIST *)NULL); ; break;} case 6: -#line 258 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 276 "/usr/homes/chet/src/bash/src/parse.y" { yyval.word_list = make_word_list (yyvsp[0].word, yyvsp[-1].word_list); ; break;} case 7: -#line 262 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 280 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_output_direction, redir); ; break;} case 8: -#line 267 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 285 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (0, r_input_direction, redir); ; break;} case 9: -#line 272 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 290 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_output_direction, redir); ; break;} case 10: -#line 277 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 295 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_input_direction, redir); ; break;} case 11: -#line 282 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 300 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_appending_to, redir); ; break;} case 12: -#line 287 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 305 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_appending_to, redir); ; break;} case 13: -#line 292 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 310 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (0, r_reading_until, redir); @@ -1176,7 +1210,7 @@ case 13: ; break;} case 14: -#line 298 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 316 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_reading_until, redir); @@ -1184,63 +1218,63 @@ case 14: ; break;} case 15: -#line 304 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 322 "/usr/homes/chet/src/bash/src/parse.y" { redir.dest = yyvsp[0].number; yyval.redirect = make_redirection (0, r_duplicating_input, redir); ; break;} case 16: -#line 309 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 327 "/usr/homes/chet/src/bash/src/parse.y" { redir.dest = yyvsp[0].number; yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_input, redir); ; break;} case 17: -#line 314 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 332 "/usr/homes/chet/src/bash/src/parse.y" { redir.dest = yyvsp[0].number; yyval.redirect = make_redirection (1, r_duplicating_output, redir); ; break;} case 18: -#line 319 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 337 "/usr/homes/chet/src/bash/src/parse.y" { redir.dest = yyvsp[0].number; yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_output, redir); ; break;} case 19: -#line 324 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 342 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (0, r_duplicating_input_word, redir); ; break;} case 20: -#line 329 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 347 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_input_word, redir); ; break;} case 21: -#line 334 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 352 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_duplicating_output_word, redir); ; break;} case 22: -#line 339 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 357 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_output_word, redir); ; break;} case 23: -#line 344 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 362 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection @@ -1249,7 +1283,7 @@ case 23: ; break;} case 24: -#line 351 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 369 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection @@ -1258,88 +1292,88 @@ case 24: ; break;} case 25: -#line 358 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 376 "/usr/homes/chet/src/bash/src/parse.y" { redir.dest = 0L; yyval.redirect = make_redirection (1, r_close_this, redir); ; break;} case 26: -#line 363 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 381 "/usr/homes/chet/src/bash/src/parse.y" { redir.dest = 0L; yyval.redirect = make_redirection (yyvsp[-2].number, r_close_this, redir); ; break;} case 27: -#line 368 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 386 "/usr/homes/chet/src/bash/src/parse.y" { redir.dest = 0L; yyval.redirect = make_redirection (0, r_close_this, redir); ; break;} case 28: -#line 373 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 391 "/usr/homes/chet/src/bash/src/parse.y" { redir.dest = 0L; yyval.redirect = make_redirection (yyvsp[-2].number, r_close_this, redir); ; break;} case 29: -#line 378 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 396 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_err_and_out, redir); ; break;} case 30: -#line 383 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 401 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_input_output, redir); ; break;} case 31: -#line 388 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 406 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (0, r_input_output, redir); ; break;} case 32: -#line 393 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 411 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (1, r_output_force, redir); ; break;} case 33: -#line 398 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 416 "/usr/homes/chet/src/bash/src/parse.y" { redir.filename = yyvsp[0].word; yyval.redirect = make_redirection (yyvsp[-2].number, r_output_force, redir); ; break;} case 34: -#line 405 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 423 "/usr/homes/chet/src/bash/src/parse.y" { yyval.element.word = yyvsp[0].word; yyval.element.redirect = 0; ; break;} case 35: -#line 407 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 425 "/usr/homes/chet/src/bash/src/parse.y" { yyval.element.word = yyvsp[0].word; yyval.element.redirect = 0; ; break;} case 36: -#line 409 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 427 "/usr/homes/chet/src/bash/src/parse.y" { yyval.element.redirect = yyvsp[0].redirect; yyval.element.word = 0; ; break;} case 37: -#line 413 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 431 "/usr/homes/chet/src/bash/src/parse.y" { yyval.redirect = yyvsp[0].redirect; ; break;} case 38: -#line 417 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 435 "/usr/homes/chet/src/bash/src/parse.y" { register REDIRECT *t; @@ -1350,23 +1384,23 @@ case 38: ; break;} case 39: -#line 428 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 446 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_simple_command (yyvsp[0].element, (COMMAND *)NULL); ; break;} case 40: -#line 430 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 448 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_simple_command (yyvsp[0].element, yyvsp[-1].command); ; break;} case 41: -#line 434 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 452 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = clean_simple_command (yyvsp[0].command); ; break;} case 42: -#line 436 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 454 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; ; break;} case 43: -#line 438 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 456 "/usr/homes/chet/src/bash/src/parse.y" { COMMAND *tc; @@ -1395,205 +1429,221 @@ case 43: ; break;} case 44: -#line 467 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 485 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; ; break;} case 45: -#line 469 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 487 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; ; break;} case 46: -#line 471 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 489 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_while_command (yyvsp[-3].command, yyvsp[-1].command); ; break;} case 47: -#line 473 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 491 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_until_command (yyvsp[-3].command, yyvsp[-1].command); ; break;} case 48: -#line 475 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 493 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; ; break;} case 49: -#line 477 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 495 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; ; break;} case 50: -#line 479 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 497 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; ; break;} case 51: -#line 481 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 499 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; ; break;} case 52: -#line 483 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 501 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; ; break;} case 53: -#line 487 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" -{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; +#line 503 "/usr/homes/chet/src/bash/src/parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 54: -#line 489 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" -{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("$@", (WORD_LIST *)NULL), yyvsp[-1].command); ; +#line 505 "/usr/homes/chet/src/bash/src/parse.y" +{ yyval.command = yyvsp[0].command; ; break;} case 55: -#line 491 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" -{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; +#line 509 "/usr/homes/chet/src/bash/src/parse.y" +{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} case 56: -#line 493 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" -{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; +#line 511 "/usr/homes/chet/src/bash/src/parse.y" +{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("$@", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} case 57: -#line 495 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" -{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ; +#line 513 "/usr/homes/chet/src/bash/src/parse.y" +{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} case 58: -#line 497 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" -{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ; +#line 515 "/usr/homes/chet/src/bash/src/parse.y" +{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} case 59: -#line 501 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 517 "/usr/homes/chet/src/bash/src/parse.y" +{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ; + break;} +case 60: +#line 519 "/usr/homes/chet/src/bash/src/parse.y" +{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ; + break;} +case 61: +#line 523 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_select_command (yyvsp[-4].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} -case 60: -#line 505 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 62: +#line 527 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_select_command (yyvsp[-4].word, add_string_to_list ("$@", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} -case 61: -#line 509 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 63: +#line 531 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_select_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} -case 62: -#line 513 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 64: +#line 535 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_select_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ; break;} -case 63: -#line 517 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 65: +#line 539 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_select_command (yyvsp[-8].word, (WORD_LIST *)reverse_list (yyvsp[-5].word_list), yyvsp[-1].command); ; break;} -case 64: -#line 521 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 66: +#line 543 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_select_command (yyvsp[-8].word, (WORD_LIST *)reverse_list (yyvsp[-5].word_list), yyvsp[-1].command); ; break;} -case 65: -#line 527 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 67: +#line 549 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_case_command (yyvsp[-4].word, (PATTERN_LIST *)NULL); ; break;} -case 66: -#line 529 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 68: +#line 551 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_case_command (yyvsp[-5].word, yyvsp[-2].pattern); ; break;} -case 67: -#line 531 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 69: +#line 553 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_case_command (yyvsp[-4].word, yyvsp[-1].pattern); ; break;} -case 68: -#line 535 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 70: +#line 557 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command, function_dstart, function_bstart); ; break;} -case 69: -#line 539 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 71: +#line 561 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command, function_dstart, function_bstart); ; break;} -case 70: -#line 542 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 72: +#line 564 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_function_def (yyvsp[-2].word, yyvsp[0].command, function_dstart, function_bstart); ; break;} -case 71: -#line 546 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 73: +#line 568 "/usr/homes/chet/src/bash/src/parse.y" { yyvsp[-1].command->flags |= CMD_WANT_SUBSHELL; yyval.command = yyvsp[-1].command; ; break;} -case 72: -#line 550 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 74: +#line 572 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_if_command (yyvsp[-3].command, yyvsp[-1].command, (COMMAND *)NULL); ; break;} -case 73: -#line 552 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 75: +#line 574 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_if_command (yyvsp[-5].command, yyvsp[-3].command, yyvsp[-1].command); ; break;} -case 74: -#line 554 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 76: +#line 576 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_if_command (yyvsp[-4].command, yyvsp[-2].command, yyvsp[-1].command); ; break;} -case 75: -#line 559 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 77: +#line 581 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_group_command (yyvsp[-1].command); ; break;} -case 76: -#line 563 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 78: +#line 585 "/usr/homes/chet/src/bash/src/parse.y" +{ yyval.command = make_arith_command (yyvsp[0].word_list); ; + break;} +case 79: +#line 589 "/usr/homes/chet/src/bash/src/parse.y" +{ yyval.command = yyvsp[-1].command; ; + break;} +case 80: +#line 593 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_if_command (yyvsp[-2].command, yyvsp[0].command, (COMMAND *)NULL); ; break;} -case 77: -#line 565 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 81: +#line 595 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_if_command (yyvsp[-4].command, yyvsp[-2].command, yyvsp[0].command); ; break;} -case 78: -#line 567 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 82: +#line 597 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = make_if_command (yyvsp[-3].command, yyvsp[-1].command, yyvsp[0].command); ; break;} -case 80: -#line 572 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 84: +#line 602 "/usr/homes/chet/src/bash/src/parse.y" { yyvsp[0].pattern->next = yyvsp[-1].pattern; yyval.pattern = yyvsp[0].pattern; ; break;} -case 81: -#line 576 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 85: +#line 606 "/usr/homes/chet/src/bash/src/parse.y" { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, yyvsp[0].command); ; break;} -case 82: -#line 578 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 86: +#line 608 "/usr/homes/chet/src/bash/src/parse.y" { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, (COMMAND *)NULL); ; break;} -case 83: -#line 580 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 87: +#line 610 "/usr/homes/chet/src/bash/src/parse.y" { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, yyvsp[0].command); ; break;} -case 84: -#line 582 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 88: +#line 612 "/usr/homes/chet/src/bash/src/parse.y" { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, (COMMAND *)NULL); ; break;} -case 86: -#line 587 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 90: +#line 617 "/usr/homes/chet/src/bash/src/parse.y" { yyvsp[-1].pattern->next = yyvsp[-2].pattern; yyval.pattern = yyvsp[-1].pattern; ; break;} -case 87: -#line 591 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 91: +#line 621 "/usr/homes/chet/src/bash/src/parse.y" { yyval.word_list = make_word_list (yyvsp[0].word, (WORD_LIST *)NULL); ; break;} -case 88: -#line 593 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 92: +#line 623 "/usr/homes/chet/src/bash/src/parse.y" { yyval.word_list = make_word_list (yyvsp[0].word, yyvsp[-2].word_list); ; break;} -case 89: -#line 602 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 93: +#line 632 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; if (need_here_doc) gather_here_documents (); ; break;} -case 91: -#line 611 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 95: +#line 641 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; ; break;} -case 93: -#line 618 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 97: +#line 648 "/usr/homes/chet/src/bash/src/parse.y" { if (yyvsp[-2].command->type == cm_connection) yyval.command = connect_async_list (yyvsp[-2].command, (COMMAND *)NULL, '&'); @@ -1601,16 +1651,16 @@ case 93: yyval.command = command_connect (yyvsp[-2].command, (COMMAND *)NULL, '&'); ; break;} -case 95: -#line 629 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 99: +#line 659 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, AND_AND); ; break;} -case 96: -#line 631 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 100: +#line 661 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, OR_OR); ; break;} -case 97: -#line 633 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 101: +#line 663 "/usr/homes/chet/src/bash/src/parse.y" { if (yyvsp[-3].command->type == cm_connection) yyval.command = connect_async_list (yyvsp[-3].command, yyvsp[0].command, '&'); @@ -1618,28 +1668,28 @@ case 97: yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, '&'); ; break;} -case 98: -#line 640 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 102: +#line 670 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, ';'); ; break;} -case 99: -#line 642 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 103: +#line 672 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, ';'); ; break;} -case 100: -#line 644 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 104: +#line 674 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; ; break;} -case 106: -#line 663 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 110: +#line 693 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; if (need_here_doc) gather_here_documents (); ; break;} -case 107: -#line 669 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 111: +#line 699 "/usr/homes/chet/src/bash/src/parse.y" { if (yyvsp[-1].command->type == cm_connection) yyval.command = connect_async_list (yyvsp[-1].command, (COMMAND *)NULL, '&'); @@ -1649,24 +1699,24 @@ case 107: gather_here_documents (); ; break;} -case 108: -#line 678 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 112: +#line 708 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[-1].command; if (need_here_doc) gather_here_documents (); ; break;} -case 109: -#line 686 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 113: +#line 716 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, AND_AND); ; break;} -case 110: -#line 688 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 114: +#line 718 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, OR_OR); ; break;} -case 111: -#line 690 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 115: +#line 720 "/usr/homes/chet/src/bash/src/parse.y" { if (yyvsp[-2].command->type == cm_connection) yyval.command = connect_async_list (yyvsp[-2].command, yyvsp[0].command, '&'); @@ -1674,65 +1724,65 @@ case 111: yyval.command = command_connect (yyvsp[-2].command, yyvsp[0].command, '&'); ; break;} -case 112: -#line 697 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 116: +#line 727 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = command_connect (yyvsp[-2].command, yyvsp[0].command, ';'); ; break;} -case 113: -#line 700 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 117: +#line 730 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; ; break;} -case 114: -#line 704 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 118: +#line 734 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; ; break;} -case 115: -#line 706 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 119: +#line 736 "/usr/homes/chet/src/bash/src/parse.y" { yyvsp[0].command->flags |= CMD_INVERT_RETURN; yyval.command = yyvsp[0].command; ; break;} -case 116: -#line 711 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 120: +#line 741 "/usr/homes/chet/src/bash/src/parse.y" { yyvsp[0].command->flags |= yyvsp[-1].number; yyval.command = yyvsp[0].command; ; break;} -case 117: -#line 716 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 121: +#line 746 "/usr/homes/chet/src/bash/src/parse.y" { yyvsp[0].command->flags |= yyvsp[-2].number; yyval.command = yyvsp[0].command; ; break;} -case 118: -#line 721 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 122: +#line 751 "/usr/homes/chet/src/bash/src/parse.y" { yyvsp[0].command->flags |= yyvsp[-1].number|CMD_INVERT_RETURN; yyval.command = yyvsp[0].command; ; break;} -case 119: -#line 729 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 123: +#line 759 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, '|'); ; break;} -case 120: -#line 731 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 124: +#line 761 "/usr/homes/chet/src/bash/src/parse.y" { yyval.command = yyvsp[0].command; ; break;} -case 121: -#line 735 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 125: +#line 765 "/usr/homes/chet/src/bash/src/parse.y" { yyval.number = CMD_TIME_PIPELINE; ; break;} -case 122: -#line 737 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +case 126: +#line 767 "/usr/homes/chet/src/bash/src/parse.y" { yyval.number = CMD_TIME_PIPELINE|CMD_TIME_POSIX; ; break;} } /* the action file gets copied in in place of this dollarsign */ -#line 498 "/usr/local/lib/bison.simple" +#line 498 "/usr/share/misc/bison.simple" yyvsp -= yylen; yyssp -= yylen; @@ -1928,7 +1978,7 @@ yyerrhandle: yystate = yyn; goto yynewstate; } -#line 739 "/usr/homes/chet/src/bash/bash-2.01.1/parse.y" +#line 769 "/usr/homes/chet/src/bash/src/parse.y" /* Possible states for the parser that require it to do special things. */ @@ -1940,6 +1990,8 @@ yyerrhandle: #define PST_SUBSHELL 0x020 /* ( ... ) subshell */ #define PST_CMDSUBST 0x040 /* $( ... ) command substitution */ #define PST_CASESTMT 0x080 /* parsing a case statement */ +#define PST_CONDCMD 0x100 /* parsing a [[...]] command */ +#define PST_CONDEXPR 0x200 /* parsing the guts of [[...]] */ /* Initial size to allocate for tokens, and the amount to grow them by. */ @@ -2277,6 +2329,11 @@ typedef struct 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 @@ -2291,10 +2348,8 @@ push_stream (reset_lineno) saver->bstream = (BUFFERED_STREAM *)NULL; /* If we have a buffered stream, clear out buffers[fd]. */ if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0) - { - saver->bstream = buffers[bash_input.location.buffered_fd]; - buffers[bash_input.location.buffered_fd] = (BUFFERED_STREAM *)NULL; - } + saver->bstream = set_buffered_stream (bash_input.location.buffered_fd, + (BUFFERED_STREAM *)NULL); #endif /* BUFFERED_INPUT */ saver->line = line_number; @@ -2340,7 +2395,7 @@ pop_stream () saver->bstream->b_fd = default_buffered_input; } } - buffers[bash_input.location.buffered_fd] = saver->bstream; + set_buffered_stream (bash_input.location.buffered_fd, saver->bstream); } #endif /* BUFFERED_INPUT */ @@ -2373,7 +2428,11 @@ stream_on_stack (type) * everything between a `;;' and the next `)' or `esac' */ -#if defined (ALIAS) +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) + +#if !defined (ALIAS) +typedef void *alias_t; +#endif #define END_OF_ALIAS 0 @@ -2390,7 +2449,9 @@ 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; @@ -2417,12 +2478,16 @@ push_string (s, expand, ap) 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); @@ -2456,8 +2521,10 @@ pop_string () 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); } @@ -2471,14 +2538,17 @@ free_string_list () { t1 = t->next; FREE (t->saved_line); - t->expander->flags &= ~AL_BEINGEXPANDED; +#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 */ +#endif /* ALIAS || DPAREN_ARITHMETIC */ /* 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 @@ -2603,6 +2673,10 @@ STRING_INT_ALIST word_token_alist[] = { { "{", '{' }, { "}", '}' }, { "!", BANG }, +#if defined (COND_COMMAND) + { "[[", COND_START }, + { "]]", COND_END }, +#endif { (char *)NULL, 0} }; @@ -2650,16 +2724,16 @@ shell_getc (remove_quoted_newline) QUIT; -#if defined (ALIAS) +#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 */ +#else /* !ALIAS && !DPAREN_ARITHMETIC */ if (!shell_input_line || !shell_input_line[shell_input_line_index]) -#endif /* !ALIAS */ +#endif /* !ALIAS && !DPAREN_ARITHMETIC */ { line_number++; @@ -2810,7 +2884,7 @@ shell_getc (remove_quoted_newline) goto restart_read; } -#if defined (ALIAS) +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) /* If C is NULL, we have reached the end of the current input string. If pushed_string_list is non-empty, it's time to pop to the previous string because we have fully consumed the result of the last alias expansion. @@ -2832,7 +2906,7 @@ shell_getc (remove_quoted_newline) c = ' '; } } -#endif /* ALIAS */ +#endif /* ALIAS || DPAREN_ARITHMETIC */ if (!c && shell_input_line_terminator == EOF) return ((shell_input_line_index != 0) ? '\n' : EOF); @@ -2983,10 +3057,16 @@ static int open_brace_count; { \ if ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \ break; \ + if (word_token_alist[i].token == TIME) \ + 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) \ @@ -3040,6 +3120,27 @@ alias_expand_token (token) } #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 '&': + 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. @@ -3054,6 +3155,14 @@ alias_expand_token (token) before that was FUNCTION. `}' is recognized if there is an unclosed `{' prsent. + + `-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 @@ -3119,9 +3228,21 @@ special_case_tokens (token) return ('}'); } +#if defined (COMMAND_TIMING) /* Handle -p after `time'. */ if (last_read_token == TIME && token[0] == '-' && token[1] == 'p' && !token[2]) return (TIMEOPT); +#endif + +#if defined (COMMAND_TIMING) + if (STREQ (token, "time") && time_command_acceptable ()) + return (TIME); +#endif /* COMMAND_TIMING */ + +#if defined (COND_COMMAND) /* [[ */ + if ((parser_state & PST_CONDEXPR) && token[0] == ']' && token[1] == ']' && token[2] == '\0') + return (COND_END); +#endif return (-1); } @@ -3136,13 +3257,10 @@ reset_parser () parser_state = 0; -#if defined (ALIAS) +#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) if (pushed_string_list) - { - free_string_list (); - pushed_string_list = (STRING_SAVER *)NULL; - } -#endif /* ALIAS */ + free_string_list (); +#endif /* ALIAS || DPAREN_ARITHMETIC */ if (shell_input_line) { @@ -3186,6 +3304,26 @@ read_token (command) 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) + { + if (EOF_Reached && cond_token != COND_ERROR) /* [[ */ + parser_error (cond_lineno, "unexpected EOF while looking for `]]'"); + else if (cond_token != COND_ERROR) + parser_error (cond_lineno, "syntax error in conditional expression"); + 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 () */ @@ -3273,17 +3411,17 @@ read_token (command) { int cmdtyp, sline; char *wval; + WORD_DESC *wd; sline = line_number; cmdtyp = parse_arith_cmd (&wval); if (cmdtyp == 1) /* arithmetic command */ { - word_desc_to_read = make_word (wval); - word_desc_to_read->flags = W_QUOTED; - token_to_read = WORD; - free (wval); - yylval.word = make_word ("let"); - return (WORD); + wd = make_word (wval); + wd->flags = W_QUOTED; + yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL); + free (wval); /* make_word copies it */ + return (ARITH_CMD); } else if (cmdtyp == 0) /* nested subshell */ { @@ -3555,6 +3693,175 @@ parse_arith_cmd (ep) } #endif /* DPAREN_ARITHMETIC */ +#if defined (COND_COMMAND) +static COND_COM *cond_term (); +static COND_COM *cond_and (); +static COND_COM *cond_or (); +static COND_COM *cond_expr (); + +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 (interactive && (bash_input.type == st_stdin || bash_input.type == st_stream)) + 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; + + /* 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); /* ( */ + 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); + parser_error (line_number, "unexpected argument to conditional unary operator"); + COND_RETURN_ERROR (); + } + + (void)cond_skip_newlines (); + } + else /* 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; + else if (tok == '<' || tok == '>') + op = make_word_from_token (tok); + else if (tok == COND_END || tok == AND_AND || tok == OR_OR) + { + /* Special case. [[ x ]] is equivalent to [[ -n x ]], just like + the test command. Similarly for [[ x && expr ]] or + [[ x || expr ]] */ + op = make_word ("-n"); + term = make_cond_node (COND_UNARY, op, tleft, (COND_COM *)NULL); + cond_token = tok; + return (term); + } + 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 + { + parser_error (line_number, "unexpected argument to conditional binary operator"); + dispose_cond_node (tleft); + dispose_word (op); + COND_RETURN_ERROR (); + } + + (void)cond_skip_newlines (); + } + 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 + static int read_token_word (character) int character; @@ -3651,6 +3958,34 @@ read_token_word (character) 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 (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_digits = 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 defined (PROCESS_SUBSTITUTION) @@ -3696,13 +4031,16 @@ read_token_word (character) /* This handles $'...' and $"..." new-style quoted strings. */ else if (character == '$' && (peek_char == '\'' || peek_char == '"')) { + int first_line; + + first_line = line_number; ttok = parse_matched_pair (peek_char, peek_char, peek_char, &ttoklen, 0); if (ttok == &matched_pair_error) return -1; if (peek_char == '\'') ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen); else - ttrans = localeexpand (ttok, 0, ttoklen - 1, &ttranslen); + ttrans = localeexpand (ttok, 0, ttoklen - 1, first_line, &ttranslen); free (ttok); RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 2, token_buffer_size, @@ -3894,9 +4232,9 @@ ansiexpand (string, start, end, lenp) by the caller. The length of the translated string is returned in LENP, if non-null. */ static char * -localeexpand (string, start, end, lenp) +localeexpand (string, start, end, lineno, lenp) char *string; - int start, end, *lenp; + int start, end, lineno, *lenp; { int len, tlen; char *temp, *t; @@ -3909,7 +4247,11 @@ localeexpand (string, start, end, lenp) /* If we're just dumping translatable strings, don't do anything. */ if (dump_translatable_strings) { - printf ("\"%s\"\n", temp); + if (dump_po_strings) + printf ("#: %s:%d\nmsgid \"%s\"\nmsgstr \"\"\n", + (bash_input.name ? bash_input.name : "stdin"), lineno, temp); + else + printf ("\"%s\"\n", temp); if (lenp) *lenp = tlen; return (temp); @@ -4042,6 +4384,8 @@ history_delimiting_chars () else return "; "; /* (...) subshell */ } + else if (token_before_that == WORD && two_tokens_ago == FUNCTION) + return " "; /* function def using `function name' without `()' */ for (i = 0; no_semi_successors[i]; i++) { @@ -4244,6 +4588,12 @@ decode_prompt_string (string) } goto add_string; + case 'r': + temp = xmalloc (2); + temp[0] = '\r'; + temp[1] = '\0'; + goto add_string; + case 'n': temp = xmalloc (3); temp[0] = no_line_editing ? '\n' : '\r'; @@ -21,25 +21,30 @@ typedef union { #define DO 269 #define DONE 270 #define FUNCTION 271 -#define IN 272 -#define BANG 273 -#define TIME 274 -#define TIMEOPT 275 -#define WORD 276 -#define ASSIGNMENT_WORD 277 -#define NUMBER 278 -#define AND_AND 279 -#define OR_OR 280 -#define GREATER_GREATER 281 -#define LESS_LESS 282 -#define LESS_AND 283 -#define GREATER_AND 284 -#define SEMI_SEMI 285 -#define LESS_LESS_MINUS 286 -#define AND_GREATER 287 -#define LESS_GREATER 288 -#define GREATER_BAR 289 -#define yacc_EOF 290 +#define COND_START 272 +#define COND_END 273 +#define COND_ERROR 274 +#define IN 275 +#define BANG 276 +#define TIME 277 +#define TIMEOPT 278 +#define WORD 279 +#define ASSIGNMENT_WORD 280 +#define NUMBER 281 +#define ARITH_CMD 282 +#define COND_CMD 283 +#define AND_AND 284 +#define OR_OR 285 +#define GREATER_GREATER 286 +#define LESS_LESS 287 +#define LESS_AND 288 +#define GREATER_AND 289 +#define SEMI_SEMI 290 +#define LESS_LESS_MINUS 291 +#define AND_GREATER 292 +#define LESS_GREATER 293 +#define GREATER_BAR 294 +#define yacc_EOF 295 extern YYSTYPE yylval; |