From da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968 Mon Sep 17 00:00:00 2001 From: chin Date: Fri, 17 Aug 2007 12:01:52 -0700 Subject: 6437624 RFE: Add ksh93 (as /usr/bin/ksh93) and libshell.so to OS/Net 6505835 AST tools and library (libpp) required for creating l10n messages for ksh93 PSARC/2006/550 Korn Shell 93 Integration PSARC/2006/587 /etc/ksh.kshrc for ksh93 PSARC/2007/035 ksh93 Amendments Contributed by Roland Mainz --HG-- rename : usr/src/lib/libcmd/common/mapfile-vers => deleted_files/usr/src/lib/libcmd/common/mapfile-vers rename : usr/src/lib/libcmd/common/placeholder.c => deleted_files/usr/src/lib/libcmd/common/placeholder.c --- usr/src/lib/libshell/common/COMPATIBILITY | 129 + usr/src/lib/libshell/common/DESIGN | 163 + usr/src/lib/libshell/common/OBSOLETE | 152 + usr/src/lib/libshell/common/PROMO.mm | 141 + usr/src/lib/libshell/common/README | 227 + usr/src/lib/libshell/common/RELEASE | 1455 ++++ usr/src/lib/libshell/common/RELEASE88 | 422 ++ usr/src/lib/libshell/common/RELEASE93 | 455 ++ usr/src/lib/libshell/common/bltins/alarm.c | 276 + usr/src/lib/libshell/common/bltins/cd_pwd.c | 280 + usr/src/lib/libshell/common/bltins/cflow.c | 118 + usr/src/lib/libshell/common/bltins/getopts.c | 185 + usr/src/lib/libshell/common/bltins/hist.c | 309 + usr/src/lib/libshell/common/bltins/misc.c | 589 ++ usr/src/lib/libshell/common/bltins/mkservice.c | 494 ++ usr/src/lib/libshell/common/bltins/print.c | 897 +++ usr/src/lib/libshell/common/bltins/read.c | 590 ++ .../lib/libshell/common/bltins/shiocmd_solaris.c | 1180 ++++ usr/src/lib/libshell/common/bltins/shopen.c | 533 ++ usr/src/lib/libshell/common/bltins/sleep.c | 190 + usr/src/lib/libshell/common/bltins/test.c | 629 ++ usr/src/lib/libshell/common/bltins/trap.c | 347 + usr/src/lib/libshell/common/bltins/typeset.c | 979 +++ usr/src/lib/libshell/common/bltins/ulimit.c | 211 + usr/src/lib/libshell/common/bltins/umask.c | 98 + usr/src/lib/libshell/common/bltins/whence.c | 273 + usr/src/lib/libshell/common/builtins.mm | 631 ++ usr/src/lib/libshell/common/data/aliases.c | 58 + usr/src/lib/libshell/common/data/bash_pre_rc.sh | 221 + usr/src/lib/libshell/common/data/builtins.c | 1833 +++++ usr/src/lib/libshell/common/data/keywords.c | 63 + usr/src/lib/libshell/common/data/lexstates.c | 411 ++ usr/src/lib/libshell/common/data/limits.c | 57 + usr/src/lib/libshell/common/data/math.tab | 64 + usr/src/lib/libshell/common/data/msg.c | 188 + usr/src/lib/libshell/common/data/options.c | 140 + usr/src/lib/libshell/common/data/signals.c | 227 + usr/src/lib/libshell/common/data/solaris_cmdlist.h | 128 + usr/src/lib/libshell/common/data/strdata.c | 104 + usr/src/lib/libshell/common/data/testops.c | 168 + usr/src/lib/libshell/common/data/variables.c | 105 + usr/src/lib/libshell/common/edit/completion.c | 522 ++ usr/src/lib/libshell/common/edit/edit.c | 1489 ++++ usr/src/lib/libshell/common/edit/emacs.c | 1444 ++++ usr/src/lib/libshell/common/edit/hexpand.c | 736 ++ usr/src/lib/libshell/common/edit/history.c | 1109 +++ usr/src/lib/libshell/common/edit/vi.c | 2635 +++++++ usr/src/lib/libshell/common/features/cmds | 1 + usr/src/lib/libshell/common/features/dynamic | 12 + usr/src/lib/libshell/common/features/externs | 12 + usr/src/lib/libshell/common/features/locale | 25 + usr/src/lib/libshell/common/features/math | 4 + usr/src/lib/libshell/common/features/math.sh | 158 + usr/src/lib/libshell/common/features/options | 46 + usr/src/lib/libshell/common/features/poll | 149 + usr/src/lib/libshell/common/features/rlimits | 3 + usr/src/lib/libshell/common/features/setjmp | 18 + usr/src/lib/libshell/common/features/sigfeatures | 49 + usr/src/lib/libshell/common/features/time | 35 + usr/src/lib/libshell/common/features/ttys | 3 + usr/src/lib/libshell/common/fun/dirs | 108 + usr/src/lib/libshell/common/fun/gnaw | 1029 +++ usr/src/lib/libshell/common/fun/mandelbrotset1 | 234 + usr/src/lib/libshell/common/fun/popd | 111 + usr/src/lib/libshell/common/fun/pushd | 111 + usr/src/lib/libshell/common/fun/rssread | 414 ++ usr/src/lib/libshell/common/fun/termclock | 267 + usr/src/lib/libshell/common/fun/title | 57 + usr/src/lib/libshell/common/include/argnod.h | 147 + usr/src/lib/libshell/common/include/builtins.h | 200 + usr/src/lib/libshell/common/include/defs.h | 377 + usr/src/lib/libshell/common/include/edit.h | 257 + usr/src/lib/libshell/common/include/env.h | 50 + usr/src/lib/libshell/common/include/fault.h | 124 + usr/src/lib/libshell/common/include/fcin.h | 62 + usr/src/lib/libshell/common/include/history.h | 75 + usr/src/lib/libshell/common/include/io.h | 123 + usr/src/lib/libshell/common/include/jobs.h | 159 + usr/src/lib/libshell/common/include/lexstates.h | 151 + usr/src/lib/libshell/common/include/name.h | 208 + usr/src/lib/libshell/common/include/national.h | 37 + usr/src/lib/libshell/common/include/nval.h | 305 + usr/src/lib/libshell/common/include/path.h | 140 + usr/src/lib/libshell/common/include/shell.h | 245 + usr/src/lib/libshell/common/include/shlex.h | 152 + usr/src/lib/libshell/common/include/shnodes.h | 222 + usr/src/lib/libshell/common/include/shtable.h | 65 + usr/src/lib/libshell/common/include/streval.h | 195 + usr/src/lib/libshell/common/include/terminal.h | 195 + usr/src/lib/libshell/common/include/test.h | 71 + usr/src/lib/libshell/common/include/timeout.h | 30 + usr/src/lib/libshell/common/include/ulimit.h | 175 + usr/src/lib/libshell/common/include/variables.h | 104 + usr/src/lib/libshell/common/include/version.h | 20 + usr/src/lib/libshell/common/llib-lshell | 138 + usr/src/lib/libshell/common/nval.3 | 619 ++ usr/src/lib/libshell/common/sh.1 | 7453 ++++++++++++++++++++ usr/src/lib/libshell/common/sh.memo | 3248 +++++++++ usr/src/lib/libshell/common/sh/args.c | 846 +++ usr/src/lib/libshell/common/sh/arith.c | 363 + usr/src/lib/libshell/common/sh/array.c | 865 +++ usr/src/lib/libshell/common/sh/bash.c | 430 ++ usr/src/lib/libshell/common/sh/defs.c | 47 + usr/src/lib/libshell/common/sh/deparse.c | 584 ++ usr/src/lib/libshell/common/sh/env.c | 255 + usr/src/lib/libshell/common/sh/expand.c | 465 ++ usr/src/lib/libshell/common/sh/fault.c | 573 ++ usr/src/lib/libshell/common/sh/fcin.c | 211 + usr/src/lib/libshell/common/sh/init.c | 1465 ++++ usr/src/lib/libshell/common/sh/io.c | 2215 ++++++ usr/src/lib/libshell/common/sh/jobs.c | 1706 +++++ usr/src/lib/libshell/common/sh/lex.c | 2276 ++++++ usr/src/lib/libshell/common/sh/macro.c | 2301 ++++++ usr/src/lib/libshell/common/sh/main.c | 769 ++ usr/src/lib/libshell/common/sh/name.c | 2382 +++++++ usr/src/lib/libshell/common/sh/nvdisc.c | 1263 ++++ usr/src/lib/libshell/common/sh/nvtree.c | 679 ++ usr/src/lib/libshell/common/sh/parse.c | 1757 +++++ usr/src/lib/libshell/common/sh/path.c | 1697 +++++ usr/src/lib/libshell/common/sh/pmain.c | 30 + usr/src/lib/libshell/common/sh/shcomp.c | 172 + usr/src/lib/libshell/common/sh/streval.c | 904 +++ usr/src/lib/libshell/common/sh/string.c | 704 ++ usr/src/lib/libshell/common/sh/subshell.c | 555 ++ usr/src/lib/libshell/common/sh/suid_exec.c | 509 ++ usr/src/lib/libshell/common/sh/tdump.c | 260 + usr/src/lib/libshell/common/sh/timers.c | 248 + usr/src/lib/libshell/common/sh/trestore.c | 342 + usr/src/lib/libshell/common/sh/waitevent.c | 54 + usr/src/lib/libshell/common/sh/xec.c | 2947 ++++++++ usr/src/lib/libshell/common/shell.3 | 408 ++ usr/src/lib/libshell/common/tests/alias.sh | 83 + usr/src/lib/libshell/common/tests/append.sh | 72 + usr/src/lib/libshell/common/tests/arith.sh | 466 ++ usr/src/lib/libshell/common/tests/arrays.sh | 381 + usr/src/lib/libshell/common/tests/attributes.sh | 216 + usr/src/lib/libshell/common/tests/basic.sh | 336 + usr/src/lib/libshell/common/tests/bracket.sh | 233 + usr/src/lib/libshell/common/tests/builtins.sh | 451 ++ usr/src/lib/libshell/common/tests/case.sh | 81 + usr/src/lib/libshell/common/tests/comvar.sh | 197 + usr/src/lib/libshell/common/tests/coprocess.sh | 218 + usr/src/lib/libshell/common/tests/exit.sh | 81 + usr/src/lib/libshell/common/tests/expand.sh | 123 + usr/src/lib/libshell/common/tests/functions.sh | 758 ++ usr/src/lib/libshell/common/tests/glob.sh | 303 + usr/src/lib/libshell/common/tests/grep.sh | 102 + usr/src/lib/libshell/common/tests/heredoc.sh | 213 + usr/src/lib/libshell/common/tests/io.sh | 251 + usr/src/lib/libshell/common/tests/nameref.sh | 229 + usr/src/lib/libshell/common/tests/options.sh | 313 + usr/src/lib/libshell/common/tests/path.sh | 186 + usr/src/lib/libshell/common/tests/quoting.sh | 331 + usr/src/lib/libshell/common/tests/quoting2.sh | 200 + usr/src/lib/libshell/common/tests/return.sh | 177 + usr/src/lib/libshell/common/tests/select.sh | 63 + usr/src/lib/libshell/common/tests/shtests | 63 + usr/src/lib/libshell/common/tests/substring.sh | 504 ++ .../libshell/common/tests/sun_solaris_getconf.sh | 160 + usr/src/lib/libshell/common/tests/tilde.sh | 87 + usr/src/lib/libshell/common/tests/variables.sh | 558 ++ 161 files changed, 79566 insertions(+) create mode 100644 usr/src/lib/libshell/common/COMPATIBILITY create mode 100644 usr/src/lib/libshell/common/DESIGN create mode 100644 usr/src/lib/libshell/common/OBSOLETE create mode 100644 usr/src/lib/libshell/common/PROMO.mm create mode 100644 usr/src/lib/libshell/common/README create mode 100644 usr/src/lib/libshell/common/RELEASE create mode 100644 usr/src/lib/libshell/common/RELEASE88 create mode 100644 usr/src/lib/libshell/common/RELEASE93 create mode 100644 usr/src/lib/libshell/common/bltins/alarm.c create mode 100644 usr/src/lib/libshell/common/bltins/cd_pwd.c create mode 100644 usr/src/lib/libshell/common/bltins/cflow.c create mode 100644 usr/src/lib/libshell/common/bltins/getopts.c create mode 100644 usr/src/lib/libshell/common/bltins/hist.c create mode 100644 usr/src/lib/libshell/common/bltins/misc.c create mode 100644 usr/src/lib/libshell/common/bltins/mkservice.c create mode 100644 usr/src/lib/libshell/common/bltins/print.c create mode 100644 usr/src/lib/libshell/common/bltins/read.c create mode 100644 usr/src/lib/libshell/common/bltins/shiocmd_solaris.c create mode 100644 usr/src/lib/libshell/common/bltins/shopen.c create mode 100644 usr/src/lib/libshell/common/bltins/sleep.c create mode 100644 usr/src/lib/libshell/common/bltins/test.c create mode 100644 usr/src/lib/libshell/common/bltins/trap.c create mode 100644 usr/src/lib/libshell/common/bltins/typeset.c create mode 100644 usr/src/lib/libshell/common/bltins/ulimit.c create mode 100644 usr/src/lib/libshell/common/bltins/umask.c create mode 100644 usr/src/lib/libshell/common/bltins/whence.c create mode 100644 usr/src/lib/libshell/common/builtins.mm create mode 100644 usr/src/lib/libshell/common/data/aliases.c create mode 100644 usr/src/lib/libshell/common/data/bash_pre_rc.sh create mode 100644 usr/src/lib/libshell/common/data/builtins.c create mode 100644 usr/src/lib/libshell/common/data/keywords.c create mode 100644 usr/src/lib/libshell/common/data/lexstates.c create mode 100644 usr/src/lib/libshell/common/data/limits.c create mode 100644 usr/src/lib/libshell/common/data/math.tab create mode 100644 usr/src/lib/libshell/common/data/msg.c create mode 100644 usr/src/lib/libshell/common/data/options.c create mode 100644 usr/src/lib/libshell/common/data/signals.c create mode 100644 usr/src/lib/libshell/common/data/solaris_cmdlist.h create mode 100644 usr/src/lib/libshell/common/data/strdata.c create mode 100644 usr/src/lib/libshell/common/data/testops.c create mode 100644 usr/src/lib/libshell/common/data/variables.c create mode 100644 usr/src/lib/libshell/common/edit/completion.c create mode 100644 usr/src/lib/libshell/common/edit/edit.c create mode 100644 usr/src/lib/libshell/common/edit/emacs.c create mode 100644 usr/src/lib/libshell/common/edit/hexpand.c create mode 100644 usr/src/lib/libshell/common/edit/history.c create mode 100644 usr/src/lib/libshell/common/edit/vi.c create mode 100644 usr/src/lib/libshell/common/features/cmds create mode 100644 usr/src/lib/libshell/common/features/dynamic create mode 100644 usr/src/lib/libshell/common/features/externs create mode 100644 usr/src/lib/libshell/common/features/locale create mode 100644 usr/src/lib/libshell/common/features/math create mode 100644 usr/src/lib/libshell/common/features/math.sh create mode 100644 usr/src/lib/libshell/common/features/options create mode 100644 usr/src/lib/libshell/common/features/poll create mode 100644 usr/src/lib/libshell/common/features/rlimits create mode 100644 usr/src/lib/libshell/common/features/setjmp create mode 100644 usr/src/lib/libshell/common/features/sigfeatures create mode 100644 usr/src/lib/libshell/common/features/time create mode 100644 usr/src/lib/libshell/common/features/ttys create mode 100644 usr/src/lib/libshell/common/fun/dirs create mode 100644 usr/src/lib/libshell/common/fun/gnaw create mode 100644 usr/src/lib/libshell/common/fun/mandelbrotset1 create mode 100644 usr/src/lib/libshell/common/fun/popd create mode 100644 usr/src/lib/libshell/common/fun/pushd create mode 100644 usr/src/lib/libshell/common/fun/rssread create mode 100644 usr/src/lib/libshell/common/fun/termclock create mode 100644 usr/src/lib/libshell/common/fun/title create mode 100644 usr/src/lib/libshell/common/include/argnod.h create mode 100644 usr/src/lib/libshell/common/include/builtins.h create mode 100644 usr/src/lib/libshell/common/include/defs.h create mode 100644 usr/src/lib/libshell/common/include/edit.h create mode 100644 usr/src/lib/libshell/common/include/env.h create mode 100644 usr/src/lib/libshell/common/include/fault.h create mode 100644 usr/src/lib/libshell/common/include/fcin.h create mode 100644 usr/src/lib/libshell/common/include/history.h create mode 100644 usr/src/lib/libshell/common/include/io.h create mode 100644 usr/src/lib/libshell/common/include/jobs.h create mode 100644 usr/src/lib/libshell/common/include/lexstates.h create mode 100644 usr/src/lib/libshell/common/include/name.h create mode 100644 usr/src/lib/libshell/common/include/national.h create mode 100644 usr/src/lib/libshell/common/include/nval.h create mode 100644 usr/src/lib/libshell/common/include/path.h create mode 100644 usr/src/lib/libshell/common/include/shell.h create mode 100644 usr/src/lib/libshell/common/include/shlex.h create mode 100644 usr/src/lib/libshell/common/include/shnodes.h create mode 100644 usr/src/lib/libshell/common/include/shtable.h create mode 100644 usr/src/lib/libshell/common/include/streval.h create mode 100644 usr/src/lib/libshell/common/include/terminal.h create mode 100644 usr/src/lib/libshell/common/include/test.h create mode 100644 usr/src/lib/libshell/common/include/timeout.h create mode 100644 usr/src/lib/libshell/common/include/ulimit.h create mode 100644 usr/src/lib/libshell/common/include/variables.h create mode 100644 usr/src/lib/libshell/common/include/version.h create mode 100644 usr/src/lib/libshell/common/llib-lshell create mode 100644 usr/src/lib/libshell/common/nval.3 create mode 100644 usr/src/lib/libshell/common/sh.1 create mode 100644 usr/src/lib/libshell/common/sh.memo create mode 100644 usr/src/lib/libshell/common/sh/args.c create mode 100644 usr/src/lib/libshell/common/sh/arith.c create mode 100644 usr/src/lib/libshell/common/sh/array.c create mode 100644 usr/src/lib/libshell/common/sh/bash.c create mode 100644 usr/src/lib/libshell/common/sh/defs.c create mode 100644 usr/src/lib/libshell/common/sh/deparse.c create mode 100644 usr/src/lib/libshell/common/sh/env.c create mode 100644 usr/src/lib/libshell/common/sh/expand.c create mode 100644 usr/src/lib/libshell/common/sh/fault.c create mode 100644 usr/src/lib/libshell/common/sh/fcin.c create mode 100644 usr/src/lib/libshell/common/sh/init.c create mode 100644 usr/src/lib/libshell/common/sh/io.c create mode 100644 usr/src/lib/libshell/common/sh/jobs.c create mode 100644 usr/src/lib/libshell/common/sh/lex.c create mode 100644 usr/src/lib/libshell/common/sh/macro.c create mode 100644 usr/src/lib/libshell/common/sh/main.c create mode 100644 usr/src/lib/libshell/common/sh/name.c create mode 100644 usr/src/lib/libshell/common/sh/nvdisc.c create mode 100644 usr/src/lib/libshell/common/sh/nvtree.c create mode 100644 usr/src/lib/libshell/common/sh/parse.c create mode 100644 usr/src/lib/libshell/common/sh/path.c create mode 100644 usr/src/lib/libshell/common/sh/pmain.c create mode 100644 usr/src/lib/libshell/common/sh/shcomp.c create mode 100644 usr/src/lib/libshell/common/sh/streval.c create mode 100644 usr/src/lib/libshell/common/sh/string.c create mode 100644 usr/src/lib/libshell/common/sh/subshell.c create mode 100644 usr/src/lib/libshell/common/sh/suid_exec.c create mode 100644 usr/src/lib/libshell/common/sh/tdump.c create mode 100644 usr/src/lib/libshell/common/sh/timers.c create mode 100644 usr/src/lib/libshell/common/sh/trestore.c create mode 100644 usr/src/lib/libshell/common/sh/waitevent.c create mode 100644 usr/src/lib/libshell/common/sh/xec.c create mode 100644 usr/src/lib/libshell/common/shell.3 create mode 100644 usr/src/lib/libshell/common/tests/alias.sh create mode 100644 usr/src/lib/libshell/common/tests/append.sh create mode 100644 usr/src/lib/libshell/common/tests/arith.sh create mode 100644 usr/src/lib/libshell/common/tests/arrays.sh create mode 100644 usr/src/lib/libshell/common/tests/attributes.sh create mode 100644 usr/src/lib/libshell/common/tests/basic.sh create mode 100644 usr/src/lib/libshell/common/tests/bracket.sh create mode 100644 usr/src/lib/libshell/common/tests/builtins.sh create mode 100644 usr/src/lib/libshell/common/tests/case.sh create mode 100644 usr/src/lib/libshell/common/tests/comvar.sh create mode 100644 usr/src/lib/libshell/common/tests/coprocess.sh create mode 100644 usr/src/lib/libshell/common/tests/exit.sh create mode 100644 usr/src/lib/libshell/common/tests/expand.sh create mode 100644 usr/src/lib/libshell/common/tests/functions.sh create mode 100644 usr/src/lib/libshell/common/tests/glob.sh create mode 100644 usr/src/lib/libshell/common/tests/grep.sh create mode 100644 usr/src/lib/libshell/common/tests/heredoc.sh create mode 100644 usr/src/lib/libshell/common/tests/io.sh create mode 100644 usr/src/lib/libshell/common/tests/nameref.sh create mode 100644 usr/src/lib/libshell/common/tests/options.sh create mode 100644 usr/src/lib/libshell/common/tests/path.sh create mode 100644 usr/src/lib/libshell/common/tests/quoting.sh create mode 100644 usr/src/lib/libshell/common/tests/quoting2.sh create mode 100644 usr/src/lib/libshell/common/tests/return.sh create mode 100644 usr/src/lib/libshell/common/tests/select.sh create mode 100644 usr/src/lib/libshell/common/tests/shtests create mode 100644 usr/src/lib/libshell/common/tests/substring.sh create mode 100644 usr/src/lib/libshell/common/tests/sun_solaris_getconf.sh create mode 100644 usr/src/lib/libshell/common/tests/tilde.sh create mode 100644 usr/src/lib/libshell/common/tests/variables.sh (limited to 'usr/src/lib/libshell/common') diff --git a/usr/src/lib/libshell/common/COMPATIBILITY b/usr/src/lib/libshell/common/COMPATIBILITY new file mode 100644 index 0000000000..8f20d44374 --- /dev/null +++ b/usr/src/lib/libshell/common/COMPATIBILITY @@ -0,0 +1,129 @@ + + KSH-93 VS. KSH-88 + + +The following is a list of known incompatibilities between ksh-93 and ksh-88. +I have not include cases that are clearly bugs in ksh-88. I also have +omitted features that are completely upward compatible. + +1. Functions, defined with name() with ksh-93 are compatible with + the POSIX standard, not with ksh-88. No local variables are + permitted, and there is no separate scope. Functions defined + with the function name syntax, maintain compatibility. + This also affects function traces. + +2. ! is now a reserved word. As a result, any command by that + name will no longer work with ksh-93. + +3. The -x attribute of alias and typeset -f is no longer + effective and the ENV file is only read for interactive + shells. You need to use FPATH to make function definitions + visible to scripts. + +4. A built-in command named command has been added which is + always found before the PATH search. Any script which uses + this name as the name of a command (or function) will not + be compatible. + +5. The output format for some built-ins has changed. In particular + the output format for set, typeset and alias now have single + quotes around values that have special characters. The output + for trap without arguments has a format that can be used as input. + +6. With ksh-88, a dollar sign ($') followed by a single quote was + interpreted literally. Now it is an ANSI-C string. You + must quote the dollar sign to get the previous behavior. + Also, a $ in front of a " indicates that the string needs + to be translated for locales other than C or POSIX. The $ + is ignored in the C and POSIX locale. + +7. With ksh-88, tilde expansion did not take place inside ${...}. + with ksh-93, ${foo-~} will cause tilde expansion if foo is + not set. You need to escape the ~ for the previous behavior. + +8. Some changes in the tokenizing rules where made that might + cause some scripts with previously ambiguous use of quoting + to produce syntax errors. + +9. Programs that rely on specific exit values for the shell, + (rather than 0 or non-zero) may not be compatible. The + exit status for many shell failures has been changed. + +10. Built-ins in ksh-88 were always executed before looking for + the command in the PATH variable. This is no longer true. + Thus, with ksh-93, if you have the current directory first + in your PATH, and you have a program named test in your + directory, it will be executed when you type test; the + built-in version will be run at the point /bin is found + in your PATH. + +11. Some undocumented combinations of argument passing to ksh + builtins no longer works since ksh-93 is getopts conforming + with respect to its built-ins. For example, typeset -8i + previously would work as a synonym for typeset -i8. + +12. Command substitution and arithmetic expansion are now performed + on PS1, PS3, and ENV when they are expanded. Thus, ` and $( + as part of the value of these variables must be preceded by a \ + to preserve their previous behavior. + +13. The ERRNO variable has been dropped. + +14. If the file name following a redirection symbol contain pattern + characters they will only be expanded for interactive shells. + +15. The arguments to a dot script will be restored when it completes. + +16. The list of tracked aliases is not displayed with alias unless + the -t option is specified. + +17. The POSIX standard requires that test "$arg" have exit status + of 0, if and only if $arg is null. However, since this breaks + programs that use test -t, ksh93 treats an explicit test -t + as if the user had entered test -t 1. + +18. The ^T directive of emacs mode has been changed to work the + way it does in gnu-emacs. + +19. ksh-88 allowed unbalanced parenthes within ${name op val} whereas + ksh-93 does not. Thus, ${foo-(} needs to be written as ${foo-\(} + which works with both versions. + +20. kill -l in ksh-93 lists only the signal names, not their numerical + values. + +21. Local variables defined by typeset are statically scoped in + ksh93. In ksh88 they were dynamically scoped although this + behavior was never documented. + +22. The value of the variable given to getopts is set to ? when + the end-of-options is reached to conform to the POSIX standard. + +23. Since the POSIX standard requires that octal constants be + recongnized, doing arithmetic on typeset -Z variables can + yield different results that with ksh88. Most of these + differences were eliminated in ksh93o. + +24. Starting after ksh93l, If you run ksh name, where name does + not contain a /, the current directory will be searched + before doing a path search on name as required by the POSIX + shell standard. + +25. In ksh93, cd - will output the directory that it changes + to on standard output as required by X/Open. With ksh88, + this only happened for interactive shells. + +26. As an undocumented feature of ksh-88, a leading 0 to an + assignment of an integer variable caused that variable + to be treated as unsigned. This behavior was removed + starting in ksh93p. + +27. The getopts builtin in ksh93 requires that optstring contain + a leading + to allow options to begin with a +. + +28. In emacs/gmacs mode, control-v will not display the version when + the stty lnext character is set to control-v or is unset. + The sequence escape control-v will display the shell version. + +I am interested in expanding this list so please let me know if you +uncover any others. diff --git a/usr/src/lib/libshell/common/DESIGN b/usr/src/lib/libshell/common/DESIGN new file mode 100644 index 0000000000..8e35e3fc55 --- /dev/null +++ b/usr/src/lib/libshell/common/DESIGN @@ -0,0 +1,163 @@ +Here is an overview of the source code organization for ksh93. + +Directory layout: + + The directory include contains header files for ksh93. + The files nval.h and shell.h are intended to be public + headers and can be used to add runtime builtin command. + The remainder are private. + + The directory data contains readonly data files for ksh93. + + The directory edit contains the code for command line + editing and history. + + The fun directory contains some shell function such as + pushd, popd, and dirs. + + The directory features contains files that are used to generate + header files in the FEATURE directory. Most of these files + are in a format that is processed by iffe. + + The directory bltins contains code for most of the built-in + commands. Additional built-in commands are part of libcmd. + + The directory sh contains most of the code for ksh93. + + The directory tests contains a number of regression tests. + In most cases, when a bug gets fixed, a test is added to + one of these files. The regression tests can be run by + going to this directory and running + SHELL=shell_path shell_path shtests + where shell_path is an absolute pathname for the shell to + be tested. + + The top level directory contains the nmake Makefile, a README, + and several documentation files. The RELEASE file contains + the list of bug fixes and new features since the original + ksh93 release. The file COMPATIBILITY is a list of all + known incompatibilities with ksh88. + + The bash_pre_rc.sh is a startup script used when emulating + bash if the shell is compiled with SHOPT_BASH and the shell + is invoked as bash. The bash emulation is not complete. + +Include directory: + 1. argnod.h contains the type definitions for command + nodes, io nodes, argument nodes, and for positional + parameters.a It defines the prototypes for + all the positional parameters functions. + 2. builtins.h contains prototypes for builtins as well + as symbolic constants that refer to the name-pairs + that are associated with some of the built-ins. + It also contains prototypes for many of the strings. + 3. defs.h is the catch all for all definitions that + don't fit elsewhere and it includes several other + headers. It defines a strucuture that contains ksh + global data, sh, and a structure that contains per + function data, sh.st. + 4. edit.h contains definitions that are common to both + vi and emacs edit modes. + 5. env.h contains interfaces for creating and modifying + environment variables. + 6. fault.h contains prototypes for signal related + functions and trap and fault handling. + 7. fcin.h contains macro and function definitions for + reading from a file or string. + 8. history.h contains macros and functions definitions + related to history file processing. + 9. jobs.h contains the definitions relating to job + processing and control. + 10. lexstates.h contains the states associated with + lexical processing. + 11. name.h contains the internal definitions related + to name-value pair processing. + 12. national.h contains a few I18N definitions, mostly + obsolete. + 13. nval.h is the public interface to the name-value + pair library that is documented with nval.3. + 14. path.h contains the interface for pathname processing + and pathname searching. + 15. shell.h is the public interface for shell functions + that are documented int shell.3. + 16. shlex.h contains the lexical token definitions and + interfaces for lexical analysis. + 17. shnodes.h contains the definition of the structures + for each of the parse nodes and flags for the attributes. + 18. shtable.h contains some interfaces and functions for + table lookup. + 19. streval.h contains the interface to the arithmetic + functions. + 20. terminal.h is a header file that includes the appropriate + terminal include. + 21. test.h contains the definitions for the test and [[...]] + commands. + 22. timeout.h contains the define constant for the maximum + shell timeout. + 23. ulimit.h includes the appropriate resource header. + 24. variables.h contains symbolic constants for the built-in + shell variables. + +sh directory: + 1. args.c contains functions for parsing shell options + and for processing positional parameters. + 2. arith.c contains callback functions for the streval.c + library and the interface to shell arithmetic. + 3. array.c contains the code for indexed and associative + arrays. + 4. bash.h contains code used when compiling with SHOPT_BASH + to add bash specific features such as shopt. + 5. defs.c contains the data definitions for global symbols. + 6. deparse.c contains code to generate shell script from + a parse tree. + 7. env.c contains code to add and delete environment variables + to an environment list. + 8. expand.c contains code for file name expansion and + file name generation. + 9. fault.c contains code for signal processing, trap + handling and termination. + 10. fcin.c contains code for reading and writing a character + at a time from a file or string. + 11. init.c contains initialization code and callbacks + for get and set functions for built-in variables. + 12. io.o contains code for redirections and managing file + descriptors and file streams. + 13. jobs.c contains the code for job management. + 14. lex.c contains the code for the lexical analyzer. + 15. macro.c contains code for the $ macro expansions, including + here-documents. + 16. main.c contains the calls to initialization, profile + processing and the main evaluation loop as well as + mail processing. + 17. name.c contains the name-value pair routines that are + built on the hash library in libast. + 18. nvdisc.c contains code related to name-value pair disciplines. + 19. nvtree.c contains code for compound variables and for + walking the namespace. + 20. parse.c contains the code for the shell parser. + 21. path.c contains the code for pathname lookup and + some path functions. It also contains the code + that executes commands and scripts. + 22. pmain.c is just a calls sh_main() so that all of the + rest of the shell can be in a shared library. + 23. shcomp.c contains the main program to the shell + compiler. This program parses a script and creates + a file that the shell can read containing the parse tree. + 24. streval.c is an C arithmetic evaluator. + 25. string.c contains some string related functions. + 26. subshell.c contains the code to save and restore + environments so that subshells can run without creating + a new process. + 27. suid_exec.c contains the program from running execute + only and/or setuid/setgid scripts. + 28. tdump.c contains the code to dump a parse tree into + a file. + 29. timers.c contains code for multiple event timeouts. + 30. trestore contians the code for restoring the parse + tree from the file created by tdump. + 31. userinit.c contains a dummy userinit() function. + This is now obsolete with the new version of sh_main(). + 32. waitevent.c contains the sh_waitnotify function so + that builtins can handle processing events when the + shell is waiting for input or for process completion. + 33. xec.c is the main shell executuion loop. diff --git a/usr/src/lib/libshell/common/OBSOLETE b/usr/src/lib/libshell/common/OBSOLETE new file mode 100644 index 0000000000..c29cb8bb63 --- /dev/null +++ b/usr/src/lib/libshell/common/OBSOLETE @@ -0,0 +1,152 @@ +.sp 3 +.tl ''Ksh Features That Are Obsolete in Ksh93'' +.sp 2 +.AL 1 +.LI +Using a pair of grave accents \^\fB\(ga\fR ... \fB\(ga\fR\^ +for command substition. Use \fB$(\fR ... \fB)\fR instead. +.LI +.B FCEDIT +is an obsolete name for +the default editor name for the +.B hist +command. +.B FCEDIT +is not used when +.B HISTEDIT +is set. Use +.B HISTEDIT +instead. +.LI +The newtest (\fB[[\fR ... \fB]]\fR) operator +\fB\-a\fP \fIfile\fP +is obsolete. Use +\fB\-e\fP instead. +.LI +The newtest (\fB[[\fR ... \fB]]\fR) operator +.BR = , +as used in +\fIstring\fP \fB=\fP \fIpattern\fP +is obsolete. Use +\fB==\fP instead. +.LI +The following obsolete arithmetic comparisons are also permitted: +.in +5 +.VL 20 +.LI "\fIexp1\fP \fB\-eq\fP \fIexp2\fP" +True, if +.I exp1 +is equal to +.IR exp2 . +.LI "\fIexp1\fP \fB\-ne\fP \fIexp2\fP" +True, if +.I exp1 +is not equal to +.IR exp2 . +.LI "\fIexp1\fP \fB\-lt\fP \fIexp2\fP" +True, if +.I exp1 +is less than +.IR exp2 . +.LI "\fIexp1\fP \fB\-gt\fP \fIexp2\fP" +True, if +.I exp1 +is greater than +.IR exp2 . +.LI "\fIexp1\fP \fB\-le\fP \fIexp2\fP" +True, if +.I exp1 +is less than or equal to +.IR exp2 . +.LI "\fIexp1\fP \fB\-ge\fP \fIexp2\fP" +True, if +.I exp1 +is greater than or equal to +.IR exp2 . +.LE \" End .VL +.in -5 +.LI +Using test -t or [ -t ] without specifying the file unit number. +.LI +The +.B \-k +option to the \fBset\fR builtin is obsolete. It causes +.I all\^ +variable assignment arguments are placed in the environment, +even if they occur after the command name. +The following +first prints +.B "a=b c" +and then +.BR c : +There is no alternative. +.LI +The obsolete +.B \-xf +option of the +.B typeset +command allows a function to be exported +to scripts that are executed without a separate +invocation of the shell. +Functions that need to be defined across separate +invocations of the shell should +be placed in a directory and the +.B FPATH +variable should contains the name of this directory. +They may also +be specified in the +.B ENV +file with the +.B \-xf +option of +.BR typeset . +.LI +The shell environment variable +.B FCEDIT +is obsolete. Use +.B HISTEDIT +instead. +.LI +In the +.B \-s +option +(to \fBfc\fR or \fBhist\fR command???) +( +and in obsolete versions, the editor name +.B \- +) +is used to skip the editing phase and +to re-execute the command. +.LI +The +.B \-t +option to \fBalias\fR builtin is is obsolete. It +is used to set and list tracked aliases. +There is no replacement. +.LI +The shell command line option +.B \-t +is obsolete. This option cause the shell to exit after reading +and executing one command. The is no replacement (although ending +\&"command" with the exit builtin should have the same effect). +.LI +As an obsolete feature of the "set" builtin, +if the first +.I arg\^ +is +.B \- +then the +.B \-x +and +.B \-v +options are turned off and the next +.I arg +is treated as the first argument. +Using +.B \+ +rather than +.B \- +causes these options to be turned off. +These options can also be used upon invocation of the shell. +.LE + diff --git a/usr/src/lib/libshell/common/PROMO.mm b/usr/src/lib/libshell/common/PROMO.mm new file mode 100644 index 0000000000..332ff3a855 --- /dev/null +++ b/usr/src/lib/libshell/common/PROMO.mm @@ -0,0 +1,141 @@ +.H 1 ksh93 +KSH-93 is the most recent version of the KornShell Language +described in +"The KornShell Command and Programming Language," +by Morris Bolsky and David Korn of AT&T Bell Laboratories, ISBN 0-13-182700-6. +The KornShell is a shell programming language, +which is upward compatible with "sh" (the Bourne Shell), +and is intended to conform to the IEEE P1003.2/ISO 9945.2 Shell and +Utilities standard. +KSH-93 provides an enhanced programming environment in +addition to the major command-entry features of the BSD +shell "csh". With KSH-93, medium-sized programming tasks can be +performed at shell-level without a significant loss in performance. +In addition, "sh" scripts can be run on KSH-93 without modification. +.P +The code should conform to the IEEE POSIX 1003.1 standard and to the +proposed ANSI-C standard so that it should be portable to all +such systems. Like the previous version, KSH-88, +it is designed to accept eight bit character sets +transparently, thereby making it internationally compatible. +It can support multi-byte characters sets with some characteristics +of the character set given at run time. +.P +KSH-93 provides the following features, many of which were also inherent +in KSH-88: +.BL +.LI +Enhanced Command Re-entry Capability: The KSH-93 history +function records commands entered at any shell level and stores +them, up to a user-specified limit, even after you log off. +This allows you to re-enter long commands with a few keystrokes +- even those commands you entered yesterday. +The history file allows for eight bit characters in +commands and supports essentially unlimited size histories. +.LI +In-line Editing: In "sh", the only way to fix mistyped +commands is to backspace or retype the line. KSH-93 allows you +to edit a command line using a choice of EMACS-TC or "vi" +functions. +You can use the in-line editors to complete filenames as +you type them. +You may also use this editing feature when entering +command lines from your history file. +A user can capture keystrokes and rebind keys to customize the +editing interface. +.LI +Extended I/O Capabilities: KSH-93 provides several I/O +capabilities not available in "sh", including the ability to: +.BL +.LI +specify a file descriptor for input and output +.LI +start up and run co-processes +.LI +produce a prompt at the terminal before a read +.LI +easily format and interpret responses to a menu +.LI +echo lines exactly as output without escape processing +.LI +format output using printf formats. +.LI +read and echo lines ending in "\e". +.LE +.LI +Improved performance: KSH-93 executes many scripts faster +than the System V Bourne shell. A major reason for this is +that many of the standard utilities are built-in. +To reduce the time to initiate a command, KSH-93 allows +commands to be added as built-ins at run time +on systems that support dynamic loading such as System V Release 4. +.LI +Arithmetic: KSH-93 allows you to do integer arithmetic in any +base from two to sixty-four. You can also do double +precision floating point arithmetic. +Almost the complete set of C language operators are available +with the same syntax and precedence. +Arithmetic expressions can be used to as an argument expansion +or as a separate command. +In addition there is an arithmetic for command that works +like the for statement in C. +.LI +Arrays: KSH-93 supports both indexed and associative arrays. +The subscript for an indexed array is an arithmetic expression, +whereas, the subscript for an associative array is a string. +.LI +Shell Functions and Aliases: Two mechanisms - functions and +aliases - can be used to assign a user-selected identifier to +an existing command or shell script. +Functions allow local variables and provide scoping +for exception handling. +Functions can be searched for and loaded on first reference the +way scripts are. +.LI +Substring Capabilities: KSH-93 allows you to create a +substring of any given string either by specifying the starting +offset and length, or by stripping off leading +or trailing substrings during parameter substitution. +You can also specify attributes, such as upper and lower case, +field width, and justification to shell variables. +.LI +More pattern matching capabilities: KSH-93 allows you to specify +extended regular expressions for file and string matches. +.LI +KSH-93 uses a hierarchal name space for variables. +Compound variables can be defined and variables can +be passed by reference. In addition, each variable +can have one or more disciplines associated with +it to intercept assignments and references. +.LI +Improved debugging: KSH-93 can generate line numbers on execution +traces. Also, I/O redirections are now traced. +There is a DEBUG trap that gets evaluated after each command +so that errors can be localized. +.LI +Job Control: On systems that support job control, including +System V Release 4, KSH-93 +provides a job-control mechanism almost identical to that of +the BSD "csh", version 4.1. +This feature allows you +to stop and restart programs, and to move programs between the +foreground and the background. +.LI +Added security: +KSH-93 can execute scripts which do not have read permission +and scripts which have the setuid and/or setgid set when +invoked by name, rather than as an argument to the shell. +It is possible to log or control the execution of setuid and/or +setgid scripts. +The noclobber option prevents you from accidentally erasing +a file by redirecting to an existing file. +.LI +KSH-93 can be extended by adding built-in commands at run time. +In addition, KSH-93 can be used as a library that can +be embedded into an application to allow scripting. +.LE +Documentation for KSH-93 consists of an "Introduction to KSH-93", +"Compatibility with the Bourne Shell" and a manual page and a +README file. In addition, the "New KornShell Command and Programming +Language," book is available from Prentice Hall. + diff --git a/usr/src/lib/libshell/common/README b/usr/src/lib/libshell/common/README new file mode 100644 index 0000000000..3c3899fda2 --- /dev/null +++ b/usr/src/lib/libshell/common/README @@ -0,0 +1,227 @@ +This directory, and its subdirectories contain the source code +for ksh-93; the language described in the second addition of +the book, "The KornShell Command and Programming Language," by +Morris Bolsky and David Korn which is published by Prentice Hall. +ksh-93 has been compiled and run on several machines with several +operating systems. The end of this file contains a partial list of +operating systems and machines that ksh-93 has been known to run on. + +The layout of files for ksh-93 has changed somewhat since ksh-88, +the last major release. Most of the source code for ksh remains in +the sh directory. However, the shell editing and history routines +are in the edit sub-directory. The code for shell built-ins is +in the bltins directory. The data directory contains read-only +data tables and messages that are used by the shell. The include +files remain in the include directory and the shlib directory +is gone. The features directory replaces the older install +directory. The method for generating systems specific feature +information has changed substantially. + +The Makefile file contains several compilation options that can be set +before compiling ksh. Options are of the form SHOPT_option and become +#define inside the code. These options are set to their recommended +value and some of these may disappear as options in future releases. +A value of 0, or no value represents off, 1 represents on. +Note that == is needed, not =, because these are nmake state variables +and changing their value will cause all modules that could be affected +by this change to be recompiled. +The options have the following defaults and meanings: + ACCT off Shell accounting. + ACCTFILE off Enable per user accounting info + APPEND on Allows var+=val string and array append. + BASH off Bash compatibility mode. It is not fully implemented + and is experimental. + BRACEPAT on C-shell type abc{d,e}f style file generation + CMDLIB_BLTIN off Makes all commands in libcmd.a builtins. The + SH_CMDLIB_DIR nmake state variable can be used to + specify a directory. + CMDLIB_DIR off Sets CMDLIB_BLTIN=1 and provides a default value + of "/opt/ast/bin" for SH_CMDLIB_DIR. + COMPOUND_ARRAY + on Allows all components of compound variables except the + first to be any string by enclosing in [...]. It also + allows components other than the last to be arrays. + This is experimental and only partially complete. + CRNL off treated as in shell grammar. + DYNAMIC on Dynamic loading of builtins. (Requires dlopen() interface.) + ECHOPRINT off Make echo equivalent to print. + ESH on Compile with emacs command line editing. The original + emacs line editor code was provided by Mike Veach at IH. + FILESCAN on Experimental option that allows fast reading of files + using while < file;do ...; done and allowing fields in + each line to be accessed as positional parameters. + FS_3D off For use with 3-D file system. Enabled automatically for + sytems with dynamic linking. + KIA off Allow generation of shell cross reference database with -I. + MULTIBYTE on Multibyte character handling. Requires mblen() and + mbctowc(). + NAMESPACE on Allows namespaces. This is experimental, incomplete + and undocumented. + OLDTERMIO off Use either termios or termio at runtime. + OO on Experimental object oriented extension. This option + should disappear soon. + OPTIMIZE on Optimize loop invariants for with for and while loops. + P_SUID off If set, all real uids, greater than or equal to this + value will require the -p flag to run suid/sgid scripts. + PFSH off Compile with support for profile shell. + RAWONLY off Turn on if the vi line mode doesn't work right unless + you do a set -o viraw. + SEVENBIT off Strip the eigth bit from characters. + SPAWN off Use spawn as combined fork/exec. May improve speed on + some systems. + SUID_EXEC on Execute /etc/suid_exec for setuid, setgid script. + TIMEOUT off Set this to the number of seconds for timing out and + exiting the shell when you don't enter a command. If + non-zero, TMOUT can not be set larger than this value. + VSH on Compile with vi command line editing. The original vi + line editor code was provided by Pat Sullivan at CB. + +The following compile options are set automatically by the feature testing: + DEVFD Set when /dev/fd is a directory that names open files. + SHELLMAGIC + Set on systems that recognize script beginning with #! specially. + VPIX Set on systems the have /usr/bin/vpix program for running MS-DOS. + + +In most instances, you will generate ksh from a higher level directory +which also generates libcmd and libast libraries on which ksh depends. +However, it is possible to generate ksh, with by running make -f ksh.mk +in this directory. The ksh.mk file was generated from the nmake Makefile. +If you do not have make or nmake, but do have a Version 7 UNIX compatible +shell, then you can run the script mamexec < Mamfile to build ksh. +If you have nmake, version 2.3 or later, you can use it without the -f ksh.mk. +In either case, ksh relies on libraries libast and libcmd which must be +built first. The binary for ksh becomes the file named ./ksh which can +be copied to where ever you install it. + +If you use old make or the Mamfile, and you system has dynamic shared +libraries, then you should define the variables mam_cc_static and +mam_cc_dynanamic as the compiler options that request static linking +and dynamic linking respectively. This will decrease the number of +shared libraries that ksh need and cut startup time substantially. + +The makefile should also generate shcomp, a program that will precompile +a script. ksh93 is able to recognize files in this format and process +them as scripts. You can use shcomp to send out scripts when you +don't want to give away the original script source. + +It is advisable that you put the line PWD=$HOME;export PWD into the +/etc/profile file to reduce initialization time for ksh. + +To be able to run setuid/setgid shell scripts, or scripts without read +permission, the SUID_EXEC compile option must be on, and ksh must be installed +in the /bin directory, the /usr/bin directory, the /usr/lbin directory, +or the /usr/local/bin directory and the name must end in sh. The program +suid_exec must be installed in the /etc directory, must be owned by root, +and must be a suid program. If you must install ksh in some other directory +and want to be able to run setuid/setgid and execute only scripts, then +you will have to change the source code file sh/suid_exec.c explicitly. +If you do not have ksh in one of these secure locations, /bin/sh will +be invoked with the -p options and will fail when you execute a setuid/setgid +and/or execute only script. Note, that ksh does not read the .profile +or $ENV file when it the real and effective user/group id's are not +equal. + +The tests sub-directory contains a number of regression tests for ksh. +To run all these tests with the shell you just built, go to the tests +directory and run the command + SHELL=../ksh shtests + +The file PROMO.mm is an advertisement that extolls the virtues of ksh. +The file sh.1 contains the troff (man) description of this Shell. +The file nval.3 contains the troff (man) description of the name-value +pair library that is needed for writing built-ins that need to +access shell variables. + +The file sh.memo contains a draft troff (mm) memo describing ksh. The +file RELEASE88 contains the changes made for ksh88. The file RELEASE93 +contains the changes made in this release since ksh-88. The file +RELEASE contains bug fixes made in this release since ksh-88. The file +COMPATIBILITY contains a list of incompatibilities with ksh-88. The +file bltins.mm is a draft troff (mm) memo describing how to write +built-in commands that can be loaded at run time. + +Most of the work for internationalization has been done with ksh93. +The file ksh.msg is a generated file that contains error messages +that need to be translated. In addition, the function translate() +in sh/init.c has to be completed to interface with the dictionary +lookup. The translate function takes two argument, the string +that is to be translated and a type which is + 0 when a library string needs translation. + 1 when one of the error messages in ksh.msg needs translation. + 2 when a string in a script needs translation. You use a $ in front + of a double quoted string in a script to indicate that it + needs translation. The -D option for ksh builds the dictionary. +The translate routine needs to return the translated message. +For dictionaries that need to use a numeric key, it should be +possible to use the strhash() function to generate numbers to +go along with each of the messages and to use this number both +when generating the dictionary and when converting strings. +If you encounter error messages of type 1 that are not be translated via +this translate() function send mail to the address below. + +Please report any problems or suggestions to: + +dgk@research.att.com + + +ksh93 has been compiled and alpha tested on the following. An asterisk +signifies that ksh has been installed as /bin/sh on this machine. + +* Sun OS 4.1.[123] on sparc. + Sun OS 4.1.1 on sun. + Solaris 2.[1-9] on sparc. + Solaris 2.[4-8] on X86. + HP/UX 8 on HP-9000/730. + HP/UX 9 on HP-9000/730. + HP/UX 10 on HP-9000/857. + HP/UX 11 on pa-risc. + System V Release 3 on Counterpoint C19 + System V Release 4 on AT&T Intel 486. + System V Release 4 on NCR 4850 Intel 486. + IRIX Release 4.0.? System V on SGI-MIPS. + IRIX Release 5.1 System V on SGI-MIPS. + IRIX Release 6.[1-5] System V on SGI-MIPS. + System V Release 3.2 on 3B2. + UTS 5.2.6 on Amdahl 3090,5990,580. + System V Release 3.2 on i386. + SMP_DC.OSx olivetti dcosx MIServer-S 2/128. + SMP_DC.OSx Pyramid dcosx MIServer-S 2/160 r3000. + 4.3BSD on Vax 8650. + AIX release 2 on RS6000. + AIX 3.2 on RS6000. + Linux 1.X on Intel + Linux 2.X on Intel + Linux 2.X on Alpha + Linux 2.X on Alpha + Linux 2.X on OS/390 + Linux 2.X on sparc + Linux 2.4 on intel itanium 64 + Linux Slackware on sparc64 +* Linux ARM on i-PAQ + OSF1 on DEC alpha. + OSF4 on DEC alpha. + UMIPS 4.52 on mips. + BSD-i [2-4] on X86. + OpenBSD on X86 + NetBSD on X86 + FreeBSD on X86 + NeXT on Intel X86. + NeXT on HP. +* Windows NT using UWIN on X86 +* Windows NT using UWIN on alpha + Windows NT using Cygwin on X86 + Windows NT with NutCracker libraries. + Windows NT with Portage libraries. + Windows 3.1 using custom C library. + OpenEdition on MVS + Darwin OS X on PPC + MVS on OS 390 + SCO Openserver 3.2 on X86 + Unixware 7 on X86 + +Good luck!! + +David Korn +dgk@research.att.com + diff --git a/usr/src/lib/libshell/common/RELEASE b/usr/src/lib/libshell/common/RELEASE new file mode 100644 index 0000000000..034ca7033d --- /dev/null +++ b/usr/src/lib/libshell/common/RELEASE @@ -0,0 +1,1455 @@ +07-04-18 --- Release ksh93s+ --- +07-04-18 A small memory leak with each redirection of a non-builtin has + been fixed. +07-03-08 A bug in which set +o output command line options has been fixed. +07-03-08 A bug in which an error in read (for example, an invalid variable + name), could leave the terminal in raw mode has been fixed. +07-03-06 A bug in which read could core dump when specified with an array + variable with a subscript that is an arithmetic expression has + been fixed. +07-03-06 Several serious bugs with the restricted shell were reported and + fixed. +07-03-02 If a job is stopped, and subsequently restarted with a CONT + signal and exits normally, ksh93 was incorrectly exiting with + the exit status of the stop signal number. +07-02-26 M-^L added to emacs mode to clear the screen. +07-02-26 A bug in which setting a variable readonly in a subshell would + cause an unset error when the subshell completed has been fixed. +07-02-19 The format with printf uses the new = flag to center the output. +07-02-19 A bug in which ksh93 did not allow multibyte characters in + identifier names has been fixed. +07-02-19 A bug introduced in ksh93 that causes global compound variable + definitions inside functions to exit with "no parent" has been fixed. +07-02-19 A bug in which using compound commands in process redirection + arguments would give syntax errors <(...) and >(...) has been fixed. +07-01-29 A bug which caused the shell to core dump which can occur when a + built-in exits without closing files that it opens has been fixed. +07-01-26 A bug in which ~(E) in patterns containing \ that are not inside () + has been fixed. + +06-12-29 --- Release ksh93s --- +06-12-29 A bug in which the value of IFS could be changed after a command + substitution has been fixed. +06-12-22 /dev/(tcp|udp|sctp)/HOST/SEVRICE now handles IPv6 addresses on + systems that provide getaddrinfo(3). +06-12-19 A -v option was added to read. With this option the value of + the first variable name argument will become the default value + when read from a terminal device. +06-11-20 A bug in which "${foo[@]:1}}" expands a null argument (instead of + no argument), when foo[0] is not empty has been fixed. +06-11-16 The discipline functions have been modified to allow each subscript + to act independently. Currently the discipline function will not + be called when called from a discipline function of the same variable. +06-11-14 A bug which could cause a core dump if a file descriptor for + an internal file was closed from with a subshell has been fixed. +06-10-30 The redirections <# pattern, and <## pattern have been added. + Both seek forward to the beginning of the next line that contains + the pattern. The <## form copies the skipped portion to standard + output. +06-10-26 On systems that support stream control transport, the virtual file + name /dev/sctp/host/port can now be used to establish connections. +06-10-26 The printf modifier # when used with d produces units in thousands + with a single letter suffix added. The modifier # when used with + the i specification provides units of 1024 with a two letter suffix. +06-10-24 The value of $! is now set to the process id of a job put + into the background with the bg command as required by POSIX. +06-10-23 A bug in which the value of $! was affected by a background + job started from a subshell has been fixed. +06-10-23 A bug in ${var:offset:len} in multibyte locales has been fixed. +06-10-15 The remaining math functions from C99 were added for any system + that supports them. +06-10-13 The klockwork.com software detected a few coding errors that + have been fixed. +06-10-12 A bug when skipping over `...` with ${x:=`...`} when x is set + has been fixed. +06-10-11 A bug in process floating constants produced by the %a format + of printf has been fixed. +06-10-06 A bug in which IFS was not being restored correctly in some + cases after a subshell has been fixed. +06-10-06 A bug in which pipefail was not detecting some failures in + pipelines with 3 or more states has been fixed. +06-10-03 A bug in the processing of >(...) with builtins which could + cause the builtin to hang has been fixed. +06-10-03 A bug in the for loop optimizer which causes >(...) process + substitution to be ignored has been fixed. +06-09-17 The -a option was added to typeset for indexed arrays. This + is only needed when using the ([subscript]=value ...) form. +06-09-06 The showme option was added. Each simple command not beginning + with a redirection and not occurring with in the while, until, if, + select condition can be preceded by a semi-colon which will + be ignored when showme is off. When showme is on, any command + preceded by a colon will be traced but not executed. +06-08-16 As a new feature, a leading ~(N) on a pattern has no effect + except when used for file expansion. In this case if not + matches are found, the pattern is replaced by nothing rather + than itself. +06-08-11 A bug in the expansion of ${.sh.match[i]:${#.shmatch[i]}} has + been fixed. +06-08-10 The read builtin options -n and -N have been modified to treat + the size as characters rather than bytes unless storing into a + binary (typeset -B) variable. +06-07-27 When the here document operator << is followed directly by a # + rather than a -, the first line of the here-document determines + how much whitespace is removed for each line. +06-07-26 A bug in the C-shell history (enabled with set -H) in which the + history event !$ was not processed has been fixed. +06-07-21 A bug on some systems in which assigning PATH on a command line + would not take effect has been fixed. +06-07-20 Add ksh93 and rksh93 as allowable names for ksh binaries. +06-07-20 Removed the SHOPT_OO compilation option which was only partially + implemented. +06-07-20 The ability to use egrep, grep, and fgrep expressions within + shell patterns has been documented. +06-07-17 A bug with arithmetic command expressions for locales in which + the comma is a thousands separator has been fixed. +06-07-13 The default HISTSIZE was increased from 128 to 512. +06-07-13 A multibyte problem with locales that use shift codes has been fixed. +06-06-23 A number of bug fixes for command, file, and variable completion + have been mode. +06-06-20 Floating point division by zero now yields the constant Inf or -Inf + and floating functions with invalid arguments yield NaN. +06-06-20 The floating point constants Inf and NaN can be used in arithmetic + expressions. +06-06-20 The functions isinf(), isnan(), tanhl() have been added for + arithmetic expressions. +06-06-13 Internal change to use ordering for variables instead of hashing + to speed up prefix matching. +06-06-13 A window between fork/exec in which a signal could get lost + and cause a program to hang has been eliminated +06-06-13 A bug in edit completion with quoted strings has been fixed. +06-06-07 The restricted options can now be enabled by set as well as on + the command line. Once set, it can not be disabled. +06-06-04 Modified built-in binding so that for systems for which /bin + and /usr/bin are the same, a builtin bound to /bin will get + selected when either /bin or /usr/bin is scanned. +06-06-04 Added literal-next character processing for emacs/gmacs mode. + This change is not compatible with earlier versions of ksh93 + and ksh88 when the stty lnext is control-v. The sequence + escape-control-v will display the shell version. +06-05-31 Modified emacs and vi mode so that entering a TAB after a partial + TAB completion, generates a listing of possible completions. + After the second TAB, a number followed by a TAB will perform + the completion with the corresponding item. +06-05-19 Modified arithmetic so that conversions to strings default to + the maximum number of precision digits. +06-05-16 Bug fixes for multibyte locales. +06-05-10 The =~ operator was added to [[...]] and [[ string ~= ERE ]] + is equivalent to [[ string == ~(E)ERE ]]. +06-04-25 A bug in the vi edit mode which could cause the shell to core dump + when switching from emacs mode. +06-04-17 A bug in which using LANG or LC_ in assignment lists with builtins + did not restore the localed correctly has been fixed. +06-04-04 A bug in which discipline functions could not be added to variables + whose names started with .sh has been fixed. +06-03-28 The -s option to typeset was added to modify -i to indicate short + integers. +06-03-28 A bug in which variables assignment lists before functions + defined with function name were not passed on the functions + invoked by this function has been fixed. +06-03-28 A bug in which name references defined within a function defined + with function name could not be used with compound variables has + been fixed. +06-03-27 A bug in which read <&p (print >&p) would cause the coprocess input + (output) pipe to close before reading from (after writing to) + it has been fixed. +06-02-28 A bug in which stopping a job created with the hist builtin command + would create a job that could not be restarted has been fixed. + +06-01-24 --- Release ksh93r --- +06-01-24 A bug in which running commands with standard output closed would + not work as expected has been fixed. +06-01-23 A bug in which print -u could fail when file descriptor was + open for writing has been fixed. +06-01-19 The ?: arithmetic operator fixed to work when the operation after + the colon was an assignment. +05-12-24 A bug which could lead to a core dump when elements of a compound + variable were array elements, i.e. foo=(bar=(1 2)), has been fixed. +05-12-13 An arithmetic bug in which x+=y+=z was not working has been fixed. +05-12-13 An arithmetic bug in which x||y was returning x when x was non-zero + rather than 1 has been fixed. +05-12-07 The aliases for integer and float have been changed to use attributes + -li and -lE to handle long long and long double types. +05-12-07 The histexpand (-H) option has been added which allows C-shell + style history expansions using the history character !. +05-12-07 The multiline option was added which changes that way the edit + modes handle lines longer than the window width. Instead of + horizontal scrolling, multiple lines on the screen are used. +05-12-05 The whence builtin now returns an absolute pathname when the + command is found in the current directory. +05-11-29 A bug which caused ksh -c '[[ ! ((' to core dump rather than + report a syntax error has been fixed. +05-11-29 A bug when reading fixed length records into typeset -b variables + which caused a zero byte to terminate the value has been fixed. +05-11-22 The ability to seek to an offset within a file has been added + with the new I/O redirection operators, <# and >#. Currently, + these redirection operators must be followed by ((expr)) + but in a future release, it should be able to used to seek forward + to the specified shell pattern. In addition $(n<#) expands to the + current byte offset for file descriptor n. +05-11-22 The .sh.match array variable is now set after each [[ ... ]] + pattern match. Previously it was only set for substring matches. +05-10-17 A bug in which the library path variable could be prefixed + with a directory when a .path file was not encountered in + the directory of the executable has been fixed. +05-09-15 A for/while loop optimizer bug in which $OPTIND was not + correctly expanded has been fixed. +05-09-05 A bug in which a history command that invoked a history + command could go into an infinite loop has been fixed. +05-08-31 In the case that IFS contains to adjacent new-lines so that + new-line is not treated as a space delimiter, only a single + new-line is deleted at the end of a command substitution. +05-08-19 When a tilde substitution expands to the / directory and is + followed by a /, it is replaced by the empty string. +05-08-16 A bug in which n<&m did not synchronize m has been fixed. +05-08-16 A bug in which process substitution ( <() and >() ) was not + working within for and while loops has been fixed. +05-07-24 A bug in which the pattern ~(E)(foo|bar) was treated as a syntax + error has been fixed. +05-07-24 A bug in completion with =, where n was the one of the + previous selection choices has been fixed. +05-07-21 A bug with multibyte input when no edit mode was specified which + caused the input line to shift left/right has been fixed. +05-06-24 A race condition which could cause the exit status to get lost + on some fast systems has been fixed. +05-06-21 A bug in which nested patterns of the form {m,n}(pat) would cause + syntax errors has been fixed. +05-06-21 A bug in the macro expander has been fixed which could cause a + syntax error for an expansion of the form ${x-$(...)} when + x is set and the command substitution contained certain strings. +05-06-08 On systems for which echo does not do System V style \ expansions, + the -e option was added to enable these expansion. +05-06-08 A bug in which ${var op pattern} to not work when inside an + arithmetic expression has been fixed. +05-05-23 An extension to shell patterns that allows matching of nested + groups while skipping over quoted strings has been added. +05-05-18 A bug in which the line number for errors was not correct for + functions loaded from FPATH has been fixed. +05-04-18 A bug in which the exit status $? is not set when a trap triggered + by the [[...]] command is executed has been fixed. +05-04-08 Redirection operators can be directly preceded with {varname} + with no intervening space, where varname is a variable name which + allows the shell to select a file descriptor > 10 and store it + into varname. +05-04-08 SHOPT_CMDLIB_BLTIN=1 now includes generated table. +05-04-07 [[ -o ?option ]] is true if "option" is a supported option. +05-04-05 A bug in handling file completion with spaces in the names + has been fixed. +05-03-25 The SIGWINCH signal is caught by default to keeps the LINES and + COLUMNS variables in sync with the actual window size. +05-03-25 Building ksh with SHOPT_REMOTE=1 causes ksh to set --rc if stdin is + a socket (presumably part of a remote shell invocation.) +05-03-25 Building ksh with SHOPT_SYSRC=1 causes interactive ksh to source + /etc/ksh.kshrc (if it exists) before sourcing the $ENV file. +05-03-25 {first..last[..incr][%fmt]} sequences added to brace expansions + when braceexpand is enabled. +05-03-03 A bug where a SIGCHLD interrupt could cause a fifo open to fail has + been fixed. +05-02-25 A bug in which a builtin command run in the background could + keep a file descriptor open which could cause a foreground + process to hang has been fixed. +05-02-24 A bug where builtin library commands (e.g., date and TZ) failed to + detect environment variable changes has been fixed. +05-02-22 The read builtin and word splitting are now consistent with respect + to IFS -- both treat IFS as field delimiters. +05-02-22 The read builtin no longer strips off trailing delimiters that + are not space characters when there are fewer variables than fields. +05-02-17 A builtin bug on systems where dlsym(libcmd) returns link-time + bindings has been fixed. +05-02-12 A bug in which the lib_init() function for .paths BUILTIN_LIB + libraries was not called has been fixed. +05-02-06 A bug on some systems in which moving the write end of a co-process + to a numbered file descriptor could cause it to close has been fixed. +05-02-06 A bug in the vi-edit mode in which the character under the cursor + was not deleted in some cases with the d% directive has been fixed. +05-02-06 A bug where external builtin stdout/stderr redirection corrupted + stdout has been fixed. +05-02-04 A bug where times formatting assumed CLK_TCK==60 has been fixed. + +05-01-11 --- Release ksh93q --- +05-01-11 A bug in the integral divide by zero check has been fixed. +05-01-11 The -l option has been added to read /etc/profile and + $HOME/.profile, if they exist, before the first command. +05-01-11 An argument parsing bug that caused `kill -s x -- n' to fail has + been fixed. +05-01-11 The .paths file, introduced in ksh93m, which can appear in + any directory in PATH, now allows a line of the form 'BUILTIN_LIB=.' + When a command is searched for this directory, and the full path + matches the path of the built-in version of the command (listed + by the 'builtin' command) then the built-in version of the command + is used. When ksh is built with SHOPT_CMDLIB_DIR=1 then all libcmd + functions become builtins with the '/opt/ast/bin/' directory prefix. +05-01-10 A bug in which a nameref to a compound name caused a core dump has + been fixed. +05-01-09 A bug in which some SIGCHLD interrupts (from child processes exiting) + caused a fatal print/echo error diagnostic has been fixed. +04-12-24 A bug in which some SIGCHLD interrupts (from child processes exiting) + corrupted the internal process/job list, sometimes causing the shell + to hang, has been fixed. +04-12-01 A bug in which typeset -Fn truncated less than n digits for large + numbers has been fixed. +04-11-25 A bug in which standard error could be closed after a redirection + to /dev/stderr has been fixed. +04-11-17 A bug in which an expansion of the form ${array[@]:3} could expand + to ${array[0]} when ${array[3]} was not set has been fixed. +04-10-22 The -E or -orc command line option reads ${ENV-$HOME/.kshrc} file. +04-10-22 `-o foo' equivalent to `+o nofoo', `-o nobar' equivalent to `+o bar'. + `--foo' equivalent to `-o foo', `--nofoo' equivalent to `+o foo' +04-10-05 The .paths file, introduced in ksh93m, which can appear in + any directory in PATH, now allows a line of the form + 'BUILTIN_LIB=libname'. When a command is searched for this directory, + the shared library named by libname will first be searched for a + built-in version of the command. +04-09-03 <<< here documents now handle quotes in the word token correctly. +04-08-08 The maximum size for read -n and and read -N was increased from + 4095 to 32M. +04-08-04 printf %q was modified so that if an no operand was supplied, no + no output would be generated rather than a quoted empty string. +04-08-01 The -n and -N options of the read builtin has been modified + when reading variables with the binary attribute so that the + data is stored directly rather than through assignment. +04-08-01 The shcomp command has been modified to process alias commands + under some conditions. +04-07-31 The .sh.match variable added in ksh93l, now works like other + indexed arrays. +04-07-08 A loop optimizer bug which occurs when typeset is used in + a for or while loop inside a function has been fixed. +04-06-24 The number of subexpressions in a pattern was increased to 64 + from the current number of 20. +04-06-17 The -t option to read was modified to allow seconds to be + specified as any arithmetic expression rather than just + an integral number of seconds, for example even -t 'sin(.5)' + is now valid. +04-06-16 Two small memory leak problems were fixed. +04-06-15 A bug in ${var/pattern/"string"} which occurred when string + contained pattern matching characters has been fixed. +04-05-08 printf $'%d\n' produced an erroneous error message and has + been fixed. +04-05-24 A bug in which an associative array without any elements could + cause a core dump when a script with an associative array with + the same name was declared in a script invoked by name has + been fixed. +04-05-11 A bug in which an exec statement could close the script that + is being processed in a script that is run by name causing + a failure has been fixed. +04-04-28 If the first character of assignment to an integer variable was 0, + the variable had been treated as unsigned. This behavior was + undocumented and has been removed. +04-04-05 A bug in which the positioning of standard input could be incorrect + after reading from standard input from a subshell has been fixed. +04-03-30 A bug in the for loop optimizer which in rare cases could cause + memory corruption has been fixed. +04-03-29 The preset alias source='command .' has been added. +04-03-29 A bug introduced in ksh93p on some systems in which invoked by + name with #! on the first line would not get the signals handling + initialized correctly has been fixed. +04-03-29 A bug introduced in ksh93p in which a HUP signal received by + a shell that is a session group leader was not passed down to + its children has been fixed. + +04-02-28 --- Release ksh93p --- +04-02-28 The ability to apply an append discipline to any variable has + been added. +04-02-14 A bug in which the exportall option (set -a) would cause incorrect + results for arrays has been fixed. +04-02-02 A bug in which an exported array would pass more than + the first element to a script invoked by name has been fixed. +04-02-02 A bug on some systems in which name=value pairs preceding a script + invoked by name was not getting passed to the script has been fixed. +04-01-20 A bug in which an unset discipline function could cause a core + dump on some systems has been fixed. +04-01-12 A bug in which a continue or break called outside a loop from + inside a function defined with name() syntax could affect + the invoking function has been fixed. +04-01-08 If a command name begins with ~, only filename completion will be + attempted rather than pathname completion using the builtin editors. +04-01-08 A bug in the vi edit mode in which the wrong repeat count on + multiple word replacements with the . directive has been fixed. +04-01-06 Backspace characters are now handled correctly in prompt strings. +04-01-06 The getopts builtin has been modified to accept numerical + arguments of size long long on systems that support this. +04-01-06 A bug in which unsetting all elements of an associative array + would cause it to be treated as an indexed array has been fixed. +03-12-15 A bug in which a quoted string ending with an unescaped $ would + delete the ending $ in certain cases has been fixed. +03-12-05 A bug in which the shell could hang when set -x tracing a command + when an invalid multibyte character is encountered has been fixed. +03-12-05 On some systems, if the KEYBD trap is set, then commands that use + the meta key were not processed until return was hit. This + has been fixed. +03-12-05 A problem which occurred when the login shell was not a group + leader that could cause it to fail has been fixed. +03-12-05 A problem in which a shell could core dump after receiving a signal + that should cause it to terminate while it was in the process + of acquiring more space has been fixed. +03-12-05 If ENV is not specified, the shell will default to $HOME/.kshrc + for interactive shells. +03-11-21 A bug introduced in ksh93o in which the DEBUG trap could get + disabled after it triggered has been fixed. +03-11-04 A bug in which using arithmetic prefix operators ++ or -- on a + non-lvalue could cause a core dump has been fixed. +03-11-04 A bug in which leading zeros were stripped from variable + expansions within arithmetic computation to avoid being treated + as octal constants when they should not have, has been fixed. +03-10-08 A bug introduced in ksh93o in which a large here document inside + a function definition could get corrupted has been fixed. +03-09-22 A bug in which the .get discipline function was not being + called when a string variable was implicitly referenced from + within a numerical expression has been fixed. +03-09-22 A bug in which a script without a leading #! could get executed + by /bin/sh rather than the current shell on some systems has + been fixed. +03-09-12 To improve conformance with ksh88, leading zeros will be ignored + when getting the numerical value of a string variable so that + they will not be treated as octal constants. +03-09-03 The builtin kill command now processes obsolete invocations + such as kill -1 -pid. +03-09-02 The restriction on modifying FPATH in a restricted shell (sh -r) + has been documented. +03-09-02 The restricted shell (sh -r) has been modified to disallow + executing command -p. +03-08-07 A bug in which the KEYBD trap was not being invoked when + characters with the 8th bit set has been fixed. +03-08-02 A parser bug introduced in ksh93o which caused the character + after () in a Posix function definition to be skipped + when reading from standard input has been fixed. +03-08-01 A bug in which "${foo#pattern}(x)" treated (x) as if it were + part of the pattern has been fixed. +03-08-01 The command -x option has been modified so that any trailing + arguments that do expand to a single word will be included + on each invocation, so that commands like command -x mv * dir + work as expected. + +03-07-20 --- Release ksh93o+ --- +03-07-20 A bug in which could cause memory corruption when a posix + function invoked another one has been fixed. +03-07-15 A bug in which a file descriptor>2 could be closed before + executing a script has been fixed. +03-07-15 A parsing error for <() and >() process substitutions inside + command substitution has been fixed. +03-07-15 A parsing error for patterns of the form {...}(...) when + used inside ${...} has been fixed. +03-07-15 An error in which expanding an indexed array inside a compound + variable could cause a core dump has been fixed. +03-07-15 A bug in which under on rare occassions a job completion interrupt + could cause to core dump has been fixed. +03-06-26 A bug in which process substitution embedded within command + substitution would generate a syntax error has been fixed. +03-96-23 A bug in which ${@:offset:len} could core dump when there + were no arguments has been fixed. +03-96-23 A bug in which ${X[@]:offset:len} could core dump when X + was unset has been fixed. +03-06-22 The -x option was added to the command builtin. If this + option is on, and the number of arguments would exceed ARG_MAX, + the command will be invoked multiple times with a subset of + the arguments. For example, with alias grep='command -x grep, + any number of arguments can be specified. +03-06-14 A bug in which could cause a core dump on some systems with + vi and emacs editors with the MULTIBYTE option has been fixed. +03-06-06 A bug in which the shell could core dump when a script was + run from its directory, and the script name a symlink to a file + beginning with .., has been fixed. +03-06-05 A bug in which the shell could core dump when a child process + that it is unaware of terminates while it is calling malloc() + has been fixed. +03-06-02 An option named globstar (set -G) has been added. When enabled, + during pathname expansion, any component that consists only of ** is + matches all files and any number of directory levels. +03-05-30 A bug in which the PATH search could give incorrect results when + run from directory foo and PATH contained .:foo:xxx has been fixed. +03-05-29 Some changes were made to the code that displays the prompt in edit + mode to better handle escape sequences in the prompt. +03-05-27 I added = to the list of characters that mark the beginning of + a word for edit completion so that filenames in assignments + can be completed. +03-05-20 A bug in which read -N could hang on some systems when reading + from a terminal or a pipe has been fixed. +03-05-19 A bug in which the output of uname from a command substitution + would go to the standard output of the invoking command when + uname was invoked with a non-standard option has been fixed. +03-05-19 A job control bug which would cause the shell to exit because + it hadn't take back the terminal has been fixed. The bug + could occur when running a function that contained a pipeline + whose last element was a function. +03-05-19 A job control timing bug introduced in ksh93o on some systems + which could cause a pipeline to hang if the first component + completed quickly has been fixed. +03-05-13 The read builtin has been modified so that the builtin editors + will not overwrite output from a previous incomplete line. +03-05-13 A bug in which the name of an identifier could have the string + .sh. prefixed to it after expanding a variable whose name begins + with .sh. has been fixed. +03-05-13 A bug in the expansion of $var for compound variables in which + some elements would not be output when the name was a prefix + of another name in the compound variable has been fixed. +03-05-08 The last item in the ksh93o release on 03-01-02 has been + altered slightly to preserve the leading 0's when the + preceding character is a digit. Thus, with typeset -LZ3 x=10, + $(( 1$x)) will be 1010 whereas $(( $x) will be 10. +03-04-25 A bug in which if x is a name reference, then nameref y=x.foo + did not follow x has been fixed. + +03-03-18 --- Release ksh93o --- +03-03-18 A -N unary operator was added to test and [[...]] which returns + true if the file exists and the file has been modified since it + was last read. +03-03-18 The TIMEFORMAT variable was added to control the format for + the time compound command. The formatting description is + described in the man page. +03-03-06 A -N n option was added to read which causes exactly n bytes + to be read unlike -n n which causes at most n bytes to be read. +03-03-03 Three new shell variables were added. The variable .sh.file + stores the full pathname of the file that the current command + was found in. The variable .sh.fun names the current function + that is running. The variable .sh.subshell contains the depth + of the current subshell or command substitution. +03-03-03 When the DEBUG trap is executed, the current command line after + expansions is placed in the variable .sh.command. The trap + is also now triggered before each iteration of a for, select, + and case command and before each assignment and redirection. +03-02-28 Function definitions are no longer stored in the history file so + that set -o nolog no longer has any meaning. +03-02-28 All function definitions can be displayed with typeset -f not + just those stored in the history file. In addition, typeset +f + displays the function name followed by a comment containing the + line number and the path name for the file that defined this function. +03-02-28 A bug in which the value of $LINENO was not correct when executing + command contained inside mult-line command substitutions has been + fixed. +03-02-19 Since some existing ksh88 scripts use the undocumented and + unintended ability to insert a : in front of the % and # parameter + expansion operators, ksh93 was modified to accept :% as equivalent + to % and :# as equivalent to # with ${name op word}. +03-02-14 A bug which could cause a core dump when reading from standard + error when standard error was a pty has been fixed. +03-02-14 The shell arithmetic was modified to use long double on systems + that provide this data type. +03-02-09 A bug in which a function located in the first directory in FPATH + would not be found when the last component of PATH was . and the + current directory was one of the directories in PATH has been fixed. +03-02-07 The trap and kill builtin commands now accept a leading SIG prefix + on the signal names as documented. +03-02-05 A bug in the expansion of ${var/$pattern}, when pattern contained + \[ has been fixed. +03-02-05 A bug in which .sh.match[n], n>0, was not being set for substring + matches with % and %% has been fixed. +03-01-15 A bug in which getopts did not work for numerical arguments specified + as n#var in the getopts string has been fixed. +03-01-09 A bug in which using ${.sh.match} multiple times could lead to + a memory exception has been fixed. +03-01-06 A bug in the expansion of ${var/pattern/$string} in the case that + $string contains \digit has been fixed. +03-01-02 A -P option was added for systems such as Solaris 8 that support + profile shell. +03-01-02 For backward compatibility with ksh88, arithmetic expansion + with ((...)) and let has been modified so that if x is a zero-filled + variable, $x will not be treated as an octal constant. + +02-12-05 --- Release ksh93n+ --- +02-11-30 A bug that can show up in evaluating arithmetic statements that + are in an autoloaded function when the function is autoload from + another function has been fixed. +02-11-30 An optimization bug in which an expansion of the form ${!name.@}, + which occurred inside a for or a while loop, when name is a name + reference, has been fixed. +02-11-18 A bug in which modifying array variables in a subshell could leave + side effects in the parent shell environment has been fixed. +02-11-18 A memory leak when unsetting an associative array has been fixed. +02-11-14 The code to display compound objects was rewritten to make + it easier for runtime extensions to reuse this code. +02-11-14 A change was made to allow runtime builtins to be notified when + a signal is received so that cleanup can be performed. +02-10-31 User applications can now trap the ALRM signal. Previously, + the ALRM signal was used internally and could not be used + by applications. +02-10-31 A bug in which signals received while reading from a coprocess + for which traps were set was not handled correctly has been fixed. +02-10-31 A bug in which a file opened with exec inside a subshell could + be closed before the subshell completed has been fixed. +02-10-21 A bug in which setting PATH or FPATH inside a function might not + take effect has been fixed. +02-10-21 A bug which could cause a core dump when a local SECONDS variable + is defined in a function has been fixed. +02-10-15 A bug in which the associate array name operator ${!array[@]} + could return the same name multiple times has been fixed. +02-10-15 A bug in which the zero'th element of an associative array was + not getting set when an assignment was made without a subscript + specified has been fixed. + +02-09-30 --- Release ksh93n --- +02-09-30 The maximum indexed array size was increased to 16Megs. +02-09-30 A bug which could cause a core dump when changing attributes + of associative array has been fixed. +02-09-30 A bug in which exporting an array variable would not export the + 0-th element has been fixed. +02-09-30 A bug in which an array assignment of the form a=($a ...) would unset + 'a' before the right hand side was evaluated has been fixed. +02-09-27 A bug in which the error message for ${var?message} when var was + null or unset did not contain the variable name var has been fixed. +02-09-27 A bug in which closing file descriptors 0 through 2 could + cause a subsequent here document to fail has been fixed. +02-09-14 A bug in whence which occurs when the specified name contained + a / has been fixed. +02-09-14 A bug in the parser for strings of the form name$((expr))=value + has been fixed. +02-09-14 A for loop optimization bug in which the number of elements in + an array was treated as an invariant has been fixed. +02-09-09 A bug in which redirection or closing of a file descriptor between + 3 and 9 could cause a subsequent here document to fail has been + fixed. +02-09-09 A bug in which a background job was not removed from the job list + when a subshell completed has been fixed, for example (prog&). +02-09-03 A bug in which an assignment of the form name=(integer x=3) + could be interpretted as an array assignment rather than a + compound variable assignment has been fixed. +02-08-19 A command completion bug which occurred on file systems that + are case insensitive has been fixed. +02-08-19 A bug which could lead to an exception on some systems (for + example FREEBSD) which occurred when setting PATH has been fixed. +02-08-11 A bug in arithmetic rounding in which a value input as a decimal + string would output as a rounded version of the string has + been fixed. +02-08-11 A bug in which the last character could be deleted from shell + traces and from whence when called from a multibyte locale + has been fixed. +02-08-01 A bug which could cause a core dump to occur when a shell script + is executed while a coprocess is running that has closed the + output pipe has been fixed. +02-08-01 A bug in which command completion in multibyte mode could + corrupt memory for long command lines has been fixed. + +02-06-17 --- Release ksh93n- --- +02-06-17 A bug in which user defined macros could cause a core dump in + with MULTIBYE mode has been fixed. +02-06-17 A bug in which printf format specifiers of the form %2$s were causing + a core dump has been fixed. +02-06-17 A bug in which setting stty to noecho mode did not prevent the + echoing of characters by ksh when emacs or viraw mode + was enabled has been fixed. +02-06-17 A bug in which background job completion could cause the sleep + builtin to terminate prematurely has been fixed. +02-06-17 A bug in which the shell could core dump if getopts was called + when the OPTIND variable contained a negative value has been fixed. +02-06-10 The edit mode prompt has been modified to handle escape sequences. +02-06-10 A bug which occurred for interactive shells in which the builtin + cat command was used in command substitution on a file whose + size was larger than PIPE_BUF has been fixed. +02-06-10 A bug in which the trap on ERR was not being processed when + set inside a function has been fixed. +02-06-07 A bug in which function definitions could cause the history count + to be decremented by one (and even become negative) has been fixed. +02-06-05 A bug in read in which share mode could be enabled has been fixed. +02-05-28 A bug which could occur when the last command of a script was + a case statement and the action selected ended in ;& instead of ;; + has been fixed. +02-05-23 A bug with unary + introduced in ksh93k has been fixed. +02-05-07 A bug in substitutions of the form ${var/pattern/string} in which + a backslash was inserted in the replacement string when it contained + a special pattern character has been fixed. +02-05-01 A bug in the emacs edit mode which occurred in versions compiled + for multibyte character sets which occurred when a repeated search + was requested after a long line had been returned for the previous + search has been fixed. +02-04-02 vi and emacs edit modes were modified so that tab completion is + disabled when invoked from the read built-in. + +02-03-26 --- Release ksh93m+ --- +02-03-26 A bug in which \ was not handled correctly when used in file + expansion has been fixed. +02-02-18 A bug in which lines beginning with a # were deleted from here + documents when the here-document delimiter was followed by + a comment has been fixed. +02-12-06 An optimization bug in which ${!x[@]) was treated as invariant in + a for loop has been fixed. +02-02-06 A bug in which the ERR trap is not cleared for a script invoked + by name from within a function has been fixed. +02-01-08 A bug in which a shell script executed from within a subshell + could cause this script to have an invalid pointer leading + to a memory fault has been fixed. +02-01-07 Added here documents of the form <<< word (as per zsh) which + is equivalent to << delim\nword\ndelim. +02-01-07 A bug in which the first word of a compound assignment, + x=(word ...), was treated as a reserved word has been fixed. +02-01-07 A bug in the handling of \ when noglob was enabled and a + substitution of the form ${word op pattern} occurred in the + same word has been fixed. +02-01-07 A compilation option, CMDLIB_BLTIN in the file OPTION, has + been added. When this options is set, all commands implemented + in libcmd become shell builtin commands by default. +02-01-07 A bug in which builtin foo, where foo is already a builtin + would result in the builtin foo getting removed has been fixed. +02-01-07 A bug which the shell executed a command found in the current + directory when PATH have no valid directories has been fixed. +01-11-28 The value of $? was not being set when called with exit. +01-11-28 If the last command was of the form (...) and a trap on EXIT or + ERR was set, and the command inside () modified the trap, then + the original trap wasn't executed. +01-11-26 The value for 0 is now preceded by the base number when + the base was not 10. +01-11-26 The default has compilation mode has been changes so that + viraw mode will always be on. + +01-10-31 --- Release ksh93m --- +01-10-31 A for loop optimizer bug for subshells contained withing for + loops has been fixed. +01-10-16 typeset without arguments no longer outputs variable names + that do not have any attributes that are set. +01-10-16 A bug introduced in ksh93l in which assignments specified with + the exec built-in were not being expanded properly has been + fixed. +01-10-11 An optimization bug in which ${!x) was treated as invariant in + a for loop has been fixed. +01-10-11 Unsigned integer variables in bases other than 10 are printed now + expand in that base with the base prefix. +01-10-10 A number of typos in the self generating man pages for shell + built-ins have been fixed. +01-10-04 The self generated man pages for hist and fc were not working + correctly and have been fixed. +01-10-03 Yet another optimizer bug in which shell patterns were + treated as invariants has been fixed. +01-09-27 Two bugs relating to multibyte history searches and to find + have been fixed. +01-09-27 A bug introduced in ksh93k in which the PATH searching was + not restored after running a command with an assignment list + has been fixed. +01-09-26 A bug in which a zero filled field was treated as octal when + converted to integer has been fixed. +01-09-26 Yet another bug in the optimization of for loops related to + recursive functions with break or continue statements has been fixed. +01-09-25 The exponentiation operator ** was added to the shell arithmetic + evaluation. It has higher precedence than * and is left + associative. +01-09-25 The code was modified to use the ast multibyte macros + and functions for handing multibyte locales. +01-09-25 The expansion ${parameter:offset:length} now handles negative + offsets which cause offsets to be measured from the end. +01-09-25 Some spelling errors in the documentation were corrected. +01-09-24 The /dev/tcp/host/port and /dev/udp/host/port now allow + the ports to be specified by service name. +01-09-24 The change staring with ksh93g in which the the appropriate + library path variable is prepended with a corresponding library + directory has been modified. With the new method, only the + library path defined in the file named .paths in the directory + where the executable is found will be modified. See the + man page for more details. +01-09-23 The .fpath file (see ksh93h) is no longer looked for in each + directory on the path to locate function directories. The + file named .paths is used instead. +01-09-23 A bug in which IFS was not being restored after being changed in + a subshell has been fixed. +01-09-16 With the vi and emacs edit modes, after a list of command + or functions is generated with = or M-= respectively, + any element from the list can be pasted on the command line + by preceding the = or M-= with a numeric parameter specifying + the position on the list. +01-09-16 A bug in ksh93l caused command completion not to find aliases + and functions. Command listing from the edit mode was presented + in reverse order. This has been fixed. +01-09-13 Another bug in the optimization of for loops related to subshells + when traps were set has been fixed. +01-09-07 A change in ksh93l caused brace expansion to stop working + and this has been fixed. +01-09-04 A bug introduced in ksh93k in which an arithmetic statement + within a function that used name references did not follow the + reference has been fixed. +01-09-04 A bug introduced in ksh93l in which export -p did not prefix + each export with the word export has been fixed. +01-08-29 A bug in multibyte input which occurred when a partial multibyte + character was received has been fixed. +01-08-29 A bug introduced in ksh93l which could cause a core dump + when an assignment list containing PATH is specified inside + command substitution has been fixed. +01-08-09 Another bug in the optimization of for loops in ksh93l caused + errors in recursive functions using local variables that + contained for loops has been fixed. +01-07-27 A bug in which IFS would be unset after a command substitution + inside a here document has been fixed. +01-07-26 To conform to the POSIX standard, if you invoked ksh name, + and name does not contain a /, it will first try to run + one in the current directory whether it is executable or not + before doing a path search for an executable script. Earlier + versions first checked for an executable script using the + PATH variable. +01-07-23 A bug in which unset -f invoked in a subshell could unset a + function defined in the parent has been fixed. +01-07-16 A bug in the optimization of for loops in ksh93l caused + name references to be treated as invariants has been fixed. +01-07-09 A bug in which a discipline function applied to a local variable + could cause a shell exception has been fixed. Discipline + functions can only be specified for global variables. + +01-06-18 --- Release ksh93l --- +01-06-18 A bug in assigning integers larger than can be represented as + long integers to floating point variables has been fixed. +01-06-18 A bug in the handling of unsigned integers (typeset -ui) has + been fixed. +01-06-04 The evaluation of the PS1 prompt no longer effects the value + of the $? variable. +01-06-01 A small memory leak from subshells has been fixed. +01-05-22 A bug in which attributes for variables that did not have + values would be lost after a subshell has been fixed. +01-05-22 The %R format has been added to convert a shell pattern into + an extended regular expression. +01-05-22 The escape sequences \e, \cX, \C[.collating-element.], and + \x{hex} have been added to ASCII-C strings and to printf format + strings. +01-05-20 Patterns of the form {n}(pattern) and {m,n}(pattern) are now + recognized. The first form matches exactly n of pattern whereas, + the second form matches from m to n instances of pattern. +01-05-20 The shell allows *-(pattern), +-(pattern), ?-(pattern), + {m,n}-(pattern}, and @-(pattern) to cause the minimal + match of pattern to be selected whenever possible rather + than the maximal (greedy) match. +01-05-20 The character class [:word:] has been added to patterns. + The word class is the union of [:alnum:] and the character _. +01-05-20 Inside (...) pattern groups, the \ character is now treated + specially even when in an enclosing character class. The + sequences, \w, \d, \s are equivalent to the character classes + word, digit, and space respectively. The sequences \W, \D, + and \S are their complement sets. +01-05-20 The shell now recognizes pattern groups of the form + ~(options:pattern) where options or :pattern can be omitted. + Options use the letters + and - to enable and disable options + respectively. The option letters g (greedy), i (ignore case) + are used to cause maximal matching and to cause case + insensitive matching respectively. If :pattern is also + specified, these options are only in effect while this + pattern is being processed. Otherwise, these options remain + in effect until the end of the pattern group that they are contained + in or until another ~(...) is encountered. These pattern groups + are not counted with respect to group numbering. +01-05-14 When edit completion, expansion, or listing occurs in the + middle of a quoted string, the leading quote is ignored when + performing the completion, expansion, or listing. +01-05-14 A small memory leak from subshells has been fixed. +01-05-10 A bug in which open files were not restored after a subshell + that had used exec to replace a file has been fixed. +01-05-10 Redirection to a null file name now generates an error message. +01-05-09 The shell now rejects some invalid parameter substitutions that + were previously processed in undefined ways. +01-05-09 A bug in which the output of select was not flushed before the + read when input did not come from the terminal has been fixed. +01-05-08 A bug in which job ids would not be freed for interactive shells + when subshells ran built-ins in the background has been fixed. +01-05-08 The FPATH variable now requires an explicit . to cause the + current directory to be treated as a function directory. +01-05-08 A bug in read -n when echo mode was disabled has been fixed. +01-05-07 A bug in which function definitions could be listed as part + of the history has been fixed. +01-04-30 This release uses a new and often much faster pattern matcher than + earlier releases. +01-04-30 An optimizer now eliminates invariant parameter expansions from + for while and until loops. +01-04-30 The variable .sh.match is set after each pattern match (# % or /) + in a variable substitution. The variable .sh.match is an + indexed array with element 0 being the complete match. + The array is only valid until the next subsequent pattern + match or until the value of the variable changes which ever + comes first. +01-04-30 A self generating man page has been added to shcomp. Also, + shcomp now stops compiling when it finds an exit or exec + command and copies the remainder so that it can be used + for standard input. +01-04-30 The shcomp command was modified so that it can work in an + EBCIDIC environment and that binary scripts are portable + across environments. +01-04-30 A bug in the handling of a trailing : in PATH has been fixed. +01-04-30 A bug in which the builtin version of a command would get invoked + even though the full pathname for the command was specified + has been fixed. +01-04-30 A bug in which read would loose the last character when + reading the last line of a file that did not contain a new-line + character has been fixed. +01-04-23 A bug on some systems in which in vi mode the end of file + character and end of line character could be swapped has + been fixed. +01-04-23 A bug on some systems in which invoking a shell script that + did not have execute permission could set the exit value to + 127 rather than 126 has been fixed. +01-04-20 A bug in which read -n from a pipe would block if fewer than + n characters was received has been fixed. +01-04-09 A bug in which invalid patterns, for example, ) by itself, + was not treated as a string has been fixed so that if i=')', + then [[ $i == $i ]] is true. +01-04-09 The shell arithmetic now interprets C character constants. +01-04-09 A bug in which a non-zero return from a function defined + with the function reserved word did not trigger the ERR + trap or exit with set -e has been fixed. +01-04-02 A bug on some systems, in which characters above 127 were + not displayed correctly in vi or emacs edit mode has been fixed. +01-04-02 A bug on some systems, introduced in the 'k' point release, in + which the erase character in viraw mode was moving the cursor + to the left without erasing the character has been fixed. +01-04-02 On some systems the wcwith() function was returning a wrong + value for characters and caused characters to be displayed + incorrectly from the shell edit modes. A work around for + this problem has been added. +01-03-26 A bug in which valid scripts could produce syntax errors + when run with locales that considered characters such as "'" + to be space characters has been fixed. +01-03-20 A bug in which an syntax error in an arithmetic expression + entered interactively could cause the shell to go into + an infinite loop outputting the error message has been fixed. +01-03-10 ksh93 accepts -l as a synonym for -L in test on systems for + which /bin/test -l tests for symbolic links. +01-03-10 A bug in parsing scripts in which { and } are used in place of + in and esac in case statements embedded in compound commands + has been fixed. Use of { and } for in and esac is obsolete. +01-03-06 A bug in which an argument of the form foo=bar was not + being passed correctly to a traced function whose name + was foo has been fixed. +01-03-02 Using $(trap -p name) did not print the name of the current + trap setting for trap name. +01-02-26 Exported floating point variables gave incorrect results + when passing them to ksh88. This has been fixed. +01-02-25 A race condition in which a coprocess which completed too quickly + would not allow subsequent coprocesses to start has been fixed. +01-02-25 The 'g' format specifier is now handled by printf. It had + inadvertently been omitted. +01-02-20 The + was not being displayed during an execution trace + with the += assignment operator. +01-02-19 The error message which occurs when the interpreter name + defined on the #! line does not exist is more informative. +01-02-19 A bug in which $0 would not be set correctly when a + script with #! was invoked by full pathname from the + directory of the script has been fixed. +01-02-19 A shell script did not always pick up tty mode changes + made by external commands such as stty which could + effect the behavior of read. +01-02-19 The -u, -g, and -k unary tests did not give the correct + results when used with negation and this has been fixed. + +01-02-05 --- Release ksh93k+ --- +01-02-05 The sequence \ inside $'...' was not incrementing + the line count and this has been fixed. +01-02-05 Modified expansion of "${@-}" so that if no arguments are set + it results in null string rather than nothing. +01-02-02 memory leak problem with local variables in functions fixed. +01-01-25 allow arithmetic expressions with float%int and treat them + as ((int)float)%int rather than as an error. +01-01-19 read -n1 was not working and has been fixed. +01-01-17 ksh now handles the case in which a here document in command + substitution $() is terminated by the trailing ). Previously, + a new-line was needed at the end of the delimiter word. +01-01-02 A bug in which a KEYBD trap would cause a multi-line token + to be processed incorrectly has been fixed. +00-12-10 Arithmetic integer constants can now have L and U suffices. +00-12-10 A bug in the processing of arithmetic expressions with compound + variables when the -n option is on has been fixed. +00-12-08 A bug in M-f and M-b from emacs mode has been fixed. This + bug only occurs when ksh93 is compiled without MULTIBYTE enabled. +00-11-29 A bug in which jobs -p would yield 0 for background + jobs run in a script has been fixed. +00-11-21 A bug in integer arrays in which the number of elements is + incorrect when the ++ operator is applied to a non-existing + element has been fixed. For example, integer x; ((x[3]++)). +00-11-20 A timing bug in which the shell could reset the terminal + group to the wrong value in the case that the a new process + changes the terminal group during startup has been fixed. + +00-10-27 --- Release ksh93k --- +00-10-27 Using tab for completion now works only when applied + after a non-blank character at the end of the current line. + In other case a tab is inserted. +00-10-27 A bug in the emacs edit mode for ^X^E has been fixed. + The ^X^E sequence is supposed to invoke the full editor + on the current command. +00-10-18 A bug in which expansions of the form ${var//pattern/string} + did not work correctly when pattern was '/' or "/" has + been fixed. +00-10-18 The output format for indexed arrays in compound variables + has been modified so that it can be used as input. +00-10-18 Assignments with name references (typeset -n) will now + implicitly unreference an existing name reference. +00-10-17 A bug the += append operator when a single array element + is appended to a variable that is not an array has been fixed. +00-10-16 A bug in which the SIGCONT signal was being sent to + each process will kill -0 or kill -n 0 has been fixed. +00-10-12 The arithmetic evaluation portion has been rewritten to + perform a number of optimizations. +00-10-10 A bug in which name prefix matching ${!name.*} was not + checking name to see if it was a name reference has been fixed. +00-09-26 A bug in the multibyte version in which the width of for + non-printing characters was not correct has been fixed. +00-09-12 Made changes to get multibyte editing work on UWIN for windows +00-09-12 A bug in which multibyte characters would be displayed incorrectly + has been fixed. +00-08-08 Removed build dependency on iswprint() and iswalph(). +00-07-20 In some cases the read builtin would read more than a single + line from a pipe on standard input and therefore leave the seek + position in the wrong location. +00-07-05 If the directory / is on the path, a / will not be inserted + between the directory and the file name during path searching + to avoid searching // for systems that treat this specially. +00-06-26 A bug in which on rare occasions wait could return before all + jobs have completed has been fixed. +00-06-21 A bug in which backspace did not work correctly during the + R replace directive in vi-mode has been fixed. +00-06-12 Added variable name completion/expansion/listing to the set of + completions. Variable name completions begin with $ or "$ followed + by a letter. +00-05-09 --- Release ksh93j --- +00-05-09 Modified command substitution to avoid using /tmp files when + run on read-only file systems. +00-04-17 Modified printf to handle '%..Xc' and '%..Xs' options where X + is not an alpha character. Previous versions core dumped with this. +00-04-10 Changes to multibyte editing code were made to use standard + ISO C functions rather than methods devised before the standard. +00-04-09 Add %H options to printf to output strings with <"'&\t> properly + converted for use in HTML and XML documents. +00-04-07 Modified getopts builtin to handle \f...\f in usage string + by invoking specified function. +00-04-04 Added self generating man pages for bg, fc, fg, disown, jobs, + hist, let, ., and ulimit. +00-03-30 The append operator += has been added and can be used + for all assignments, strings, arrays, and compound variables. +00-03-30 Code was modified in several places to support automatic + generation of C locale dictionaries. +00-03-28 A bug in which the set and trap commands invoked with --name + type arguments would terminate the invoking script has + been fixed. +00-03-27 A bug in which the library path variable was not updated + correctly on some systems as described in the 'g' point + release has been fixed. +00-03-07 printf now returns a non-zero exit status when one of + its arguments cannot be converted to the given type. +00-03-05 The return value and error message for a command that + was found on the path but was not executable was set + incorrectly. +00-03-05 A prototype for ioctl() was removed from the vi edit mode. + +00-01-28 --- Release ksh93i --- +00-01-28 Most of the built-in commands and ksh itself are now + self documenting. Running command --man will produce + screen output. Running command --html produces the + man page in html format. +00-01-28 The getopts builtin can process command description + strings to produce man pages. +00-01-28 A bug in which a script could terminate when getopts + encountered an error when invoked inside a function + has been fixed. +00-01-28 When a symbolic link was specified as the name of + the script to invoke by name, the value of $0 was + set to the real file name rather than the link name + in some cases and this has been fixed. +00-01-28 A bug in which the precision given as an argument + to printf was not working has been fixed. + +99-03-31 --- Release ksh93h --- +99-03-31 The PATH search algorithm has been modified to look + for a file named .fpath in each bin directory and if + found, to search for functions in this directory if + it cannot find the command in that directory. +99-03-31 When performing pathname expansion, the shell checks + to see whether each directory it reads is case sensitive + or not, and performs the matching accordingly. +99-03-31 The %T format for printing formatted date/time. +99-03-31 The emacs and vi modes now handle arrow keys when + they use standard ANSI escape sequences. +99-03-31 The TAB key can be used for completion in emacs and viraw mode. +99-03-31 A bug in setting .sh.editchar during the KEYBD trap + for the MULTIBYTE option was fixed in release ksh93h. +99-03-31 A bug in shcomp for compilation of unary operators with [[...]] + has been fixed. +99-03-31 A bug in which the value of $? was changed when executing + a keyboard trap has been fixed. +99-03-31 The handling of SIGCHLD has been changed so that the + trap is not triggered while executing trap commands + to avoid recursive trap calls. +99-03-31 A bug in which a local variable in a function declared readonly + would generated an error when the function went out of + scope has been fixed. +99-03-31 A bug in which \ entered from the keyboard + with the KEYBD trap enabled has been fixed. +99-03-31 The error message for a misplaced ((, for example print ((3), + was often garbled and has been fixed. +99-03-31 A bug in the KEYBD trap in which escape sequences of the form + [#~ were not being handled as a unit has been fixed. +99-03-31 A bug in which ksh would consider expressions like [[ (a) ]] + as syntax errors has been fixed. +99-03-31 A function defined as foo() without a function body + was not reported as a syntax error. +99-03-31 A bug in which ksh could run out of file descriptors when + a stream was repeatedly opened with exec and read from + has been fixed. + +98-04-30 --- Release ksh93g --- +98-04-30 The pipefail option has been added. With pipefail + enabled, a pipeline will not complete until all + commands are complete, and the return value will + be that of the last command to fail, or zero if + all complete successfully. +98-04-30 The name-value pair library uses the cdt library rather + than the hash library. This change should be transparent + to applications. +98-04-30 On the U/WIN version for Window 95 and Windows NT, + when a directory beginning with a letter followed by + a colon is given to cd, it is assumed to be an absolute + directory +98-04-30 When an executable is found on a given path, + the appropriate library path variable is prepended + with a corresponding library directory. +98-04-30 A bug in which a name reference could be created to + itself and later cause the shell to get into an infinite + loop has been fixed. +98-04-30 A bug in shcomp relating to compound variables was fixed. +98-04-30 A bug introduced in ksh93e in which leading 0's in -Z + fields caused the value to be treated as octal for arithmetic + evaluation has been fixed. +98-04-30 A bug when a name reference with a shorter name than + the variable it references was the subject of a compound + assignment has been fixed. +98-04-30 A bug which in which assignment to array variables in + a subshell could effect the parent shell has been + fixed. +98-04-30 read name?prompt was putting a 0 byte at the end of the + prompt on standard error. +98-04-30 A bug in [[ string1 > string2 ]] when ksh was run with -x + has been fixed. +98-04-30 A bug in which the escape character was not processed + correctly inside {...} when brace expansion is enabled + has been fixed, for example {\$foo}. +98-04-30 A bug in line continuation in here-documents has been + fixed. +98-04-30 The default base when not specified with typeset -i is + 10 in accordance with the documentation. Previously, + the value was determined by the first assignment. +98-04-30 A parsing bug in which a # preceded alphanumeric + characters inside a command substitution caused + a syntax error to be reported has been fixed. +98-04-30 A bug in which a decimal constant represented as 10#ddd + where ddd was more than five digits generated a syntax + error has been fixed. +98-04-30 A bug in here document expansion in which ${...} expansions + were split across buffer boundaries has been fixed. +98-04-30 The sh_fun() function now takes third argument which + is an argument list for the invoked discipline function + or built-in. +98-04-30 A callback function can be installed which will give + notification of file duplications and file closes. +98-04-30 When ksh is compiled on systems that do not use fork() + current option settings where not propagated to sub-shells. + +97-06-30 --- Release ksh93f --- +97-06-30 Hostnames in addition to host addresses can be given in + /dev/tcp/host/port virtual file names. +97-06-30 File name completion and expansion now quotes special + characters in file names from both emacs and vi edit modes. +97-06-30 An empty for list behave like a for list with null expansions. + It produces a warning message with sh -n. +97-06-30 The code has been modified to work with EBCDIC as well as ASCII. +97-06-30 A bug which would cause the secondary prompt to be + displayed when a user entered a literal carriage + return has been fixed. +97-06-30 A bug which caused ksh read -s name to core dump was + fixed. +97-06-30 A bug with the expansion of \} and \] inside double + quoted strings that also contained variable expansions + has been fixed +97-06-30 Changes in the ksh93e point release caused autoload + functions invoked from within command substitution + to fail. This has been fixed. +97-06-30 A bug in the processing of here-documents that could + prevent variable substitution to occur after $(...) command + substitution for long here documents has been fixed. +97-06-30 A bug caused by a race condition that could cause SIGTERM + to be ignored by a child process has been fixed. +97-06-30 A bug which prevented the startup of a coprocess immediately + after killing a running coprocess has been fixed. +97-06-30 ulimit foobar, where foobar is not an arithmetic + expression, now gives an error message as it did with ksh88 + instead of setting the file size limit to 0. +97-06-30 A bug which could cause an interactive shell to terminate when + the last process of a pipeline was a POSIX function was fixed. +97-06-30 A bug which could cause command substitution of a shell script + to core dump has been fixed. +97-06-30 A security hole was fixed in suid_exec. +97-06-30 Arithmetic functions such as pow() that take more than + one argument, did not work if arguments other than the + first contained parenthesized sub-expression. +97-06-30 The error message from a script containing an incomplete + arithmetic expression has been corrected. +97-06-30 A bug which caused a core dump on some machines when + the value of a name reference contained a positional + parameter and the name reference was not defined inside + a function has been fixed. +97-06-30 Arithmetic expressions now correctly handle hexadecimal + constants. +97-06-30 A bug in which integer variables could be expanded + with a leading 10# when declared with typeset -i + multiple times has been corrected. +97-06-30 A bug in which IFS wasn't correctly restored when + set within command substitution has been fixed. +97-06-30 The _ character is now considered as part of a word + with the M-f and M-b emacs directives as it was in ksh88. +97-06-30 A bug in brace pattern expansions that caused expressions + such as {foo\,bar,bam} to expand incorrectly have been fixed. + + +96-07-31 --- Release ksh93e --- +96-07-31 The math functions, atan2, hypot, fmod, and pow were added. +96-07-31 When a shared library is loaded, if the function lib_init() + is defined in the library, it is invoked the first time that + the library is loaded with builtin -f library. +96-07-31 The k-shell information abstraction database option, KIA, + has been revamped. +96-07-31 Empty command substitutions of the form $() now work. + whence -v foo now gives the correct result after calling + builtin -d foo. +96-07-31 A bug in right to left arithmetic assignment for which + the arithmetic expression (( y = x = 1.5 )) did not + yield 1 for y when x was declared typeset -i was fixed. +96-07-31 printf has been fixed to handle format containing \0 + and/or \0145 correctly. In addition, characters following + %b in the format string are no longer displayed when + the operand contains \c. +96-07-31 A bug in printf that could cause the %E format to + produce unnormalized results has been fixed. +96-07-31 A bug which causes some arithmetic expressions to be + incorrectly evaluated as integer expressions rather + that floating point has been fixed. +96-07-31 Functions defined inside a subshell no longer remain + defined when the subshell completes. +96-07-31 The error message from sh -c ';echo foo' has been + corrected. +96-07-31 The format for umask -S has been changed to agree + with the specification in the POSIX standard. +96-07-31 A bug that caused side effects in subscript evaluation + when tracing was enabled for subscripts using ++ or -- + has been fixed. +96-07-31 To conform to the Posix standard getopts has been changed + so that the option char is set to ? when it returns with + a non-zero exit status. +96-07-31 The handling of \} inside ${name...} has been fixed so + that the \ quotes the }. +96-07-31 A bug that caused the read builtin to resume execution + after processing a trap has been fixed. +96-07-31 [[ -s file ]] has been fixed so that if file is open + by ksh, it is flushed first. +96-07-31 In some cases attributes and sizes for non exported + variables weren't being reset before running a script. +96-07-31 The value of TMOUT was affected by changes make to + it in a subshell. +96-07-31 The jobs command did not reflect changes make by + sending the CONT signal to a command. +96-07-31 The error message for ksh -o unknown was incorrect. +96-07-31 Functions invoked as name=value name, did not use + values from the calling scope when evaluating value. +96-07-31 A bug in which the shell would reexecute previously + executed code when a shell script or coprocess was + run in the background has been fixed. +96-07-31 A bug in which an empty here-document would leave + a file descriptor open has been fixed. +96-07-31 A bug in which $(set -A array ...) would leave a + side effect has been fixed. +96-07-31 A discipline function for a global variable defined + within a function defined with the function keyword, + incorrectly created a local variable of the same name + and applied the discipline to it. + +95-08-28 --- Release ksh93d --- +95-08-28 The \ character was not handled correctly in replacement + patterns with ${x/pattern/replace}. +95-08-28 A bug with read in which the line did not end with + a new-line has been fixed. +95-08-28 A bug in file name generation which sometimes + appended a . for filenames that ended in / has + been fixed. +95-08-28 If a process is waited for after a status has + been returned by a previous wait, wait now + returns 127. +95-08-28 A bug with hist (fc) -e which prevented a command + to re-executed after it had been edited has been fixed. +95-08-28 A bug which prevented quoting from removing the meaning + of unary test operators has been fixed. +95-08-28 A bug with typeahead and KEYBOARD traps with the + MULTIBYTE option set has been fixed. +95-08-28 Builtin functions can take a third argument which is + a void*. +95-08-28 The nv_scan() function can restrict the scope of a walk + to the top scope. + +95-04-31 --- Release ksh93c --- +95-04-31 The expansion of "$@" was incorrect when $1 was the null + string. +95-04-31 A bug which could incorrectly report a syntax error in + a backquoted expression when a $ was preceded by \\ + has been fixed. +95-04-31 A bug which prevented the shell from exiting after + reporting an error when failing to open a script + has been fixed. +95-04-31 A bug that could lead to memory corruption when a + large here document that required parameter or command + substitution was expanded has been fixed. +95-04-31 A bug that could cause a core dump on some systems + after ksh detected an error when reading a function + has been fixed. +95-04-31 A bug which could cause a coprocess to hang when + reading from a process that has terminated has been fixed. +95-04-31 A bug which caused a script to terminate when set -e + was on and the first command of and && or || list + failed has been fixed. +95-04-31 A bug with here documents inside $(...) when the delimiter + word is an identifier has been fixed. +95-04-31 A bug which caused $0 to display the wrong value when + a script was invoked as an argument to the . command + and the eval command has been fixed. +95-04-31 A bug that could cause the built-in sleep to hang + has been fixed. +95-04-31 A bug introduces in 12/28/93b which caused the backslash + to be removed when it was followed by digit inside double + quotes in some instances has been fixed. +95-04-31 A bug which could cause a core dump if ksh was invoked with + standard input closed has been fixed. +95-04-31 A bug which could cause a core dump if typeset -A was + specified for an existing variable has been fixed. +95-04-31 Variables that were unset but had attributes such as readonly + and export were not listed with readonly, export and typeset. +95-04-31 Several problems with signals have been fixed. +95-04-31 A bug which prevented ulimit -t from working has been fixed. + Also, a bug in which failed ulimits could cause a core dump + has also been fixed. +95-04-31 A bug in expansion of the form ${name/#pattern/string} and + ${name/%pattern/string} has been fixed. +95-04-31 A bug which caused read -r on a line that contained only + blanks to get a non-null value has been fixed. +95-04-31 A bug introduced in the 'a' point release in which + ${x='\\'} expanded to \ when x was unset has been fixed. +95-04-31 A bug which prevented a trap on EXIT from being executed + when the last command in a script was a function invocation + has been fixed. +95-04-31 A bug which caused an interactive shell ignore input when + standard error was redirected to a file with exec, + and then restored with exec 2>&1 has been fixed. +95-04-31 An interactive shell turns on monitor mode even when + standard error has been redirected to a file. +95-04-31 A bug which could cause standard input to be incorrectly + positioned for the last command of a script has been fixed. +95-04-31 A bug in the edit modes which allowed walking back in + the history file for more than HISTSIZE commands has + beed fixed. +95-04-31 A bug which could cause a core dump if variable TMPDIR was + changed between two command substitutions has been fixed. +95-04-31. A bug which prevented a trap on EXIT from being cleared + has been fixed. +95-04-31 A bug fixed for the v directive in vi MULTIBYTE has been + fixed. +95-04-31 Code to for IFS handling of multibyte characters has + been added. +95-04-31 The displaying of multibyte strings in export, readonly, + typeset, and execution traces has been fixed. +95-04-31 Variables inside functions are now statically scoped. + The previous behavior was never documented. +95-04-31 Variables inside functions are now statically scoped. + The previous behavior was never documented. +95-04-31 A few changes have been made to the name-value library + that affect built-ins that use disciplines. The + changes allow disciplines to be shared by variables + and should make it possible to add new disciplines + without recompilation. +95-04-31 The name-value library interface has undergone significant + change for this revision. See the new nval.3 man page. + +94-12-31 --- Release ksh93b --- +94-12-31 Variables inside functions are now statically scoped. + The previous behavior was never documented. +94-12-31 If IFS contains two consecutive identical characters belonging + to the [:space:] class, then this character is treated as + a non-space delimiter so that each instance will delimit + a field. For example, IFS=$'\t\t' will cause two consecutive + tabs to delimit a null field. +94-12-31 The getopts command has a -a name option that specifies a + name that will be used for usage messages. +94-12-31 A bug which caused unset RANDOM to dump core has been + fixed. +94-12-31 A bug which prevented return for terminating a profile + or ENV file has been fixed. +94-12-31 A bug which prevented standard input from being + directed to /dev/null for background jobs when + monitor mode was turned off has been fixed. +94-12-31 Statements of the form typeset -options var[expr]=value + did not perform substitutions on expr as expected. +94-12-31 A bug which prevented the shell from sending a HUP + signal to some background jobs that were not disowned + has been fixed. +94-12-31 A bug which allowed a script to trap signals that are + ignored at the time that the shell was invoked by exec + has been fixed. +94-12-31 A bug which could cause a core dump when a discipline + function was unset within a discipline was fixed. +94-12-31 The typeset builtin now accepts a first argument of + + or - for compatibility with ksh88. +94-12-31 For compatibility with ksh88, the results of expansions + of command arguments will treat the extended character + match characters ()|& as ordinary characters. +94-12-31 A bug which caused read to fail on a file that was + open for read/write with <> when the first operation + was print or printf has been fixed. +94-12-31 When a job is suspended, it is put on the top of + the job list as required by the POSIX standard. +94-12-31 The value of OPTARG when an option that required + an argument but didn't have one was incorrect in the + case the the option string began with a :. +94-12-31 A bug which caused the terminal to get into a bad + state with some KEYBD traps in vi-mode has been fixed. +94-12-31 A bug which caused an invalid trap to cause a script + to terminate, rather than just return an error, has + been fixed. +94-12-31 Backreferencing sub-expressions in patterns and replacement + strings now works. +94-12-31 A bug in chmod which caused the -R option to fail has + been fixed. +94-12-31 More signal names have been added for Solaris + +94-06-30 --- Release ksh93a --- +94-06-30 An expansion bug which causes portions of a word after + a $((...)) expansion that contains a nested $var expansion + to be lost has been fixed. +94-06-30 A bug that caused a core dump when a script that did not + have PWD set and did a cd inside command substitution + has been fixed. +94-06-30 A bug which caused a core dump on some machines when + the LANG variable was assigned to has been fixed. +94-06-30 A bug which incorrectly handled set disciplines that + performed arithmetic evaluation when the discipline + was called from the arithmetic evaluator has been fixed. +94-06-30 A bug caused by an EXIT trap inside a function that + was executed in a subshell was fixed. +94-06-30 If foo is a function, and not a program, then command foo + now reports that foo isn't found rather than invoking foo. +94-06-30 The previous version incorrectly listed -A as an + invocation option. The -A option is only for set. +94-06-30 A bug was fixed which caused ksh to loop when execution trace + was enabled and the PS4 prompt required command substitution. +94-06-30 A bug which could cause the job control switch character + to be disabled when a script that enabled monitor mode + terminated was fixed. +94-06-30 A bug in the macro expansion global replacement operator //, + when the pattern began with a [ or +( has been fixed. +94-06-30 A bug which prevented ~ expansion from occurring when + it was terminated with a colon inside an assignment + has been fixed. +94-06-30 A bug in the dot command which prevented autoload functions + from working has been fixed. +94-06-30 A bug which caused a variable to be unset if the + its value were expanded inside a set discipline has + been fixed. +94-06-30 Whence -a now longer reports that a defined function + is undefined. +94-06-30 A bug on some systems in which $0 would be incorrect + in scripts invoked by name has been fixed. +94-06-30 Here documents with an empty body now work. +94-06-30 A bug which disabled argument passing and resetting + of options for a script invoked by name inside a + function has been fixed. +94-06-30 A bug in which an EXIT trap set the caller of a function + would be executed if a command called inside a function + was not found has been fixed. +94-06-30 A bug which allowed a script to trap signals that are + ignored at the time that the shell was invoked has + been fixed. +94-06-30 A bug which caused 2<&1- when applied to a shell built-in + to leave standard input closed has been fixed. +94-06-30 A bug which caused the shell to incorrectly parse + $() command substitutions with nested case statements + has been fixed. + diff --git a/usr/src/lib/libshell/common/RELEASE88 b/usr/src/lib/libshell/common/RELEASE88 new file mode 100644 index 0000000000..2466e39781 --- /dev/null +++ b/usr/src/lib/libshell/common/RELEASE88 @@ -0,0 +1,422 @@ +This is a list of changes that have been made since the 11/16/88 version +of ksh. + +1. New features in 12/28/93 + a. Associative arrays. The new version of ksh supports both + associate arrays and the older indexed arrays with the same + array syntax. A new -A option of typeset is used to declare + an array to be associative. As with indexed arrays, $name is + equivalent to ${name[0]}. The prefix operator ! was added + to the parameter expansion syntax to expand to the list of + indices. For example, ${!name[@]} expands to the list of array + indices for variable name. + + b. Several additions have been made to shell arithmetic: + 1. The shell now performs floating point arithmetic. The + typeset options -F and -E have been added for floating + point and scientific notation respectively. + 2. The prefix and postfix ++ and -- operators. + 3. The comma and ?: operators. + 4. The math library functions. + 5. An arithmetic for statement of the form + for ((expr1; expr2; expr3)) + do ... + done + 6. Integer arithmetic extended up to base 64. + + c. Some additions to the macro expansion syntax have been made + to specify substrings and sub-arrays: + 1. ${name:expr} expands to the substring of ${name} starting at + the character position defined by arithmetic expression expr. + 2. ${name:expr1:expr2} expands to the substring of ${name} starting + at expr1 and consisting of at most expr2 characters. + 3. ${name[@]:expr} expands to the values of ${name[@]} starting at + the element defined by arithmetic expression expr. + 4. ${name[@]:expr1:expr2} expands to at most expr2 values of + ${name} starting at expr1. + 5. ${@:expr} expands the positional parameters starting at expr. + 6. ${@:expr1:expr2} expands to at most expr2 positional parameters + starting at expr1. + 7. ${!name} expands to the name of the variable named by name. + It will expand to name unless name is reference variable. + 8. ${!name[sub]} expands to the name of the subscript of the + given variable. If sub is @ or * the list of subscripts + is generated. + 9. ${!prefix*} and ${!prefix@} expand to the list of variable + names beginning with prefix. + 10. The substring operators, # and % can be now be applied + with aggregates (@ or *) and are applied to each. + 11. ${name/pattern/string} expands to the value of name with + the first occurrence of pattern replaced by string. + With aggregates (@ or *) this operation is applied to each. + 12. ${name/#pattern/string} Same as above but the pattern + to be replaced must match at the beginning. + 13. ${name/%pattern/string} Same as above but the pattern + to be replaced must match at the end. + 14. ${name//pattern/string} expands to the value of name with + the each occurrence of pattern replaced by string. + With aggregates (@ or *) this operation is applied to each. + + d. The name space for variables has been extended. The character '.' + can be used at the beginning of a name, and to separate identifiers + within a name. However, to create a name of the form, foo.bar, + the variable foo must exist. The namespace starting with .sh + is reserved for shell implementation variables. Exported + variable cannot contain a '.'. + + e. Compound assignments. The assignment syntax, varname=value, + has been extended to allow assignments of the form + varname=(assignment_list). As elsewhere in the shell + spaces or tabs are optional around the parentheses, and + no space is permitted between the varname and the =. The + assignment_list can be one of the following: + 1. A list of words. In this case each word is expanded as + in a for list and the resulting items become elements + of the indexed array varname. + 2. A list of subscript assignments in the form + [subscript]=value. In this, these elements become + elements of the associative array varname. + 3. A list of assignments; simple or compound. In this + case, each assignment is made to varname.name, where + name is the name of the enclosed assignment. + 4. Assignments in the form of readonly or typeset + statements. In this case each assignment is made as + in 3 above, and the attributes are given to the + corresponding variable. + In case 3 and 4 above, the value of "$varname" after + the above assignment is (assignment_list), where the + assignment_list produced would reproduce all of the + variables under varname.*. + + f. Function names of the form variable.action (called discipline + functions) can be defined where variable is any valid variable + name and action is get, set, or unset. The function variable.get + is invoked each time the variable is referenced. The set + discipline is invoked each time the variable is assigned to. + The unset discipline is invoked when a variable is unset. + The new variables .sh.name, .sh.subscript, and .sh.value are + defined inside the function body. Other shell extensions + may have their own set of discipline functions. + + g. The compound command !, which negates the return value of the + following pipeline, has been added. + + h. On systems that support dynamic loading with dlopen(), it is + now possible to add built-in commands at runtime with the + a builtin command named builtin. + + i. The following builtins have been added: + 1. command name [ ... ] + 2. sleep [decimal-seconds] + 3. builtin [-ds] [-f file] [name...] + 4. getconf name [pathname] + 5. disown [job...] + + j. An addition format for literal strings, $'....' can + be used where ever literal strings are valid. The string + inside the single quotes will be converted using the ANSI-C + escape conventions. Additionally, the escape sequence \E + expands to the escape character (default \033) whenever ANSI-C + escape sequences are recognized. + + k. A typeset -n option has been added which causes the value of a + variable to be treated as a reference to another variable so that + variables can be indirectly named. For example, if $1 contains + the name of a variable, then typeset -n foo=$1 causes the variable + foo to be synonymous with the variable whose name is $1. A builtin + alias, nameref='typeset -n' has been added to aid mnemonics. + Reference names cannot contain a '.'. Whenever that portion of + a variable up to the first '.' matches a reference name, the + reference value is substituted. For example, with nameref foo=.top, + then ${foo.bar} is equivalent to ${.top.bar}. When used as the + index of a for or select loop, each assignment causes a + new name reference to occur. + + l. The KEYBD trap has been added which is triggered when a key + or escape sequence is typed while reading from the keyboard + in an edit mode. This, combined with some new variables + makes it possible to program your key bindings in ksh. + + m. New variables have been added: + 1. FIGNORE defines a set of file names to be ignored in each + directory when performing pathname expansion, replacing + the rule that requires that a leading . be matched explicitly. + 2. Variable sh.edchar contains the value of the keyboard character + that has been entered when processing a KEYBD trap. If the value + is changed as part of the trap action, then the new value replaces + the key or keys that caused the trap. + 3. Variable sh.edcol is set to the character position of the cursor + within the input buffer during a KEYBD trap. + 4. Variable sh.edmode is set to the escape character when in vi + insert mode. + 5. Variable sh.edtext is set to the contents of the input buffer + during a KEYBD trap. + 6. HISTEDIT is checked before FCEDIT. FCEDIT is obsolete. + 7. HISTCMD is the number of the current command in the history + file. + 8. Variable .sh.version is set to the version string for + this shell. + 9. Variable .sh.name is set to the name of the variable + that that was referenced or assigned to when executing a get + or set discipline function. + 10. Variable .sh.subscript is set to the subscript for the variable + that was referenced or assign to when executing a get or + set discipline function. + 11. Variable .sh.value is set to the new value for the variable + that was assigned to when executing the set discipline function. + + n. New invocation and set -o options have been added: + 1. set -o notify (or set -b) causes background completion messages + to be displayed as soon as the job completes. + 2. There is a compile time option named KIA which enables + creation of a relational database for commands, variables + and functions defined and referenced by a script. The + option -I , causes the database to be generated + in . The database format can be queried via + the cql command. + o. ksh93 can read and evaluate pre-compiled scripts generated by + a separate program called shcomp. + p. More work on internationalization has been added: + 1. The decimal point character is processed per locale + 2. A $ can be placed in front of each string to indicate + that the string needs translation but is otherwise ignored. + This means that if a message catalog of all $"..." strings + is generated, then a program such as print $"hello world" + could display "bonjour monde" in the french locale. + q. Backreferences have been added to pattern matching. The sequence + \d, where d is a digit from 1-9, matches the same string as + the d-th previous parenthesis group. Backreferences + can be used within patterns, and within replacement strings + with any of the ${name/...} operators. + +2. Changes made in 12/28/93 + a. The output format of many commands has changed as follows: + 1. System error messages are displayed whenever a failure + is caused by a system call. + 2. The exit status has changed in many cases: + a. USAGE messages cause an exit status of 2. + b. Commands not found cause exit - 127. + c. Command found, but not executable - 126. + d. Terminated because of signal - 256+sig + 3. The output of values from built-ins that contain special + characters are quoted in a manner that then can be re-input. + 4. The trace output puts quotes around the output so that it + can be reused as input. + 5. The output for trap is in a format that can be reinput the + the shell to restore the traps. + 6. kill -l lists the signal names without numbers as + required by the POSIX standard. + + b. The following changes have been made to shell functions: + 1. The semantics of functions declared with name() has changed + to conform with the IEEE-POSIX 1003.2 standard. In particular, + these functions are executed in a dot script environment rather + than a separated function environment so that there are no + local variables and no scoping for traps. + 2. Functions declared as function name, preserve the old ksh + semantics can be also used as the first argument to the dot (.) + command to have them executed in a dot script environment. + + c. The command search rules have changed as follows: + 1. Special built-ins (those with a dagger in front of them) are + executed first. + 2. Functions are executed next. + 3. Other built-ins that do not require an executable version + (for example cd and read) come next. + 4. If the command name contains a slash, the pathname corresponding + to the command name is executed. + 5. If name corresponds to a previously encountered pathname + on the PATH variable, the corresponding command is executed. + 6. If the command name does not contain a slash, then the PATH + variable is used to find an executable by that name. If + the directory that the command is found is also contained in + the FPATH variable, then the command treated as a function. + If the shell has a built-in version of the command corresponding + to this command, then the built-in version of this command + is executed. Otherwise, the shell remembers that pathname + corresponding to this command name and executes this pathname. + 7. If the name is not found on PATH, then the directories in + FPATH are searched. If found, then the command is executed + as a function. + + d. Built-in commands options now conform to the IEEE-POSIX 1003.2 + conventions with some additions. In particular, + name -? + will now print a Usage line for name, except for true, false, + colon, login, newgrp, echo, [, and command. + + e. Tilde expansion is now performed as part of the word expansions. + The effect of this is that if word begins with ~ in ${name op word}, + it will be expanded unless escaped. + + f. Pathname expansion is no longer performed on redirection words + unless the shell is interactive. + + g. Changes to shell and options: + 1. The -n option has been enhanced to produce more warning and + portability messages. + 2. The -C option is equivalent to -o noclobber. Files are + created with O_EXCL when -C is on. + + h. The following changes have been made to [[...]]: + 1. A string by itself is equivalent to -n string. + 2. -e has been added as equivalent to -a. + 3. == has been added as equivalent =. + 4. -a and = are now considered obsolete. + 5. Arithmetic comparisons are now considered obsolete. + + i. kill has been changed as follows: + 1. Signal names can be upper case or lower case. + 2. Numerical arguments to kill -l cause the given signal names to + be displayed. + 3. String arguments to kill -l cause the given signal numbers to + be displayed. + 4. Synopsis changed for getopts conformance. + + j. print has a -f format option which is equivalent to + the IEEE POSIX printf. Both print -f format, and + printf have the following extensions from IEEE POSIX: + 1. Floating point formats are supported. + 2. Size and precision specifications can be *. + 3. The %d option can take an argument after precision to + specify the base that the number will be displayed. + 4. A %q format can be used to output a string quoted so + that it can be re-input to the shell. + 5. A %P format can be used to output the shell pattern which + corresponds to the give extended regular expression. + 6. For numerical fields, the arguments can be arithmetic + expressions which will be evaluated. + 7. The %n format works as described in ANSI-C. + + k. The following changes have been made to fc: + 1. It has been renamed hist. fc is now a predefined alias. + 2. hist uses ${HISTEDIT:-$FCEDIT}. FCEDIT is obsolete. + 3. A new -s option is equivalent to the obsolete -e -. + 4. If the first argument refers to a command earlier than the + first accessible command, it now implies the first accessible + command, so that hist -l 1 lists all accessible history commands. + + l. The dot command (.) has changed as follows: + 1. The argument can be the name of a function declared as + function name. The function will execute without creating a + new scope. + 2. If there are arguments to the given script or function, + the positional parameters are restored to their original + value when . completes. + + m. The read built-in has been changed as follows: + 1. A -A option to read has been added to allow the fields to be + read into an indexed array. + 2. A -t n option has been added which causes read to + timeout after n seconds when reading from a slow device. + 3. A -d char option has been added which causes the read + to terminate at char rather than at new-line. + + n. The trap command has been changed as follows: + 1. Trap names can be either upper case or lower case. + 2. Trap -p cause only the specified trap values to be displayed. + 3. The value of trap in a subshell will be the value in the parent + shell until a call to trap which changes the trap settings has + been made. Thus, savetraps=$(trap) works as required by the + POSIX standard. + + o. The exec command has been extended as follows: + 1. The -c option clears the environment first. + 2. The -a name option sets argv[0] to name for the program. + + p. true and false are built-ins, not aliases to built-ins. + + q. test has been modified to conform to the IEEE-POSIX 1003.2 + standard when there are three or less arguments. + + r. umask -S option displays the mask in a symbolic format. + + s. wait now returns the correct exit status of any previous + background job that has not been waited for, not just + the most recent one. + + t. The whence built-in has an option -a which causes all + uses for the given command name to be reported. + + u. unalias has -a option to clear all the aliases. + + v. The times built-in command has been removed. The time + reserved word, without a command, gives time cumulative + time for the shell and its children. A built-in alias + for times should enable scripts using times to continue + to run. + + w. Command substitution and arithmetic substitution will now be + performed for PS1, ENV, and PS4 evaluation in addition to + parameter expansion. + + x. The SECONDS variable now displays elapsed time in floating + point seconds with 3 places after the decimal point by + default. + + y. The getopts built-in now handles the complete libast optget + functionality. If any errors have occurred with getopts + when it has reached the end of arguments, then the Usage + message will be generated from the option string and the + exit status from getopts will be 2 rather than 1. The + usage message will be stored in the OPTARG variable if + the option string contains a leading colon; otherwise + it will be printed on standard error automatically. + + z. THE ENV file is only processed for interactive shell + invocations. In addition, the -x attributes for + aliases and functions is ignored. + + aa. The built-in edit modes have been changed as follows: + 1. The pathname completion and pathname listing options + now perform command completion and command listing + when applied to a word in the command position. + 2. In emacs mode ^N as the first related command after + the prompt will move to the next command relative to the + last known history position. + 3. In emacs mode, successive kill and delete commands will + accumulate their data in the kill buffer, by appending or + prepending as appropriate. This mode will be reset by any + command not adding something to the kill buffer. + 4. The control-T of emacs mode has been changed to behave like + control-T in gnu-emacs. + bb. The TMOUT variable also sets a limit for select timeouts + and default timeouts for read. + + +4. The source code has undergone significant modification. + a. Much of the code has been rewritten, In many cases this has + resulted in significant performance improvement. + + b. The code is organized differently. See the README files + for more details. + + c. Most configuration parameters now get generated using + the FEATURE mechanism of nmake. Other options are set + in the OPTIONS file. + + c. The are several new compile time options. See the README + file for details. Some of the old ones have been removed. + + d. The install script is a Mamfile that is generated by + nmake and processed by a script that comes with the + distribution. + + e. There are far fewer global names. This should make it + must easier to add built-in commands without worrying + about conflicts. + + f. The code uses the sfio library which makes it possible + to mix with stdio. + + g. The code is written in ANSI C with full prototypes. + The code is based on the IEEE POSIX 1003.1 standard. + The code can be compiled with K&R C and with C++ by + using the ANSI cpp that comes with nmake or running + the code through the proto filter before pre-processing. + This happens automatically with our shipping system. + + h. There is a programming interface for capturing references + and assignment to shell variables. It is also possible + to intercept variable creation and supply the array processing + function for that variable. See nval.3 for a description. diff --git a/usr/src/lib/libshell/common/RELEASE93 b/usr/src/lib/libshell/common/RELEASE93 new file mode 100644 index 0000000000..e99c8781c6 --- /dev/null +++ b/usr/src/lib/libshell/common/RELEASE93 @@ -0,0 +1,455 @@ +This is a list of changes that have been made since the 12/28/93 version +of ksh. + +1. New features in 12/28/93b + a. If IFS contains two consecutive identical characters belonging + to the [:space:] class, then this character is treated as + a non-space delimiter so that each instance will delimit + a field. For example, IFS=$'\t\t' will cause two consecutive + tabs to delimit a null field. + b. The getopts command has a -a name option that specifies a + name that will be used for usage messages. + +2. New features in 12/28/93e + a. The math functions, atan2, hypot, fmod, and pow were added. + b. When a shared library is loaded, if the function lib_init() + is defined in the library, it is invoked the first time that + the library is loaded with builtin -f library. + +3. New features in 12/28/93f + a. Hostnames in addition to host addresses can be given in + /dev/tcp/host/port virtual file names. + b. File name completion and expansion now quotes special + characters in file names from both emacs and vi edit modes. + +4. New features in 12/28/93g + a. The pipefail option has been added. With pipefail + enabled, a pipeline will not complete until all + commands are complete, and the return value will + be that of the last command to fail, or zero if + all complete successfully. + b. When an executable is found on a given path, + the appropriate library path variable is prepended + with a corresponding library directory. +5. New features in 12/28/93h + a. The PATH search algorithm has been modified to look + for a file named .fpath in each bin directory and if + found, to search for functions in this directory if + it cannot find the command in that directory. + b. When performing pathname expansion, the shell checks + to see whether each directory it reads is case sensitive + or not, and performs the matching accordingly. + c. The %T format for printing formatted date/time. +6. New features in 12/28/93i + a. Most of the built-in commands and ksh itself are now + self documenting. Running command --man will produce + screen output. Running command --html produces the + man page in html format. + b. The getopts builtin can process command description + strings to produce man pages. + +7. Bugs fixed in 12/28/93a for default OPTIONS + a. An expansion bug which causes portions of a word after + a $((...)) expansion that contains a nested $var expansion + to be lost has been fixed. + b. A bug that caused a core dump when a script that did not + have PWD set and did a cd inside command substitution + has been fixed. + c. A bug which caused a core dump on some machines when + the LANG variable was assigned to has been fixed. + d. A bug which incorrectly handled set disciplines that + performed arithmetic evaluation when the discipline + was called from the arithmetic evaluator has been fixed. + e. A bug caused by an EXIT trap inside a function that + was executed in a subshell was fixed. + f. If foo is a function, and not a program, then command foo + now reports that foo isn't found rather than invoking foo. + g. The previous version incorrectly listed -A as an + invocation option. The -A option is only for set. + h. A bug was fixed which caused ksh to loop when execution trace + was enabled and the PS4 prompt required command substitution. + i. A bug which could cause the job control switch character + to be disabled when a script that enabled monitor mode + terminated was fixed. + j. A bug in the macro expansion global replacement operator //, + when the pattern began with a [ or +( has been fixed. + k. A bug which prevented ~ expansion from occurring when + it was terminated with a colon inside an assignment + has been fixed. + l. A bug in the dot command which prevented autoload functions + from working has been fixed. + m. A bug which caused a variable to be unset if the + its value were expanded inside a set discipline has + been fixed. + n. Whence -a now longer reports that a defined function + is undefined. + o. A bug on some systems in which $0 would be incorrect + in scripts invoked by name has been fixed. + p. Here documents with an empty body now work. + 1. A bug which disabled argument passing and resetting + of options for a script invoked by name inside a + function has been fixed. + r. A bug in which an EXIT trap set the caller of a function + would be executed if a command called inside a function + was not found has been fixed. + s. A bug which allowed a script to trap signals that are + ignored at the time that the shell was invoked has + been fixed. + t. A bug which caused 2<&1- when applied to a shell built-in + to leave standard input closed has been fixed. + u. A bug which caused the shell to incorrectly parse + $() command substitutions with nested case statements + has been fixed. + +8. Bugs fixed in 12/28/93b for default OPTIONS + a. A bug which caused unset RANDOM to dump core has been + fixed. + b. A bug which prevented return for terminating a profile + or ENV file has been fixed. + c. A bug which prevented standard input from being + directed to /dev/null for background jobs when + monitor mode was turned off has been fixed. + d. Statements of the form typeset -options var[expr]=value + did not perform substitutions on expr as expected. + e. A bug which prevented the shell from sending a HUP + signal to some background jobs that were not disowned + has been fixed. + f. A bug which allowed a script to trap signals that are + ignored at the time that the shell was invoked by exec + has been fixed. + g. A bug which could cause a core dump when a discipline + function was unset within a discipline was fixed. + h. The typeset builtin now accepts a first argument of + + or - for compatibility with ksh88. + i. For compatibility with ksh88, the results of expansions + of command arguments will treat the extended character + match characters ()|& as ordinary characters. + j. A bug which caused read to fail on a file that was + open for read/write with <> when the first operation + was print or printf has been fixed. + k. When a job is suspended, it is put on the top of + the job list as required by the POSIX standard. + l. The value of OPTARG when an option that required + an argument but didn't have one was incorrect in the + case the the option string began with a :. + m. A bug which caused the terminal to get into a bad + state with some KEYBD traps in vi-mode has been fixed. + n. A bug which caused an invalid trap to cause a script + to terminate, rather than just return an error, has + been fixed. + o. Backreferencing sub-expressions in patterns and replacement + strings now works. + p. A bug in chmod which caused the -R option to fail has + been fixed. + +9. Bugs fixed in 12/28/93c for default OPTIONS + a. The expansion of "$@" was incorrect when $1 was the null + string. + b. A bug which could incorrectly report a syntax error in + a backquoted expression when a $ was preceded by \\ + has been fixed. + c. A bug which prevented the shell from exiting after + reporting an error when failing to open a script + has been fixed. + d. A bug that could lead to memory corruption when a + large here document that required parameter or command + substitution was expanded has been fixed. + e. A bug that could cause a core dump on some systems + after ksh detected an error when reading a function + has been fixed. + f. A bug which could cause a coprocess to hang when + reading from a process that has terminated has been fixed. + g. A bug which caused a script to terminate when set -e + was on and the first command of and && or || list + failed has been fixed. + h. A bug with here documents inside $(...) when the delimiter + word is an identifier has been fixed. + i. A bug which caused $0 to display the wrong value when + a script was invoked as an argument to the . command + and the eval command has been fixed. + j. A bug that could cause the built-in sleep to hang + has been fixed. + k. A bug introduces in 12/28/93b which caused the backslash + to be removed when it was followed by digit inside double + quotes in some instances has been fixed. + l. A bug which could cause a core dump if ksh was invoked with + standard input closed has been fixed. + m. A bug which could cause a core dump if typeset -A was + specified for an existing variable has been fixed. + n. Variables that were unset but had attributes such as readonly + and export were not listed with readonly, export and typeset. + o. Several problems with signals have been fixed. + p. A bug which prevented ulimit -t from working has been fixed. + Also, a bug in which failed ulimits could cause a core dump + has also been fixed. + q. A bug in expansion of the form ${name/#pattern/string} and + ${name/%pattern/string} has been fixed. + r. A bug which caused read -r on a line that contained only + blanks to get a non-null value has been fixed. + s. A bug introduced in the 'a' point release in which + ${x='\\'} expanded to \ when x was unset has been fixed. + t. A bug which prevented a trap on EXIT from being executed + when the last command in a script was a function invocation + has been fixed. + u. A bug which caused an interactive shell ignore input when + standard error was redirected to a file with exec, + and then restored with exec 2>&1 has been fixed. + v. An interactive shell turns on monitor mode even when + standard error has been redirected to a file. + w. A bug which could cause standard input to be incorrectly + positioned for the last command of a script has been fixed. + y. A bug in the edit modes which allowed walking back in + the history file for more than HISTSIZE commands has + beed fixed. + z. A bug which could cause a core dump if variable TMPDIR was + changed between two command substitutions has been fixed. + aa. A bug which prevented a trap on EXIT from being cleared + has been fixed. + +10. Bugs fixed in 12/28/93d for default OPTIONS + a. The \ character was not handled correctly in replacement + patterns with ${x/pattern/replace}. + b. A bug with read in which the line did not end with + a new-line has been fixed. + c. A bug in file name generation which sometimes + appended a . for filenames that ended in / has + been fixed. + d. If a process is waited for after a status has + been returned by a previous wait, wait now + returns 127. + e. A bug with hist (fc) -e which prevented a command + to re-executed after it had been edited has been fixed. + f. A bug which prevented quoting from removing the meaning + of unary test operators has been fixed. + +11. Bugs fixed in 12/28/93e for default OPTIONS + a. Empty command substitutions of the form $() now work. + b. whence -v foo now gives the correct result after calling + builtin -d foo. + c. A bug in right to left arithmetic assignment for which + the arithmetic expression (( y = x = 1.5 )) did not + yield 1 for y when x was declared typeset -i was fixed. + d. printf has been fixed to handle format containing \0 + and/or \0145 correctly. In addition, characters following + %b in the format string are no longer displayed when + the operand contains \c. + e. A bug in printf that could cause the %E format to + produce unnormalized results has been fixed. + f. A bug which causes some arithmetic expressions to be + incorrectly evaluated as integer expressions rather + that floating point has been fixed. + g. Functions defined inside a subshell no longer remain + defined when the subshell completes. + h. The error message from sh -c ';echo foo' has been + corrected. + i. The format for umask -S has been changed to agree + with the specification in the POSIX standard. + j. A bug that caused side effects in subscript evaluation + when tracing was enabled for subscripts using ++ or -- + has been fixed. + k. To conform to the Posix standard getopts has been changed + so that the option char is set to ? when it returns with + a non-zero exit status. + l. The handling of \} inside ${name...} has been fixed so + that the \ quotes the }. + m. A bug that caused the read builtin to resume execution + after processing a trap has been fixed. + n. [[ -s file ]] has been fixed so that if file is open + by ksh, it is flushed first. + o. In some cases attributes and sizes for non exported + variables weren't being reset before running a script. + p. The value of TMOUT was affected by changes make to + it in a subshell. + q. The jobs command did not reflect changes make by + sending the CONT signal to a command. + r. The error message for ksh -o unknown was incorrect. + s. Functions invoked as name=value name, did not use + values from the calling scope when evaluating value. + t. A bug in which the shell would reexecute previously + executed code when a shell script or coprocess was + run in the background has been fixed. + u. A bug in which an empty here-document would leave + a file descriptor open has been fixed. + v. A bug in which $(set -A array ...) would leave a + side effect has been fixed. + w. A discipline function for a global variable defined + within a function defined with the function keyword, + incorrectly created a local variable of the same name + and applied the discipline to it. + +12. Bugs fixed in 12/28/93f for default OPTIONS + a. A bug which would cause the secondary prompt to be + displayed when a user entered a literal carriage + return has been fixed. + b. I bug which caused ksh read -s name to core dump was + fixed. + c. I bug with the expansion of \} and \] inside double + quoted strings that also contained variable expansions + has been fixed + d. Changes in the 'e' point release caused autoload + functions invoked from within command substitution + to fail. This has been fixed. + e. A bug in the processing of here-documents that could + prevent variable substitution to occur after $(...) command + substitution for long here documents has been fixed. + f. A bug caused by a race condition that could cause SIGTERM + to be ignored by a child process has been fixed. + g. A bug which prevented the startup of a coprocess immediately + after killing a running coprocess has been fixed. + h. ulimit foobar, where foobar is not an arithmetic + expression, now gives an error message as it did with ksh88 + instead of setting the file size limit to 0. + i. A bug which could cause an interactive shell to terminate when + the last process of a pipeline was a POSIX function was fixed. + j. A bug which could cause command substitution of a shell script + to core dump has been fixed. + k. A security hole was fixed in suid_exec. + l. Arithmetic functions such as pow() that take more than + one argument, did not work if arguments other than the + first contained parenthesized sub-expression. + m. The error message from a script containing an incomplete + arithmetic expression has been corrected. + n. A bug which caused a core dump on some machines when + the value of a name reference contained a positional + parameter and the name reference was not defined inside + a function has been fixed. + o. Arithmetic expressions now correctly handle hexidecimal + constants. + p. A bug in which integer variables could be expanded + with a leading 10# when declared with typeset -i + multiple times has been corrected. + q. A bug in which IFS wasn't correctly restored when + set within command substitution has been fixed. + r. The _ character is now considered as part of a word + with the M-f and M-b emacs directives as it was in ksh88. + +13. Bugs fixed in 12/28/93g for default OPTIONS + a. A bug in which a name reference could be created to + itself and later cause the shell to get into an infinite + loop has been fixed. + b. A bug in shcomp relating to compound variables was fixed. + c. A bug introduced in 'e' in which leading 0's in -Z + fields caused the value to be treated as octal for arithmetic + evaluation has been fixed. + d. A bug when a name reference with a shorter name than + the variable it references was the subject of a compound + assignment has been fixed. + e. A bug which in which assignment to array variables in + a subshell could effect the parent shell has been + fixed. + f. read name?prompt was putting a 0 byte at the end of the + prompt on standard error. + g. A bug in [[ string1 > string2 ]] when ksh was run with -x + has been fixed. + k. A bug in which the escape character was not processed + correctly inside {...} when brace expansion is enabled + has been fixed, for example {\$foo}. + l. A bug in line continuation in here-documents has been + fixed. + m. The default base when not specified with typeset -i is + 10 in accordance with the documentation. Previously, + the value was determined by the first assignment. + n. A parsing bug in which a # preceded alphanumeric + characters inside a command substitution caused + a syntax error to be reported has been fixed. + o. A bug in which a decimal constant represented as 10#ddd + where ddd was more than five digits generated a syntax + error has been fixed. + p. A bug in here document expansion in which ${...} expansions + were split across buffer boundaries has been fixed. + +14. Bugs fixed in 12/28/93h for default OPTIONS + a. I bug in shcomp for compilation of unary operators with [[...]] + has been fixed. + b. A bug in which the value of $? was changed when executing + a keyboard trap has been fixed. + c. The handling of SIGCHLD has been changed so that the + trap is not triggered while executing trap commands + to avoid recursive trap calls. + d. I bug in which a local variable in a function declared readonly + would generated an error when the function went out of + scope has been fixed. + e. I bug in which \ entered from the keyboard + with the KEYBD trap enabled has been fixed. + f. The error message for a misplaced ((, for example print ((3), + was often garbled and has been fixed. + g. I bug in the KEYBD trap in which escape sequences of the form + [#~ were not being handled as a unit has been fixed. + h. A bug in which ksh would consider expressions like [[ (a) ]] + as syntax errors has been fixed. + i. A function defined as foo() without a function body + was not reported as a syntax error. + j. A bug in which ksh could run out of file descriptors when + a stream was repeatedly opened with exec and read from + has been fixed. + k. A bug introduced when fixing item n from the 'g' point + release has been fixed. + +15. Bugs fixed in 12/28/93i for default OPTIONS + a. A bug in which a script could terminate when getopts + encountered an error when invoked inside a function + has been fixed. + b. When a symbolic link was specified as the name of + the script to invoke by name, the value of $0 was + set to the real file name rather than the link name + in some cases and this has been fixed. + +16. Bug fixes for specific non-default option combinations. + a. More signal names have been added for Solaris + b. A bug fixed for the v directive in vi MULTIBYTE has been + fixed. + c. Code to for IFS handling of multibyte characters has + been added. + d. The displaying of multibyte strings in export, readonly, + typeset, and execution traces has been fixed. + e. A bug with type ahead and KEYBOARD traps with the + MULTIBYTE option set has been fixed. + f. The k-shell information abstraction database option, KIA, + has been revamped for the 'e' point release. + g. A bug in brace pattern expansions that caused expressions + such as {foo\,bar,bam} to expand incorrectly have been fixed. + h. On the U/WIN version for Window 95 and Windows NT, + when a directory beginning with a letter followed by + a colon is given to cd, it is assumed to be an absolute + directory. + i. There was a bug in the compile option that does not + use fork() in which the current option settings where + not propagated to sub-shells. + j. A bug in setting .sh.editchar during the KEYBD trap + for the MULTIBYTE option was fixed in release 'h'. + k. A bug in which the precision given as an argument + to printf was not working has been fixed. + +17. Other changes to 12/28/93[abcdefghi] + a. A couple of minor changes to make adding built-ins easier. + b. Variables inside functions are now statically scoped. + The previous behavior was never documented. + c. A few changes have been made to the name-value library + that affect built-ins that use disciplines. The + changes allow disciplines to be shared by variables + and should make it possible to add new disciplines + without recompilation. + d. The name-value library interface has undergone significant + change for this revision. See the new nval.3 man page. + e. Builtin functions can take a third argument which is + a void*. + f. The nv_scan() function can restrict the scope of a walk + to the top scope. Starting in 'f', nv_scan() has an + additional pointer argument that is passed to each invoked + function. + g. Starting with release 'f', an empty for list behave like + a for list with null expansions. It produces a warning + message with sh -n. + h. Starting with release 'f' the code has been modified to + work with EBCDIC as well as ASCII. + i. Starting with the release 'g', the name-value pair library + uses the cdt library rather than the hash library. + j. The sh_fun() function now takes third argument which + is an argument list for the invoked discipline function + or built-in. + k. A callback function can be installed which will give + notification of file duplications and file closes. + +18. Incompatibilities with 12/28/93 version. + None intentional. + diff --git a/usr/src/lib/libshell/common/bltins/alarm.c b/usr/src/lib/libshell/common/bltins/alarm.c new file mode 100644 index 0000000000..6f4aa2f644 --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/alarm.c @@ -0,0 +1,276 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped +/* + * alarm [-r] [varname [+]when] + * + * David Korn + * AT&T Labs + * + */ + +#include "defs.h" +#include +#include +#include "builtins.h" +#include "FEATURE/time" + +#define R_FLAG 1 +#define L_FLAG 2 + +struct tevent +{ + Namfun_t fun; + Namval_t *node; + Namval_t *action; + struct tevent *next; + long milli; + int flags; + void *timeout; + Shell_t *sh; +}; + +static const char ALARM[] = "alarm"; + +static void trap_timeout(void*); + +/* + * insert timeout item on current given list in sorted order + */ +static void *time_add(struct tevent *item, void *list) +{ + register struct tevent *tp = (struct tevent*)list; + if(!tp || item->milli < tp->milli) + { + item->next = tp; + list = (void*)item; + } + else + { + while(tp->next && item->milli > tp->next->milli) + tp = tp->next; + item->next = tp->next; + tp->next = item; + } + tp = item; + tp->timeout = (void*)sh_timeradd(tp->milli,tp->flags&R_FLAG,trap_timeout,(void*)tp); + return(list); +} + +/* + * delete timeout item from current given list, delete timer + */ +static void *time_delete(register struct tevent *item, void *list) +{ + register struct tevent *tp = (struct tevent*)list; + if(item==tp) + list = (void*)tp->next; + else + { + while(tp && tp->next != item) + tp = tp->next; + if(tp) + tp->next = item->next; + } + if(item->timeout) + timerdel((void*)item->timeout); + return(list); +} + +static void print_alarms(void *list) +{ + register struct tevent *tp = (struct tevent*)list; + while(tp) + { + if(tp->timeout) + { + register char *name = nv_name(tp->node); + if(tp->flags&R_FLAG) + { + double d = tp->milli; + sfprintf(sfstdout,e_alrm1,name,d/1000.); + } + else + sfprintf(sfstdout,e_alrm2,name,nv_getnum(tp->node)); + } + tp = tp->next; + } +} + +static void trap_timeout(void* handle) +{ + register struct tevent *tp = (struct tevent*)handle; + tp->sh->trapnote |= SH_SIGALRM; + if(!(tp->flags&R_FLAG)) + tp->timeout = 0; + tp->flags |= L_FLAG; + tp->sh->sigflag[SIGALRM] |= SH_SIGALRM; + if(sh_isstate(SH_TTYWAIT)) + sh_timetraps(); +} + +void sh_timetraps(void) +{ + register struct tevent *tp, *tpnext; + register struct tevent *tptop; + while(1) + { + sh.sigflag[SIGALRM] &= ~SH_SIGALRM; + tptop= (struct tevent*)sh.st.timetrap; + for(tp=tptop;tp;tp=tpnext) + { + tpnext = tp->next; + if(tp->flags&L_FLAG) + { + tp->flags &= ~L_FLAG; + if(tp->action) + sh_fun(tp->action,tp->node,(char**)0); + tp->flags &= ~L_FLAG; + if(!tp->flags) + { + nv_unset(tp->node); + nv_close(tp->node); + } + } + } + if(!(sh.sigflag[SIGALRM]&SH_SIGALRM)) + break; + } +} + + +/* + * This trap function catches "alarm" actions only + */ +static char *setdisc(Namval_t *np, const char *event, Namval_t* action, Namfun_t + *fp) +{ + register struct tevent *tp = (struct tevent*)fp; + if(!event) + return(action?"":(char*)ALARM); + if(strcmp(event,ALARM)!=0) + { + /* try the next level */ + return(nv_setdisc(np, event, action, fp)); + } + if(action==np) + action = tp->action; + else + tp->action = action; + return(action?(char*)action:""); +} + +/* + * catch assignments and set alarm traps + */ +static void putval(Namval_t* np, const char* val, int flag, Namfun_t* fp) +{ + register struct tevent *tp; + register double d; + if(val) + { + double now; +#ifdef timeofday + struct timeval tmp; + timeofday(&tmp); + now = tmp.tv_sec + 1.e-6*tmp.tv_usec; +#else + now = (double)time(NIL(time_t*)); +#endif /* timeofday */ + nv_putv(np,val,flag,fp); + d = nv_getnum(np); + tp = (struct tevent*)fp; + if(*val=='+') + { + double x = d + now; + nv_putv(np,(char*)&x,NV_INTEGER,fp); + } + else + d -= now; + tp->milli = 1000*(d+.0005); + if(tp->timeout) + sh.st.timetrap = time_delete(tp,sh.st.timetrap); + if(tp->milli > 0) + sh.st.timetrap = time_add(tp,sh.st.timetrap); + } + else + { + tp = (struct tevent*)nv_stack(np, (Namfun_t*)0); + sh.st.timetrap = time_delete(tp,sh.st.timetrap); + if(tp->action) + nv_close(tp->action); + nv_unset(np); + free((void*)fp); + } +} + +static const Namdisc_t alarmdisc = +{ + sizeof(struct tevent), + putval, + 0, + 0, + setdisc, +}; + +int b_alarm(int argc,char *argv[],void *extra) +{ + register int n,rflag=0; + register Namval_t *np; + register struct tevent *tp; + register Shell_t *shp = (Shell_t*)extra; + while (n = optget(argv, sh_optalarm)) switch (n) + { + case 'r': + rflag = R_FLAG; + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); + break; + } + argc -= opt_info.index; + argv += opt_info.index; + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0)); + if(argc==0) + { + print_alarms(shp->st.timetrap); + return(0); + } + if(argc!=2) + errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0)); + np = nv_open(argv[0],shp->var_tree,NV_NOARRAY|NV_VARNAME|NV_NOASSIGN); + if(!nv_isnull(np)) + nv_unset(np); + nv_setattr(np, NV_INTEGER|NV_DOUBLE); + if(!(tp = newof(NIL(struct tevent*),struct tevent,1,0))) + errormsg(SH_DICT,ERROR_exit(1),e_nospace); + tp->fun.disc = &alarmdisc; + tp->flags = rflag; + tp->node = np; + tp->sh = shp; + nv_stack(np,(Namfun_t*)tp); + nv_putval(np, argv[1], 0); + return(0); +} + diff --git a/usr/src/lib/libshell/common/bltins/cd_pwd.c b/usr/src/lib/libshell/common/bltins/cd_pwd.c new file mode 100644 index 0000000000..f57f7c977e --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/cd_pwd.c @@ -0,0 +1,280 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped +/* + * cd [-LP] [dirname] + * cd [-LP] [old] [new] + * pwd [-LP] + * + * David Korn + * AT&T Labs + * research!dgk + * + */ + +#include "defs.h" +#include +#include +#include "variables.h" +#include "path.h" +#include "name.h" +#include "builtins.h" +#include +#include + +#ifdef PATH_BFPATH +/* + * Invalidate path name bindings to relative paths + */ +static void rehash(register Namval_t *np,void *data) +{ + Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp; + NOT_USED(data); + if(pp && *pp->name!='/') + nv_unset(np); +} +#endif + +int b_cd(int argc, char *argv[],void *extra) +{ +#ifdef PATH_BFPATH + register char *dir; + Pathcomp_t *cdpath = 0; +#else + register char *dir, *cdpath=""; +#endif + register const char *dp; + register Shell_t *shp = (Shell_t*)extra; + int saverrno=0; + int rval,flag=0; + char *oldpwd; + Namval_t *opwdnod, *pwdnod; + if(sh_isoption(SH_RESTRICTED)) + errormsg(SH_DICT,ERROR_exit(1),e_restricted+4); + while((rval = optget(argv,sh_optcd))) switch(rval) + { + case 'L': + flag = 0; + break; + case 'P': + flag = 1; + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); + break; + } + argv += opt_info.index; + argc -= opt_info.index; + dir = argv[0]; + if(error_info.errors>0 || argc >2) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + oldpwd = (char*)shp->pwd; + opwdnod = (shp->subshell?sh_assignok(OLDPWDNOD,1):OLDPWDNOD); + pwdnod = (shp->subshell?sh_assignok(PWDNOD,1):PWDNOD); + if(argc==2) + dir = sh_substitute(oldpwd,dir,argv[1]); + else if(!dir || *dir==0) + dir = nv_getval(HOME); + else if(*dir == '-' && dir[1]==0) + dir = nv_getval(opwdnod); + if(!dir || *dir==0) + errormsg(SH_DICT,ERROR_exit(1),argc==2?e_subst+4:e_direct); +#if _WINIX + if(*dir != '/' && (dir[1]!=':')) +#else + if(*dir != '/') +#endif /* _WINIX */ + { +#ifdef PATH_BFPATH + if(!(cdpath = (Pathcomp_t*)shp->cdpathlist) && (dp=(CDPNOD)->nvalue.cp)) + { + if(cdpath=path_addpath((Pathcomp_t*)0,dp,PATH_CDPATH)) + { + shp->cdpathlist = (void*)cdpath; + cdpath->shp = shp; + } + } +#else + cdpath = nv_getval(nv_scoped(CDPNOD)); +#endif + if(!oldpwd) + oldpwd = path_pwd(1); + } +#ifndef PATH_BFPATH + if(!cdpath) + cdpath = ""; +#endif + if(*dir=='.') + { + /* test for pathname . ./ .. or ../ */ + if(*(dp=dir+1) == '.') + dp++; + if(*dp==0 || *dp=='/') +#ifdef PATH_BFPATH + cdpath = 0; +#else + cdpath = ""; +#endif + } + rval = -1; + do + { +#ifdef PATH_BFPATH + dp = cdpath?cdpath->name:""; + cdpath = path_nextcomp(cdpath,dir,0); +#else + dp = cdpath; + cdpath=path_join(cdpath,dir); +#endif +#if _WINIX + if(*stakptr(PATH_OFFSET+1)==':' && isalpha(*stakptr(PATH_OFFSET))) + { + *stakptr(PATH_OFFSET+1) = *stakptr(PATH_OFFSET); + *stakptr(PATH_OFFSET)='/'; + } +#endif /* _WINIX */ + if(*stakptr(PATH_OFFSET)!='/') + + { + char *last=(char*)stakfreeze(1); + stakseek(PATH_OFFSET); + stakputs(oldpwd); + /* don't add '/' of oldpwd is / itself */ + if(*oldpwd!='/' || oldpwd[1]) + stakputc('/'); + stakputs(last+PATH_OFFSET); + stakputc(0); + } + if(!flag) + { + register char *cp; + stakseek(PATH_MAX+PATH_OFFSET); +#if SHOPT_FS_3D + if(!(cp = pathcanon(stakptr(PATH_OFFSET),PATH_DOTDOT))) + continue; + /* eliminate trailing '/' */ + while(*--cp == '/' && cp>stakptr(PATH_OFFSET)) + *cp = 0; +#else + if(*(cp=stakptr(PATH_OFFSET))=='/') + if(!pathcanon(cp,PATH_DOTDOT)) + continue; +#endif /* SHOPT_FS_3D */ + } + if((rval=chdir(path_relative(stakptr(PATH_OFFSET)))) >= 0) + goto success; + if(errno!=ENOENT && saverrno==0) + saverrno=errno; + } + while(cdpath); + if(rval<0 && *dir=='/' && *(path_relative(stakptr(PATH_OFFSET)))!='/') + rval = chdir(dir); + /* use absolute chdir() if relative chdir() fails */ + if(rval<0) + { + if(saverrno) + errno = saverrno; + errormsg(SH_DICT,ERROR_system(1),"%s:",dir); + } +success: + if(dir == nv_getval(opwdnod) || argc==2) + dp = dir; /* print out directory for cd - */ + if(flag) + { + dir = stakptr(PATH_OFFSET); + if (!(dir=pathcanon(dir,PATH_PHYSICAL))) + { + dir = stakptr(PATH_OFFSET); + errormsg(SH_DICT,ERROR_system(1),"%s:",dir); + } + stakseek(dir-stakptr(0)); + } + dir = (char*)stakfreeze(1)+PATH_OFFSET; +#ifdef PATH_BFPATH + if(*dp && (*dp!='.'||dp[1]) && strchr(dir,'/')) +#else + if(*dp && *dp!= ':' && strchr(dir,'/')) +#endif + sfputr(sfstdout,dir,'\n'); + if(*dir != '/') + return(0); + nv_putval(opwdnod,oldpwd,NV_RDONLY); + if(oldpwd) + free(oldpwd); + flag = strlen(dir); + /* delete trailing '/' */ + while(--flag>0 && dir[flag]=='/') + dir[flag] = 0; + nv_putval(pwdnod,dir,NV_RDONLY); + nv_onattr(pwdnod,NV_NOFREE|NV_EXPORT); + shp->pwd = pwdnod->nvalue.cp; +#ifdef PATH_BFPATH + nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED); + path_newdir(shp->pathlist); + path_newdir(shp->cdpathlist); +#endif + return(0); +} + +int b_pwd(int argc, char *argv[],void *extra) +{ + register int n, flag = 0; + register char *cp; + register Shell_t *shp = (Shell_t*)extra; + NOT_USED(argc); + while((n = optget(argv,sh_optpwd))) switch(n) + { + case 'L': + flag = 0; + break; + case 'P': + flag = 1; + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); + break; + } + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + if(*(cp = path_pwd(0)) != '/') + errormsg(SH_DICT,ERROR_system(1), e_pwd); + if(flag) + { +#if SHOPT_FS_3D + if(shp->lim.fs3d && (flag = mount(e_dot,NIL(char*),FS3D_GET|FS3D_VIEW,0))>=0) + { + cp = (char*)stakseek(++flag+PATH_MAX); + mount(e_dot,cp,FS3D_GET|FS3D_VIEW|FS3D_SIZE(flag),0); + } + else +#endif /* SHOPT_FS_3D */ + cp = strcpy(stakseek(strlen(cp)+PATH_MAX),cp); + pathcanon(cp,PATH_PHYSICAL); + } + sfputr(sfstdout,cp,'\n'); + return(0); +} + diff --git a/usr/src/lib/libshell/common/bltins/cflow.c b/usr/src/lib/libshell/common/bltins/cflow.c new file mode 100644 index 0000000000..3f32f4386d --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/cflow.c @@ -0,0 +1,118 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped +/* + * break [n] + * continue [n] + * return [n] + * exit [n] + * + * David Korn + * AT&T Labs + * dgk@research.att.com + * + */ + +#include "defs.h" +#include +#include +#include +#include "shnodes.h" +#include "builtins.h" + +/* + * return and exit + */ +#if 0 + /* for the dictionary generator */ + int b_exit(int n, register char *argv[],void *extra){} +#endif +int b_return(register int n, register char *argv[],void *extra) +{ + register char *arg; + register Shell_t *shp = (Shell_t*)extra; + struct checkpt *pp = (struct checkpt*)shp->jmplist; + const char *options = (**argv=='r'?sh_optreturn:sh_optexit); + while((n = optget(argv,options))) switch(n) + { + case ':': + if(!strmatch(argv[opt_info.index],"[+-]+([0-9])")) + errormsg(SH_DICT,2, "%s", opt_info.arg); + goto done; + case '?': + errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); + return(2); + } +done: + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + pp->mode = (**argv=='e'?SH_JMPEXIT:SH_JMPFUN); + argv += opt_info.index; + n = (((arg= *argv)?(int)strtol(arg, (char**)0, 10):shp->oldexit)&SH_EXITMASK); + /* return outside of function, dotscript and profile is exit */ + if(shp->fn_depth==0 && shp->dot_depth==0 && !sh_isstate(SH_PROFILE)) + pp->mode = SH_JMPEXIT; + sh_exit(shp->savexit=n); + return(1); +} + + +/* + * break and continue + */ +#if 0 + /* for the dictionary generator */ + int b_continue(int n, register char *argv[],void *extra){} +#endif +int b_break(register int n, register char *argv[],void *extra) +{ + char *arg; + register int cont= **argv=='c'; + register Shell_t *shp = (Shell_t*)extra; + while((n = optget(argv,cont?sh_optcont:sh_optbreak))) switch(n) + { + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); + return(2); + } + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + argv += opt_info.index; + n=1; + if(arg= *argv) + { + n = strtol(arg,&arg,10); + if(n<=0 || *arg) + errormsg(SH_DICT,ERROR_exit(1),e_nolabels,*argv); + } + if(shp->st.loopcnt) + { + shp->st.execbrk = shp->st.breakcnt = n; + if(shp->st.breakcnt > shp->st.loopcnt) + shp->st.breakcnt = shp->st.loopcnt; + if(cont) + shp->st.breakcnt = -shp->st.breakcnt; + } + return(0); +} + diff --git a/usr/src/lib/libshell/common/bltins/getopts.c b/usr/src/lib/libshell/common/bltins/getopts.c new file mode 100644 index 0000000000..65057da8d2 --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/getopts.c @@ -0,0 +1,185 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped +/* + * getopts optstring name [arg...] + * + * David Korn + * AT&T Labs + * research!dgk + * + */ + +#include "defs.h" +#include "variables.h" +#include +#include +#include "builtins.h" + +static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp) +{ + if(nv_search(s,sh.fun_tree,0)) + { + int savtop = staktell(); + char *savptr = stakfreeze(0); + stakputc('$'); + stakputc('('); + stakputs(s); + stakputc(')'); + sfputr(sp,sh_mactry(stakfreeze(1)),-1); + stakset(savptr,savtop); + } + return(1); +} + +int b_getopts(int argc,char *argv[],void *extra) +{ + register char *options=error_info.context->id; + register Namval_t *np; + register int flag, mode, r=0; + register Shell_t *shp = (Shell_t*)extra; + char value[2], key[2]; + int jmpval; + struct checkpt buff, *pp; + Optdisc_t disc; + memset(&disc, 0, sizeof(disc)); + disc.version = OPT_VERSION; + disc.infof = infof; + value[1] = 0; + key[1] = 0; + while((flag = optget(argv,sh_optgetopts))) switch(flag) + { + case 'a': + options = opt_info.arg; + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); + break; + } + argv += opt_info.index; + argc -= opt_info.index; + if(error_info.errors || argc<2) + errormsg(SH_DICT,ERROR_usage(2), "%s", optusage((char*)0)); + error_info.context->flags |= ERROR_SILENT; + error_info.id = options; + options = argv[0]; + np = nv_open(argv[1],shp->var_tree,NV_NOASSIGN|NV_VARNAME); + if(argc>2) + { + argv +=1; + argc -=1; + } + else + { + argv = shp->st.dolv; + argc = shp->st.dolc; + } + opt_info.index = shp->st.optindex; + opt_info.offset = shp->st.optchar; + if(mode= (*options==':')) + options++; + sh_pushcontext(&buff,1); + jmpval = sigsetjmp(buff.buff,0); + if(jmpval) + { + sh_popcontext(&buff); + pp = (struct checkpt*)shp->jmplist; + pp->mode = SH_JMPERREXIT; + sh_exit(2); + } + opt_info.disc = &disc; + switch(opt_info.index>=0 && opt_info.index<=argc?(opt_info.num= LONG_MIN,flag=optget(argv,options)):0) + { + case '?': + if(mode==0) + errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); + opt_info.option[1] = '?'; + /* FALL THRU */ + case ':': + key[0] = opt_info.option[1]; + if(strmatch(opt_info.arg,"*unknown*")) + flag = '?'; + if(mode) + opt_info.arg = key; + else + { + errormsg(SH_DICT,2, "%s", opt_info.arg); + opt_info.arg = 0; + flag = '?'; + } + *(options = value) = flag; + shp->st.opterror = 1; + if (opt_info.offset != 0 && !argv[opt_info.index][opt_info.offset]) + { + opt_info.offset = 0; + opt_info.index++; + } + break; + case 0: + if(shp->st.opterror) + { + char *com[2]; + com[0] = "-?"; + com[1] = 0; + flag = opt_info.index; + opt_info.index = 0; + optget(com,options); + opt_info.index = flag; + if(!mode && strchr(options,' ')) + errormsg(SH_DICT,ERROR_usage(2), "%s", optusage((char*)0)); + } + opt_info.arg = 0; + options = value; + *options = '?'; + r=1; + opt_info.offset = 0; + break; + default: + options = opt_info.option + (*opt_info.option!='+'); + } + error_info.context->flags &= ~ERROR_SILENT; + shp->st.optindex = opt_info.index; + shp->st.optchar = opt_info.offset; + nv_putval(np, options, 0); + nv_close(np); + np = nv_open(nv_name(OPTARGNOD),shp->var_tree,NV_NOSCOPE); + if(opt_info.num == LONG_MIN) + nv_putval(np, opt_info.arg, NV_RDONLY); + else if (opt_info.num > 0 && opt_info.arg && opt_info.arg[0] == (char)opt_info.num) + { + key[0] = (char)opt_info.num; + key[1] = 0; + nv_putval(np, key, NV_RDONLY); + } + else + { + Sfdouble_t d; + d = opt_info.number; + nv_putval(np, (char*)&d, NV_LDOUBLE|NV_RDONLY); + } + nv_close(np); + sh_popcontext(&buff); + opt_info.disc = 0; + return(r); +} + diff --git a/usr/src/lib/libshell/common/bltins/hist.c b/usr/src/lib/libshell/common/bltins/hist.c new file mode 100644 index 0000000000..fcb81958e4 --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/hist.c @@ -0,0 +1,309 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped +#include "defs.h" +#include +#include +#include +#include +#include "variables.h" +#include "io.h" +#include "name.h" +#include "history.h" +#include "builtins.h" +#if SHOPT_HISTEXPAND +# include "edit.h" +#endif + +#define HIST_RECURSE 5 + +static void hist_subst(const char*, int fd, char*); + +#if 0 + /* for the benefit of the dictionary generator */ + int b_fc(int argc,char *argv[], void *extra){} +#endif +int b_hist(int argc,char *argv[], void *extra) +{ + register History_t *hp; + register char *arg; + register int flag,fdo; + register Shell_t *shp = (Shell_t*)extra; + Sfio_t *outfile; + char *fname; + int range[2], incr, index2, indx= -1; + char *edit = 0; /* name of editor */ + char *replace = 0; /* replace old=new */ + int lflag = 0, nflag = 0, rflag = 0; +#if SHOPT_HISTEXPAND + int pflag = 0; +#endif + Histloc_t location; + NOT_USED(argc); + if(!sh_histinit()) + errormsg(SH_DICT,ERROR_system(1),e_histopen); + hp = shp->hist_ptr; + while((flag = optget(argv,sh_opthist))) switch(flag) + { + case 'e': + edit = opt_info.arg; + break; + case 'n': + nflag++; + break; + case 'l': + lflag++; + break; + case 'r': + rflag++; + break; + case 's': + edit = "-"; + break; +#if SHOPT_HISTEXPAND + case 'p': + pflag++; + break; +#endif + case 'N': + if(indx<=0) + { + if((flag = hist_max(hp) - opt_info.num-1) < 0) + flag = 1; + range[++indx] = flag; + break; + } + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); + break; + } + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + argv += (opt_info.index-1); +#if SHOPT_HISTEXPAND + if(pflag) + { + hist_cancel(hp); + pflag = 0; + while(arg=argv[1]) + { + flag = hist_expand(arg,&replace); + if(!(flag & HIST_ERROR)) + sfputr(sfstdout, replace, '\n'); + else + pflag = 1; + if(replace) + free(replace); + argv++; + } + return pflag; + } +#endif + flag = indx; + while(flag<1 && (arg=argv[1])) + { + /* look for old=new argument */ + if(!replace && strchr(arg+1,'=')) + { + replace = arg; + argv++; + continue; + } + else if(isdigit(*arg) || *arg == '-') + { + /* see if completely numeric */ + do arg++; + while(isdigit(*arg)); + if(*arg==0) + { + arg = argv[1]; + range[++flag] = (int)strtol(arg, (char**)0, 10); + if(*arg == '-') + range[flag] += (hist_max(hp)-1); + argv++; + continue; + } + } + /* search for last line starting with string */ + location = hist_find(hp,argv[1],hist_max(hp)-1,0,-1); + if((range[++flag] = location.hist_command) < 0) + errormsg(SH_DICT,ERROR_exit(1),e_found,argv[1]); + argv++; + } + if(flag <0) + { + /* set default starting range */ + if(lflag) + { + flag = hist_max(hp)-16; + if(flag<1) + flag = 1; + } + else + flag = hist_max(hp)-2; + range[0] = flag; + flag = 0; + } + index2 = hist_min(hp); + if(range[0]=(flag=(hist_max(hp) - !lflag))) + range[1] = flag; + /* check for valid ranges */ + if(range[1]=flag) + errormsg(SH_DICT,ERROR_exit(1),e_badrange,range[0],range[1]); + if(edit && *edit=='-' && range[0]!=range[1]) + errormsg(SH_DICT,ERROR_exit(1),e_eneedsarg); + /* now list commands from range[rflag] to range[1-rflag] */ + incr = 1; + flag = rflag>0; + if(range[1-flag] < range[flag]) + incr = -1; + if(lflag) + { + outfile = sfstdout; + arg = "\n\t"; + } + else + { + if(!(fname=pathtmp(NIL(char*),0,0,NIL(int*)))) + errormsg(SH_DICT,ERROR_exit(1),e_create,""); + if((fdo=open(fname,O_CREAT|O_RDWR,S_IRUSR|S_IWUSR)) < 0) + errormsg(SH_DICT,ERROR_system(1),e_create,fname); + outfile= sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fdo,SF_WRITE); + arg = "\n"; + nflag++; + } + while(1) + { + if(nflag==0) + sfprintf(outfile,"%d\t",range[flag]); + else if(lflag) + sfputc(outfile,'\t'); + hist_list(shp->hist_ptr,outfile,hist_tell(shp->hist_ptr,range[flag]),0,arg); + if(lflag) + sh_sigcheck(); + if(range[flag] == range[1-flag]) + break; + range[flag] += incr; + } + if(lflag) + return(0); + sfclose(outfile); + hist_eof(hp); + arg = edit; + if(!arg && !(arg=nv_getval(nv_scoped(HISTEDIT))) && !(arg=nv_getval(nv_scoped(FCEDNOD)))) + arg = (char*)e_defedit; +#ifdef apollo + /* + * Code to support the FC using the pad editor. + * Exampled of how to use: HISTEDIT=pad + */ + if (strcmp (arg, "pad") == 0) + { + extern int pad_create(char*); + sh_close(fdo); + fdo = pad_create(fname); + pad_wait(fdo); + unlink(fname); + strcat(fname, ".bak"); + unlink(fname); + lseek(fdo,(off_t)0,SEEK_SET); + } + else + { +#endif /* apollo */ + if(*arg != '-') + { + char *com[3]; + com[0] = arg; + com[1] = fname; + com[2] = 0; + error_info.errors = sh_eval(sh_sfeval(com),0); + } + fdo = sh_chkopen(fname); + unlink(fname); + free((void*)fname); +#ifdef apollo + } +#endif /* apollo */ + /* don't history fc itself unless forked */ + error_info.flags |= ERROR_SILENT; + if(!sh_isstate(SH_FORKED)) + hist_cancel(hp); + sh_onstate(SH_HISTORY); + sh_onstate(SH_VERBOSE); /* echo lines as read */ + if(replace) + hist_subst(error_info.id,fdo,replace); + else if(error_info.errors == 0) + { + char buff[IOBSIZE+1]; + Sfio_t *iop = sfnew(NIL(Sfio_t*),buff,IOBSIZE,fdo,SF_READ); + /* read in and run the command */ + if(shp->hist_depth++ > HIST_RECURSE) + errormsg(SH_DICT,ERROR_exit(1),e_toodeep,"history"); + sh_eval(iop,1); + shp->hist_depth--; + } + else + { + sh_close(fdo); + if(!sh_isoption(SH_VERBOSE)) + sh_offstate(SH_VERBOSE); + sh_offstate(SH_HISTORY); + } + return(shp->exitval); +} + + +/* + * given a file containing a command and a string of the form old=new, + * execute the command with the string old replaced by new + */ + +static void hist_subst(const char *command,int fd,char *replace) +{ + register char *newp=replace; + register char *sp; + register int c; + off_t size; + char *string; + while(*++newp != '='); /* skip to '=' */ + if((size = lseek(fd,(off_t)0,SEEK_END)) < 0) + return; + lseek(fd,(off_t)0,SEEK_SET); + c = (int)size; + string = stakalloc(c+1); + if(read(fd,string,c)!=c) + return; + string[c] = 0; + *newp++ = 0; + if((sp=sh_substitute(string,replace,newp))==0) + errormsg(SH_DICT,ERROR_exit(1),e_subst,command); + *(newp-1) = '='; + sh_eval(sfopen(NIL(Sfio_t*),sp,"s"),1); +} + diff --git a/usr/src/lib/libshell/common/bltins/misc.c b/usr/src/lib/libshell/common/bltins/misc.c new file mode 100644 index 0000000000..974c3de037 --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/misc.c @@ -0,0 +1,589 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped +/* + * exec [arg...] + * eval [arg...] + * jobs [-lnp] [job...] + * login [arg...] + * let expr... + * . file [arg...] + * :, true, false + * vpath [top] [base] + * vmap [top] [base] + * wait [job...] + * shift [n] + * + * David Korn + * AT&T Labs + * + */ + +#include "defs.h" +#include "variables.h" +#include "shnodes.h" +#include "path.h" +#include "io.h" +#include "name.h" +#include "history.h" +#include "builtins.h" +#include "jobs.h" + +#define DOTMAX MAXDEPTH /* maximum level of . nesting */ + +static void noexport(Namval_t*,void*); + +struct login +{ + Shell_t *sh; + int clear; + char *arg0; +}; + +int b_exec(int argc,char *argv[], void *extra) +{ + struct login logdata; + register int n; + logdata.clear = 0; + logdata.arg0 = 0; + logdata.sh = (Shell_t*)extra; + logdata.sh->st.ioset = 0; + while (n = optget(argv, sh_optexec)) switch (n) + { + case 'a': + logdata.arg0 = opt_info.arg; + argc = 0; + break; + case 'c': + logdata.clear=1; + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); + return(2); + } + argv += opt_info.index; + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + if(*argv) + B_login(0,argv,(void*)&logdata); + return(0); +} + +static void noexport(register Namval_t* np, void *data) +{ + NOT_USED(data); + nv_offattr(np,NV_EXPORT); +} + +int B_login(int argc,char *argv[],void *extra) +{ + struct checkpt *pp; + register struct login *logp=0; + register Shell_t *shp; + const char *pname; + if(argc) + shp = (Shell_t*)extra; + else + { + logp = (struct login*)extra; + shp = logp->sh; + } + pp = (struct checkpt*)shp->jmplist; + if(sh_isoption(SH_RESTRICTED)) + errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[0]); + else + { + register struct argnod *arg=shp->envlist; + register Namval_t* np; + register char *cp; + if(shp->subshell) + sh_subfork(); + if(logp && logp->clear) + { +#ifdef _ENV_H + env_close(shp->env); + shp->env = env_open((char**)0,3); +#else + nv_scan(shp->var_tree,noexport,0,NV_EXPORT,NV_EXPORT); +#endif + } + while(arg) + { + if((cp=strchr(arg->argval,'=')) && + (*cp=0,np=nv_search(arg->argval,shp->var_tree,0))) + { + nv_onattr(np,NV_EXPORT); + sh_envput(shp->env,np); + } + if(cp) + *cp = '='; + arg=arg->argnxt.ap; + } + pname = argv[0]; + if(logp && logp->arg0) + argv[0] = logp->arg0; +#ifdef JOBS + if(job_close() < 0) + return(1); +#endif /* JOBS */ + /* force bad exec to terminate shell */ + pp->mode = SH_JMPEXIT; + sh_sigreset(2); + sh_freeup(); + path_exec(pname,argv,NIL(struct argnod*)); + sh_done(0); + } + return(1); +} + +int b_let(int argc,char *argv[],void *extra) +{ + register int r; + register char *arg; + NOT_USED(argc); + NOT_USED(extra); + while (r = optget(argv,sh_optlet)) switch (r) + { + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); + break; + } + argv += opt_info.index; + if(error_info.errors || !*argv) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + while(arg= *argv++) + r = !sh_arith(arg); + return(r); +} + +int b_eval(int argc,char *argv[], void *extra) +{ + register int r; + register Shell_t *shp = (Shell_t*)extra; + NOT_USED(argc); + while (r = optget(argv,sh_opteval)) switch (r) + { + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg); + return(2); + } + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + argv += opt_info.index; + if(*argv && **argv) + { + sh_offstate(SH_MONITOR); + sh_eval(sh_sfeval(argv),0); + } + return(shp->exitval); +} + +int b_dot_cmd(register int n,char *argv[],void* extra) +{ + register char *script; + register Namval_t *np; + register int jmpval; + register Shell_t *shp = (Shell_t*)extra; + struct sh_scoped savst, *prevscope = shp->st.self; + char *filename=0; + int fd; + struct dolnod *argsave=0, *saveargfor; + struct checkpt buff; + Sfio_t *iop=0; + NOT_USED(extra); + while (n = optget(argv,sh_optdot)) switch (n) + { + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg); + return(2); + } + argv += opt_info.index; + script = *argv; + if(error_info.errors || !script) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + if(shp->dot_depth++ > DOTMAX) + errormsg(SH_DICT,ERROR_exit(1),e_toodeep,script); + shp->st.lineno = error_info.line; + if(!(np=shp->posix_fun)) + { + /* check for KornShell style function first */ + np = nv_search(script,shp->fun_tree,0); + if(np && is_afunction(np) && !nv_isattr(np,NV_FPOSIX)) + { + if(!np->nvalue.ip) + { +#ifdef PATH_BFPATH + path_search(script,NIL(Pathcomp_t*),0); +#else + path_search(script,NIL(char*),0); +#endif + if(np->nvalue.ip) + { + if(nv_isattr(np,NV_FPOSIX)) + np = 0; + } + else + errormsg(SH_DICT,ERROR_exit(1),e_found,script); + } + } + else + np = 0; + if(!np) + { + if((fd=path_open(script,path_get(script))) < 0) + errormsg(SH_DICT,ERROR_system(1),e_open,script); + filename = path_fullname(stakptr(PATH_OFFSET)); + } + } + *prevscope = shp->st; + if(filename) + shp->st.filename = filename; + shp->st.prevst = prevscope; + shp->st.self = &savst; + shp->topscope = (Shscope_t*)shp->st.self; + prevscope->save_tree = shp->var_tree; + shp->st.cmdname = argv[0]; + if(np) + shp->st.filename = np->nvalue.rp->fname; + nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE); + shp->posix_fun = 0; + if(np || argv[1]) + argsave = sh_argnew(argv,&saveargfor); + sh_pushcontext(&buff,SH_JMPDOT); + jmpval = sigsetjmp(buff.buff,0); + if(jmpval == 0) + { + if(np) + sh_exec((Shnode_t*)(nv_funtree(np)),sh_isstate(SH_ERREXIT)); + else + { + char buff[IOBSIZE+1]; + iop = sfnew(NIL(Sfio_t*),buff,IOBSIZE,fd,SF_READ); + sh_eval(iop,0); + } + } + sh_popcontext(&buff); + if(!np) + free((void*)shp->st.filename); + shp->dot_depth--; + if((np || argv[1]) && jmpval!=SH_JMPSCRIPT) + sh_argreset(argsave,saveargfor); + else + { + prevscope->dolc = shp->st.dolc; + prevscope->dolv = shp->st.dolv; + } + if (shp->st.self != &savst) + *shp->st.self = shp->st; + /* only restore the top Shscope_t portion for posix functions */ + memcpy((void*)&shp->st, (void*)prevscope, sizeof(Shscope_t)); + shp->topscope = (Shscope_t*)prevscope; + nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE); + if(shp->exitval > SH_EXITSIG) + sh_fault(shp->exitval&SH_EXITMASK); + if(jmpval && jmpval!=SH_JMPFUN) + siglongjmp(*shp->jmplist,jmpval); + return(shp->exitval); +} + +/* + * null, true command + */ +int b_true(int argc,register char *argv[],void *extra) +{ + NOT_USED(argc); + NOT_USED(argv[0]); + NOT_USED(extra); + return(0); +} + +/* + * false command + */ +int b_false(int argc,register char *argv[], void *extra) +{ + NOT_USED(argc); + NOT_USED(argv[0]); + NOT_USED(extra); + return(1); +} + +int b_shift(register int n, register char *argv[], void *extra) +{ + register char *arg; + register Shell_t *shp = (Shell_t*)extra; + while((n = optget(argv,sh_optshift))) switch(n) + { + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg); + return(2); + } + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + argv += opt_info.index; + n = ((arg= *argv)?(int)sh_arith(arg):1); + if(n<0 || shp->st.dolcst.dolv += n; + shp->st.dolc -= n; + } + return(0); +} + +int b_wait(int n,register char *argv[],void *extra) +{ + register Shell_t *shp = (Shell_t*)extra; + while((n = optget(argv,sh_optwait))) switch(n) + { + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg); + break; + } + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + argv += opt_info.index; + job_bwait(argv); + return(shp->exitval); +} + +#ifdef JOBS +# if 0 + /* for the dictionary generator */ + int b_fg(int n,char *argv[],void *extra){} + int b_disown(int n,char *argv[],void *extra){} +# endif +int b_bg(register int n,register char *argv[],void *extra) +{ + register int flag = **argv; + register Shell_t *shp = (Shell_t*)extra; + register const char *optstr = sh_optbg; + if(*argv[0]=='f') + optstr = sh_optfg; + else if(*argv[0]=='d') + optstr = sh_optdisown; + while((n = optget(argv,optstr))) switch(n) + { + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg); + break; + } + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + argv += opt_info.index; + if(!sh_isoption(SH_MONITOR) || !job.jobcontrol) + { + if(sh_isstate(SH_INTERACTIVE)) + errormsg(SH_DICT,ERROR_exit(1),e_no_jctl); + return(1); + } + if(flag=='d' && *argv==0) + argv = (char**)0; + if(job_walk(sfstdout,job_switch,flag,argv)) + errormsg(SH_DICT,ERROR_exit(1),e_no_job); + return(shp->exitval); +} + +int b_jobs(register int n,char *argv[],void *extra) +{ + register int flag = 0; + register Shell_t *shp = (Shell_t*)extra; + while((n = optget(argv,sh_optjobs))) switch(n) + { + case 'l': + flag = JOB_LFLAG; + break; + case 'n': + flag = JOB_NFLAG; + break; + case 'p': + flag = JOB_PFLAG; + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg); + break; + } + argv += opt_info.index; + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + if(*argv==0) + argv = (char**)0; + if(job_walk(sfstdout,job_list,flag,argv)) + errormsg(SH_DICT,ERROR_exit(1),e_no_job); + job_wait((pid_t)0); + return(shp->exitval); +} +#endif + +#ifdef _cmd_universe +/* + * There are several universe styles that are masked by the getuniv(), + * setuniv() calls. + */ +int b_universe(int argc, char *argv[],void *extra) +{ + register char *arg; + register int n; + NOT_USED(extra); + while((n = optget(argv,sh_optuniverse))) switch(n) + { + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg); + break; + } + argv += opt_info.index; + argc -= opt_info.index; + if(error_info.errors || argc>1) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + if(arg = argv[0]) + { + if(!astconf("UNIVERSE",0,arg)) + errormsg(SH_DICT,ERROR_exit(1), e_badname,arg); + } + else + { + if(!(arg=astconf("UNIVERSE",0,0))) + errormsg(SH_DICT,ERROR_exit(1),e_nouniverse); + else + sfputr(sfstdout,arg,'\n'); + } + return(0); +} +#endif /* cmd_universe */ + +#if SHOPT_FS_3D +# if 0 + /* for the dictionary generator */ + int b_vmap(int argc,char *argv[], void *extra){} +# endif + int b_vpath(register int argc,char *argv[], void *extra) + { + register int flag, n; + register const char *optstr; + register char *vend; + register Shell_t *shp = (Shell_t*)extra; + if(argv[0][1]=='p') + { + optstr = sh_optvpath; + flag = FS3D_VIEW; + } + else + { + optstr = sh_optvmap; + flag = FS3D_VERSION; + } + while(n = optget(argv, optstr)) switch(n) + { + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg); + break; + } + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + if(!shp->lim.fs3d) + goto failed; + argv += opt_info.index; + argc -= opt_info.index; + switch(argc) + { + case 0: + case 1: + flag |= FS3D_GET; + if((n = mount(*argv,(char*)0,flag,0)) >= 0) + { + vend = stakalloc(++n); + n = mount(*argv,vend,flag|FS3D_SIZE(n),0); + } + if(n < 0) + goto failed; + if(argc==1) + { + sfprintf(sfstdout,"%s\n",vend); + break; + } + n = 0; + while(flag = *vend++) + { + if(flag==' ') + { + flag = e_sptbnl[n+1]; + n = !n; + } + sfputc(sfstdout,flag); + } + if(n) + sfputc(sfstdout,'\n'); + break; + default: + if((argc&1)) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + /*FALLTHROUGH*/ + case 2: + if(!shp->lim.fs3d) + goto failed; + if(shp->subshell) + sh_subfork(); + for(n=0;n1) + errormsg(SH_DICT,ERROR_exit(1),e_cantset,flag==2?e_mapping:e_versions); + else + errormsg(SH_DICT,ERROR_exit(1),e_cantget,flag==2?e_mapping:e_versions); + return(1); + } +#endif /* SHOPT_FS_3D */ + diff --git a/usr/src/lib/libshell/common/bltins/mkservice.c b/usr/src/lib/libshell/common/bltins/mkservice.c new file mode 100644 index 0000000000..bba532b79d --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/mkservice.c @@ -0,0 +1,494 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped +/* + * mkservice varname pathname + * eloop [-t timeout] + * Written by David Korn + * AT&T Labs + */ + +static const char mkservice_usage[] = +"[-?\n@(#)$Id: mkservice (AT&T Research) 2001-06-13 $\n]" +USAGE_LICENSE +"[+NAME? mkservice - create a shell server ]" +"[+DESCRIPTION?\bmkservice\b creates a tcp or udp server that is " + "implemented by shell functions.]" +"[+?The \aservice_path\a must be of the form \b/dev/tcp/localhost/\b\aportno\a " + "or \b/dev/udp/localhost/\b\aportno\a depending on whether the " + "\btcp\b or \budp\b protocol is used. \aportno\a is the port " + "number that the service will use.]" +"[+?The shell variable \avarname\a is associated with the service. This " + "variable can have subvariables that keeps the state of all " + "active connections. The functions \avarname\a\b.accept\b, " + "\avarname\a\b.action\b and \avarname\a\b.close\b implement the " + "service as follows:]{" + "[+accept?This function is invoked when a client tries to connect " + "to the service. It is called with an argument which " + "is the file descriptor number associated with the " + "accepted connection. If the function returns a non-zero " + "value, this connection will be closed.]" + "[+action?This function is invoked when there is data waiting " + "to be read from one of the active connections. It is " + "called with the file descriptor number that has data " + "to be read. If the function returns a non-zero " + "value, this connection will be closed.]" + "[+close?This function is invoked when the connection is closed.]" + "}" +"[+?If \avarname\a is unset, then all active connection, and the service " + "itself will be closed.]" +"" +"\n" +"\nvarname service_path\n" +"\n" +"[+EXIT STATUS?]{" + "[+0?Success.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\beloop\b(1)]" +; + + +static const char eloop_usage[] = +"[-?\n@(#)$Id: eloop (AT&T Research) 2001-06-13 $\n]" +USAGE_LICENSE +"[+NAME? eloop - process event loop]" +"[+DESCRIPTION?\beloop\b causes the shell to block waiting for events " + "to process. By default, \beloop\b does not return.]" +"[t]#[timeout?\atimeout\a is the number of milliseconds to wait " + "without receiving any events to process.]" +"\n" +"\n\n" +"\n" +"[+EXIT STATUS?If no timeout is specified, \beloop\b will not return " + "unless interrupted. Otherwise]{" + "[+0?The specified timeout interval occurred.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\bmkservice\b(1)]" +; + + +#include "defs.h" + +#include +#include +#include +#include +#include + +#define ACCEPT 0 +#define ACTION 1 +#define CLOSE 2 + +#ifndef O_SERVICE +# define O_SERVICE O_NOCTTY +#endif + +static const char* disctab[] = +{ + "accept", + "action", + "close", + 0 +}; + +typedef struct Service_s Service_t; + +struct Service_s +{ + Namfun_t fun; + short fd; + int refcount; + int (*acceptf)(Service_t*,int); + int (*actionf)(Service_t*,int,int); + int (*errorf)(Service_t*,int,const char*, ...); + void *context; + Namval_t* node; + Namval_t* disc[elementsof(disctab)-1]; +}; + +static short *file_list; +static Sfio_t **poll_list; +static Service_t **service_list; +static int npoll; +static int nready; +static int ready; +static int (*covered_fdnotify)(int, int); + +static int fdclose(Service_t *sp, register int fd) +{ + register int i; + service_list[fd] = 0; + if(sp->fd==fd) + sp->fd = -1; + for(i=0; i < npoll; i++) + { + if(file_list[i]==fd) + { + file_list[i] = file_list[npoll--]; + if(sp->actionf) + (*sp->actionf)(sp, fd, 1); + return(1); + } + } + return(0); +} + +static int fdnotify(int fd1, int fd2) +{ + Service_t *sp; + if (covered_fdnotify) + (*covered_fdnotify)(fd1, fd2); + if(fd2!=SH_FDCLOSE) + { + register int i; + service_list[fd2] = service_list[fd1]; + service_list[fd1] = 0; + for(i=0; i < npoll; i++) + { + if(file_list[i]==fd1) + { + file_list[i] = fd2; + return(0); + } + } + } + else if(sp = service_list[fd1]) + { + fdclose(sp,fd1); + if(--sp->refcount==0) + nv_unset(sp->node); + } + return(0); +} + +static void process_stream(Sfio_t* iop) +{ + int r=0, fd = sffileno(iop); + Service_t * sp = service_list[fd]; + if(fd==sp->fd) /* connection socket */ + { + struct sockaddr addr; + socklen_t addrlen = sizeof(addr); + fd = accept(fd, &addr, &addrlen); + service_list[fd] = sp; + sp->refcount++; + file_list[npoll++] = fd; + if(fd>=0) + { + if(sp->acceptf) + r = (*sp->acceptf)(sp,fd); + } + } + else if(sp->actionf) + { + service_list[fd] = 0; + r = (*sp->actionf)(sp, fd, 0); + service_list[fd] = sp; + if(r<0) + close(fd); + } +} + +static int waitnotify(int fd, long timeout, int rw) +{ + Sfio_t *special=0, **pstream; + register int i; + + if (fd >= 0) + special = sh_fd2sfio(fd); + while(1) + { + pstream = poll_list; + while(ready < nready) + process_stream(pstream[ready++]); + if(special) + *pstream++ = special; + for(i=0; i < npoll; i++) + { + if(service_list[file_list[i]]) + *pstream++ = sh_fd2sfio(file_list[i]); + } +#if 1 + for(i=0; i < pstream-poll_list; i++) + sfset(poll_list[i],SF_WRITE,0); +#endif + nready = ready = 0; + errno = 0; +#ifdef DEBUG + sfprintf(sfstderr,"before poll npoll=%d",pstream-poll_list); + for(i=0; i < pstream-poll_list; i++) + sfprintf(sfstderr," %d",sffileno(poll_list[i])); + sfputc(sfstderr,'\n'); +#endif + nready = sfpoll(poll_list,pstream-poll_list,timeout); +#ifdef DEBUG + sfprintf(sfstderr,"after poll nready=%d",nready); + for(i=0; i < nready; i++) + sfprintf(sfstderr," %d",sffileno(poll_list[i])); + sfputc(sfstderr,'\n'); +#endif +#if 1 + for(i=0; i < pstream-poll_list; i++) + sfset(poll_list[i],SF_WRITE,1); +#endif + if(nready<=0) + return(errno? -1: 0); + if(special && poll_list[0]==special) + { + ready = 1; + return(fd); + } + } +} + +static int service_init(void) +{ + file_list = newof(NULL,short,n,0); + poll_list = newof(NULL,Sfio_t*,n,0); + service_list = newof(NULL,Service_t*,n,0); + covered_fdnotify = sh_fdnotify(fdnotify); + sh_waitnotify(waitnotify); + return(1); +} + +void service_add(Service_t *sp) +{ + static int init; + if (!init) + init = service_init(); + service_list[sp->fd] = sp; + file_list[npoll++] = sp->fd; +} + +static int Accept(register Service_t *sp, int accept_fd) +{ + register Namval_t* nq = sp->disc[ACCEPT]; + int fd; + + fd = fcntl(accept_fd, F_DUPFD, 10); + if (fd >= 0) + { + close(accept_fd); + if (nq) + { + char* av[3]; + char buff[20]; + + av[1] = buff; + av[2] = 0; + sfsprintf(buff, sizeof(buff), "%d", fd); + if (sh_fun(nq, sp->node, av)) + { + close(fd); + return -1; + } + } + } + sfsync(NiL); + return fd; +} + +static int Action(Service_t *sp, int fd, int close) +{ + register Namval_t* nq; + int r=0; + + if(close) + nq = sp->disc[CLOSE]; + else + nq = sp->disc[ACTION]; + if (nq) + { + char* av[3]; + char buff[20]; + + av[1] = buff; + av[2] = 0; + sfsprintf(buff, sizeof(buff), "%d", fd); + r=sh_fun(nq, sp->node, av); + } + sfsync(NiL); + return r > 0 ? -1 : 1; +} + +static int Error(Service_t *sp, int level, const char* arg, ...) +{ + va_list ap; + + va_start(ap, arg); + if(sp->node) + nv_unset(sp->node); + free((void*)sp); + errorv(NiL, ERROR_exit(1), ap); + va_end(ap); + return 0; +} + +static char* setdisc(Namval_t* np, const char* event, Namval_t* action, Namfun_t* fp) +{ + register Service_t* sp = (Service_t*)fp; + register const char* cp; + register int i; + register int n = strlen(event) - 1; + register Namval_t* nq; + + for (i = 0; cp = disctab[i]; i++) + { + if (memcmp(event, cp, n)) + continue; + if (action == np) + action = sp->disc[i]; + else + { + if (nq = sp->disc[i]) + free((void*)nq); + if (action) + sp->disc[i] = action; + else + sp->disc[i] = 0; + } + return action ? (char*)action : ""; + } + /* try the next level */ + return nv_setdisc(np, event, action, fp); +} + +static void putval(Namval_t* np, const char* val, int flag, Namfun_t* fp) +{ + register Service_t* sp = (Service_t*)fp; + if (!val) + fp = nv_stack(np, NiL); + nv_putv(np, val, flag, fp); + if (!val) + { + register int i; + for(i=0; i< sh.lim.open_max; i++) + { + if(service_list[i]==sp) + { + close(i); + if(--sp->refcount<=0) + break; + } + } + free((void*)fp); + return; + } +} + +static const Namdisc_t servdisc = +{ + sizeof(Service_t), + putval, + 0, + 0, + setdisc +}; + +int b_mkservice(int argc, char** argv, void* extra) +{ + register char* var; + register char* path; + register Namval_t* np; + register Service_t* sp; + register int fd; + + NOT_USED(argc); + NOT_USED(extra); + for (;;) + { + switch (optget(argv, mkservice_usage)) + { + case 0: + break; + case ':': + error(2, opt_info.arg); + continue; + case '?': + error(ERROR_usage(2), opt_info.arg); + continue; + } + break; + } + argv += opt_info.index; + if (error_info.errors || !(var = *argv++) || !(path = *argv++) || *argv) + error(ERROR_usage(2), optusage(NiL)); + if (!(sp = newof(0, Service_t, 1, 0))) + error(ERROR_exit(1), "out of space"); + sp->acceptf = Accept; + sp->actionf = Action; + sp->errorf = Error; + sp->refcount = 1; + sp->context = extra; + sp->node = 0; + sp->fun.disc = &servdisc; + if((fd = sh_open(path, O_SERVICE|O_RDWR))<=0) + { + free((void*)sp); + error(ERROR_exit(1), "%s: cannot start service", path); + } + if((sp->fd = fcntl(fd, F_DUPFD, 10))>=10) + close(fd); + else + sp->fd = fd; + np = nv_open(var,sh.var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN); + sp->node = np; + nv_putval(np, path, 0); + nv_stack(np, (Namfun_t*)sp); + service_add(sp); + return(0); +} + +int b_eloop(int argc, char** argv, void* extra) +{ + register long timeout = -1; + NOT_USED(argc); + NOT_USED(extra); + for (;;) + { + switch (optget(argv, eloop_usage)) + { + case 0: + break; + case 't': + timeout = opt_info.num; + continue; + case ':': + error(2, opt_info.arg); + continue; + case '?': + error(ERROR_usage(2), opt_info.arg); + continue; + } + break; + } + argv += opt_info.index; + if (error_info.errors || *argv) + error(ERROR_usage(2), optusage(NiL)); + while(1) + { + if(waitnotify(-1, timeout, 0)==0) + break; + sfprintf(sfstderr,"interrupted\n"); + } + return(errno != 0); +} diff --git a/usr/src/lib/libshell/common/bltins/print.c b/usr/src/lib/libshell/common/bltins/print.c new file mode 100644 index 0000000000..5363c6f3ab --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/print.c @@ -0,0 +1,897 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped +/* + * echo [arg...] + * print [-nrps] [-f format] [-u filenum] [arg...] + * printf format [arg...] + * + * David Korn + * AT&T Labs + */ + +#include "defs.h" +#include +#include +#include "io.h" +#include "name.h" +#include "history.h" +#include "builtins.h" +#include "streval.h" +#include +#include +#include + +union types_t +{ + unsigned char c; + short h; + int i; + long l; + Sflong_t ll; + Sfdouble_t ld; + double d; + float f; + char *s; + int *ip; + char **p; +}; + +struct printf +{ + Sffmt_t hdr; + int argsize; + int intvar; + char **nextarg; + char cescape; + char err; + Shell_t *sh; +}; + +static int extend(Sfio_t*,void*, Sffmt_t*); +static const char preformat[] = ""; +static char *genformat(char*); +static int fmtvecho(const char*, struct printf*); + +struct print +{ + Shell_t *sh; + const char *options; + char raw; + char echon; +}; + +static char* nullarg[] = { 0, 0 }; + +/* + * Need to handle write failures to avoid locking output pool + */ +static int outexceptf(Sfio_t* iop, int mode, void* data, Sfdisc_t* dp) +{ + if(mode==SF_DPOP || mode==SF_FINAL) + free((void*)dp); + else if(mode==SF_WRITE && (errno!= EINTR || sh.trapnote)) + { + int save = errno; + sfpurge(iop); + sfpool(iop,NIL(Sfio_t*),SF_WRITE); + errno = save; + errormsg(SH_DICT,ERROR_system(1),e_badwrite,sffileno(iop)); + } + return(0); +} + +#if !SHOPT_ECHOPRINT + int B_echo(int argc, char *argv[],void *extra) + { + static char bsd_univ; + struct print prdata; + prdata.options = sh_optecho+5; + prdata.raw = prdata.echon = 0; + prdata.sh = (Shell_t*)extra; + NOT_USED(argc); + /* This mess is because /bin/echo on BSD is different */ + if(!prdata.sh->universe) + { + register char *universe; + if(universe=astconf("UNIVERSE",0,0)) + bsd_univ = (strcmp(universe,"ucb")==0); + prdata.sh->universe = 1; + } + if(!bsd_univ) + return(b_print(0,argv,&prdata)); + prdata.options = sh_optecho; + prdata.raw = 1; + while(argv[1] && *argv[1]=='-') + { + if(strcmp(argv[1],"-n")==0) + prdata.echon = 1; +#if !SHOPT_ECHOE + else if(strcmp(argv[1],"-e")==0) + prdata.raw = 0; + else if(strcmp(argv[1],"-ne")==0 || strcmp(argv[1],"-en")==0) + { + prdata.raw = 0; + prdata.echon = 1; + } +#endif /* SHOPT_ECHOE */ + else + break; + argv++; + } + return(b_print(0,argv,&prdata)); + } +#endif /* SHOPT_ECHOPRINT */ + +int b_printf(int argc, char *argv[],void *extra) +{ + struct print prdata; + NOT_USED(argc); + memset(&prdata,0,sizeof(prdata)); + prdata.sh = (Shell_t*)extra; + prdata.options = sh_optprintf; + return(b_print(-1,argv,&prdata)); +} + +/* + * argc==0 when called from echo + * argc==-1 when called from printf + */ + +int b_print(int argc, char *argv[], void *extra) +{ + register Sfio_t *outfile; + register int exitval=0,n, fd = 1; + register Shell_t *shp = (Shell_t*)extra; + const char *options, *msg = e_file+4; + char *format = 0; + int sflag = 0, nflag=0, rflag=0; + if(argc>0) + { + options = sh_optprint; + nflag = rflag = 0; + format = 0; + } + else + { + struct print *pp = (struct print*)extra; + shp = pp->sh; + options = pp->options; + if(argc==0) + { + nflag = pp->echon; + rflag = pp->raw; + argv++; + goto skip; + } + } + while((n = optget(argv,options))) switch(n) + { + case 'n': + nflag++; + break; + case 'p': + fd = shp->coutpipe; + msg = e_query; + break; + case 'f': + format = opt_info.arg; + break; + case 's': + /* print to history file */ + if(!sh_histinit()) + errormsg(SH_DICT,ERROR_system(1),e_history); + fd = sffileno(shp->hist_ptr->histfp); + sh_onstate(SH_HISTORY); + sflag++; + break; + case 'e': + rflag = 0; + break; + case 'r': + rflag = 1; + break; + case 'u': + fd = (int)strtol(opt_info.arg,&opt_info.arg,10); + if(*opt_info.arg) + fd = -1; + else if(fd<0 || fd >= shp->lim.open_max) + fd = -1; + else if(!(sh.inuse_bits&(1<hist_ptr && fd==sffileno(shp->hist_ptr->histfp)))) + + fd = -1; + break; + case ':': + /* The following is for backward compatibility */ +#if OPT_VERSION >= 19990123 + if(strcmp(opt_info.name,"-R")==0) +#else + if(strcmp(opt_info.option,"-R")==0) +#endif + { + rflag = 1; + if(error_info.errors==0) + { + argv += opt_info.index+1; + /* special case test for -Rn */ + if(strchr(argv[-1],'n')) + nflag++; + if(*argv && strcmp(*argv,"-n")==0) + { + + nflag++; + argv++; + } + goto skip2; + } + } + else + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); + break; + } + argv += opt_info.index; + if(error_info.errors || (argc<0 && !(format = *argv++))) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); +skip: + if(format) + format = genformat(format); + /* handle special case of '-' operand for print */ + if(argc>0 && *argv && strcmp(*argv,"-")==0 && strcmp(argv[-1],"--")) + argv++; +skip2: + if(fd < 0) + { + errno = EBADF; + n = 0; + } + else if(!(n=shp->fdstatus[fd])) + n = sh_iocheckfd(fd); + if(!(n&IOWRITE)) + { + /* don't print error message for stdout for compatibility */ + if(fd==1) + return(1); + errormsg(SH_DICT,ERROR_system(1),msg); + } + if(!(outfile=shp->sftable[fd])) + { + Sfdisc_t *dp; + sh_onstate(SH_NOTRACK); + n = SF_WRITE|((n&IOREAD)?SF_READ:0); + shp->sftable[fd] = outfile = sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fd,n); + sh_offstate(SH_NOTRACK); + sfpool(outfile,shp->outpool,SF_WRITE); + if(dp = new_of(Sfdisc_t,0)) + { + dp->exceptf = outexceptf; + dp->seekf = 0; + dp->writef = 0; + dp->readf = 0; + sfdisc(outfile,dp); + } + } + /* turn off share to guarantee atomic writes for printf */ + n = sfset(outfile,SF_SHARE|SF_PUBLIC,0); + if(format) + { + /* printf style print */ + Sfio_t *pool; + struct printf pdata; + memset(&pdata, 0, sizeof(pdata)); + pdata.sh = shp; + pdata.hdr.version = SFIO_VERSION; + pdata.hdr.extf = extend; + pdata.nextarg = argv; + sh_offstate(SH_STOPOK); + pool=sfpool(sfstderr,NIL(Sfio_t*),SF_WRITE); + do + { + if(shp->trapnote&SH_SIGSET) + break; + pdata.hdr.form = format; + sfprintf(outfile,"%!",&pdata); + } while(*pdata.nextarg && pdata.nextarg!=argv); + if(pdata.nextarg == nullarg && pdata.argsize>0) + sfwrite(outfile,stakptr(staktell()),pdata.argsize); + sfpool(sfstderr,pool,SF_WRITE); + exitval = pdata.err; + } + else + { + /* echo style print */ + if(sh_echolist(outfile,rflag,argv) && !nflag) + sfputc(outfile,'\n'); + } + if(sflag) + { + hist_flush(shp->hist_ptr); + sh_offstate(SH_HISTORY); + } + else if(n&SF_SHARE) + { + sfset(outfile,SF_SHARE|SF_PUBLIC,1); + sfsync(outfile); + } + return(exitval); +} + +/* + * echo the argument list onto + * if is non-zero then \ is not a special character. + * returns 0 for \c otherwise 1. + */ + +int sh_echolist(Sfio_t *outfile, int raw, char *argv[]) +{ + register char *cp; + register int n; + struct printf pdata; + pdata.cescape = 0; + pdata.err = 0; + while(!pdata.cescape && (cp= *argv++)) + { + if(!raw && (n=fmtvecho(cp,&pdata))>=0) + { + if(n) + sfwrite(outfile,stakptr(staktell()),n); + } + else + sfputr(outfile,cp,-1); + if(*argv) + sfputc(outfile,' '); + sh_sigcheck(); + } + return(!pdata.cescape); +} + +/* + * modified version of stresc for generating formats + */ +static char strformat(char *s) +{ + register char* t; + register int c; + char* b; + char* p; + + b = t = s; + for (;;) + { + switch (c = *s++) + { + case '\\': + if(*s==0) + break; + c = chresc(s - 1, &p); + s = p; +#if SHOPT_MULTIBYTE + if(c>UCHAR_MAX && mbwide()) + { + t += wctomb(t, c); + continue; + } +#endif /* SHOPT_MULTIBYTE */ + if(c=='%') + *t++ = '%'; + else if(c==0) + { + *t++ = '%'; + c = 'Z'; + } + break; + case 0: + *t = 0; + return(t - b); + } + *t++ = c; + } +} + + +static char *genformat(char *format) +{ + register char *fp; + stakseek(0); + stakputs(preformat); + stakputs(format); + fp = (char*)stakfreeze(1); + strformat(fp+sizeof(preformat)-1); + return(fp); +} + +static char *fmthtml(const char *string) +{ + register const char *cp = string; + register int c, offset = staktell(); + while(c= *(unsigned char*)cp++) + { +#if SHOPT_MULTIBYTE + register int s; + if((s=mbsize(cp-1)) > 1) + { + cp += (s-1); + continue; + } +#endif /* SHOPT_MULTIBYTE */ + if(c=='<') + stakputs("<"); + else if(c=='>') + stakputs(">"); + else if(c=='&') + stakputs("&"); + else if(c=='"') + stakputs("""); + else if(c=='\'') + stakputs("'"); + else if(c==' ') + stakputs(" "); + else if(!isprint(c) && c!='\n' && c!='\r') + sfprintf(stkstd,"&#%X;",CCMAPC(c,CC_NATIVE,CC_ASCII)); + else + stakputc(c); + } + stakputc(0); + return(stakptr(offset)); +} + +static void *fmtbase64(char *string, ssize_t *sz) +{ + char *cp; + Sfdouble_t d; + size_t size; + Namval_t *np = nv_open(string, NiL, NV_VARNAME|NV_NOASSIGN|NV_NOADD); + static union types_t number; + if(!np) + return(""); + if(nv_isattr(np,NV_INTEGER)) + { + d = nv_getnum(np); + if(nv_isattr(np,NV_DOUBLE)) + { + if(nv_isattr(np,NV_LONG)) + { + size = sizeof(Sfdouble_t); + number.ld = d; + } + else if(nv_isattr(np,NV_SHORT)) + { + size = sizeof(float); + number.f = (float)d; + } + else + { + size = sizeof(double); + number.d = (double)d; + } + } + else + { + if(nv_isattr(np,NV_LONG)) + { + size = sizeof(Sflong_t); + number.ll = (Sflong_t)d; + } + else if(nv_isattr(np,NV_SHORT)) + { + size = sizeof(short); + number.h = (short)d; + } + else + { + size = sizeof(short); + number.i = (int)d; + } + } + if(sz) + *sz = size; + return((void*)&number); + } + if(nv_isattr(np,NV_BINARY)) + nv_onattr(np,NV_RAW); + cp = nv_getval(np); + if(nv_isattr(np,NV_BINARY)) + nv_offattr(np,NV_RAW); + if((size = nv_size(np))==0) + size = strlen(cp); + if(sz) + *sz = size; + return((void*)cp); +} + +static int extend(Sfio_t* sp, void* v, Sffmt_t* fe) +{ + char* lastchar = ""; + register int neg = 0; + Sfdouble_t d; + Sfdouble_t longmin = LDBL_LLONG_MIN; + Sfdouble_t longmax = LDBL_LLONG_MAX; + int format = fe->fmt; + int n; + int fold = fe->base; + union types_t* value = (union types_t*)v; + struct printf* pp = (struct printf*)fe; + register char* argp = *pp->nextarg; + + fe->flags |= SFFMT_VALUE; + if(!argp || format=='Z') + { + switch(format) + { + case 'c': + value->c = 0; + fe->flags &= ~SFFMT_LONG; + break; + case 'q': + format = 's'; + /* FALL THROUGH */ + case 's': + case 'H': + case 'B': + case 'P': + case 'R': + case 'Z': + case 'b': + fe->fmt = 's'; + fe->size = -1; + fe->base = -1; + value->s = ""; + fe->flags &= ~SFFMT_LONG; + break; + case 'a': + case 'e': + case 'f': + case 'g': + case 'A': + case 'E': + case 'F': + case 'G': + if(SFFMT_LDOUBLE) + value->ld = 0.; + else + value->d = 0.; + break; + case 'n': + value->ip = &pp->intvar; + break; + case 'Q': + value->ll = 0; + break; + case 'T': + fe->fmt = 'd'; + value->ll = tmxgettime(); + break; + default: + if(!strchr("DdXxoUu",format)) + errormsg(SH_DICT,ERROR_exit(1),e_formspec,format); + fe->fmt = 'd'; + value->ll = 0; + break; + } + } + else + { + switch(format) + { + case 'p': + value->p = (char**)strtol(argp,&lastchar,10); + break; + case 'n': + { + Namval_t *np; + np = nv_open(argp,sh.var_tree,NV_VARNAME|NV_NOASSIGN|NV_NOARRAY); + nv_unset(np); + nv_onattr(np,NV_INTEGER); + if (np->nvalue.lp = new_of(int32_t,0)) + *np->nvalue.lp = 0; + nv_setsize(np,10); + if(sizeof(int)==sizeof(int32_t)) + value->ip = (int*)np->nvalue.lp; + else + { + int32_t sl = 1; + value->ip = (int*)(((char*)np->nvalue.lp) + (*((char*)&sl) ? 0 : sizeof(int))); + } + nv_close(np); + break; + } + case 'q': + case 'b': + case 's': + case 'B': + case 'H': + case 'P': + case 'R': + fe->fmt = 's'; + fe->size = -1; + if(format=='s' && fe->base>=0) + { + value->p = pp->nextarg; + pp->nextarg = nullarg; + } + else + { + fe->base = -1; + value->s = argp; + } + fe->flags &= ~SFFMT_LONG; + break; + case 'c': + if(fe->base >=0) + value->s = argp; + else + value->c = *argp; + fe->flags &= ~SFFMT_LONG; + break; + case 'o': + case 'x': + case 'X': + case 'u': + case 'U': + longmax = LDBL_ULLONG_MAX; + case '.': + if(fe->size==2 && strchr("bcsqHPRQTZ",*fe->form)) + { + value->ll = ((unsigned char*)argp)[0]; + break; + } + case 'd': + case 'D': + case 'i': + switch(*argp) + { + case '\'': + case '"': + value->ll = ((unsigned char*)argp)[1]; + break; + default: + d = sh_strnum(argp,&lastchar,0); + if(derr = 1; + d = longmin; + } + else if(d>longmax) + { + errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp); + pp->err = 1; + d = longmax; + } + value->ll = (Sflong_t)d; + if(lastchar == *pp->nextarg) + { + value->ll = *argp; + lastchar = ""; + } + break; + } + if(neg) + value->ll = -value->ll; + fe->size = sizeof(value->ll); + break; + case 'a': + case 'e': + case 'f': + case 'g': + case 'A': + case 'E': + case 'F': + case 'G': + d = sh_strnum(*pp->nextarg,&lastchar,0); + if(SFFMT_LDOUBLE) + { + value->ld = d; + fe->size = sizeof(value->ld); + } + else + { + value->d = d; + fe->size = sizeof(value->d); + } + break; + case 'Q': + value->ll = (Sflong_t)strelapsed(*pp->nextarg,&lastchar,1); + break; + case 'T': + value->ll = (Sflong_t)tmxdate(*pp->nextarg,&lastchar,TMX_NOW); + break; + default: + value->ll = 0; + fe->fmt = 'd'; + fe->size = sizeof(value->ll); + errormsg(SH_DICT,ERROR_exit(1),e_formspec,format); + break; + } + if (format == '.') + value->i = value->ll; + if(*lastchar) + { + errormsg(SH_DICT,ERROR_warn(0),e_argtype,format); + pp->err = 1; + } + pp->nextarg++; + } + switch(format) + { + case 'Z': + fe->fmt = 'c'; + fe->base = -1; + value->c = 0; + break; + case 'b': + if((n=fmtvecho(value->s,pp))>=0) + { + if(pp->nextarg == nullarg) + { + pp->argsize = n; + return -1; + } + value->s = stakptr(staktell()); + } + break; + case 'B': + value->s = (char*)fmtbase64(value->s, &fe->size); + break; + case 'H': + value->s = fmthtml(value->s); + break; + case 'q': + value->s = sh_fmtqf(value->s, !!(fe->flags & SFFMT_ALTER), fold); + break; + case 'P': + { + char *s = fmtmatch(value->s); + if(!s || *s==0) + errormsg(SH_DICT,ERROR_exit(1),e_badregexp,value->s); + value->s = s; + break; + } + case 'R': + value->s = fmtre(value->s); + if(*value->s==0) + errormsg(SH_DICT,ERROR_exit(1),e_badregexp,value->s); + break; + case 'Q': + if (fe->n_str>0) + { + fe->fmt = 'd'; + fe->size = sizeof(value->ll); + } + else + { + value->s = fmtelapsed(value->ll, 1); + fe->fmt = 's'; + fe->size = -1; + } + break; + case 'T': + if(fe->n_str>0) + { + n = fe->t_str[fe->n_str]; + fe->t_str[fe->n_str] = 0; + value->s = fmttmx(fe->t_str, value->ll); + fe->t_str[fe->n_str] = n; + } + else value->s = fmttmx(NIL(char*), value->ll); + fe->fmt = 's'; + fe->size = -1; + break; + } + return 0; +} + +/* + * construct System V echo string out of + * If there are not escape sequences, returns -1 + * Otherwise, puts null terminated result on stack, but doesn't freeze it + * returns length of output. + */ + +static int fmtvecho(const char *string, struct printf *pp) +{ + register const char *cp = string, *cpmax; + register int c; + register int offset = staktell(); +#if SHOPT_MULTIBYTE + int chlen; + if(mbwide()) + { + while(1) + { + if ((chlen = mbsize(cp)) > 1) + /* Skip over multibyte characters */ + cp += chlen; + else if((c= *cp++)==0 || c == '\\') + break; + } + } + else +#endif /* SHOPT_MULTIBYTE */ + while((c= *cp++) && (c!='\\')); + if(c==0) + return(-1); + c = --cp - string; + if(c>0) + stakwrite((void*)string,c); + for(; c= *cp; cp++) + { +#if SHOPT_MULTIBYTE + if (mbwide() && ((chlen = mbsize(cp)) > 1)) + { + stakwrite(cp,chlen); + cp += (chlen-1); + continue; + } +#endif /* SHOPT_MULTIBYTE */ + if( c=='\\') switch(*++cp) + { + case 'E': + c = ('a'==97?'\033':39); /* ASCII/EBCDIC */ + break; + case 'a': + c = '\a'; + break; + case 'b': + c = '\b'; + break; + case 'c': + pp->cescape++; + pp->nextarg = nullarg; + goto done; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 'v': + c = '\v'; + break; + case 't': + c = '\t'; + break; + case '\\': + c = '\\'; + break; + case '0': + c = 0; + cpmax = cp + 4; + while(++cp='0' && *cp<='7') + { + c <<= 3; + c |= (*cp-'0'); + } + default: + cp--; + } + stakputc(c); + } +done: + c = staktell()-offset; + stakputc(0); + stakseek(offset); + return(c); +} diff --git a/usr/src/lib/libshell/common/bltins/read.c b/usr/src/lib/libshell/common/bltins/read.c new file mode 100644 index 0000000000..930470275c --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/read.c @@ -0,0 +1,590 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped +/* + * read [-Aprs] [-d delim] [-u filenum] [-t timeout] [-n n] [-N n] [name...] + * + * David Korn + * AT&T Labs + * + */ + +#include +#include +#include +#include "defs.h" +#include "variables.h" +#include "lexstates.h" +#include "io.h" +#include "name.h" +#include "builtins.h" +#include "history.h" +#include "terminal.h" +#include "edit.h" + +#define R_FLAG 1 /* raw mode */ +#define S_FLAG 2 /* save in history file */ +#define A_FLAG 4 /* read into array */ +#define N_FLAG 8 /* fixed size read at most */ +#define NN_FLAG 0x10 /* fixed size read exact */ +#define V_FLAG 0x20 /* use default value */ +#define D_FLAG 8 /* must be number of bits for all flags */ + +int b_read(int argc,char *argv[], void *extra) +{ + Sfdouble_t sec; + register char *name; + register int r, flags=0, fd=0; + register Shell_t *shp = (Shell_t*)extra; + long timeout = 1000*shp->st.tmout; + int save_prompt; + static char default_prompt[3] = {ESC,ESC}; + NOT_USED(argc); + while((r = optget(argv,sh_optread))) switch(r) + { + case 'A': + flags |= A_FLAG; + break; + case 't': + sec = sh_strnum(opt_info.arg, (char**)0,1); + timeout = sec ? 1000*sec : 1; + break; + case 'd': + if(opt_info.arg && *opt_info.arg!='\n') + { + char *cp = opt_info.arg; + flags &= ~((1<cpipe[0])<=0) + errormsg(SH_DICT,ERROR_exit(1),e_query); + break; + case 'n': case 'N': + flags &= ~((1< (1<<((8*sizeof(int))-D_FLAG))-1) + errormsg(SH_DICT,ERROR_exit(1),e_overlimit,"n"); + flags |= (r<< D_FLAG); + break; + case 'r': + flags |= R_FLAG; + break; + case 's': + /* save in history file */ + flags |= S_FLAG; + break; + case 'u': + fd = (int)opt_info.num; + if(sh_inuse(fd)) + fd = -1; + break; + case 'v': + flags |= V_FLAG; + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); + break; + } + argv += opt_info.index; + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2), "%s", optusage((char*)0)); + if(!((r=shp->fdstatus[fd])&IOREAD) || !(r&(IOSEEK|IONOSEEK))) + r = sh_iocheckfd(fd); + if(fd<0 || !(r&IOREAD)) + errormsg(SH_DICT,ERROR_system(1),e_file+4); + /* look for prompt */ + shp->prompt = default_prompt; + if((name = *argv) && (name=strchr(name,'?')) && (r&IOTTY)) + { + r = strlen(++name)+1; + if(shp->prompt=(char*)sfreserve(sfstderr,r,SF_LOCKR)) + { + memcpy(shp->prompt,name,r); + sfwrite(sfstderr,shp->prompt,r-1); + } + } + shp->timeout = 0; + save_prompt = shp->nextprompt; + shp->nextprompt = 0; + r=sh_readline(shp,argv,fd,flags,timeout); + shp->nextprompt = save_prompt; + if(r==0 && (r=(sfeof(shp->sftable[fd])||sferror(shp->sftable[fd])))) + { + if(fd == shp->cpipe[0]) + { + sh_pclose(shp->cpipe); + return(1); + } + } + sfclrerr(shp->sftable[fd]); + return(r); +} + +/* + * here for read timeout + */ +static void timedout(void *handle) +{ + sfclrlock((Sfio_t*)handle); + sh_exit(1); +} + +/* + * This is the code to read a line and to split it into tokens + * is an array of variable names + * is the file descriptor + * is union of -A, -r, -s, and contains delimiter if not '\n' + * is number of milli-seconds until timeout + */ + +int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeout) +{ + register int c; + register unsigned char *cp; + register Namval_t *np; + register char *name, *val; + register Sfio_t *iop; + char *ifs; + unsigned char *cpmax; + unsigned char *del; + char was_escape = 0; + char use_stak = 0; + char was_write = 0; + char was_share = 1; + int rel, wrd; + long array_index = 0; + void *timeslot=0; + int delim = '\n'; + int jmpval=0; + int size = 0; + struct checkpt buff; + if(!(iop=shp->sftable[fd]) && !(iop=sh_iostream(fd))) + return(1); + if(names && (name = *names)) + { + if(val= strchr(name,'?')) + *val = 0; + np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME|NV_ARRAY); + if((flags&V_FLAG) && shp->ed_context) + ((struct edit*)shp->ed_context)->e_default = np; + if(flags&A_FLAG) + { + flags &= ~A_FLAG; + array_index = 1; + nv_unset(np); + nv_putsub(np,NIL(char*),0L); + } + else + name = *++names; + if(val) + *val = '?'; + } + else + { + name = 0; + if(dtvnext(shp->var_tree) || shp->namespace) + np = nv_open(nv_name(REPLYNOD),shp->var_tree,0); + else + np = REPLYNOD; + } + if(flags>>D_FLAG) /* delimiter not new-line or fixed size read */ + { + if(flags&(N_FLAG|NN_FLAG)) + size = ((unsigned)flags)>>D_FLAG; + else + delim = ((unsigned)flags)>>D_FLAG; + if(shp->fdstatus[fd]&IOTTY) + tty_raw(fd,1); + } + if(!(flags&(N_FLAG|NN_FLAG))) + { + Namval_t *mp; + /* set up state table based on IFS */ + ifs = nv_getval(mp=nv_scoped(IFSNOD)); + if((flags&R_FLAG) && shp->ifstable['\\']==S_ESC) + shp->ifstable['\\'] = 0; + else if(!(flags&R_FLAG) && shp->ifstable['\\']==0) + shp->ifstable['\\'] = S_ESC; + shp->ifstable[delim] = S_NL; + if(delim!='\n') + { + shp->ifstable['\n'] = 0; + nv_putval(mp, ifs, NV_RDONLY); + } + shp->ifstable[0] = S_EOF; + } + sfclrerr(iop); + if(np->nvfun && np->nvfun->disc->readf) + return((* np->nvfun->disc->readf)(np,iop,delim,np->nvfun)); + was_write = (sfset(iop,SF_WRITE,0)&SF_WRITE)!=0; + if(fd==0) + was_share = (sfset(iop,SF_SHARE,1)&SF_SHARE)!=0; + if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK))) + { + sh_pushcontext(&buff,1); + jmpval = sigsetjmp(buff.buff,0); + if(jmpval) + goto done; + if(timeout) + timeslot = (void*)sh_timeradd(timeout,0,timedout,(void*)iop); + } + if(flags&(N_FLAG|NN_FLAG)) + { + char buf[64],*var=buf; + /* reserved buffer */ + if((c=size)>=sizeof(buf)) + { + if(!(var = (char*)malloc(c+1))) + sh_exit(1); + } + if((sfset(iop,SF_SHARE,1)&SF_SHARE) && fd!=0) + was_share = 1; + if(size==0) + { + cp = sfreserve(iop,0,0); + c = 0; + } + else + { + c= (shp->fdstatus[fd]&(IOTTY|IONOSEEK))?1:-1; + if(flags&NN_FLAG) + c = size; + if(cp = sfreserve(iop,c,!(flags&NN_FLAG))) + c = sfvalue(iop); + else + c = 0; + if(c>size) + c = size; + if(c>0) + { + memcpy((void*)var,cp,c); + if(flags&N_FLAG) + sfread(iop,cp,c); + } + var[c] = 0; + if(c>=size) + sfclrerr(iop); + } + if(timeslot) + timerdel(timeslot); + if(nv_isattr(np,NV_BINARY)) + { + if(c=sizeof(buf)) + free((void*)var); + } + goto done; + } + else if(cp = (unsigned char*)sfgetr(iop,delim,0)) + c = sfvalue(iop); + else if(cp = (unsigned char*)sfgetr(iop,delim,-1)) + c = sfvalue(iop)+1; + if(timeslot) + timerdel(timeslot); + if((flags&S_FLAG) && !shp->hist_ptr) + { + sh_histinit(); + if(!shp->hist_ptr) + flags &= ~S_FLAG; + } + if(cp) + { + cpmax = cp + c; +#if SHOPT_CRNL + if(delim=='\n' && c>=2 && cpmax[-2]=='\r') + cpmax--; +#endif /* SHOPT_CRNL */ + if(*(cpmax-1) != delim) + *(cpmax-1) = delim; + if(flags&S_FLAG) + sfwrite(shp->hist_ptr->histfp,(char*)cp,c); + c = shp->ifstable[*cp++]; +#if !SHOPT_MULTIBYTE + if(!name && (flags&R_FLAG)) /* special case single argument */ + { + /* skip over leading blanks */ + while(c==S_SPACE) + c = shp->ifstable[*cp++]; + /* strip trailing delimiters */ + if(cpmax[-1] == '\n') + cpmax--; + if(cpmax>cp) + { + while((c=shp->ifstable[*--cpmax])==S_DELIM || c==S_SPACE); + cpmax[1] = 0; + } + else + *cpmax =0; + if(nv_isattr(np, NV_RDONLY)) + { + errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); + jmpval = 1; + } + else + nv_putval(np,(char*)cp-1,0); + goto done; + } +#endif /* !SHOPT_MULTIBYTE */ + } + else + c = S_NL; + shp->nextprompt = 2; + rel= staktell(); + /* val==0 at the start of a field */ + val = 0; + del = 0; + while(1) + { + switch(c) + { +#if SHOPT_MULTIBYTE + case S_MBYTE: + if(val==0) + val = (char*)(cp-1); + if(sh_strchr(ifs,(char*)cp-1)>=0) + { + c = mbsize((char*)cp-1); + if(name) + cp[-1] = 0; + if(c>1) + cp += (c-1); + c = S_DELIM; + } + else + c = 0; + continue; +#endif /*SHOPT_MULTIBYTE */ + case S_ESC: + /* process escape character */ + if((c = shp->ifstable[*cp++]) == S_NL) + was_escape = 1; + else + c = 0; + if(val) + { + stakputs(val); + use_stak = 1; + was_escape = 1; + *val = 0; + } + continue; + + case S_EOF: + /* check for end of buffer */ + if(val && *val) + { + stakputs(val); + use_stak = 1; + } + val = 0; + if(cp>=cpmax) + { + c = S_NL; + break; + } + /* eliminate null bytes */ + c = shp->ifstable[*cp++]; + if(!name && val && (c==S_SPACE||c==S_DELIM||c==S_MBYTE)) + c = 0; + continue; + case S_NL: + if(was_escape) + { + was_escape = 0; + if(cp = (unsigned char*)sfgetr(iop,delim,0)) + c = sfvalue(iop); + else if(cp=(unsigned char*)sfgetr(iop,delim,-1)) + c = sfvalue(iop)+1; + if(cp) + { + if(flags&S_FLAG) + sfwrite(shp->hist_ptr->histfp,(char*)cp,c); + cpmax = cp + c; + c = shp->ifstable[*cp++]; + val=0; + if(!name && (c==S_SPACE || c==S_DELIM || c==S_MBYTE)) + c = 0; + continue; + } + } + c = S_NL; + break; + + case S_SPACE: + /* skip over blanks */ + while((c=shp->ifstable[*cp++])==S_SPACE); + if(!val) + continue; +#if SHOPT_MULTIBYTE + if(c==S_MBYTE) + { + if(sh_strchr(ifs,(char*)cp-1)>=0) + { + if((c = mbsize((char*)cp-1))>1) + cp += (c-1); + c = S_DELIM; + } + else + c = 0; + } +#endif /* SHOPT_MULTIBYTE */ + if(c!=S_DELIM) + break; + /* FALL THRU */ + + case S_DELIM: + if(!del) + del = cp - 1; + if(name) + { + /* skip over trailing blanks */ + while((c=shp->ifstable[*cp++])==S_SPACE); + break; + } + /* FALL THRU */ + + case 0: + if(val==0 || was_escape) + { + val = (char*)(cp-1); + was_escape = 0; + } + /* skip over word characters */ + wrd = -1; + while(1) + { + while((c=shp->ifstable[*cp++])==0) + if(!wrd) + wrd = 1; + if(!del&&c==S_DELIM) + del = cp - 1; + if(name || c==S_NL || c==S_ESC || c==S_EOF || c==S_MBYTE) + break; + if(wrd<0) + wrd = 0; + } + if(wrd>0) + del = (unsigned char*)""; + if(c!=S_MBYTE) + cp[-1] = 0; + continue; + } + /* assign value and advance to next variable */ + if(!val) + val = ""; + if(use_stak) + { + stakputs(val); + stakputc(0); + val = stakptr(rel); + } + if(!name && *val) + { + /* strip off trailing space delimiters */ + register unsigned char *vp = (unsigned char*)val + strlen(val); + while(shp->ifstable[*--vp]==S_SPACE); + if(vp==del) + { + if(vp==(unsigned char*)val) + vp--; + else + while(shp->ifstable[*--vp]==S_SPACE); + } + vp[1] = 0; + } + if(nv_isattr(np, NV_RDONLY)) + { + errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); + jmpval = 1; + } + else + nv_putval(np,val,0); + val = 0; + del = 0; + if(use_stak) + { + stakseek(rel); + use_stak = 0; + } + if(array_index) + { + nv_putsub(np, NIL(char*), array_index++); + if(c!=S_NL) + continue; + name = *++names; + } + while(1) + { + if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.') && !nv_isattr(np,NV_EXPORT)) + { + nv_onattr(np,NV_EXPORT); + sh_envput(sh.env,np); + } + if(name) + { + nv_close(np); + np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME); + name = *++names; + } + else + np = 0; + if(c!=S_NL) + break; + if(!np) + goto done; + if(nv_isattr(np, NV_RDONLY)) + { + errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); + jmpval = 1; + } + else + nv_putval(np, "", 0); + } + } +done: + if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK))) + sh_popcontext(&buff); + if(was_write) + sfset(iop,SF_WRITE,1); + if(!was_share) + sfset(iop,SF_SHARE,0); + nv_close(np); + if((flags>>D_FLAG) && (shp->fdstatus[fd]&IOTTY)) + tty_cooked(fd); + if(flags&S_FLAG) + hist_flush(shp->hist_ptr); + if(jmpval > 1) + siglongjmp(*shp->jmplist,jmpval); + return(jmpval); +} + diff --git a/usr/src/lib/libshell/common/bltins/shiocmd_solaris.c b/usr/src/lib/libshell/common/bltins/shiocmd_solaris.c new file mode 100644 index 0000000000..25bced42a2 --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/shiocmd_solaris.c @@ -0,0 +1,1180 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped + +#include +#include +#include +#include +#include +#include "name.h" +#undef nv_isnull +#ifndef SH_DICT +# define SH_DICT "libshell" +#endif +#include + +/* + * time formatting related +*/ +struct dctime +{ + Namfun_t fun; + Namval_t *format; + char buff[256]; /* Must be large enougth for |tmfmt()| */ +}; + +static char *get_time(Namval_t* np, Namfun_t* nfp) +{ + struct dctime *dp = (struct dctime*)nfp; + time_t t = nv_getn(np,nfp); + char *format = nv_getval(dp->format); + tmfmt(dp->buff,sizeof(dp->buff),format,(time_t*)0); + return(dp->buff); +} + +static void put_time(Namval_t* np, const char* val, int flag, Namfun_t* nfp) +{ + struct dctime *dp = (struct dctime*)nfp; + char *last; + if(val) + { + int32_t t; + if(flag&NV_INTEGER) + { + if(flag&NV_LONG) + t = *(Sfdouble_t*)val; + else + t = *(double*)val; + } + else + { + t = tmdate(val, &last, (time_t*)0); + if(*last) + errormsg(SH_DICT, ERROR_exit(1),"%s: invalid date/time string", val); + } + nv_putv(np, (char*)&t,NV_INTEGER, nfp); + } + else + { + nv_unset(dp->format); + free((void*)dp->format); + nv_putv(np, val, flag, nfp); + } +} + +static Namval_t *create_time(Namval_t *np, const char *name, int flags, Namfun_t *nfp) +{ + struct dctime *dp = (struct dctime*)nfp; + if(strcmp(name, "format")) + return((Namval_t*)0); + return(dp->format); +} + +static const Namdisc_t timedisc = +{ + sizeof(struct dctime), + put_time, + get_time, + 0, + 0, + create_time, +}; + + +static Namval_t *make_time(Namval_t* np) +{ + int offset = stktell(stkstd); + char *name = nv_name(np); + struct dctime *dp = newof(NULL,struct dctime,1,0); + if(!dp) + return((Namval_t*)0); + sfprintf(stkstd,"%s.format\0",name); + sfputc(stkstd,0); + dp->format = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD); + dp->fun.disc = &timedisc; + nv_stack(np,&dp->fun); + return(np); +} + +/* + * mode formatting related +*/ +static char *get_mode(Namval_t* np, Namfun_t* nfp) +{ + mode_t mode = nv_getn(np,nfp); + return(fmtperm(mode)); +} + +static void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp) +{ + if(val) + { + int32_t mode; + char *last; + if(flag&NV_INTEGER) + { + if(flag&NV_LONG) + mode = *(Sfdouble_t*)val; + else + mode = *(double*)val; + } + else + { + mode = strperm(val, &last,0); + if(*last) + errormsg(SH_DICT, ERROR_exit(1),"%s: invalid mode string", val); + } + nv_putv(np,(char*)&mode,NV_INTEGER,nfp); + } + else + nv_putv(np,val,flag,nfp); +} + +static const Namdisc_t modedisc = +{ + 0, + put_mode, + get_mode, +}; + +static Namval_t *make_mode(Namval_t* np) +{ + char *name = nv_name(np); + Namfun_t *nfp = newof(NULL,Namfun_t,1,0); + if(!nfp) + return((Namval_t*)0); + nfp->disc = &modedisc; + nv_stack(np,nfp); + return(np); +} + +/* + * field related typese and functions + */ +typedef struct _field_ +{ + char *name; /* field name */ + int flags; /* flags */ + short offset; /* offset of field into data */ + short size; /* size of field */ + Namval_t *(*make)(Namval_t*); /* discipline constructor */ +} Shfield_t; + +/* + * lookup field in field table + */ +static Shfield_t *sh_findfield(Shfield_t *ftable, int nelem, const char *name) +{ + Shfield_t *fp = ftable; + register int i,n; + register const char *cp; + for(cp=name; *cp; cp++) + { + if(*cp=='.') + break; + } + n = cp-name; + for(i=0; i < nelem; i++,fp++) + { + if(memcmp(fp->name,name,n)==0 && fp->name[n]==0) + return(fp); + } + return(0); +} + +/* + * class types and functions + */ + +typedef struct _class_ +{ + int nelem; /* number of elements */ + int dsize; /* size for data structure */ + Shfield_t *fields; /* field description table */ +} Shclass_t; + +struct dcclass +{ + Namfun_t fun; + Shclass_t sclass; +}; + +static Namval_t *sh_newnode(register Shfield_t *fp, Namval_t *np) +{ + char *val = np->nvalue + fp->offset; + char *name = nv_name(np); + register Namval_t *nq; + int offset = stktell(stkstd); + sfprintf(stkstd,"%s.%s\0",name,fp->name); + sfputc(stkstd,0); + nq = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD); + if(fp->size<0) + val = *(char**)val; + nv_putval(nq,val,fp->flags|NV_NOFREE); + if(fp->make) + (*fp->make)(nq); + return(nq); +} + +static Namval_t *fieldcreate(Namval_t *np, const char *name, int flags, Namfun_t *nfp) +{ + struct dcclass *dcp = (struct dcclass*)nfp; + Shclass_t *sp = &dcp->sclass; + Shfield_t *fp = sh_findfield(sp->fields,sp->nelem,name); + Namval_t *nq,**nodes = (Namval_t**)(dcp+1); + int n = fp-sp->fields; + int len = strlen(fp->name); + void *data = (void*)np->nvalue; + if(!(nq=nodes[n])) + { + nodes[n] = nq = sh_newnode(fp,np); + nfp->last = ""; + } + if(name[len]==0) + return(nq); + return(nq); +} + +static void genvalue(Sfio_t *out, Shclass_t *sp, int indent, Namval_t *npar) +{ + Shfield_t *fp = sp->fields; + Namval_t *np, **nodes= (Namval_t**)(sp+1); + register int i,isarray; + if(out) + { + sfwrite(out,"(\n",2); + indent++; + } + for(i=0; i < sp->nelem; i++,fp++) + { +#if 0 + /* handle recursive case */ +#endif + if(!(np=nodes[i]) && out) + np = sh_newnode(fp,npar); + if(np) + { + isarray=0; + if(nv_isattr(np,NV_ARRAY)) + { + isarray=1; + if(array_elem(nv_arrayptr(np))==0) + isarray=2; + else + nv_putsub(np,(char*)0,ARRAY_SCAN); + } + sfnputc(out,'\t',indent); + sfputr(out,fp->name,(isarray==2?'\n':'=')); + if(isarray) + { + if(isarray==2) + continue; + sfwrite(out,"(\n",2); + sfnputc(out,'\t',++indent); + } + while(1) + { + char *fmtq; + if(isarray) + { + sfprintf(out,"[%s]",sh_fmtq(nv_getsub(np))); + sfputc(out,'='); + } + if(!(fmtq=nv_getval(np)) || !(fmtq=sh_fmtq(fmtq))) + fmtq = ""; + sfputr(out,fmtq,'\n'); + if(!nv_nextsub(np)) + break; + sfnputc(out,'\t',indent); + } + if(isarray) + { + sfnputc(out,'\t',--indent); + sfwrite(out,")\n",2); + } + } + } + if(out) + { + if(indent>1) + sfnputc(out,'\t',indent-1); + sfputc(out,')'); + } +} + +static char *walk_class(register Namval_t *np, int dlete, struct dcclass *dcp) +{ + static Sfio_t *out; + Sfio_t *outfile; + int savtop = stktell(stkstd); + char *savptr = stkfreeze(stkstd,0); + if(dlete) + outfile = 0; + else if(!(outfile=out)) + outfile = out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING); + else + sfseek(outfile,0L,SEEK_SET); + genvalue(outfile,&dcp->sclass,0,np); + stkset(stkstd,savptr,savtop); + if(!outfile) + return((char*)0); + sfputc(out,0); + return((char*)out->_data); +} + +static char *get_classval(Namval_t* np, Namfun_t* nfp) +{ + return(walk_class(np,0,(struct dcclass *)nfp)); +} + +static void put_classval(Namval_t* np, const char* val, int flag, Namfun_t* nfp) +{ + walk_class(np,1,(struct dcclass *)nfp); + if(nfp = nv_stack(np,(Namfun_t*)0)) + { + free((void*)nfp); + if(np->nvalue && !nv_isattr(np,NV_NOFREE)) + free((void*)np->nvalue); + } + if(val) + nv_putval(np,val,flag); +} + +static const Namdisc_t classdisc = +{ + sizeof(struct dcclass), + put_classval, + get_classval, + 0, + 0, + fieldcreate +}; + +static int mkclass(Namval_t *np, Shclass_t *sp) +{ + struct dcclass *tcp = newof(NULL,struct dcclass,1,sp->nelem*sizeof(Namval_t*)); + if(!tcp) + return(0); + memset((void*)(tcp+1),0,sp->nelem*sizeof(Namval_t*)); + tcp->fun.disc = &classdisc; + tcp->sclass = *sp; + np->nvalue = (char*)calloc(sp->dsize,1); + nv_stack(np,&tcp->fun); + return(1); +} + +/* + * ====================from here down is file class specific + */ +static struct stat *Sp; + +struct filedata +{ + struct stat statb; + int fd; + char *name; +}; + +static Shfield_t filefield[] = +{ + { "atime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_atime), sizeof(Sp->st_atime), make_time}, + { "ctime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ctime), sizeof(Sp->st_ctime), make_time}, + { "dev", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_dev),sizeof(Sp->st_dev)}, + { "fd", NV_INTEGER|NV_RDONLY, offsetof(struct filedata,fd), sizeof(int)}, + { "gid", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_gid), sizeof(Sp->st_gid)}, + { "ino", NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ino), sizeof(Sp->st_ino)}, + { "mode", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mode), sizeof(Sp->st_mode), make_mode}, + { "mtime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mtime), sizeof(Sp->st_mtime), make_time}, + { "name", NV_RDONLY, offsetof(struct filedata,name), -1 }, + { "nlink", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_nlink), sizeof(Sp->st_nlink)}, + { "size", NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_size), sizeof(Sp->st_size)}, + { "uid", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_uid), sizeof(Sp->st_uid)} +}; + +static Shclass_t Fileclass = +{ + sizeof(filefield)/sizeof(*filefield), + sizeof(struct filedata), + filefield +}; + + +#define letterbit(bit) (1<<((bit)-'a')) + +static const char sh_optopen[] = +"[-?\n@(#)$Id: open (AT&T Labs Research) 2007-05-07 $\n]" +"[-author?David Korn ]" +"[-author?Roland Mainz ]" +"[-license?http://www.opensource.org/licenses/cpl1.0.txt]" +"[+NAME? open - create a shell variable correspnding to a file]" +"[+DESCRIPTION?\bopen\b creates the compound variable \avar\a correspinding " + "to the file given by the pathname \afile\a. The elements of \avar\a " + "are the names of elements in the \astat\a structure with the \bst_\b " + "prefix removed.]" +"[+?\afile\a is opened (based on \b-r\b and/or \b-w\b) and the variable " + "\avar\a\b.fd\b is the file descriptor.]" +"[a:append?Open for append.]" +"[b:binary?Open in binary mode" +#ifndef O_BINARY + " (not supported/ignored on this platform)" +#endif + ".]" +"[t:text?Open in text mode" +#ifndef O_TEXT + " (not supported/ignored on this platform)" +#endif + ".]" +"[c:create?Open for create.]" +"[i:inherit?Open without the close-on-exec bit set.]" +"[I:noinherit?Open with the close-on-exec bit set.]" +"[r:read?Open with read access.]" +"[w:write?Open with write access.]" +"[m:mode]:[mode:=rwrwrw?Open with access mode \amode\a.]" +"[x:exclusive?Open exclusive.]" + +"[N:nofollow?If the path names a symbolic link, open fails with ELOOP " +#ifndef O_NOFOLLOW + " (not supported/ignored on this platform)" +#endif + ".]" +"[S:sync?Write I/O operations on the file descriptor complete as " + "defined by synchronized I/O file integrity completion" +#ifndef O_SYNC + " (not supported/ignored on this platform)" +#endif + ".]" +"[T:trunc?If the file exists and is a regular file, and the file " + "is successfully opened read/write or write-only, its length is " + "truncated to 0 and the mode and owner are unchanged. It " + "has no effect on FIFO special files or terminal device " + "files. Its effect on other file types is " + "implementation-dependent. The result of using -T " + "with read-only files is undefined" +#ifndef O_TRUNC + " (not supported/ignored on this platform)" +#endif + ".]" +"\n" +"\nvar file\n" +"\n" +"[+EXIT STATUS?]{" + "[+0?Success.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bpoll\b(1),\bstat\b(2)]" +; + + +extern int b_open(int argc, char *argv[], void *extra) +{ + register Namval_t *np; + register int n,oflag=0; + Shell_t *shp = (Shell_t*)extra; + struct filedata *fdp; + mode_t mode = 0666; + long flags = 0; + int fd = -1; + char *arg; + + while (n = optget(argv, sh_optopen)) switch (n) + { + case 'r': + case 'w': + case 'i': + flags |= letterbit(n); + break; + case 'I': + flags &= ~(letterbit('i')); + break; + case 'b': +#ifdef O_BINARY + oflag |= O_BINARY; +#endif + break; + case 't': +#ifdef O_TEXT + oflag |= O_TEXT; +#endif + break; + case 'N': +#ifdef O_NOFOLLOW + oflag |= O_NOFOLLOW; +#endif + break; + case 'T': +#ifdef O_TRUNC + oflag |= O_TRUNC; +#endif + break; + case 'x': + oflag |= O_EXCL; + break; + case 'c': + oflag |= O_CREAT; + break; + case 'a': + oflag |= O_APPEND; + break; + case 'S': +#ifdef O_SYNC + oflag |= O_SYNC; +#endif + break; + case 'm': + mode = strperm(arg = opt_info.arg, &opt_info.arg, mode); + if (*opt_info.arg) + errormsg(SH_DICT, ERROR_system(1), "%s: invalid mode", arg); + break; + case ':': + errormsg(SH_DICT, 2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); + break; + } + argc -= opt_info.index; + argv += opt_info.index; + if(argc!=2 || !(flags&(letterbit('r')|letterbit('w')))) + errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); + + if(flags&letterbit('r')) + { + if(flags&letterbit('w')) + oflag |= O_RDWR; + else + oflag |= O_RDONLY; + } + else if(flags&letterbit('w')) + oflag |= O_WRONLY; + + fd = sh_open(argv[1], oflag, mode); + if(fd<0) + errormsg(SH_DICT, ERROR_system(1), "%s: open failed", argv[1]); + + if(!(flags&letterbit('i'))) + fcntl(fd, F_SETFL, 0); + + np = nv_open(argv[0], shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN); + if(!nv_isnull(np)) + nv_unset(np); + mkclass(np, &Fileclass); + fdp = (struct filedata*)np->nvalue; + fstat(fd, &fdp->statb); + fdp->fd = fd; + fdp->name = strdup(argv[1]); + return(0); +} + +static const char sh_optclose[] = +"[-?\n@(#)$Id: close (AT&T Labs Research) 2007-04-21 $\n]" +"[-author?Roland Mainz ]" +"[-license?http://www.opensource.org/licenses/cpl1.0.txt]" +"[+NAME? close - close a file descriptor]" +"[+DESCRIPTION?\bclose\b closes the file descriptor specified by fd.]" +"\n" +"\nfd\n" +"\n" +"[+EXIT STATUS?]{" + "[+0?Success.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\bopen\b(1),\bdup\b(1),\btmpfile\b(1),\bpoll\b(1),\bstat\b(1)]" +; + +extern int b_close(int argc, char *argv[], void *extra) +{ + register int n=0; + int fd = -1; + + while (n = optget(argv, sh_optclose)) switch (n) + { + case ':': + errormsg(SH_DICT, 2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); + break; + } + argc -= opt_info.index; + argv += opt_info.index; + if(argc!=1) + errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); + + errno = 0; + fd = strtol(argv[0], (char **)NULL, 0); + if (errno != 0 || fd < 0) + errormsg(SH_DICT, ERROR_system(1), "%s: invalid descriptor", argv[0]); + + n = sh_close(fd); + + if (n < 0) + errormsg(SH_DICT, ERROR_system(1), "%s: close error", argv[0]); + + return(n==0?0:1); +} + + +static const char sh_opttmpfile[] = +"[-?\n@(#)$Id: tmpfile (AT&T Labs Research) 2007-05-07 $\n]" +"[-author?Roland Mainz ]" +"[-license?http://www.opensource.org/licenses/cpl1.0.txt]" +"[+NAME? tmpfile - create a shell variable correspnding to a temporary file]" +"[+DESCRIPTION?\btmpfile\b creates the compound variable \avar\a correspinding " + "to a temporary file. The elements of \avar\a " + "are the names of elements in the \astat\a structure with the \bst_\b " + "prefix removed.]" +"[i:inherit?Open without the close-on-exec bit set.]" +"[I:noinherit?Open with the close-on-exec bit set.]" +"\n" +"\nvar\n" +"\n" +"[+EXIT STATUS?]{" + "[+0?Success.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\bopen\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bstat\b(2)]" +; + + +extern int b_tmpfile(int argc, char *argv[], void *extra) +{ + register Namval_t *np; + register int n; + Shell_t *shp = (Shell_t*)extra; + struct filedata *fdp; + int inherit = 0; + FILE *file = NULL; + int ffd, fd = -1; + while (n = optget(argv, sh_opttmpfile)) switch (n) + { + case 'i': + inherit = 1; + break; + case 'I': + inherit = 0; + break; + case ':': + errormsg(SH_DICT, 2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); + break; + } + argc -= opt_info.index; + argv += opt_info.index; + if(argc!=1) + errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); + + file = tmpfile(); + if(!file) + errormsg(SH_DICT, ERROR_system(1), "%s: tmpfile failed", argv[1]); + ffd = fileno(file); + fd = sh_dup(ffd); + if(fd<0) + errormsg(SH_DICT, ERROR_system(1), "%s: tmpfile failed", argv[1]); + fclose(file); + + if(!inherit) + fcntl(fd, F_SETFL, 0); + + np = nv_open(argv[0], shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN); + if(!nv_isnull(np)) + nv_unset(np); + mkclass(np,&Fileclass); + fdp = (struct filedata*)np->nvalue; + + fstat(fd, &fdp->statb); + fdp->fd = fd; + fdp->name = NULL; + return(0); +} + +static const char sh_optdup[] = +"[-?\n@(#)$Id: dup (AT&T Labs Research) 2007-05-07 $\n]" +"[-author?Roland Mainz ]" +"[-license?http://www.opensource.org/licenses/cpl1.0.txt]" +"[+NAME? dup - duplicate an open file descriptor]" +"[+DESCRIPTION?The \bdup\b commands returns a new file descriptor having the " + "following in common with the original open file descriptor " + "fd: same open file (or pipe), same file pointer (that is, both file descriptors " + "share one file pointer) same access mode (read, write or read/write). " + "The file descriptor returned is the lowest one available.]" +"[i:inherit?Open without the close-on-exec bit set.]" +"[I:noinherit?Open with the close-on-exec bit set.]" +"\n" +"\nvar fd\n" +"\n" +"[+EXIT STATUS?]{" + "[+0?Success.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bclose\b(1),\bpoll\b(1),\bstat\b(1)]" +; + + +extern int b_dup(int argc, char *argv[], void *extra) +{ + register Namval_t *np; + register int n; + Shell_t *shp = (Shell_t*)extra; + struct filedata *fdp; + int inherit = 0; + int ffd, fd = -1; + while (n = optget(argv, sh_optdup)) switch (n) + { + case 'i': + inherit = 1; + break; + case 'I': + inherit = 0; + break; + case ':': + errormsg(SH_DICT, 2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); + break; + } + argc -= opt_info.index; + argv += opt_info.index; + if(argc!=2) + errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); + + errno = 0; + ffd = strtol(argv[1], (char **)NULL, 0); + if (errno != 0 || ffd < 0) + errormsg(SH_DICT, ERROR_system(1), "%s: invalid fd", argv[1]); + + fd = sh_dup(ffd); + if(fd<0) + errormsg(SH_DICT, ERROR_system(1), "%s: dup failed", argv[1]); + + if(!inherit) + fcntl(fd,F_SETFL,0); + + np = nv_open(argv[0],shp->var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN); + if(!nv_isnull(np)) + nv_unset(np); + mkclass(np, &Fileclass); + fdp = (struct filedata*)np->nvalue; + + fstat(fd, &fdp->statb); + fdp->fd = fd; + fdp->name = NULL; + return(0); +} + +static const char sh_optstat[] = +"[-?\n@(#)$Id: stat (AT&T Labs Research) 2007-05-07 $\n]" +"[-author?David Korn ]" +"[-author?Roland Mainz ]" +"[-license?http://www.opensource.org/licenses/cpl1.0.txt]" +"[+NAME? stat - get file status]" +"[+DESCRIPTION?\bstat\b creates the compound variable \avar\a correspinding " + "to the file given by the pathname \afile\a. The elements of \avar\a " + "are the names of elements in the \astat\a structure with the \bst_\b " + "prefix removed.]" +"[l:lstat?If the the named file is a symbolic link returns information about " + "the link itself.]" +"\n" +"\nvar file\n" +"\n" +"[+EXIT STATUS?]{" + "[+0?Success.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bpoll\b(1),\bstat\b(2),\blstat\b(2)]" +; + + +extern int b_stat(int argc, char *argv[], void *extra) +{ + register Namval_t *np; + register int n; + Shell_t *shp = (Shell_t*)extra; + struct filedata *fdp; + long flags = 0; + struct stat statb; + while (n = optget(argv, sh_optstat)) switch (n) + { + case 'l': + flags |= letterbit(n); + break; + case ':': + errormsg(SH_DICT, 2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); + break; + } + argc -= opt_info.index; + argv += opt_info.index; + if(argc!=2) + errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); + + if(flags&letterbit('l')) + { + if(lstat(argv[1], &statb) < 0) + errormsg(SH_DICT, ERROR_system(1), "%s: stat failed", argv[1]); + } + else + { + if(stat(argv[1], &statb) < 0) + errormsg(SH_DICT, ERROR_system(1), "%s: stat failed", argv[1]); + + } + + np = nv_open(argv[0],shp->var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN); + if(!nv_isnull(np)) + nv_unset(np); + mkclass(np,&Fileclass); + fdp = (struct filedata*)np->nvalue; + fdp->statb = statb; + fdp->fd = -1; + fdp->name = strdup(argv[1]); + return(0); +} + +static const char sh_optpoll[] = +"[-?\n@(#)$Id: poll (AT&T Labs Research) 2007-05-07 $\n]" +"[-author?Roland Mainz 0) may be " + "written. This event only examines bands " + "that have been written to at least once.]" + "[+POLLERR?An error has occurred on the device or " + "stream. This flag is only valid in the " + "revents bitmask; it is not used in the " + "events member.]" + "[+POLLHUP?A hangup has occurred on the stream. This " + "event and POLLOUT are mutually exclusive; a " + "stream can never be writable if a hangup has " + "occurred. However, this event and POLLIN, " + ", POLLRDBAND, or POLLPRI are not " + "mutually exclusive. This flag is only valid " + "in the revents bitmask; it is not used in " + "the events member.]" + "[+POLLNVAL?The specified fd value does not belong to an " + "open file. This flag is only valid in the " + "revents member; it is not used in the events " + "member.]" + "}" +"]" + +"[+?If the value fd is less than 0, events is ignored and " + "revents is set to 0 in that entry on return from poll.]" + +"[+?The results of the poll query are stored in the revents " + "member in the \bvar\b structure. POLL*-strings are set in the \brevents\b " + "variable to indicate which of the requested events are true. " + "If none are true, the \brevents\b will be an empty string when " + "the poll command returns. The event flags " + "POLLHUP, POLLERR, and POLLNVAL are always set in \brevents\b " + "if the conditions they indicate are true; this occurs even " + "though these flags were not present in events.]" + +"[+?If none of the defined events have occurred on any selected " + "file descriptor, poll waits at least timeout milliseconds " + "for an event to occur on any of the selected file descriptors. " + "On a computer where millisecond timing accuracy is not " + "available, timeout is rounded up to the nearest legal value " + "available on that system. If the value timeout is 0, poll " + "returns immediately. If the value of timeout is -1, poll " + "blocks until a requested event occurs or until the call is " + "interrupted.]" + +"[+?The poll function supports regular files, terminal and " + "pseudo-terminal devices, STREAMS-based files, FIFOs and " + "pipes. The behavior of poll on elements of fds that refer " + "to other types of file is unspecified.]" + +"[+?The poll function supports sockets.]" + +"[+?A file descriptor for a socket that is listening for connections " + "will indicate that it is ready for reading, once connections " + "are available. A file descriptor for a socket that " + "is connecting asynchronously will indicate that it is ready " + "for writing, once a connection has been established.]" + +"[+?Regular files always poll TRUE for reading and writing.]" + +"[t:timeout]:[milliseconds?Timeout in milliseconds. If the value timeout is 0, " + "poll returns immediately. If the value of timeout is -1, poll " + "blocks until a requested event occurs or until the call is " + "interrupted.]" +"\n" +"\nvar\n" +"\n" +"[+EXIT STATUS?]{" + "[+0?Success.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bpoll\b(2)]" +; + +/* + * |mystpcpy| - like |strcpy()| but returns the end of the buffer + * + * Copy string s2 to s1. s1 must be large enough. + * return s1-1 (position of string terminator ('\0') in destnation buffer). + */ +static +char *mystpcpy(char *s1, const char *s2) +{ + while (*s1++ = *s2++) + ; + return (s1-1); +} + +static +Namval_t *nv_open_fmt(Dt_t *dict, int flags, const char *namefmt, ...) +{ + char varnamebuff[PATH_MAX]; + va_list ap; + + va_start(ap, namefmt); + vsnprintf(varnamebuff, sizeof(varnamebuff), namefmt, ap); + va_end(ap); + + return nv_open(varnamebuff, dict, flags); +} + +static +int poll_strtoevents(const char *str) +{ + int events = 0; + + if (strstr(str, "POLLIN")) events |= POLLIN; + if (strstr(str, "POLLRDNORM")) events |= POLLRDNORM; + if (strstr(str, "POLLRDBAND")) events |= POLLRDBAND; + if (strstr(str, "POLLPRI")) events |= POLLPRI; + if (strstr(str, "POLLOUT")) events |= POLLOUT; + if (strstr(str, "POLLWRNORM")) events |= POLLWRNORM; + if (strstr(str, "POLLWRBAND")) events |= POLLWRBAND; + if (strstr(str, "POLLERR")) events |= POLLERR; + if (strstr(str, "POLLHUP")) events |= POLLHUP; + if (strstr(str, "POLLNVAL")) events |= POLLNVAL; + + return events; +} + + +static +void poll_eventstostr(char *s, int events) +{ + *s='\0'; + if (!events) + return; + + if (events & POLLIN) s=mystpcpy(s, "POLLIN|"); + if (events & POLLRDNORM) s=mystpcpy(s, "POLLRDNORM|"); + if (events & POLLRDBAND) s=mystpcpy(s, "POLLRDBAND|"); + if (events & POLLPRI) s=mystpcpy(s, "POLLPRI|"); + if (events & POLLOUT) s=mystpcpy(s, "POLLOUT|"); + if (events & POLLWRNORM) s=mystpcpy(s, "POLLWRNORM|"); + if (events & POLLWRBAND) s=mystpcpy(s, "POLLWRBAND|"); + if (events & POLLERR) s=mystpcpy(s, "POLLERR|"); + if (events & POLLHUP) s=mystpcpy(s, "POLLHUP|"); + if (events & POLLNVAL) s=mystpcpy(s, "POLLNVAL|"); + + /* Remove trailling '|' */ + s--; + if(*s=='|') + *s='\0'; +} + +extern int b_poll(int argc, char *argv[], void *extra) +{ + register Namval_t *np; + register int n; + Shell_t *shp = (Shell_t*)extra; + char *varname; + int fd; +/* |BPOLL_MAX| needs to be larger than |OPEN_MAX| to make sure we + * can listen to different sets of events per fd. + */ +#define BPOLL_MAX 512 + struct pollfd pollfd[BPOLL_MAX]; + unsigned int numpollfd = 0; + int i; + char *s; + long timeout = -1; + char buff[256]; + + while (n = optget(argv, sh_optpoll)) switch (n) + { + case 't': + errno = 0; + timeout = strtol(opt_info.arg, (char **)NULL, 0); + if (errno != 0) + errormsg(SH_DICT, ERROR_system(1), "%s: invalid timeout", opt_info.arg); + break; + case ':': + errormsg(SH_DICT, 2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); + break; + } + argc -= opt_info.index; + argv += opt_info.index; + if(argc!=1) + errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); + + varname = argv[0]; + + for(i=0 ; i < BPOLL_MAX ; i++) + { + np = nv_open_fmt(shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN|NV_NOFAIL|NV_NOADD, "%s[%d].fd", varname, i); + if (!np) + break; + fd = (int)nv_getnum(np); + if (fd < 0 || fd > OPEN_MAX) + errormsg(SH_DICT, ERROR_system(1), "poll: invalid pollfd fd"); + nv_close(np); + pollfd[i].fd = fd; + + np = nv_open_fmt(shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN|NV_NOFAIL|NV_NOADD, "%s[%d].events", varname, i); + if (!s) + errormsg(SH_DICT, ERROR_system(1), "poll: missing pollfd events"); + + s = nv_getval(np); + if (!s) + errormsg(SH_DICT, ERROR_system(1), "poll: missing pollfd events value"); + pollfd[i].events = poll_strtoevents(s); + nv_close(np); + + pollfd[i].revents = 0; + + numpollfd++; + } + + if (i == BPOLL_MAX) + errormsg(SH_DICT, ERROR_system(1), "poll: cannot handle more than %d entries.", BPOLL_MAX); + + n = poll(pollfd, numpollfd, timeout); + /* FixMe: EGAIN and EINTR may require extra handling */ + if (n < 0) + errormsg(SH_DICT, ERROR_system(1), "poll: failure"); + + for(i=0 ; i < numpollfd ; i++) + { + np = nv_open_fmt(shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN|NV_NOFAIL, "%s[%d].revents", varname, i); + if (!np) + errormsg(SH_DICT, ERROR_system(1), "poll: couldn't create pollfd %s[%d].revents", varname, i); + + poll_eventstostr(buff, pollfd[i].revents); + + nv_putval(np, buff, 0); + nv_close(np); + } + + return(0); +} + +static const char sh_optrewind[] = +"[-?\n@(#)$Id: rewind (AT&T Labs Research) 2007-05-07 $\n]" +"[-author?Roland Mainz ]" +"[-license?http://www.opensource.org/licenses/cpl1.0.txt]" +"[+NAME? rewind - reset file position indicator in a stream]" +"[+DESCRIPTION?The \brewind\b command will move the file pointer of fd to position 0.]" +"\n" +"\nfd\n" +"\n" +"[+EXIT STATUS?]{" + "[+0?Success.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bstat\b(1),\bstat\b(2)]" +; + + +extern int b_rewind(int argc, char *argv[], void *extra) +{ + Shell_t *shp = (Shell_t*)extra; + int fd = -1; + register int n; + while (n = optget(argv, sh_optrewind)) switch (n) + { + case ':': + errormsg(SH_DICT, 2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); + break; + } + argc -= opt_info.index; + argv += opt_info.index; + if(argc!=1) + errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); + + errno = 0; + fd = strtol(argv[0], (char **)NULL, 0); + if (errno != 0 || fd < 0) + errormsg(SH_DICT, ERROR_system(1), "%s: invalid fd", argv[0]); + + if (sh_seek(fd, 0, SEEK_SET) == (off_t)-1) + errormsg(SH_DICT, ERROR_system(1), "seek error"); + + return(0); +} + diff --git a/usr/src/lib/libshell/common/bltins/shopen.c b/usr/src/lib/libshell/common/bltins/shopen.c new file mode 100644 index 0000000000..6a7a85a990 --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/shopen.c @@ -0,0 +1,533 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped + +static const char id[] = "\n@(#)$Id: open (AT&T Research) 1998-07-07 $\0\n"; + +#include +#include +#include +#include +#ifndef SH_DICT +# define SH_DICT "libshell" +#endif + +/* + * time formatting related +*/ +struct dctime +{ + Namfun_t fun; + Namval_t *format; +}; + +static char *get_time(Namval_t* np, Namfun_t* nfp) +{ + static char buff[256]; + struct dctime *dp = (struct dctime*)nfp; + time_t t = nv_getn(np,nfp); + char *format = nv_getval(dp->format); + tmfmt(buff,sizeof(buff),format,(time_t*)0); + return(buff); +} + +static void put_time(Namval_t* np, const char* val, int flag, Namfun_t* nfp) +{ + struct dctime *dp = (struct dctime*)nfp; + char *last; + if(val) + { + int32_t t; + if(flag&NV_INTEGER) + { + if(flag&NV_LONG) + t = *(Sfdouble_t*)val; + else + t = *(double*)val; + } + else + { + t = tmdate(val, &last, (time_t*)0); + if(*last) + errormsg(SH_DICT,ERROR_exit(1),"%s: invalid date/time string",val); + } + nv_putv(np,(char*)&t,NV_INTEGER,nfp); + } + else + { + nv_unset(dp->format); + free((void*)dp->format); + nv_putv(np,val,flag,nfp); + } +} + +static Namval_t *create_time(Namval_t *np, const char *name, int flags, Namfun_t *nfp) +{ + struct dctime *dp = (struct dctime*)nfp; + if(strcmp(name,"format")) + return((Namval_t*)0); + return(dp->format); +} + +static const Namdisc_t timedisc = +{ + sizeof(struct dctime), + put_time, + get_time, + 0, + 0, + create_time, +}; + + +static Namval_t *make_time(Namval_t* np) +{ + int offset = stktell(stkstd); + char *name = nv_name(np); + struct dctime *dp = newof(NULL,struct dctime,1,0); + if(!dp) + return((Namval_t*)0); + sfprintf(stkstd,"%s.format\0",name); + sfputc(stkstd,0); + dp->format = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD); + dp->fun.disc = &timedisc; + nv_stack(np,&dp->fun); + return(np); +} + +/* + * mode formatting related +*/ +static char *get_mode(Namval_t* np, Namfun_t* nfp) +{ + mode_t mode = nv_getn(np,nfp); + return(fmtperm(mode)); +} + +static void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp) +{ + if(val) + { + int32_t mode; + char *last; + if(flag&NV_INTEGER) + { + if(flag&NV_LONG) + mode = *(Sfdouble_t*)val; + else + mode = *(double*)val; + } + else + { + mode = strperm(val, &last,0); + if(*last) + errormsg(SH_DICT,ERROR_exit(1),"%s: invalid mode string",val); + } + nv_putv(np,(char*)&mode,NV_INTEGER,nfp); + } + else + nv_putv(np,val,flag,nfp); +} + +static const Namdisc_t modedisc = +{ + 0, + put_mode, + get_mode, +}; + +static Namval_t *make_mode(Namval_t* np) +{ + char *name = nv_name(np); + Namfun_t *nfp = newof(NULL,Namfun_t,1,0); + if(!nfp) + return((Namval_t*)0); + nfp->disc = &modedisc; + nv_stack(np,nfp); + return(np); +} + +/* + * field related typese and functions + */ +typedef struct _field_ +{ + char *name; /* field name */ + int flags; /* flags */ + short offset; /* offset of field into data */ + short size; /* size of field */ + Namval_t *(*make)(Namval_t*); /* discipline constructor */ +} Shfield_t; + +/* + * lookup field in field table + */ +static Shfield_t *sh_findfield(Shfield_t *ftable, int nelem, const char *name) +{ + Shfield_t *fp = ftable; + register int i,n; + register const char *cp; + for(cp=name; *cp; cp++) + { + if(*cp=='.') + break; + } + n = cp-name; + for(i=0; i < nelem; i++,fp++) + { + if(memcmp(fp->name,name,n)==0 && fp->name[n]==0) + return(fp); + } + return(0); +} + +/* + * class types and functions + */ + +typedef struct _class_ +{ + int nelem; /* number of elements */ + int dsize; /* size for data structure */ + Shfield_t *fields; /* field description table */ +} Shclass_t; + +struct dcclass +{ + Namfun_t fun; + Shclass_t sclass; +}; + +static Namval_t *sh_newnode(register Shfield_t *fp, Namval_t *np) +{ + char *val = np->nvalue + fp->offset; + char *name = nv_name(np); + register Namval_t *nq; + int offset = stktell(stkstd); + sfprintf(stkstd,"%s.%s\0",name,fp->name); + sfputc(stkstd,0); + nq = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD); + if(fp->size<0) + val = *(char**)val; + nv_putval(nq,val,fp->flags|NV_NOFREE); + if(fp->make) + (*fp->make)(nq); + return(nq); +} + +static Namval_t *fieldcreate(Namval_t *np, const char *name, int flags, Namfun_t *nfp) +{ + struct dcclass *dcp = (struct dcclass*)nfp; + Shclass_t *sp = &dcp->sclass; + Shfield_t *fp = sh_findfield(sp->fields,sp->nelem,name); + Namval_t *nq,**nodes = (Namval_t**)(dcp+1); + int n = fp-sp->fields; + int len = strlen(fp->name); + void *data = (void*)np->nvalue; + if(!(nq=nodes[n])) + { + nodes[n] = nq = sh_newnode(fp,np); + nfp->last = ""; + } + if(name[len]==0) + return(nq); + return(nq); +} + +static void genvalue(Sfio_t *out, Shclass_t *sp, int indent, Namval_t *npar) +{ + Shfield_t *fp = sp->fields; + Namval_t *np, **nodes= (Namval_t**)(sp+1); + register int i,isarray; + if(out) + { + sfwrite(out,"(\n",2); + indent++; + } + for(i=0; i < sp->nelem; i++,fp++) + { +#if 0 + /* handle recursive case */ +#endif + if(!(np=nodes[i]) && out) + np = sh_newnode(fp,npar); + if(np) + { + isarray=0; + if(nv_isattr(np,NV_ARRAY)) + { + isarray=1; + if(array_elem(nv_arrayptr(np))==0) + isarray=2; + else + nv_putsub(np,(char*)0,ARRAY_SCAN); + } + sfnputc(out,'\t',indent); + sfputr(out,fp->name,(isarray==2?'\n':'=')); + if(isarray) + { + if(isarray==2) + continue; + sfwrite(out,"(\n",2); + sfnputc(out,'\t',++indent); + } + while(1) + { + char *fmtq; + if(isarray) + { + sfprintf(out,"[%s]",sh_fmtq(nv_getsub(np))); + sfputc(out,'='); + } + if(!(fmtq=nv_getval(np)) || !(fmtq=sh_fmtq(fmtq))) + fmtq = ""; + sfputr(out,fmtq,'\n'); + if(!nv_nextsub(np)) + break; + sfnputc(out,'\t',indent); + } + if(isarray) + { + sfnputc(out,'\t',--indent); + sfwrite(out,")\n",2); + } + } + } + if(out) + { + if(indent>1) + sfnputc(out,'\t',indent-1); + sfputc(out,')'); + } +} + +static char *walk_class(register Namval_t *np, int dlete, struct dcclass *dcp) +{ + static Sfio_t *out; + Sfio_t *outfile; + int savtop = stktell(stkstd); + char *savptr = stkfreeze(stkstd,0); + if(dlete) + outfile = 0; + else if(!(outfile=out)) + outfile = out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING); + else + sfseek(outfile,0L,SEEK_SET); + genvalue(outfile,&dcp->sclass,0,np); + stkset(stkstd,savptr,savtop); + if(!outfile) + return((char*)0); + sfputc(out,0); + return((char*)out->_data); +} + +static char *get_classval(Namval_t* np, Namfun_t* nfp) +{ + return(walk_class(np,0,(struct dcclass *)nfp)); +} + +static void put_classval(Namval_t* np, const char* val, int flag, Namfun_t* nfp) +{ + walk_class(np,1,(struct dcclass *)nfp); + if(nfp = nv_stack(np,(Namfun_t*)0)) + { + free((void*)nfp); + if(np->nvalue && !nv_isattr(np,NV_NOFREE)) + free((void*)np->nvalue); + } + if(val) + nv_putval(np,val,flag); +} + +static const Namdisc_t classdisc = +{ + sizeof(struct dcclass), + put_classval, + get_classval, + 0, + 0, + fieldcreate +}; + +static int mkclass(Namval_t *np, Shclass_t *sp) +{ + struct dcclass *tcp = newof(NULL,struct dcclass,1,sp->nelem*sizeof(Namval_t*)); + if(!tcp) + return(0); + memset((void*)(tcp+1),0,sp->nelem*sizeof(Namval_t*)); + tcp->fun.disc = &classdisc; + tcp->sclass = *sp; + np->nvalue = (char*)calloc(sp->dsize,1); + nv_stack(np,&tcp->fun); + return(1); +} + +/* + * ====================from here down is file class specific + */ +static struct stat *Sp; + +struct filedata +{ + struct stat statb; + int fd; + char *name; +}; + +static Shfield_t filefield[] = +{ + { "atime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_atime), sizeof(Sp->st_atime), make_time}, + { "ctime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ctime), sizeof(Sp->st_ctime), make_time}, + { "dev", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_dev),sizeof(Sp->st_dev)}, + { "fd", NV_INTEGER|NV_RDONLY, offsetof(struct filedata,fd), sizeof(int)}, + { "gid", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_gid), sizeof(Sp->st_gid)}, + { "ino", NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ino), sizeof(Sp->st_ino)}, + { "mode", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mode), sizeof(Sp->st_mode), make_mode}, + { "mtime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mtime), sizeof(Sp->st_mtime), make_time}, + { "name", NV_RDONLY, offsetof(struct filedata,name), -1 }, + { "nlink", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_nlink), sizeof(Sp->st_nlink)}, + { "size", NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_size), sizeof(Sp->st_size)}, + { "uid", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_uid), sizeof(Sp->st_uid)} +}; + +static Shclass_t Fileclass = +{ + sizeof(filefield)/sizeof(*filefield), + sizeof(struct filedata), + filefield +}; + + +#define letterbit(bit) (1<<((bit)-'a')) + +static const char sh_optopen[] = +"[-?\n@(#)$Id: open (AT&T Labs Research) 2007-03-11 $\n]" +"[-author?David Korn ]" +"[-license?http://www.opensource.org/licenses/cpl1.0.txt]" +"[+NAME? open - create a shell variable correspnding to a file]" +"[+DESCRIPTION?\bopen\b creates the compound variable \avar\a correspinding " + "to the file given by the pathname \afile\a. The elements of \avar\a " + "are the names of elements in the \astat\a structure with the \bst_\b " + "prefix removed.]" +"[+?If the \b-r\b and/or \b-w\b mode is specified, then \afile\a is opened and " + "the variable \avar\a\b.fd\b is the file descriptor.]" +"[a:append?Open for append.]" +"[b:binary?Open in binary mode.]" +"[c:create?Open for create.]" +"[i:inherit?Open without the close-on-exec bit set.]" +"[r:read?Open with read access.]" +"[w:write?Open with write access.]" +"[m:mode]:[mode:=rwrwrw?Open with access mode \amode\a.]" +"[x:exclusive?Open exclusive.]" +"\n" +"\nvar file\n" +"\n" +"[+EXIT STATUS?]{" + "[+0?Success.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\bstat\b(2)]" +; + + +extern int b_open(int argc, char *argv[], void *extra) +{ + register Namval_t *np; + register int n,oflag=0; + Shell_t *shp = (Shell_t*)extra; + struct filedata *fdp; + struct stat statb; + mode_t mode = 0666; + long flags = 0; + int fd = -1; + while (n = optget(argv, sh_optopen)) switch (n) + { + case 'r': + case 'i': + case 'w': + flags |= letterbit(n); + break; + case 'b': +#ifdef O_BINARY + oflag |= O_BINARY; +#endif + break; + case 't': +#ifdef O_TEXT + oflag |= O_TEXT; +#endif + break; + case 'x': + oflag |= O_EXCL; + break; + case 'c': + oflag |= O_CREAT; + break; + case 'a': + oflag |= O_APPEND; + break; + case 'm': + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); + break; + } + argc -= opt_info.index; + argv += opt_info.index; + if(argc!=2) + errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0)); + if(!(flags&(letterbit('r')|letterbit('w')))) + { + if(stat(argv[1],&statb)<0) + errormsg(SH_DICT,ERROR_system(1),"%s: open failed",argv[1]); + } + else + { + if(flags&letterbit('r')) + { + if(flags&letterbit('w')) + oflag |= O_RDWR; + else + oflag |= O_RDONLY; + } + else if(flags&letterbit('w')) + oflag |= O_WRONLY; + fd = open(argv[1],oflag,mode); + if(fd<0) + errormsg(SH_DICT,ERROR_system(1),"%s: open failed",argv[1]); + } + if(!(flags&letterbit('i'))) + fcntl(fd,F_SETFL,0); + np = nv_open(argv[0],shp->var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN); + if(!nv_isnull(np)) + nv_unset(np); + mkclass(np,&Fileclass); + fdp = (struct filedata*)np->nvalue; + if(!(flags&(letterbit('r')|letterbit('w')))) + fdp->statb = statb; + else + fstat(fd,&fdp->statb); + fdp->fd = fd; + fdp->name = strdup(argv[1]); + return(0); +} diff --git a/usr/src/lib/libshell/common/bltins/sleep.c b/usr/src/lib/libshell/common/bltins/sleep.c new file mode 100644 index 0000000000..2f52ca651c --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/sleep.c @@ -0,0 +1,190 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped +/* + * sleep delay + * + * David Korn + * AT&T Labs + * research!dgk + * + */ + +#define sleep ______sleep +#include "defs.h" +#undef sleep +#include +#include +#include "builtins.h" +#include "FEATURE/time" +#include "FEATURE/poll" +#ifdef _NEXT_SOURCE +# define sleep _ast_sleep +#endif /* _NEXT_SOURCE */ +#ifdef _lib_poll_notimer +# undef _lib_poll +#endif /* _lib_poll_notimer */ + +int b_sleep(register int argc,char *argv[],void *extra) +{ + register char *cp; + register double d; + register Shell_t *shp = (Shell_t*)extra; + time_t tloc = 0; + while((argc = optget(argv,sh_optsleep))) switch(argc) + { + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); + break; + } + argv += opt_info.index; + if(error_info.errors || !(cp= *argv) || !(strmatch(cp,e_numeric))) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + if((d=strtod(cp, (char**)0)) > .10) + { + sfsync(shp->outpool); + time(&tloc); + tloc += (time_t)(d+.5); + } + while(1) + { + time_t now; + errno = 0; + shp->lastsig=0; + sh_delay(d); + if(tloc==0 || errno!=EINTR || shp->lastsig) + break; + sh_sigcheck(); + if(tloc < (now=time(NIL(time_t*)))) + break; + d = (double)(tloc-now); + if(shp->sigflag[SIGALRM]&SH_SIGTRAP) + sh_timetraps(); + } + return(0); +} + +static void completed(void * handle) +{ + char *expired = (char*)handle; + *expired = 1; +} + +unsigned int sleep(unsigned int sec) +{ + pid_t newpid, curpid=getpid(); + void *tp; + char expired = 0; + sh.lastsig = 0; + tp = (void*)sh_timeradd(1000*sec, 0, completed, (void*)&expired); + do + { + if(!sh.waitevent || (*sh.waitevent)(-1,-1L,0)==0) + pause(); + if(sh.sigflag[SIGALRM]&SH_SIGTRAP) + sh_timetraps(); + if((newpid=getpid()) != curpid) + { + curpid = newpid; + sh.lastsig = 0; + sh.trapnote &= ~SH_SIGSET; + if(expired) + expired = 0; + else + timerdel(tp); + tp = (void*)sh_timeradd(1000*sec, 0, completed, (void*)&expired); + } + } + while(!expired && sh.lastsig==0); + if(!expired) + timerdel(tp); + sh_sigcheck(); + return(0); +} + +/* + * delay execution for time + */ + +void sh_delay(double t) +{ + register int n = (int)t; +#ifdef _lib_poll + struct pollfd fd; + if(t<=0) + return; + else if(n > 30) + { + sleep(n); + t -= n; + } + if(n=(int)(1000*t)) + { + if(!sh.waitevent || (*sh.waitevent)(-1,(long)n,0)==0) + poll(&fd,0,n); + } +#else +# if defined(_lib_select) && defined(_mem_tv_usec_timeval) + struct timeval timeloc; + if(t<=0) + return; + if(n=(int)(1000*t) && sh.waitevent && (*sh.waitevent)(-1,(long)n,0)) + return; + n = (int)t; + timeloc.tv_sec = n; + timeloc.tv_usec = 1000000*(t-(double)n); + select(0,(fd_set*)0,(fd_set*)0,(fd_set*)0,&timeloc); +# else +# ifdef _lib_select + /* for 9th edition machines */ + if(t<=0) + return; + if(n > 30) + { + sleep(n); + t -= n; + } + if(n=(int)(1000*t)) + { + if(!sh.waitevent || (*sh.waitevent)(-1,(long)n,0)==0) + select(0,(fd_set*)0,(fd_set*)0,n); + } +# else + struct tms tt; + if(t<=0) + return; + sleep(n); + t -= n; + if(t) + { + clock_t begin = times(&tt); + if(begin==0) + return; + t *= sh.lim.clk_tck; + n += (t+.5); + while((times(&tt)-begin) < n); + } +# endif +# endif +#endif /* _lib_poll */ +} diff --git a/usr/src/lib/libshell/common/bltins/test.c b/usr/src/lib/libshell/common/bltins/test.c new file mode 100644 index 0000000000..f21db8a75c --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/test.c @@ -0,0 +1,629 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped +/* + * test expression + * [ expression ] + * + * David Korn + * AT&T Labs + * + */ + + +#include "defs.h" +#include +#include +#include +#include "io.h" +#include "terminal.h" +#include "test.h" +#include "builtins.h" +#include "FEATURE/externs" +#include "FEATURE/poll" +#include + +#if !_lib_setregid +# undef _lib_setreuid +#endif /* _lib_setregid */ + +#ifdef S_ISSOCK +# if _pipe_socketpair +# if _socketpair_shutdown_mode +# define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)||S_ISSOCK((p)->st_mode)&&(p)->st_ino&&((p)->st_mode&(S_IRUSR|S_IWUSR))!=(S_IRUSR|S_IWUSR)) +# else +# define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)||S_ISSOCK((p)->st_mode)&&(p)->st_ino) +# endif +# else +# define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)||S_ISSOCK((p)->st_mode)&&(p)->st_ino) +# endif +# define isasock(f,p) (test_stat(f,p)>=0&&S_ISSOCK((p)->st_mode)) +#else +# define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)) +# define isasock(f,p) (0) +#endif + +#define permission(a,f) (sh_access(a,f)==0) +static time_t test_time(const char*, const char*); +static int test_stat(const char*, struct stat*); +static int test_mode(const char*); + +/* single char string compare */ +#define c_eq(a,c) (*a==c && *(a+1)==0) +/* two character string compare */ +#define c2_eq(a,c1,c2) (*a==c1 && *(a+1)==c2 && *(a+2)==0) + +struct test +{ + Shell_t *sh; + int ap; + int ac; + char **av; +}; + +static char *nxtarg(struct test*,int); +static int expr(struct test*,int); +static int e3(struct test*); + +static int test_strmatch(const char *str, const char *pat) +{ + int match[2*(MATCH_MAX+1)],n; + register int c, m=0; + register const char *cp=pat; + while(c = *cp++) + { + if(c=='(') + m++; + if(c=='\\' && *cp) + cp++; + } + if(m) + m++; + else + match[0] = 0; + if(m > elementsof(match)/2) + m = elementsof(match)/2; + n = strgrpmatch(str, pat, match, m, STR_MAXIMAL|STR_LEFT|STR_RIGHT); + if(m==0 && n==1) + match[1] = strlen(str); + if(n) + sh_setmatch(str, -1, n, match); + return(n); +} + +int b_test(int argc, char *argv[],void *extra) +{ + struct test tdata; + register char *cp = argv[0]; + register int not; + tdata.sh = (Shell_t*)extra; + tdata.av = argv; + tdata.ap = 1; + if(c_eq(cp,'[')) + { + cp = argv[--argc]; + if(!c_eq(cp, ']')) + errormsg(SH_DICT,ERROR_exit(2),e_missing,"']'"); + } + if(argc <= 1) + return(1); + cp = argv[1]; + not = c_eq(cp,'!'); + /* posix portion for test */ + switch(argc) + { + case 5: + if(!not) + break; + argv++; + /* fall through */ + case 4: + { + register int op = sh_lookup(cp=argv[2],shtab_testops); + if(op&TEST_BINOP) + break; + if(!op) + { + if(argc==5) + break; + if(not && cp[0]=='-' && cp[2]==0) + return(test_unop(cp[1],argv[3])!=0); + else if(argv[1][0]=='-' && argv[1][2]==0) + return(!test_unop(argv[1][1],cp)); + errormsg(SH_DICT,ERROR_exit(2),e_badop,cp); + } + return(test_binop(op,argv[1],argv[3])^(argc!=5)); + } + case 3: + if(not) + return(*argv[2]!=0); + if(cp[0] != '-' || cp[2] || cp[1]=='?') + { + if(cp[0]=='-' && (cp[1]=='-' || cp[1]=='?') && + strcmp(argv[2],"--")==0) + { + char *av[3]; + av[0] = argv[0]; + av[1] = argv[1]; + av[2] = 0; + optget(av,sh_opttest); + errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg); + return(2); + } + break; + } + return(!test_unop(cp[1],argv[2])); + case 2: + return(*cp==0); + } + if(argc==5) + argv--; + tdata.ac = argc; + return(!expr(&tdata,0)); +} + +/* + * evaluate a test expression. + * flag is 0 on outer level + * flag is 1 when in parenthesis + * flag is 2 when evaluating -a + */ +static int expr(struct test *tp,register int flag) +{ + register int r; + register char *p; + r = e3(tp); + while(tp->ap < tp->ac) + { + p = nxtarg(tp,0); + /* check for -o and -a */ + if(flag && c_eq(p,')')) + { + tp->ap--; + break; + } + if(*p=='-' && *(p+2)==0) + { + if(*++p == 'o') + { + if(flag==2) + { + tp->ap--; + break; + } + r |= expr(tp,3); + continue; + } + else if(*p == 'a') + { + r &= expr(tp,2); + continue; + } + } + if(flag==0) + break; + errormsg(SH_DICT,ERROR_exit(2),e_badsyntax); + } + return(r); +} + +static char *nxtarg(struct test *tp,int mt) +{ + if(tp->ap >= tp->ac) + { + if(mt) + { + tp->ap++; + return(0); + } + errormsg(SH_DICT,ERROR_exit(2),e_argument); + } + return(tp->av[tp->ap++]); +} + + +static int e3(struct test *tp) +{ + register char *arg, *cp; + register int op; + char *binop; + arg=nxtarg(tp,0); + if(arg && c_eq(arg, '!')) + return(!e3(tp)); + if(c_eq(arg, '(')) + { + op = expr(tp,1); + cp = nxtarg(tp,0); + if(!cp || !c_eq(cp, ')')) + errormsg(SH_DICT,ERROR_exit(2),e_missing,"')'"); + return(op); + } + cp = nxtarg(tp,1); + if(cp!=0 && (c_eq(cp,'=') || c2_eq(cp,'!','='))) + goto skip; + if(c2_eq(arg,'-','t')) + { + if(cp && isdigit(*cp)) + return(*(cp+1)?0:tty_check(*cp-'0')); + else + { + /* test -t with no arguments */ + tp->ap--; + return(tty_check(1)); + } + } + if(*arg=='-' && arg[2]==0) + { + op = arg[1]; + if(!cp) + { + /* for backward compatibility with new flags */ + if(op==0 || !strchr(test_opchars+10,op)) + return(1); + errormsg(SH_DICT,ERROR_exit(2),e_argument); + } + if(strchr(test_opchars,op)) + return(test_unop(op,cp)); + } + if(!cp) + { + tp->ap--; + return(*arg!=0); + } +skip: + op = sh_lookup(binop=cp,shtab_testops); + if(!(op&TEST_BINOP)) + cp = nxtarg(tp,0); + if(!op) + errormsg(SH_DICT,ERROR_exit(2),e_badop,binop); + if(op==TEST_AND | op==TEST_OR) + tp->ap--; + return(test_binop(op,arg,cp)); +} + +int test_unop(register int op,register const char *arg) +{ + struct stat statb; + int f; + switch(op) + { + case 'r': + return(permission(arg, R_OK)); + case 'w': + return(permission(arg, W_OK)); + case 'x': + return(permission(arg, X_OK)); + case 'V': +#if SHOPT_FS_3D + { + register int offset = staktell(); + if(stat(arg,&statb)<0 || !S_ISREG(statb.st_mode)) + return(0); + /* add trailing / */ + stakputs(arg); + stakputc('/'); + stakputc(0); + arg = (const char*)stakptr(offset); + stakseek(offset); + /* FALL THRU */ + } +#else + return(0); +#endif /* SHOPT_FS_3D */ + case 'd': + return(test_stat(arg,&statb)>=0 && S_ISDIR(statb.st_mode)); + case 'c': + return(test_stat(arg,&statb)>=0 && S_ISCHR(statb.st_mode)); + case 'b': + return(test_stat(arg,&statb)>=0 && S_ISBLK(statb.st_mode)); + case 'f': + return(test_stat(arg,&statb)>=0 && S_ISREG(statb.st_mode)); + case 'u': + return(test_mode(arg)&S_ISUID); + case 'g': + return(test_mode(arg)&S_ISGID); + case 'k': +#ifdef S_ISVTX + return(test_mode(arg)&S_ISVTX); +#else + return(0); +#endif /* S_ISVTX */ +#if SHOPT_TEST_L + case 'l': +#endif + case 'L': + case 'h': /* undocumented, and hopefully will disappear */ + if(*arg==0 || arg[strlen(arg)-1]=='/' || lstat(arg,&statb)<0) + return(0); + return(S_ISLNK(statb.st_mode)); + + case 'C': +#ifdef S_ISCTG + return(test_stat(arg,&statb)>=0 && S_ISCTG(statb.st_mode)); +#else + return(0); +#endif /* S_ISCTG */ + case 'H': +#ifdef S_ISCDF + { + register int offset = staktell(); + if(test_stat(arg,&statb)>=0 && S_ISCDF(statb.st_mode)) + return(1); + stakputs(arg); + stakputc('+'); + stakputc(0); + arg = (const char*)stakptr(offset); + stakseek(offset); + return(test_stat(arg,&statb)>=0 && S_ISCDF(statb.st_mode)); + } +#else + return(0); +#endif /* S_ISCDF */ + + case 'S': + return(isasock(arg,&statb)); + case 'N': + return(test_stat(arg,&statb)>=0 && tmxgetmtime(&statb) > tmxgetatime(&statb)); + case 'p': + return(isapipe(arg,&statb)); + case 'n': + return(*arg != 0); + case 'z': + return(*arg == 0); + case 's': + sfsync(sfstdout); + case 'O': + case 'G': + if(*arg==0 || test_stat(arg,&statb)<0) + return(0); + if(op=='s') + return(statb.st_size>0); + else if(op=='O') + return(statb.st_uid==sh.userid); + return(statb.st_gid==sh.groupid); + case 'a': + case 'e': + return(permission(arg, F_OK)); + case 'o': + f=1; + if(*arg=='?') + return(sh_lookopt(arg+1,&f)>0); + op = sh_lookopt(arg,&f); + return(op && (f==(sh_isoption(op)!=0))); + case 't': + if(isdigit(*arg) && arg[1]==0) + return(tty_check(*arg-'0')); + return(0); + default: + { + static char a[3] = "-?"; + a[1]= op; + errormsg(SH_DICT,ERROR_exit(2),e_badop,a); + /* NOTREACHED */ + return(0); + } + } +} + +int test_binop(register int op,const char *left,const char *right) +{ + register double lnum,rnum; + if(op&TEST_ARITH) + { + while(*left=='0') + left++; + while(*right=='0') + right++; + lnum = sh_arith(left); + rnum = sh_arith(right); + } + switch(op) + { + /* op must be one of the following values */ + case TEST_AND: + case TEST_OR: + return(*left!=0); + case TEST_PEQ: + return(test_strmatch(left, right)); + case TEST_PNE: + return(!test_strmatch(left, right)); + case TEST_SGT: + return(strcoll(left, right)>0); + case TEST_SLT: + return(strcoll(left, right)<0); + case TEST_SEQ: + return(strcmp(left, right)==0); + case TEST_SNE: + return(strcmp(left, right)!=0); + case TEST_EF: + return(test_inode(left,right)); + case TEST_NT: + return(test_time(left,right)>0); + case TEST_OT: + return(test_time(left,right)<0); + case TEST_EQ: + return(lnum==rnum); + case TEST_NE: + return(lnum!=rnum); + case TEST_GT: + return(lnum>rnum); + case TEST_LT: + return(lnum=rnum); + case TEST_LE: + return(lnum<=rnum); + } + /* NOTREACHED */ + return(0); +} + +/* + * returns the modification time of f1 - modification time of f2 + */ + +static time_t test_time(const char *file1,const char *file2) +{ + Time_t t1, t2; + struct stat statb1,statb2; + int r=test_stat(file2,&statb2); + if(test_stat(file1,&statb1)<0) + return(r<0?0:-1); + if(r<0) + return(1); + t1 = tmxgetmtime(&statb1); + t2 = tmxgetmtime(&statb2); + if (t1 > t2) + return(1); + if (t1 < t2) + return(-1); + return(0); +} + +/* + * return true if inode of two files are the same + */ + +int test_inode(const char *file1,const char *file2) +{ + struct stat stat1,stat2; + if(test_stat(file1,&stat1)>=0 && test_stat(file2,&stat2)>=0) + if(stat1.st_dev == stat2.st_dev && stat1.st_ino == stat2.st_ino) + return(1); + return(0); +} + + +/* + * This version of access checks against effective uid/gid + * The static buffer statb is shared with test_mode. + */ + +int sh_access(register const char *name, register int mode) +{ + struct stat statb; + if(*name==0) + return(-1); + if(strmatch(name,(char*)e_devfdNN)) + return(sh_ioaccess((int)strtol(name+8, (char**)0, 10),mode)); + /* can't use access function for execute permission with root */ + if(mode==X_OK && sh.euserid==0) + goto skip; + if(sh.userid==sh.euserid && sh.groupid==sh.egroupid) + return(access(name,mode)); +#ifdef _lib_setreuid + /* swap the real uid to effective, check access then restore */ + /* first swap real and effective gid, if different */ + if(sh.groupid==sh.euserid || setregid(sh.egroupid,sh.groupid)==0) + { + /* next swap real and effective uid, if needed */ + if(sh.userid==sh.euserid || setreuid(sh.euserid,sh.userid)==0) + { + mode = access(name,mode); + /* restore ids */ + if(sh.userid!=sh.euserid) + setreuid(sh.userid,sh.euserid); + if(sh.groupid!=sh.egroupid) + setregid(sh.groupid,sh.egroupid); + return(mode); + } + else if(sh.groupid!=sh.egroupid) + setregid(sh.groupid,sh.egroupid); + } +#endif /* _lib_setreuid */ +skip: + if(test_stat(name, &statb) == 0) + { + if(mode == F_OK) + return(mode); + else if(sh.euserid == 0) + { + if(!S_ISREG(statb.st_mode) || mode!=X_OK) + return(0); + /* root needs execute permission for someone */ + mode = (S_IXUSR|S_IXGRP|S_IXOTH); + } + else if(sh.euserid == statb.st_uid) + mode <<= 6; + else if(sh.egroupid == statb.st_gid) + mode <<= 3; +#ifdef _lib_getgroups + /* on some systems you can be in several groups */ + else + { + static int maxgroups; + gid_t *groups; + register int n; + if(maxgroups==0) + { + /* first time */ + if((maxgroups=getgroups(0,(gid_t*)0)) <= 0) + { + /* pre-POSIX system */ + maxgroups=NGROUPS_MAX; + } + } + groups = (gid_t*)stakalloc((maxgroups+1)*sizeof(gid_t)); + n = getgroups(maxgroups,groups); + while(--n >= 0) + { + if(groups[n] == statb.st_gid) + { + mode <<= 3; + break; + } + } + } +# endif /* _lib_getgroups */ + if(statb.st_mode & mode) + return(0); + } + return(-1); +} + +/* + * Return the mode bits of file + * If is null, then the previous stat buffer is used. + * The mode bits are zero if the file doesn't exist. + */ + +static int test_mode(register const char *file) +{ + struct stat statb; + if(file && (*file==0 || test_stat(file,&statb)<0)) + return(0); + return(statb.st_mode); +} + +/* + * do an fstat() for /dev/fd/n, otherwise stat() + */ +static int test_stat(const char *name,struct stat *buff) +{ + if(*name==0) + { + errno = ENOENT; + return(-1); + } + if(strmatch(name,(char*)e_devfdNN)) + return(fstat((int)strtol(name+8, (char**)0, 10),buff)); + else + return(stat(name,buff)); +} diff --git a/usr/src/lib/libshell/common/bltins/trap.c b/usr/src/lib/libshell/common/bltins/trap.c new file mode 100644 index 0000000000..7197144d5e --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/trap.c @@ -0,0 +1,347 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped +/* + * trap [-p] action sig... + * kill [-l] [sig...] + * kill [-s sig] pid... + * + * David Korn + * AT&T Labs + * research!dgk + * + */ + +#include "defs.h" +#include +#include "jobs.h" +#include "builtins.h" + +#define L_FLAG 1 +#define S_FLAG 2 + +static const char trapfmt[] = "trap -- %s %s\n"; + +static int sig_number(const char*); +static void sig_list(Shell_t*,int); + +int b_trap(int argc,char *argv[],void *extra) +{ + register char *arg = argv[1]; + register int sig, pflag = 0; + register Shell_t *shp = (Shell_t*)extra; + NOT_USED(argc); + while (sig = optget(argv, sh_opttrap)) switch (sig) + { + case 'p': + pflag=1; + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); + return(2); + break; + } + argv += opt_info.index; + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0)); + if(arg = *argv) + { + register int clear; + char *action = arg; + if(!pflag) + { + /* first argument all digits or - means clear */ + while(isdigit(*arg)) + arg++; + clear = (arg!=action && *arg==0); + if(!clear) + { + ++argv; + if(*action=='-' && action[1]==0) + clear++; + } + while(!argv[0]) + errormsg(SH_DICT,ERROR_exit(1),e_condition); + } + while(arg = *argv++) + { + sig = sig_number(arg); + if(sig<0) + { + errormsg(SH_DICT,2,e_trap,arg); + return(1); + } + /* internal traps */ + if(sig&SH_TRAP) + { + sig &= ~SH_TRAP; + if(sig>SH_DEBUGTRAP) + { + errormsg(SH_DICT,2,e_trap,arg); + return(1); + } + if(pflag) + { + if(arg=shp->st.trap[sig]) + sfputr(sfstdout,sh_fmtq(arg),'\n'); + continue; + } + if(shp->st.trap[sig]) + free(shp->st.trap[sig]); + shp->st.trap[sig] = 0; + if(!clear && *action) + shp->st.trap[sig] = strdup(action); + if(sig == SH_DEBUGTRAP) + { + if(shp->st.trap[sig]) + shp->trapnote |= SH_SIGTRAP; + else + shp->trapnote = 0; + } + continue; + } + if(sig>shp->sigmax) + { + errormsg(SH_DICT,2,e_trap,arg); + return(1); + } + else if(pflag) + { + char **trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom); + if(arg=trapcom[sig]) + sfputr(sfstdout,arg,'\n'); + } + else if(clear) + sh_sigclear(sig); + else + { + if(sig >= shp->st.trapmax) + shp->st.trapmax = sig+1; + if(arg=shp->st.trapcom[sig]) + free(arg); + shp->st.trapcom[sig] = strdup(action); + sh_sigtrap(sig); + } + } + } + else /* print out current traps */ + sig_list(shp,-1); + return(0); +} + +int b_kill(int argc,char *argv[],void *extra) +{ + register char *signame; + register int sig=SIGTERM, flag=0, n; + register Shell_t *shp = (Shell_t*)extra; + NOT_USED(argc); + while((n = optget(argv,sh_optkill))) switch(n) + { + case ':': + if((signame=argv[opt_info.index++]) && (sig=sig_number(signame+1))>=0) + goto endopts; + opt_info.index--; + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case 'n': + sig = (int)opt_info.num; + goto endopts; + case 's': + flag |= S_FLAG; + signame = opt_info.arg; + goto endopts; + case 'l': + flag |= L_FLAG; + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); + break; + } +endopts: + argv += opt_info.index; + if(*argv && strcmp(*argv,"--")==0 && strcmp(*(argv-1),"--")!=0) + argv++; + if(error_info.errors || flag==(L_FLAG|S_FLAG) || (!(*argv) && !(flag&L_FLAG))) + errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0)); + /* just in case we send a kill -9 $$ */ + sfsync(sfstderr); + if(flag&L_FLAG) + { + if(!(*argv)) + sig_list(shp,0); + else while(signame = *argv++) + { + if(isdigit(*signame)) + sig_list(shp,((int)strtol(signame, (char**)0, 10)&0177)+1); + else + { + if((sig=sig_number(signame))<0) + { + shp->exitval = 2; + errormsg(SH_DICT,ERROR_exit(1),e_nosignal,signame); + } + sfprintf(sfstdout,"%d\n",sig); + } + } + return(shp->exitval); + } + if(flag&S_FLAG) + { + if((sig=sig_number(signame)) < 0 || sig > shp->sigmax) + errormsg(SH_DICT,ERROR_exit(1),e_nosignal,signame); + } + if(job_walk(sfstdout,job_kill,sig,argv)) + shp->exitval = 1; + return(shp->exitval); +} + +/* + * Given the name or number of a signal return the signal number + */ + +static int sig_number(const char *string) +{ + const Shtable_t *tp; + register int n,sig=0; + char *last; + if(isdigit(*string)) + { + n = strtol(string,&last,10); + if(*last) + n = -1; + } + else + { + register int c; + n = staktell(); + do + { + c = *string++; + if(islower(c)) + c = toupper(c); + stakputc(c); + } + while(c); + stakseek(n); + if(memcmp(stakptr(n),"SIG",3)==0) + { + sig = 1; + n += 3; + } + tp = sh_locate(stakptr(n),(const Shtable_t*)shtab_signals,sizeof(*shtab_signals)); + n = tp->sh_number; + if(sig==1 && (n>=(SH_TRAP-1) && n < (1<sh_name)==0) + n = tp->sh_number; + } + n &= (1< is positive, then print signal name corresponding to + * if is zero, then print all signal names + * if is negative, then print all traps + */ +static void sig_list(register Shell_t *shp,register int flag) +{ + register const struct shtable2 *tp; + register int sig = shp->sigmax+1; + const char *names[SH_TRAP]; + const char *traps[SH_DEBUGTRAP+1]; + tp=shtab_signals; + if(flag==0) + { + /* not all signals may be defined, so initialize */ + while(--sig >= 0) + names[sig] = 0; + for(sig=SH_DEBUGTRAP; sig>=0; sig--) + traps[sig] = 0; + } + while(*tp->sh_name) + { + sig = tp->sh_number; + sig &= ((1<sh_name); + return; + } + else if(sig&SH_TRAP) + traps[sig&~SH_TRAP] = (char*)tp->sh_name; + else if(sig < sizeof(names)/sizeof(char*)) + names[sig] = (char*)tp->sh_name; + tp++; + } + if(flag > 0) + sfprintf(sfstdout,"%d\n",flag-1); + else if(flag<0) + { + /* print the traps */ + register char *trap,*sname,**trapcom; + char name[6]; + sig = shp->st.trapmax; + /* use parent traps if otrapcom is set (for $(trap) */ + trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom); + while(--sig >= 0) + { + if(!(trap=trapcom[sig])) + continue; + if(!(sname=(char*)names[sig+1])) + { + sname = name; + sname[0] = 'S'; + sname[1] = 'I'; + sname[2] = 'G'; + sname[3] = (sig/10)+'0'; + sname[4] = (sig%10)+'0'; + } + sfprintf(sfstdout,trapfmt,sh_fmtq(trap),sname); + } + for(sig=SH_DEBUGTRAP; sig>=0; sig--) + { + if(!(trap=shp->st.trap[sig])) + continue; + sfprintf(sfstdout,trapfmt,sh_fmtq(trap),traps[sig]); + } + } + else + { + /* print all the signal names */ + for(sig=2; sig <= shp->sigmax; sig++) + { + if(names[sig]) + sfputr(sfstdout,names[sig],'\n'); + else + sfprintf(sfstdout,"SIG%d\n",sig-1); + } + } +} + diff --git a/usr/src/lib/libshell/common/bltins/typeset.c b/usr/src/lib/libshell/common/bltins/typeset.c new file mode 100644 index 0000000000..14b02a6ad3 --- /dev/null +++ b/usr/src/lib/libshell/common/bltins/typeset.c @@ -0,0 +1,979 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn * +* * +***********************************************************************/ +#pragma prototyped +/* + * export [-p] [arg...] + * readonly [-p] [arg...] + * typeset [options] [arg...] + * alias [-ptx] [arg...] + * unalias [arg...] + * builtin [-sd] [-f file] [name...] + * set [options] [name...] + * unset [-fnv] [name...] + * + * David Korn + * AT&T Labs + * + */ + +#include "defs.h" +#include +#include "path.h" +#include "name.h" +#include "history.h" +#include "builtins.h" +#include "variables.h" +#include + +struct tdata +{ + Shell_t *sh; + Namval_t *tp; + Sfio_t *outfile; + char *prefix; + int aflag; + int argnum; + int scanmask; + Dt_t *scanroot; + char **argnam; +}; + + +static int print_namval(Sfio_t*, Namval_t*, int, struct tdata*); +static void print_attribute(Namval_t*,void*); +static void print_all(Sfio_t*, Dt_t*, struct tdata*); +static void print_scan(Sfio_t*, int, Dt_t*, int, struct tdata*t); +static int b_unall(int, char**, Dt_t*, Shell_t*); +static int b_common(char**, int, Dt_t*, struct tdata*); +static void pushname(Namval_t*,void*); +static void(*nullscan)(Namval_t*,void*); + +static Namval_t *load_class(const char *name) +{ + errormsg(SH_DICT,ERROR_exit(1),"%s: type not loadable",name); + return(0); +} + +/* + * Note export and readonly are the same + */ +#if 0 + /* for the dictionary generator */ + int b_export(int argc,char *argv[],void *extra){} +#endif +int b_readonly(int argc,char *argv[],void *extra) +{ + register int flag; + char *command = argv[0]; + struct tdata tdata; + NOT_USED(argc); + memset((void*)&tdata,0,sizeof(tdata)); + tdata.sh = (Shell_t*)extra; + tdata.aflag = '-'; + while((flag = optget(argv,*command=='e'?sh_optexport:sh_optreadonly))) switch(flag) + { + case 'p': + tdata.prefix = command; + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); + return(2); + } + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*))); + argv += (opt_info.index-1); + if(*command=='r') + flag = (NV_ASSIGN|NV_RDONLY|NV_VARNAME); +#ifdef _ENV_H + else if(!argv[1]) + { + char *cp,**env=env_get(tdata.sh->env); + while(cp = *env++) + { + if(tdata.prefix) + sfputr(sfstdout,tdata.prefix,' '); + sfprintf(sfstdout,"%s\n",sh_fmtq(cp)); + } + return(0); + } +#endif + else + { + flag = (NV_ASSIGN|NV_EXPORT|NV_IDENT); + if(!sh.prefix) + sh.prefix = ""; + } + return(b_common(argv,flag,tdata.sh->var_tree, &tdata)); +} + + +int b_alias(int argc,register char *argv[],void *extra) +{ + register unsigned flag = NV_NOARRAY|NV_NOSCOPE|NV_ASSIGN; + register Dt_t *troot; + register int n; + struct tdata tdata; + NOT_USED(argc); + memset((void*)&tdata,0,sizeof(tdata)); + tdata.sh = (Shell_t*)extra; + troot = tdata.sh->alias_tree; + if(*argv[0]=='h') + flag = NV_TAGGED; + if(argv[1]) + { + opt_info.offset = 0; + opt_info.index = 1; + *opt_info.option = 0; + tdata.argnum = 0; + tdata.aflag = *argv[1]; + while((n = optget(argv,sh_optalias))) switch(n) + { + case 'p': + tdata.prefix = argv[0]; + break; + case 't': + flag |= NV_TAGGED; + break; + case 'x': + flag |= NV_EXPORT; + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); + return(2); + } + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); + argv += (opt_info.index-1); + if(flag&NV_TAGGED) + { + if(argv[1] && strcmp(argv[1],"-r")==0) + { + /* hack to handle hash -r */ + nv_putval(PATHNOD,nv_getval(PATHNOD),NV_RDONLY); + return(0); + } + troot = tdata.sh->track_tree; + } + } + return(b_common(argv,flag,troot,&tdata)); +} + + +#if 0 + /* for the dictionary generator */ + int b_local(int argc,char *argv[],void *extra){} +#endif +int b_typeset(int argc,register char *argv[],void *extra) +{ + register int flag = NV_VARNAME|NV_ASSIGN; + register int n; + struct tdata tdata; + Namtype_t *ntp = (Namtype_t*)extra; + Dt_t *troot; + int isfloat=0, shortint=0; + NOT_USED(argc); + memset((void*)&tdata,0,sizeof(tdata)); + tdata.sh = ntp->shp; + tdata.tp = ntp->np; + troot = tdata.sh->var_tree; + opt_info.disc = (Optdisc_t*)ntp->optinfof; + while((n = optget(argv,ntp->optstring))) + { + switch(n) + { + case 'a': + flag |= NV_IARRAY; + break; + case 'A': + flag |= NV_ARRAY; + break; + case 'E': + /* The following is for ksh88 compatibility */ + if(opt_info.offset && !strchr(argv[opt_info.index],'E')) + { + tdata.argnum = (int)opt_info.num; + break; + } + case 'F': + if(!opt_info.arg || (tdata.argnum = opt_info.num) <0) + tdata.argnum = 10; + isfloat = 1; + if(n=='E') + flag |= NV_EXPNOTE; + break; + case 'b': + flag |= NV_BINARY; + break; + case 'n': + flag &= ~NV_VARNAME; + flag |= (NV_REF|NV_IDENT); + break; + case 'H': + flag |= NV_HOST; + break; + case 'T': + flag |= NV_TYPE; + tdata.prefix = opt_info.arg; + break; + case 'L': + if(tdata.argnum==0) + tdata.argnum = (int)opt_info.num; + if(tdata.argnum < 0) + errormsg(SH_DICT,ERROR_exit(1), e_badfield, tdata.argnum); + flag &= ~NV_RJUST; + flag |= NV_LJUST; + break; + case 'Z': + flag |= NV_ZFILL; + /* FALL THRU*/ + case 'R': + if(tdata.argnum==0) + tdata.argnum = (int)opt_info.num; + if(tdata.argnum < 0) + errormsg(SH_DICT,ERROR_exit(1), e_badfield, tdata.argnum); + flag &= ~NV_LJUST; + flag |= NV_RJUST; + break; + case 'f': + flag &= ~(NV_VARNAME|NV_ASSIGN); + troot = tdata.sh->fun_tree; + break; + case 'i': + if(!opt_info.arg || (tdata.argnum = opt_info.num) <0) + tdata.argnum = 10; + flag |= NV_INTEGER; + break; + case 'l': + flag |= NV_UTOL; + break; + case 'p': + tdata.prefix = argv[0]; + continue; + case 'r': + flag |= NV_RDONLY; + break; + case 's': + shortint=1; + break; + case 't': + flag |= NV_TAGGED; + break; + case 'u': + flag |= NV_LTOU; + break; + case 'x': + flag &= ~NV_VARNAME; + flag |= (NV_EXPORT|NV_IDENT); + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); + opt_info.disc = 0; + return(2); + } + if(tdata.aflag==0) + tdata.aflag = *opt_info.option; + } + argv += opt_info.index; + opt_info.disc = 0; + /* handle argument of + and - specially */ + if(*argv && argv[0][1]==0 && (*argv[0]=='+' || *argv[0]=='-')) + tdata.aflag = *argv[0]; + else + argv--; + if((flag&NV_INTEGER) && (flag&(NV_LJUST|NV_RJUST|NV_ZFILL))) + error_info.errors++; + if((flag&NV_BINARY) && (flag&(NV_LJUST|NV_UTOL|NV_LTOU))) + error_info.errors++; + if(troot==tdata.sh->fun_tree && ((isfloat || flag&~(NV_FUNCT|NV_TAGGED|NV_EXPORT|NV_LTOU)))) + error_info.errors++; + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*))); + if(isfloat) + flag |= NV_INTEGER|NV_DOUBLE; + if(shortint) + flag |= NV_SHORT|NV_INTEGER; + if(tdata.sh->fn_depth) + flag |= NV_NOSCOPE; + if(flag&NV_TYPE) + { + int offset = staktell(); + stakputs(NV_CLASS); + if(NV_CLASS[sizeof(NV_CLASS)-2]!='.') + stakputc('.'); + stakputs(tdata.prefix); + stakputc(0); + tdata.tp = nv_open(stakptr(offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN); + stakseek(offset); + if(!tdata.tp) + errormsg(SH_DICT,ERROR_exit(1),"%s: unknown type",tdata.prefix); + flag &= ~NV_TYPE; + } + else if(tdata.aflag==0 && ntp->np) + tdata.aflag = '-'; + return(b_common(argv,flag,troot,&tdata)); +} + +static int b_common(char **argv,register int flag,Dt_t *troot,struct tdata *tp) +{ + register char *name; + char *last = 0; + int nvflags=(flag&(NV_ARRAY|NV_NOARRAY|NV_VARNAME|NV_IDENT|NV_ASSIGN)); + int r=0, ref=0; + Shell_t *shp =tp->sh; + if(!sh.prefix) + nvflags |= NV_NOSCOPE; + else if(*sh.prefix==0) + sh.prefix = 0; + flag &= ~(NV_NOARRAY|NV_NOSCOPE|NV_VARNAME|NV_IDENT); + if(argv[1]) + { + if(flag&NV_REF) + { + flag &= ~NV_REF; + ref=1; + if(tp->aflag!='-') + nvflags |= NV_NOREF; + } + while(name = *++argv) + { + register unsigned newflag; + register Namval_t *np; + unsigned curflag; + if(troot == shp->fun_tree) + { + /* + *functions can be exported or + * traced but not set + */ + flag &= ~NV_ASSIGN; + if(flag&NV_LTOU) + { + /* Function names cannot be special builtin */ + if((np=nv_search(name,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC)) + errormsg(SH_DICT,ERROR_exit(1),e_badfun,name); + np = nv_open(name,shp->fun_tree,NV_NOARRAY|NV_IDENT|NV_NOSCOPE); + } + else + np = nv_search(name,shp->fun_tree,HASH_NOSCOPE); + if(np && ((flag&NV_LTOU) || !nv_isnull(np) || nv_isattr(np,NV_LTOU))) + { + if(flag==0) + { + print_namval(sfstdout,np,tp->aflag=='+',tp); + continue; + } + if(shp->subshell) + sh_subfork(); + if(tp->aflag=='-') + nv_onattr(np,flag|NV_FUNCTION); + else if(tp->aflag=='+') + nv_offattr(np,flag); + } + else + r++; + continue; + } + np = nv_open(name,troot,nvflags); + /* tracked alias */ + if(troot==shp->track_tree && tp->aflag=='-') + { +#ifdef PATH_BFPATH + path_alias(np,path_absolute(nv_name(np),NIL(Pathcomp_t*))); +#else + nv_onattr(np,NV_NOALIAS); + path_alias(np,path_absolute(nv_name(np),NIL(char*))); +#endif + continue; + } + if(flag==NV_ASSIGN && !ref && tp->aflag!='-' && !strchr(name,'=')) + { + if(troot!=shp->var_tree && (nv_isnull(np) || !print_namval(sfstdout,np,0,tp))) + { + sfprintf(sfstderr,sh_translate(e_noalias),name); + r++; + } + continue; + } + if(tp->tp) + { + nv_settype(np,tp->tp,tp->aflag=='-'?0:NV_APPEND); + flag = (np->nvflag&NV_NOCHANGE); + } + if(troot==shp->var_tree && (flag&NV_IARRAY)) + { + flag &= ~NV_IARRAY; + if(nv_isnull(np)) + nv_onattr(np,NV_ARRAY); + else + nv_putsub(np, (char*)0, 0); + } + if(troot==shp->var_tree && (nvflags&NV_ARRAY)) + nv_setarray(np,nv_associative); + curflag = np->nvflag; + flag &= ~NV_ASSIGN; + if(last=strchr(name,'=')) + *last = 0; + if (tp->aflag == '-') + { + if((flag&NV_EXPORT) && strchr(name,'.')) + errormsg(SH_DICT,ERROR_exit(1),e_badexport,name); +#if SHOPT_BSH + if(flag&NV_EXPORT) + nv_offattr(np,NV_IMPORT); +#endif /* SHOPT_BSH */ + newflag = curflag; + if(flag&~NV_NOCHANGE) + newflag &= NV_NOCHANGE; + newflag |= flag; + if (flag & (NV_LJUST|NV_RJUST)) + { + if(!(flag&NV_RJUST)) + newflag &= ~NV_RJUST; + + else if(!(flag&NV_LJUST)) + newflag &= ~NV_LJUST; + } + if (flag & NV_UTOL) + newflag &= ~NV_LTOU; + else if (flag & NV_LTOU) + newflag &= ~NV_UTOL; + } + else + { + if((flag&NV_RDONLY) && (curflag&NV_RDONLY)) + errormsg(SH_DICT,ERROR_exit(1),e_readonly,nv_name(np)); + newflag = curflag & ~flag; + } + if (tp->aflag && (tp->argnum>0 || (curflag!=newflag))) + { + if(shp->subshell) + sh_assignok(np,1); + if(troot!=shp->var_tree) + nv_setattr(np,newflag&~NV_ASSIGN); + else + { + char *oldname=0; + if(tp->argnum==1 && newflag==NV_INTEGER && nv_isattr(np,NV_INTEGER)) + tp->argnum = 10; + /* use reference name for export */ + if((newflag^curflag)&NV_EXPORT) + { + oldname = np->nvname; + np->nvname = name; + } + nv_newattr (np, newflag&~NV_ASSIGN,tp->argnum); + if(oldname) + np->nvname = oldname; + } + } + if(last) + *last = '='; + /* set or unset references */ + if(ref) + { + if(tp->aflag=='-') + { + Dt_t *hp=0; + if(nv_isattr(np,NV_PARAM) && shp->st.prevst) + { + if(!(hp=(Dt_t*)shp->st.prevst->save_tree)) + hp = dtvnext(shp->var_tree); + } + nv_setref(np,hp,NV_VARNAME); + } + else + nv_unref(np); + } + nv_close(np); + } + } + else if(!sh.envlist) + { + if(tp->aflag) + { + if(troot==shp->fun_tree) + { + flag |= NV_FUNCTION; + tp->prefix = 0; + } + else if(troot==shp->var_tree) + flag |= (nvflags&NV_ARRAY); + print_scan(sfstdout,flag,troot,tp->aflag=='+',tp); + } + else if(troot==shp->alias_tree) + print_scan(sfstdout,0,troot,0,tp); + else + print_all(sfstdout,troot,tp); + sfsync(sfstdout); + } + return(r); +} + +typedef void (*Iptr_t)(int); +typedef int (*Fptr_t)(int, char*[], void*); + +#define GROWLIB 4 + +static void** liblist; +static int nlib; +static int maxlib; + +/* + * This allows external routines to load from the same library */ +void **sh_getliblist(void) +{ + return(liblist); +} + +/* + * add library to loaded list + * call (*lib_init)() on first load if defined + * always move to head of search list + * return: 0: already loaded 1: first load + */ +int sh_addlib(void* library) +{ + register int n; + register int r; + Iptr_t initfn; + + for (n = r = 0; n < nlib; n++) + { + if (r) + liblist[n-1] = liblist[n]; + else if (liblist[n] == library) + r++; + } + if (r) + nlib--; + else if ((initfn = (Iptr_t)dlllook(library, "lib_init"))) + (*initfn)(0); + if (nlib >= maxlib) + { + maxlib += GROWLIB; + if (liblist) + liblist = (void**)realloc((void*)liblist, (maxlib+1)*sizeof(void**)); + else + liblist = (void**)malloc((maxlib+1)*sizeof(void**)); + } + liblist[nlib++] = library; + liblist[nlib] = 0; + return !r; +} + +/* + * add change or list built-ins + * adding builtins requires dlopen() interface + */ +int b_builtin(int argc,char *argv[],void *extra) +{ + register char *arg=0, *name; + register int n, r=0, flag=0; + register Namval_t *np; + long dlete=0; + struct tdata tdata; + Fptr_t addr; + void *library=0; + char *errmsg; + NOT_USED(argc); + tdata.sh = (Shell_t*)extra; + while (n = optget(argv,sh_optbuiltin)) switch (n) + { + case 's': + flag = BLT_SPC; + break; + case 'd': + dlete=1; + break; + case 'f': +#if SHOPT_DYNAMIC + arg = opt_info.arg; +#else + errormsg(SH_DICT,2, "adding built-ins not supported"); + error_info.errors++; +#endif /* SHOPT_DYNAMIC */ + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); + break; + } + argv += opt_info.index; + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*))); + if(arg || *argv) + { + if(sh_isoption(SH_RESTRICTED)) + errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[-opt_info.index]); + if(sh_isoption(SH_PFSH)) + errormsg(SH_DICT,ERROR_exit(1),e_pfsh,argv[-opt_info.index]); + if(tdata.sh->subshell) + sh_subfork(); + } + if(arg) + { +#ifdef _hdr_dlldefs +#if (_AST_VERSION>=20040404) + if(!(library = dllplug(SH_ID,arg,NIL(char*),RTLD_LAZY,NIL(char*),0))) +#else + if(!(library = dllfind(arg,NIL(char*),RTLD_LAZY,NIL(char*),0))) +#endif +#else + if(!(library = dlopen(arg,DL_MODE))) +#endif + { + errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dlerror()); + return(1); + } + sh_addlib(library); + } + else if(*argv==0 && !dlete) + { + print_scan(sfstdout, flag, tdata.sh->bltin_tree, 1, &tdata); + return(0); + } + r = 0; + flag = staktell(); + while(arg = *argv) + { + name = path_basename(arg); + stakputs("b_"); + stakputs(name); + errmsg = 0; + addr = 0; + for(n=(nlib?nlib:dlete); --n>=0;) + { + /* (char*) added for some sgi-mips compilers */ + if(dlete || (addr = (Fptr_t)dlllook(liblist[n],stakptr(flag)))) + { + if(np = sh_addbuiltin(arg, addr,pointerof(dlete))) + { + if(dlete || nv_isattr(np,BLT_SPC)) + errmsg = "restricted name"; + } + break; + } + } + if(!dlete && !addr) + { + np = sh_addbuiltin(arg, 0 ,0); + if(np && nv_isattr(np,BLT_SPC)) + errmsg = "restricted name"; + else if(!np) + errmsg = "not found"; + } + if(errmsg) + { + errormsg(SH_DICT,ERROR_exit(0),"%s: %s",*argv,errmsg); + r = 1; + } + stakseek(flag); + argv++; + } + return(r); +} + +int b_set(int argc,register char *argv[],void *extra) +{ + struct tdata tdata; + memset(&tdata,0,sizeof(tdata)); + tdata.sh = (Shell_t*)extra; + tdata.prefix=0; + if(argv[1]) + { + if(sh_argopts(argc,argv) < 0) + return(2); + if(sh_isoption(SH_VERBOSE)) + sh_onstate(SH_VERBOSE); + else + sh_offstate(SH_VERBOSE); + if(sh_isoption(SH_MONITOR)) + sh_onstate(SH_MONITOR); + else + sh_offstate(SH_MONITOR); + } + else + /*scan name chain and print*/ + print_scan(sfstdout,0,tdata.sh->var_tree,0,&tdata); + return(0); +} + +/* + * The removing of Shell variable names, aliases, and functions + * is performed here. + * Unset functions with unset -f + * Non-existent items being deleted give non-zero exit status + */ + +int b_unalias(int argc,register char *argv[],void *extra) +{ + Shell_t *shp = (Shell_t*)extra; + return(b_unall(argc,argv,shp->alias_tree,shp)); +} + +int b_unset(int argc,register char *argv[],void *extra) +{ + Shell_t *shp = (Shell_t*)extra; + return(b_unall(argc,argv,shp->var_tree,shp)); +} + +static int b_unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp) +{ + register Namval_t *np; + register const char *name; + register int r; + int nflag=0,all=0,isfun; + NOT_USED(argc); + if(troot==shp->alias_tree) + { + name = sh_optunalias; + if(shp->subshell) + troot = sh_subaliastree(0); + } + else + name = sh_optunset; + while(r = optget(argv,name)) switch(r) + { + case 'f': + troot = sh_subfuntree(0); + break; + case 'a': + all=1; + break; + case 'n': + nflag = NV_NOREF; + case 'v': + troot = shp->var_tree; + break; + case ':': + errormsg(SH_DICT,2, "%s", opt_info.arg); + break; + case '?': + errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); + return(2); + } + argv += opt_info.index; + if(error_info.errors || (*argv==0 &&!all)) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); + if(!troot) + return(1); + r = 0; + if(troot==shp->var_tree) + nflag |= NV_VARNAME; + else + nflag = NV_NOSCOPE; + if(all) + dtclear(troot); + else while(name = *argv++) + { + if(np=nv_open(name,troot,NV_NOADD|nflag)) + { + if(is_abuiltin(np)) + { + r = 1; + continue; + } + isfun = is_afunction(np); + if(shp->subshell && troot==shp->var_tree) + np=sh_assignok(np,0); + nv_unset(np); + nv_close(np); + if(isfun) + dtdelete(troot,np); + } + else + r = 1; + } + return(r); +} + +/* + * print out the name and value of a name-value pair + */ + +static int print_namval(Sfio_t *file,register Namval_t *np,register int flag, struct tdata *tp) +{ + register char *cp; + sh_sigcheck(); + if(flag) + flag = '\n'; + if(nv_isattr(np,NV_NOPRINT)==NV_NOPRINT) + { + if(is_abuiltin(np)) + sfputr(file,nv_name(np),'\n'); + return(0); + } + if(tp->prefix) + sfputr(file,tp->prefix,' '); + if(is_afunction(np)) + { + Sfio_t *iop=0; + char *fname=0; + if(!flag && !np->nvalue.ip) + sfputr(file,"typeset -fu",' '); + else if(!flag && !nv_isattr(np,NV_FPOSIX)) + sfputr(file,"function",' '); + sfputr(file,nv_name(np),-1); + if(nv_isattr(np,NV_FPOSIX)) + sfwrite(file,"()",2); + if(np->nvalue.ip && np->nvalue.rp->hoffset>=0) + fname = np->nvalue.rp->fname; + else + flag = '\n'; + if(flag) + { + if(np->nvalue.ip && np->nvalue.rp->hoffset>=0) + sfprintf(file," #line %d %s\n",np->nvalue.rp->lineno,fname?sh_fmtq(fname):""); + else + sfputc(file, '\n'); + } + else + { + if(nv_isattr(np,NV_FTMP)) + { + fname = 0; + iop = tp->sh->heredocs; + } + else if(fname) + iop = sfopen(iop,fname,"r"); + else if(tp->sh->hist_ptr) + iop = (tp->sh->hist_ptr)->histfp; + if(iop && sfseek(iop,(Sfoff_t)np->nvalue.rp->hoffset,SEEK_SET)>=0) + sfmove(iop,file, nv_size(np), -1); + else + flag = '\n'; + if(fname) + sfclose(iop); + } + return(nv_size(np)+1); + } + if(cp=nv_getval(np)) + { + sfputr(file,nv_name(np),-1); + if(!flag) + { + flag = '='; + if(nv_arrayptr(np)) + sfprintf(file,"[%s]", sh_fmtq(nv_getsub(np))); + } + sfputc(file,flag); + if(flag != '\n') + { + if(nv_isref(np) && nv_refsub(np)) + { + sfputr(file,sh_fmtq(cp),-1); + sfprintf(file,"[%s]\n", sh_fmtq(nv_refsub(np))); + } + else + sfputr(file,sh_fmtq(cp),'\n'); + } + return(1); + } + else if(tp->scanmask && tp->scanroot==tp->sh->var_tree) + sfputr(file,nv_name(np),'\n'); + return(0); +} + +/* + * print attributes at all nodes + */ +static void print_all(Sfio_t *file,Dt_t *root, struct tdata *tp) +{ + tp->outfile = file; + nv_scan(root, print_attribute, (void*)tp, 0, 0); +} + +/* + * print the attributes of name value pair give by + */ +static void print_attribute(register Namval_t *np,void *data) +{ + register struct tdata *dp = (struct tdata*)data; + nv_attribute(np,dp->outfile,dp->prefix,dp->aflag); +} + +/* + * print the nodes in tree which have attributes set + * of