summaryrefslogtreecommitdiff
path: root/bin/pdksh
diff options
context:
space:
mode:
Diffstat (limited to 'bin/pdksh')
-rw-r--r--bin/pdksh/BUG-REPORTS1117
-rw-r--r--bin/pdksh/CONTRIBUTORS103
-rw-r--r--bin/pdksh/ChangeLog1071
-rw-r--r--bin/pdksh/ChangeLog.03589
-rw-r--r--bin/pdksh/IAFA-PACKAGE17
-rw-r--r--bin/pdksh/INSTALL151
-rw-r--r--bin/pdksh/LEGAL36
-rw-r--r--bin/pdksh/Makefile30
-rw-r--r--bin/pdksh/NEWS603
-rw-r--r--bin/pdksh/NOTES514
-rw-r--r--bin/pdksh/PROJECTS112
-rw-r--r--bin/pdksh/README190
-rw-r--r--bin/pdksh/alloc.c288
-rw-r--r--bin/pdksh/c_ksh.c1402
-rw-r--r--bin/pdksh/c_sh.c787
-rw-r--r--bin/pdksh/c_test.c616
-rw-r--r--bin/pdksh/c_test.h55
-rw-r--r--bin/pdksh/c_ulimit.c257
-rw-r--r--bin/pdksh/conf-end.h62
-rw-r--r--bin/pdksh/config.h351
-rw-r--r--bin/pdksh/edit.c1013
-rw-r--r--bin/pdksh/edit.h86
-rw-r--r--bin/pdksh/emacs-gen.sh44
-rw-r--r--bin/pdksh/emacs.c2182
-rw-r--r--bin/pdksh/eval.c1361
-rw-r--r--bin/pdksh/exec.c1671
-rw-r--r--bin/pdksh/expand.h106
-rw-r--r--bin/pdksh/expr.c596
-rw-r--r--bin/pdksh/history.c1193
-rw-r--r--bin/pdksh/io.c473
-rw-r--r--bin/pdksh/jobs.c1844
-rw-r--r--bin/pdksh/ksh.1tbl3298
-rw-r--r--bin/pdksh/ksh_dir.h26
-rw-r--r--bin/pdksh/ksh_limval.h24
-rw-r--r--bin/pdksh/ksh_stat.h59
-rw-r--r--bin/pdksh/ksh_time.h26
-rw-r--r--bin/pdksh/ksh_times.h20
-rw-r--r--bin/pdksh/ksh_wait.h51
-rw-r--r--bin/pdksh/lex.c1281
-rw-r--r--bin/pdksh/lex.h133
-rw-r--r--bin/pdksh/mail.c198
-rw-r--r--bin/pdksh/main.c820
-rw-r--r--bin/pdksh/misc.c1318
-rw-r--r--bin/pdksh/missing.c271
-rw-r--r--bin/pdksh/path.c346
-rw-r--r--bin/pdksh/proto.h292
-rw-r--r--bin/pdksh/sh.1tbl2372
-rw-r--r--bin/pdksh/sh.h707
-rw-r--r--bin/pdksh/shf.c1271
-rw-r--r--bin/pdksh/shf.h81
-rw-r--r--bin/pdksh/siglist.in56
-rw-r--r--bin/pdksh/siglist.sh42
-rw-r--r--bin/pdksh/syn.c948
-rw-r--r--bin/pdksh/table.c239
-rw-r--r--bin/pdksh/table.h176
-rw-r--r--bin/pdksh/tests/alias.t91
-rw-r--r--bin/pdksh/tests/arith.t79
-rw-r--r--bin/pdksh/tests/bksl-nl.t339
-rw-r--r--bin/pdksh/tests/brkcont.t195
-rw-r--r--bin/pdksh/tests/cdhist.t160
-rw-r--r--bin/pdksh/tests/eglob.t138
-rw-r--r--bin/pdksh/tests/glob.t96
-rw-r--r--bin/pdksh/tests/heredoc.t144
-rw-r--r--bin/pdksh/tests/history.t529
-rw-r--r--bin/pdksh/tests/ifs.t162
-rw-r--r--bin/pdksh/tests/integer.t218
-rw-r--r--bin/pdksh/tests/read.t56
-rw-r--r--bin/pdksh/tests/regress.t770
-rw-r--r--bin/pdksh/tests/th819
-rw-r--r--bin/pdksh/tests/th.sh28
-rw-r--r--bin/pdksh/tests/unclass1.t97
-rw-r--r--bin/pdksh/tests/unclass2.t166
-rw-r--r--bin/pdksh/tests/version.t8
-rw-r--r--bin/pdksh/trap.c432
-rw-r--r--bin/pdksh/tree.c656
-rw-r--r--bin/pdksh/tree.h137
-rw-r--r--bin/pdksh/tty.c179
-rw-r--r--bin/pdksh/tty.h109
-rw-r--r--bin/pdksh/var.c1137
-rw-r--r--bin/pdksh/version.c10
-rw-r--r--bin/pdksh/vi.c2174
81 files changed, 0 insertions, 44904 deletions
diff --git a/bin/pdksh/BUG-REPORTS b/bin/pdksh/BUG-REPORTS
deleted file mode 100644
index 1295a31fefb..00000000000
--- a/bin/pdksh/BUG-REPORTS
+++ /dev/null
@@ -1,1117 +0,0 @@
-$OpenBSD: BUG-REPORTS,v 1.5 1996/11/21 07:59:24 downsj Exp $
-
-List of reported problems (problems reported and fixed before 5.0.4 not
-included). Unresolved problems (may or may not still exist) marked by *,
-problems believed to be fixed marked by x.
-
-* pdksh 5.0.3, MIPS RISC/os 5.0 (bsd universe) (noted by Michael Rendell):
- for interactive, job controlled shells, the kernel's tty state gets twisted
- in such a way that all output is lost (eg, if ttyXX is wedged then
- "echo hi > /dev/ttyXX" from a seperate login appears to succeed but produces
- no output on ttyXX).
- Work around is to run a program and hit ^C.
-
-* pdksh 5.0.1, NetBSD 0.9a? (reported by Simon J. Gerraty): problem with
- job control not finding tty
- [from Mail.1:71]:
- Also, I have noticed (with 5.0.1 anyway) that if as root I su to a
- user I get:
- root:511$ su foobar
- warning: won't have full job control
- [1] + Stopped (tty output) stty erase ^?
- foobar:1$
-
-* pdksh 5.0.8, - (reported by Sean Hogan): attempting file name completion
- on a word with a single backquote causes a "no closing quote" error and
- loses the partially entered command (vi mode).
- [see Mail.2:48]
-
-* pdksh 5.0.10, - (reported by Andrew Moore): no overflow checking is done
- in integer parsing code.
- [see Mail.3:78]
-
-* pdksh 5.0.6+5.1.2, BSD43/MachTen (reported by Dan Menchaca): ksh freezes up
- terminal after a while after printing process exit message. 5.1.2 causes
- system to hang after executing two commands.
- [see Mail.3:96,5:42]
-
-* pdksh 5.1.3, - (reported by Brad Warkentin & others): if the last command of
- a pipeline is a shell builtin, it is not executed in the parent shell,
- so "echo a b | read foo bar" does not set foo and bar in the parent
- shell (at&t ksh will).
- [see Mail.7:32,Mail.9:65]
-
-* pdksh 5.1.3, - (reported by Gabor Zahemszky): emacs/vi doesn't have \ as quote
- character.
- [see Mail.7:87]
-
-* pdksh 5.1.3, - (reported by Gabor Zahemszky): emacs default bindings doesn't
- have vt52 arrow keys or vt100 alternate keypad mode bindings.
- [see Mail.7:87]
-
-* pdksh 5.1.3, SCO 3.2.2 (reported by Gabor Zahemszky): shell hangs
- waiting for finished process to finish.
- [see Mail.7:87]
-
-* pdksh 5.2.0, - (reported by Gabor Zahemszky): ^V in vi leaves cursor at
- start of the line.
- [see Mail.8:43]
-
-* enhancements that haven't been merged yet
- - Mail.6:36-39,78,84 recursive function diffs (add hard limit on
- depeth of recursion)
-
-* pdksh 5.2.3, - (reported by David Gast(? gast@twinsun.com)): history (fc,
- et al) don't work in shell scripts.
- [see Mail.10:49]
-
-* pdksh 5.2.4, - (reported by Gabor Zahemszky): echo ${foo[*]#/} generates
- bad substsitution error, newer ksh's don't (older ones do);
- error includes {...#@(/)}.
- [see Mail.XXX:XXX]
-
-* pdksh 5.2.4, - (reported by Gabor Zahemszky): emacs: ^P steps through
- multiline commands - should go to start of command.
- [see Mail.XXX:XXX]
-
-* pdksh 5.2.7, - (reported by Adrian Marsh): typeset -L20u xxx is ok is ksh88
- but not in pdksh.
- [see Mail.XXX:XXX]
-
-* pdksh 5.2.7, - (reported by Gabor Zahemszky): TMOUT doesn't effect
- select and read operations.
- [see Mail.XXX:XXX]
-
-* pdksh 5.2.8, - : extended pattern globing doesn't handle nested parens ().
-
-* pdksh 5.2.10, - (reported by Simon J. Gerraty): in emacs, <ESC><ESC> applied
- to a word with a macro does not complete the word (only expands the macro).
- [see Mail.XXX]
-
---------------------- put fixed problems below this line ---------------------
-
-x pdksh 5.0.3, NetBSD 0.9a (reported by Simon J. Gerraty): pipelines
- occasionally hang.
- [from Mail.1:71]:
- Yes, I just built 5.0.3 on zen (NetBSD) and the menu stuff worked fine.
- However I've just done:
-
- sjg:910$ diff -cb /etc/profile profile | more
-
- And it has been sitting there ever since.
- [... gdb output indicating process groups set up ok - presumed problem is
- with tty process group]
- [Fixed in 5.0.4 - do tcsetpgrp() in both parent and child for first process]
-
-x pdksh 5.0.2, ISC unix 3.01 (reported by Sean Hogan): set +o monitor (in
- interactive shell?) closes tty
- [from Mail.1:64]:
- I'm having two problems with the job control code, which I believe might
- be related. The first one is that "set +o monitor" closes the tty,
- which causes the shell to exit since its input is gone. According to
- the code, that would imply that FTALKING has mysteriously been turned
- off (jobs.c:343). But my understanding of the code is that FTALKING
- would only be clear for background processes, and set would be done by
- the shell. Do you have any insights here? It's not a big deal of course;
- I don't need to turn off monitor anyway.
- [fixed in 5.0.5 - problem was tty process group was being restored so
- shell could no longer read from tty]
-
-x pdksh 5.0.4, - (reported by Simon J. Gerraty and Sean Hogan):
- test "" -a x would fail.
- [fixed in 5.0.5 - t_wp being unnecessarily decremented in primary()]
-
-x pdksh 5.0.4, -: test -p foo would always fail.
- [fixed in 5.0.5 - spell S_ISFIFO correctly]
-
-x pdksh 5.0.4, -: test ! ! foo would generate error (unexpected !)
- [fixed in 5.0.5 - nexpr() always calls nexpr(), changes to posix code]
-
-x pdksh 5.0.4, -: set -i would generate an internal error.
- [fixed in 5.0.5 - use OF_SET in creating set_opts]
-
-x pdksh 5.0.4, -: let 0>22 would evaluate to true (and 0<22 false)
- [fixed in 5.0.5 - reversed order of O_LT and O_GT in enum]
-
-x pdksh 5.0.4, - (reported by Sean Hogan): echo does not process escape
- characters (ie, echo "foo\c" doesn't to the sysV thing)
- [see Mail.1:98]
- [fixed in 5.0.5 - echo now behaves like sysv echo]
-
-x pdksh 5.0.4, - (reported by Sean Hogan): tty process groups not restored
- properly (vi, :sh, exit causes vi to received SIGTTOU).
- [see Mail.1:98]
- [fixed in 5.0.5 - restore tty process group in j_exit]
-
-x pdksh 5.0.4, - (reported by Sean Hogan): the exit command does not do the
- stopped jobs check.
- [see Mail.1:94,95,98]
- [fixed in 5.0.5 - added LSHELL, hack c_exitreturn to use it]
-
-x pdksh 5.0.3, ISC unix 3.01 (reported by Sean Hogan): if notify is set,
- running cat & produces "[1] + Stopped (tty input) cat", but jobs, fg,
- etc. don't know about the job.
- [from Mail.1:76]
- I get [1] + Stopped (tty input) cat. Interestingly, "jobs" reports
- nothing, and "fg" doesn't see it either. But it's definitely there in
- the ps output. It only responds to kill -9, nothing else. I guess this
- is a side track?
- [see also Mail.1:97,Mail.2:2,3]
- [fixed in 5.0.6 - don't remove stopped jobs in the notify code of check_job()]
-
-x pdksh 5.0.5, - (reported by Sean Hogan): repeated history commands were being
- echoed after the command was executed.
- [see Mail.2:5,6]
- [fixed in 5.0.6 - call shf_flush() in case SHIST: of yylex()]
-
-x pdksh 5.0.5, -: wait with no arguments would hang forever.
- [fixed in 5.0.6 - only wait for running jobs in waitfor()]
-
-x pdksh 5.0.2, HP-UX 9.01 (reported by Sean Hogan): scipts occasionally get
- stopped with SIGTTIN
- [from Mail.1:68]:
- I noticed another small problem today, which is that occasionally
- (on an HP 9000/715, HP-UX 9.01, cc from the ANSI C developer set)
- a background process which is definitely not reading from its input
- stops with SIGTTIN. I first noticed this with a nohup'ed process, but
- it periodically happens without as well. The process is a perl script,
- if that makes any difference. Have you seen this on your HP(s)?
- [hasn't been seen in 5.0.3: Mail.1:73,76]
- [not a shell bug, see Mail.2:14,15]
-
-x pdksh 5.0.6, - (reported by Gordan Larson, Ed Ferguson): shell does not
- compile when VI isn't defined.
- [see Mail.2:22,40]
- [fixed in 5.0.7 - fixed up lex.c]
-
-x pdksh 5.0.6, - (reported by Gordan Larson): ksh.1 font typo.
- [see Mail.2:23]
- [fixed in 5.0.7]
-
-x pdksh 5.0.6, FreeBSd 1.1.5 (reported by Thomas Gellekum): CLK_TCK is defined
- to wrong value on FreeBSD; no depend target in Makefile; update /etc/shells
- in install target.
- [see Mail.2:28]
- [fixed in 5.0.7 - include <limits.h> in sh.h to get the right value; added
- depend target; print warning if ksh not in /etc/shells]
-
-x pdksh 5.0.6, - (reported by Michael Haardt): shell does not compile if JOBS
- not defined.
- [see Mail.2:32]
- [fixed in 5.0.7 - added ifdefs to jobs.c(check_job)]
-
-x pdksh 5.0.6, - (reported by Nick Holloway): exit status of command
- substitution is lost (known problem).
- [from Mail.2:33]:
- This is a variation on a theme of bug number 10 (and is one reason why
- currently ksh can not be used for Linux's MAKEDEV).
-
- The exit status from command substitution is not available when used with
- variable assignment.
-
- x=`false` && echo "Non-zero exit status lost".
- [fixed in 5.0.7 - instead of faking :, set rv to subst_exstat]
-
-x pdksh 5.0.7 - (reported by Sean Hogan): CMASK redefined in emacs.c
- [see Mail.2:44]
- [fixed in 5.0.8 changed CMASK to CHARMASK]
-
-x pdksh 5.0.7 - (reported by Sean Hogan): "r" (fc -e -) doesn't work.
- [see Mail.2:45]
- [fixed in 5.0.8 - increment wp, change strcmp() test]
-
-x pdksh 5.0.7 - (reported by Thomas Gellekum): make install typeo.
- [see Mail.2:46]
- [fixed in 5.0.8 - added missing $]
-
-x pdksh 5.0.8 - (reported by Sean Hogan): "FOO=bar exec blah" does not
- put FOO in environment.
- [see Mail.2:50]
- [fixed in 5.0.9 - re-arranged exec/command/builtin code in comexec()]
-
-x pdksh 5.0.8, QNX 4.2 (reported by Brian Campbell): "exec > /dev/null"
- generates an error.
- [see Mail.2:51]
- [see Mail.2.58 - caused by ambitious compiler using same label for c_exec()
- and c_builtin()]
- [fixed in 5.0.9 - c_exec() no longer an empty function.]
-
-x pdksh 5.0.8, - (reported by Brian Campbell): "echo a{b," prints a "Missing }"
- error - at&t ksh does not. at&t ksh always has brace-expansion on (unless
- set -o nogolob).
- [see Mail.2:51]
- [fixed in 5.0.9 - brace expansion now compatible with at&t ksh]
-
-x pdksh 5.0.8, - (reported by Sean Hogan): ulimit output garbled; syntax error
- in c_ulimit.c; no configure check for HAVE_SETRLIMIT.
- [see Mail.2:64]
- [fixed in 5.0.9 - use shprintf instead of shellf to print values; add
- setrlimit() check to configure]
-
-x pdksh 5.0.7, - (reported by Jan Djarv): `echo > /foo/bar' causes a script to
- exit - POSIX says it shouldn't.
- [see Mail.2:60]
- [fixed in 5.0.9 - iosetup returns error code, error messages cleaned up, etc]
-
-x pdksh 5.0.8, - : `more /etc/passwd &' followed by fg messes up tty settings.
- [fixed in 5.0.9 - only save new tty settings if job originally started in fg]
-
-x pdksh 5.0.9, - (reported by Andrew Moore): a blank line causes $? to be
- set to zero, newline after a here-document marker isn't read.
- [see Mail.3:5,6]
- [fixed in 5.0.10 - don't execute null trees, read the newline]
-
-x pdksh 5.0.9, - (reported by Michael Sullivan): mail checking reports you
- have mail, when there is only old mail.
- [fixed in 5.0.10 - use atime/mtime instead of size]
-
-x pdksh 5.0.9, - (reported by Chris Oates): if RANDOM is in ksh's environ
- when it starts, the shell dumps core.
- [see Mail.3:7,8]
- [fixed in 5.0.10 - var.c(typeset): free t->val.s instead of
- t->val.s + t->type]
-
-x pdksh 5.0.9, - (reported by Seah Hogan): ISC 3.01's make is confused by
- a backslash followed by a blank line.
- [see Mail.3:9,13]
- [fixed in 5.0.10 - changed make depend target to change blank lines to sh.h]
-
-x pdksh 5.0.9, - (reported by Andrew Moore): commands without a newline cause
- syntax errors - sh/ksh execute the commands.
- [see Mail.3:15]
- [fixed in 5.0.10 - have yyparse() accept newline and EOF]
-
-x pdksh 5.0.9, - (reported by Andrew Moore): empty arithmetic expressions not
- accepted.
- [see Mail.3:15,17]
- [fixed in 5.0.10 - v_evaluate(): if first token is END, changed to literal 0]
-
-x pdksh 5.0.9, - (reported by Andrew Moore): nulls in input are not ignored.
- [see Mail.3:15]
- [fixed in 5.0.10 - added strip_nuls() function and calls to it]
-
-x pdksh 5.0.9, - (reported by Andrew Moore): \241 (M-!) not passed through
- command substitutions.
- [see Mail.3:15]
- [fixed in 5.0.10 - evaluate(): cast c to a char before comparing to MAGIC]
-
-x pdksh 5.0.9, - (reported by Andrew Moore): newlines after here-documents
- are read twice; shell reports an error if newline is missing.
- [see Mail.3:25]
- [fixed in 5.0.10 - fixed up readhere()]
-
-x pdksh 5.0.9, - (reported with fix by Mike Jetzer): 'r r' repeats the r
- command forever.
- [see Mail.3:38]
- [fixed in 5.0.10 - start the search from the previous command]
-
-x pdksh 5.0.9, - (reported by Mike Jetzer): edit of multi-line commands
- does not result in single history entry.
- [see Mail.3:38]
- [fixed in 5.0.10 - use hist_append() to add second+ lines]
-
-x pdksh 5.0.9, - (reported by Dale DePriest): ksh_times.h uses BROKEN_TIMES
- [see Mail.3:43]
- [fixed in 5.0.10 - changed ksh_times.h]
-
-x pdksh 5.0.9, - (reported by J. T. Conklin): using [ instead of test is slow.
- [see Mail.3:46]
- [fixed in 5.0.10 - put in kludgy check for [ in eval.c(glob)]
-
-x pdksh 5.0.9, - (reported by Michael Haardt): signals do not interrupt
- read commands.
- [see Mail.3:20]
- [fixed in 5.0.10 - changed c_read() to check for fatal signals after EINTR]
-
-x pdksh 5.0.10, BSDI (reported by David Tamkin): use of _POSIX_VDISABLE in
- tty.h causes compiler error.
- [see Mail.3:67]
- [fixed in 5.0.10.1 - new variable vdisable_c set/used in edit.c]
-
-x pdksh 5.0.8, - (reported by Donald Craig): on systems with both union wait
- and waitpid(), waitpid() is passed a union wait pointer instead of an int
- pointer.
- [see Mail.2:54]
- [fixed in 5.1 - added ksh_waitpid() define; cast status arg as needed.]
-
-x pdksh 5.0.10, - (reported by David Tamkin): space in vi command mode does
- nothing.
- [see Mail.3:76]
- [fixed in 5.1 - vi.c(classify[]) table got changed by accident.]
-
-x pdksh 5.0.10, - (reported by Danial Quinlan): forward-word and
- delete-word-forward functions in emacs don't go to the right place.
- [see Mail.3:79]
- [Fixed in 5.1 - changed order of loops in emacs.c(x_fword())]
-
-x pdksh 5.0.10, - (reported by David Tamkin): eof in multiline command
- causes shell to exit, even if ignoreeof is set.
- [see Mail.3:76]
- [Fixed in 5.1 - reset eof after longjmp() in main.c(shell)]
-
-x pdksh 5.0.9, Ultrix 4.2 (reported by Matthew Nethook): type-ahead while
- shell is waiting for a command to finish is temporarily lost until a
- program that reads from stdin or goes a stty/gtty is run.
- [see Mail.3:61,62]
- [Fixed in 5.1 - changed aclocal.m4 to not define HAVE_TERMIOS_H on ultrix]
-
-x pdksh 5.0.10, - (reported by David Tamkin): if INT is trapped, ^C in
- vi/emacs won't flush buffer/re-issue new prompt.
- [see Mail.3:5,76]
- [Fixed in 5.1 - use unwind() in vi/emacs to get back to shell()]
-
-x pdksh 5.0.10, - (reported by Dale DePriest): in emacs mode, file completions
- resulting in long names (>256) cause core dumps
- [see Mail.3:72]
- [Fixed in 5.1 - use dynamically sized buffers in emacs code]
-
-x pdksh 5.0.10, - (reported by Dale DePriest): in emacs mode, command
- completions (^[=) resulting in multiple hits caused internal memory error.
- [see Mail.4:8]
- [Fixed in 5.1 - don't call list_stash() twice in compl_command]
-
-x pdksh 5.0.10, - (reported by Dave Hatton): autoloading functions fail
- on the first attempt, then work.
- [see Mail.4:10]
- [Fixed in 5.1 - in findcom(), check for include() returning non-0 (was 0)]
-
-x pdksh 5.0.10, - (reported by Art Pina via Dale DePriest): when SECONDS
- parameter is assigned, it always acts as if 0 were assigned.
- [see Mail.4:12]
- [Fixed in 5.1 - set internal seconds variable to time - assigned value]
-
-x pdksh 5.1.0 - (reported by Larry Bouzane): for/select loops don't allow
- {..} to be used instead of do...done.
- [see Mail.4:16]
- [Fixed in 5.1.1 - changed syn.c(dogroup) to allow {/} instead of do/done]
-
-x pdksh 5.1.0 - (reported by Andrew Moore and Larry Bouzane): a command ending
- in ; or & that is not followed by a newline causes a syntax error.
- [see Mail.4:126,128]
- [Fixed in 5.1.1 - don't call syntaxerr() in get_command() if EOF is read]
-
-x pdksh 5.1.0, - (reported by Simon J. Gerraty): ksh died reading history
- file (complex history, in hist_skip_backup()).
- [see Mail.4:24]
- [Fixed in 5.1.1 - hist_skip_back(): don't start past the end of the buffer]
-
-x pdksh 5.1.0 BSDI 1.1 (reported by Karl Denninger): after receipt of SIGHUP,
- shell waits for foreground process to complete.
- [see Mail.4:50,57]
- [Fixed in 5.1.1 - added fatal_trap flag, check in jobs.c(j_waitj)]
-
-x pdksh 5.1.0 - (reported by Bob Manson): a leading non-white-space IFS
- character does cause a field to be delimited.
- [see Mail.4:68]
- [Fixed in 5.1.2 - changed expand() to do the right thing.]
-
-x pdksh 5.1.2, -: ^c during $ENV or .profile kills shell; should just go
- to prompt.
- [see Mail.5:14]
- [fixed in 5.2.4 - added intr_ok flag to main.c(include)]
-
-x pdksh 5.1.2, - (reported by Dan Quinlan): when shell prints out
- execution trees (typeset -f), if botches elif statements.
- [see Mail.5:17]
- [fixed in 5.1.3 - changed tree.c(ptree) to deal with elif.]
-
-x pdksh 5.1.2, - (reported by Dale DePriest): fc -l -- -40 fails if there
- are fewer than 40 commands.
- [see Mail.5:19]
- [fixed in 5.1.3 - changed history.c(histget) to allow out of range numbers]
-
-x pdksh 5.1.2, - (reported by Art Mills): file completion in command mode
- doesn't work on a single character.
- [see Mail.5:13]
- [fixed in 5.1.3 - in vi.c(vi_cmd) call complete_word() with 1 not 0]
-
-x pdksh 5.1.2, - (reported by Dan Quinlan): an error in a let statement
- causes shell to exit function/script. at&t ksh just prints error and
- returns from let.
- [see Mail.5:17]
- [fixed in 5.2.3 - added error_ok arg to evaluate() and v_evaluate()]
-
-x pdksh 5.1.2, - (reported by Art Mills): if markdirs option is set, file
- completion in vi adds two slashes to directories.
- [see Mail.5:35]
- [fixed in 5.1.3 - vi.c(complete_word), don't add / if file ends in one]
-
-x pdksh 5.1.2, - (reported by Dale DePriest): history read from history file
- have negitive numbers and can't be accessed (fc thinks neg numbers are
- relative).
- [see Mail.5:39]
- [fixed in 5.1.3 - EASY_HISTORY/hist_init: increment line for each line]
-
-x pdksh 5.1.2, - (reported by David Tamkin): FPATH isn't searched if PATH
- search can't find command (undocumented at&t ksh feature).
- [see Mail.5:45]
- [fixed in 5.1.3 - exec.c(findcom) search FPATH if PATH search fails]
-
-x pdksh 5.1.2, - (reported by Dan Quinlan): output typeset -f isn't
- very pretty (no indenting done).
- [see Mail.5:17]
- [fixed in 5.1.3 - indenting added to ptree routines]
-
-x pdksh 5.0.9, ISC 3.2 (reported by cobra@guarany.cpd.unb.br): Running the
- following script with pdksh crashes the machine:
- cat > /tmp/foobar
- The same command in an interactive pdksh does not cause a crash.
- [see Mail.3:21,Mail.5:62]
- [Fixed by Interactive - it is caused by an OS bug for which there is a patch]
-
-x pdksh 5.1.3, linux - (reported by Dan Quinlan): doesn't compile under new
- linux due to declaration conflict between basename() in unistd.h and
- pdksh'd basename.
- [see Mail.5:90]
- [fixed in 5.2.0 - changed basename() to arrayname()]
-
-x pdksh 5.1.3, - (reported by William Hudacek): very long prompts cause
- vi command line editor grief.
- [see Mail.6:2]
- [fixed in 5.2.0 - initial part of prompt is stripped if its too long]
-
-x pdksh 5.1.3, - (reported by Roberto Zacheo): when set -u, variable trimming
- with always causes an error.
- [see Mail.6:21]
- [fixed in 5.2.0 - fixed varsub() to test if variable is null]
-
-x pdksh 5.1.3, - (reported by David Tamkin): when a fucntion is autoloaded,
- ksh complains the definition file didn't define the function, even if it did.
- [see Mail.6:52]
- [fixed in 5.2.0 - exec.c(comexec): when checking if defined, use cp,
-
-x pdksh 5.1.3, ICS unix 3.2 (reported by Robert Clark): auto configuration
- test for memmove doesn't work
- [see Mail.6:65]
- [fixed in 5.2.0 - special cases added for memmove, bcopy, memset]
-
-x pdksh 5.1.3, Unixware (Intel-SVR4.2) (reported by Thanh Ma): auto
- configuration test for memset doesn't work; same for rlimit type.
- [see Mail.6:67]
- [fixed in 5.2.0 - special cases added for memmove, bcopy, memset; rlim_t
- configuration stuff re-arranged]
-
-x pdksh 5.1.3, - (reported by Mike Jetzer + fix): . in vi doesn't work
- after history motion or after one command is completed and another is being
- edited.
- [see Mail.6:85]
- [fixed in 5.2.0 - fix up classify table, special case for empty initial
- insert]
-
-x pdksh 5.1.3, - Janjaap van Velthooven: ^v (version) missing in vi mode.
- [see Mail.6:98]
- [fixed in 5.2.0 - added]
-
-x pdksh 5.1.3, - : y% on or before right bracket/paren/brace doesn't yank the
- brackets - just what is in the brackets...
- [fixed in 5.2.0 - changes to vi.c(domove,vi_cmd)]
-
-x pdksh 5.1.3, - (reported by Rob Mayoff): [[ ]] command doesn't do lazy
- evaluation.
- [see Mail.7:2]
- [fixed in 5.2.1 - test routines re-arranged to deal with this]
-
-x pdksh 5.1.3, - (reported by Will Renkel): "r | more" doesn't work (nothing
- is sent to more).
- [see Mail.7:13]
- [fixed in 5.2.0 - history commands now done in c_fc, not pushed onto input
- stack]
-
-x pdksh 5.1.3, - (reported by Rod Byrne, John Rochester): if a program leaves
- the non-blocking (O_NONBLOCK) flag set after it exists, the shell
- exits (multiple eofs).
- [see Mail.7:15,16,51]
- [fixed in 5.2.0: O_NONBLOCK is reset if read fails with EAGAIN,EWOULDBLOCK]
-
-x pdksh 5.1.3, - (reported by Dale DePriest + fix): emacs: can't delete chars
- from pattern in incremental search mode.
- [see Mail.7:17]
- [fixed in 5.2.0 - handle it]
-
-x pdksh 5.1.3, Linux 1.2.2 (reported by Fritz Heinrichmeyer + fix): siglist.sh
- doesn't work due to bug in bash 1.4.3 (trap is called incorrectly in
- subshell causing temp file to be removed prematurely).
- [see Mail.7:21]
- [fixed in 5.2.0 - clear all traps in subshell so file isn't removed]
-
-x pdksh 5.1.3, - (reported by Dale DePriest + fix): emacs: can't prefix
- commands with more than single digit; many commands don't use nnumber
- prefix.
- [see Mail.7:26,40]
- [fixed in 5.2.0 - x_set_arg reads sequence of numbers, other commands
- changed to use x_arg]
-
-x pdksh 5.1.3, - (reported by Dale DePriest): fc command line parsing
- (and its interaction with history alias) doesn't act like at&t ksh:
- history -40 gives bad option 4 error.
- [see Mail.7:41,49]
- [fixed in 5.2.1 - kludge parsing of -40 (numbers are option letters)]
-
-x pdksh 5.1.3, - (reported by Dale DePriest): if PS1 contains paramaters that
- get expanded, and if those parameters contain any ! characters, the !'s get
- changed to history numbers.
- [see Mail.7:44]
- [fixed in 5.2.0 - substitution done after ! and !! substitution]
-
-x pdksh 5.1.3, - (reported by Steve Wallis): set -a (set -o allexport) has
- no effect.
- [see Mail.7:47]
- [fixed in 5.2.0 - changes to c_read, c_getopts, and comexec]
-
-x pdksh 5.1.3, - (reported by Alexander S. Jones): (sleep 10000&) waits for
- the sleep to complete.
- [see Mail.7:54]
- [fixed in 5.2.0 - execute() case TASYNC clears EXEC flag in call to execute]
-
-x pdksh 5.1.3, - (reported by Will Renkel): positional parameters can't be
- accessed within temporary variable assignments (eg, "FOO=$1 blah" doesn't
- set FOO to $1.
- [see Mail.7:57]
- [fixed in 5.2.0 - var.c(newblock) - copy argc/argv from previous environment]
-
-x pdksh 5.1.3, SCO unix ? (reported by Sean Hogan): job control stuff doesn't
- work as sco doesn't do job control operations on /dev/tty.
- [see Mail.7:30,43,69,70,74]
- [fixed in 5.2.0 - don't try opening /dev/tty if on SCO]
-
-x pdksh 5.1.3, - (reported with fix by Mike Jetzer): vi globing tacks
- * at the end of files even if there are globing chars in last component
- of filename (at&t ksh does not).
- [see Mail.7:71]
- [fixed in 5.2.0 - don't append * if there are unescaped globing chars]
-
-x pdksh 5.1.3, - (reported with fix by Gabor Zahemszky): typoes in acconfig.h,
- sh.h uses SVR3_PGRP insteda of SYSV_PGRP.
- [see Mail.7:87]
- [fixed in 5.2.0]
-
-x pdksh 5.1.3, - (reported by Gabor Zahemszky): emacs doesn't have ^[^].
- [see Mail.7:87]
- [fixed in 5.2.0 - added search-char-backward]
-
-x pdksh 5.2.0, - (reported by David Tamkin): pwd -P doesn't strip .. and .
- properly.
- [see Mail.7:98]
- [fixed in 5.2.0 - include ksh_stat.h in c_ksh.c]
-
-x pdksh 5.2.0, - (reported by Dale DePriest): unistd.h config test
- doesn't include sys/types before dirent.h.
- [see Mail.8:2]
- [fixed in 5.2.0]
-
-x pdksh 5.2.0, - (reported by Robert Gallant): emacs file/command completion
- code can clobber memory.
- [see Mail.8:11]
- [fixed in 5.2.1 - wrong variable being checked in buffer growing in
- emacs.c(compl_file,compl_command)]
-
-x pdksh 5.2.0, - (reported by David Tamkin): when CDPATH set and cd'ing to a
- directory that doesn't exist, the error message contains the last element
- of the CDPATH.
- [see Mail.8:8]
- [fixed in 5.2.0 - fixed error message]
-
-x pdksh 5.2.0, - (reported by David Tamkin): if PS1 has an error in it
- (eg, parameter expansion error), the shell loops forever printing
- the error.
- [see Mail.8:32]
- [fixed in 5.2.3 - create error handling environment while expanding PS1]
-
-x pdksh 5.2.0, Coherent machines (reported by Gabor Zahemszky): insert after
- movement in emacs mode replaces all chars with first char on line.
- System's bcopy doesn't handle overlapping src/dst.
- [see Mail.8:38,43]
- [fixed in 5.2.1 - check for broken memmove/bcopy in aclocal.m4]
-
-x pdksh 5.2.0, - (reported by Gabor Zahemszky): ^[= in vi prints empty
- strings for directory matches if markdirs is set.
- [see Mail.8:48]
- [fixed in 5.2.1 - skip trailing /'s before looking for last /]
-
-x pdksh 5.2.0, - (reported by Gabor Zahemszky): <ESC>^H bound to del-back-char
- not del-back-word
- [see Mail.8:50-52]
- [fixed in 5.2.1 - fixed x_emacs_keys]
-
-x pdksh 5.2.1, - (reported by David Tamkin): compile fails due to lack
- of c_test.h
- [see Mail.8:58]
- [fixed in 5.2.2 - fixed put c_test.h in distribution]
-
-x pdksh 5.2.2, - (reported by Simon J. Gerraty): hist_source not being
- initialized in complex history.
- [see Mail.8:64]
- [fixed in 5.2.3 - set it in second hist_init()]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): set -A does not reset
- the array contents.
- [see Mail.8:65]
- [fixed in 5.2.3 - changed var.c(unset) to unset whole array if appropriate]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): getopts stops after an error;
- at&t ksh carries on with next option.
- [see Mail.8:65]
- [fixed in 5.2.3 - remove GI_DONE flag from ksh_getopt()]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): getopts prints shell name
- twice in error messages.
- [see Mail.8:65]
- [fixed in 5.2.3 - added GI_NONAME flag]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): pdksh's test doesn't know about
- /dev/fd/n.
- [see Mail.8:65]
- [fixed in 5.2.3 - added test_stat() and test_eaccess()]
-
-x pdksh 5.2.2, - (reported by Thomas Gellekum): config test for memmove/bcopy
- missing semi-colon
- [see Mail.8:67]
- [fixed in 5.2.3]
-
-x pdksh 5.2.2, - (reported by Donald Craig): fc string doesn't find string
- if it is the most recent command.
- [see Mail.8:76]
- [fixed in 5.2.3 - fixed off by one error in history.c(hist_get)]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): pdksh doesn't do the
- "You have running jobs" when user attempts to log out.
- [see Mail.8:74]
- [fixed in 5.2.3 - added set -o nohup option with supporting code]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): configure test for
- broken memmove/bcopy doesn't work.
- [see Mail.8:93]
- [fixed in 5.2.3 - fixed test to copy overlapping buffers]
-
-x pdksh 5.1.3, - (reported by <wendt@sv5.mch.sni.de>): doesn't compile on
- solaris 5.x with COMPLEX_HISTORY defined.
- [see Mail.8:98]
- [fixed in 5.2.3 - undef COMPLEX_HISTORY if flock not available]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): tilde expansion not preformed
- in word part of ${foo[-+=?} substitution.
- [see Mail.9:7]
- [fixed in 5.2.3 - allow ~foo to end in a close brace]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): "fc 30" edits from 30 to
- most recent history (should be just 30).
- [see Mail.9:7]
- [fixed in 5.2.3 - if !-l and no last given, use first]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): [many problems with man page]
- [see Mail.9:12]
- [fixed in 5.2.3 - fixed problems]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): #else followed by non-comment
- in sigact.c.
- [see Mail.9:13]
- [fixed in 5.2.3 - turn it into a comment]
-
-x pdksh 5.2.2, - (reported with fix by Gabor Zahemszky): two argument form of
- cd doesn't work.
- [see Mail.9:14]
- [fixed in 5.2.3 - in c_cd(), use current_wd not path]
-
-x pdksh 5.2.2, - (reported with fix by Gabor Zahemszky): command -V doesn't
- report reserved words.
- [see Mail.9:30]
- [fixed in 5.2.3 - in c_whence(), look for reserved words if vflag set]
-
-x pdksh 5.2.3, - (reported by Dale DePriest): at&t's tbl wants space
- between font specification and end of table descrption (ie, fB . not
- fB.).
- [see Mail.9:41]
- [fixed in 5.2.4 - put spaces in]
-
-x pdksh 5.2.3, - (reported by David Tamkin & Claus L{gel Rasmussen): PS1
- isn't imported from environment anymore.
- [see Mail.9:43,76]
- [fixed in 5.2.4 - main: don't set PS1 if it is already set]
-
-x pdksh 5.2.3, - (reported by Gary Rafe): If PS1 contains newlines, vi
- editing mode dones't redraw lines properly.
- [see Mail.9:63]
- [fixed in 5.2.4 - added prompt_skip stuff to vi/emacs]
-
-x pdksh 5.2.3, - (reported & fixed by Mike Jetzer): cd: error message if
- directory didn't exist was wrong.
- [see Mail.9:66]
- [fixed in 5.2.4 - print correct string in error message]
-
-x pdksh 5.2.3, - (reported & fixed by Mike Jetzer): vi: <ESC>* shouldn't append
- a * if word contains a $.
- [see Mail.9:66]
- [fixed in 5.2.4 - vi.c(glob_word): check for $ in word, check for null
- expansion]
-
-x pdksh 5.2.3, - (reported & fixed by Mike Jetzer): vi: <ESC>= doesn't
- list expansions in column form.
- [see Mail.9:66]
- [fixed in 5.2.4 - use pr_menu to print things nicely]
-
-x pdksh 5.2.3, - (reported Larry Bouzane): should be a way of installing
- binary/man page as pdksh instead of ksh.
- [see Mail.9:100]
- [fixed in 5.2.4 - use the --enable-shell=pdksh option to configure]
-
-x pdksh 5.2.3, - (reported by Gabor Zahemszky): [many problems with man
- page]
- [see Mail.10:20]
- [fixed in 5.2.4 - fixed problems]
-
-x pdksh 5.2.3, - (reported by Gabor Zahemszky): exec 1<&9 reports
- error with ">&9" in it.
- [see Mail.10:20]
- [fixed in 5.2.4 - changed iosetup()]
-
-x pdksh 5.2.3, - (reported by Gabor Zahemszky): man page doesn't document
- /dev/fd/N
- [see Mail.10:20]
- [fixed in 5.2.4 - updated manual]
-
-x pdksh 5.2.3, - (reported by Ted Coady): [[ foo/bar = foo* ]]
- fails; should succeed.
- [see Mail.10:32]
- [fixed in 5.2.4 - fixed problem in exec.c(dbteste_getopnd)]
-
-x pdksh 5.2.3, - (reported by Ruei-wun Tu): make on NeXT/NeXTSTEP 3.3
- doesn't understand .PRECIOUS target and so does nothing.
- [see Mail.10:43]
- [fixed in 5.2.4 - moved .PRECIOUS after all in Makefile.in]
-
-x pdksh 5.2.3, - (reported & fixed by Paul Borman): shell doesn't kill
- foreground process when SIGHUP received; Also, CONT sent before HUP.
- [see Mail.10:44]
- [fixed in 5.2.4 - j_exit now sends HUP to foreground process]
-
-x pdksh 5.2.3, AIX 3.2.5 (reported by Ian Portsmouth): C compiler compains
- about sigtraps[] being re-declared in trap.c.
- [see Mail.10:73]
- [fixed in 5.2.4 - use cpp define to avoid bogus re-declaration error]
-
-x pdksh 5.2.3, - (reported by Michael Haardt): ENV should not be
- included if shell is compiled as sh and posix option not set.
- [see Mail.10:83]
- [fixed in 5.2.4 - only include ENV if POSIX, if compiled as sh]
-
-x pdksh 5.2.3, - (reported & fixed by DaviD W. Sanderson): case statements
- don't allow {/} in place of IN/ESAC.
- [see Mail.10:77,78]
- [fixed in 5.2.4 - allow {/} in case statements]
-
-x pdksh 5.2.3, - (reported by Larry Daffner): $? is incorrectly zero'd
- at start of traps.
- [see Mail.11:9]
- [fixed in 5.2.4 - don't clear exstat in main.c(shell)]
-
-x pdksh 5.2.3, - (reported by Frank "Crash" Edwards): configure on linux XXX
- doesn't detect the presence of lstat().
- [see Mail.11:36]
- [fixed in 5.2.4 - change configure to include <sys/stat.h> in lstat() test]
-
-x pdksh 5.2.3, - (reported by Gabor Zahemszky): typeset -f dumps core
- in the after using autoload functions.
- [see Mail.11:74?]
- [fixed in 5.2.4 - c_typeset no longer traverses the array link for functions]
-
-x pdksh 5.2.3, - (reported by Gabor Zahemszky): typeset -f does not report
- undefined autoload functions
- [see Mail.11:74?]
- [fixed in 5.2.4 - c_typeset: don't ignore unset functions]
-
-x pdksh 5.2.3, - (reported by Dale DePriest): alias -t -r does not
- reset aliases.
- [see Mail.11:99]
- [fixed in 5.2.4 - c_alias: call ksh_getopt_reset() before calling c_unalias]
-
-x pdksh 5.2.3, - (reported & fixed by Jason Tyler): 'echo abc^Jfc -e - a=b e'
- echos b, not bbc.
- [see Mail.11:100?]
- [fixed in 5.2.4 - hist_replace: use s, not last]
-
-x pdksh 5.2.3, - (reported by Jason Tyler): 'fc -e -' when there is
- no history causes infinite loop.
- [see Mail.11:100?]
- [fixed in 5.2.4 - histbackup: allow histptr to go below history]
-
-x pdksh 5.2.4, - (reported by David Tamkin): jmp_buf is used instead of
- sigjmp_buf.
- [see Mail.XXX:XXX]
- [fixed in 5.2.5 - added ksh_jmp_buf and defined appropriately]
-
-x pdksh 5.2.4, - (reported by Stephen Coffin): /<RETURN> in vi mode does not
- repeat last search.
- [see Mail.XXX:XXX]
- [fixed in 5.2.5 - vi.c(vi_hook) - make it repeat last search]
-
-x pdksh 5.2.4, - (reported by Gabor Zahemszky): functions containing select
- commands aren't printed correctly by typeset.
- [see Mail.XXX:XXX]
- [fixed in 5.2.5 - tree.c(ptree) - add case for TSELECT]
-
-x pdksh 5.2.4, - (reported & fixed by Stefan Dalibor): COLUMNS isn't set on
- shell start up (and window size is ignored) 'cause tty_fd isn't valid when
- x_init() is called.
- [see Mail.XXX:XXX]
- [fixed in 5.2.5 - call x_init() after j_init() is called]
-
-x pdksh 5.2.4, - (reported by Will Renkel): "echo -" just prints a blank
- line - should print the minus.
- [see Mail.XXX:XXX]
- [fixed in 5.2.5 - c_ksh.c(c_print): don't do argument parsing on lone -]
-
-x pdksh 5.1.3, - (reported by Gabor Zahemszky): emacs doesn't have ^[*.
- [see Mail.7:87]
- [fixed in 5.2.5]
-
-x pdksh 5.2.3, - (reported by Mike Jetzer): in vi, <ESC>= doesn't append
- a / after directories.
- [see Mail.9:66]
- [fixed in 5.2.5]
-
-x pdksh 5.2.0, - (reported by Gabor Zahemszky): can set readonly variables
- via command assignments (eg, "readonly x=y; x=z /bin/echo hi" should
- fail and doesn't).
- [see Mail.8:50,65]
- [fixed in 5.2.5 - LOCAL_COPY flag passed from comexec() down to local()]
-
-x pdksh 5.2.4, - (reported by Tom Karches): history: "r old=new", with
- no commands prefix given, prints "fc: too mnay arguments" - it should
- do the subst on the previous command.
- [see Mail.XXX:XXX]
- [fixed in 5.2.5]
-
-x pdksh 5.2.3, - (reported by Vigen Pogosyan): assignments in $(( ... ))
- remember the base that was assigned in pdksh - does not in at&t ksh.
- [see Mail.10:54]
- [fixed in 5.2.5: uset setint() in expr.c(evalexpr)]
-
-x pdksh 5.2.4, - (reported by Gabor Zahemszky): emacs: ^O steps down
- two lines (should be 1).
- [see Mail.XXX:XXX]
- [fixed in 5.2.5: convert history line to command number, then convert back]
-
-x pdksh 5.2.3, - (reported by David Gast(? gast@twinsun.com)): fc -ln -1 -1
- reports the current command, not the previous command.
- [see Mail.10:49]
- [fixed in 5.2.5]
-
-x pdksh 5.2.3, - (reported by Matthew Green): foo=`^Jecho bar` doesn't
- set foo to bar (foo is empty).
- [see Mail.XXX:XXX]
- [fixed in 5.2.5: syn.c: set multiline.on when source is SSTRING]
-
-x pdksh 5.2.5, - (reported by Gabor Zahemszky): continue/break: if n
- is too big, shell prints internal error message.
- [see Mail.XXX:XXX]
- [fixed in 5.2.6: fix c_brkcont to use last loop if n is too big]
-
-x pdksh 5.2.5, - (reported by Gabor Zahemszky): set: +o in ksh93
- prints command that sets various options.
- [see Mail.XXX:XXX]
- [fixed in 5.2.6: changed misc.c(printoptions)]
-
-x pdksh 5.2.5, - (reported by Gabor Zahemszky): COLUMNS/LINES variables
- are not exported.
- [see Mail.XXX:XXX]
- [fixed in 5.2.6: use typeset() in edit.c(x_init) to export COLUMNS/LINES]
-
-x pdksh 5.2.5, - (reported by Gabor Zahemszky): emacs: <ESC><ESC> puts
- space after completed directories.
- [see Mail.XXX:XXX]
- [fixed in 5.2.6: check for single/non-directory match in emacs.c(do_complete)]
-
-x pdksh 5.2.5, - (reported by Gabor Zahemszky): vi: # removes comment
- and executes if command already commented.
- [see Mail.XXX:XXX]
- [fixed in 5.2.6: added vi.c(do_comment)]
-
-x pdksh 5.2.7, - (reported by Adrian Marsh): test doesn't have == operator.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: added == to c_test.c operator table]
-
-x pdksh 5.2.7, - (reported by Mike Jetzer): pdksh sets/exports COLUMNS/LINES
- which causes applications not to respond to window size changes.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: COLUMNS/LINES no longer exported automatically]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): getopts sets OPTIND differently
- that at&t ksh when a bad option is given.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: OPTIND not set if option was bad - fragile fix - may go away]
-
-x pdksh 5.2.7, - (reported with fix by Marc Olzheim): sh version shouldn't
- have mail check stuff, macro expansion in PS[0-9].
- [fixed in 5.2.8: added lots of ifdefs]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): sub commands in PS1 cause
- a warning message to be printed.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: lex.c(set_prompt) - don't print the warning message]
-
-x pdksh 5.2.7, - (reported by Tom Watson): some environment variables
- (eg, PATH) are converted to uppercase on 16-bit int machine.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: struct tbl.flag (32 bit thing) was being treated as an
- int in some places]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): unset always returns 0 - should
- return 1 if variable/function is not set.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: fixed c_sh.c(c_unset)]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): select should only print the
- menu the first time, if REPLAY is empty, or if a blank line is entered.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: fixed up exec.c(execute,do_selectargs)]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): shell reports "cannot execute"
- error if file exists, even if . not in path.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: fixed up exec.c(comexec)]
-
-x pdksh 5.1.3, - (reported with partial fix by ra@rhi.hi.is): shell doesn't
- listen to sigwinch.
- [see Mail.7:7 and related]
- [fixed in 5.2.8: changed edit.c(x_init) to catch sigwinch]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): typeset doesn't report
- variables that have attributes (like export) but no values.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: fixed up c_ksh.c(c_typeset)]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): error message printed as
- a result of "set -o nounset" is different from at7t ksh.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: fixed error messges in eval.c]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): vi/emacs: when listing
- command/file completions, should go back at most one space. Also, should
- allow completions on zero length names.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: fixed edit.c(x_locate_word); now allows zero-length
- file completions (but not command)]
-
-* pdksh 5.2.7, - (reported by Gabor Zahemszky): emacs: <esc># doesn't do
- the comment thing.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: added emacs.c(x_comment) et al.]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): arithmatic expressions
- containing variables not expanded as in at&t ksh. eg, "x=1+2, let y=x"
- fails.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: added evaling/INEXPREVAL/ET_RECURSIVE code to expr.c]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): unsetting the 0th element
- of an array kills the whole array.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: var.c(unset) - allow ARRAY to be preserved]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): unsetting a function while
- it is being executed can result in core dump.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: table.c(texpand) - dont free if FINUSE is set]
-
-* pdksh 5.2.7, - (reported by Gabor Zahemszky): exec 3<&p doesn't close
- shells copy of the coprocess file desc.
- [see Mail.XXX:XXX]
- [fixed in 5.2.8: coprocess stuff made to act like ksh93 co-processes]
-
-x pdksh 5.2.8, - (reported with fix by Lars Hecking): doesn't compile as
- sh - c_ksh.c and jobs.c boom out.
- [see Mail.XXX:XXX]
- [fixed in 5.2.9: added ifdef KSH to appropriate places]
-
-x pdksh 5.2.8, - (reported by Paolo Zeppegno): assignments containing brackets
- are treated as commands.
- [see Mail.XXX:XXX]
- [fixed in 5.2.9: fixed bug in vars.c(skip_wdvarname).]
-
-x pdksh 5.2.5, - (reported by Adrian Marsh): configuration on Linux FT fails.
- Caused by configure script using -g flag - gcc passes -lg to ld, ld fails
- to find -lg (autoconf or Linux FT bug).
- [see Mail.XXX:XXX]
- [fixed in 5.2.9: changed autoconf's -g test to do linking as well.]
-
-x pdksh 5.2.8, Solaris 2.5.1 (reported by Stefan Dalibor): 2 tests
- (xxx-exec-environment-1 and 2) fail because printenv isn't found.
- [see Mail.XXX:XXX]
- [fixed in 5.2.9: changed test to use env instead]
-
-x pdksh 5.2.8, - (reported by Stefan Dalibor): shell assumes 80 columns when
- it starts up if COLUMNS is set correctly in the environ.
- [see Mail.XXX:XXX]
- [fixed in 5.2.9: fixed so window size is checked at startup]
-
-x pdksh 5.2.8, NeXT machines (reported by Kai Wong): clock_t, which lives
- in sys/time.h, isn't found by configure (causes warning messages).
- [fixed in 5.2.9: configure now checks in sys/time.h]
-
-x pdksh 5.2.3, - (reported by Mike Jetzer): in vi, <ESC>= on word with ~
- but no /, beeps (or prints final path comonent?).
- [see Mail.9:66]
- [fixed in 5.2.9: fixed edit.c(add_glob) so no * is appended to ~username]
-
-x pdksh 5.1.3, NeXT machines (reported by Jason Baugher): job control doesn't
- work on NeXT machines (both m68k and x86 based) in rlogin sessions.
- (caused by open("/dev/tty") failing - rlogin on NeXT doesn't set up
- controlling tty properly).
- [see Mail.7:29]
- [fixed in 5.2.9: added hack to main to get a controlling tty]
-
-x pdksh 5.2.8, NeXT 3.2 (reported by Andrew S Townley): the output of the
- siglist.sh script fills the disk. Also, the signal list generated (by the
- fixed script) is mostly empty.
- [see Mail.XXX]
- [fixed in 5.2.9: fixed siglist.sh script to avoid infinite loops. Added
- comment to README warning of problem with NeXT's native cc -E]
-
-x pdksh 5.2.9, - (reported by Loris Talpo): long prompts are messed up in
- vi mode.
- [see Mail.XXX]
- [fixed in 5.2.9: lex.c(pprompt) was broken]
-
-x pdksh 5.2.9, - (reported by Will Renkel): a double backslash followed
- by a newline in an unquoted here document results in one of the backslashes
- and the newline being stripped.
- [see Mail.XXX]
- [fixed in 5.2.10: fixed backslash-newline processing in lex.c]
-
-x pdksh 5.2.9, - (reported by Han Holl): read x?prompt doesn't work
- on non-interactive shells when the input is from a tty.
- [see Mail.XXX]
- [fixed in 5.2.10: changed test in c_read() from FTALKING to isatty]
-
-x pdksh 5.2.10, - (reported by Dale DePriest): expanding aliases causes
- extra input.
- [see Mail.XXX]
- [fixed in 5.2.11: fixed syn.c(c_list).]
-
-x pdksh 5.2.10, - (reported by John Rochester): window size changes don't
- happen on Dec unix (osf) because TIOCGWINSZ is defined in <sys/ioctl.h>
- not in <termios.h>.
- [see Mail.XXX]
- [fixed in 5.2.12: sys/ioctl.h included with termios.h/termio.h if possible]
-
-x pdksh 5.2.11, - (reported by Randy Bouzane): aliases in command substitutions
- result in code dumps.
- [see Mail.XXX]
- [fixed in 5.2.12: lex.c(getsc__): break if eof is read]
-
-x pdksh 5.2.11, - (reported by Will Renkel): aliases containing ;<newline>
- or <newline><newline> aren't fully read/executed.
- [see Mail.XXX]
- [fixed in 5.2.12: syn.c(get_command): call inalias()]
-
-x pdksh 5.2.11, SGI/IRIX 5.2 (reported by bert@xpilot.com): pipelines
- containing built in commands hang forever.
- [see Mail.XXX]
- [fixed in 5.2.12: fixed pgrp sync code in jobs.c]
-
-x pdksh 5.2.11, - (reported by Herbert Thielen via Larry Daffner): shell leaves
- temp files around when executing shell scripts that have functions with
- here documents which end in an exec.
- [see Mail.XXX]
- [fixed in 5.2.12: call main.c(cleanup_proc_env()) from exec.c(execute()).]
-
diff --git a/bin/pdksh/CONTRIBUTORS b/bin/pdksh/CONTRIBUTORS
deleted file mode 100644
index edf32c0db35..00000000000
--- a/bin/pdksh/CONTRIBUTORS
+++ /dev/null
@@ -1,103 +0,0 @@
-$OpenBSD: CONTRIBUTORS,v 1.3 1996/10/01 02:05:25 downsj Exp $
-
-This is a partial history of this shell gleened from old change logs and
-readmes (most of which are still in the misc directory) and the source
-code. Hopefully it is correct and no contributors have been left out
-(file a bug report if you spot a problem :-)).
-
-Release history:
- * Eric Gisin (egisin@math.uwaterloo.ca), created pdksh, using
- Charles Forsyth's public domain V7 shell as a base; also used parts
- of the BRL shell (written by Doug A Gwyn, Doug Kingston, Ron Natalie,
- Arnold Robbins, Lou Salkind, and others?, circa '87; the parts used in
- pdksh included getopts, test builtin, ulimit, tty setting/getting, emacs
- editing, and job control; the test builtin was based on code by Erik
- Baalbergen).
- '87..'89 ?
- Released versions: .. 3.2
- * John R MacMillan (@yonge.csri.toronto.edu:chance!john@sq.sq.com)
- takes over as maintainer
- dates?
- Released versions: 3.3 (?)
- * Simon J. Gerraty (sjg@zen.void.oz.au) takes over as maintainer
- Nov '91..July '94 ?
- Released versions: 4.0 .. 4.9
- * Michael Rendell (michael@cs.mun.ca) takes over as maintainer
- July, 1994
- Released versions: 5.0 .. 5.2
-
-Major contributions:
- * John R MacMillan (@yonge.csri.toronto.edu:chance!john@sq.sq.com), ?:
- cleaned up configuration, many bug fixes (see misc/Changes.jrm).
- * Simon Gerraty, (sjg@zen.void.oz.au), Nov '91..?: much improved emacs mode
- ala at&t ksh, 386bsd port, sigaction routines for non-POSIX systems
- (see misc/ChangeLog.sjg and misc/ReadME.sjg).
- * Peter Collinson (pc@hillside.co.uk), July '92: added select, at&t ksh
- style history file, original csh-style {} globbing, BSD/386 port,
- misc bug fixes.
- * Larry Bouzane (larry@compusult.nf.ca), Mar '89..'93: re-wrote job control,
- added async job notification, added CDPATH and other cd fixes, misc bug
- fixes.
- * John Rochester (jr@cs.mun.ca), '87: wrote vi command line editor; various
- bug fixes/enhancements.
- * Jeff Sparkes (jsparkes@bnr.ca), Mar '89..Mar '90: added arrays,
- merged John Rochester's vi code into pdksh, misc bug fixes.
- * Michael Haardt (u31b3hs@POOL.Informatik.RWTH-Aachen.DE), Sept '94:
- organized man page, filled in many of its copious blank spots; added
- KSH ifdefs.
- * Dale DePriest (daled@cadence.com): ported to OS/2 (initially based on
- port of pdksh4.9 to OS/2 by Kai Rommel (rommel@ars.muc.de)); maintains
- OS/2 port; misc bug fixes.
-
-Other contributors:
- * Piercarlo Grandi (pcg@aber.ac.uk), Dec '93: fixes for linux port
- * Neil Smithline (Neil.Smithline@eng.sun.com), Aug '92: emacs-style
- filename completion.
- * Mike Jetzer [mlj] (jetzer@studsys.mscs.mu.edu), ?;Nov '94: fixes for vi
- mode (see misc/Changes.mlj), added v to vi, fixes for history; fixed
- command redoing in vi; fixes to vi globbing.
- * Robert J Gibson: mailbox checking code that was adapted for pdksh by
- John R. MacMillan.
- * ? (guy@demon.co.uk), ?: promptlen() function.
- * J.T. Conklin (jtc@cygnus.com): POSIXized test builtin; miscellaneous
- fixes/enhancements.
- * Sean Hogan (sean@neweast.ca): fixes for ICS 3.0 Unix, found and helped
- fix numerous problems.
- * Gordan Larson (hoh@approve.se): fix to compile sans VI, ksh.1 typo.
- * Thomas Gellekum (thomas@ghpc8.ihf.rwth-aachen.de): fixes for Makefile
- typos, fixed CLK_TCK for FreeBSD, man page fixes.
- * Ed Ferguson (Ed.Ferguson@dseg.ti.com): fix to compile sans VI.
- * Brian Campbell (brianc@qnx.com): fixes to compile under QNX and
- to compile with dmake.
- * (guy@netapp.com), Oct '94: patch to use gmacs flag.
- * Andrew Moore (alm@netcom.com): reported many bugs, fixes.
- * William Bader (wbader@CSEE.Lehigh.Edu): fix to compile on SCO Unix
- (strut winsize).
- * Mike Long (mike.long@analog.com): makefile fix - use $manext, not 1.
- * Art Mills (aem@hpbs9162.bio.hp.com): bug fix for vi file completion in
- command mode.
- * Tory Bollinger (tboll@authstin.ibm.com): allow ~ in vi mode to take
- a count.
- * Frank Edwards (<crash@azhrei.EEC.COM>): added macros to vi (@char).
- * Fritz Heinrichmeyer (<Fritz.Heinrichmeyer@FernUni-Hagen.de>): fixes
- to allow compile under Linux 1.4.3.
- * Gabor Zahemszky (<zgabor@CoDe.hu>): SVR3_PGRP vs SYSV_PGRP, many
- bug reports and man page fixes.
- * Dave Kinchlea (<kinch@julian.uwo.ca>): DEFAULT_ENV patches.
- * Paul Borman (<prb@bsdi.com>): j_exit: send HUP, then CONT; HUP fg process.
- * DaviD W. Sanderson (<dws@ssec.wisc.edu>): patches to allow { .. } instead
- of in .. esac in case statements.
- * ? (<ra@rhi.hi.is>): partial patches to handle SIGWINCH for command line
- editing.
- * Jason Tyler (<jason@nc.bhpese.oz.au>): fixes for bugs in fc.
- * Stefan Dalibor (<Stefan.Dalibor@informatik.uni-erlangen.de>): fix for
- COLUMNS never being set in x_init().
- * Arnon Kanfi (<arnon@gilly.datatools.com>): fix for prompt.
- * Marc Olzheim (<marcolz@stack.urc.tue.nl>): patches to ifdef KSH the
- mail check code and aliases.
- * Lars Hecking (<lhecking@nmrc.ucc.ie>): fixes so shell compiles as sh
- again.
- * Bill Kish (<kish@browncow.com>): added prompt delimiter hack for
- hidden characters (eg, escape codes).
- * Andrew S. Townley (<atownley@informix.com>): fixes for NeXT machines:
- get a controlling if one needed, use correct profile.
diff --git a/bin/pdksh/ChangeLog b/bin/pdksh/ChangeLog
deleted file mode 100644
index b515993f3aa..00000000000
--- a/bin/pdksh/ChangeLog
+++ /dev/null
@@ -1,1071 +0,0 @@
-$OpenBSD: ChangeLog,v 1.5 1996/11/21 07:59:25 downsj Exp $
-
-Tue Oct 29 11:34:58 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.2.12 distribution
-
-Fri Oct 25 11:59:48 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(vi_cmd): case Cntl('i'): dont fall through, call complete_word().
-
-Tue Oct 22 17:38:21 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * table.h(USERATTRIB): new define.
- * c_ksh.c(c_typeset): report unset params only if it has some
- interesting attributes.
-
-Tue Oct 22 15:54:39 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * jobs.c(exchild): changed NEED_PGRP_SYNC code so j_sync_pipe[1] isn't
- left open in 2nd+ children.
-
-Tue Oct 22 12:59:49 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * main.c(main): memset() env to 0.
-
-Mon Oct 21 12:53:44 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * main.c(cleanup_proc_env): new function.
- * exec.c(execute): call cleanup_proc_env() before calling ksh_execve().
-
-Fri Oct 11 22:53:57 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(display): use ch not e->buf[cur] when printing character.
-
-Fri Oct 11 13:26:11 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * aclocal.m4(KSH_TIMES_CHECK,KSH_DUP2_CLEXEC_CHECK,KSH_OPENDIR_CHECK):
- changed sense of test so "yes" result is printed if you have a good
- system.
- * aclocal.m4(KSH_C_FUNC_ATTR): changed return type of test_cnst to int.
-
-Fri Oct 11 13:05:40 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * syn.c(get_command): added inalias() call when setting cf = CONTIN.
-
-Thu Oct 10 16:22:03 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.c(getsc__): case SALIAS: if we read eof, break, don't continue.
-
-Tue Oct 8 13:14:00 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * aclocal.m4(KSH_TERM): added SYS_IOCTL_WITH_TERMIOS,
- SYS_IOCTL_WITH_TERMIO tests.
- * tty.h: include <sys/ioctl.h> with <termios.h>/<termio.h>
- if possible.
-
-Tue Oct 8 11:42:36 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.2.11 distribution
-
-Tue Oct 8 11:02:54 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * syn.c(inalias): new function.
- * syn.c(c_list): call inalias() instead of testing source->type.
-
-Mon Oct 7 17:00:40 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.2.10 distribution
-
-Mon Oct 7 16:23:53 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_sh.c(c_read): when printing prompt, use isatty, not FTALKING.
-
-Wed Oct 2 12:00:51 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.c(yylex): redirection stuff: save result of getsc() == '-'
- and use it for ungetsc().
-
- * lex.h(struct source): moved ugbuf out of union so it can be used
- with alias stuff.
- * lex.c(getsc__) case SALIAS: instead of appending a space, get the
- next character and stuff it in ugbuf.
-
- * lex.c(getsc_,getsc__): getsc_() renamed to getsc__().
- * lex.c(getsc_,getsc): getsc() macro renamed to getsc_().
- * lex.c(backslash_skip,ignore_backslash_newline): new variables.
- * lex.c(getsc): new macro that checks backslash_skip.
- * lex.c(getsc_bn_,getsc_bn): getsc_bn() macro deleted (all calls
- replaced with getsc()); getsc_bn_ renamed to getsc_bn.
- * lex.c(ungetsc_,ungetsc): ungetsc() macro deleted; renamed ungetsc_()
- to ungetsc().
- * lex.c(yylex,ungetsc,getsc_bn): set and use backslash_skip,
- ignore_backslash_newline.
- * lex.c(yylex): removed special cases for backslash-newline sequence,
- explicitly ignore backslash followed by eof.
-
-Mon Sep 30 17:14:41 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.2.9 distribution
-
-Mon Sep 30 12:52:21 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.c(pprompt): fixed usage of ntruncate.
-
-Thu Sep 19 17:43:33 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(KSH_SYSTEM_PROFILE): new define.
- * main.c(main): use KSH_SYSTEM_PROFILE.
-
- * aclocal.m4(KSH_OS_TYPE): added case for NEXT.
-
-Thu Sep 19 15:39:54 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * tty.c(tty_init): added hack for NeXT's rlogin's missing controlling
- tty.
-
-Mon Sep 16 11:18:10 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * edit.c(add_glob): don't append a * to a ~username.
-
- * edit.c(x_init): set got_sigwinch before calling check_sigwinch().
-
-Wed Sep 11 14:38:38 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ksh.c(c_let): ifdef'd KSH.
- * lex.h(SDPAREN),lex.c: ifdef'd KSH all uses of SDPAREN.
- * lex.h(MDPAREN),syn.c: ifdef'd KSH all uses of MDPAREN.
-
-Mon Sep 9 16:18:03 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * aclocal.m4(AC_PROG_CC): replaced autoconf's version with
- modified version.
-
- * configure.in(clock_t): check in sys/time.h as well.
- * ksh_times.h: include ksh_time.h.
- * ksh_time.h,ksh_times.h: added ifndef KSH_TIME_H/KSH_TIMES_H.
-
-Fri Sep 6 13:20:24 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * edit.c(promptlen): X\r hack for delimiting hidden characters
- in prompt.
- (Based on fix from Bill Kish)
-
-Tue Sep 3 11:03:26 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * Makefile.in: removed options.h from HDRS (also removed file).
-
-Thu Aug 29 10:04:01 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * aclocal.m4(KSH_MEMMOVE): added return 0 to end of main().
-
-Fri Aug 23 14:23:50 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * aclocal.m4,ksh_stat.h: changed S_IFFIFO to S_IFIFO.
-
-Fri Aug 23 09:58:09 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * var.c(skip_wdvarname): don't check for array if first char
- isn't [.
-
-Thu Aug 22 12:51:25 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * jobs.c: added ifdef KSH around Coproc_id/j->coproc_id usagae.
- * c_ksh.c(c_read): added ifdef KSH around opipe.
-
-Tue Aug 20 09:41:32 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * configure.in: fixed quoting of sed LDSTATIC expression.
-
-Mon Aug 19 14:26:08 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.2.8 distribution
-
-Mon Aug 19 11:38:16 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * table.c(texpand): don't free entry if FINUSE is set.
-
- * var.c(unset): preserve ARRAY and DEFINED if unsetting foo[0].
-
-Thu Aug 15 15:08:52 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * jobs.c(sm_sigchld,sm_default): moved to sh.h.
- * sh.h(Coproc_id, struct coproc): new typedef; added njobs and
- id fields to struct coproc.
- * exec.c(execute): case TCOPROC: re-did coprocess stuff to use
- njobs/coprocess id.
- * jobs.c(struct Job): added coproc_id field.
- * jobs.c(exchild): initialize coproc_id to 0; set job coproc_id
- and increment coproc.njobs in parent.
- * jobs.c(checkjob): check coproc_id and close co-process input/output
- if needed.
-
- * exec.c(iosetup): only play with coprocess fds if this is an
- empty exec.
- * c_sh.c(c_read): commented out coproc_readw_close() call and eof call.
- * c_ksh.c(c_print): commented out closing coprocess fd on EPIPE.
-
- * jobs.c(exchild): in parent, last part of job: use orig_flags (not
- flags) when checking XCOPROC.
-
-Thu Aug 15 15:00:42 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * io.c(get_coproc_fd,cleanup_coproc): renamed to coproc_getfd() and
- coproc_cleanup(), respecitively; changed all calls.
-
-Tue Aug 13 16:56:59 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * expr.c(O_COMMA,P_COMMA): new enums.
- * expr.c(evalexpr): added case for O_COMMA.
-
-Tue Aug 13 15:18:28 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * expr.c(do_ppmm): new function to handle ++/--.
- * expr.c(evalexpr): call do_ppmm() in P_PRIMARY code.
- * expr.c(LAST_BINOP): deleted.
- * expr.c(IS_BINOP): new define.
- * expr.c(evalexpr): use IS_BINOP.
- * expr.c(O_PLUSPLUS,O_MINUSMUNS,opinfo[]): new enums; updated opinfo
- * expr.c(ET_LVALUE,ET_RDONLY): new enums.
-
- * expr.c(token): var code: don't increment cp in iter part of for loop,
- do it in body; don't correct for off by 1 in array or !noasign code.
- * table.h(EXPRLVALUE): new define.
- * expr.c(token): var code: set EXPRLVALUE flag if noassign.
- * expr.c(intvar): copy temp var if EXPRLVALUE set.
- * expr.c(assign_check): new function.
- * expr.c(evalexpr): if assign-op, call assign_check().
-
-Tue Aug 13 11:02:32 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(do_comment),edit.c(x_do_comment): made do_comment generic,
- renamed and moved to edit.c; changed all calls.
- * emacs.c(x_ftab[]): added x_comment.
- * emacs.c(x_defbindings[]): added XFUNC_comment as <esc>#.
- * emacs.c(x_comment): new function.
-
-Mon Aug 12 16:13:36 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * expr.c(ET_BADVAR): deleted.
- * expr.c(ET_RECURSIVE, struct expr.evaling),table.h(EXPRNEVAL): added.
- * expr.c(v_evaluate): if curstate.evaling set, clear EXPRINEVAL.
- * expr.c(evalerr): added ET_RECURSIVE case, removed ET_BADVAR case.
- * expr.c(intvar): do recursion check, call v_evaluate() on value.
-
-Mon Aug 12 14:25:23 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * io.c(coproc_read_close): call coproc_readw_close() instead of
- duplicating code.
-
-Mon Aug 12 11:21:39 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * edit.c(x_locate_word): changed to allow at most 1 leading blank
- before the word.
- * edit.c(x_file_glob,x_command_glob,add_glob): allow zero length word.
- * edit.c(x_cf_glob): allow zero length globs on when doing file
- completion.
-
- * edit.c(x_complete_word): #if 0 - it isn't used...
- * edit.c(x_file_glob,x_command_glob,x_locate_word): made static.
-
- * eval.c(varsub): changed FNOUNSET error from "unset variable"
- to "parameter no set", ala at&t ksh.
-
- * c_ksh.c(c_typeset): print variables that aren't set (just
- leave out the =...).
-
-Mon Aug 12 11:03:22 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(findfunc): removed redundent DEFINED check after tsearch().
-
-Fri Aug 9 22:16:21 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * jobs.c(j_change): when turning off FMONITOR and not FTALKING,
- changed SS_RESTORE_CURR to SS_RESTORE_ORIG.
-
- * edit.c(x_sigwinch): new function.
- * edit.c(x_init): set up signal handler for SIGWINCH; moved
- code to get window size into x_sigwinch(); call x_sigwinch().
- * emacs.c(xx_cols): new variable.
- * emacs.c(x_init): set xx_cols_to x_cols; change all uses of x_cols
- to xx_cols.
- * vi.c(display): when displaying morec, changed x_cols-2 to
- pwidth+winwidth+1.
-
-Fri Aug 9 12:49:00 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * table.h(FKSH): new define.
- * tree.h(struct op): put evalflags into new union u, added ksh_func
- to union; changed all uses of evalflags.
- * syn.c(function_body): set u.ksh_func.
- * exec.c(execute): changed define() arg to t (was t->left).
- * exec.c(define): copy t->left (was t); set FKSH in flag if is
- a ksh function.
- * exec.c(comexec): don't keep assignments for x() style functions.
- * exec.c(comexec: case CFUNC: set kshname ($0) for ksh style functions
- only (was FPOSIX).
-
- * exec.c(execute): case TAND/TOR: pass XERROK on when executing right
- hand side.
-
- * jobs.c(exchild): deleted redundant code to set j->flags
- (near new_job() call).
-
- * sh.h(ksh_tmout),main.c(alarm_init),trap.c(alarm_init,alarm_catcher):
- ifdef'd KSH.
-
- * sh.h(SS_SHTRAP,Trap.shtrap): added.
- * trap.c(trapsig): if shtrap is non-zero, call it.
- * trap.c(setsig): set shtrap if SS_SHTRAP set.
- * jobs.c(j_init),trap.c(alarm_init): pass SS_SHTRAP.
- * jobs.c(j_sigchld),trap.c(alarm_catcher): don't call trapsig().
- * trap.c(Sigact_alarm): removed.
-
-Thu Aug 8 15:57:14 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(comexec): case CEXEC: print cannot execute error only
- if / in pathname; also, set exit code to 126.
-
- * exec.c(do_selectargs): added print_menu arg; only print
- menu if this is set, or if REPLY is null; removed "while isspace"
- loop.
- * exec.c(execute): case TSELECT: call do_selectargs with print_menu
- of TRUE on first call only.
-
- * exec.c(define): added was_set variable and logic.
- * c_sh.c(c_unset): return 1 if variable/function to be unset wasn't
- set to begin with.
-
-Wed Jul 31 10:33:00 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(Tflag): new type.
- * sh.h(builtin_flag): changed type to Tflag.
- * table.h(struct tbl): changed type of flag field to Tflag.
- * c_ksh.c(typeset): changed type of flag, fset, fclr to Tflag.
- * c_ksh.c(c_alias): changed type of xflag to Tflag.
- * exec.c(comexec): changed type of old_inuse to Tflag.
- * exec.c(builtin): changed type of flag to Tflag.
- * var.c(typeset): changed set, clr args to Tflag; convert second
- arg of call to local() to boolean.
-
-Wed Jul 31 10:26:25 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(C_QUOTE): new define.
- * sh.h(ctypes[]),misc.c(ctypes[]): changed from char to short.
- * misc.c(initctypes): set C_QUOTE bits in ctypes[].
- * misc.c(print_value_quoted): use C_QUOTE.
-
-Mon Jul 29 11:38:36 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.c(set_prompt): don't print warning message if setjmp returns
- non-zero.
-
-Fri Jul 26 10:16:27 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.c(set_prompt): don't do ! and parameter expansion if !KSH.
-
- * table.h(V_MAIL,V_MAILPATH,V_MAILCHECK): ifdef KSH.
- * var.c(initvar,setspec,unsetspec): ifdef KSH use of MAIL stuff.
- * mail.c: ifdef KSH whole file.
- * main.c(shell): ifdef KSH call to mcheck().
- * main.c(initcoms[]): ifdef KSH the MAILCHECK=600.
- (based on patches from Marc Olzheim).
-
- * exec.c(PS4_SUBSTITUTE): new macro.
- * exec.c(execute, comexec, iosetup): use PS4_SUBSTITUTE.
-
-Thu Jul 25 17:19:17 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(F_VIESCCOMPLETE): new define.
- * misc.c(options[]): added vi-esccomplete.
- * vi.c(classify[]): make ^[ a repeatable command.
- * vi.c(vi_cmd): check F_VIESCCOMPLETE for ^[.
-
-Mon Jul 22 16:54:38 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ksh.c(c_getopts): return if variable is readonly; don't change
- OPTIND if option is bad (fragile).
- * c_sh.c(c_brkcont): use ksh_getopt(); changed error message if
- n <= 0.
- * c_sh.c(c_dot,c_eval,c_exitreturn): use ksh_getopt().
- * misc.c(ksh_getopt): print `unknown option' instead of `bad option'.
-
-Mon Jul 22 16:08:40 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * edit.c(x_init): do NOT export COLUMNS/LINES - causes more problems
- than it fixes.
-
-Mon Jul 22 15:49:35 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * syn.c(get_command): fixed test for '< foo (command)' so it
- works.
-
-Fri Jun 21 09:57:47 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * aclocal.m4(KSH_OPENDIR_CHECK): include dirent.h if HAVE_DIRENT_H
- defined (was DIRENT || _POSIX_VERSION).
- * aclocal.m4(KSH_UNISTD_H): don't test HAVE_DIRENT_H when including
- dirent.h.
-
-Wed Jun 12 11:02:32 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_test.c(b_ops[]): added "==" entry (ksh93ism).
-
-Mon Jun 10 14:00:21 1996 Michael Rendell (michael@lyman.cs.mun.ca)
-
- * ksh_stat.h: undef S_ISSOCK if STAT_MACROS_BROKEN defined.
- * aclocal.m4(AC_HEADER_STAT): redefine autoconf's version to handle
- FreeBSD's S_ISSOCK.
-
-Tue Jun 4 08:41:19 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.2.7 distribution
-
- * vi.c(CMDLEN): changed from 16 back to 1024.
-
-Sun Jun 2 11:54:46 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.2.6 distribution
-
-Sun Jun 2 11:46:56 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(search_access): changed ordering of xsuffixes[], rsuffixes[];
- removed code that used xsuffixes[] when suffix is present.
- * lex.c(getsc_line): set O_TEXT/O_BINARY if os/2.
- * main.c(remove_temps): added os2 ifdefs.
- [Changes from Dale DePriest.]
-
-Tue May 21 14:18:22 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(vi_cmd): case '#': call do_comment() to do work.
- * vi.c(do_comment): new function.
- * vi.c(putbuf,grabhist,grabsearch): fixed pesimestic off-by-1 error
- (cbufsize - 1 -> cbufsize).
- * vi.c(vi_hook): case VCMD: case -1: added refresh(0).
- * vi.c(vi_cmd): case 'P': don't move cursor back if nothing added.
-
-Tue May 21 12:03:34 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * emacs.c(do_complete): don't add space if single match and
- it doesn't end with a /.
-
-Tue May 21 11:51:36 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * edit.c(x_init): use typeset to set EXPORT attribute for
- COLUMNS/LINES.
-
-Tue May 21 11:40:12 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * misc.c(parseargs): option setting: ignore context if option
- isn't being changed.
- * misc.c(printoptions): for non-verbose mode: print a set command
- (eg, set -o vi -o ...) instead of just the option names.
-
-Tue May 21 11:14:27 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_sh.c(c_brkcont): if n is too big, use last enclosing loop.
-
-Fri May 10 09:27:47 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(Getopt): changed field p from int to unsigned.
-
-Tue May 7 12:10:47 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.2.5 distribution
-
-Tue May 7 11:45:37 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * syn.c(compile): set multiline if source is SSTRING.
- * syn.c(yyparse): don't peek before calling c_list() - build
- TEOF if c_list() fails and c is 0.
- * syn.c(c_list): remove SSTRING test.
- * syn.c(get_command): if EOF is reached, free iops,args,vars.
- * syn.c(syntaxerr): set multiline.on to false when it is used;
- don't use multiline.on if start token is 0.
-
-Tue May 7 10:11:41 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * history.c(c_fc,hist_execute): moved calls to histbackup() from
- c_fc() to hist_execute().
- * history.c(hist_get): number: took out +1 correction as histbackup
- hasn't been done yet; string: added -1 correction to ensure
- current fc command isn't searched.
- * history.c(hist_get_newest,hist_get_oldest): don't find the
- current (fc) command; removed print_err argument (was always
- true).
- * history.c(hist_get,hist_get_newest): added allow_cur argument;
- changed all calls.
-
-Mon May 6 09:55:29 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * emacs.c(x_nextcmdp): renamed to x_nextcmd, changed from
- char ** to int.
- * emacs.c(x_nl_next_com): save absolute command number, not
- relative position in history array (which changes).
- * emacs.c(x_emacs): convert x_nextcmd back to relative position.
- * emacs.c(x_init_emacs): initialize x_nextcmd to -1.
-
-Sun May 5 13:10:48 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * expr.c(evalexpr): when assigning a non-integer, call setint()
- (not setstr(..., strval(...))).
-
-Sun May 5 12:16:11 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * mail.c(maddmsg): changed name to mprintit(); now prints message
- directly instead of saving in a linked list; changed all calls.
- * mail.c(mprint): deleted; deleted all calls.
- * mail.c(mmsgs,struct mailmsg): deleted.
-
-Sun May 5 11:52:05 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.h(SF_TTY): new flag.
- * lex.h(STTY): deleted.
- * main.c(main): if tty, use SSTDIN, set SF_TTY.
- * main.c(shell): check SF_TTY instead of STTY.
- * lex.c(getsc_): call getsc_line for SSTDIN/SFILE.
- * lex.c(getsc_line): new function (merged old STTY/SSTDIN/SFILE code).
-
-Fri May 3 11:24:17 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * main.c(shell): changed exit_atend to toplevel. Changed interactive
- to be falking&toplevel (was talking&s->type==STTY).
-
-Fri May 3 10:59:22 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * var.c(getint): only allow one base (ie, disallow 2#4#5).
-
-Thu May 2 21:31:23 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * var.c(array_index_calc): new function
- * var.c(global): call array_index_calc(); moved $2 code into
- if (!letter(c))...
- * var.c(local): call array_index_calc(); added copy argument & code;
- changed all calls.
- * table.h(LOCAL_COPY): new define.
- * exec.c(comexec): maybe pass LOCAL_COPY to typeset().
-
-Thu May 2 16:34:29 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * emacs.c: command completion changes.
- * emacs.c(Comp_type,CT_LIST,CT_COMPLETE,CT_COMPLIST): new type.
- * emacs.c(x_ins): return type changed to int; return -1 if
- string can't be inserted.
- * emacs.c(x_do_ins): new function.
- * emacs.c(add_stash,list_stash,compl_dec,compl_file,compl_command,
- str_match): deleted; changed callers to use do_complete().
- * emacs.c(do_complete,x_expand): new functions.
- * emacs.c(x_ftab[],x_defbindings[]): added entry for file-expand;
- bound to <ESC>*.
-
-Thu May 2 15:31:32 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.c(set_prompt): pass strlen() + 1 to shf_sopen.
- (fix from Arnon Kanfi).
-
-Wed Apr 24 11:50:52 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * history.c(c_fc): -e -: don't increment wp past null; allow
- pat=replace arg with "-1" type argument.
- (based on fix from Jason Tyler).
-
-Mon Apr 15 11:58:34 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * table.c(tenter),alloc.c(alloc): changed use of offsetof() so field
- parameter is a constant expression.
- * sh.h: took out undef of offsetof on CRAYs.
-
-Fri Apr 12 16:01:40 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * jobs.c(JF_USETTYMODE): renamed JR_ORIGFG to JF_USETTYMODE.
- * jobs.c(j_waitj): clear JF_USETTYMODE if fg job is stopped.
-
-Sun Apr 7 12:35:30 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ksh(c_print): echo: don't treat a lone minus as an option.
-
-Sat Apr 6 00:09:37 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ulimit.c(c_ulimit.c): always pass 2 args to ulimit().
- * ksh_sigsetjmp(): changed all uses to be simple expressions - seems
- to be required by the cray C compiler.
- * sh.h(offsetof): undef if on a cray.
- (based on fixes from Dave Kinchlea)
-
-Sat Mar 23 13:58:12 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * siglist.in: added WAITING,LWP,FREEZE,THAW,CANCEL
-
-Thu Mar 7 23:26:37 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * edit.c(x_init): set LINES if possible.
-
-Thu Mar 7 23:01:55 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * main.c(main): call x_init() after j_init()
- (based on fix from Stefan Dalibor).
-
-Thu Mar 7 16:13:10 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * aclocal.m4(KSH_OS_TYPE): check for TitanOS (use cc -43).
- * aclocal.m4(KSH_SIGNAL_TYPE): for bsd41 signals, check if signal
- interrupt read().
-
-Thu Mar 7 13:59:29 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(strstr),missing.c(strstr): changed args to const.
-
-Wed Mar 6 17:21:36 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * io.c(errorf,bi_errorf): changed null pointer string check to
- empty string; changed all calls (due to new error gcc warnings).
-
-Wed Mar 6 17:15:58 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(search_access): files aren't executable if they don't
- have any execute bits.
- * ksh_stat.h: added S_IXUSR,S_IXGRP,S_IXOTH.
- * exec.c(search_access,search_access1): OS2: changed the meaning
- of these two functions (search_access1 now called from search_access).
-
-Wed Mar 6 16:23:23 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * tree.c(ptree): add case for TSELECT.
-
-Wed Mar 6 12:40:34 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(Z_,is_zeroarg): new defines.
- * vi.c(classify): use Z_ for G, g, _, |, v, ^I, ^F.
- * vi.c(vi_cmd): use is_zerocount().
- * vi.c(complete_word): if command prefixed by a count, complete
- to count'th expansion (as reported by print_expansions()).
-
-Tue Mar 5 14:43:48 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * eval.c(GF_NONE,GF_EXCHECK,GF_GLOBBED,GF_MARKDIR): new defines.
- * eval.c(glob_str): added markdirs argument; changed all calls;
- made function non-static.
- * eval.c(glob): added markdirs argument; changed all calls.
- * tree.h(DOMARKDIRS): new define.
- * eval.c(expand): set DOMARKDIRS if FMARKDIRS.
- * edit.c(x_complete_word,x_print_expansions,x_file_glob,x_command_glob,
- x_locate_word,x_cf_glob,x_add_glob,x_longest_prefix,x_free_words):
- new functions.
- * proto,edit.h: moved functions defined in edit.c to edit.h.
- * vi.c(struct edstate): moved to top of file.
- * vi.c(print_expansions): added struct edstate argument; changed all
- calls.
- * vi.c(struct glob,Glob,globstr,glob_word,): deleted
- * vi.c(vi_pprompt): new function; changed all calls of pprompt() in
- vi.c to use vi_pprompt().
- * vi.c(x_vi): moved to top of file.
- * vi.c(expand_word,complete_word): free buf if it is not null.
- * vi.c(expand_word,complete_word,print_expansions): changed
- to use new edit.c functions.
-
-Tue Feb 20 11:02:05 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * table.c(twalk,tnext,struct tstate),table.h(struct tstate): moved
- struct tstate from table.c to table.h; changed twalk,tnext to take
- struct tstate* argument; changed all calls; deleted static tstate
- variable.
-
-Sat Feb 17 12:28:11 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(vi_hook): case VSEARCH: if new pattern is empty, repeat last
- search.
-
-Sat Feb 10 15:59:28 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * table.h(struct arg_info): new struct.
- * table.h(struct block): changed argv, argc fields to argi.
-
-Sat Feb 10 15:12:47 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- ANSI C name space requirements:
-
- * vi.c(isbad,iscmd,islong,ismove,issrch,isundoable,iswordch): changed
- to is_bad,is_cmd,is_long,is_move,is_srch,is_undoable,is_wordch.
- * emacs.c(iscfs,ismfs): changed to is_cfs, is_mfs.
- * emacs.c(strmatch): changed to str_match.
- * sh.h(strchr_dirsep,strrchr_dirsep): changed to ksh_strchr_dirsep,
- ksh_strtchr_dirsep; changed all calls.
- * missing.c(strichars[]): changed to ichars[].
- * var.c(strint,strval): changed to setint_v, str_val.
- * missing.c(strsave,strnsave): changed to str_save,str_nsave.
-
-Fri Feb 9 11:30:15 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * main.c(main): remove envp parameter; declare and use environ.
-
- * c_ksh.c(c_print): octal digit escape sequences must start with \0.
-
-Sat Feb 3 15:35:41 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(vi_cmd,classify[]): made ^I a command.
-
-Fri Feb 2 10:40:32 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.h(struct source): added u.freeme field.
- * lex.c(getsc_): case SREREAD: free u.freeme iff start isn't u.ugbuf.
-
-Thu Feb 1 15:27:06 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_test.h(Test_env): added end union.
- * c_test.c(c_test): keep track of end postition using end.wp;
- don't write on wp.
-
- * emacs.c(x_mapin): changed to dup string, then munge; return duped;
- changed all calls.
-
- * eval.c(homedir): deleted getpwnam() declaration - can't believe
- its needed anywhere (we shall see, though).
-
- * sh.h(handler_t): use ARGS for prototype; use h
- * sh.h(struct trap),trap.c(setsig,settrap),sigact.c,sigact.h:
- use handler_t.
- * history.c,c_sh.c,c_ksh.c: removed register declaration from
- c_*() functions.
- * exec.c(builtin),proto.h(builtin): use prototype for func.
- * misc.c(qsortp,qsort1),proto.h(qsortp): use prototype for f.
-
- * c_ksh.c(ksh_getopt): made options arg const.
- * tree.c(fptreef,snptreef,vfptreef): made fmt arg const.
- * jobs.c(waitfor,j_kill,j_resume,j_lookup,j_jobs): made cp arg const.
- * shf.c(shf_snprintf,shf_smprintf,shf_vfprintf): made fmt arg const.
- * c_test.h(Test_env.error),c_test.c(ptest_error): made msg arg const.
- * c_test.c(test_stat,test_eaccess): made path arg const.
- * c_test.c(ptest_getopnd,dbteste_getopnd): made return value const.
- * c_test.c(ptest_eval,test_eval,dbteste_eval,dbtestp_eval,test_primary):
- made opnd1,opnd2 arg const.
- * c_test.c(test_isop): made s arg const.
-
- * misc.c(bi_getn,getn): made as arg const.
- * misc.c(getn): made as arg const.
- * misc.c(gmatch): made s/p arg const.
- * misc.c(has_globbing): made xp/xpe arg const.
- * misc.c(do_gmatch): made s/p/se/pe arg const.
- * misc.c(cclass): made p arg const.
-
-Thu Feb 1 14:54:32 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * edit.h, sh.h, tty.h: changed _I_ to I__.
- * edit.h, edit.c: changed _D_ to D__.
-
- * jobs.c,shf.c,tty.c: include ksh_stat.h (POSIX: needed for open).
-
- * sigact.c: use ARGS instead of __P; comment out __P defines.
-
- * shf.c: include math.h if FP.
- * shf.c(my_ceil): remove modf() declaration.
- * shf.c(shf_fvprintf): comment out frexp() declaration; changed
- exp to expo.
-
- * jobs.c(struct job, j_utime, j_stime): changed utime/stime to
- usrtime/systime; change j_utime/j_stime to j_usrtime/j_systime.
-
-Wed Jan 31 16:13:44 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * edit.c(x_getc): cast return value to int to avoid warnings on
- strange compilers.
- * exec.c(funcfunc): changed second arg to unsigned int (was int).
- * syn.c(elsepart): move return NULL to end of function (avoids
- warning from some compilers).
- * vi.c(classify[]): changed type to unsigned char.
- * shf.c(shf_smprintf): delete unused variable n.
- * aclocal.m4(KSH_TIMES_CHECK): define INT32 in test code.
- * aclocal.m4(KSH_SIGNAL_CHECK): typeo: had bsd42 instead of bsd41.
- * sh.h(MAGIC): changed to 7 to increase portability.
- * jobs.c(tcsetpgrp,tcgetpgrp): define if TTY_PGRP (was TIOCSPGRP).
-
-Tue Jan 23 11:40:25 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(ksh_jmp_buf): new define.
-
-Thu Jan 18 15:03:19 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * history.c(hist_replace): fixed substitution code (again).
-
-Wed Jan 17 20:10:02 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.2.4 distribution
-
- * main.c(initcoms): changed hash alias to "hash=alias -t".
-
- * exec.c(do_selectargs): deleted c_read() declaration.
-
- * c_ksh(c_alias): call ksh_getopt_reset() before calling c_unalias().
-
-Wed Jan 17 19:47:55 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * history.c(histbackup): changed "histptr > history"
- to "histptr >= history".
-
- * history.c(hist_replace): removed un-needed "last" - use "s" instead.
- (based on fix from Jason Tyler).
-
-Thu Jan 11 15:59:46 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ksh.c(c_whence,c_command),main.c(initcoms[]): removed ifdef KSH
- (type is a builtin in sys-5 sh).
-
-Wed Jan 10 11:49:59 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * Makefile.in: added NEWS.os2 to OS2FILES.
-
- * version.c: include "sh.h" (needed for const define).
-
- * exec.c(pr_menu): made non-static.
- * vi.c(print_expansions): gather expansions into an arrat
- and use pr_menu().
- (fixes from Mike Jetzer).
-
- * vi.c(redraw_line): added newline option; changed all calls.
-
-Wed Jan 10 10:21:06 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(classify): made 'U' a C_.
- * vi.c(ohnum): new variable.
- * vi.c(vi_reset): set ohnum to hlast.
- * vi.c(grabhist): set ohnum.
- * vi.c(vi_cmd): case n,N,/,? set ohnum; added case 'U'.
- * vi.c(edit_reset): clear holdlen.
- (based on fix from Dale DePriest).
-
-Tue Jan 9 11:23:36 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * emacs.c(iscfs): make ', " seperators.
- (fix from Dale DePriest).
-
- * conf-end.h: deleted stuff to undef HISTORY, VI, EMACS, etc if
- KSH wasn't defined (now done in configure).
-
- * sh.h(GI_NONAME): changed to GF_NONAME; changed all uses.
-
- * configure.in: added AC_ARG_PROGRAM.
- * Makefile.in: replaced binprefix and manprefix with
- program_transform stuff.
-
-Mon Jan 8 11:42:46 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(struct temp): added shf field.
- * io.c(maketemp): changed to use O_EXCL; keep trying if open
- fails (due to O_EXCL); fill in shf field; changed all calls.
-
- * main.c(include): added intr_ok flag; changed all calls.
-
- * main.c(main): if compiled as sh and posix option not set, do not
- include $ENV.
-
- * trap.c: define FROM_TRAP_C before including sh.h.
- * sh.h: don't declare sigtraps if FROM_TRAP_C declared.
-
- * c_ksh.c(c_cd): fixed error message.
- * vi.c(glob_word): don't add * if word contains a $.
- (Based on fixes from Mike Jetzer).
-
- * eval.c(tilde): if HOME,PWD,OLDPWD aren't set, don't expand
- ~,~+/~-.
-
-Fri Jan 5 12:15:58 NST 1996 Michael Rendell (michael@garfield.cs.mun.ca)
-
- * c_ksh.c(c_typeset): seperate loop for printing functions
- (do not traverse array link).
- * c_ksh.c(c_typeset): list functions: do not ignore unset functions.
- * exec.c(findfunc): set val.t to 0 when creating new entry.
- * exec.c(define): if FINUSE, use tail recursion.
-
-Thu Jan 4 11:10:22 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(globstr): deleted ifdef'd out code.
-
-Sun Dec 10 11:07:52 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.c(yylex): added case for STBRACE; wrap word part of
- trim substitution in @(..).
- * eval.c(trimsub): deleted code to wrap pattern in @(..); changed
- '%' code to use strnsave().
-
-Fri Dec 8 22:55:56 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * eval.c(trimsub): if trim pattern contains a |, wrap pattern
- in @(...).
- * lex.c(yylex): make | special when incounted in a ${...}
- substitution.
-
-Fri Dec 8 11:52:38 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * var.c: ifdef'd HISTFILE, HISTSIZE stuff with HISTORY (was KSH).
-
- * *.c,*.h: ifdef'd coprocess stuff with KSH.
-
-Thu Dec 7 14:41:06 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
- * options.h(BRACEEXPAND): changed to BRACE_EXPAND; changed all
- references.
-
-Thu Dec 7 13:54:20 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
- * exec.c(do_selectargs): don't print newline on eof.
-
-Thu Dec 7 10:23:30 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
- * c_ksh.c(c_print): added -f for OS2.
- * tree.h(DODIRSWP),eval.c: deleted define and all uses of it.
- * exec.c(scriptexec): ...
- * io.c(check_fd): set O_TEXT/O_BINARY flag for OS2.
- * main.c(main): set O_BINARY/O_TEXT, search path for arg.
- * emacs.c(compl_file): call opendir with buf, not dirnam.
- (based on changes from Dale DePriest).
-
-Wed Nov 29 15:50:36 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
- * eval.c(expand,debunk): handle extended pattern matching stuff.
- * eval.c(debunk): now has two arguments, changed all calls.
- * eval.c(globit): changed to use has_globbing.
- * eval.c(copy_non_glob): deleted.
-
- * misc.c(has_globbing): new function.
- * misc.c(cclass): changed argument to unsigned char *; handle
- extended pattern matching.
- * misc.c(do_gmatch): new function (taken from gmatch()).
- * misc.c(gmatch): changed to call do_gmatch.
- * misc.c(do_gmatch): added cases for extended pattern matching
- (*(foo|bar), etc.).
- * misc.c(pat_scan): new function.
-
- * lex.c(yylex): added SPATTERN case.
-
- * lex.c(arraysub): changed to assume just past the leading [
- (was assuming about to read [); changed all calls; changed
- to use getsc_bn().
-
- * lex.c(ungetsc): added argument; changed all calls; can now unget
- arbitrary number of characters.
- * lex.c(ungetsc_): new function.
-
- * lex.h(struct source): added start field, removed u.start field,
- changed all uses.
- * lex.c(getsc_): case STTY: skip blank line only if this is first line
- of a command (eg, not part of here documennt, etc.).
-
- * lex.c(yylex): case SHEREDELIM,SHEREDQUOTE: ignore \newline.
- * lex.c(readhere,get_brace_var): ignore \newline.
- * lex.c(getsc_bn,getsc_bn_): new define/function.
-
- * exec.c(iosetup): don't enforce noclobber for non-regular files.
-
- * tree.h(OPAT,SPAT,CPAT): new defines.
- * tree.c(tputS,wdscan): added cases for OPAT,SPAT,CPAT.
-
- * lex.c(yylex): moved case '[' from Subst: switch to case SBASE:.
-
-Tue Nov 14 11:00:48 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
- * syn.c(get_command,caselist): moved parsing of IN/ESAC into
- caselist; allow {/} instead of IN/ESAC;
- * syn.c(casepart): new parameter: endtok.
- * lex.c(yylex): allow } as well as ESAC when ESACONLY set.
- (changes based on fix from DaviD W. Sanderson).
-
-Tue Nov 14 10:22:17 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
- * main.c(shell): do not zero exstat at start of routine.
-
- * exec.c(execute): removed redundent "exstat = rv" before
- unwind(LERROR).
-
-Thu Nov 9 15:01:54 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
- * var.c(arrayname): made argument const.
- * var.c(typeset): made var argument const.
- * var.c(export): made val argument const.
- * tree.c(wdscan): changed return type to non-const (added casts).
-
-Thu Nov 9 14:39:49 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ksh.c(c_alias),c_sh.c(c_set): made args[] array const.
- * c_ulimt.c(c_ulimit): made limits[] array const.
- * edit.c(x_mode): x_cur_mode no longer explicitly initialized to 0.
- * emacs.c(x_tab,x_atab): no longer explicitly initialized to 0.
- * exec.c(comexec): made texec non-static, non-initialized.
- * history.c(hist_finish): once no longer explicitly initialized to 0.
- * io.c(maketemp): io no longer explicitly initialized to 0.
- * jobs.c(job_list,last_job,async_job,free_jobs,free_procs): no longer
- explicitly initialized to 0.
- * jobs.c(lookup_msgs[],tt_sigs[]): made array const.
- * mail.c(mplist,mbox,mlastchkd,mmsgs): no longer explicitly
- initialized to 0.
- * vi.c(expand_word,complete_word): buf no longer explicitly
- initialized to 0.
- * vi.c(classify[]): made array const.
-
-Tue Nov 7 11:08:01 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * mkman: new script
- * Makefile.in: use mkman to generate ksh.1
- * ksh.Man,ksh.1: renamed ksh.1 to ksh.Man
- * ksh.Man: changed way sh/ksh option handled.
- (changes based on fix from Michael Haardt).
-
-Tue Sep 19 09:53:53 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * jobs.c(j_stopped): deleted function.
- * jobs.c(j_exit): send SIGCONT, then SIGHUP; send SIGHUP if
- job is in foreground.
- (based on fix from Paul Borman)
-
- * Makefile.in: move .PRECIOUS to after all.
-
-Wed Sep 13 15:00:22 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(dbteste_getopnd): changed tests from TO_STLT/TO_STGT
- to TO_STEQL/TO_STNEQ.
-
-Thu Aug 31 11:54:02 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * jobs.c(exchild): if fork fails, allow user to ^C out of loop.
-
-Tue Aug 29 09:40:37 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(iosetup): don't do globing if not interactive (POSIX).
-
- * exec.c(iosetup): print <& or >& as appropriate in error message.
-
- * tree.h(IONAMEXP): new define.
- * tree.c(pioact): handle IONAMEXP.
- * exec.c(iosetup): set IONAMEXP.
-
- * io.c(savefd): added noclose parameter; changed all calls.
- * exec.c(iosetup): move call to savefd() to after the open();
- re-arranged the dup'ing (failed dups reported).
-
- * main.c(shell): call quitenv() before internal_error().
-
-Sun Aug 13 21:38:44 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(ksh_sigsetjmp,ksh_siglongjmp): new defines; changed
- all uses of setjmp/longjmp to these.
- * configure.in: added checks for sigsetjmp() and _setjmp().
-
-Wed Jul 26 10:08:23 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ulimit.c(c_ulimit): added -p ("maxproc", RLIMIT_NPROC)
- (fix from Simon J. Gerraty).
-
-Thu Jun 29 10:22:51 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * edit.c(promptlen): added spp parameter; changed all calls.
- * vi.c(prompt_skip): new variable.
- * vi.c(edit_reset): set prompt_skip; use prompt_skip in all calls
- to pprompt().
-
-Sat Jun 24 15:55:03 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * IAFA-PACKAGE: new file.
- * Makefile.in: added IAFA-PACKAGE to DISTFILES.
-
-Mon Jun 19 10:04:52 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * main.c(initcoms[]): added EXTRA_INITCOMS.
-
-Fri Jun 16 12:33:10 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(search_access1): use FILECMP() instead of strcmp().
-
- * sh.h(FIELCHCONV): OS2 version: added isascii().
- * misc.c(gmatch); took unsigned out again for sc and pc.
-
- * main.c(main): don't set PS1 if it's already set; set it if
- we are root and prompt doesn't contain a #.
-
diff --git a/bin/pdksh/ChangeLog.0 b/bin/pdksh/ChangeLog.0
deleted file mode 100644
index 23dc38eb028..00000000000
--- a/bin/pdksh/ChangeLog.0
+++ /dev/null
@@ -1,3589 +0,0 @@
-$OpenBSD: ChangeLog.0,v 1.1 1996/08/14 06:19:10 downsj Exp $
-
-Thu Jun 15 11:02:06 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.2.3 distribution
-
- * c_ksh.c(c_whence): search keyword table if vflag set.
-
- * tree.h(DOVACHECK): new define.
- * eval.c(expand): check DOVACHECK flag.
- * exec.c(execute): when calling eval(), or in t->evalflags.
- * syn.c(get_command): set evalflags to DOVACHECK instead of DOASNTILDE.
-
-Wed Jun 14 09:27:19 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ksh.c(c_cd): two argument format: use current_wd, not path
- when appending elen bytes.
- (fix from Gabor Zahemszky).
-
-Tue Jun 13 15:54:11 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * history.c(c_fc): if last not specified and !-l, use first as last.
-
- * eval.c(maybe_expand_tilde): allow CSUBST to end tilde word.
-
- * misc.c(gmatch): made sc and pc unsigned.
-
-Fri Jun 2 11:55:40 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * configure.in: added flock to AC_CHECK_FUNCS call.
- * conf-end.h: undef COMPLEX_HISTORY if !HAVE_FLOCK.
-
-Tue May 30 20:38:47 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(SEEK_SET,SEEK_CUR,SEEK_END): define if not defined.
- * history.c: change L_XTND to SEEK_END.
-
-Tue May 30 17:01:34 NDT 1995 John Rochester (jr@panda.cs.mun.ca)
-
- * shf.c(shf_seek): new function.
- * shf.h(shf_seek): new prototype.
-
-Tue May 30 16:42:41 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * aclocal.m4(KSH_DEV_FD): new test.
- * acconfig.h(HAVE_DEV_FD): new define.
- * configure.in: call KSH_DEV_FD.
-
- * c_test.h(TO_FILAXST): new enum.
- * c_test.c(test_stat,test_eaccess): new functions for /dev/fd/n
- handling.
- * c_test.c(test_evalop): call test_stat() and test_eaccess()
- instead of stat() and eaccess() in most places; added case
- for TO_FILAXST.
-
-Tue May 30 16:06:21 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * aclocal.m4(KSH_MEMMOVE): fixed test so copies overlap.
-
-Sun May 28 11:11:03 NDT 1995 John Rochester (jr@panda.cs.mun.ca)
-
- * sh.h(safe_prompt): new variable.
- * main.c(initsubs): removed PS1.
- * main.c(main): initialize safe_prompt; initialize PS1 from
- safe_prompt.
- * lex.c(set_prompt): create new env while expanding PS1 - if expansion
- fails, use safe_prompt.
-
-Sat May 27 20:59:02 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c: put comments around token after #endif.
-
-Thu May 25 10:10:45 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_test.c(test_eval): case TO_OPTION: negate test if option starts
- with a !, always fail if option doesn't exist.
-
- * sh.h(FNOHUP): new define.
- * misc.c(options[]): "nohup" new option.
- * jobs.c(j_stopped,j_stopped_running): name of j_stopped changed
- to j_stopped_running; changed all calls; check for/warn about
- running jobs if appropriate.
- * jobs.c(j_exit): check for/kill running jobs if appropriate.
- * main.c(shell),c_sh.c(c_exit): un-ifdef JOBS the j_stopped_running()
- call and really_exit initialization/clearing.
-
-Wed May 24 10:06:14 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * options.h(DEFAULT_ENV): new define.
- * main.c(main): if ENV isn't set and DEFAULT_ENV is defined, include
- the later.
- (based on patches from Dave Kinchlea).
-
- * sh.h(LAEXPR): new define.
- * expr.c(evaluate): changed return type to error indicator; added
- rval and error_ok arguments; changed all calls (c_sh.c(c_shift),
- c_ulimit.c(c_ulimit),eval.c(expand),var.c(global,local)).
- * expr.c(v_evaluate): added error_ok argument; changed return value
- to error indicator; call unwind() if !error_ok.
- * expr.c(evalerr): changed errorf() to warningf(); call unwind(LAEXPR).
- * c_test.c(test_eval): merged code for integer operations to have
- two calls to evaluate().
-
- * io.c(warningf): print trailing newline; changed all calls.
-
- * history.c(hist_get): string search: use histptr, not histptr - 1.
-
-Tue May 23 11:07:50 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(GI_NONAME): new define.
- * misc.c(ksh_getopts): honour GI_NONAME flag.
- * c_ksh.c(getopts_reset): set GI_NONAME flag.
-
- * exec.c(comexec): don't change $0 if FPOSIX flag set.
-
- * misc.c(ksh_getopt): don't use GI_DONE to allow parsing past
- bad options.
- * sh.h(GI_DONE): deleted define.
-
- * var.c(unset): added array_ref parameter; unset/free whole array
- if not an array_reference; changed all calls.
- * c_sh.c(c_unset): set array_ref parameter if there is a [ in the name.
-
-Mon May 22 10:33:14 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * history.c(hist_init): complex version: initialize hist_source
- (fix from Simon J. Gerraty).
-
-Sat May 20 11:06:15 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.2.2 distribution
-
- * Makefile.in: added c_test.h to HDRS.
-
-Fri May 19 12:35:18 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.2.1 distribution
-
- * emacs.c(v_version): ignore typed character if it is a space.
- * emacs.c(x_emacs_keys): bind <ESC>erase-char to delete-back-word
- (was delete-back-char).
- * emacs.c(x_defkeybindings[]): bound list-file to ^X^Y and
- newline-and-next to ^O, as per man page.
-
- * c_ksh.c(c_whence): changed "is a keyword" to "is a reserved word".
-
- * sh.h: changed SVSV_PGRP to SYSV_PGRP.
-
- * vi.c(vi_cmd): uncommented case for ^[ to make it easy to enable
- completion.
-
-Mon May 15 15:25:22 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * history.c(c_fc): accept -40 as -- -40.
- * main.c(initcoms[]): take -- out of history alias.
-
- * vi.c(print_expansions): handle trailing slash correctly (don't
- print empty strings).
-
- * c_ksh.c(c_cd): put back ksh_get_wd() call for os/2.
-
- * misc.c(ksh_get_wd): changed buf to b in call to getcwd().
-
-Tue May 9 13:57:31 NDT 1995 Michael Rendell (michael@dragon.cs.mun.ca)
-
- * c_test.h: new file.
- * c_test.c: major code restructuring: common parsing/evaluation
- routines call/called-by three sets of routines: one for
- normal test (and [..]), one for parsing [[ .. ]] one for
- evaluating [[ .. ]].
- * c_test.c(oexpr,aexpr,nexpr,primary,is_op): renamed to test_oexpr,
- test_aexpr, test_nexpr, test_primary, test_isop.
- * c_test.c(eval_unop,eval_binop): combined into new test_eval function.
- * c_test.c(syntax): renamed to ptest_error,
- * c_test.c(ptest_isa,ptest_getopnd,ptest_eval): new functions.
- * syn.c(syntaxerr): added extra arg; changed all calls.
- * syn.c(db_parse,db_oaexpr,db_nexpr,db_primary): deleted.
- * syn.c(dbtestp_isa,dbtestp_getopnd,dbtestp_eval,dbtestp_error): added.
- * syn.c(get_command): case DBRACKET: changed to call new routines.
- * tree.c(ptree): case DBRACKET: changed.
- * exec.c(execute): case DBRACKET: changed.
- * exec.c(dbteste_isa,dbteste_getopnd,dbteste_eval,dbteste_error): added.
-
-Fri May 5 17:10:23 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * emacs.c(compl_file,compl_command): fixed buffer growing code.
-
-Thu May 4 22:44:01 NDT 1995 Michael Rendell (michael@garfield.cs.mun.ca)
-
- * aclocal.m4(KSH_UNISTD_H): include <sys/types.h> and only include
- <dirent.h> if HAVE_DIRENT_H is defined.
-
-Thu May 4 21:19:15 NDT 1995 Michael Rendell (michael@garfield.cs.mun.ca)
-
- * c_ksh.c: include "ksh_stat.h".
- * c_ksh.c(c_cd): don't do physical chdir if S_ISLNK not defined.
-
-Wed May 3 10:08:32 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.2.0 distribution
-
- * misc.c: include <ctype.h>.
- * misc.c(gmatch): added isfile argument; changed all calls.
- * sh.h(FILECHCONV): (os2 version) - use isupper.
- * emacs.c(strmatch): don't increment in FILECHCONV.
-
- * aclocal.m4(KSH_HEADER_SYS_WAIT): new macro.
- * configure.in: use KSH_HEADER_SYS_WAIT instead of AC_HEADER_SYS_WAIT.
- * ksh_wait.h: if POSIX_SYS_WAIT not defined, undef W* macros.
-
-Tue May 2 12:10:39 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * emacs.c,emacs-gen.sh,emacs-c.in,emacs.out,Makefile.in: changed emacs
- source munging to create emacs.out which is included by emacs.c
- rather then munging emacs.c itself.
-
- * lex.c(pprompt): flush shl_out.
-
- * vi.c(glob_word): if path has *?[, don't add * (was if last component).
-
- * emacs.c(x_search_char): renamed to x_search_char_forw.
- * emacs.c(x_search_char_back): new function; bound to ^[^].
-
- * sh.h: changed SVR3_PGRP to SYSV_PGRP.
- (fixes from Gabor Zahemszky).
-
-Tue May 2 10:09:57 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ksh.c(c_cd): deleted OS2 ifdefs.
- * path.c(make_path): use ISRELPATH instead of ISABSPATH
- * path.c(simplify_path): use ISROOTEDPATH instead of ISABSPATH.
- * sh.h(ISABSPATH,ISROOTEDPATH,ISRELPATH): changed/new defines.
-
- * aclocal.m4(AC_LANG_C,AC_LANG_CPLUSPLUS,AC_TRY_RUN): copied
- from autoconf's acgeneral.m4, changed to handle .exe suffix.
- * aclocal.m4(KSH_OS_TYPE): os2 case: set $ac_exe_suffix.
- * configure.in: substitute ac_exe_suffix.
- * Makefile.in: changed references to E to exe_suffix, set to
- ac_exe_suffix
-
- * c_ksh.c(c_cd): ifdef S_ISLNK second use of get_phys_path().
- * edit.c(x_mode): removed ifndef OS2.
- (fixes from Dale DePriest)
- * exec.c(search_access1): add .sh to suffix lists.
- * vi.c(vi_insert,vi_hook): OS2: changes to allow arrow keys work
- in insert mode.
-
-Mon May 1 16:28:44 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * path.c(ksh_get_wd): getcwd() case, return alloc'd buffer, not
- a malloc'd one.
-
-Mon May 1 09:41:56 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * aclocal.m4: changed HAVE_SYS_RESOURCES_H to HAVE_SYS_RESOURCE_H.
-
- * aclocal.m4(KSH_OS_TYPE): new macro.
- * aclocal.m4(KSH_OS2_EMX): deleted.
- * configure.in: deleted calls to AC_AIX,AC_MINIX,AC_ISC_POSIX,
- KSH_OS2_EMX; replaced with KSH_OS_TYPE.
- * acconfig.h(OS_ISC,OS_SCO): new undefs.
- * sh.h: changed use of isc386 to OS_ISC
- * edit.c: changed use of M_UNIX to OS_SCO.
-
-Sat Apr 29 21:10:54 NDT 1995 Michael Rendell (michael@garfield.cs.mun.ca)
-
- * vi.c(glob_word): don't append * if there are unescaped globing
- characters in the last component of the filename; some redundent
- code eliminated.
- (based on fix from Michael Jetzer).
-
-Fri Apr 28 16:10:22 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * eval.c(globit): save/restore actual DIRSEP char - don't use DIRSEP.
-
- * c_ulimit.c: removed ARGS from declaration of ulimit to avoid
- portability problems (osf/1 has ulimit(int,...), os2 has
- ulimit(int,long)).
-
- * tty.c(tty_init): added __SCO__ defines to avoid opening /dev/tty.
-
- * configure.in,aclocal.m4,acconfig.h: added KSH_OS2_EMX test.
- * os2/config.h, os2/configure.cmd, os2/make.sed: updated for new
- autoconf.
-
-Tue Apr 25 12:20:45 NDT 1995 Michael Rendell (michael@dragon.cs.mun.ca)
-
- * configure.in: added sys/param.h test; changed getcwd test to getwd.
- * c_ksh.c(c_pwd): new function.
- * sh.h(current_wd, current_wd_size): new variables.
- * c_ksh.c(c_cd): changed to handle -L, -P.
- * main.c(main): use set_current_wd when setting $PWD;
- instead of changing to / when can't get pwd, print warning;
- deleted pwd alias; don't make PWD and OLDPWD reaedonly.
- * path.c(simplify_path): changed to handle relative paths.
- * path.c(make_path): added phys_path argument to support cd -P.
- * path.c(set_current_wd,get_phys_path,do_phys_path): new functions.
- * misc.c(ksh_get_wd): new function.
- * missing.c(getcwd): deleted.
- * misc.c(options[]),sh.h: added "physical", FPHYSICAL.
-
-Mon Apr 24 14:33:03 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * shf.c(shf_smprintf): new function.
-
- * expand.h(Xsize): new define.
-
-Fri Apr 21 21:22:44 NDT 1995 Michael Rendell (michael@garfield.cs.mun.ca)
-
- * sh.h: changed SIZEOF_long to SIZEOF_LONG.
- * exec.c(scriptexec): if OS2 ifdefed code, changed ISDIRSEP to
- explicit /.
-
-Thu Apr 20 21:18:12 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * history.c(hist_get) if n < 0, use n + 1 to account for histbackup().
-
- * lex.c(set_prompt): added source argument; changed all calls;
- changed to do ! and !! substitutions when setting PS1.
- * lex.c(pprompt): ifdef'd out code to deal with ! and !!.
-
- * shf.c(shf_puts): new routine.
- * exec.c(herein), lex.c(getsc_): changed to use shf_puts.
-
-Thu Apr 20 15:50:35 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * siglist.sh: clear traps in subshell to cover for bug in bash 1.4.3
- (based on fix from Fritz Heinrichmeyer).
-
-Wed Apr 19 12:04:59 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(classify): cleaned up table; filled in U_ flag for commands
- that don't modify things.
- * vi.c(first_insert, saved_inslen): new variables.
- * vi.c(vi_reset): don't reset yanklen, inslen, lastcmd, lastac;
- set first_insert, saved_inslen.
- * vi.c(vi_insert): added code to handle first insertion to allow
- redoing commands from last edit.
- (based on fixes from Michael Jetzer).
-
- * vi.c(VVERSION): new state.
- * vi.c(classify): cleared C_ flag for 032 (^Z); set it for ^V.
- * vi.c(nextstate): added VVERSION.
- * vi.c(vi_hook): cases for VVERSION.
- * sh.h(ksh_version): new declaration; removed declaration from
- all other files.
-
- * Makefile.in: removed rcs-ci, rcs-diff targets; put RCSFILES
- into DISTFILES and removed former.
-
- * var.c(newblock): copy argc/argv from previous env if it exists.
-
-Tue Apr 18 23:10:32 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * jobs.c(exchild): report internal error if execute() returns in child.
- * exec.c(execute): case TASYNC: clear exec flag in call to execute().
-
-Tue Apr 18 12:05:23 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * emacs.c(x_bind): added list argument.
- * c_ksh.c(c_bind): added -l (list) option.
-
- * emacs.c,emacs-c.in: moved emacs.c to emacs-c.in.
- * Makefile: add rule to create emacs.c from emacs-c.in.
- * emacs-gen.sh: new file.
- * emacs.c(struct x_defbindings, x_defbindings[]): new struct/array.
- * emacs.c(struct x_ftab, x_ftab[]): removed x_db_tab, x_db_char;
- initialize x_ftab[] via script.
- * emacs.c(x_init_emacs): changed to load key bindings from
- x_defbindings.
- * emacs.c(Findex): added typedef.
- * emacs.c(x_tab[]): changed to index into x_ftab; changed all refernces.
- * emacs.c(xft_*): changed to XFUNC_*.
- * emacs.c(XF_PREFIX): new flag, used for x_meta1, 2, 3.
- * emacs.c(KPREF,KNULL): deleted (no functional use), changed
- references to KSTD.
- * emacs.c(x_last_command): changed type to Findex.
- * emacs.c(x_emacs): set x_last_command to 0 at start; removed
- same from case KEOL.
-
- * emacs.c(XF_ARG): new flag for struct ftab.
- * emacs.c(x_ftab[]): filled in XF_ARG for appropriate commands.
- * emacs.c(x_arg_defaulted): new variable.
- * emacs.c(x_emacs,x_set_arg): set x_arg_defaulted.
- * emacs.c(x_bword, x_fword,x_fold_case): removed use of x_last_command.
- * emacs.c(x_fold_upper,x_fold_lower,x_fold_capitailze): trivial
- functions that call x_fold_case; changed x_ftab[] to use these
- instead of x_fold_case so arbitrary keys can be bound to them.
- * emacs.c(x_fold_case): changed to assume argument is 'L', 'U', or 'C'.
- * emacs.c(x_del_back,x_del_char,x_prev_histword,x_prev_com,x_next_com,
- x_kill,x_insert): use x_arg and x_arg_defaulted.
- * emacs.c(x_delete): don't change mark point (xmp) if <= cp; added
- force_push argument; changed all calls.
-
-Mon Apr 17 10:30:12 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * emacs.c(x_e_getc): changed to handle macroptr, ungetting characters.
- * emacs.c(x_e_ungetc): new function.
- * emacs.c(x_emacs): let x_e_getc() take care of macroptr.
- * emacs.c(x_version,x_search_hist): use x_e_ungetc() instead of
- macroptr.
- * emacs.c(x_set_arg): handle string of digits.
-
- * emacs.c(x_search_hist): handle deleting chars from search string.
- (fix from Dale DePriest)
- * emacs.c(x_search): added sameline paramater.
- * emacs.c(x_search_list): changes x_zots() to x_e_puts(); make
- deleting in empty pattern break out of search.
-
- * vi.c(domove): case '%': adjust ncursor forward only if matching
- opening bracket (so when cursor is on the B in "(fooBar)", c%
- changes the openbracket as well.
- * vi.c(vi_cmd): case y/d/c: special case to move end point ahead
- if move cmd is % and match was to the left of the cursor.
-
-Thu Apr 13 10:34:26 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(complete_word): no bell on ambiguous matches (user can
- tell its ambiguous 'cause there is not space or slash appended)
-
- * configure.in,aclocal.m4: added KSH_MEMMOVE, KSH_MEMSET tests
- to fix problems with compiler builtins.
-
- * misc.c(blocking_read, reset_nonblock) new routines.
- * sh.h: deleted O_NONBLOCK ifdefs/defines.
- * main.c(main),lex.c(getsc_),edit.c(x_getc),shf.c(shf_fillbuf):
- use reset_nonblock().
- (fix based on code from John Rochester)
-
-Tue Apr 11 14:36:22 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * history.c(c_fc): mostly POSIXized.
- * history.c(hist_execute,hist_get_newest,hist_get_oldest): new routines.
- * history.c(hist_get,histget): changed histget to hist_get.
- * history.c(hist_replace,histrpl): changed histrpl to hist_replace.
- * lex.h(SHIST,histpush): deleted; deleted all references.
- * history.c(histget): add approx check for history that hasn't
- happened yet.
-
- * misc.c(getn): allow leading plus (eg, +3).
-
- * main.c(initcoms[]): defined history as "fc -l --".
-
- * conf-end.h(JOBS): don't define if no posix or bsd process groups
- (was if SIGCONT not defined).
-
-Mon Apr 10 14:51:54 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(comexec),c_ksh.c(c_getopts),c_sh.c(c_read): use FEXPORT flag.
-
- * ksh_wait.h: changed to work with autoconf 2.x AC_HEADER_SYS_WAIT -
- if sys/wait.h uses union wait, don't include it.
-
-Thu Apr 6 12:19:58 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * tty.c(tty_init): print warning if open of /dev/tty fails.
-
-Sat Mar 4 01:20:03 NST 1995 Michael Rendell (michael@garfield.cs.mun.ca)
-
- * io.c(maketemp): create valid dos filenames.
-
-Mon Feb 27 11:04:32 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * Changed from autoconf 1.x to autoconf 2.x.
- * acconfig.h: included old config.h.top and config.h.bot.
- * config.h.top, config.h.bot: deleted; deleted all references.
- * install.sh: changed to install-sh; changed all references.
- * Makefile.in: use @CPPFLAGS@, @CFLAGS@, @LDFLAGS@;
- use @configure_input@; remove config.log and config.cache in
- distclean; use @prefix@ and @exec_prefix@.
- * ksh_dir.h: changed to use new autoconf defines; changed NLENGTH()
- to NAMLEN(); changed all references.
-
-Mon Feb 27 9:31:02 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(ISABSPATH): new macro.
- * var.c(setspec): use ISABSPATH() when setting tmpdir.
-
- * emacs.c(compl_file): added OS2 ifdefs.
- * exec.c(scriptexec): OS2: ignore path specified in #! scripts.
- * sh.h(ksh_dupbase): OS2: now same as unix.
- * trap.c(sigtraps[],inittraps): remove OS2 defines.
- * trap.c(alarm_catcher): V7_SIGNALS: use sig, not i.
- (Fixes from Dale DePriest)
-
-Mon Feb 27 10:06:00 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * configure.in: test for resource.h.
- * c_ulimit.c: include ksh_time.h instead of sys/time.h; use
- HAVE_SYS_RESOURCE_H when including sys/resource.h
- (was HAVE_SETRLIMIT).
- * aclocal.m4(KSH_RLIM_T): check sys/resources.h for rlim_t.
-
-Fri Feb 24 17:30:16 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(struct macro_state, macro): new structure/variable.
- * vi.c(vi_hook, vi_cmd): use macro state info to allow nested macros,
- detect recursive macros.
-
-Wed Feb 22 21:20:43 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ksh.c(c_whence): "an export" instead of "a export".
- * vi.c(classify[]): added @<char>.
- * vi.c(vi_hook,vi_cmd): added support for @<char> (macros).
- (fixes from Frank Edwards).
-
-Sun Feb 19 11:57:20 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(comexec): case CFUNC: use cp (not tp->name) when checking if
- an autoloaded function was defined; save/restore kshname before/after
- function call.
- * var.c(popblock): don't set kshname to e->loc->argv[0] - it isn't
- always right.
-
-Fri Feb 10 12:36:16 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * misc.c(parse_args): check OF_SET when building set_opts (was
- checking OF_CMDLINE).
-
- * conf-end.h(JOBS): don't define if SIGCONT not defined.
-
- * sh.h(FLOGIN) new enum.
- * misc.c(options[],parse_args): added login option; set FLOGIN if
- name in argv[0] starts with -.
- * main.c(main): use FLOGIN flag; changed the way OS2 code looks
- for profile.
-
-Wed Feb 1 09:55:40 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * expr.c(varsub): in FUNSET test, don't always fail # and %
- substitutions (test for unset variable).
-
-Wed Jan 25 09:22:15 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(MIN_COLS): new define.
- * sh.h(MIN_EDIT_SPACE): new define.
- * vi.c(prompt_trunc): new variable.
- * vi.c(edit_resize): calculate how much of prompt to truncate.
- * lex.c(pprompt): added new argument; changed all calls.
- * lex.c(yylex),emacs.c(x_emacs),vi.c(x_vi): move pprompt() inside
- x_emacs(), x_vi() or just before read in yylex().
-
-Tue Jan 24 12:35:18 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
- * misc.c(parse_args): changed arrayname variable to array.
- * var.c(basename): changed name of function to arrayname();
- changed all references (Based on fix from Dan Quinlan).
-
-Fri Dec 30 10:34:50 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * ksh.1: modifications to generate two man pages: sh and ksh
- (Fixes from Michael Harrdt).
-
-Wed Dec 28 16:55:13 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(complete_word): don't check for globing characters.
-
-Wed Dec 28 10:32:18 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(search_access1): don't use ret variable; move "." to end
- of xsuffixes/rsuffixes.
- * os2.c(_execve): OS2: fixed typo.
- * sh.h(FILENCMP): changed stricmp to strnicmp.
- * os2/config.h: added define for rlim_t.
- * os2/make.sed: changed > null to > nul.
- * Makefile.in(dist): generate os2/makefile after running Dist-fixup.
- (Fixes from Dale DePriest)
-
-Thu Dec 22 15:06:06 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.1.3 distribution
-
- * *.c: removed RCSids.
-
-Wed Dec 21 11:55:01 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * table.h(struct tbl): changed array field to union of array/fname;
- changed all references.
- * c_ksh.c(c_whence): print undefined function path.
- * exec.c(comexec): do autoloading of undefined functions; print
- error if function can't be found.
- * exec.c(findcom): fill in tp->u.fname for undefined functions;
- search FPATH if search of PATH fails.
- * table.h(FC_NOAUTOLOAD): deleted define; removed all references.
-
-Tue Dec 20 14:16:16 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(herein): check if name is null.
- * lex.h(HEREDELIM,SHEREDELIM,SHEREDQUOTE): new defines.
- * lex.c(yylex): added code for HEREDELIM.
- * syn.c(synio): use HEREDELIM.
- * lex.c(readhere): changed to allow \n in here-delimiter.
-
- * tree.c(tputS): quote ", ` and $ inside "-quotes.
- * tree.c(ptree,pioact): made static.
- * tree.c(ptree,fptreef,vfptreef): added indent argument; changed to
- use indent argument; changed all calls.
- * tree.h(struct ioword): added delim field.
- * tree.c(iocopy),syn.c(synio,syntaxerr): deal with delim field.
- * tree.c(pioact): print contents of here documents.
-
- * c_ksh.c(c_typeset): typeset -f foo: set exit code to 1 if function
- not found.
-
-Mon Dec 19 15:14:02 NST 1994 Michael Rendell (michael@garfield.cs.mun.ca)
-
- * history.c(histinit): increment line number for each history line.
-
- * exec.c(iosetup): OS2: if open /dev/null fails, try nul instead.
- * Makefile.in(debugtools,install,uninstall): make check-pgrp last;
- use $E.
- * eval.c(eval,expand): OS2: added DODIRSWP code.
- * main.c(main): OS2: only include $HOME/kshrc.ksh if interactive.
- * sh.h(FILENCMP,FILECMP,FILECHCONV): new defines.
- * misc.c(gmatch),vi.c(grabsearch,complete_word),emacs.c(compl_file):
- OS2: case insensitive compares.
- (fixes from Dale DePriest).
-
-Mon Dec 19 09:54:42 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(vi_cmd): make ~ honour argcnt (fix from Troy Bollinger).
-
- * vi.c(complete_word): don't add trailing / if there is already one.
- * vi.c(glob_word): return rval, not 0.
-
-Thu Dec 15 11:06:01 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(vi_cmd): call complete_word() with argument of 1 not 0.
-
-Tue Dec 13 12:07:50 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * history.c(histget): made static; added approx argument; changed
- all calls.
-
-Tue Dec 13 10:58:14 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * Makefile.in(mandir): use $(manext), not 1 (fix from Mike Long).
-
-Mon Dec 12 20:55:53 NST 1994 John Rochester (jr@panda.cs.mun.ca)
-
- * tree.c(ptree): print TELIF part of if statements
-
-Fri Dec 9 15:21:36 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * trap.c(inittraps): OS2: don't trap SIGTERM (temproary fix).
-
- * exec.c(search_access1): OS2: fixed to check for valid suffix
- and change mode from X_OK to R_OK if appropriate.
-
- * edit.c: include <sys/stream.h>, <sys/ptem.h> for SCO unix
- (fix from William Bader).
-
- * c_ulimit.c(c_ulimit): changed type of val from long to rlim_t
- (fix from Thomas Gellekum and J.T.Conklin).
- * aclocal.m4(KSH_RLIM_T): new test for rlim_t.
- * configure.in: use KSH_RLIM_T.
- * acconfig.h: added rlim_t.
-
-Thu Dec 8 12:20:25 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * expr.c(evalexpr): changed div-by-zero test to only derefernce vr
- if operation is a divide.
-
-Mon Dec 5 14:42:52 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(search): OS2: typo - changed namlen to namelen.
- * exec.c(search_access): OS2: check execute bit explicitly.
- * main.c(main): OS2: don't include ./profile.ksh.
- * options.h(DEFAULT_PATH): OS2: added /os2 to path.
- * sh.h(ksh_getdup): OS2: define to getdup(); prototype for getdup().
- * Makefile.in(dist): create os2 Makefile based on distribution
- Makefile.in.
-
-Mon Dec 5 12:17:14 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.1.2 distribution
-
- * eval.c(globit): when searching directory, re-calculate end of
- string based on prefix length.
-
-Fri Dec 2 11:07:48 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * syn.c(wordlist): if token isn't 'in', don't reject ;.
-
- * eval.c(expand): leading non-white-space IFS chars no cause initial
- empty field.
-
-Thu Dec 1 12:04:00 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.1.1 distribution
-
-Thu Dec 1 10:50:38 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(TF_FATAL,fatal_trap): new define,variable.
- * trap.c(inittraps,trapsig,fatal_trap_check,trap_pending,runtrap,
- settrap): use TF_FATAL, fatal_trap.
- * trap.c(runtraps): changed argument from bool to TF_* flag; changed
- all calls.
- * jobs.c(j_waitj): check fatal_trap flag.
-
-Wed Nov 30 11:20:03 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * conf-end.h: new file.
- * config.h.bot: moved guts to conf-end.h.
-
- * emacs.c(struct x_ftab): changed type of xf_db_char from char to int.
- * emacs.c(x_emacs): changed type of c from char to int.
- * emacs.c(X_NTAB): new define.
- * emacs.c(x_bind,x_init_eamcs): new X_NTAB, X_TABSZ.
- * emacs.c(x_prefix3, x_meta3): ifdef OS2.
- * emacs.c(x_bind): ifdef OS2; mask *a1 with CHARMASK.
-
- * exec.c(search_access): new function.
- * exec.c(search): use search_access() instead of duplicating test.
- * exec.c(search,search_access1): ifdef OS2.
-
- * Makefile.in(OS2FILES): new macro.
- * Makefile.in(dist): add OS2FILES to distribution.
-
- * options.h(DEFAULT_PATH): ifdef OS2.
- * edit.c(x_getc,x_mode): ifdef OS2.
- * path.c(make_path): ifdef OS2.
-
-Tue Nov 29 16:51:35 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(EXECSHELL,EXECSHELL_STR): ifdef OS2.
- * exec.c(scriptexec): use EXECSHELL_STR (was "EXECSHELL").
-
- * trap.c(sigtraps[]): ifdef OS2.
- * lex.c(yylex): ifdef OS2.
- * misc.c(change_flag): ifdef OS2.
- * history.c(HISTFILE): ifdef OS2.
- * eval.c(homedir): ifdef OS2.
- * c_sh.c(shbuiltins[]): ifdef OS2.
-
- * sh.h(ksh_execve,ksh_dupbase): new defines.
-
- * jobs.c(exchild): ifdef use of nice.
-
-Tue Nov 29 12:32:26 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * eval.c(globit,copy_non_glob): changed to pass/use &xp it can change
- (memory can be re-allocated).
-
- * ksh_dir.h(NLENGTH): new macro.
- * eval.c(globit): use NLENGTH macro.
-
- * alloc.c(aresize): removed redundent np and optr variables.
-
-Mon Nov 28 14:55:49 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * config.h.bot(HISTORY): new define.
- * lex.c(getsc_): ifdef HISTORY.
- * history.c: ifdef HISTORY (dummy histsave, init_histvec and
- hist_finish routines).
- * c_ksh.c(kshbuiltins): c_fc: ifdef KSH
- * lex.h(HISTORY): changed to HISTORYSIZE; changed all references.
-
- * options.h(KSH): new define.
- * config.h.bot: changed to deal with KSH define.
- * exec.c(do_select,pr_menu): ifdef KSH.
- * exec.c(execute): case TSELECT: ifdef KSH.
- * c_ksh.c(c_whence,c_command,kshbuiltins[]): ifdef KSH.
- * main.c(initcoms[],main): ifdef some aliases, SECONDS/RANDOM/TMOUT.
- * syn.c(get_command): case TDBRACKET: ifdef KSH.
- * syn.c(db_parse,db_aoexpr,db_nexpr,dp_primary): ifdef KSH.
- * syn.c(tokentab[]): "select", "[[" ifdef KSH.
- * var.c(special,getspec,setspec,unsetspec): ifdef KSH.
- * ksh.1: ifdef KSH; misc fixups.
- (changes mostly from Michael Haardt).
-
-Mon Nov 28 14:27:34 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * var.c(skip_varname,special,global,local), table.c(hash,tsearch,
- tenter): made argument and return value const.
-
- * main.c(version_param[]): new variable.
- * main.c(initcoms[],main): use version_param instead of "KSH_VERSION".
-
- * history.c(histsave): EASY_HISTORY: changed to take same arguments
- as COMPLEX_HISTORY histsave(); changed all calls, removing
- unneeded ifdefs.
-
- * vi.c(x_vi), emacs.c(x_emacs): changed unwind() call from LINTR
- to LSHELL so newline isn't printed twice - also lets runtrap()
- set the exit code.
-
- * vi.c(vi_cmd): increment source line if saving to history.
-
-Fri Nov 25 14:43:57 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * syn.c(get_command): don't generate a syntax error if EOF is read.
-
- * configure.in: add LDSTATIC to LDFALGS if the former is set.
-
- * history.c(hist_skip_back): start at the end of the buffer, not
- one past the end (fix from Simon J. Gerraty).
-
-Thu Nov 24 09:53:49 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * syn.c(get_command,dogroup): allow { ...;} to be used instead
- of do ...;done in for/select loops.
-
-Wed Nov 23 09:09:43 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.1.0 distribution
-
- * var.c(setspec): set seconds to current time - assigned value,
- not just current time.
-
- * emacs.c(x_copy_arg): deleted ifdef'd out code (x_prev_histword()
- does what it was supposed to do).
-
- * emacs.c(compl_command): don't call list_stash() twice (happened
- if type == 2 and multi set).
-
-Tue Nov 22 10:26:13 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_test.c(eval_unop): don't assume S_ISBLK, S_ISCHR, S_ISUID,
- S_ISGID are defined.
-
- * path.c(make_path): avoid addeding extra /'s in paths; avoid
- infinate loop if result buffer not big enough.
-
- * main.c(main): setting PWD: avoid calling setstr() with the
- current value of PWD.
-
- * var.c(typeset): set free_me to 0 if t is integer.
-
- * emacs.c(x_search_hist): added overflow checking to fixed sized
- buffers.
- * emacs.c(compl_file,compl_command): removed fixed sized buffers.
-
- * vi.c(x_vi), emacs.c(x_emacs): on interrupt, unwind instead of
- calling runtraps().
-
- * vi.c(vi_cmd): added 'g' command to goto the most recent command.
-
- * c_sh.c(c_read), c_ksh.c(c_print): always increment source->line when
- saving history.
-
-Mon Nov 21 10:45:34 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(do_selectargs): removed use of pmenu variable (redundent)
- use isspace() instead of IFS chars; include <ctype.h>.
-
- * aclocal.m4(KSH_TERM_CHECK): do not allow HAVE_TERMIOS_H check to
- succeed on ultrix (avoid type-ahead loss).
-
- * emacs.c(x_fword): cahnged loop to skip non word chars, then word
- chars (was the opposite).
-
- * main.c(shell): after error/interrupt/etc, reset an EOF if ignoreeof
- option is set.
-
- * vi.c(classify[]): changed space (040) from C_|U_ to M_
- (got broken in 5.0.10).
-
- * ksh_wait.h(ksh_waitpid): new define.
- * jobs.c(waitpid): moved define to ksh_wait.h; changed use of
- waitpid() to ksh_waitpid().
-
- * history.c(hist_skip_back),io.c(maketemp): use procpid instead of
- getpid().
-
-Fri Nov 18 16:08:09 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(FSHOW8): inverted meaning: now if set, do the M- stuff
- (done so 8 bit char sets work by default).
-
- * main.c(main): set exstat to 127 if command file can't be opened.
-
- * main.c(main): use argv[0] instead of kshname when deciding
- whether to include profiles.
-
-Fri Nov 18 14:25:11 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.0.10.1 distribution
-
- * tty.h: deleted KSH_VDISABLE; moved _POSIX_VDISABLE stuff to edit.c.
- * edit.c(x_init): calculate value for vdisable_c.
- * edit.c(x_mode): use vdisable_c instead of KSH_VDISABLE.
-
-Thu Nov 17 12:09:13 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.0.10 distribution
-
- * lex.c(getsc_),edit.c(x_getc): call runtraps(FALSE) if read is
- interrupted.
- * vi.c(x_vi),emacs.c(x_emacs): call runtraps(FALSE) (was TRUE).
-
-Wed Nov 16 09:48:54 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(execute,scriptexec): call __setostype(0)/(1) before/after
- execve() on ISC machines.
-
- * trap.c(trap_pending): new fuction.
- * jobs.c(j_waitj): use trap_pending(); return -<signal-number> if
- interrupted.
- * jobs.c(waitfor): added sigp argument; changed all calls.
- * c_sh.c(c_wait): use signal number set by waitfor() to set exit status.
-
- * shf.c(SHF_INTERRUPT): no longer calls intrcheck() - now sets
- error flag and returns EOF.
- * c_sh.c(c_read): re-arranged to have single shf_getc() call; if read
- interrupted and signal is fatal (fatal_trap_check()), make read
- return with appropriate exit code.
- * trap.c(fatal_trap_check()): new function.
- * trap.c(inittraps()): catch and cleanup on SIGHUP; don't force the
- setting of SIGINT,SIGQUIT,SIGTERM,SIGHUP.
-
- * table.c(tenter): changed to use strlen()/memcpy() instead of loops.
-
- * var.c(initvar): new function.
- * main.c(main): call initvar().
- * var.c(special): changed to use hash table for lookup.
-
- * main.c(main),syn.c(initkeywords): moved table initialization
- from main() to initkeywords().
-
-Tue Nov 15 10:01:20 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * eval.c(copy_non_glob): new routine.
- * eval.c(globit): changed to use copy_non_glob() instead of strchr().
-
- * misc.c(cclass): if [..] pattern has no closing ], do literal
- compare of character with [ (used to always fail).
-
- * eval.c(globit): handle symbolic links in the check code.
-
- * configure.in: added check for lstat().
- * ksh_stat.h: defined lstat to be stat if lstat is not available.
-
- * exec.c(search): return Xclose() instead of Xstring().
-
-Mon Nov 14 16:28:41 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * ksh_times.h: changed BROKEN_TIMES to TIMES_BROKEN.
-
- * c_test.c(syntax): removed \n from error messages.
-
- * eval.c(glob,globit): changed to use dynamicly allocated string
- instead of a fixed sized buffer.
-
-Thu Nov 10 10:47:55 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * history.c(sethistsize): don't set size if new size is < 0; fixed
- offset calculation so histptr is not way beyond the end of array;
- if history is shrinking, save newest history back.
-
- * vi.c(vi_hook): case VSEARCH: call restore_cbuf() after \n or \r.
-
- * main.c(quitenv): call restfd() even if fd < 0 to re-close fd.
-
- * exec.c(execute): commented out code that set savefd[0/1] to -1
- if input/output was a pipeline.
-
- * missing.c(dup2_fixup): deleted function.
- * sh.h(dup2->dup2_fixup): deleted define.
- * io.c(ksh_dup2): new function; changed all dup2() calls to ksh_dup2().
-
-Wed Nov 9 11:11:31 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * edit.h(struct edchars): added eof field.
- * edit.c(x_init): initialize eof fields.
- * vi.c(x_vi): changed ^D to edchars.eof.
- * vi.c(vi_cmd): make I/cc/S skip blanks.
-
- * history.c(histsave): EASY_HISTORY: use memmove() to copy pointers
- back one.
-
- * vi.c(vi_cmd): make G act the same as at&t ksh.
- * vi.c(ismeta,O_): deleted macros; removed all references to O_.
- * vi.c(classify[]): add ^X and ^F to command mode.
-
-Tue Nov 8 11:15:01 NST 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * main.c(initsubs[]): don't set SHELL.
-
- * vi.c(vi_cmd): added v command (start up vi).
- * vi.c(vi_hook): added case for vi_cmd() returning 2.
- * vi.c(grabsearch): set anchored flag if pattern starts with ^.
- (based on fixes from Michael Jetzer).
-
- * history.c(findhist): added anchored argument; changed all calls.
- * history.c(histget): start searching from histptr-1; changed to
- call findhist() to do searching.
- * history.c(c_fc): changed to print multiline commands correctly.
- (based on fixes from Michael Jetzer).
-
-Fri Nov 4 10:30:14 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.c(yylex): when pushing alias sources, allocate from existing
- source's area.
-
- * lex.c(struct source): added areap field.
- * lex.c(pushs): added area argument; changed all calls.
- * history.c(histrpl): changed constant sized hline[] to expandable
- string; removed hline/hsize parameters; changed all calls; put
- newline at end of string.
- * history.c(c_fc): changed to use dynamically sized buffer when reading
- commands; strip nulls after read.
- * history.c(histbackup): made static.
-
- * trap.c(block_pipe): if handler is SIG_DFL, change it to SIG_IGN.
-
- * lex.c(readhere): changed to allow eof after end-of-file marker
- (bug report from Andrew Moore).
-
-Thu Nov 3 09:09:39 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * io.c(coproc_read_close,coproc_write_close): new functions.
- * c_sh.c(c_read): call coproc_read_close() when eof is read.
- * c_ksh.c(c_print): set PO_COPROC if fd is coproc.write; call
- coproc_write_close() if write fails due to EPIPE.
- * exec.c(iosetup): call coproc_write_close() after #>&p.
- * sh.h(EF_COPROC_DUPED): deleted.
- * sh.h(struct coproc): deleted isopen field.
- * io.c(cleanup_coproc): do not use isopen field.
- * c_sh.c(c_exec): deleted EF_COPROC_DUPED code.
- * exec.c(TCOPROC): don't set isopen; don't start new coprocess if
- old job exists and write pipe hasn't been closed.
-
- * misc.c(str_zcpy): new function.
- * lex.c(getsc_): made line[] buffer local/static; use str_zcpy()
- to fill line[].
- * history.c(c_fc): use local hline buffer instead of global line[];
- use str_zcpy() to fill hline[];
- * history.c(histrpl): added hline and hsize parameters; changed all
- calls.
- * history.c(hist_init): EASY_HISTORY: use local hilne buffer instead
- of global line[].
- * lex.h(line[]): deleted.
- * syn.c(compile): do not set s->str to null for STTY and SHIST.
-
-Wed Nov 2 11:48:36 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.c(getsc_): case SDDPAREN: set csstate before going to
- SPAREN state.
-
- * Makefile.in(RCSFILES): removed POSIX from list (now covered in
- man page).
-
-Tue Nov 1 09:27:46 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * eval.c(comsub): save/restore source before/after compile().
-
- * c_ulimit.c(c_ulimit): allow value to be arithmetic expression
- (as per Korn book).
-
- * c_sh.c(c_read): call set_prompt() before printing prompt.
-
- * expr.c(v_evaluate): treat an empty expression as 0.
-
-Mon Oct 31 09:23:57 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(grabhist,grabsearch): check that history line doesn't overflow
- edit buffer.
-
- * history.c(hist_finish): (EASY_HISTORY) changed for-loop condition to
- prevent passing the end of history.
-
- * eval.c(expand): when stuffing MAGIC, cast c to char.
-
- * misc.c(strip_nuls): new function.
- * lex.c(getsc_): case STTY/SFILE/SSTDIN: call strip_nuls() after
- reading commands.
-
- * edit.c(set_editmode): reversed strstr() arguments - check for
- vi/emacs in $EDITOR/$VISUAL string.
-
- * syn.c(yyparse): allow EOF as well as newline after a command.
- * lex.c(getsc_): case SSTRING: don't fake newline
-
-Sun Oct 30 10:55:20 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ksh.c(c_print): echo: check for -n, -e and -E options.
-
- * exec.c(comexec): don't allow command -p if restricted.
-
-Fri Oct 28 10:24:48 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * var.c(typeset): in fake_assign code, was freeing t->val.s + t->type
- instead of t->val.s - now uses free_me variable instead of aflag.
-
- * Makefile.in(depend): change blank lines in depend output to sh.h
- so dumb make(1)s won't die.
-
- * mail.c: changed checking to use atime/mtime instead of size; changed
- struct mbox mb_size field to mb_mtime, changed all references.
-
- * main.c(shell): do not execute (or set the exit status for) a null
- command.
- * lex.c(readhere): read the newline after the eof marker.
-
-Wed Oct 26 09:11:08 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * eval.c(globit): added FMARKDIRS support.
-
- * emacs.c(x_ftab[]): added entries for ansi arrow key bindings.
-
- * exec.c(execute,iosetup): move tracing of redirections from
- execute() to iosetup() so expanded name can be printed.
-
- * exec.c(execute): case TDBRACKET: read was being called instead of
- test.
-
- * ksh_stat.h(S_ISCDF): new define.
- * c_test.c: added -H for context dependent files (HP bizarreness).
-
- * main.c(initcoms[]): added alias local=typeset.
-
- * Makefile.in(stamp-h,config.status): added double quotes CONFIG_FILES
- and LDSTATIC assignments for dmake.
- * aclocal.m4(KSH_SYS_SIGLIST): do something with sys_siglist so it
- isn't optimized away.
- * aclocal.m4(KSH_CLOCK_T): do extra check for clock_t in sys/times.h.
- * acconfig.h(CLOCK_T_IN_SYS_TIMES_H): new define.
- * sh.h(SIGNALS): use _SIGMAX if NSIG, _MINIX not defined.
- (fixes from Brian Campbell <brianc@qnx.com>)
-
- * emacs.c(x_transpose): changed behavior if FGMACS flag set
- (fix from <guy@netapp.com>).
-
-Tue Oct 25 17:11:58 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * tty.c(KSH_VDISABLE): new define.
- * edit.c(x_init): use KSH_VDISABLE.
-
-Tue Oct 25 09:55:09 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.0.9 distribution
-
- * c_ulimit.c(c_ulimit): changed SOFT, HARD from enum to defines
- to avoid problems with ancient compilers.
-
- * vi.c(CHAR_LEN,char_len): changed macro to function; added FVISHOW8
- support.
- * misc.c(options[]), sh.h(FVISHOW8): added FVISHOW8 option.
-
-Sun Oct 23 11:02:26 NDT 1994 Michael Rendell (michael@maple.cs.mun.ca)
-
- * main.c(shell): keep unwinding if LINTR and not interactive.
-
- * lex.c(yylex): do redumentery quote parsing for $(..).
-
-Thu Oct 20 11:02:27 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(execute): case TSELECT: set rv to 1 if eof is read.
- * exec.c(execute): case TFOR/TSELECT/TWHILE/TUNTIL: set rv to 0 before
- entering loop, but after setjmp incase of a continue; rv to 0
- after a break.
- * exec.c(execute): case TFOR/TSELECT: do readonly check before
- assigning value.
- * c_ksh.c(c_getopts): do readonly check before assigning value.
-
- * misc.c(print_columns),c_ksh.c(kill_fmt_entry),
- misc.c(options_fmt_entry),exec.c(select_fmt_entry): new functions.
- * c_ksh.c(c_kill),misc.c(printoptions),exec.c(pr_menu): use
- print_columns() call a call-back routine to format information
- in columns.
-
-Wed Oct 19 10:26:25 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * misc.c(cclass): require MAGIC before - and ].
- * eval.c(expand): prefix - and ] with MAGIC if appropriate.
-
- * var.c(typeset): don't allow export flag of readonly variables
- to be cleared.
-
- * eval.c(globit): added call to intrcheck().
-
-Mon Oct 17 11:48:05 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * lex.c(readhere): check for and report write errors.
-
-Sun Oct 16 16:10:59 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * c_ksh.c(c_cd): don't allow cd if restricted.
- * exec.c(comexec): if restricted and command contains /, print error.
- * exec.c(ioestup): if restricted, don't allow file creations.
- * main.c(is_restricted): new function.
- * main.c(main): save and reset FRESTRICTED during .profile/ENV reading;
- set FRESTRICTED if argv[0] or SHELL refers to restricted shell;
- make PATH, ENV, SHELL readonly if restricted.
- * var.c(typeset): check for restricted shell and PATH/ENV/SHELL.
-
-Thu Oct 13 21:01:14 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * main.c(shell): only call j_notify() for interactive shells.
-
- * c_sh.c(c_read): check if variable is readonly before assigning
- value.
-
-Wed Oct 12 14:08:46 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.h(COPROC),tree.h(TCOPROC,XCOPROC): added defines.
- * lex.c(yylex): return COPROC for |& token.
- * syn.c(tokentab): added COPROC.
- * syn.c(c_list): accept COPROC, create TCOPROC node.
- * tree.c(ptree): added case for TCOPROC.
- * exec.c(execute): added case for TCOPROC.
- * io.c(check_fd,get_coproc_fd): new functions.
- * c_sh.c(c_read),c_ksh.c(c_print): changed to use check_fd();
- added -p option; for c_print() ensure SIGPIPE doesn't kill shell.
- * exec.c(iosetup): changed to use check_fd() for IODUP; when
- checking fore close, require exactly the string '-', not any
- string starting with '-'; added strerror() to error message.
- * jobs.c(exchild): don't open /dev/null if XCOPROC; close
- coproc.read/write/childread in child if XCOPROC; don't pass
- XCOPROC flag on to execute(); set coproc.job to job in parent
- if XCOPROC.
- * jobs.c(check_job): clear coproc.job if said job dies.
- * trap.c(block_pipe,restore_pipe): new functions.
- * sh.h(struct coproc, EF_COPROC_DUPED): new structure and define.
- * c_sh.c(c_exec): if EF_COPROC_DUPED set, clean up co-process stuff.
-
- * main.c(cleanup_parents_env): new function.
- * jobs.c(exchild): call cleanup_parents_env() after fork().
-
- * tree.h(IORDUP): new define.
- * lex.c(yylex): changed redirection parsing to not accept & only after
- a single < or >; set IORDUP flag for x<&y; fixed <</<>/>> check to
- not allow >< (again).
- * tree.c(pioact): use IORDUP flag to print <& or >&.
-
- * jobs.c(exchild): set JF_ORIGFG flag if job started in foreground.
- * jobs.c(j_waitj): don't get default tty settings if JF_ORIGFG not
- set.
-
- * misc.c(parse_args): treat -A as a flag that is handled later
- (used to require argument); do array setting after argument
- sorting.
- * var.c(set_array): changed second argument from 0/1 flag to
- -1/1 flag; changed all calls.
-
-Thu Oct 6 11:55:27 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * table.c(tinit): added initial table size argument; call texpand
- if size isn't 0; changed all calls.
- * main.c(main): try to make sure table size is big enough for
- builtins and keywords (cut down on amount of re-hashing).
-
- * eval.c(expand): added next and prev fields to struct SubType;
- removed fixed length subtype array, changed code to allocate
- SubTypes as needed.
-
-Wed Oct 5 09:25:06 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * main.c(main): moved initio() above inittraps() as later can print
- stuff.
-
- * table.h(IMPORT): new flag.
- * var.c(typeset): if IMPORT flag set, don't allow array references,
- insist on assignment.
- * var.c(import): deleted function.
- * main.c(main): use typeset() instead of import().
-
- * sh.h: include expand.h.
- * expand.h(Xnleft): new define.
- * expand.h(struct XString, Xinit): added areap field; added area
- argument to Xinit; changed all calls.
- * lex.h(struct source): added xs field.
- * shf.c(shf_gets,shf_getse): changed name fromshf_gets to shf_getse;
- return pointer to null byte instead of start of buffer.
- * lex.c(pushs): if type is SFILE or SSTDIN, initialize s->xs.
- * lex.c(getsc_): case SFILE/SSTDIN: use s->xs instead of fixed
- size line buffer.
-
- * syn.c(compile): don't change s->str if SFILE.
- * main.c(main): call pushs() explicitly for each of SSTRING,
- SFILE, SSTDIN, STTY.
-
- * aclocal.m4(KSH_GCC_FUNC_ATTR): changed GCC_FUNC_ATTR to
- HAVE_GCC_FUNC_ATTR.
- * config.h.bot: changed use of GCC_FUNC_ATTR; deleted
- GCC_FA_NORETURN, GCC_FA_CONST, GCC_FA_FORMAT defines, created
- generic GCC_FUNC_ATTR define; changed all uses of GCC_FA_*.
-
- * main.c(main): set s->file for SSTDIN input.
-
- * main.c(shell): pass LERROR on if not interactive.
-
- * expand.h(Xcheck,XcheckN): added XcheckN define, changed Xcheck
- to use XcheckN; made XcheckN call Xcheck_grow_() do do any real work
- (to cut down on code size).
- * misc.c(Xcheck_grow_): new function.
- * exec.c(search),c_sh.c(c_read): changed to use Xstring() routines
- (used to use the fixed size buffer line[]).
- * exec.c(findcom): avoid re-saving search() result in ATEMP.
-
-Tue Oct 4 15:32:37 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * jobs.c(j_jobs): return int value indicating error/ok; changed
- all calls.
-
- * misc.c(getn): added int * argument to hold result; changed
- return value to indicate success/failure; changed all calls.
- * misc.c(bi_getn): new function.
- * misc.c(getn_): deleted function.
-
- * io.c(internal_error,error_prefix,warningf): new functions.
- * *.c: changed errorf() calls reporting internal errors to
- use internal_error() function; changed many shellf()s to
- warningf().
- * io.c(errorf),lex.c(yyerror): changed to use error_prefix().
-
- * alloc.c(aprint): ifdef'd out.
- * tree.c(phash): deleted function.
-
-Mon Oct 3 15:08:24 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * sh.h(kshname): new variable
- * main.c(main): changed name to kshname, deleted local variable.
- * exec.c(comsub): update kshname.
- * var.c(popblock): restore kshname.
- * io.c(errorf,bi_errorf): print shell name before error message.
-
- * c_ksh.c(c_cd): print new directory on stdout, not stderr.
-
- * sh.h(GI_MINUS): new define.
- * misc.c(ksh_getopts): changed so once - or + introduces option,
- all options must start with same character.
-
- * sh.h(builtin_argv0): new variable.
- * exec.c(call_builtin): set/clear builtin_argv0, builtin_flag; changed
- argument to a struct tbl *; changed all calls.
- * io.c(bi_errorf): new function.
- * c_ksh.c,c_sh.c,c_ulimit.c,emacs.c,history.c,jobs.c: changed all uses
- of errorf() to bi_errorf().
- * emacs.c(x_bind): changed return value to int; changed all calls.
- * history.c(histrpl): return 0 if there is an error; changed all calls.
- * misc.c(parse_args): use bi_errorf(); return -1 for error; changed all
- calls.
- * misc.c(ksh_getopts): call bi_errorf instead of errorf which means
- ksh_getopts() may return after an error, so changed all calls to
- check for '?' return.
-
- * exec.c(iosetup): use shellf() to report errors and return value
- indicating success or failure.
- * exec.c(execute): if iosetup fails, cause fatal error for special
- builtins, return otherwise; print PS4 and redirections.
-
-Fri Sep 30 15:17:37 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * c_ulimit.c(c_ulimit): accept unlimited as a valid value.
-
- * c_test.c(c_test): changed posix special case code to use
- while loop.
-
- * c_ksh.c(c_whence): for whence -p, don't look for built-ins or
- fuctions.
-
-Thu Sep 29 10:34:59 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * c_ksh.c(c_alias): added -r option so the sysv-bounre shell
- hash -r will work.
-
- * eval.c(debunk): use strchr() to find first MAGIC, if any.
-
-Wed Sep 28 15:34:32 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * sh.h(O_NONBLOCK): define to O_NDELAY or FNDELAY if not defined.
- * main.c(main): if stdin is O_NONBLOCK'd, clear O_NONBLOCK.
-
- * misc.c(options[], parse_args): make -c a normal flag, not an option
- with an argument (POSIX); deleted cargp argument to parse_args().
- * main.c(main): print error if -c and no arguments left.
-
- * lex.h(SSTDIN): new define.
- * lex.c(yylex): added case for SSTDIN.
- * main.c(main): if -s flag used, set source type to SSTDIN.
-
-Tue Sep 27 08:52:11 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * lex.c(get_brace_var): new function.
- * lex.c(yylex): removed most ${..} parsing - leave it to expand();
- use get_brace_var() to read the variable part of a ${..} expression.
- * tree.c(tputs,wdscan): case OSUBST: delete code that understood
- partially compiled ${..}.
- * sh.h(C_SUBOP,C_SUBOP1,C_SUBOP2): changed C_SUBOP to C_SUBOP1,
- added C_SUBOP2.
- * misc.c(initctypes): removed # and % from C_SUBOP; changed C_SUBOP to
- C_SUBOP1; added C_SUBOP2.
- * eval.c(varsub): look at word part of substitution to figure out
- type of substitution; check for bad substitutions; check for unset
- variables for #/% substitutions.
- * eval.c(struct SubType): changed type field to stype; changed quote
- field to short; added f field.
- * tree.h(DOTEMP_): new define.
- * eval.c(expand): case CSUBST: case '=': deleted bad substitution
- error (now handled in varsub); case OSUBST: removed special handling
- of trimming - varsub() does it now; when pushing/poping state (st),
- save/restore value of f; set f to DOPAT when trimming; case CSUBST:
- case '=': restore original position in string, substitute the value
- of the variable (as opposed to the value that was assigned to the
- variable); case OSUBST: if '?' qualifier, turn off DOBLANK when
- expandined word part; define DOTEMP_ when expanding word part
- of ${..[#%=?]..}; deleted first_eq and tstart - replaced with
- tilde_ok and saw_eq.
-
- * eval.c(expand): tilde expansion: use tstart variable instead of cp;
- changed '?' error message to be like at&t ksh; don't test if strval()
- returns NULL - it doesn't.
-
- * var.c(strval): if !ISSET, instead of returning null, set s to null.
-
- * exec.c(comexec): case TDBRACKET: don't pass DOASNTILDE to evalstr().
-
- * exec.c(scriptexec): changed line[] to buf[] so it doesn't get
- confused with global the line[].
-
- * main.c(initsubs): initialize PS4.
- * edit.c(x_getc): cast char to unsigned before returning.
-
-Mon Sep 26 11:06:55 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * eval.c(globit): call strnsave instead of strsave; if file has
- trailing /, use stat() to check that it is a directory.
-
- * eval.c(expand): case CSUBST: case #/%: deleted duplicate *dp = 0;
- case CSUBST: case =: copy string and call debunk() to oust MAGICs.
-
- * misc.c(print_value_quoted): deleted bogus shf_shlout argument to
- shprintf(); deleted unneeded test (p != s).
-
- * main.c(main): turn on FBRACEEXPAND.
- * misc.c(change_flag): turn FBRACEEXPAND off if turning FPOSIX on.
-
- * vi.c(x_vi): use x_vi_zotc() to print ^D.
- * vi.c(CHAR_LEN): new define.
- * vi.c(vi_hook): use CHAR_LEN() instead of inline tests for
- c < ' ' || c== 0x7f; search editing: display M- if necessary.
- * vi.c(display): changed to deal tiwh meta-characters.
-
- * vi.c(x_vi_zotc): print M- for meta chars.
- * emacs.c(x_e_getc): new function; changed all x_getc() calls to
- x_e_getc() calls.
- * edit.c(x_getc): don't and out upper bit.
-
- * sh.h(OPAREN,CPAREN,OBRACK,CBRACK,OBRACE,CBRACE): new defines
- * expr.c(OPAREN,CPAREN): re-named to OPEN_PAREN, CLOSE_PAREN.
-
- * eval.c(debunk): changed to convert MAGIC MAGIC -> MAGIC.
- * eval.c(expand): removed ismagic_bracket stuff - not needed.
- * eval.c(expand): always restore value of quote when CSUBST
- reached; don't set DOGLOB in fdo if trimming.
-
-Sat Sep 24 11:46:03 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * tree.h(DOBRACE_): new define.
- * eval.c(expand): changed check for leading ! in [..] to be more
- robust (old test could have looked before start of string).
- * eval.c(expand,maybe_expand_tilde): case ~: moved code into a function
- (maybe_expand_tilde).
- * eval.c(expand): expand alternations after macros, before globing
- (was before macros).
- * eval.c(alt_expand): changed to be called after macro expansion.
- * eval.c(alt_scan,alt_count): deleted (no longer needed).
-
- * misc.c(cclass): return NULL (no match) if first char in a range
- is greater than the second.
- * eval.c(expand): when building strings, stuff literal MAGIC chars.
-
-Thu Sep 22 15:05:48 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(comexec): re-arranged handling of builtin and exec;
- handle command (and command -p, etc.); deleted comexec_flags
- variable; made function static again; removed fcflags argument.
- * table.h(FC_NOBLOCK): deleted define.
- * c_sh.c(c_exec): changed empty function to deal with preserving I/O
- redirects (code taken from comexec()).
- * c_ksh.c(c_command): new function - calls c_whence.
- * c_ksh.c(c_whence): removed code to deal with command -p.
-
- * Makefile.in: changed [ to test.
- * shf.h: changed errno structure member to errno_; changed all uses
- (fixes for QNX from Brian Campbell).
-
- * c_test.c(enum Op): deleted trailing comma (some compilers complain).
- * proto.h: added volatile to tp arg of comexec() prototype.
-
-Thu Sep 22 11:08:31 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.0.8 distribution
-
- * Makefile.in(install): added missing dollar (fix from Thomas Gellekum).
-
- * emacs.c: changed CMASK to CHARMASK to avoid conflicts with some
- system headers (eg, HP-UX 9.01 <sys/param.h>). Reported by Sean
- Hogan.
-
- * history.c(c_fc): wp not being incremented; -e strcmp() test reversed
- (reported by Sean Hogan).
-
-Thu Sep 21 21:12:03 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.0.7 distribution
-
-Tue Sep 20 09:56:54 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * history.c(c_fc): use ksh_getopt() to parse arguments.
- * c_ksh.c(c_bind): use ksh_getopt() to parse arguments.
-
- * main.c(initcoms[]): changed hash alias from alias -t - to alias -t --.
-
- * misc.c(print_value_quoted): don't use quotes if no special
- characters.
-
- * c_ksh.c(c_whence): added POSIX command command.
-
- * c_sh.c(c_label): removed check for null wp.
-
- * exec.c(comexec): added new flags argument (FC_*);
- don't call newblock() if FC_NOBLOCK set; pass flags on to
- findcom(); changed all calls; made comexc() a non-static
- function.
-
- * table.h:(FC_SPECBI,FC_FUNC,FC_REGBI,FC_UNREGBI,FC_PATH,FC_DEFPATH,
- FC_NOAUTOLOAD,FC_NOBLOCK): new defines.
- * exec.c(findcom): merged insert/justsearch/autoload arguments
- into one flags argument; changed code to check various flags;
- changed all calls.
-
-Sat Sep 17 20:17:59 NDT 1994 Michael Rendell (michael@garfield.cs.mun.ca)
-
- * exec.c(comexec): print error if builtin has no command.
-
- * exec.c(execute): before doing redirections, check for TCOM and
- evaluate arguments and determine if it is a special builtin;
- print arguments (using PS4) if FXTRACE set; case TCOM: simply call
- comexec().
- * exec.c(comexec): deleted vp argument; only call newblock() if
- needed (ie, !special, !empty); evaluate assignments and put
- in environment one at a time; print environment (using PS4) if
- FXTRACE set; removed code to turn empty command into :;
- removed environment setting code in switch statement.
- * exec.c(echo): deleted function.
-
- * lex.c(yylex): only honour CMDWORD if FPOSIX set.
-
- * c_sh.c(shbuiltins): removed = attribute from false/true commands.
-
- * sh.h(E_TCOM): delete define - not used.
-
- * sh.h(null),var.c: use EXTERN for initialization of null.
- * sh.h(space,newline,slash): new variables (" ", "\n", "/")
- use these everwhere instead of "", " ", "\n", "/".
- * path.c: include sh.h.
-
- * exec.c(execute): combined TFOR/TSELECT cases.
-
-Fri Sep 16 11:32:01 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.h(CMDWORD): new define to prevent continued alias expansion in
- non-command contexts.
- * lex.c(yylex): only set ALIAS if SF_ALIAS and CMDWORD are set.
- * syn.c(get_command): case LWORD/REDIR: pass CMDWORD if argc is 0.
-
- * exec.c(comexec): if there is no command, do assignments and set
- the return value to subst_exstat (used to fake a : command).
-
- * sh.h(subst_exstat): new variable.
- * exec.c(execute): case TCOM: clear subst_exstat before doing eval()s.
- * eval.c(expand): set subst_exstat to return value of waitlast().
- * c_sh.c(c_set): if !FPOSIX, return subst_exstat instead of 0.
-
- * exec.c(execute): removed redundent "exstat = rv;" near if FERREXIT.
- * exec.c(comexec): case CFUNC: for normal function completion, set
- i to 0 and rv to return value of execute() (was i=LRETURN,exstat=..).
-
- * main.c(include): return -1 if file could not be found/opened,
- otherwise, the exit status of the last command is returned;
- changed all calls.
- * c_sh.c(c_dot): print error if include() returns < 0.
-
- * var.c(setspec): ifdef EDIT'd V_VISUAL, V_EDITOR cases.
-
- * misc.c(parse_args): no longer accept set -o alternations as
- a substitute for set -o braceexpand.
-
- * jobs.c(j_exit): when restoring tty process group, also restore
- our process group.
-
- * config.h.bot: define JOB_SIGS iff we have modern signal and wait
- routines.
- * jobs.c: use ifdef JOB_SIGS instead of ifdef JOBS when setting
- signal masks and routines or using waitpid; define TTY_PGRP and
- NEED_PGRP_SYNC seperately from JOBS.
- * jobs.c(j_kill): only send SIGCONT if job is stopped.
- * jobs.c(j_jobs): remove exited/signaled jobs even if !FMONITOR,
- un-ifdef JOBS same.
-
- * jobs.c(check_job): ifdef FNOTIFY with JOBS (noted by
- Michael Haardt <u31b3hs@POOL.Informatik.RWTH-Aachen.DE>).
- * jobs.c(j_notify,j_waitj): put ifdef JOBS around use of FMONITOR.
- * main.c(shell): removed ifdef JOBS from declaration of interactive.
-
- * ksh_limval.h,sh.h: moved include of <limits.h> from ksh_limval.h
- to sh.h since some machines define CLK_TCK there.
-
-Thu Sep 15 09:58:14 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * vi.c(vi_cmd): took out ESC as file completion char in command mode
- (too annoying).
-
- * jobs.c(exchild): if starting a job in the background and FBGNICE
- is set, call nice().
-
- * Makefile.in: changed maxext to manext (fix from Thomas Gellekum
- <thomas@ghpc8.ihf.rwth-aachen.de>); in the install target, check
- if the path of the installed shell is in /etc/shells and
- complain if it isn't; added depend target, removed old $(OBJS)
- and trap.o dependencies.
-
-Wed Sep 14 09:39:55 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * misc.c(options[]): changed position of vi-tabcomplete option.
-
- * lex.c(yylex): ifdef use of FVI/FEMACS/FGMACES with VI/EMACS
- (fix from Gordan Larson <hoh@approve.se>).
-
- * ksh.1(DESCRIPTION): added missing P in \fP
- (fix from Gordan Larson <hoh@approve.se>).
-
-Tue Sep 13 11:01:47 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.0.6 distribution
-
-Mon Sep 12 11:39:07 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(scriptexec): changed so it will compile if SHARPBANG is
- defined; fixed error message; shell argument is everything up to
- a newline; don't listen to #! line unless it ends in a newline.
-
- * syn.c(get_command): case FOR: changed VARASN to ARRAYVAR.
-
- * jobs.c(waitfor): restore signal mask before returning if named job
- isn't own own; when waiting for unspecified jobs, only consider
- running jobs; don't pass JW_STOPPEDWAIT flag to j_wait.
-
- * table.h(V_TMPDIR,tmpdir): new define/variable.
- * var.c(setspec, unsetspec): added case for V_TMPDIR.
- * io.c(maketemp): use tmpdir variable if it is set, else use /tmp.
-
- * var.c(popblock): if poping a variable that wasn't set in the old
- environment, call unsetspec().
-
-Fri Sep 9 10:37:18 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(PATHMAX): increased value from 256 to 1024.
-
- * main.c(main): moved initialization of name to start of main;
- if getcwd() fails, use name in error message and call shf_flush().
-
- * io.c(maketemp): check/use TMPDIR variable instead of /tmp; allocate
- temp structure and path in one chunk.
-
- * c_ksh.c(c_cd): when checking for no home directory, compare
- against null, not (char *) 0.
-
-Thu Sep 8 10:52:59 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.c(yylex): case SHIST: flush shl_out after printing command.
-
- * jobs.c(check_job): when notifing, do not remove job if it is stopped.
-
-Wed Sep 7 10:55:35 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.0.5 distribution
-
- * main.c(shell): commented out shf_flush(shl_out) - shouldn't be
- needed since -v flushes itself.
-
-Tue Sep 6 09:30:57 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * sh.h(LSHELL,really_exit): new define/variable.
- * c_sh.c(c_exitreturn): if how is LEXIT, check if there are stopped
- jobs and, if so, unwind with LSHELL (also check/set really_exit).
- * main.c(shell): added case for LSHELL - stop unwinding if shell
- is interactive; changed local reallyquit to global really_exit.
- * main.c(include),exec.c(comexec): added case for LSHELL.
-
- * c_sh.c(c_exitreturn): quitenv() for LRETURN as well as LEXIT.
-
- * sh.h(TF_CHANGED): new define.
- * trap.c(runtrap): default EXIT/ERR trap during execution and restore
- original if TF_CHANGED not set.
- * trap.c(settrap): set TF_CHANGED when setting trap.
-
- * jobs.c(j_stopped): check that job created by current process; print
- "You have stopped jobs" message.
- * main.c(shell): don't print you have stopped jobs message.
-
- * main.c(initcoms): removed echo alias.
- * c_ksh.c(kshbuiltins): added echo as a builtin.
- * c_ksh.c(c_print): if wp[0] is echo, act like strict sysv echo;
- added \a (BEL) escape sequence.
-
- * syn.c(function_body): new function; calls get_command() to get
- the body of a function (old code did nested { } block which
- caused problems with how redirections after the block were
- handled).
- * syn.c(get_command): call function body to deal with foo() and
- function foo.
-
- * jobs.c(restore_ttypgrp): new variable.
- * jobs.c(j_change): set restore_ttypgrp if process group is set.
- * jobs.c(j_exit): if necessary, restore tty process group for main
- shell.
-
-Fri Sep 2 21:32:03 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * main.c(main): set FPRIVILEGED if uid (gid) doesn't match euid (egid);
- don't include $HOME/.profile if FPRIVILEGED; include
- /etc/suid_profile instead of $ENV if FPRIVILEGED.
- * misc.c(change_flag): if clearing FPRIVILEGED flag, set euid (egid)
- to uid (gid).
-
-Fri Sep 2 21:10:23 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * main.c(main): don't include $ENV if uid (gid) doesn't match
- euid (egid) (from J.T.Conklin).
-
-Fri Sep 2 12:07:14 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * syn.c(get_command): removed MPAREN case, taken care of in '(' case,
- as per POSIX.2 which says () is two operators, not one.
- * lex.c(yylex): don't check for/return MPAREN.
- * lex.h(MPAREN): deleted define.
-
- * configure.in: add test for library routine confstr(); add
- header test for paths.h.
- * sh.h: include paths.h if available; define DEFAULT__PATH.
- * table.h(def_path): new variable.
- * options.h(DEFAULT_PATH): new define.
- * main.c(main): initialize value of def_path; set path to def_path;
- remove PATH initalization from initsubs; do not set value of HOME
- variable (POSIX); allow SHELL, PS1, PS2, PS3 to have empty values
- (at&t ksh).
- * var.c(unsetspec): when unsetting PATH, set path to def_path.
-
- * jobs.c(j_waitj): restore proc mask before calling error if
- 1st tcsetpgrp() fails.
-
-Thu Sep 1 10:28:03 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * Makefile.in: added check-sig.c, check-fd.c and check-pgrp.c
- to RCSFILES; added rules for compiling the above; added debugtools
- target to compile them all.
-
- * c_test.c(arg0,t_error,T_ERR_EXIT): new variables/defines.
- * c_test.c(c_test): set arg0 to wp[0], t_error to 0; after
- calling eval_binop() or oexpr() check t_error and if set,
- return T_ERR_EXIT.
- * c_test.c(syntax): set t_error exit; use shellf() instead of
- errorf(); use arg0 instead of "test"; delete GCC_FA_NORETURN
- attribute; changed all calls to return after calling.
- * c_test.c(oexpr,aexpr,primary): check terror after calling
- oexpr(), aexpr(), nexpr().
-
- * c_test.c(primary): if unary operator is -t and there is no
- argument, don't increment t_wp; if missing closing parenthesis,
- show next operand (if any) in error message.
- * c_test.c(eval_unop): default case, print t_wp[-2] (was -1).
- * c_test.c(c_test): set t_wp before calling eval_binop() incase
- there is an erorr.
- * c_test.c(syntax): print first message even if op is an empty string.
-
-Wed Aug 31 11:48:51 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * expr.c(O_LT, O_GT): reverse order of enums to match opinfo table.
-
- * c_test.c(nexpr): always call !nexpr() (never !primary()).
- * c_test.c(c_test): switch on argc-1 to make code match POSIX
- description; make 4 arg case fall into 3 arg case, and 3 arg case
- fall into 2 arg case.
- * c_test.c(is_not,is_and,is_or): new defines.
- * c_test.c(c_test,oexpr,aexpr,nexpr): use is_not,is_and and is_or.
- * c_test.c(primary): don't decrement t_wp in final string case.
-
- * c_test.c(eval_unop): change S_ISIFO to S_ISFIFO and S_ISFITO
- to S_ISFIFO.
-
- * misc.c(parse_args): use OF_SET when initializing set_opts.
-
-Wed Aug 31 09:32:39 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * made pdksh-5.0.4 distribution
-
- * jobs.c(j_change): do not restore tty process group when turning
- off job control; no need to save original tty process group;
- deleted orig_ttypgrp variable. (fixes bug in which turning off
- job control causes an interactive shell to exit)
-
-Tue Aug 30 14:43:48 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * aclocal.m4(KSH_OPENDIR_CHECK): always include sys/types.h;
- set return value according to what failed.
-
-Tue Aug 30 11:17:09 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * missing.c(strerror): for systems without sys_errlist[], report
- error number if unknown.
-
- * Makefile.in: added BUG-REPORTS to DISTFILES.
-
- * jobs.c(exchild): do tcsetpgrp() in both parent and child after
- the first process is created (may need to change to every child).
-
- * aclocal.m4(KSH_PGRP_SYNC): new test - defines NEED_PGRP_SYNC.
- * acconfig.h: added define for NEED_PGRP_SYNC.
- * configure.in: use KSH_PGRP_SYNC test.
- * jobs.c(exchild,j_startjob,j_sync_open,j_sync_pipe): if NEED_PGRP_SYNC
- is defined, use a pipe to block the first process in a pipeline
- until the whole pipeline is set up.
-
-Mon Aug 29 09:15:00 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * jobs.c(exchild): for background, unmonitored jobs, don't open
- /dev/null if input is a pipe.
-
- * jobs.c(exchild): for background, unmonitored jobs, use setsig()
- instead of setexecsig() to set up SIGQUIT and SIGINT; changed
- restoration of SIGTSTP,SIGTTIN,SIGTTOU - set them to DFL if
- monitoring and not a `..` command, otherwise leave them alone.
- * jobs.c(j_init): only use SIGTSTP,SIGTTIN,SIGTTOU if talking
- or monitoring - if just talking leave signals ignored.
- * jobs.c(j_change): if going into job control, set TF_SHELL_USES
- flag for sigtraps[SIGTSTP,SIGTTIN,SIGTTOU]; if leaving job control
- ignore signals if interactive, else restore original signals.
-
- * table.h(SPEC_BI, REG_BI): new defines.
- * exec.c(builtin): check for * or + in front of builtin names and set
- SPEC_BI or REG_BI if found.
- * exec.c(findcom): search for special builtins first, then functions,
- then regular builtins, then PATH search.
- * c_sh.c(shbuiltins[]),c_ksh(kshbuiltins[]): add */+ in front of POSIX
- special/regular builtins; add = infront of unset;
- remove = from alias.
- * c_sh.c(c_label): set exit value according to name (for true/false).
- * c_sh.c(shbuiltins[]): add entries for true and false.
- * main.c(initcoms[]): deleted true/false aliases.
-
- * aclocal.m4(KSH_OPENDIR_CHECK): new test - see if opendir() will
- open non-directories.
- * configure.in,acconfig.h: added KSH_OPENDIR_CHECK.
- * missing.c,ksh_dir.h(ksh_opendir): new define/function.
- * eval.c(globit),emacs.c(compl_file): use ksh_opendir() instead of
- opendir().
-
- * main.c(include): save source filename since search() uses line[]
- for the filename and shell() trashes line[].
-
- * table.h(FINUSE,FDELETE) new defines.
- * exec.c(execute): case CFUNC: re-arranged code so normal return goes
- through setjmp() switch; use FDELETE/FINUSE flags to avoid problems
- with a function being undefined or redefined during its execution.
- * exec.c(define): if FINUSE is set, set FDELETED and find a new table
- entry.
-
-Fri Aug 26 21:58:25 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.c(getsc_): flush output after write when echoing.
-
- * Makefile.in(dist): after creating distrubution, use pathchk -p
- to check file names.
-
-Fri Aug 26 10:28:20 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * made pdksh-5.0.3 distribution
-
- * expr.c(IS_ASSIGNOP): new define.
- * expr.c(evalexpr): use IS_ASSIGNOP (bug fix).
-
- * exec.c(execute): case TFOR,TSELECT: change e->type just
- before setjmp() to avoid problems with bad jmpbufs.
-
- * jobs.c(startlast): new function.
- * jobs.c(waitlast): print error if job not started.
- * eval.c(comsub): call startlast() after execute().
- * jobs.c(exchild,j_startjob,j_sync_pipe): when starting a pipeline
- use a pipe to ensure the first process doesn't die before
- the last process is started.
-
- * exec.c(execute): case TFUNC: set/clear FXTRACE according to
- tp->flag & TRACE, and restore old value when function completes.
-
- * c_test.c,exec.c,io.c,mail.c,vi.c: changed all uses of
- (x&S_IFMT) == S_IF* to the equivilent S_IS* (for ISC unix).
- * c_test.c(eval_unop): if system doesn't have symlinks or sockets
- (S_ISLNK,S_ISSOCK), return 0 (used to cause internal error).
- * ksh_stat.h(S_ISVTX): define if sys/stat.h doesn't.
-
- * sigaction.c(Signal,signal): ifdef'd Signal() and signal() out as
- they cause header file conflicts on some systems (eg, signal()
- in ISC unix); also ifdef'd out other routines not used by ksh
- (ie, sigdelset, sigfillset, sigismember, sigpending).
-
-Thu Aug 25 11:50:03 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * c_test.c(primary): always check that *t_wp isn't 0 before using it.
-
- * eval.c(homedir): cache home directory values.
-
- * exec.c(findcom): search builtins before tracked aliases.
-
- * table.h(commands,taliases): changed name of commands to taliases.
-
- * c_ksh.c(c_unalias): changed to use ksh_getopt(); added -t and -a
- options; exit with non-zero value if non-alias name unaliased
- (POSIX).
-
- * main.c(initcoms[]): alias hash to 'alias -t -'; added autoload alias
- as well; set selected comands to be tracked aliases (eg, grep,
- ls, who, vi, emacs, etc.).
-
- * c_ksh.c(c_alias): when printing aliases, check ISSET, not DEFINED
- flag (so unset tracked aliases won't cause problems); changed
- to use ksh_getopt(); added -t flag; added -x flag (does nothing).
- * c_ksh.c(c_hash): deleted function; removed all references.
-
- * table.h(CTALIAS): new define.
- * exec.c(findcom): added search argument for whence -p; fixed
- introduced bug preventing tracking of commands when insert set;
- changed all calls; when creating tracked aliases, set type to CTALIAS
- (was CEXEC).
- * exec.c(findcom,flushcom): when freeing old tracked aliases, use
- APERM, not commands.areap.
- * c_ksh.c(c_whence): changed to use ksh_getopt(); assume findcom()
- never returns 0 and never returns tp->type == CNONE; made output
- closer to at&t ksh output; combined vflag/!vflag switch statements;
- added case for CTALIAS.
- * exec.c(findcom): set tracked alias type to CTALIAS.
-
- * c_ksh.c(c_print): added -s option; changed to use Xstring() routines
- and write() instead of shf routines; returns non-zero if there
- was a write error.
-
- * jobs.c(struct job): changed pid_t lpid field to Proc *last_proc;
- changed all uses.
- * jobs.c(check_job): use j->last_proc instead of lp.
- * jobs.c(j_waitj): when checking for fake ^C, test j->last_proc
- status to see if it was signaled and use WTERMSIG to get signal.
-
- * main.c: initialize integer TMOUT parameter to 0; call alarm_init()
- if FTALKING.
- * trap.c(alarm_init,alarm_catcher): new functions.
- * trap.c(runtraps): if ksh_tmout_leave is set, exit.
- * sh.h(TMOUT_EXECUTING,TMOUT_READING,TMOUT_LEAVING,ksh_tmout,
- ksh_tmout_state): new enum values/variables.
- * table.h(V_TMOUT): new define.
- * var.c(special,setspec,unsetspec): added V_TMOUT entry.
- * edit.c(x_getc): call intrcheck() if read interrupted.
-
-Thu Aug 25 09:36:54 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * c_test.c(c_test): for argc cases 4 and 5, return the complement
- of the expressioin result; for [[ .. ]] expressions, don't parse
- based on argc; deleted struct t_op.op_flags field and related
- defines UNOP,BINOP,ACCEPT_BE,ISTEST,ISDBRACKET,ISBOTH - changed all
- uses to test the value of isdbracket.
- * c_test.c(filstat): moved body of filstat() into eval_unop(), deleted
- filstat().
-
- * c_test.c: incorperated changes from J.T. Conlin (jtc@cygnus.com)
- for POSIXization of test builtin.
-
-Wed Aug 24 12:16:25 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * new-version.sh: new file - updates date in version.c
- * Makefile.in: added new-version.sh to RCSFILES; call new-version.sh
- in dist: target.
-
-Tue Aug 23 09:28:10 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * made pdksh-5.0.2 distribution
-
- * jobs.c(exchild): don't call restoresigs().
- * exec.c(execute): do call restoresigs() (just before execve()).
-
- * c_sh.c(c_trap): ifdef'd out code to print default traps. Too ugly
- and it isn't clear POSIX needs it.
-
- * c_ksh.c(c_print): put -e option back in for echo emulation (-R).
-
- * c_sh.c(c_shift): generate error if n < 0.
-
- * c_sh.c(c_trap): use shellf instead of errorf to report errors
- (so we can return a value instead of unwinding - POSIX).
-
- * exec.c(execute): if command fails and !FERREXIT, call
- trapsig(SIGERR_).
-
- * c_sh.c(c_exit,c_return,c_exitreturn): combined c_exit and c_return
- functions.
-
-Mon Aug 22 09:39:54 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * eval.c(expand): case XARG: set word to IFS_WORD to force null
- words to be created.
-
- * lex.c(yylex): added indquotes flag and code for `...` parsing
- (to deal with "`...`" the way sh/at&t-ksh does).
-
- * trap.c(runtrap): don't reset ERR trap.
-
- * sh.h: combnied SS_USER/SS_FORCE flags with RESTORE_CURR et. al.
- flags; changed RESTORE_* to SS_RESTORE_*.
- * trap.c(setsig): combined restore, force and user flags; changed
- all calls.
- * trap.c(setexecsig): use SS_RESTORE_* values as argument.
-
- * table.h: changed LCASE to LCASEV (and UCASE_AL to UCASEV_AL) to
- avoid problems with ioctl/tty LCASE define.
-
- * sh.h(struct env): deleted interactive field.
- * main.c(shell),exec.c(iopsetup): deleted e->interactive assignment.
-
- * sh.h: made e a struct env * (was struct env); changed all references.
- * main.c(newenv): copy loc, flags and interactive fields explicitly.
-
- * var.c(newblock): allocate block structure, don't assume already
- exists.
- * var.c(popblock): free old block structure.
- * main.c(main): set e->loc to 0 before calling newblock().
- * exec.c(comexec): let newblock() allocate new structure; deleted
- l variable (changed references to e->loc).
- * table.h: deleted globals variable.
-
- * c_ksh.c(c_print): treat a lone - like --.
-
- * main.c(main),trap.c(inittraps): move SIGINT,SIGQUIT,SIGTERM signal
- initialization to inittraps() and do it regardless of FTALKING.
-
- * trap.c(settrap): deleted force trap since probably will never
- add -f flag to trap.
-
- * main.c(unwind): if we are dieing of SIGINT or SIGTERM, kill
- ourselves with a signal.
-
- * vi.c(x_vi),emacs(x_emacs): if ^C read, call trapsig()/runtraps();
- don't return -2.
- * edit.c(x_read): don't check for -2 return value.
- * vi.c(x_vi): check for quit char (^\) and fake SIGQUIT.
-
- * exec.c(comexec): made flags argument volatile.
-
- * misc.c(getn_): new function.
- * c_sh.c(c_exit,c_return): call quitenv() before unwind()ing;
- moved c_exit() next to c_return(); use getn_() instead of getn().
-
- * main.c(shell): added exit_atend argument to deal with POSIX trap exit
- semantics; changed all calls.
- * sh.h: added STOP_RETURN macro.
- * c_sh.c(c_return): determine if we are returning or exiting before
- unwind()ing so POSIX trap exit semantics are honored.
-
- * jobs.c(j_sigchld): call trapsig() instead of messing with sigtraps[].
- * trap.c(trapsig): don't restore signal handler if it wasn't set to
- trapsig.
-
- * sh.h: added TF_TTY_INTR flag.
- * trap.c(inittrap): set TF_TTY_INTR for SIGINT.
- * jobs.c(j_waitj): if
-
- * jobs.c,sh.h: deleted SA_RESTART ifdefs; moved SIGCLD->SIGCHLD ifdefs
- from jobs.c to sh.h.
-
-Sat Aug 20 15:26:24 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * sh.h: added KSH_SA_FLAGS define.
- * trap.c(inittrap,setsig): set sa_flags field to KSH_SA_FLAGS.
- * sigact.c(sigaction): if using BSD42_SIGNALS, set the SV_INTERRUPT
- flag.
- * configure.in: deleted AC_RESTARTABLE_SYSCALLS.
- * config.h.bot: add error message to prevent compilation if using
- BSD41 signals.
-
- * shf.h: added SHF_INTERRUPT flag.
- * shf.c(shf_fillbuf,shf_putchar,shf_write,shf_emptybuf): call
- intrcheck() if read()/write() interrupted and SHF_INTERRUPT set.
- * c_sh.c(c_read): use SHF_INTERRUPT flag.
- * lex.c(getsc_): call intrcheck() if read() interrupted.
-
- * main.c(main),trap.c(inittrap): moved Sigact* initialization
- from main() to inittrap(); made Sigact_trap/Sigact_ign static;
- deleted Sigact and Sigact_dfl.
- * sh.h: deleted declarations of Sigact*.
-
- * main.c(shell): deleted sigaction call - no longer needed.
-
- * sh.h: added RESTORE_CURR, RESTORE_ORIG, RESTORE_DFL and RESTORE_IGN
- defines.
-
- * trap.c(intrcheck): new function.
- * trap.c(runtraps): added intr argument; clear trap/intrsig
- before running traps; changed all calls.
- * trap.c(runtrap): save/restore exstat when running trap.
- * jobs.c(j_waitj): changed interrupt test to check intrsig
- and return -1.
- * jobs.c(waitfor): if j_waitj() returns -1, call intrcheck().
- * jobs.c(j_change): use setsig() instead of sigaction() to
- set up SIGTTIN,SIGTTOU,SIGTSTP.
-
- * trap.c(inittraps): initialize flags for INT/QUIT/TERM.
- * sh.h(intrsig): new variable.
- * trap.c(trapsig): set intrsig if signal has TF_DFL_INTR flag set;
- deleted longjmp().
- * trap.c(runtraps): clear intrsig.
- * trap.c(runtrap): if signal is defaulted and TF_DFL_INTR is
- set, set exstat and call unwind(); return if signal ignored;
- reset an ERR trap before executing it.
- * trap.c(cleartraps): deleted special case for EXIT; reset
- command traps using settrap(); clear intrsig.
- * trap.c(restoresigs): only deal with traps that have the TF_EXEC_IGN
- flag set (others take care of themselves).
-
- * trap.c(sigtraps[]): added ERR trap.
- * trap.c(gettrap): deleted #if 0'd ERR/EXIT check.
- * trap.c(gettrap,runtrap,cleartraps,restoresigs): use SIGNAL+1 to
- go through trap table.
- * sh.h(SIGEXIT_,SIGERR_): new defines.
- * c_kill.c(c_kill): test for signals > 128 (was >= 128)
- * c_sh.c(c_trap): when printing traps, use SIGNALS+1.
-
- * sh.h(struct trap): replaced ourtrap and sig_dfl fields with
- flags field; defined TF_SHELL_USES, etc. for flags field; added
- cursig field.
- * sh.h(struct env): replaced func_parse field with
- flags field; defined EF_FUNC_PARSE, EF_BRKCONT_PASS for flags
- field; defined STOP_BRKCONT(); changed uses of func_parse
- (get_command()/readhere()).
- * c_sh.c(c_brkcont): use STOP_BRKCONT(), EF_BRKCONT_PASS; call
- unwind() to do the work.
-
-Fri Aug 19 09:59:43 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * trap.c(settrap): new function - does most of what c_trap did.
- * c_sh.c(c_trap): changed to use settrap(); print out default
- actions as well as caught/ignored actions.
- * trap.c,c_sh.c(setsig): moved setsig from c_sh.c to trap.c and
- made it static; added force and user arguments; don't do anything
- for EXIT and ERR.
- * main.c(main): use sigtrap() instead of ignoresig().
- * trap.c(ignoresig): deleted function.
-
- * exec.c(execute): case TSELECT: don't change SIGINT signal handler.
-
- * proto.h: use GCC_FA_NORETURN on aerror().
- * syn.c(yyparse): made function static and void.
-
- * exec.c(herein): changed error() calls to errorf()s; use error()
- in error handler; call shf_close() instead of shf_fdclose().
-
- * tree.h,sh.h: moved LBREAK/LCONTIN from tree.h to sh.h;
- added LEXIT, LRETURN, LERROR, and LINTR defines; changed values
- of LBREAK/LCONTIN; changed all calls to longjmp() and setjmp().
- * exec.c(execute): put Break: label after main switch, changed
- goto Break[0-9] to Break; deleted Break[0-9] labels.
- * exec.c(execute): changed FOR, SELECT, WHILE, DO loop setjmps
- to explicitly check for LBREAK/LCONTIN, otherwise call unwind().
- * exec.c(execute): case TFUNC: added setjmp switch statement to take
- care of various L* values.
- * main.c(include,shell): added setjmp switch statement to take care of
- various L* values.
- * main.c(unwind): added L* parameter to pass on to longjmp();
- changed all calls.
- * c_sh.c(c_return): just call unwind(LRETURN);
- * main.c(unwind): put code from leave() in E_NONE case.
- * main.c(error,leave): deleted functions; replace all calls with
- unwind(LLEAVE or LERROR).
- * *.c(longjmp): replaced all calls with unwind(L..) (except the
- call in unwind()).
-
- * shf.h: add areap field to struct shf.
- * shf.c(shf_fdopen,shf_sopen): initialize areap
- * shf.c(shf_emptybuf,shf_close,shf_sclose,shf_finish): use areap
- instead of ATEMP.
-
- * shf.c(shf_sopen): if buf is 0 and writing and DYNMAIC, allocate
- a buffer; if writing, save room for a trailing null.
- * shf.c(shf_sclose): new function.
- * shf.c(shf_snprintf),tree.c(snptreef): use shf_sclose().
- * tree.c(snptreef): changed return type to char *; if buffer
- is null, pass SHF_DYNAMIC to shf_sopen(); return (possibly
- allocated) string.
- * syn.c(syntaxerr): use snptreef() instead of ident.
-
- * tree.h: new define TDBRACKET; new defines DB_NORM,DB_OR,DB_AND,
- DB_BE,DB_PAT.
- * tree.c(ptree): added case for TDBRACKET.
- * syn.c(get_command): case DBRACKET: make TDBRACKET command;
- at end of function, null terminate args/vars if TDBRACKET.
- * c_test.c(is_db_patop): new function.
- * syn.c(db_primary): set type of arg to DB_PAT if is_db_patop()
- returns true.
- * exec.c(execute): added case for TDBRACKET.
-
- * syn.c(get_command): case MDPAREN: make arg[0] an allocated stuffed
- string (was a literal string).
-
-Thu Aug 18 11:06:49 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * c_test.c(is_op,is_binop,is_unop): new functions to test for
- unary/binary operators.
- * c_test.c(oexpr,aexpr,nexpr,primary): no longer take argument -
- call is_unop/is_binop directly.
- * c_test.c(ISDBRACKET,ISTEST,ISBOTH,ACCEPT_BE): new defines.
- * c_test.c(struct t_op): changed op_type field to op_flags.
- * c_test.c(ops[]): broke into two arrays: u_ops and b_ops;
- set flag field to ISDBRACKET/ISTEST/ISBOTH as appropriate.
- * c_test.c(t_lex): deleted function.
- * c_test.c(primary): before checking for unary operator, check
- for -BE (binary expression next) if appropriate.
-
- * c_test.c: made operator type an enum to make it easier to add
- operators; changed oexpr/aexpr/nexpr/primary/filstat/t_lex
- operand/return types.
- * c_test.c(struct t_op): changed op_text from char * to char [4].
- * c_test.c(primary): case FILTT: using digit(**t_wp) causes core dump
- when there is no arg - just test if *t_wp is 0; move test into
- filstat().
- * c_test.c(primary): use *opnd1 != 0 instead of strlen(opnd1) (3
- instances).
-
- * tree.c(wdscan,wdcopy): changed string argument to const; changed
- return type of wdscan to const.
-
- * eval.c(expand): case CSUBST: case '?': use st->var->anme instead
- of cp to allow proper nesting.
- * eval.c(expand): case OSUBST: don't change cp - declare local
- variable.
- * eval.c(expand): case COMSUB: deleted Xsavepos() call; XCOM: deleted
- Xrestpos() call.
- * eval.c(expand): save the position of the first unquoted = for tilde
- expansion.
- * eval.c(expand): case '~': use sp == (cp+2) instead of dp == Xstring
- so we aren't fooled by ''~ or ${foo}~; sp[-1]/sp[-2] and firsteq
- for the DOASNTILDE after first = or unquoted : test.
-
- * tree.h(struct op): changed noexpand field to evalflags; changed
- all uses.
- * exec.c(execute): if t->evalflags is non-zero, pass them to eval().
-
- * lex.h: added DBRACKET define for [[ keyword.
- * syn.c(get_command): added case for DBRACKET.
- * syn.c(db_parse,db_oaexpr,db_nexpr,db_primary): new functions
- to parse [[ .. ]] expressions.
- * syn.c(tokentab[]): added [[/DBRACKET keyword.
- * c_test.c(is_db_unop,is_db_binop): new functions to test if arg
- is [[ .. ]] unary/binary operator.
-
- * syn.c(syntaxerr): call REJECT; before token; removed REJECT
- before all calls to syntaxerr().
- * syn.c(get_command): removed syntax error kludge.
-
-Wed Aug 17 11:07:40 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
- * c_test.c(struct ops): changed -U to -O.
-
- * tree.h: added new defined DOASNTILDE.
- * eval.c(expand): case '~': changed !(f&DOBLANK) to f&DOASNTILDE.
- * exec.c(execute): case TCOM: pass DOASNTILDE when evaluating vars
- and when expanding args when t->noexpand is set.
-
- * exec.c(execute): case TCASE: pass DOTILDE to both evalstr() calls
- (POSIX).
-
- * syn.c(get_command): don't check for redirections before determining
- command type; handle REDIR where LWORD are handled; default case
- always returns; pass ARRAYVAR flag to tpeek() if t->noexpand;
- don't allow redirections before "x()" function; don't allow
- redirection before keywords; allow a '(' in the case LWORD/REDIR:
- if no variables or arguments (POSIX doesn't allow this, but
- at&t ksh/bourne sh do).
- * lex.h(ARRAYVAR): new define.
- * lex.c(yylex): parse x[1 & 2] as one word if VARASN|ARRAYVAR.
-
- * var.c(is_wdvarname): added aok argument; changed all calls.
- * syn.c(get_command): case FOR/SELECT: check identifier is valid.
-
- * c_sh.c(c_trap): use print_value_quoted() to print traps;
- use ksh_getopt() to skip possible --.
- * trap.c(gettrap): allow digits only if signal numbers match
- POSIX values (ie, HUP=1,INT=2,QUIT=3,ABRT=6,KILL=9,ALRM=14,TERM=15).
-
- * misc.c(print_value_quoted): new function to print strings with
- appropriate quoting.
- * c_ksh.c(c_typeset,c_alias): use print_value_quoted() when printing
- values.
-
- * lex.h: added new ESACONLY flag - only accept ESAC keyword.
- * lex.c(yylex): check for ESACONLY flag when doing keyword search.
- * syn.c(caselist): pass ESACONLY flag to tpeek().
-
-Tue Aug 16 10:17:47 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.h(struct source); changed echo field to generic flags field;
- defined SF_ECHO and SF_ALIASEND.
- * lex.c(_getsc): case SALIAS: use isspace() to check for trailing
- space in alias; if alias does not end in a space, return a fake
- space to keep the current alias in the source list - this allows
- recursive alias detection; set SF_ALIAS in next source if alias
- does end if space.
- * lex.c(yylex): deleted expanding_alias, rec_alias_cnt and
- rec_alias_table variables; check for recursive aliases by checking
- the source list; don't use EXPALIAS flag; if SF_ALIAS is set in
- current source, set ALIAS flag and clear SF_ALAIS; deleted global
- alias variable.
- * table.h: deleted EXPALIAS define.
- * main.c(shell): changed s->echo to set/clr of SF_ECHO in s->flags.
-
- * table.h: added aliases and keywords tables; deleted lexicals table
- (POSIX says they are seperate).
- * syn.c(keywords,initkeywords): changed name of keywords() function
- to initkeywords(); changed all calls; add to keywords table instead
- of lexicals table.
- * main.c(main): initialized aliases/keywords tables; deleted
- initialization of lexicals table.
- * c_ksh.c(c_whence,c_alias,c_unalias),lex.c(yylex): use
- keywords/aliases tables instead of lexicals table; removed unneeded
- type == CALIAS checks.
-
- * var.c(getint): new function, largely take from strint().
- * var.c(strint): call getint() to do most of the work; if vq
- was an allocated string, free the string and clear the alloc
- flag.
- * var.c(intval): call getint() instead of strint().
-
- * mail.c(mcheck): use getint() instead of strint() when getting
- value of MAILCHECK.
-
- * var.c(skip_varname): added argument to allow array references;
- changed all calls.
- * var.c(set_array): remove valid variable name check - done in
- parse_args().
-
- * var.c(strint): check if getspec()/setspec() need to be called.
- * var.c(intval): remove getspec()/INTEGER checks - let strint() do it.
-
- * var.c(skip_wdvarname,is_wdvarname,is_wdvarassign): new
- functions.
- * lex.h(VARASN): new define indicating variable assignment expected,
- currently used to parse "x[1 & 2]" as one token - may be used
- in future in returning AWORD (assignment word) to the parser.
- * lex.c(yylex): Subst: case '[': use is_wdvarname() in determining
- whether to parse an array dereference; do not require an = after the
- dereference (typeset -r x[1 & 2] is legal).
- * syn.c(many functions): pass VARASN to token/musthave/tpeek/synio
- when ever the next token might be the first word of a simple
- command.
- * syn.c(get_command): case LWORD: use is_wdvarassign() to distinguish
- variable assignments from normal arguments; allow aliases after
- redirections and variable assignments; generate syntax error
- for "foo=bar bogusfunction()"; allow array variables in for
- and select statements.
- * lex.c: make global alias variable static (no longer used by
- get_command()).
-
- * syn.c(get_command): put MDPAREN into its own case.
-
- * lex.c(yylex): deleted place holder for tilde expansion.
-
- * tree.h(struct tree): added noexpand field for
- alias/export/readonly/typeset.
- * syn.c(newtp),tree.c(tcopy): initialize/copy noexpand field.
- * syn.c(get_command): case LWORD: set noexpand if assign_command()
- returns true.
- * syn.c(assign_command): new function - returns true if command
- is alias, export, readonly or typeset.
- * exec.c(execute): case TCOM: don't pass DOTILDE flag when
- expanding t->vars; don't do field splitting/globbing/tilde expansion
- of t->args if t->noexpand is set.
-
- * table.h: re-grouped the struct tbl flags into common, variable,
- funtion, builtin/alias, etc (some values overlap); new flag
- names: KEEPASN (was overloaded with TRACE) and NOEXPAND.
- * exec.c(comexec,builtin): changed TRACE to KEEPASN.
-
- * tree.c(tcopy): when copying t->str, use strsave(), not wdcopy()
- if not copying a TCASE.
-
- * c_ksh.c(c_typeset): added -p flag for POSIX export/readonly.
-
- * eval.c(expand): expand tilde in place; don't do tilde expansion
- on results of substitution (POSIX); only do tilde expansion
- if login name is unquoted (POSIX); don't check for fdo&DOTILDE
- when a word is completed.
- * eval.c(tilde): changed to return home directory of a given login name
- (taking care of null/+/-) (old version copied string, scanning
- for, and replacing, magic tildes).
-
- * exec.c(findcom): don't create commands table entries when
- not inserting; when doing access test of tracked alias,
- check for ISSET, not ALLOC (but test ALLOC before calling afree).
- * exec.c(search): use strcpy() instead of loop.
-
-Mon Aug 15 14:46:58 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ksh.c(c_print): added at&t ksh -R flag; deleted -e flag;
- changed to use ksh_getopt().
- * main.c(initcoms[]): changed echo alias from 'print -' to 'print -R'.
-
- * sh.h: new variable procpid; added pid field to struct temp.
- * jobs.c: changed references to my_pid to procpid; deleted my_pid
- variable.
- * io.c(maketemp): initialize pid field from procpid.
- * main.c(remove_temps): only remove temporary files created by
- the current process.
-
-Sun Aug 14 11:47:05 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * var.c: added var field to struct Expand and struct SubType; deleted
- struct SubType.name field.
- * var.c(expand): case OSUBST: use x.var/st->var field to save result
- of global() for use in case CSUBST - this avoids problems with
- x[i+=1] being evaluated twice; check to see if value is being
- assigned to non-variable (eg, ${*:=aja}) or read-only variable.
- * var.c(varsub): set value of xp->var; possibly generate error if
- FNOUNSET set when expanding ${#*}, ${#var}, or ${#array[*]}.
-
- * table.h: added struct tbl.areap field to get rid of lastarea
- problems; deleted lastarea variable; changted all refernces
- to lastarea to var->areap.
- * table.c(tenter): initialize areap field.
- * var.c(arraysearch): deleted area parameter; initialize areap field.
- * var.c(global,local,intval,setint): initialize areap field of vtemp.
-
-Fri Aug 12 10:54:51 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * expr.c: re-wrote e*() functions using single function and table;
- token() now does table lookup; added full C expressions (sans
- pre/post increment, sizeof).
-
- * table.h(INT_U,INT_L): new flags.
- * var.c(strval): handle INT_U.
- * c_ksh.c(c_typeset): add exclusions for INT_U/INT_L;
- add -U option for unsigned (non-at&t ksh).
-
- * var.c(set_array): use global() instead of local();
-
- * var.c(global): when parsing $123, don't limit number to 1000.
-
- * expr.c(v_evaluate): like old evaluate, but assigns result to
- specified variable.
- * expr.c(evaluate): changed to use v_evaluate().
- * expr.c(e0): when parsing literals, use strint() instead of setstr().
-
- * var.c(setstr): when assigning to integers, use v_evaluate() instead
- of strint().
-
-Thu Aug 11 11:33:17 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * var.c(strint): don't change anything until number completely
- parsed; don't clear ISSET flag if parsing fails; fail parse
- if non-integer/non-letter found; default base if copying from
- integer variable; set ISSET if parsing succeeds.
-
- * expr.c(tempvar): set vp->val.i to 0.
- * expr.c(token): when skipping a literal number, don't allow _;
- use isspace() to skip.
- * expr.c(asn): use strint()/setstr() instead of setint().
- * expr.c(e0): added unary ~ and + (posix).
-
- * var.c(global,local): always call substitute on contents of [..];
- free sub when finished eval.
-
- * ksh_limval.h: new file.
- * shf.c: use ksh_limval.h.
- * Makefile.in: added ksh_limval.h to HDRS.
-
-Wed Aug 10 10:57:01 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ksh.c(c_whence): case CFUNC: print exported/traced/undefined,
- do not print function definition.
- * exec.c(findcom): new argument indicated if functions to be
- autoloaded; changed all calls.
-
- * misc.c(ksh_getopt): added # option modifier for typeset.
- * c_ksh.c(c_typeset): changed to use ksh_getopt(); added
- -L, -R, -Z, -l, -u flags; quote variable values when printing;
- generally re-arranged function.
- * table.h: added LJUST,RJUST,ZEROFIL,LCASE,RCASE; deleted FUNCT.
- * exec.c(findfunc): new function.
- * exec.c(define,findcom): use findfunc(); skeleton autoload code.
- * var.c(typeset): added two arguments for initial field width and
- base; changed all calls; deal with LJUST,.. flags; re-arrange to
- have one loop iterating over array; do readonly check before
- changing attributes.
- * var.c(strval): deal with LJUST,.. flags when getting integers.
- * var.c(setstr): deal with LJUST,.. flags when setting strings.
- * var.c(setstr): deal with LJUST,.. flags when setting strings.
- * var.c(arraysearch,tenter): initialize {new,p}->field to 0.
- * table.h: added struct tbl.field.
-
- * siglist.in: changed signal messages to be more or less the
- same as sys_siglist[]; moved SIGUNUSED before SIGBUS.
- * jobs.c(j_print): assume sigtrap[].mess always valid; use
- sigtrap[].mess directly for stopped processes.
-
- * aclocal.m4(KSH_SYS_SIGLIST): new macro like KSH_SYS_ERRLIST.
- * configure.in: use KSH_SYS_SIGLIST instead of AC_SYS_SIGLIST_DECLARED.
-
-Tue Aug 9 10:28:45 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * version.c: removed RCS logs since version numbers don't match
- release numbers.
-
- * configure.in: added AC_PROG_CPP
- * Makefile.in: added rules for generating siglist.out
- * siglist.in,siglist.sh: new files.
- * trap.c(inittraps,deftraps[]): deleted deftraps[]; initialize
- sigtraps[] directly by including siglist.out.
-
- * tree.h: added EXPRSUB for $((..)), re-numbered defines.
- * tree.c(tputS,wdscan): added case for EXPRSUB.
- * eval.c(expand,alt_count,alt_scan): added case for EXPRSUB.
- * lex.h: added SDDPAREN for $((..)).
- * lex.c(yylex): added case for SDDPAREN.
-
- * lex.c(yylex): case SPAREN: match parenthesis using counter instead
- of pushing/poping states.
-
- * lex.h: re-numbered S* defines to be sequential; added SREREAD.
- * lex.c(yyerror): pop SREREADs.
- * lex.c(getsc_): added case for SREREAD.
- * lex.c(arraysub): changed to save whatever is read and return a value
- indicating if brackets matched; changed all calls.
- * lex.c(yylex): if brackets in array reference are not balanced,
- or if array reference not followed by an =, re-read the input.
-
-Mon Aug 8 21:20:08 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h: fix lseek prototype (from sjg@zen.void.oz.au)
-
- * configure.in,jobs.c: added HAVE_SYSCONF; don't use sysconf() unless
- HAVE_SYSCONF defined (for NetBSD-Feb12 from sjg@zen.void.oz.au).
-
- * jobs.c(put_job): removed PJ_ON_END case and define (not used).
-
-Wed Jul 27 10:19:42 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-5.0.1 distribution
-
- * exec.c(comexec): when doing exec has no command, fall through
- and do variable assignments.
-
- * c_ksh.c(c_let): complain if there are no arguments.
-
- * exec.c(comexec): if XEXEC is set, exit after executing
- (builtin/function) command; deleted FERREXIT code; don't set
- exstat.
- * exec.c(execute): handle FERREXIT; set exstat to rv for all
- cases.
-
- * lex.c,syn.c: changed calls to errorf to yyerror (except the
- on in yyerror()).
- * lex.h(struct source): added errline field.
- * lex.c(yyerror): now a varargs function; if source->errline field is
- non-zero, print it instead of source->line.
- * syn.c(syntaxerr): set source->errline if read EOF in a multiline
- command.
-
-Tue Jul 26 11:22:06 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * lex.h(SYNTAXERR,INP): deleted macros.
- * lex.h(HISTORY): upped to 128 as per POSIX.
- * lex.h,syn.c(multiline): moved from lex.h to syn.c.
- * tree.c(vfptreef): added %R to format I/O redirections.
- * tree.c(pioact): don't output unit more than once; print unit
- only if it isn't the default for the action; print only
- one opening quote for quoted here documents; print <> for
- read-write (was ><).
- * syn.c(zzerr, syntaxerr): replaced zzerr function with new syntaxerr
- function; changed uses of SYNTAXERR to syntaxerr() calls; print
- out the last unused token; if in a multiline command when EOF
- encountered, print token that was unmatched.
-
- * tree.h(TBANG),lex.h(BANG): for POSIX ! keyword
- * tree.c(ptree),exec.c(execute): added case for TBANG.
- * syn.c(restab[]): added ! keyword.
- * syn.c(get_command): added case for BANG (!).
-
- * tree.h(XERROK): new define to allow non-zero exits to be
- ignored in certian circumstances (set -e).
- * exec.c(execute): pass XERROK to recursive execute() calls; set
- XERROK when evaluating conditional part of if/while/until/&&/||.
- * exec.c(comexec): pass XERROK on to functions; don't exit if
- XERROK is set.
-
- * jobs.c(async_pid): new variable needed since async_job may go
- away, but $! should still be expanded.
- * jobs.c(j_async): return async_pid.
- * jobs.c(j_set_async): set async_pid.
-
-Mon Jul 25 14:15:25 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * misc.c(parse_args): changed to use ksh_getopt().
-
- * c_sh(c_set): deleted call to resetopts() - neither POSIX nor
- at&t ksh touch OPTIND when positional parameters are changed.
- * exec.c(comexec): changed resetopts() call to getopts_reset(1) - this
- is not a proper fix - should declare a local optind.
-
- * misc.c(builtin_getopt,ksh_getopt): renamed builtin_getopt to
- ksh_getopt (shorter); changed to use state structure instead
- of static variables; changed all calls; optionally allow + to
- introduce an option; don't skip lone - (or +) in arguments - set
- optind to point to it.
- * misc.c(ksh_getopt_reset): changed to use state structure instead
- of static variables.
- * sh.h(Getopt): new structure for ksh_getopt() state.
- * exec.c(call_builtin): call ksh_getopt_reset().
- * c_ksh.c(c_getopts,getopts_reset): new getopts implementation that is
- POSIX complient and uses ksh_getopt() routine.
- * var.c(setspec): call getopts_reset() when OPTIND set.
- * getopts.c: deleted file.
- * Makefile.in: deleted getopts.c and getopts.o.
- * options.h(FASCIST): deleted option.
-
-Thu Jul 21 09:52:03 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-4.9+mun.5 distribution
-
- * syn.c(get_command),shf.c(shf_fdopen,shf_sopen,shf_emptybuf):
- added cast to alloc()/aresize() calls.
- * sh.h: changed enum flags_enum to enum flags.
- * misc.c(change_flag): changed type of first argument to enum flag.
- * edit.c(set_editmode): change type of static array to enum flag.
-
- * edit.c(x_init): initialize tty chars to -1, except for werase,
- which is set to ^W.
- * edit(x_mode): split oldedchars structure declaration and
- initalization (some old compilers don't like them combined).
-
- * c_test.c: made -h work like -L.
-
-Wed Jul 20 11:12:52 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * config.h.top: moved compile options into options.h; include
- options.h.
- * options.h: new file.
-
- * c_ksh.c(c_fgbg): if !FPOSIX, set return job exit status.
-
- * jobs.c(j_jobs,j_notify): use JF_REMOVE to flag jobs to delete
- after all notification done (to prevent multiple + or - jobs).
-
- * jobs.c(put_job): new funtion, takes argument to specify where
- to put job; changed all calls to put_job_on_front and
- put_job_on_end to use this; put background processes just
- after stopped jobs (instead of at end) (POSIX).
- * jobs.c(put_job_on_front,put_job_on_end): deleted.
-
-Tue Jul 19 10:33:55 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * aclocal.m4(AC_MMAP): copied from autoconf's acspecific.m4 and
- modified to use the MAP_FILE flag if available.
-
- * misc.c(change_flag): ifdef use of FVI/FEMACS/FGMACS.
-
-Mon Jul 18 13:19:29 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(async): deleted.
- * var.c(global): call j_async() instead of using async global.
- * jobs.c(j_async,j_set_async()): new functions.
- * jobs.c(j_startjob): new function.
- * jobs.c(exchild,j_waitlast): call j_startjob() to start job.
- * jobs.c(j_sigchld): if any jobs aren't started, note signal
- occured and return without calling wait.
- * jobs.c(j_resume): allow un-reported dead jobs to be fg'd/bg'd;
- if backgrounding, set async job.
- * jobs.c(j_jobs,j_notify,j_waitj,check_job,remove_job): re-wrote to
- deal with posix `known processes'.
- * jobs.c(j_lookup()): if number specified, see if it is a lpid first,
- then check for pgrp.
- * jobs.c(new_job): added functionality of j_newjob().
- * jobs.c(j_newjob): deleted function and all calls.
-
- * tty.c(tty_init,tty_close): new functions which initialize
- tty_fd, tty_state and tty_devtty.
- * jobs.c(j_init,j_change): use tty_init()/tty_close(); changed
- references of ttyfd to tty_fd; moved tty_fd, tty_state and
- tty_devtty to tty.h; call tty_init() if !FMONITOR; save/restore
- tty modes on foreground job completion if FTALKING (was FMONITOR).
- * edit.h(X_chars): new structure for tty driver characters (replaces
- ed_erase, ed_kill, ed_werase, ed_intr, ed_quit); moved prototypes
- for emacs.c and vi.c from proto.h to edit.h; changed all references
- to ed_* to edchars.*.
- * edit.c(x_mode): use tty_state instead of cborig; re-initialize
- tty state from tty_state whenever entering xmode; save tty characters
- in edchars structure.
- * edit.c(x_init): now called from main(); initializes edchars, x_cols,
- and calls x_init_emacs.
- * emacs.c(x_init_emacs): changed erase,kill,werase,intr,quit arguments
- to X_chars argument.
-
-Fri Jul 15 10:35:13 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * io.c(restfd): only flush if fd is 2; use dup2() instead of
- fcntl(F_DUPFD) (2 system calls instead of 3).
-
- * ksh_wait.h(WEXITSTATUS): changed mask from 0x7f to 0xff.
-
- * tty.h: added TTY_state structure.
- * tty.c: new file - contains get_tty() and set_tty().
- * edit.c(x_init,x_mode): use get_tty() and set_tty().
- * jobs.c(j_waitj,j_resume): save/restore tty modes of stopped
- jobs, as per POSIX.1, B.2, job control; for foreground jobs,
- save tty state after successful completion, restore tty state
- after non-successful completion (signaled, non-0 exit, stopped).
-
- * misc.c(options): changed "alternations" to "braceexpand" (this
- is what bash uses - no need to invent new option names); changed
- ALTERNATIONS define to BRACEEXPAND, same for FALTERNATIONS to
- FBRACEEXPAND.
-
- * jobs.c(check_job): if process died of SIGINT or SIGPIPE, leave
- job state as PEXITED (not PSIGNALLED).
- * jobs.c(j_print): if printing short notice, ignore SIGPIPE the
- way SIGINT is ignored.
-
- * exec.c(comexec): flush shl_out after 'not found' message.
-
- * c_ksh(c_kill): re-wrote function (again) to handle posix
- options (-s, --, etc.) and posix -l output.
-
- * configure.in: added strcasecmp function check.
- * missing.c(strcasecmp): define strcasecmp function if not available.
- * trap.c(gettrap): use strcasecmp when comparing signal names.
-
- * var.c(global): expand $! to nothing if there haven't been any
- asynchronous processes started yet.
-
- * misc.c(options): added posix option (set automatically if
- POSIXLY_CORRECT env variable is set or if POSIXLY_CORRECT config
- define is defined)
- * var.c(special,setspec): added POSIXLY_CORRECT.
- * config.h.top: added POSIXLY_CORRECT define.
- * main.c(main): set FPOSIX if POSIXLY_CORRECT is defined.
- * POSIX: new file describing what the posix flag controls.
-
-Thu Jul 14 10:53:15 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * jobs.c,sh.h(killpg): moved killpg define to sh.h.
-
- * jobs.c(exchild): set async variable when starting background
- processes.
- * jobs.c(j_resume): print [job-num] before command when backgrounding;
- print to stdout instead of stderr.
- * c_ksh.c(c_fgbg): call builtin_getopt to skip possible --, complain
- about unknown options.
-
- * jobs.c(held_sigchld): new global variable.
- * jobs.c(j_sigchld): if any jobs aren't started, set held_sigchld and
- return.
- * jobs.c(exchild,waitlast): after setting JF_START, if held_sigchld
- set, call j_sigchld().
-
- * jobs.c(exchild): added/initialized ppid field to struct job; deleted
- global is_child.
- * jobs.c(waitfor): don't wait for a process that isn't a child of
- the current process.
- * jobs.c(j_exit): kill stopped jobs owned by current process only.
-
- * jobs.c(check_job): don't do monitor stuff for XXCOM jobs, but do
- set up notification.
- * jobs.c(j_waitj): added JW_NOTIFY flag to print job notification
- messages.
-
- * jobs.c(exchild): remove !XPIPEI condition - we now close pipe so
- pipeline doesn't have to call waitlast().
- * exec.c(execute): case TPIPE: no need to restore 0 or call waitlast()
- since exchild() handles everything.
-
- * jobs.c(remove_job): set last_job to 0 if we are removing it.
- * jobs.c(waitlast): check if last_job is 0.
-
- * jobs.c(struct job): combined started, waiting, interactive
- field into flags field; added JF_* flags; changed JW_NONOTIFY
- to JW_NOTIFY and changed all calls to j_waitj() to reverse
- this flag.
-
- * jobs.c(exchild): ignore SIGTSTP, TTIN, TTOU for `command` jobs.
-
-Wed Jul 13 09:28:34 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * main.c(main): when checking if FMONITOR set on command line,
- use 127 instead of -1 (signed vs unsigned char problem).
-
- * tree.h: renumbered, XEXEC, XFORK, ... and DOBLANK, DOGLOB, ...
- to use bits in order (instead of 0 5 2 4...).
- * jobs.c(j_init): don't set sigtrap[SIGCHLD].sig_dfl = 1 as a
- forked child may be a shell that needs to trap SIGCHLD.
-
- * tree.h(XPCLOSE,XCCLOSE): flags for close in parent, close in child.
- * jobs.c(exchild): added third argument - a file descriptor - if
- flags has XPCLOSE, close fd in parent, if flags has XCCLOSE, close
- in child.
- * exec.c(execute): pass input side of pipe to exchild() so it can
- be closed in the child.
-
-Tue Jul 12 10:21:57 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * main.c(main): let ignoresig() handle SIGTERM.
- * jobs.c(exchild): let restoresigs handle SIGTERM.
-
- * lex.c(yylex): don't parse array references inside double quotes
- (partial fix).
-
- * emacs.c(x_print): use shprintf instead of shellf so the output
- of bind can be redirected.
-
- * trap.c(deftraps): added SIGINFO (from jconklin@netcom.com).
-
-Fri Jul 8 09:37:51 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-4.9+mun.4 distribution
-
- * Makefine.in: added $(LDSTATIC) to LDFALGS to make static
- linking easier (suggested by sjg); use cp -p when creating
- distributions to preserve file dates.
- * configure.in: set LDSTATIC in Makefile if present in environ
- when configure is run.
-
- * sigact.c(sigsuspend): when calling 4.2bsd sigpause, pass *mask,
- not mask.
-
- * main.c(main): fixed up initialization of PWD (free memory, print
- more informative message).
-
- * misc.c(getcwd): range check backwards.
-
- * c_sh.c(setsig): set sa_flags/sa_mask.
-
- * edit.c(init_editmode),main.c,proto.h: deleted function - not needed
- since VISUAL/EDITOR are special.
-
- * lex.c(set_prompt),table.h: take out PS3.
-
- * c_sh.c(c_umask): handle multiple actions in symbolic mode clauses
- (eg, u+r-w); handle X (eg, o+X); ignore s (eg, u+s).
-
- * shf.c(shf_fillbuf): continue reading if we get an EINTR.
- * shf.c(shf_emptybuf,shf_write,shf_putchar): continue writing if we
- get an EINTR.
-
-Thu Jul 7 10:19:24 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sigaction,sigprocmask: changed NULL third argument to
- (struct sigaction *) 0.
- * sh.h(kshpid): changed type from int to pid_t.
- * proto.h(do_ulimit): removed do_ulimit() declaration.
- * vi.c(complete_word): removed unused variable pos.
- * syn.c(pipeline,elsepart): removed unused variable c.
- * jobs.c(exchild): deleted variable s (assigned but not used).
- * history(hist_init),shf.c(shf_gets): changed variable e to end
- because there is a global e.
- * exec.c(do_selectargs): removed secondarg argument; changed return
- (char *) 1 to (char *) 0; changed all calls.
-
- * io.c(canseek): use fd argument instead of 0.
-
- * lex.c(readhere): don't use fixed sized buffer (line).
-
- * expand.h: changed multi-statement macros to use do {..} while (0);
- changed temporary variable vp to vp__ to avoid lint complaints.
-
- * aclocal.m4(KSH_DUP2_CHECK): define F_GETFD/F_SETFD if not
- already defined.
-
- * etc/profile, etc/ksh.kshrc: replaced with new versions from
- Simon J. Gerraty (sjg@zen.void.oz.au).
-
-Wed Jul 6 10:09:55 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * jobs.c(killpg),configure.in: restored use of killpg() - some
- systems don't understand kill(-pgrp, signal) (ultrix 2.2);
- added test for killpg() in configure.in.
-
- * trap.c(inittraps): changed initialization of sigtraps - was
- using -1 in deftraps[] as end of table marker but some systems
- (eg, ultrix 2.2) define signals with -1 values (SIGPWR).
-
- * Makefile.in(mandir,install): fixed mandir value; added /
- in man installation; prefixed ksh.1 with $(srcdir).
-
- * jobs.c(j_init): Ignore failure of TIOCSETD.
-
- * misc.c(options[]): changed "vicomplete" to "vitabcomplete".
-
- * emacs.c(x_e_putc,x_e_puts,x_debug_info): x_e_putc()/x_e_puts() are
- the x_putc()/x_puts() functions from ksh4.9 edit.c (they got lost
- in the merge); same for x_debug_info(); changed x_e_putc/x_e_puts
- to call x_putc/x_puts.
-
-Mon Jul 4 09:29:05 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-4.9+mun.3 distribution
-
- * main.c(remove_temps): use unlink() instead of remove(); delete
- remove() define.
-
- * sh.h(func_heredocs, struct env): added func_heredocs for here
- documents in functions; added func_parse field to struct env
- - set when a function is being parsed.
- * lex.c(readhere): if e.func_parse, save temp file in func_heredocs.
- * syn.c(get_command): increment/decrement func_parse when parsing
- functions.
- * main.c(remove_temps,reclaim,leave): added remove_temps(); make
- reclaim() call remove_temps(); make leave() clean up function
- here documents.
-
- * aclocal.m4(KSH_TIMES_CHECK): new test - define TIMES_BROKEN
- if times() doesn't exist or if it always returns 0.
- * acconfig.h(TIMES_BROKEN): new define.
- * missing.c(ksh_times): new function.
- * ksh_times.h: new file.
- * c_sh.c,jobs.c: changed <sys/times.h> to "ksh_times.h"
- * c_sh.c,ksh_time.h(CLK_TCK): moved CLK_TCK define from c_sh.c
- to ksh_time.h (needed in missing.c).
-
- * syn.c(get_command): case TIME: don't call pipeline() with CONTIN
- flag.
-
- * c_sh.c(c_times): combined some printfs().
-
- * jobs.c(j_jobs,j_kill,j_resume,waitfor): block SIGCHLD before
- calling j_lookup() or looking at jobs list - avoids potential
- problems with remove_job() being called in signal handler.
-
-Sun Jul 3 11:09:01 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * exec.c(do_selectargs, selread, pr_menu): re-wrote do_selectargs to
- let c_read() to most of the work; deleted selread; make pr_menu
- calculate width/ncolumns each call so select can be used recursively.
-
- * configure.in, aclocal.m4(KSH_TERMIOS_H, KSH_TERM_CHECK): replaced
- KSH_TERMIOS_H with KSH_TERM_CHECK; removed calls to
- tcgetpgrp/tcsetpgrp - there is a seperate test for this.
-
- * main.c(main), sh.h: move getcwd() declaration to sh.h.
-
- * eval.c(expand,varsub): added XNULLSUB case to deal with "$@"
- (and "${foo[@]}") when $# (or ${#foo}) is 0.
-
- * eval.c(expand,varsub): removed free_me field - let reclaim() take
- care of it.
-
-Wed Mar 9 00:50:12 1994 Simon J. Gerraty (sjg@zen.void.oz.au)
-
- * var.c (setstr): don't set ALLOC flag if vp.s is NULL.
-
-Thu Jun 30 10:16:44 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_sh.c(c_read): ignore null characters; use builtin_getopt()
- instead of explicit parsing; removed -e option (neither at&t ksh
- nor POSIX have this); added -s option (put line in history, at&t ksh);
- if no variable specified, use REPLY (at&t ksh).
-
- * exec.c(do_selectargs): use Xstring macros to deal with saving
- input (was static, growing, buffers); flush shl_out after
- shellf().
-
- * vi.c(expand_word,complete_word): deleted call to free_edstate
- since already done by restore_edstate().
- * var.c(global): in 'if !letter(c)' block, deleted !c from
- 'if (!c || !n[1])' - don't know why it was added since it makes
- no difference to what is returned.
-
- * syn.c(dogroup): removed onlydone argument since it is only
- used in the while/until statements, where "while command; done"
- is not allowed anyway; Changed all calls.
-
- * misc.c(options[]): allow -i to be specified on the command
- line.
-
- * exec.c(iosetup): if stderr (fd 2) is being re-directed,
- re-open shl_out to clear any errors.
- * main.c(quitenv): if restoring fd 2, clear any write errors
- * io.c(initio): initialize shl_out, shl_spare for writing
- (was SHF_GETFL).
-
- * main.c(main): ignore SIGQUIT if talking.
-
-Wed Jun 29 11:11:34 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_sh.c(c_exit): removed jobs/really quit stuff - exit should
- always exit.
- * main.c(shell): made reallyquit a local variable.
- * sh.h(reallyquit): deleted reallyquit
-
- * exec.c(comexec), main.c(main), misc.c(change_flag), jobs.c:
- ifdef'd use of FMONITOR.
- * sh.h, misc.c: define FMONITOR option only if JOBS defined.
-
- * c_sh.c(c_wait): POSIXized: option parsing (of no options);
- return 0 if not given any arguments; deal with multiple arguments.
- * jobs.c(j_lookup): changed second argument to return an integer
- error code, added defines for error codes, added error message
- array; changed all calls to use new conventions.
- * jobs.c(waitfor): returns -1 if job not found; added argument
- to specify if notification messages should be suppressed.
- * jobs.c(j_waitj): added flags argument instead of intr argument;
- added JW_STOPPEDWAIT flag to wait for stopped jobs to complete;
- added JW_NONOTIFY flag to suppress notification of normal
- job termination.
-
-Tue Jun 28 16:13:10 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ksh.c(c_jobs): added -n and -p options, allow job ids to be
- specified for -l option.
- * jobs.c(j_jobs): added new arguments to deal with -n and -p options.
-
- * shf.h(SHF_BSIZE): reduced size to 512 to reduce memory requirements
- (I/O is used mostly for one line messages).
-
- * config.h.bot: removed necessity for tty process groups to define
- JOBS, added necessity of signal blocking/pausing.
-
-Mon Jun 27 21:49:52 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * jobs.c(exchild,j_print,j_waitj,j_jobs,check_job): exchild() - removed
- commented out shf_flush() calls; j_print() - print a space between
- status reports when lflag < 0, changed flag argument to use
- long/medium/short defines; Changed Job.notify field to use
- long/medium/short defines; j_waitj() - instead of calling j_print(),
- set j->notify to print the job; j_jobs() - clear j->notify so user
- won't be notified twice if a job finishes before a jobs command;
- check_job() - put job on front of list only if it is stopped.
-
- * main.c(main): pass flag to j_init() indicating if -m flag set/cleared
- on command line; don't initialize ttyfd.
- * sh.h: delete ttyfd.
- * jobs.c(j_init,ttyfd,check_job): made ttyfd static; re-worked j_init()
- to initialize ttyfd, initialize FMONITOR if not set by command line,
- initialize shl_j for asynchronous job notification;
- check_job() - use shl_j, look through saved fds to find real
- standard-error.
-
- * jobs.c(TTY_PGRP, ttypgrps_ok): modified conditions so job control
- is useful without tty process groups; added ttypgrps_ok flag that
- indicates if tty process groups should be set up; modifications so
- job control useful if ttypgrps_ok not set.
-
- * main.c(main): set FTALKING if 0 and 2 are tty as specified in POSIX
- (was 0 and 1).
-
- * misc.c(parse_args): do POSIX option processing for -A, -c and -o
- (allow -onoglob, -ctrue).
- * main.c(main): don't set up shl_stdout before/after parse_args() since
- lone -o on command line no longer accepted; remove code to allow
- -c with no options to read from stdin (at&t khs does this but POSIX
- requires an option to -c).
-
-Thu Jun 23 17:46:54 NDT 1994 John Rochester (jr@panda.cs.mun.ca)
-
- * trap.c(cleartraps): added special case for clearing trap 0 from
- ksh-4.9 sources.
-
-Thu Jun 23 10:17:03 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * misc.c(builtin_getopt): print error messages for unknown option,
- missing option; reset state if argv is 0.
- * c_ulimit.c(c_ulimit): let builtin_getopt() print error messages.
- * exec.c(call_builtin): call builtin_getopt() with 0 argv.
-
- * c_sh.c(c_unset): added -v option (POSIX); use builtin_getopt() to
- parse arguments; removed bogus comment about global() and special
- variables; don't allow read-only variables to be unset (POSIX).
-
- * var.c(unset, unsetspec): when unsetting a special variable, call
- unsetspec(); unsetspec() new function.
- * mail.c(mbset, mcheck): check that path is not 0 before calling stat
- (so mbset() can be called with 0 when MAIL is unset); deleted #if 0'd
- declarations of munset, mballoc and maddmsg.
-
- * misc.c(parse_args): pass argv+i+1 to set_array (not argv+i); when
- skipping arguments, leave i just before the NULL.
-
- * exec.c(echo): flush shl_out when done.
-
- * shf.c(shf_close): always used to return EOF.
-
- * trap.c(trapsig): skip error handlers when checking for PARSE or LOOP.
-
-Wed Jun 22 10:24:09 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * sh.h(C_IFSWS), misc.c(initctypes): added and initialized C_IFSWS
- (IFS white space).
- * c_sh.c(c_read): print continuation prompt if line ends in backslash;
- multiple non-white-space IFS chars delimit fields; strip trailing
- IFS-white-space from last variable; watch out for backslash followed
- by EOF.
- * eval.c(expand): only do field splitting on the results of
- parameter/command substition (POSIX, !v7-sh); multiple
- non-white-space IFS chars delimit fields.
-
- * eval.c(expand,alt_expand): removed NOALT tests since it could
- never be set; added return after call to alt_expand() in expand().
-
-Mon Jun 6 10:12:41 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * misc.c(setctypes, initctypes): setctypes - don't allow leading null
- in IFS (IFS="" could cause problems, 0 is already added);
- initctypes - don't use a leading null.
-
- * sh.h, eval.c: move definition of ifs0 from eval.c to sh.h; handle
- null ifs0.
- * var.c(setspec): set ifs0 to first character of IFS.
-
- * lex.c(yylex): when parsing ${..}, array references were not being
- null terminated.
-
-Fri Jun 3 12:28:06 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * var.c(export): changed to use memcpy() instead of loops.
-
- * eval.c(varsub, expand): check for #foo[@] in addition to #foo[*];
- handle ${foo[*]} and ${foo[@]} - added free_me field to struct Expand
- so pointer vector can get freed.
-
- * c_sh.c(c_dot), main.c(include): set up positional parameters if
- any are specified; Added argc,argv args to include(); changed all
- calls to include(); change include() to return 0 or 1 - caller
- can check exstat if desired; c_dot() should return 1 if can't open
- file (was -1).
-
- * c_sh.c(c_brkcont): warning message could call getn() with NULL - save
- original number and print it.
-
- * main.c(main): set $0 to first argument when -c used, ie,
- "sh -c cmd-string this-is-$0 argumernts..."
-
- * exec.c(iosetup): print "cannot open" if IOHERE fails.
-
- * io.c(errorf): set exstat to 1.
-
- * exec.c(search): assume mode is R_OK or X_OK (not 0/1 - 0 is F_OK, we
- want R_OK); changed all calls to pass R_OK/X_OK.
- sh.h: define R_OK,W_OK,X_OK,F_OK if not defined.
- eaccess(): changed all calls to use [RWXF]_OK.
-
- * sh.h(flag[], shell_flags[], Flag()): Renamed flag[] array to
- shell_flags[] to avoid conflicts with other uses of flag; Changed
- all references to flag[] to Flag(); defined Flag() to cast its arg
- to an int (for old pcc based C compilers).
-
- * vi.c(iswordch): use letnum() instead of isalnum || _.
-
- * misc.c(parse_args): call set_array() to deal with -A flag.
- * var.c(set_array): new function.
-
-
-Fri Jun 3 10:22:26 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * eval.c(substitute): afree(s).
-
- * var.c(global,local), sh.h: ARRAYMAX: new define - max index of an
- array; changed 511 constants to this; changed global() and local()
- to use array_ref_len() instead of arraysub().
-
- * expr.c(token): deleted unneeded arraysub() decl.
-
- * lex.c(arraysub), proto.h: made static, removed unused arguments,
- changed callers; removed prototype from proto.h.
-
- * ChangeLog: changed descriptions from func(file) to file(func).
-
-Wed Jun 1 09:17:50 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-4.9+mun.2 distribution
-
- * Makefile.in: added RCSFILES macro and rcs-ci target.
-
- * configure.in: add termio.h to the AC_HAVE_HEADERS() call.
-
- * sh.h, main.c, edit.c, misc.c: use EXTERN for aperm, x_cols,
- builtin_optind and builtin_optarg in sh.h, delete definitions
- in main.c, edit.c and misc.c.
-
- * io.c(maketemp): changed sizeof(PATH) to sizeof(path).
-
- * aclocal.m4(KSH_VOID,KSH_DUP2_CHECK): test that a void * variable
- can be used (Ultrix 2.2 compiler doesn't do this); added ifdef
- HAVE_FCNTL_H to dup2 test.
-
- * aclocal.m4, configure.in, sh.h, tree.c, io.c, shf.c: added
- new config test KSH_PROTOTYPES to check for function prototypes
- (MIPS RICS/os 5.0 C compiler isn't STDC and it can't mix <stddef.h>
- with <varargs.h>). Removed stdarg.h test (now redundent). Changed
- all varargs functions to use HAVE_PROTOTYPES instead of
- HAVE_STDARG_H && STDC.
-
- * eval.c(alt_scan): changed type of endc param from char to int to
- avoid problems with mixing prototype declarations and K&R
- definitions.
-
- * main.c(main), sh.h: added plain getcwd() decl to main(), removed
- ARGS() version from sh.h (some systems have getcwd() but don't
- declare it, some have getcwd() with a size_t arg 2, some have
- an int arg 2).
-
- * misc.c(memset,memmove): changed the second memset() to memmove().
-
- * c_sh.c(clocktos): changed #if CLK_TCK ... to if (CLK_TCK.. since
- CLK_TCK is not always defined to a number (may be a _sysconf())).
-
-Tue May 31 10:49:16 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * configure.in, Makefile.in: added code to set GCC_WARNFLAGS from
- $(srcdir)/Warn-flags if gcc is being used; Took -Wall, etc.
- out of CFLAGS, took -Dno_RCSids out of DEFS. Added install.sh to
- DISTFILES, grabbed copy of install.sh from autoconf (who grabbed
- it from X11R5).
-
- * io.c(errorf,shellf,shprintf),shf.c(shf_fprintf,shf_snprintf),
- tree.c(fptreef,snptreef): don't use ansi decls with old style
- varargs; changed ifdef __STDC__ to ifdef HAVE_STDARG_H.
-
- * jobs.c(j_init): changed getpgrp() call to getpgID(), defined getpgID()
- appropriately for BSD vs POSIX/SYSV getpgrp.
-
- * expand.h, ksh_dir.h, ksh_stat.h, ksh_time.h, ksh_wait.h, shf.h,
- tty.h: added RCS $Id: ChangeLog.0,v 1.1 1996/08/14 06:19:10 downsj Exp $'s.
-
- * acconfig.h: updated SIGSET_T comment: unisgned int -> unsigned.
-
- * aclocal.m4(KSH_CLOCK_T,KSH_TIME_T,KSH_SIGSET_T): make sure
- type is a word (same fix as was done for more_t, et.al.).
-
- * aclocal.m4(KSH_VOLATILE): check that the compiler can deal with
- volatile pointers (dec/pmax ultrix 4.2 compiler can't).
-
- * misc.c(parse_args): added skelatal code for dealing with -A.
-
- * var.c,proto.h(skip_varname): new function; deleted isassign()
- function, which is no longer called. Changed typeset(var.c)
- to use skip_varname().
-
- * var.c(strint): fail if base is not in the range 2..36; set variable
- base according to first base seen; generate an error if a non-alnum
- char is seen (1^A was the same as 11).
-
- * var.c(strval): for integer variables, output base if != 10.
-
- * sh.h: fixed typo in x_cols define (#defined -> #define).
-
-Fri May 27 16:49:29 NDT 1994 Micharl Rendell (michael@panda.cs.mun.ca)
-
- * made pdksh-4.9+mun.1 distribution
-
- * finished autoconf'ing source code.
-
-Fri May 20 16:47:06 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * c_ulimit.c(c_ulimit) (was do_ulimit.c(do_ulimit)): major rework;
- deal with combinations of getrusage and ulimit, use options at&t
- ksh uses (-SHa..).
- * misc.c(builtin_getopt): yet another getopt routine for builtin
- commands
- * misc.c(parse_args), c_sh.c(c_set), main.c(main): custom option
- parsing routine for command line/set options. Lots of changes
- to main() to incorporate this (easier to follow).
- * c_test.c(c_test): added -e (file exists) test.
-
-Fri May 5 12:16:46 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
- * numerous changes from old Notes.4-9 file:
- - c_ksh.c:
- - calls to errorf identify what function the error is in
- (eg, errorf("print: bad -u option");)
- - added array stuff (lots of places)
- - table.c
- - lex.c
- - var.c: +arraysearch(), +basename()
- - c_sh.c(c_exit), main.c(shell), sh.h:
- - added reallyquit flag to deal with stopped jobs at exit time;
- only two exit commands (or eofs) in a row will work. in
- shell(), set exstat from execute value.
- - c_ksh.c(c_print):
- - handle \\ at end of string better (don't skip the null)
- - c_ksh.c(c_whence):
- - stop looking as soon as we get a failure
- - pass flag[FTRACKALL] to findcom() instead of 0
- - c_ksh.c(c_alias):
- - print '%s alias not found' if not found
- - c_ksh.c(c_jobs):
- - handle -l option (list pid)
- - c_ksh.c(c_kill):
- - two column -l output to try to keep it on one screen
- - c_sh.c(c_read):
- - skip IFS at start of line "echo ' a b' |(read a b; echo $a)"
- should print a, not nothing.
- - changed EOF check to set all vars to null (same way \n is
- handled)
- - eval.c(comsub):
- - after compile(), return if t is NULL
- - use setfileno() instead of fileno(x) = .. (see sh.h changes);
- - exec.c(iosetup):
- - set exstat if redirect fails
- - exec.c(fd_clexec):
- - check that fd >= 0
- - exec.c:
- - change SHARPBANG ifdef code - everyone uses scriptexec().
- ifdef is put around open/read/parse code in scriptexec().
- [code cleanup]
- - exec.c(search):
- - eaccess test out side of loop: must be regular file to exec it
- (like test in loop)
- - eval.c(expand):
- - added while getc() == 0 in XCOM
- [a null in the output of a file would be treated as eof and
- waitlast would not be called]
- - eval.c(trimsub):
- - '%' subst: use ATEMP, not APERM
- - eval.c(tilde): use Xinit et. al., instead of fixed length buffer
- - getopts.c(getopt): rename getopt() to ksh_getopt() to avoid
- problems with prototypes in system #include files.
- - io.c(fopenshf):
- - call clearerr(fd) if already open
- - use F_GETFL to determine appropriate mode for fdopen() call
- instead of opening everything for read/write
- - use ifdef _FSTDIO instead of ifdef _BSDI (_FSTDIO is used in
- 4.4bsd, NetBSD, FreeBSD and other non BSDI environs)
- - lex.c(ungetsc): don't decrement if str == null, remove nullstr hack
- - lex.c(yylex):
- - \ at eol: call Xfree before goto Again
- - use memset() to clear ident, instead of while loop
- - syn.c(get_command): renamed from command() to get_command() to
- avoid conflicts with command(main.c).
- - sym.c(get_command):
- - allow A=B <alias-name> to work (alias was not being expanded)
- - allow `if .. if .. fi fi' to work (no ; after group terminator
- (fi , esac, done, ), })
- - allow `alias FI=fi ; if .. if .. fi FI' to work (alias
- expansion after group terminator)
- - do not assume resize returns same pointer
- - tree.c(pioact):
- - handle IORDWR case
- - added leading quote for file in IOHERE case
- - var.c(special):
- - add MAILCHECK check
- - var.c(setspec):
- - add MAILCHECK case (doesn't do anything yet)
- - var.c(strint):
- - handle null vp->val.s
- - eval.c(sh.h, expand), misc.c(options[]):
- - enable alternations only if alternations flag set
- (set -o alternations). This is so (att ksh) scripts that don't
- expect alternations won't break.
- - added notify option (asynchronous job completion notification)
- - added vicomplete to enable tab char as file name completion
- char in vi (this is likely to go away - exits for historical
- reasons)
- - jobs.c, main.c, sh.c, trap.c:
- - define/use SIG_HDLR instead of void
- - eval.c(expand): alt_expand() does not return a value so don't test
- it, just return. Also changed decl of alt_expand() to reflect
- reality.
- - emacs.c(x_emacs): first return returns random value (i); change to
- return 0. Also changed the way interrupts are returned to called
- (return -2 means interrupt).
- - c_sh.c(c_brkcont): at&t ksh allows breaks/continues outside of
- loops, 4.9 prints an error and breaks out of all env's (if, case,
- etc.). Fixed to act like at&t (ie, allow bogus continues), except
- a warning message is printed. (Some HP-UX shell scripts actually
- have continues outside of loops...)
- - main.c(shell): parameter s should be volatile as it is used after a
- setjmp.
- - edit.c(promptlen): handle tabs, backspaces...
- - cleaner fix to the ^C/source->line problem: in pprompt(lex.c),
- convert ! to source->line+1 (same in promptlen(edit.c)), increment
- source->line after a (non-empty, non-eof) line has been read
- (before call to histsave()). To be pedantic, also adjust
- position of source->line++ in SHIST in case PS9 is ever used.
- Remove code in shell(main.c) that does the source->line--,
- remove the source->line-- for eof and empty line in from
- getsc_(lex.c).
- - trap.c(sigtrap[]): do not depend on signal number matching position
- in initialization array. Use second table in which order does not
- matter to initialize sigtrap[] array. Easier to read/port, and
- generally less fragile. requires call to inittraps() in main.c.
- - trap.c(cleartraps): need to clear Sigact flags/mask after use
- (actually, declare a local struct sigact and use that instead of
- Sigact)
- - exec.c(execute): case TSELECT: no USE_SIGACT code for call to
- signal(); case TPIPE: don't call waitlast() if XXCOM since
- waitlast() will be called in expand(); 4.9 code that set and
- then cleared the XEXEC flag in the TPIPE case not added since
- it was ifdef'd out, also the code to not exit if XPIPEI flag
- set was not added; 4.9 XXWHL flag not added (don't flush stdin
- if in a while loop) since this problem fixed (I hope) by shf stuff.
- - ttyfd{sh.h/lex.c}: use EXTERN/_I_ to initialize ttyfd. Remove from
- lex.c
- - interrupted reads: instead of testing sigchld_caught after reads
- fail, continue them if errno == EINTR.
- - edit.c(x_getc): check for EINTR, and continue reading if so.
- - lex.c(getsc_): check for EINTR, and continue reading if so.
- (don't check return of x_read() - check has already been done)
- - exec.c(selread): check for EINTR, and continue reading if so.
- - history changes:
- - history.c:
- - histrpl(): bounds check doesn't take global flag into
- account - move check into loop and past loop.
- - c_fc(): if pattern is the empty string, histrpl()
- goes into infinate loop. Start searching for = after first
- char (this is what at&t ksh seems to do).
- - c_fc(): `fc -l first' should list at most 16
- commands according to at&t manual.
- - findhist(): re-wrote: shorter, easier to follow. Now
- returns an int. (used only by vi code)
- - use COMPLEX_HISTORY's allocated history array in
- EASY_HISTORY: common init_histvec(), sethistfile() and
- sethistsize() functions.
- In the process, hist_open() went away. Use histsize
- instead of HISTORY in hist_init() and hist_finish()
- #ifdefs in lex.h, table.h,
- var.c disappear, history variable definitions in lex.c
- disappear.
- - hist_init(COMPLEX_HISTORY): move hstarted = 1 to after the
- FTALKING test.
- - hist_finish(): don't open hname if its null
- - histrpl(): made static, use ARGS in decl
- - made current and curpos static
- - changes to allow embedded newlines in commands:
- - histsave(): trash only trailing newline
- - hist_init(): read in null terminated lines instead of
- newline terminated
- - hist_finish(): write null terminated lines
- - make multiple line command appear in single history line
- (EASY_HISTORY only):
- - added histappend() to append new command to last
- command
- - added call to histappend() in getsc_(lex.c) (also: only
- adjust source->line if not multiline).
- - lex.h:
- - remove second decl of history if !EASY_HISTORY
- - tree.c(ptree): case TCOM: check if t->vars or t->args is 0
- - vi.c(x_vi): ^D anywhere in command line is eof ($ foobar^D exits).
- at&t ksh ignores ^D in middle of line
- - edit.c:
- - don't need to include string.h - included in stdh.h
- - init_editmode(): in at&t ksh, VISUAL takes precenence over
- EDITOR, so put it first. Also, at&t ksh doesn't use FCEDIT so
- trash it.
- - moved initialization of ed_* from x_read() to x_init() since
- thats where they are set from tty structs.
- - x_init(): set ed_intrc, ed_quitc for _BSD & _POSIX_TERM ifdefs
- - send output to shlout (instead of stdout - at&t ksh writes to
- stderr)
- - made x_do_init static.
- - exit.c(x_getc), lex.c(yylex): restart interrupted reads in
- x_getc(), changed read-restart in yylex() to only effect call
- to read().
- - syn.c(thenpart): then THEN is not optional - generate a syntax
- error if no THEN. (ie, `if true ; fi' is not legal).
- - syn.c(get_command): don't accept keywords after re-directory (eg,
- `> /dev/null if true ; then echo hi ; fi' is not legal).
- - vi.c: handle \ and ^[ in command mode ala at&t ksh (filename
- completion)
- - syn.c(thenpart), syn.c(elsepart): calling token(0) when they want a
- keyword (always worked 'cause tpeek() is always called before, with
- the keyword flag). Fix: call token(KEYWORD|ALIAS) (at&t ksh does
- alias expansion here). Question: pass CONTIN as well?
- - syn.c(get_command): LWORD/MPAREN case: do alias expansion when
- getting open brace ({). CASE case: ditto for `in' and `esac'.
- IF case: ditto for `fi'. FUNCTION case: dito for open brace ({).
- - syn.c(dogroup): alias expansion when getting `do' and `done'.
- - syn.c(wordlist): alias expansion when getting `in'.
- - syn.c(nested): alias expansion when getting `)', `}'
- - syn.c(casepart): alias expansion when getting `esac' or `;;'.
- Also removed use of cf variable - it does nothing.
- - eval.c(expand): case CSUBST: '#'/'%' - increment st so nested
- substitutions work.
- - var.c(typeset): INTEGER && no assignment: memory was being freed
- and then used (there was even a comment saying it was being
- done...)
- - lex.c, lex.h, exec.c, main.c:
- added shf_{open,fdopen,close,gets}() routines so stdio wasn't
- used. When reading a command file under osf/1, stdio would
- mess up the read pointer when a child exited: the exit flushed
- all open files and flushing a file open for reading changes the
- current read position (does a seek to where the next char would
- be read). This position is then used by the parent process,
- who thinks the read position is still at the end of the buffer
- it read.
- - c_sh.c:
- use shf_*() routines avoids two bugs in read:
- - on sunos 4.1.3, a read would gobble up a stdio buffer and
- never put it back (ie, lseek backwards). Neither a
- fflush() nor a fseek(x, 0L, 1) fixed the problem.
- (see Bug 26)
- - on linux, stdio knows its current offset and seeks there
- before reading a buffer. This causes grief when the shell
- replaces file descriptors behind stdio's back (ie, all the
- time).
- $ read x << EOF
- hi
- EOF
- $ cat > /dev/tty << EOF
- 1:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
- 2:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
- 3:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
- EOF
- $
- the cat picks up reading at the offset where the read
- command left off (ie, at bcdefg... - the 1:a are skipped).
- - exec.c(comexec): built-in c_exec && no args: close the saved fd's
- (were thrown away). Also, set close-on-exec flag for fd's > 2,
- as per at&t manual.
- - lex.c(yylex): only accept 1 digit before a redirection (eg, 1> is
- ok, 1abc> is not)
- - exec.c(iosetup): only accept 1 digit after a dup-redirection
- (eg, >&1 is ok, >&1abc is not)
- - exec.c(iosetup): use O_APPEND flag for >> redirections; use O_CREAT
- flag for <> redirections. (re-organized to accumulate open() flags
- and do one open() call); changed error message to know about dup
- failing.
- - c_sh.c(c_umask): umask should have leading 0 - doesn't when umask
- has 3 digits (eg, `umask 222; umask' prints 222 instead of 0222)
- - c_sh.c(setsig): declare local struct sigaction and use it so
- sa_flags doesn't have to be cleared (also to try to keep away from
- global vars).
- - main.c(main):
- - don't go set TALKING if name starts with -.
- - read $HOME/.profile (not .profile)
- - main.c(main): re-wrote option parsing code
- - edit.c(init_editmode): don't check FCEDIT
- - if set -o vi/emacs/gmacs on command line, don't set edit mode from
- FCEDIT/EDITOR/etc.
- - var.c(setspec): FCEDIT should not magicly change edit mode; VISUAL
- and EDITOR should (EDITOR only if VISUAL is not set)
- - changed noclobber char from ! to | (this is what at&t ksh uses)
- - exec.c(iosetup): use O_EXCL flag if FNOCLOBBER set and >| not used
- - c_sh.c(c_set): don't clear FERREXIT if FTALKING is set; although
- some ksh manuals say -e is ignored for interactive shells, they
- all seem to honour the -e flag for interactive shells.
- - vi.c: reset history position to the end after a line is modified
- - `(( 1 + 2 ))' no longer prints `+: bad expression'!
- - lex.c(yylex): added parenthesis counting so `(( ((1+2)) ))' no
- longer generates a syntax error
- - expr.c(intvar): if strint() fails, give bad number error
- (`let 1+foo' should fail)
- - `echo hi 1abc123> /dev/tty' no longer interpreted as
- `echo hi 1> /dev/tty' (is `echo hi 1abc123 > /dev/tty')
- - `echo hi 1<> /tmp/does-not-exist' now works (used to say cannot
- open)
- - c_sh.c(c_umask): umask now takes symbolic arguments (g-r, +w, etc.)
- - c_ksh.c(c_whence): pass flag[FTRACKALL] to findcom() instead of 1.
- - `echo hi >< bar' now produces an error
- - jobs.c(j_lookup): now checks for ambiguous job specifications;
- callers now get an error message.
- - c_ksh.c(c_fgbg): multiple jobs can be specified
- - emacs.c(x_transpose): move past transposed chars like (gnu) emacs
- does
- - main.c(main): don't copy initcoms (messes up memory allocated for
- shf_iob[] in initio(), should not be necessary)
- - main.c(main), var.c(import), var.c(typeset), c_ksh.c(c_alias),
- expr.c(token), misc.c(strnsave): added strnsave() function; use it
- instead of writing nulls in the middle of strings; main() no longer
- copies startup commands before executing them.
- - vi.c: wbuf[] no longer a fixed size (was hard coded to 80 chars).
- - alloc.c(aresize): if passed a null pointer, don't free it
- - expand.h: restored usage description and NOTE from previous version
- - alloc.c, table.h, table.c:
- - changed struct fields named `free' to nfree (struct table) and
- freelist (struct Block) to allow memory debugging
- (involves #defining free)
- - main.c(main): smart initialization of PWD (ensures it is always
- valid).
- - lex.h, table.h, tree.h: removed redundent function declarations
- (were also in proto.h)
- - sh.h: increased LINE from 256 to 1024
- - main.c(include), sh.h(E_INC), c_sh.c(c_return): added hack so a
- return in a included file returns to the includer instead of
- exiting the shell. Very useful in $ENV scripts and profiles,
- eg, so the whole script does not have to be parsed for
- non-interactive shells.
- This is not compatible with the at&t ksh, whose man page says
- return is the same as exit outside of functions. May be modified
- in the future. (note that at&t ksh parses a .'ed file before
- executing anything, so a premature return would not speed its
- parsing, which is why the return hack was added to pdksh)
- - exec.c(iosetup): don't save fd if already saved (and don't
- generate an error)
- - exec.c(findcom): in if (..ALLOC && eaccess), test for
- ALLOC redundent - always call afree()
diff --git a/bin/pdksh/IAFA-PACKAGE b/bin/pdksh/IAFA-PACKAGE
deleted file mode 100644
index 879682c0a61..00000000000
--- a/bin/pdksh/IAFA-PACKAGE
+++ /dev/null
@@ -1,17 +0,0 @@
-$OpenBSD: IAFA-PACKAGE,v 1.5 1996/11/21 07:59:25 downsj Exp $
-
-Title: pdksh
-Version: 5.2.12
-Description: A public domain implementation of the Korn shell (ksh88),
- a UNIX command line interpreter / scripting language; the few
- missing ksh features are being added and the shell is being
- POSIXized.
-Author: (Eric Gisin), (Charles Forsyth), (John R MacMillan),
- sjg@zen.void.oz.au (Simon J. Gerraty),
- michael@cs.mun.ca (Michael Rendell), (plus many others)
-Maintained-by: michael@cs.mun.ca (Michael Rendell)
-Maintained-at: ftp://ftp.cs.mun.ca:/pub/pdksh/
-Platforms: Written in C, runs on most UNIX boxes (uses GNU autoconf;
- works best in a POSIX or BSD environment). Also runs on OS/2.
-Copying-Policy: Freely Redistributable (mostly public domain, some copyrighted)
-Keywords: pdksh, ksh, Korn, shell, command line interpreter
diff --git a/bin/pdksh/INSTALL b/bin/pdksh/INSTALL
deleted file mode 100644
index afd11fa04cb..00000000000
--- a/bin/pdksh/INSTALL
+++ /dev/null
@@ -1,151 +0,0 @@
-$OpenBSD: INSTALL,v 1.1 1996/08/14 06:19:10 downsj Exp $
-
-[This file is the generic GNU autoconf/configure installation description,
- see the README for pdksh specific configuration/installation information]
-
- This is a generic INSTALL file for utilities distributions.
-If this package does not come with, e.g., installable documentation or
-data files, please ignore the references to them below.
-
- The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation, and
-creates the Makefile(s) (one in each subdirectory of the source
-directory). In some packages it creates a C header file containing
-system-dependent definitions. It also creates a file `config.status'
-that you can run in the future to recreate the current configuration.
-
-To compile this package:
-
-1. Configure the package for your system.
-
- Normally, you just `cd' to the directory containing the package's
-source code and type `./configure'. If you're using `csh' on an old
-version of System V, you might need to type `sh configure' instead to
-prevent `csh' from trying to execute `configure' itself.
-
- Running `configure' takes awhile. While it is running, it
-prints some messages that tell what it is doing. If you don't want to
-see any messages, run `configure' with its standard output redirected
-to `/dev/null'; for example, `./configure >/dev/null'.
-
- To compile the package in a different directory from the one
-containing the source code, you must use a version of `make' that
-supports the `VPATH' variable, such as GNU `make'. `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script. `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'. If
-for some reason `configure' is not in the source code directory that
-you are configuring, then it will report that it can't find the source
-code. In that case, run `configure' with the option `--srcdir=DIR',
-where DIR is the directory that contains the source code.
-
- By default, `make install' will install the package's files in
-`/usr/local/bin', `/usr/local/man', etc. You can specify an
-installation prefix other than `/usr/local' by giving `configure' the
-option `--prefix=PATH'. Alternately, you can do so by consistently
-giving a value for the `prefix' variable when you run `make', e.g.,
- make prefix=/usr/gnu
- make prefix=/usr/gnu install
-
- You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files. If you
-give `configure' the option `--exec-prefix=PATH' or set the `make'
-variable `exec_prefix' to PATH, the package will use PATH as the prefix
-for installing programs and libraries. Data files and documentation
-will still use the regular prefix. Normally, all files are installed
-using the same prefix.
-
- Some packages pay attention to `--with-PACKAGE' options to
-`configure', where PACKAGE is something like `gnu-as' or `x' (for the
-X Window System). They may also pay attention to `--enable-FEATURE'
-options, where FEATURE indicates an optional part of the package. The
-README should mention any `--with-' and `--enable-' options that the
-package recognizes.
-
- `configure' also recognizes the following options:
-
-`--help'
- Print a summary of the options to `configure', and exit.
-
-`--quiet'
-`--silent'
- Do not print messages saying which checks are being made.
-
-`--verbose'
- Print the results of the checks.
-
-`--version'
- Print the version of Autoconf used to generate the `configure'
- script, and exit.
-
-`--x-includes=DIR'
- X include files are in DIR.
-
-`--x-libraries=DIR'
- X library files are in DIR.
-
- `configure' also accepts and ignores some other options.
-
- On systems that require unusual options for compilation or linking
-that the package's `configure' script does not know about, you can give
-`configure' initial values for variables by setting them in the
-environment. In Bourne-compatible shells, you can do that on the
-command line like this:
-
- CC='gcc -traditional' LIBS=-lposix ./configure
-
-On systems that have the `env' program, you can do it like this:
-
- env CC='gcc -traditional' LIBS=-lposix ./configure
-
- Here are the `make' variables that you might want to override with
-environment variables when running `configure'.
-
- For these variables, any value given in the environment overrides the
-value that `configure' would choose:
-
- - Variable: CC
- C compiler program. The default is `cc'.
-
- - Variable: INSTALL
- Program to use to install files. The default is `install' if you
- have it, `cp' otherwise.
-
- For these variables, any value given in the environment is added to
-the value that `configure' chooses:
-
- - Variable: DEFS
- Configuration options, in the form `-Dfoo -Dbar...'. Do not use
- this variable in packages that create a configuration header file.
-
- - Variable: LIBS
- Libraries to link with, in the form `-lfoo -lbar...'.
-
- If you need to do unusual things to compile the package, we encourage
-you to figure out how `configure' could check whether to do them, and
-mail diffs or instructions to the address given in the README so we
-can include them in the next release.
-
-2. Type `make' to compile the package. If you want, you can override
-the `make' variables CFLAGS and LDFLAGS like this:
-
- make CFLAGS=-O2 LDFLAGS=-s
-
-3. If the package comes with self-tests and you want to run them,
-type `make check'. If you're not sure whether there are any, try it;
-if `make' responds with something like
- make: *** No way to make target `check'. Stop.
-then the package does not come with self-tests.
-
-4. Type `make install' to install programs, data files, and
-documentation.
-
-5. You can remove the program binaries and object files from the
-source directory by typing `make clean'. To also remove the
-Makefile(s), the header file containing system-dependent definitions
-(if the package uses one), and `config.status' (all the files that
-`configure' created), type `make distclean'.
-
- The file `configure.in' is used to create `configure' by a program
-called `autoconf'. You only need it if you want to regenerate
-`configure' using a newer version of `autoconf'.
diff --git a/bin/pdksh/LEGAL b/bin/pdksh/LEGAL
deleted file mode 100644
index 78dd76f95dc..00000000000
--- a/bin/pdksh/LEGAL
+++ /dev/null
@@ -1,36 +0,0 @@
-$OpenBSD: LEGAL,v 1.1 1996/08/14 06:19:10 downsj Exp $
-
-pdksh is provided AS IS, with NO WARRANTY, either expressed or implied.
-
-The vast majority of the code that makes pdksh is in the public domain.
-The exceptions are:
- sigact.c and sigact.h
- These are covered by copyrighten by Simon J. Gerraty;
- the copyright notice for these files is as follows:
- This is free software. It comes with NO WARRANTY.
- Permission to use, modify and distribute this source code
- is granted subject to the following conditions.
- 1/ that that the above copyright notice and this notice
- are preserved in all copies and that due credit be given
- to the author.
- 2/ that any changes to this code are clearly commented
- as such so that the author does get blamed for bugs
- other than his own.
- aclocal.m4
- This is covered by the GNU General Public Licence (GPL)
- as it contains modified versions of macros that come with
- GNU autoconf. As this is used solely for configuration,
- the pdksh code itself is not covered by the GPL.
- The following is taken from autoconf 2.x documentation
- (info autoconf questions distributing) concerning use
- of autoconf in programs:
-
- There are no restrictions on how the configuration
- scripts that Autoconf produces may be distributed
- or used. In Autoconf version 1, they were covered by
- the GNU General Public License. We still encourage
- software authors to distribute their work under terms
- like those of the GPL, but doing so is not required
- to use Autoconf.
-
-That's it. Short and simple.
diff --git a/bin/pdksh/Makefile b/bin/pdksh/Makefile
deleted file mode 100644
index 85145ad30ed..00000000000
--- a/bin/pdksh/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-# $OpenBSD: Makefile,v 1.8 1996/11/30 23:54:36 downsj Exp $
-
-PROG= ksh
-SRCS= alloc.c c_ksh.c c_sh.c c_test.c c_ulimit.c edit.c emacs.c \
- eval.c exec.c expr.c history.c io.c jobs.c lex.c mail.c \
- main.c misc.c missing.c path.c shf.c syn.c table.c trap.c \
- tree.c tty.c var.c version.c vi.c
-
-DEFS= -DHAVE_CONFIG_H
-CFLAGS+=${DEFS} -I. -I${.CURDIR} -DKSH
-MAN= ksh.1 sh.1
-
-CLEANFILES+= siglist.out emacs.out
-
-LINKS= ${BINDIR}/ksh ${BINDIR}/rksh
-LINKS+= ${BINDIR}/ksh ${BINDIR}/sh
-MLINKS= ksh.1 rksh.1
-
-.depend trap.o: siglist.out
-.depend emacs.o: emacs.out
-
-siglist.out: config.h sh.h siglist.in siglist.sh
- /bin/sh ${.CURDIR}/siglist.sh \
- "${CPP} ${CPPFLAGS} ${DEFS} -I${.CURDIR}" \
- < ${.CURDIR}/siglist.in > siglist.out
-
-emacs.out: emacs.c
- /bin/sh ${.CURDIR}/emacs-gen.sh ${.CURDIR}/emacs.c > emacs.out
-
-.include <bsd.prog.mk>
diff --git a/bin/pdksh/NEWS b/bin/pdksh/NEWS
deleted file mode 100644
index f1115015719..00000000000
--- a/bin/pdksh/NEWS
+++ /dev/null
@@ -1,603 +0,0 @@
-$OpenBSD: NEWS,v 1.5 1996/11/21 07:59:26 downsj Exp $
-
-Version 5.2.12
-
-* bug fixes
- * editing: shell recognizes window resizes on Dec alphas (config problem).
- * alias: no longer dumps core if alias is in a command substitution.
- * alias: everything after ;\n or \n\n was ignored in aliases.
- * exec: temp files used by here docs in functions now cleaned up on exec.
- * possible core dump when cleaning up environment fixed.
- * vi: set -o vi-show8 now does what it was supposed to do (cat -v like).
- * job control: process group synchronization (needed on systems with
- broken setpgrp()) now works when the pipeline contains built in commands.
- * vi: if set -o vi-tabcomplete, tab works in command mode as well.
- * set/typeset: unset parameters are only reported if they have attributes.
-
-
-Version 5.2.11
-
-* bug fixes
- * aliases: expansion was reading an extra character (bug added in 5.2.10).
-
-
-Version 5.2.10
-
-* bug fixes
- * parsing: handling of backslash-newline fixed (esp. in here documents).
- * read: prints prompt if non-interactive and input is a tty.
-
-
-Version 5.2.9
-
-* bug fixes
- * config: using LDSTATIC no longer generates config error.
- * config: can compile as sh again (--enable-shell=sh).
- * config: should compile on machines with broken "gcc -g"
- * config: fixed test for broken S_IFIFO.
- * config: fixed test for getwd() routine.
- * config: better NeXT support (signal list generated correctly, clock_t
- type detected, enable job control in rlogin sessions)
- * parsing: assignments containing brackets ([]) not treated as commands.
- * editing: terminal column width determined correctly on startup.
- * vi: long prompts truncated (more or less) correctly.
- * file completion: files of the form ~user (no /'s) expanded correctly.
-
-* at&t ksh method for delimiting hidden characters in prompt added (i.e.,
- start prompt with non-printing char and \r, use char to delimit esc codes).
-
-
-Version 5.2.8
-
-* bug fixes
- * configuration: handle FreeBSD's strange S_ISSOCK.
- * test: added == operator.
- * configuration: fixed opendir/dirent usage.
- * redirections before subshells handled correctly.
- * COLUMNS/LINES are no longer exported when they are automatically set.
- * mail checks and PS1/PS4 expansions removed if compiled as sh.
- * subcommands in PS1 no longer generate bogus warning messages.
- * environment variables not longer messed up on 16-bit machines.
- * unset: now returns non-zero if variable/function isn't set.
- * select: only prints menu first time, if REPLY is null or on blank line.
- * check for `cannot execute' improved, error message says why.
- * typeset: now reports variables with attributes but now value.
- * vi/emacs file completion: does directory listing on zero length names.
- * arithmetic: non-numeric parameters expanded recursively.
- * arithmetic: identifiers in unevaluated part of ?:,&&,|| parsed correctly.
- * functions: unsetting a function within itself is now safe.
- * arrays: unsetting element 0 of an array no longer kills the whole array.
- * co-processes now behave like ksh93 co-processes (and less like ksh88).
-
-* functions declared with "function foo" are treated differently (from those
- declared with "foo()"): $0 is (not) set to the function name, assignments
- before function calls aren't (are) kept in the parent shell.
-
-* vi: added vi-esccomplete option for people who want ESC-ESC completion.
-
-* vi/emacs: now notice window size changes (but not while editing a line).
-
-* emacs: <esc># now does the comment/uncomment thing.
-
-* arithmetic: ++, -- and , added.
-
-
-Version 5.2.7
-
-* bug fixes
- * vi: commands can be longer that 16 chars...
-
-
-Version 5.2.6
-
-* bug fixes
- * break/continue: if too big a number is given, last enclosing loop is used.
- * set: set +o now generates a set command that can be saved and executed.
- * COLUMNS/LINES are now exported when they are automatically set.
- * emacs: completion: space not added after directory names.
- * vi: # command inserts # after each newline; # on commented line
- undoes the commenting.
- * some regression tests made less sensitive to their environment.
- * should compile on os/2 again.
-
-
-Version 5.2.5
-
-* bug fixes
- * configuration: if sig_setjmp() being used, use sigjmp_buf.
- * configuration: test for times() fixed.
- * configuration: ANSI usage of setjmp() and offsetof().
- * echo/print: octal number in \ sequence must start with a 0.
- * echo: don't treat a lone minus as an option.
- * typeset -f: correctly prints functions with select statements.
- * vi: / with no pattern repeats last search.
- * vi: repeat counts no longer effect file completion/expansion.
- * vi: tab-completion now also works in command mode.
- * emacs/vi: ^O key now read as ^O on suns/alphas (was eaten by tty driver).
- * emacs: now has file expansion (^[*).
- * emacs: ^O goes to next command, not next next command.
- * COLUMNS/LINES: environment variables now set on start up.
- * variables: command line assignments can't change readonly variables.
- * arithmetic: giving multiple bases (5#4#3) no longer allowed.
- * arithmetic: when assigning a non-integer variables, base no longer shown.
- * history: fixed replacement bug introduced in last release.
- * history: -1 refers to the previous command, not current fc command.
- * parsing: correctly handles command substitutions starting with a newline.
-
-* full command completion added (both vi and emacs).
-
-
-Version 5.2.4
-
-* bug fixes
- * PS1 imported from environment again.
- * vi handles prompts with embedded newlines.
- * errors redirecting stderr aren't lost.
- * redirection errors for <&n no longer reported as to >&n.
- * don't do globbing on re-direction targets if not interactive (POSIX).
- * pattern matching in [[ foo = foo*bar ]] now works again.
- * HUP signals are passed on to jobs running in the foreground.
- * $? now valid (ie, not 0) in trap handlers, `...` expressions, etc.
- * noclobber doesn't effect redirections to non-regular files (eg, /dev/null)
- * \newline in here-document delimiters handled correctly.
- * typeset -f now reports unloaded autoload functions properly.
- * ~,~+,~- are not expanded if HOME,PWD,OLDPWD are unset.
- * vi completion/expansion: * not appeded if word contains $.
- * cd: error message contains correct directory string.
- * vi expansion list: printed in column form ala at&t ksh.
- * ^C while reading .profile/$ENV nolonger causes shell to exit.
- * option errors for build-in commands now include command name.
- * emacs completion/expansion: ' and " are treated as word delimiters.
- * fc: replacements (a=b) no longer truncates the command.
- * alias: alias -t -r now cleans out the tracked alias table.
-
-* compile-time configuration changed: configure script --enable-XXX options
- replace the old options.h file. Use "configure --help" for information
- on what the options do (they are basicly the same as what was in the
- options.h file). Shell can be configured as a (almost) plain bourne
- shell using the --enable-shell=sh (also generates appropriate man page).
- Installed name of program (ksh or sh) can be modified using configure's
- --program-* options.
-
-* ulimit: added -p (maxproc) option.
-
-* case statements can use the old syntax of {,} instead of in,esac.
-
-* extended file globbing added (eg, f*(bar|Bar) matches f, fbar fBarbar, etc).
-
-* trim expressions can be of the form ${parameter#pattern1|pattern2|...}.
-
-* if compiled as sh, $ENV included only if posix option is set.
-
-* vi: U command added (undo all changes on line).
-
-* the Bugs script has been replaced by a new regression testing system, kept
- in the tests/ directory (contains a perl script which sets up a test
- environment and runs tests, and a bunch of tests).
-
-
-Version 5.2.3
-
-* bug fixes
- * arrays: set -A and unset now unset whole array.
- * history(complex version): fixed core caused by uninitialized hist_source.
- * getopts: will continue parsing options if called after error.
- * getopts: doesn't print shell name twice in error message.
- * posix: if posix option is set, $0 is always the name of the shell.
- * history: "fc -s foo" now finds foo if it is the most recent command.
- * let: expression errors no longer cause scripts to exit.
- * PS1: does not go into infinite loop if there is an expansion error.
- * configure: memmove/bcopy test has a change of working now.
- * configure: check for flock(), undefine COMPLEX_HISTORY if not found.
- * substitution: tilde substitution works in word part of ${var[-+=?]word}.
- * history: "fc <number>" now edits <number>, not <number> to most recent.
- * cd: two argument form works again.
- * special commands taking assignments (alias,set,etc.): field splitting,
- file globbing, etc. suppressed only for args that look like assignments.
- * command: -V now finds reserved words.
-
-* added support for Korn's /dev/fd tests
-
-* new compile time option: DEFAULT_ENV - if defined, it names a file to
- include if $ENV is not set.
-
-* test -o option: if option starts with a !, the test is negated. The test
- always fails if the option doesn't exist (so [ -o foo -o -o !foo ] is true
- iff option foo exists).
-
-* new option: set -o nohup (currently on by default) - if set, running jobs
- are not kill -HUP'd when a login shell exits; if clear, they are. In
- future, this will be clear by default (to act like at&t ksh) - if you don't
- (won't) like this, add "[ -o !nohup ] && set -o nohup" to your .profile.
-
-Version 5.2.2
-
-* bug fixes
- * included c_test.h in distribution (opps).
-
-Version 5.2.1
-
-* bug fixes
- * emacs: buffer no longer overflowed when completing file names/commands.
- * emacs: <ESC><tty-erase-char> now bound to delete-back-word (was ...-char).
- * emacs: ignores a space char after ^V (version), as in at&t ksh.
- * emacs: ^O bound to newline-and-next, ^X^Y bound to list-file.
- * emacs: emacs words now include underscore.
- * vi: set -o markdirs, directories and ^[= now get along.
- * cd: -P no longer leaves .. and . in PWD.
- * cd: if CDPATH set and can't cd, error doesn't contain any of CDPATH.
- * cd: sets PWD properly, on machines without getwd().
- * configuration: unistd.h test fixed (include sys/types before dirent.h).
- * configuration: detects memmove/bcopy's that don't handle overlaps.
- * [[ ... ]] does lazy evaluation (eg, [[ ! -f foo || $(<foo) = bar ]] does
- not evaluate $(<foo) if foo doesn't exist).
-
-
-Version 5.2.0
-
-* bug fixes
- * vi: completion now allows globbing characters.
- * vi: can deal with very long prompts.
- * vi: . (redo) works after j, k, return.
- * vi: [dyc]% causing backwards motion now gets correct start/end position.
- * vi: complete_word (<ESC>\) no longer rings bell on ambiguous matches.
- * vi: globbing doesn't append * if last component of file has globbing chars.
- * emacs: most commands now take arguments, arguments can be multi digit.
- * emacs: newline-and-next command works more correctly.
- * after set -u, trimming substitutions no longer automatically fail.
- * set -i no longer reports an internal error.
- * FPATH: no longer incorrectly complains about function not being defined.
- by a file; when it connectly complains, shell name in error is correct.
- * set -a; set -o allexport: these now do something.
- * shell deals with non-blocking input (clears non-blocking flag).
- * autoconf: fixed memmove/memcpy tests.
- * ! translation in prompt now done before parameter substitution.
- * siglist.sh works around bug in bash 1.4.3.
- * correct positional parameters accessible in local assignments.
- * (sleep 100&) no longer waits for sleep to complete.
-
-* fc -s option added (same as -e -).
-
-* vi: ^V command (version) added.
-
-* vi: @<char> macros added (@X executes vi commands in alias _X).
-
-* emacs: bind -l lists all command names.
-
-* emacs: goto-history command added.
-
-* emacs: search-char function changed to search-char-forward;
- added search-char-backward (bound to <ESC>^]).
-
-* cd and pwd take -L and -P options; added set -o physical option
- (PWD,OLDPWD no longer readonly).
-
-* new command line -l option tells shell it is a login session.
-
-* os2 changes completed.
-
-* uses autoconf 2.x (was using 1.x).
-
-Version 5.1.3
-
-* bug fixes
- * fixed bug in arithmetic expression evaluation (||,&& caused core dump).
- * ulimit code now uses rlim_t or quad_t, if appropriate.
- * vi: file completion in command mode of single character filename works.
- * vi: file completion with markdirs set resulted in two trailing /'s.
- * vi: completion/expansion/listing acts like at&t ksh when expand fails.
- * vi: ~ takes count.
- * lines from history file are no longer negative (easy history).
- * Makefile now uses manual extension consistently.
- * fc now allows out of range relative (negative) numbers.
- * functions with elif now printed correctly.
- * FPATH now searched if PATH search fails, as in at&t ksh.
-
-* typeset -f output is readable (and more correct)
-
-* compiles under SCO unix
-
-* more os/2 changes integrated
-
-Version 5.1.2
-
-* bug fixes
- * for i; do ...; done now accepted.
- * leading non-white-space IFS chars no longer ignored (now delimit fields).
- * fixed globbing code so echo /usr/*/make works.
-
-Version 5.1.1
-
-* bug fixes
- * { ..;} allowed instead of do ..;done in for/select loops
- * EOF after ; or & no longer causes syntax error
- * complex history: when shrinking history file, keeps inside buffer space.
- * vi editing: `v' on modified line no longer changes command numbering.
- * ^C in vi/emacs no longer prints two newlines.
- * long arguments (> 255) with globbing characters don't cause core dumps.
-
-* new (un)option, KSH, which compiles out ksh code (for producing minimal sh).
-
-* os/2 changes partly merged.
-
-Version 5.1.0
-
-* bug fixes
- * problem caused by _POSIX_VDISABLE on BSDI machines fixed
- * exit status set to 127 if command file could not be opened
- * profile files processed if basename argv[0] starts with (was $0)
- * PWD now imported properly from environment.
- * emacs code now either uses dynamic buffers or does overflow checking.
- * emacs forward-word and delete-forward-word now work like other emacs's.
- * ^C/^\ in vi/emacs work like at&t ksh (prompt reprinted, even if trapped).
- * history number to command mapping now constant (numbers used to change).
- * configuration: BSD tty now used on ultrix (avoids type ahead problem)
- * eof in the middle of multiline commands now ignored if ignoreeof set.
- * vi space command now works again.
- * pointer mismatch compiler warning for waitpid() call dealt with.
- * emacs internal memory error in command completion fixed.
- * autoloaded functions now work first try.
- * SECONDS parameter now acts like in at&t ksh.
-
-* sense of vi-show8 option changed: 8-bit characters are printed as is by
- default; turning on vi-show8 now causes chars with 8th bit set to be
- prefixed with M-.
-
-* missing sections in man page added (now basicly complete)
-
-* emacs ^V command added: prints ksh version
-
-* vi g command added: moves to most recent history
-
-Version 5.0.10
-
-* bug fixes
- * [[ ]] construct unbroken.
- * the newline after a here document marker is now read properly.
- * blank lines no longer cause $? to be set to 0.
- * mail checking now uses atime/mtime instead of size.
- * changing attributes of exported parameters no longer causes core dump.
- * the last command in a file does not have to end in a newline.
- * empty expressions now treated as 0 (previously generated an error).
- * nul bytes stripped from input.
- * 0241 (M-!) in a command substitution no longer lost.
- * when read used in startup file, line continuation no longer causes crash.
- * very long commands in history no longer cause vi to overwrite memory.
- * easy history: when saving history, avoid going past the end of history.
- * emacs mode no longer entered if EDITOR/VISUAL set to null string.
- * command -p disabled in restricted mode.
- * closed file descriptors are re-closed after a redirection.
- * lone [ (test command) no longer causes globbing code to search directory.
- * if TIMES_BROKEN is defined, ksh_times no longer recurses infinitely.
- * `r r' no longer repeats r command forever.
- * make depend no longer generates backslash followed by a blank line.
- * globbing code now deals with symlinks that point to non-existent files.
- * if the ] is missing in a pattern, the [ matches the [ character.
- * syntax errors in test no longer have two newlines.
- * in vi, G now goes to the oldest history (was newest).
- * configuration: test for sys_siglist now harder for optimizers to break.
- * configuration: look for clock_t in sys/times.h.
- * configuration: use _SIGMAX, if available, for # of signals.
- * SIGHUP now causes builtin read command to exit.
- * wait builtin now returns whenever a traped signal occurs as per POSIX.
-
-* v command now works in vi; anchored searches now work in vi mode (/^ptrn);
- multi-line commands displayed correctly by history.
-
-* echo is now schizophrenic: accepts -n/-e/-E and backslash sequences.
-
-* test -H file added (checks for context dependent files on HPs).
-
-* set -o gmacs and markdirs honoured.
-
-* ansi arrow keys in default emacs key bindings.
-
-* ulimit now takes arithmetic expression (as per Korn book).
-
-* co-processes changed to be more compatible with at&t ksh.
-
-Version 5.0.9
-
-* bug fixes
- * FOO is put in the environment for FOO=bar exec blah.
- * compiles under QNX and with dmake.
- * the file pattern [!a--]* is now invalid (POSIX) (used to match everything)
- * echo "${foo:-"a"}*" no longer the same as echo a*.
- * alternation (brace expansion) fixes:
- * brace expansion done after variable expansion, as in csh/at&t ksh.
- * `echo a{b,c' no longer gives "Missing }" error (it echos a{b,c).
- * expansion only done if there is a comma (ie, `echo {a}' prints {a}).
- * globbing/expansion code passes 0x80 unharmed.
- * "echo ${XX=a*b}" no longer sets XX to "a\200*b".
- * "echo ${unset-a*b}" no longer has \200 in the error message.
- * bad substitution error generated for things like ${x:a}, ${x^a}, etc.
- * `x="a cdef"; echo ${x#a c}' now prints "def" instead of "a a cdef".
- * on systems where /etc/passwd//// is a valid name, echo /etc/pass*/ no
- longer matches /etc/passwd.
- * trace output (set -x) flushed correctly, PS4 initialized.
- * ulimit output ungarbled, code to use {set,get}ulimit (if available)
- enabled.
- * tilde expansion done in word part of ${foo-~/bar}
- * when reading stdin (ie, ksh -s), no longer reads too much.
- * shell handles i/o redirection and errors in builtin commands as per
- POSIX (still have to sort out variable assignment errors).
- * starting jobs that save/change/restore tty settings in the background
- no longer messes up tty settings when job finishes.
- * the pattern [a'-'z] now matches three characters, not 26, and
- the pattern [ab']'] also matches three characters.
-
-* a mostly complete man page! (work is still in progress)
-
-* quoting inside $(..) mostly works.
-
-* error reporting has been orthogonalized.
-
-* brace expansion on by default (can be disabled with set +o braceexpand, or
- set -o posix).
-
-* output of "set -o" now fits on a normal screen.
-
-* co-processes added (|&, read -p, print -p, etc.).
-
-* restricted mode added (for what its worth).
-
-* vi now prints meta characters with M- prefix, unless vi-show8 option is on.
-
-Version 5.0.8
-
-* bug fixes
- * two problems in fc (introduced in 5.0.7)
- * install target in Makefile missing a dollar
-
-Version 5.0.7
-
-* POSIX command command added
-
-* a few bug fixes
- * now compiles with various options undefined (eg, VI, EMACS, JOBS).
- * fixed typos in Makefile.in (maxext -> manext) and ksh.1 (\f -> \fP).
- * CLK_TCK defined to correct value for FreeBSD 1.1.5 (and earlier?).
- * original process group restored when an exec is done.
- * the exit value of set is that of the last $(...) on the command line.
- * ditto for a command with no command (eg, x=`false`).
- * command variable assignments done before path search (so PATH=... x works)
- and are added as they are processed (so A=1 B=$A works).
- * variable assignments infront of function calls are exported to programs
- inside the function.
- * aliases with trailing space are only honoured in command contexts
- if in posix mode.
-
-* make depend target added; install target warns if ksh not in /etc/shells.
-
-* set -o bgnice now does something.
-
-* vi mode: ESC is no longer a file completion command (too annoying).
-
-Version 5.0.6
-
-* most reported bugs/problems fixed (all but two).
-
-* temporary files now created in $TMPDIR (if it is a sane path).
-
-Version 5.0.5
-
-* function parsing POSIXized (function bodies can be any compound command,
- redirections after functions effect function invocation, not the
- instantiation, the () in a function definition now parsed as two tokens).
-
-* exit bultin now does stopped jobs check.
-
-* set -p/-o priviliged supported.
-
-* test builtin now believed to be completely posix.
-
-* a default path is now used when PATH is not set (defined in options.h).
-
-Version 5.0.4
-
-* configuration checks for buggy opendir()s and setpgrp()s.
-
-* autoloading functions now supported.
-
-* functions can safely redefine themselves.
-
-Version 5.0.3
-
-* hash command changed to "alias -t"; whence -p added; print -s added
- (all as in at&t ksh); unalias -a added (POSIX).
-
-* test builtin POSIX complient
-
-* TMOUT parameter supported (at&t ksh: timeout interactive shells)
-
-Version 5.0.2
-
-* trap/error handling changed to eliminate longjmp()s from signal handlers;
- trap ERR added.
-
-* ksh conditional expressions ([[ .. ]]) supported.
-
-* arithmetic expressions (let, $((..)), etc.) now understand full C
- integer expressions (except ++/-- and sizeof()).
-
-* typeset -L -R -Z -u -l added (as in at&t ksh)
-
-* at&t/posix $(( .. )) arithmetic expansions supported.
-
-Version 5.0.1
-
-* set -e no longer effects commands executed as part of if/while/until/&&/||/!
- condition.
-
-* posix ! keyword now recognized.
-
-* posix getopts; if not in posix mode, getopts will accept options starting
- with + (at&t kshism)
-
-* syntax error messages improved (says what was unexpected/unmatched)
-
-Version 4.9+mun.5
-
-* all known bugs related to job control fixed:
- * fg,bg,jobs,wait,kill commands fully POSIX complient
- * signals are no longer reported for foreground jobs killed by SIGINT and
- SIGPIPE
- * pipeline process groups now created more reliablely (was a problem
- if first process exited before second process exec'd).
- * "(: ; cat /etc/termcap) | sleep" nolonger hangs
-
-* save/restore tty mode if command succeeds/fails, respectively. Edit
- mode (emacs,vi) no longer use old tty mode information
-
-* test command: added -h
-
-* alternations option renamed to braceexpand (eg, use set -o braceexpand).
- Old usage (set -o alternations) still accepted (will disappear in next
- version).
-
-* trap/kill now accept upper and lower case signal names.
-
-Version 4.9+mun.3
-
-* here documents in functions now work properly
-
-* read command: added -s option, use REPLY if no variable specified
-
-* don't accept "while command; done" as a valid command
-
-* fg,bg,jobs,wait,kill commands mostly POSIX complient.
-
-* unset command: added POSIX -v option
-
-* set command: added -A option
-
-* handle ${array[@]} and ${array[*]}
-
-* compiles with old bsd 4.2 compiler (pcc)
-
-* new versions of etc/profile and etc/ksh.profile
-
-Version 4.9+mun.2 (versus 4.9)
-
-* directory/file structure has been re-arranged:
- * moved files from sh directory up a level, deleted sh directory
- * created misc directory, old ChangeLog,README,.. files moved to misc
-
-* now uses GNU autoconf for compilation.
-
-* no longer uses stdio FILE *'s for I/O redirection (most stdio
- usage has been removed). Solves many porting problems caused by
- dup'd file descriptors, forked processes and exiting.
-
-* removed lint from code (compiles with very few warning with gcc -O -Wall
- -Wno-comment)
-
-* has array support (needs work but is pretty functional).
-
-* ulimit command now more functional on more machines. Compatable with at&t ksh.
-
-* command line and set option parsing cleaned up, POSIXized.
-
-* POSIX IFS handling.
-
-* many many small bug fixes (see ChangeLog)
diff --git a/bin/pdksh/NOTES b/bin/pdksh/NOTES
deleted file mode 100644
index 17f29108eda..00000000000
--- a/bin/pdksh/NOTES
+++ /dev/null
@@ -1,514 +0,0 @@
-$OpenBSD: NOTES,v 1.3 1996/10/01 02:05:29 downsj Exp $
-
-General features of at&t ksh that are not (yet) in pdksh:
- - exported aliases.
- - exported functions.
- - set -t.
- - signals/traps not cleared during functions.
- - trap DEBUG, local ERR and EXIT traps in functions.
- - ERRNO, LINENO parameters.
- - doesn't have posix file globbing (eg, [[:alpha:]], etc.).
- - use of an `agent' to execute unreadable/setuid/setgid shell scripts
- (don't ask).
- - read/select aren't hooked in to the the command line editor
- - the last command of a pipeline is not run in the parent shell
-
-Known bugs (see also BUG-REPORTS and PROJECTS files):
- Variable parsing, Expansion:
- - some specials behave differently when unset (eg, IFS behaves like
- " \t\n") others lose their special meaning. IFS/PATH taken care of,
- still need to sort out some others (eg, TMOUT).
- Parsing,Lexing:
- - line numbers in errors are wrong for nested construct. Need to
- keep track of the line a command started on (can use for LINENO
- parameter as well).
- - a $(..) expression nested inside double quotes inside another $(..)
- isn't parsed correctly (eg, $(echo "foo$(echo ")")") )
- Commands,Execution:
- - setting special parameters that have side effects when
- changed/restored (ie, HISTFILE, OPTIND, RANDOM) in front
- of a command (eg, HISTFILE=/foo/bar echo hi) effects the parent
- shell. Note that setting other (not so special) parameters
- does not effect the parent shell.
- - `echo hi | exec cat -n' causes at&t to exit, `exec echo hi | cat -n'
- does not. pdksh exits for neither. Don't think POSIX requires
- an exit, but not sure.
- - `echo foo | read bar; echo $bar' prints foo in at&t ksh, nothing
- in pdksh (ie, the read is done in a seperate process in pdksh).
- Misc:
-
-Known differences between pdksh & at&t ksh (that may change)
- - vi:
- - `^U': at&t: kills only what has been inserted, pdksh: kills to
- start of line
- - at&t ksh login shells say "Warning: you have running jobs" if you
- try to exit when there are running jobs. An immediate second attempt
- to exit will kill the jobs and exit. pdksh does not print a warning,
- nor does it kill running jobs when it exits (it does warn/kill for
- stopped jobs).
- - TMOUT: at&t prints warning, then waits another 60 seconds. If on screwed
- up serial line, the output could cause more input, so pdksh just
- prints a message and exits. (Also, in at&t ksh, setting TMOUT has no
- effect after the sequence "TMOUT=60; unset TMOUT", which could be
- useful - pdksh may do this in the future).
- - in pdksh, if the last command of a pipeline is a shell builtin, it is
- not executed in the parent shell, so "echo a b | read foo bar" does not
- set foo and bar in the parent shell (at&t ksh will).
- This may get fixed in the future, but it may take a while.
- - in pdksh, set +o lists the options that are currently set, in at&t ksh
- it is the same as set -o.
- - in pdksh emacs mode, ^T does what gnu emacs does, not what at&t ksh
- does.
- - in ksh93, `. name' calls a function (defined with function) with POSIX
- semantics (instead of ksh semantics). in pdksh, . does not call
- functions.
- - test: "test -f foo bar blah" is the same as "test -f foo" (the extra
- arguments, of which there must be at least 2, are ignored) - pdksh
- generates an error message (unexpected operator/operand "bar") as it
- should. Sometimes used to test file globs (e.g., if test -f *.o; ...).
- - if the command 'sleep 5 && /bin/echo blah' is run interactively and
- is the sleep is stopped (^Z), the echo is run immediately in pdksh.
- In at&t ksh, the whole thing is stopped.
-
-Known differences between pdksh & at&t ksh (that are not likely to change)
- - at&t ksh seems to catch or ignore SIGALRM - pdksh dies upon receipt
- (unless it's traped of course)
- - typeset:
- - at&t ksh overloads -u/-l options: for integers, means unsigned/long,
- for strings means uppercase/lowercase; pdksh just has the
- upper/lower case (which can be useful for integers when base > 10).
- unsigned/long really should have their own options.
- - at&t ksh can't have justified integer variables
- (eg, typeset -iR5 j=10), pdksh can.
- - in pdksh, number arguments for -L/-R/-Z/-i must follow the option
- character, at&t allows it at the end of the option group (eg,
- at&t ksh likes "typeset -iu5 j", pdksh wants "typeset -i5 -u j"
- or "typeset -ui5 j"). Also, pdksh allows "typeset -i 5 j" (same
- as "typeset -i5 j"), at&t ksh does not allow this.
- - typeset -R: pdksh strips trailing space type characters (ie,
- uses isspace()), at&t ksh only skips blanks.
- - at&t ksh allows attributes of read-only variables to be changed,
- pdksh allows only the export attribute to be set.
- - (some) at&t ksh allows set -A of readonly variables, pdksh does not.
- - at&t ksh allows command assignments of readonly variables (eg, YY=2 cat),
- pdksh does not.
- - at&t ksh does not exit scripts when an implicit assignment to an integer
- variable fails due to an expression error: eg,
- echo 2+ > /tmp/x
- unset x; typeset -i x
- read x < /tmp/x
- echo still here
- prints an error and then prints "still here", similarly for
- unset x; typeset -i x
- set +A x 1 2+ 3
- echo still here
- and
- unset x y; typeset -i x y; set +A y 10 20 30
- set +A x 1 1+y[2+] 3
- echo still here
- pdksh exits a script in all the above cases. (note that both shells
- exit for:
- unset x; typeset -i x
- for x in 1 2+ 3; do echo x=$x; done
- echo still here
- ).
- - at&t ksh seems to allow function calls inside expressions
- (eg, typeset -i x='y(2)') but they do not seem to be regular functions
- nor math functions (eg, pow, exp) - anyone known anything about this?
- - `set -o nounset; unset foo; echo ${#foo}`: at&t ksh prints 0; pdksh
- generates error. Same for ${#foo[*]} and ${#foo[@]}.
- - . file: at&t ksh parses the whole file before executing anything,
- pdksh executes as it parses. This means aliases defined in the file
- will affect how pdksh parses the file, but won't affect how at&t ksh
- parses the file. Also means pdksh will not parse statements occuring
- after a (executed) return statement.
- - a return in $ENV in at&t ksh will cause the shell to exit, while in
- pdksh it will stop executing the script (this is consistent with
- what a return in .profile does in both shells).
- - at&t ksh does file globbing for `echo "${foo:-"*"}"`, pdksh does not
- (POSIX would seem to indicate pdksh is right).
- - at&t ksh thinks ${a:##foo} is ok, pdksh doesn't.
- - at&t does tilde expansion on here-document delimiters, pdksh does
- not. eg.
- $ cat << ~michael
- ~michael
- $
- works for pdksh, not for at&t ksh (POSIX seems to agree with pdksh).
- - in at&t ksh, tracked aliases have the export flag implicitly set
- and tracked aliases and normal aliases live in the same name space
- (eg, "alias" will list both tracked and normal aliases).
- in pdksh, -t does not imply -x (since -x doesn't do anything yet), and
- tracked/normal aliases live in seperate name spaces.
- in at&t ksh, alias accepts + options (eg, +x, +t) - pdksh does not.
- in pdksh, alias has a -d option to allow examination/changing of
- cached ~ entries, also unalias has -d and -t options (unalias -d
- is useful if the ~ cache gets out of date - not sure how at&t deals
- with this problem (it does cache ~ entries)).
- - at&t ksh will stop a recursive function after about 60 calls; pdksh
- will not since the limit is arbitrary and can't be controlled
- by the user (hit ^C if you get in trouble).
- - the wait command (with and without arguments) in at&t ksh will wait for
- stopped jobs when job control is enabled. pdksh doesn't.
- - at&t ksh automatically sets the bgnice option for interactive shells;
- pdksh does not.
- - in at&t ksh, "eval `false`; echo $?" prints 1, pdksh prints 0 (which
- is what POSIX says it should). Same goes for "wait `false`; echo $?".
- (same goes for "set `false`; echo $?" if posix option is set - some
- scripts that use the old getopt depend on this, so be careful about
- setting the posix option).
- - in at&t ksh, print -uX and read -uX are interrperted as -u with no
- argument (defaults to 1 and 0 respectively) and -X (which may or
- may not be a valid flag). In pdksh, -uX is interpreted as file
- descriptor X.
- - in at&t ksh, some signals (HUP, INT, QUIT) cause the read to exit, others
- (ie, everything else) do not. When it does cause exiting, anything read
- to that point is used (usually an empty line) and read returns with 0
- status. pdksh currently does similar things, but for TERM as well and
- the exit status is 128+<signal-number> - in future, pdksh's read will
- do this for all signals that are normally fatal as required by POSIX.
- (POSIX does not require the setting of variables to null so applications
- shouldn't rely on this).
- - in pdksh, ! substitution done before variable substitution; in at&t ksh
- it is done after substitution (and therefor may do ! substitutions on
- the result of variable substitutions). POSIX doesn't say which is to be
- done.
- - pwd: in at&t ksh, it ignores arguments; in pdksh, it complains when given
- arguments.
- - the at&t ksh does not do command substition on PS1, pdksh does.
- - ksh93 allows ". foo" to run the function foo if there is no file
- called foo (go figure).
- - field splitting (IFS): ksh88/ksh93 strip leading non-white space IFS
- chars, pdksh (and POSIX, I think) leave them intact. e.g.
- $ IFS="$IFS:"; read x; echo "<$x>"
- ::
- prints "<>" in at&t ksh, "<::>" in pdksh.
- - command completion: at&t ksh will do completion on a blank line (matching
- all commands), pdksh does not (as this isn't very useful - use * if
- you really want the list).
- - co-processes: if ksh93, the write portion of the co-process output is
- closed when the most recently started co-process exits. pdksh closes
- it when all the co-processes using it have exited.
-
-Oddities in ksh (pd & at&t):
- - array references inside (())/$(()) are strange:
- $(( x[2] )) does the expected, $(( $x[2] )) doesn't.
- - `typeset -R3 X='x '; echo "($X)"` produces ( x) - trailing
- spaces are stripped.
- - typeset -R turns off Z flag.
- - both shells have the following mis-feature:
- $ x='function xx {
- cat -n <<- EOF
- here we are in xx
- EOF
- }'
- $ (eval "$x"; (sleep 2; xx) & echo bye)
- [1] 1234
- bye
- $ xx: /tmp/sh1234.1: cannot open
- - bizarre special handling of alias/export/readonly/typeset arguments
- $ touch a=a; typeset a=[ab]; echo "$a"
- a=[ab]
- $ x=typeset; $x a=[ab]; echo "$a"
- a=a
- $
- - both ignore SIGTSTP,SIGTTIN,SIGTTOU in exec'd processes when talking
- and not monitoring (at&t ksh kind of does this). Doesn't really make
- sense.
- (Note that ksh.att -ic 'set +m; check-sigs' shows TSTP et al aren't
- ignored, while ksh.att -ic 'set +m^J check-sigs' does... very strange)
- - when tracing (set -x), and a command's stderr is redirected, the trace
- output is also redirected. so "set -x; echo foo 2> /tmp/O > /dev/null"
- will create /tmp/foo with the lines "+ > /dev/null" and "+ echo foo".
- - undocumented at&t ksh feature: FPATH is searched after PATH if no
- executable is found, even if typeset -uf wasn't used.
-
-at&t ksh bugs:
- [various versions:
- MIPS m120 RISC/os 5.0: Version 11/16/88d
- Dec alpha osf/1 v1.3: OSF/1 Version 11/16/88d NLS
- HP pa HP-UX 9.01: Version 11/16/88
- ]
- - (only hpux)
- $ _[2]=hi
- Bus error (core dumped)
- - (only riscos, hpux)
- $ typeset x[
- $
- - (only osf/1)
- $ A=B cat << EOF
- .$A.
- EOF
- Segmentation fault(coredump)
- $
- - (only osf/1)
- $ read "?foo "
- foo Foo
- $ set | grep Foo
- =Foo
- $
- - (all)
- $ typeset -i A
- $ typeset -L3 A
- $ typeset -l A
- Illegal instruction (core dumped)
- - (all)
- $ for i in a b c ; do echo $i, ${i[2]}, ${i[10]} ; done
- a, ,
- a, , b
- a, , c
- $
- - (all)
- $ echo ${abc:-G { I } K }
- G { I K }
- $
- $ abc=hi
- $ echo ${abc:-G { I } K }
- hi K }
- $
- The second echo should only have printed `hi'.
- - (all)
- $ echo ${abc:- > foo}
- syntax error: > unexpected
- $
- - (all? hpux) read reads too much from pipe (when pipe isn't stdin)
- print 'hi\nthere' | ksh 8<&0 0< /dev/tty
- $ read -u8 x
- $ print $x
- hi
- $ cat 0<&8
- $ read -u8 y
- $ print $y
- there
- $
- - (all)
- $ umask 0
- $ umask
- 00
- $
- - (osf, mips, !hpux)
- $ exec alias
- alias: not found
- (shell dead)
- - (all) non-white space IFS in non-substitution not preserved
- $ IFS="$IFS:"
- $ echo : "$@" # this is ok
- :
- $ echo :"$@" # this should print : too (me thinks)
-
- $
- - (only osf/1)
- $ set +m
- $ sleep 1 & # wait for a sec or two
- $ jobs
- Memory fault (core dumped)
- - (all)
- $ (sleep 1 & echo hi) &
- [1] 123
- $ [1] 234
- hi
- - (osf/1, mips)
- $ getopts abc optc -a -b -c
- $ getopts abc optc -a -b -c
- $ getopts abc optc -a
- Memory fault (core dumped)
- - (osf/1) POSIX says OPTIND shall be initialized to 1
- $ echo $OPTIND
- 0
- $
- - (osf/1 + others?)
- $ typeset -ri r=10
- $ let r=12
- $ echo $r
- 12
- $
- - (osf/1 + others?)
- $ typeset -i a
- $ typeset -L3 a
- Memory fault (core dumped)
- - (osf/1 + others?): -L strips leading \ \t\n\r, -R only strips trailing
- spaces
- $ typeset -L3 x
- $ x=' ^I^J^M 2'
- $ echo "($x)"
- (2 )
- $ typeset -R3 y
- $ x='2^I^J^M '
- $ echo "($x)"
- (^I^J^M)
- $
- - (osf/1 + others?)
- $ typeset +i RANDOM
- Memory fault (core dumped)
- - (osf/1 + others?): -L/-R/-Z clear -l/-u after assignment and vise versa
- $ typeset -u x=ab
- $ echo "($x)"
- (AB)
- $ typeset -L4 x=def
- $ echo "($x)"
- (DEF )
- $ typeset | grep ' x$'
- leftjust 4 x
- $
- $ typeset -L4 x=def
- $ echo "($x)"
- (def )
- $ typeset -u x=ab
- $ echo "($x)"
- (AB )
- $ typeset | grep ' x$'
- uppercase x
- $
- $ typeset -i x
- $ x='2()'
- $ x='()'
- $ x='2(4)'
- - (osf/1, others?)
- $ unset foo
- $ echo "${foo:-"*"}"
- <results of * expansion>
- $
- - (osf/1, others?)
- $ alias blah
- blah: alias not found
- $ alias -x blah | grep blah
- blah
- $ type blah
- Memory fault (core dumped)
- - (osf/1, others?)
- $ trap 'echo hi; false' ERR
- $ false
- hi
- hi
- ....
- Memory fault (core dumped)
- - (osf/1, others?)
- $ typeset +i ERRNO
- Memory fault (core dumped)
- - (osf/1, others?)
- $ X=abcdef
- $ echo ${X#a{b,c}e} # does not match {} inside word part of ${..#..}
- abcdefe}
- $
- - (osf/1, others?)
- $ x=f=abcdef
- $ echo ${f#a|abc}
- def
- $ echo ${f#abc|a}
- bcdef
- $ echo ${f#abc|a|d}
- abcdef
- $
- - (osf/1, hp-ux, others?)
- $ i() echo hi
- $ typeset -f
- function i
- {
- hi
- $
- - (osf/1, others?)
- $ function X {
- echo start of X
- function Y {
- echo in Y
- }
- echo end of X
- }
- $ X
- start of X
- end of X
- $ typeset -f
- function X
- {
- echo start of X
- function Y {
- echo in Y
- }
- echo end of X
- }
- function Y
- {
- echo in Y
- echo end of X
- }
- }
- $
- - (osf/1, others?)
- $ while read x; do print -r "A $x"; done |&
- [1] 18212
- $ exec 8<&p
- $ kill %1
- Memory fault
- - (osf/1, others?) Error only happens for builtin commands (/bin/echo works)
- $ while read x; do print -r "A $x"; done |&
- [1] 18212
- $ echo hi <&p
- hi
- $ echo hi <&p
- ksh: p: bad file unit number
- $ while read x; do print -r "A $x"; done |&
- ksh: process already exists
- $
- - (osf/1, others?) in restricted shells, command -p should not work.
- $ PATH=/tmp ksh -r
- $ print hi | command -p cat -n
- 1 hi
- $
- - (osf/1, others?) error message wrong for autoload files that don't define
- functions
- $ FPATH=/tmp
- $ echo echo hi there > /tmp/aja
- $ aja
- hi there
- ksh: echo: not found
- $
-
-POSIX sh questions (references are to POSIX 1003.2-1992)
- - arithmetic expressions: how are empty expressions treated?
- (eg, echo $(( ))). at&t ksh (and now pdksh) echo 0.
- Same question goes for `test "" -eq 0' - does this generate an error
- or, if not, what is the exit code?
- - should tilde expansion occur after :'s in the word part of ${..=..}?
- (me thinks it should)
- - if a signal is received during the execution of a built-in,
- does the builtin command exit or the whole shell?
- - is it legal to execute last command of pipeline in current
- execution environment (eg, can "echo foo | read bar" set
- bar?)
- - what action should be taken if there is an error doing a dup due
- to system limits (eg, not enough feil destriptors): is this
- a "redirection error" (in which case a script will exit iff the
- error occured while executing a special built-in)?
- IMHO, shell should exit script. Couldn't find a blanket statement
- like "if shell encounters an unexpected system error, it shall
- exit non-interactive scripts"...
-
-POSIX sh bugs (references are to POSIX 1003.2-1992)
- - in vi insert mode, ^W deletes to beginning of line or to the first
- blank/punct character (para at line 9124, section 3). This means
- "foo ^W" will do nothing. This is inconsistent with the vi
- spec, which says delete preceding word including and interceding
- blanks (para at line 5189, section 5).
- - parameter expansion, section 3.6.2, line 391: `in each case that a
- value of word is needed (..), word shall be subjected to tilde
- expansion, parameter expansion, ...'. Various expansions should not
- be performed if parameter is in double quotes.
- - the getopts description says assigning OPTIND a value other than 1
- produces undefined results, while the rationale for getopts suggests
- saving/restoring the OPTIND value inside functions (since POSIX
- functions don't do the save/restore automatically). Restoring
- OPTIND is kind of dumb since getopts may have been in the middle
- of parsing a group of flags (eg, -abc).
- - unclear whether arithmetic expressions (eg, $((..))) should
- understand C integer constants (ie, 0x123, 0177). at&t ksh doesn't
- and neither does pdksh.
- - `...` definition (3.6.3) says nothing about backslash followed by
- a newline, which sh and at&t ksh strip out completely. e.g.,
- $ show-args `echo 'X
- Y'`
- Number of args: 1
- 1: <XY>
- $
- POSIX would indicate the backslash-newline would be preserved.
- - does not say how "cat << ''" is to be treated (illegal, read 'til
- blank line, or read 'til eof). at&t ksh reads til eof, bourne shell
- reads 'til blank line. pdksh reads 'til blank line.
diff --git a/bin/pdksh/PROJECTS b/bin/pdksh/PROJECTS
deleted file mode 100644
index 917960ca4a0..00000000000
--- a/bin/pdksh/PROJECTS
+++ /dev/null
@@ -1,112 +0,0 @@
-$OpenBSD: PROJECTS,v 1.3 1996/10/01 02:05:30 downsj Exp $
-
-Things to be done in pdksh (see also the NOTES file):
-
- * builtin utilities:
- pdksh has most if not all POSIX/at&t ksh builtins, but they need to
- be checked that they conform to POSIX/at&t manual. Part of the
- process is changing the builtins to use the ksh_getopt() routine.
-
- The following builtins, which are defined by POSIX, haven't been
- examined:
- eval time
-
- The first pass has been done on the following commands:
- . : alias bg break cd continue echo exec exit export false fc fg
- getopts jobs kill pwd read readonly return set shift trap true umask
- unalias unset wait
-
- The second pass (ie, believed to be completely POSIX) has been done on
- the following commands:
- test
-
- (ulimit also needs to be examined to check it fits the posix style)
-
- * test suite
- Ideally, as the builtin utilities are being POSIXized, short tests
- should be written to be used in regression testing. The tests
- directory contains some tests, but many more need to be written.
-
- * internationalization
- Need to handle with the LANG and LC_* environment variables. This
- involves changes to ensure <ctype.h> macros are being used (currently
- uses its own macros in many places), figuring out how to deal with
- bases (for integer arithmetic, eg, 12#1A), and (the nasty one) doing
- string look ups for error messages, etc.. It probably isn't worth
- translating strings to other languages yet as the code is likely
- to change a lot in the near future, but it would be good to have the
- code set up so string tables can be used.
-
- * trap code
- * add the DEBUG trap.
- * fix up signal handling code. In particular, fatal vs tty signals,
- have signal routine to call to check for pending/fatal traps, etc.
-
- * parsing
- * the time keyword needs to be hacked to accept options (!) since
- POSIX says it shall accept the -p option and must skip a -- argument
- (end of options). Yuck.
-
- * lexing
- the lexing may need a re-write since it currently doesn't parse $( .. ),
- $(( .. )), (( ... )) properly.
- * need to ignore contents of quoted strings (and escaped chars?)
- inside $( .. ) and $(( .. )) when counting parentheses.
- * need to put bounds check on states[] array (if it still exists after
- the re-write)
-
- * variables
- * The "struct tbl" that is currently used for variables needs work since
- more information (eg, array stuff, fields) are needed for variables
- but not for the other things that use "struct tbl".
- * Arrays need to be implemented differently: currently does a linear
- search of a linked list to find element i; the linked list is not
- freed when a variable is unset.
-
- * functions
- finish the differences between function x and x(): trap EXIT, traps
- in general, treatment of OPTIND/OPTARG,
-
- * history
- There are two versions of the history code, COMPLEX_HISTORY and
- EASY_HISTORY, which need to be merged. COMPLEX does at&t style history
- where the history file is written after each command and checked when
- ever looking through the history (in case another shell has added
- something). EASY simply reads the history file at startup and writes
- it before exiting.
- * re-write the COMPLEX_HISTORY code so mmap() not needed (currently
- can't be used on machines without mmap()).
- * Add multiline knowledge to COMPLEX_HISTORY (see EASY_HISTORY
- stuff).
- * change COMPLEX_HISTORY code so concurrent history files are
- controlled by an option (set -o history-concurrent?). Delete
- the EASY_HISTORY code.
- * bring history code up to POSIX standards (see POSIX description
- of fc, etc.).
-
- * documentation
- Some sort of tutorial with examples would be good. Texinfo is probably
- the best medium for this. Also, the man page could be converted to
- texinfo (if the tutorial and man page are put in the same texinfo
- page, they should be somewhat distinct - i.e., the tutorial should
- be a separate thread - but there should be cross references between the
- two).
-
- * miscellaneous
- * POSIX specifies what happens when various kinds of errors occur
- in special built-ins commands vs regular commands (builtin or
- otherwise) (see POSIX.2:3.8.1). Some of this has been taken
- care of, but more needs doing.
-
- * remove static limits created by fixed sized arrays
- (eg, getsc_(line[]), ident[], heres[], PATH, states(lex.c),
- buffer size in emacs/vi code)
-
- * merge the emacs and vi code (should reduce the size of the shell and
- make maintenance easier); handle SIGWINCH while editing a line.
- [John Rochester is working on the merge]
-
- * add POSIX globbing (eg, [[:alnum:]]), see POSIX.2:2.8.3.2.
-
- * teach shf_vfprintf() about long long's (%lld); also make %p use
- long longs if appropriate.
diff --git a/bin/pdksh/README b/bin/pdksh/README
deleted file mode 100644
index f12f85b0ede..00000000000
--- a/bin/pdksh/README
+++ /dev/null
@@ -1,190 +0,0 @@
-$OpenBSD: README,v 1.5 1996/11/21 07:59:26 downsj Exp $
-
-Last updated October '96 for pdksh-5.2.12.
- (check ftp://ftp.cs.mun.ca:/pub/pdksh/ or
- http://www.cs.mun.ca/~michael/pdksh/ for new versions/patches)
-
-PD-ksh is a mostly complete AT&T ksh look-alike (see NOTES file for a list
-of things not supported). Work is currently underway to make it fully
-compatible with both POSIX and AT&T ksh (when the two don't conflict).
-
-Since pdksh is free and compiles and runs on most common unix systems, it
-is very useful in creating a consistent user interface across multiple
-machines. For example, in the CS dept. of MUN, pdksh is installed on a
-variety of machines including Suns, HPs, DecStations, pcs running Linux,
-etc., and is the login shell of ~5200 users.
-
-PDksh is currently being maintained by Michael Rendell (michael@cs.mun.ca),
-who took over from Simon J. Gerraty (sjg@zen.void.oz.au) at the later's
-suggestion. A short list of things that have been added since the last
-public pdksh release (4.9) are auto-configuration, arrays, $(( .. )),
-[[ .. ]], variable attributes, co-processes, extended file globbing,
-many POSIXisms and many bug fixes. See the NEWS and ChangeLog files for
-other features added and bugs fixed.
-
-Note that pdksh is provided AS IS, with NO WARRANTY, either expressed or
-implied. Also note that although the bulk of the code in pdksh is in the
-public domain, some files are copyrighten (but freely distributable) and
-subject to certain conditions (eg, don't remove copyright, document any
-changes, etc.). See the LEGAL file for details.
-
-If you would like to be notified via email of new releases as they become
-available, send mail to pdksh-request@cs.mun.ca with subject
-"send release notifications" (or "don't send release notifications" to stop
-them).
-
-
-Files of interest:
- NEWS short list of noticeable changes in various versions.
- CONTRIBUTORS short history of pdksh, people who contributed, etc.
- NOTES lists of known bugs in pdksh, at&t ksh, and posix.
- PROJECTS list of things that need to be done in pdksh.
- BUG-REPORTS list of recently reported bugs that have been fixed
- and all reported bugs that haven't been fixed.
- LEGAL A file detailing legal issues concerning pdksh.
- etc/* system profile and kshrc files used by Simon J. Gerraty.
- misc/README* readme files from previous versions.
- misc/Changes* changelog files from previous versions.
- os2/* files and info needed to compile ksh on os/2.
- tests/* pdksh's regression testing system.
-
-
-Compiling/Installing:
-
- The quick way:
- ./configure
- make
- make check # optional
- make install # will install /usr/local/bin/ksh
- # and /usr/local/man/man1/ksh.1
- [add path-to-installed-pdksh to /etc/shells]
-
- The more detailed description:
- * run "configure --help | your-favorite-pager" and look at the
- --enable-* and --disable-* options (they are at the end).
- Select any you options you wish to enable/disable
- (most people can skip this step).
- * run configure: this is a GNU autoconf configure script that will generate
- a Makefile and a config.h. Some of the useful options to configure are:
- --prefix=PATH indicates the directory tree under which the binary
- and man page are installed (ie, PATH/bin/ksh and
- PATH/man/man1/ksh.1).
- The default prefix is /usr/local.
- --exec-prefix=PATH overrides --prefix for machine dependent files
- (ie, the ksh binary)
- --program-prefix=pd install binary and man page as pdksh and pdksh.1
- --verbose show what is being defined as script runs
- Note that you don't have to build in the source directory. To build
- in a separate directory, do something like:
- $ mkdir objs
- $ cd objs
- $ ../configure --verbose
- ....
- $ make
- See the file INSTALL for a more complete description of configure and its
- generic options (ksh specific options are documented in the --help output)
- * miscellaneous configuration notes:
- * If your make doesn't understand VPATH, you must compile in
- the source directory.
- * On DecStations, MIPS and SONY machines with older C compilers that
- can't handle "int * volatile x", you should use gcc or turn off
- optimization. The problem is configure defines volatile to nothing
- since the compiler can't handle it properly, but the compiler does
- optimizations that the volatile is meant to prevent. So. Use gcc.
- * On MIPS RISC/os 5.0 systems, sysv environment, <signal.h> is
- messed up - it defines sigset_t, but not any of the rest of
- the posix signals (the sigset_t typedef should be in the
- ifdef KERNEL section) - also doesn't have waitpid() or wait3().
- Things compile up ok in the svr4 environment, but it dumps core
- in __start (perhaps our system doesn't have the full svr4
- environ?). Try compiling in the bsd43 environ instead (still not
- perfect - see BUG-REPORTS file), using gcc - cc has problems with
- macro expansions in the argument of a macro (in this case, the ARGS
- macro).
- * On TitanOS (Stardent/Titan), use `CC="cc -43" configure ...'.
- When configure finishes, edit config.h, undef HAVE_DIRENT_H and
- define HAVE_SYS_DIR_H (the dirent.h header file is broken).
- * On Linux (red hat distribution), check that /dev/tty has mode 0666
- (not mode 0644). If it has the wrong permissions, ksh will print
- warnings about not being able to do job control.
- * on NeXT machines (3.2, probably other releases), the siglist.out file
- won't be generated correctly if you try to use the system's compiler
- (it has a broken cc -E and strange header files). There are two
- ways to make it work:
- 1) if you have gcc, use it (for everything). Alternatively,
- force configure to use it for CPP, i.e., use
- CPP="gcc -E" configure ...
- 2) Force configure to use some extra CPPFLAGS, using
- CPPFLAGS="XXX" configure ...
- where XXX is obtained from running "cc -v YYY.c" on some
- C file. Look at the options passed to cpp (there are lots
- of them...) and replace the XXX above with them.
- Make sure you do a "make distclean" (or "rm config.cache") if
- you re-run configure with a difference CPP or CPPFLAGS.
- Also note that if you are building multiple arch binaries, you
- will have to specify both CC and CPP.
- * run make: everything should compile and link without problems.
- * run make check: this fires up a perl script that checks for some known
- and some fixed bugs. The script prints pass/fail for tests it expected
- to pass/fail, and PASS/FAIL for tests it expected to fail/pass. If you
- don't have perl, or if your perl doesn't work (most common problem is
- the .ph header files are missing or broken), you can run
- ENV= path-to-pdksh-executable misc/Bugs path-to-pdksh-executable
- instead.
- * run make install: this installs ksh (in /usr/local/bin/ksh by default,
- or where ever you told configure to put things).
- * add path-to-installed-pdksh to /etc/shells if it's not already there.
- This is only needed if you intend to use pdksh as a login shell (things
- like ftp won't allow users to connect in if their shell isn't in this
- file).
-
-The following is a list of machines that pdksh is reported to work on:
- -/PC Linux 1.x,2.x
- -/PC NetBSD 0.9a
- -/PC BSDI 1.1
- -/PC FreeBSD 2.0, 2.1
- -/PC OpenBSD
- -/PC Interactive/Sunsoft 3.0.1 and 4.1 (note that problems have been
- reported with isc3.2 - see the BUG-REPORTS file)
- -/PC OS/2
- Commadore/Amiga NetBSD 1.0
- Dec/alpha OSF/1 v2.x, v3.x
- Dec/alpha NetBSD 1.1B
- Dec/pmax Ultrix 4.2
- Dec/vax Ultrix 2.2 (not tested recently :-))
- Dec/vax 4.3BSD+NFS (MtXinu) (not tested recently :-))
- HP/pa HP-UX 9.01
- IBM/RS/6000 AIX 3.2.5
- MIPS/m120 RISC/os 5.0 (bsd43 environ)
- NeXT NeXTStep 3.2
- SGI/IRIX 6.2
- Sun/sun4 SunOS 4.1.3, 4.1.4
- Sun/sun4 Solaris 2.x
- Sun/sun386i SunOS 4.0.2
- Sun/sun3 SunOS 4.0.3, 4.1.1_U1
- Stardent/TitanOS 4.2
-
-
-Newer versions of pdksh may be available from
- ftp://ftp.cs.mun.ca:/pub/pdksh/
-you may want to check for one if you run into any problems, as the problem may
-already be fixed (you can get new release notifications automatically - see
-above).
-
-You can send bug reports, fixes, and enchancements to pdksh@cs.mun.ca (please
-don't assume I will see bug reports that are posted to some newsgroup or
-mailing list - I probably won't).
-If you are reporting a bug (with or without a fix), please include
- * the version of pdksh you are using (see version.c, or, if you are
- running pdksh, try echo $KSH_VERSION),
- * the machine, operating system and compiler you are using,
- * and a description of how to repeat the bug (a small shell
- script that demonstrates the bug is best).
-as well as the following, if relevant (if you aren't sure, include them)
- * what options you are using (both configure options and set -o options)
- * the output of configure, with the verbose flag
- (eg, make distclean; ./configure --verbose)
- * the contents of config.log (this is created by the configure script)
- * if you are using gcc (the GNU C compiler), which version it is.
-
-Michael Rendell, michael@cs.mun.ca.
diff --git a/bin/pdksh/alloc.c b/bin/pdksh/alloc.c
deleted file mode 100644
index bc39b1bc045..00000000000
--- a/bin/pdksh/alloc.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/* $OpenBSD: alloc.c,v 1.1 1996/08/14 06:19:10 downsj Exp $ */
-
-/*
- * area-based allocation built on malloc/free
- */
-
-#include "sh.h"
-#ifdef MEM_DEBUG
-# undef alloc
-# undef aresize
-# undef afree
-#endif /* MEM_DEBUG */
-
-#define ICELLS 100 /* number of Cells in small Block */
-
-typedef union Cell Cell;
-typedef struct Block Block;
-
-/*
- * The Cells in a Block are organized as a set of objects.
- * Each object (pointed to by dp) begins with a size in (dp-1)->size,
- * followed with "size" data Cells. Free objects are
- * linked together via dp->next.
- */
-
-union Cell {
- size_t size;
- Cell *next;
- struct {int _;} junk; /* alignment */
-};
-
-struct Block {
- Block *next; /* list of Blocks in Area */
- Cell *freelist; /* object free list */
- Cell *last; /* &b.cell[size] */
- Cell cell [1]; /* [size] Cells for allocation */
-};
-
-static Block aempty = {&aempty, aempty.cell, aempty.cell};
-
-/* create empty Area */
-Area *
-ainit(ap)
- register Area *ap;
-{
- ap->freelist = &aempty;
- return ap;
-}
-
-/* free all object in Area */
-void
-afreeall(ap)
- register Area *ap;
-{
- register Block *bp;
- register Block *tmp;
-
- bp = ap->freelist;
- if (bp != NULL && bp != &aempty) {
- do {
- tmp = bp->next;
- free((void*)bp);
- bp = tmp;
- } while (bp != ap->freelist);
- ap->freelist = &aempty;
- }
-}
-
-/* allocate object from Area */
-void *
-alloc(size, ap)
- size_t size;
- register Area *ap;
-{
- int cells, split;
- register Block *bp;
- register Cell *dp, *fp, *fpp;
-
- if (size <= 0) {
- aerror(ap, "allocate bad size");
- return NULL;
- }
- cells = (unsigned)(size - 1) / sizeof(Cell) + 1;
-
- /* find Cell large enough */
- for (bp = ap->freelist; ; bp = bp->next) {
- for (fpp = NULL, fp = bp->freelist;
- fp != bp->last; fpp = fp, fp = fpp->next)
- if ((fp-1)->size >= cells)
- goto Found;
-
- /* wrapped around Block list, create new Block */
- if (bp->next == ap->freelist) {
- bp = (Block*) malloc(offsetof(Block, cell[ICELLS])
- + sizeof(bp->cell[0]) * cells);
- if (bp == NULL) {
- aerror(ap, "cannot allocate");
- return NULL;
- }
- if (ap->freelist == &aempty)
- bp->next = bp;
- else {
- bp->next = ap->freelist->next;
- ap->freelist->next = bp;
- }
- bp->last = bp->cell + ICELLS + cells;
- fp = bp->freelist = bp->cell + 1; /* initial free list */
- (fp-1)->size = ICELLS + cells - 1;
- fp->next = bp->last;
- fpp = NULL;
- break;
- }
- }
- Found:
- ap->freelist = bp;
- dp = fp; /* allocated object */
- split = (dp-1)->size - cells;
- if (split < 0)
- aerror(ap, "allocated object too small");
- if (--split <= 0) { /* allocate all */
- fp = fp->next;
- } else { /* allocate head, free tail */
- (fp-1)->size = cells;
- fp += cells + 1;
- (fp-1)->size = split;
- fp->next = dp->next;
- }
- if (fpp == NULL)
- bp->freelist = fp;
- else
- fpp->next = fp;
- return (void*) dp;
-}
-
-/* change size of object -- like realloc */
-void *
-aresize(ptr, size, ap)
- register void *ptr;
- size_t size;
- Area *ap;
-{
- int cells;
- register Cell *dp = (Cell*) ptr;
-
- if (size <= 0) {
- aerror(ap, "allocate bad size");
- return NULL;
- }
- cells = (unsigned)(size - 1) / sizeof(Cell) + 1;
-
- if (dp == NULL || (dp-1)->size < cells) { /* enlarge object */
- /* XXX check for available adjacent free block */
- ptr = alloc(size, ap);
- if (dp != NULL) {
- memcpy(ptr, dp, (dp-1)->size * sizeof(Cell));
- afree((void *) dp, ap);
- }
- } else { /* shrink object */
- int split;
-
- split = (dp-1)->size - cells;
- if (--split <= 0) /* cannot split */
- ;
- else { /* shrink head, free tail */
- (dp-1)->size = cells;
- dp += cells + 1;
- (dp-1)->size = split;
- afree((void*)dp, ap);
- }
- }
- return (void*) ptr;
-}
-
-void
-afree(ptr, ap)
- void *ptr;
- register Area *ap;
-{
- register Block *bp;
- register Cell *fp, *fpp;
- register Cell *dp = (Cell*)ptr;
-
- /* find Block containing Cell */
- for (bp = ap->freelist; ; bp = bp->next) {
- if (bp->cell <= dp && dp < bp->last)
- break;
- if (bp->next == ap->freelist) {
- aerror(ap, "freeing with invalid area");
- return;
- }
- }
-
- /* find position in free list */
- for (fpp = NULL, fp = bp->freelist; fp < dp; fpp = fp, fp = fpp->next)
- ;
-
- if (fp == dp) {
- aerror(ap, "freeing free object");
- return;
- }
-
- /* join object with next */
- if (dp + (dp-1)->size == fp-1) { /* adjacent */
- (dp-1)->size += (fp-1)->size + 1;
- dp->next = fp->next;
- } else /* non-adjacent */
- dp->next = fp;
-
- /* join previous with object */
- if (fpp == NULL)
- bp->freelist = dp;
- else if (fpp + (fpp-1)->size == dp-1) { /* adjacent */
- (fpp-1)->size += (dp-1)->size + 1;
- fpp->next = dp->next;
- } else /* non-adjacent */
- fpp->next = dp;
-}
-
-#if DEBUG_ALLOC
-void
-aprint(ap, ptr, size)
- register Area *ap;
- void *ptr;
- size_t size;
-{
- Block *bp;
-
- if (!ap)
- shellf("aprint: null area pointer\n");
- else if (!(bp = ap->freelist))
- shellf("aprint: null area freelist\n");
- else if (bp == &aempty)
- shellf("aprint: area is empty\n");
- else {
- int i;
- Cell *fp;
-
- for (i = 0; !i || bp != ap->freelist; bp = bp->next, i++) {
- if (ptr) {
- void *eptr = (void *) (((char *) ptr) + size);
- /* print block only if it overlaps ptr/size */
- if (!((ptr >= (void *) bp
- && ptr <= (void *) bp->last)
- || (eptr >= (void *) bp
- && eptr <= (void *) bp->last)))
- continue;
- shellf("aprint: overlap of 0x%p .. 0x%p\n",
- ptr, eptr);
- }
- shellf("aprint: block %2d: 0x%p .. 0x%p (%d)\n", i,
- bp->cell, bp->last,
- (char *) bp->last - (char *) bp->cell);
- for (fp = bp->freelist; fp != bp->last; fp = fp->next)
- shellf(
- "aprint: 0x%p .. 0x%p (%d) free\n",
- (fp-1), (fp-1) + (fp-1)->size,
- (fp-1)->size * sizeof(Cell));
- }
- }
-}
-#endif /* DEBUG_ALLOC */
-
-
-#ifdef TEST_ALLOC
-
-Area a;
-
-main(int argc, char **argv) {
- int i;
- char *p [9];
-
- ainit(&a);
- for (i = 0; i < 9; i++) {
- p[i] = alloc(124, &a);
- printf("alloc: %x\n", p[i]);
- }
- for (i = 1; i < argc; i++)
- afree(p[atoi(argv[i])], &a);
- afreeall(&a);
- return 0;
-}
-
-void aerror(Area *ap, const char *msg) {
- abort();
-}
-
-#endif
-
diff --git a/bin/pdksh/c_ksh.c b/bin/pdksh/c_ksh.c
deleted file mode 100644
index 1435aa9c57d..00000000000
--- a/bin/pdksh/c_ksh.c
+++ /dev/null
@@ -1,1402 +0,0 @@
-/* $OpenBSD: c_ksh.c,v 1.7 1997/06/19 13:58:37 kstailey Exp $ */
-
-/*
- * built-in Korn commands: c_*
- */
-
-#include "sh.h"
-#include "ksh_stat.h"
-#include <ctype.h>
-
-int
-c_cd(wp)
- char **wp;
-{
- int optc;
- int physical = Flag(FPHYSICAL);
- int cdnode; /* was a node from cdpath added in? */
- int printpath = 0; /* print where we cd'd? */
- int rval;
- struct tbl *pwd_s, *oldpwd_s;
- XString xs;
- char *xp;
- char *dir, *try, *pwd;
- int phys_path;
- char *cdpath;
-
- while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != EOF)
- switch (optc) {
- case 'L':
- physical = 0;
- break;
- case 'P':
- physical = 1;
- break;
- case '?':
- return 1;
- }
- wp += builtin_opt.optind;
-
- if (Flag(FRESTRICTED)) {
- bi_errorf("restricted shell - can't cd");
- return 1;
- }
-
- pwd_s = global("PWD");
- oldpwd_s = global("OLDPWD");
-
- if (!wp[0]) {
- /* No arguments - go home */
- if ((dir = str_val(global("HOME"))) == null) {
- bi_errorf("no home directory (HOME not set)");
- return 1;
- }
- } else if (!wp[1]) {
- /* One argument: - or dir */
- dir = wp[0];
- if (strcmp(dir, "-") == 0) {
- dir = str_val(oldpwd_s);
- if (dir == null) {
- bi_errorf("no OLDPWD");
- return 1;
- }
- printpath++;
- }
- } else if (!wp[2]) {
- /* Two arguments - substitute arg1 in PWD for arg2 */
- int ilen, olen, nlen, elen;
- char *cp;
-
- if (!current_wd[0]) {
- bi_errorf("don't know current directory");
- return 1;
- }
- /* substitue arg1 for arg2 in current path.
- * if the first substitution fails because the cd fails
- * we could try to find another substitution. For now
- * we don't
- */
- if ((cp = strstr(current_wd, wp[0])) == (char *) 0) {
- bi_errorf("bad substitution");
- return 1;
- }
- ilen = cp - current_wd;
- olen = strlen(wp[0]);
- nlen = strlen(wp[1]);
- elen = strlen(current_wd + ilen + olen) + 1;
- dir = alloc(ilen + nlen + elen, ATEMP);
- memcpy(dir, current_wd, ilen);
- memcpy(dir + ilen, wp[1], nlen);
- memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen);
- printpath++;
- } else {
- bi_errorf("too many arguments");
- return 1;
- }
-
- Xinit(xs, xp, PATH, ATEMP);
- /* xp will have a bogus value after make_path() - set it to 0
- * so that if it's used, it will cause a dump
- */
- xp = (char *) 0;
-
- cdpath = str_val(global("CDPATH"));
- do {
- cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path);
-#ifdef S_ISLNK
- if (physical)
- rval = chdir(try = Xstring(xs, xp) + phys_path);
- else
-#endif /* S_ISLNK */
- {
- simplify_path(Xstring(xs, xp));
- rval = chdir(try = Xstring(xs, xp));
- }
- } while (rval < 0 && cdpath != (char *) 0);
-
- if (rval < 0) {
- if (cdnode)
- bi_errorf("%s: bad directory", dir);
- else
- bi_errorf("%s - %s", try, strerror(errno));
- return 1;
- }
-
- /* Clear out tracked aliases with relative paths */
- flushcom(0);
-
- /* Set OLDPWD */
- if (current_wd[0])
- setstr(oldpwd_s, current_wd);
-
- if (!ISABSPATH(Xstring(xs, xp))) {
-#ifdef OS2
- /* simplify_path() doesn't know about os/2's drive contexts,
- * so it can't set current_wd when changing to a:foo.
- * Handle this by calling getcwd()...
- */
- pwd = ksh_get_wd((char *) 0, 0);
-#else /* OS2 */
- pwd = (char *) 0;
-#endif /* OS2 */
- } else
-#ifdef S_ISLNK
- if (!physical || !(pwd = get_phys_path(Xstring(xs, xp))))
-#endif /* S_ISLNK */
- pwd = Xstring(xs, xp);
-
- /* Set PWD */
- if (pwd) {
- set_current_wd(pwd);
- setstr(pwd_s, pwd);
- } else {
- set_current_wd(null);
- pwd = Xstring(xs, xp);
- /* XXX unset $PWD? */
- }
- if (printpath || cdnode)
- shprintf("%s\n", pwd);
-
- return 0;
-}
-
-int
-c_pwd(wp)
- char **wp;
-{
- int optc;
- int physical = Flag(FPHYSICAL);
- char *p;
-
- while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != EOF)
- switch (optc) {
- case 'L':
- physical = 0;
- break;
- case 'P':
- physical = 1;
- break;
- case '?':
- return 1;
- }
- wp += builtin_opt.optind;
-
- if (wp[0]) {
- bi_errorf("too many arguments");
- return 1;
- }
-#ifdef S_ISLNK
- p = current_wd[0] ? (physical ? get_phys_path(current_wd) : current_wd)
- : (char *) 0;
-#else /* S_ISLNK */
- p = current_wd[0] ? current_wd : (char *) 0;
-#endif /* S_ISLNK */
- if (p && eaccess(p, R_OK) < 0)
- p = (char *) 0;
- if (!p) {
- p = ksh_get_wd((char *) 0, 0);
- if (!p) {
- bi_errorf("can't get current directory - %s",
- strerror(errno));
- return 1;
- }
- }
- shprintf("%s\n", p);
- return 0;
-}
-
-int
-c_print(wp)
- char **wp;
-{
-#define PO_NL BIT(0) /* print newline */
-#define PO_EXPAND BIT(1) /* expand backslash sequences */
-#define PO_PMINUSMINUS BIT(2) /* print a -- argument */
-#define PO_HIST BIT(3) /* print to history instead of stdout */
-#define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */
-#define PO_FSLASH BIT(5) /* swap slash for backslash (for os2 ) */
- int fd = 1;
- int flags = PO_EXPAND|PO_NL;
- char *s;
- const char *emsg;
- XString xs;
- char *xp;
-
- if (wp[0][0] == 'e') { /* echo command */
- int nflags = flags;
-
- /* A compromise between sysV and BSD echo commands:
- * escape sequences are enabled by default, and
- * -n, -e and -E are recognized if they appear
- * in arguments with no illegal options (ie, echo -nq
- * will print -nq).
- * Different from sysV echo since options are recognized,
- * different from BSD echo since escape sequences are enabled
- * by default.
- */
- wp += 1;
- while ((s = *wp) && *s == '-' && s[1]) {
- while (*++s)
- if (*s == 'n')
- nflags &= ~PO_NL;
- else if (*s == 'e')
- nflags |= PO_EXPAND;
- else if (*s == 'E')
- nflags &= ~PO_EXPAND;
- else
- /* bad option: don't use nflags, print
- * argument
- */
- break;
- if (*s)
- break;
- wp++;
- flags = nflags;
- }
- } else {
- int optc;
-#if OS2
- const char *options = "Rnpfrsu,"; /* added f flag */
-#else
- const char *options = "Rnprsu,";
-#endif
- while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
- switch (optc) {
- case 'R': /* fake BSD echo command */
- flags |= PO_PMINUSMINUS;
- flags &= ~PO_EXPAND;
- options = "ne";
- break;
- case 'e':
- flags |= PO_EXPAND;
- break;
-#ifdef OS2
- case 'f':
- flags |= PO_FSLASH;
- break;
-#endif
- case 'n':
- flags &= ~PO_NL;
- break;
-#ifdef KSH
- case 'p':
- if ((fd = coproc_getfd(W_OK, &emsg)) < 0) {
- bi_errorf("-p: %s", emsg);
- return 1;
- }
- break;
-#endif /* KSH */
- case 'r':
- flags &= ~PO_EXPAND;
- break;
- case 's':
- flags |= PO_HIST;
- break;
- case 'u':
- if (!*(s = builtin_opt.optarg))
- fd = 0;
- else if ((fd = check_fd(s, W_OK, &emsg)) < 0) {
- bi_errorf("-u: %s: %s", s, emsg);
- return 1;
- }
- break;
- case '?':
- return 1;
- }
- if (!(builtin_opt.info & GI_MINUSMINUS)) {
- /* treat a lone - like -- */
- if (wp[builtin_opt.optind]
- && strcmp(wp[builtin_opt.optind], "-") == 0)
- builtin_opt.optind++;
- } else if (flags & PO_PMINUSMINUS)
- builtin_opt.optind--;
- wp += builtin_opt.optind;
- }
-
- Xinit(xs, xp, 128, ATEMP);
-
- while (*wp != NULL) {
- register int c;
- s = *wp;
- while ((c = *s++) != '\0') {
- Xcheck(xs, xp);
-#ifdef OS2
- if ((flags & PO_FSLASH) && c == '\\')
- if (*s == '\\')
- *s++;
- else
- c = '/';
-#endif /* OS2 */
- if ((flags & PO_EXPAND) && c == '\\') {
- int i;
-
- switch ((c = *s++)) {
- /* Oddly enough, \007 seems more portable than
- * \a (due to HP-UX cc, Ultrix cc, old pcc's,
- * etc.).
- */
- case 'a': c = '\007'; break;
- case 'b': c = '\b'; break;
- case 'c': flags &= ~PO_NL;
- continue; /* AT&T brain damage */
- case 'f': c = '\f'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case 'v': c = 0x0B; break;
- case '0':
- /* Look for an octal number: can have
- * three digits (not counting the
- * leading 0). Truely burnt.
- */
- c = 0;
- for (i = 0; i < 3; i++) {
- if (*s >= '0' && *s <= '7')
- c = c*8 + *s++ - '0';
- else
- break;
- }
- break;
- case '\0': s--; c = '\\'; break;
- case '\\': break;
- default:
- Xput(xs, xp, '\\');
- }
- }
- Xput(xs, xp, c);
- }
- if (*++wp != NULL)
- Xput(xs, xp, ' ');
- }
- if (flags & PO_NL)
- Xput(xs, xp, '\n');
-
- if (flags & PO_HIST) {
- Xput(xs, xp, '\0');
- source->line++;
- histsave(source->line, Xstring(xs, xp), 1);
- Xfree(xs, xp);
- } else {
- int n, len = Xlength(xs, xp);
- int UNINITIALIZED(opipe);
-#ifdef KSH
-
- /* Ensure we aren't killed by a SIGPIPE while writing to
- * a coprocess. at&t ksh doesn't seem to do this (seems
- * to just check that the co-process is alive, which is
- * not enough).
- */
- if (coproc.write >= 0 && coproc.write == fd) {
- flags |= PO_COPROC;
- opipe = block_pipe();
- }
-#endif /* KSH */
- for (s = Xstring(xs, xp); len > 0; ) {
- n = write(fd, s, len);
- if (n < 0) {
-#ifdef KSH
- if (flags & PO_COPROC)
- restore_pipe(opipe);
-#endif /* KSH */
- if (errno == EINTR) {
- /* allow user to ^C out */
- intrcheck();
-#ifdef KSH
- if (flags & PO_COPROC)
- opipe = block_pipe();
-#endif /* KSH */
- continue;
- }
-#ifdef KSH
- /* This doesn't really make sense - could
- * break scripts (print -p generates
- * error message).
- *if (errno == EPIPE)
- * coproc_write_close(fd);
- */
-#endif /* KSH */
- return 1;
- }
- s += n;
- len -= n;
- }
-#ifdef KSH
- if (flags & PO_COPROC)
- restore_pipe(opipe);
-#endif /* KSH */
- }
-
- return 0;
-}
-
-int
-c_whence(wp)
- char **wp;
-{
- struct tbl *tp;
- char *id;
- int pflag = 0, vflag = 0, Vflag = 0;
- int ret = 0;
- int optc;
- int iam_whence = wp[0][0] == 'w';
- int fcflags;
- const char *options = iam_whence ? "pv" : "pvV";
-
- while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
- switch (optc) {
- case 'p':
- pflag = 1;
- break;
- case 'v':
- vflag = 1;
- break;
- case 'V':
- Vflag = 1;
- break;
- case '?':
- return 1;
- }
- wp += builtin_opt.optind;
-
-
- fcflags = FC_BI | FC_PATH | FC_FUNC;
- if (!iam_whence) {
- /* Note that -p on its own is deal with in comexec() */
- if (pflag)
- fcflags |= FC_DEFPATH;
- /* Convert command options to whence options - note that
- * command -pV uses a different path search than whence -v
- * or whence -pv. This should be considered a feature.
- */
- vflag = Vflag;
- }
- if (pflag)
- fcflags &= ~(FC_BI | FC_FUNC);
-
- while ((vflag || ret == 0) && (id = *wp++) != NULL) {
- tp = NULL;
- if ((iam_whence || vflag) && !pflag)
- tp = tsearch(&keywords, id, hash(id));
- if (!tp && !pflag) {
- tp = tsearch(&aliases, id, hash(id));
- if (tp && !(tp->flag & ISSET))
- tp = NULL;
- }
- if (!tp)
- tp = findcom(id, fcflags);
- if (vflag || (tp->type != CALIAS && tp->type != CEXEC
- && tp->type != CTALIAS))
- shprintf("%s", id);
- switch (tp->type) {
- case CKEYWD:
- if (vflag)
- shprintf(" is a reserved word");
- break;
- case CALIAS:
- if (vflag)
- shprintf(" is an %salias for ",
- (tp->flag & EXPORT) ? "exported "
- : null);
- if (!iam_whence && !vflag)
- shprintf("alias %s=", id);
- print_value_quoted(tp->val.s);
- break;
- case CFUNC:
- if (vflag) {
- shprintf(" is a");
- if (tp->flag & EXPORT)
- shprintf("n exported");
- if (tp->flag & TRACE)
- shprintf(" traced");
- if (!(tp->flag & ISSET)) {
- shprintf(" undefined");
- if (tp->u.fpath)
- shprintf(" (autoload from %s)",
- tp->u.fpath);
- }
- shprintf(" function");
- }
- break;
- case CSHELL:
- if (vflag)
- shprintf(" is a%s shell builtin",
- (tp->flag & SPEC_BI) ? " special" : null);
- break;
- case CTALIAS:
- case CEXEC:
- if (tp->flag & ISSET) {
- if (vflag) {
- shprintf(" is ");
- if (tp->type == CTALIAS)
- shprintf(
- "a tracked %salias for ",
- (tp->flag & EXPORT) ?
- "exported "
- : null);
- }
- shprintf("%s", tp->val.s);
- } else {
- if (vflag)
- shprintf(" not found");
- ret = 1;
- }
- break;
- default:
- shprintf("%s is *GOK*", id);
- break;
- }
- if (vflag || !ret)
- shprintf(newline);
- }
- return ret;
-}
-
-/* Deal with command -vV - command -p dealt with in comexec() */
-int
-c_command(wp)
- char **wp;
-{
- /* Let c_whence do the work. Note that c_command() must be
- * a distinct function from c_whence() (tested in comexec()).
- */
- return c_whence(wp);
-}
-
-/* typeset, export, and readonly */
-int
-c_typeset(wp)
- char **wp;
-{
- struct block *l = e->loc;
- struct tbl *vp, **p;
- Tflag fset = 0, fclr = 0;
- int thing = 0, func = 0, local = 0;
- const char *options = "L#R#UZ#fi#lrtux"; /* see comment below */
- char *fieldstr, *basestr;
- int field, base;
- int optc;
- Tflag flag;
- int pflag = 0;
-
- switch (**wp) {
- case 'e': /* export */
- fset |= EXPORT;
- options = "p";
- break;
- case 'r': /* readonly */
- fset |= RDONLY;
- options = "p";
- break;
- case 's': /* set */
- /* called with 'typeset -' */
- break;
- case 't': /* typeset */
- local = 1;
- break;
- }
-
- fieldstr = basestr = (char *) 0;
- builtin_opt.flags |= GF_PLUSOPT;
- /* at&t ksh seems to have 0-9 as options, which are multiplied
- * to get a number that is used with -L, -R, -Z or -i (eg, -1R2
- * sets right justify in a field of 12). This allows options
- * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and
- * does not allow the number to be specified as a seperate argument
- * Here, the number must follow the RLZi option, but is optional
- * (see the # kludge in ksh_getopt()).
- */
- while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF) {
- flag = 0;
- switch (optc) {
- case 'L':
- flag |= LJUST;
- fieldstr = builtin_opt.optarg;
- break;
- case 'R':
- flag |= RJUST;
- fieldstr = builtin_opt.optarg;
- break;
- case 'U':
- /* at&t ksh uses u, but this conflicts with
- * upper/lower case. If this option is changed,
- * need to change the -U below as well
- */
- flag |= INT_U;
- break;
- case 'Z':
- flag |= ZEROFIL;
- fieldstr = builtin_opt.optarg;
- break;
- case 'f':
- func = 1;
- break;
- case 'i':
- flag |= INTEGER;
- basestr = builtin_opt.optarg;
- break;
- case 'l':
- flag |= LCASEV;
- break;
- case 'p': /* posix export/readonly -p flag */
- pflag = 1;
- break;
- case 'r':
- flag |= RDONLY;
- break;
- case 't':
- flag |= TRACE;
- break;
- case 'u':
- flag |= UCASEV_AL; /* upper case / autoload */
- break;
- case 'x':
- flag |= EXPORT;
- break;
- case '?':
- return 1;
- }
- if (builtin_opt.info & GI_PLUS) {
- fclr |= flag;
- fset &= ~flag;
- thing = '+';
- } else {
- fset |= flag;
- fclr &= ~flag;
- thing = '-';
- }
- }
-
- field = 0;
- if (fieldstr && !bi_getn(fieldstr, &field))
- return 1;
- base = 0;
- if (basestr && !bi_getn(basestr, &base))
- return 1;
-
- if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind]
- && (wp[builtin_opt.optind][0] == '-'
- || wp[builtin_opt.optind][0] == '+')
- && wp[builtin_opt.optind][1] == '\0')
- {
- thing = wp[builtin_opt.optind][0];
- builtin_opt.optind++;
- }
-
- if (func && ((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT))) {
- bi_errorf("only -t, -u and -x options may be used with -f");
- return 1;
- }
- if (wp[builtin_opt.optind]) {
- /* Take care of exclusions */
- /* setting these attributes clears the others, unless they
- * are also set in this command
- */
- if (fset & (LJUST|RJUST|ZEROFIL|UCASEV_AL|LCASEV|INTEGER
- |INT_U|INT_L))
- fclr |= ~fset &
- (LJUST|RJUST|ZEROFIL|UCASEV_AL|LCASEV|INTEGER
- |INT_U|INT_L);
- fclr &= ~fset; /* set wins */
- if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) {
- fset |= RJUST;
- fclr &= ~RJUST;
- }
- if (fset & LCASEV) /* LCASEV has priority */
- fclr |= UCASEV_AL;
- else if (fset & UCASEV_AL)
- fclr |= LCASEV;
- if (fset & LJUST) /* LJUST has priority */
- fclr |= RJUST;
- else if (fset & RJUST)
- fclr |= LJUST;
- if ((fset | fclr) & INTEGER) {
- if (!(fset | fclr) & INT_U)
- fclr |= INT_U;
- if (!(fset | fclr) & INT_L)
- fclr |= INT_L;
- }
- fset &= ~fclr; /* in case of something like -LR */
- }
-
- /* set variables and attributes */
- if (wp[builtin_opt.optind]) {
- int i;
- int rval = 0;
- struct tbl *f;
-
- if (local && !func)
- fset |= LOCAL;
- for (i = builtin_opt.optind; wp[i]; i++) {
- if (func) {
- f = findfunc(wp[i], hash(wp[i]),
- (fset&UCASEV_AL) ? TRUE : FALSE);
- if (!f) {
- /* at&t ksh does ++rval: bogus */
- rval = 1;
- continue;
- }
- if (fset | fclr) {
- f->flag |= fset;
- f->flag &= ~fclr;
- } else
- fptreef(shl_stdout, 0,
- "function %s %T\n",
- wp[i], f->val.t);
- } else if (!typeset(wp[i], fset, fclr, field, base)) {
- bi_errorf("%s: not identifier", wp[i]);
- return 1;
- }
- }
- return rval;
- }
-
- /* list variables and attributes */
- flag = fset | fclr; /* no difference at this point.. */
- if (func) {
- for (l = e->loc; l; l = l->next) {
- for (p = tsort(&l->funs); (vp = *p++); ) {
- if (flag && (vp->flag & flag) == 0)
- continue;
- if (thing == '-')
- fptreef(shl_stdout, 0, "function %s %T\n",
- vp->name, vp->val.t);
- else
- shprintf("%s\n", vp->name);
- }
- }
- } else {
- for (l = e->loc; l; l = l->next) {
- for (p = tsort(&l->vars); (vp = *p++); )
- for (; vp; vp = vp->u.array) {
- /* Report an unset param only if the user has
- * explicitly given it some attribute (like export);
- * otherwise, after "echo $FOO", we would report FOO...
- */
- if (!(vp->flag & ISSET) && !(vp->flag & USERATTRIB))
- continue;
- if (flag && (vp->flag & flag) == 0)
- continue;
- /* no arguments */
- if (thing == 0 && flag == 0) {
- /* at&t ksh prints things like export, integer,
- * leftadj, zerofill, etc., but POSIX says must
- * be suitable for re-entry...
- */
- shprintf("typeset ");
- if ((vp->flag&INTEGER))
- shprintf("-i ");
- if ((vp->flag&EXPORT))
- shprintf("-x ");
- if ((vp->flag&RDONLY))
- shprintf("-r ");
- if ((vp->flag&TRACE))
- shprintf("-t ");
- if ((vp->flag&LJUST))
- shprintf("-L%d ", vp->u2.field);
- if ((vp->flag&RJUST))
- shprintf("-R%d ", vp->u2.field);
- if ((vp->flag&ZEROFIL))
- shprintf("-Z ");
- if ((vp->flag&LCASEV))
- shprintf("-l ");
- if ((vp->flag&UCASEV_AL))
- shprintf("-u ");
- if ((vp->flag&INT_U))
- shprintf("-U ");
- if (vp->flag&ARRAY)
- shprintf("%s[%d]\n", vp->name,vp->index);
- else
- shprintf("%s\n", vp->name);
- } else {
- if (pflag)
- shprintf("%s ",
- (flag & EXPORT) ? "export" : "readonly");
- if (vp->flag&ARRAY)
- shprintf("%s[%d]", vp->name, vp->index);
- else
- shprintf("%s", vp->name);
- if (thing == '-' && (vp->flag&ISSET)) {
- char *s = str_val(vp);
-
- shprintf("=");
- /* at&t ksh can't have justified integers.. */
- if ((vp->flag & (INTEGER|LJUST|RJUST))
- == INTEGER)
- shprintf("%s", s);
- else
- print_value_quoted(s);
- }
- shprintf(newline);
- }
- }
- }
- }
- return 0;
-}
-
-int
-c_alias(wp)
- char **wp;
-{
- struct table *t = &aliases;
- int rv = 0, rflag = 0, tflag, Uflag = 0;
- Tflag xflag = 0;
- int optc;
-
- while ((optc = ksh_getopt(wp, &builtin_opt, "drtUx")) != EOF)
- switch (optc) {
- case 'd':
- t = &homedirs;
- break;
- case 'r':
- rflag = 1;
- break;
- case 't':
- t = &taliases;
- break;
- case 'U': /* kludge for tracked alias initialization
- * (don't do a path search, just make an entry)
- */
- Uflag = 1;
- break;
- case 'x':
- xflag = EXPORT;
- break;
- case '?':
- return 1;
- }
- wp += builtin_opt.optind;
-
- tflag = t == &taliases;
-
- /* "hash -r" means reset all the tracked aliases.. */
- if (rflag) {
- static const char *const args[] = {
- "unalias", "-ta", (const char *) 0
- };
-
- if (!tflag || *wp) {
- shprintf(
- "alias: -r flag can only be used with -t and without arguments\n");
- return 1;
- }
- ksh_getopt_reset(&builtin_opt, GF_ERROR);
- return c_unalias((char **) args);
- }
-
- if (*wp == NULL) {
- struct tbl *ap, **p;
-
- for (p = tsort(t); (ap = *p++) != NULL; )
- if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) {
- shprintf("%s=", ap->name);
- print_value_quoted(ap->val.s);
- shprintf(newline);
- }
- }
-
- for (; *wp != NULL; wp++) {
- char *alias = *wp;
- char *val = strchr(alias, '=');
- char *newval;
- struct tbl *ap;
- int h;
-
- if (val)
- alias = str_nsave(alias, val++ - alias, ATEMP);
- h = hash(alias);
- if (val == NULL && !tflag && !xflag) {
- ap = tsearch(t, alias, h);
- if (ap != NULL && (ap->flag&ISSET)) {
- shprintf("%s=", ap->name);
- print_value_quoted(ap->val.s);
- shprintf(newline);
- } else {
- shprintf("%s alias not found\n", alias);
- rv = 1;
- }
- continue;
- }
- ap = tenter(t, alias, h);
- ap->type = tflag ? CTALIAS : CALIAS;
- /* Are we setting the value or just some flags? */
- if ((val && !tflag) || (!val && tflag && !Uflag)) {
- if (ap->flag&ALLOC) {
- ap->flag &= ~(ALLOC|ISSET);
- afree((void*)ap->val.s, APERM);
- }
- /* ignore values for -t (at&t ksh does this) */
- newval = tflag ? search(alias, path, X_OK, (int *) 0)
- : val;
- if (newval) {
- ap->val.s = str_save(newval, APERM);
- ap->flag |= ALLOC|ISSET;
- } else
- ap->flag &= ~ISSET;
- }
- ap->flag |= DEFINED|xflag;
- if (val)
- afree(alias, ATEMP);
- }
-
- return rv;
-}
-
-int
-c_unalias(wp)
- char **wp;
-{
- register struct table *t = &aliases;
- register struct tbl *ap;
- int rv = 0, all = 0;
- int optc;
-
- while ((optc = ksh_getopt(wp, &builtin_opt, "adt")) != EOF)
- switch (optc) {
- case 'a':
- all = 1;
- break;
- case 'd':
- t = &homedirs;
- break;
- case 't':
- t = &taliases;
- break;
- case '?':
- return 1;
- }
- wp += builtin_opt.optind;
-
- for (; *wp != NULL; wp++) {
- ap = tsearch(t, *wp, hash(*wp));
- if (ap == NULL) {
- rv = 1; /* POSIX */
- continue;
- }
- if (ap->flag&ALLOC) {
- ap->flag &= ~(ALLOC|ISSET);
- afree((void*)ap->val.s, APERM);
- }
- ap->flag &= ~(DEFINED|ISSET|EXPORT);
- }
-
- if (all) {
- struct tstate ts;
-
- for (twalk(&ts, t); (ap = tnext(&ts)); ) {
- if (ap->flag&ALLOC) {
- ap->flag &= ~(ALLOC|ISSET);
- afree((void*)ap->val.s, APERM);
- }
- ap->flag &= ~(DEFINED|ISSET|EXPORT);
- }
- }
-
- return rv;
-}
-
-#ifdef KSH
-int
-c_let(wp)
- char **wp;
-{
- int rv = 1;
- long val;
-
- if (wp[1] == (char *) 0) /* at&t ksh does this */
- bi_errorf("no arguments");
- else
- for (wp++; *wp; wp++)
- if (!evaluate(*wp, &val, TRUE)) {
- rv = 2; /* distinguish error from zero result */
- break;
- } else
- rv = val == 0;
- return rv;
-}
-#endif /* KSH */
-
-int
-c_jobs(wp)
- char **wp;
-{
- int optc;
- int flag = 0;
- int nflag = 0;
- int rv = 0;
-
- while ((optc = ksh_getopt(wp, &builtin_opt, "lpnz")) != EOF)
- switch (optc) {
- case 'l':
- flag = 1;
- break;
- case 'p':
- flag = 2;
- break;
- case 'n':
- nflag = 1;
- break;
- case 'z': /* debugging: print zombies */
- nflag = -1;
- break;
- case '?':
- return 1;
- }
- wp += builtin_opt.optind;
- if (!*wp)
- if (j_jobs((char *) 0, flag, nflag))
- rv = 1;
- else
- for (; *wp; wp++)
- if (j_jobs(*wp, flag, nflag))
- rv = 1;
- return rv;
-}
-
-#ifdef JOBS
-int
-c_fgbg(wp)
- char **wp;
-{
- int bg = strcmp(*wp, "bg") == 0;
- int UNINITIALIZED(rv);
-
- if (!Flag(FMONITOR)) {
- bi_errorf("job control not enabled");
- return 1;
- }
- if (ksh_getopt(wp, &builtin_opt, null) == '?')
- return 1;
- wp += builtin_opt.optind;
- if (*wp)
- for (; *wp; wp++)
- rv = j_resume(*wp, bg);
- else
- rv = j_resume("%%", bg);
- /* POSIX says fg shall return 0 (unless an error occurs).
- * at&t ksh returns the exit value of the job...
- */
- return (bg || Flag(FPOSIX)) ? 0 : rv;
-}
-#endif
-
-struct kill_info {
- int num_width;
- int name_width;
-};
-static char *kill_fmt_entry ARGS((void *arg, int i, char *buf, int buflen));
-
-/* format a single kill item */
-static char *
-kill_fmt_entry(arg, i, buf, buflen)
- void *arg;
- int i;
- char *buf;
- int buflen;
-{
- struct kill_info *ki = (struct kill_info *) arg;
-
- i++;
- if (sigtraps[i].name)
- shf_snprintf(buf, buflen, "%*d %*s %s",
- ki->num_width, i,
- ki->name_width, sigtraps[i].name,
- sigtraps[i].mess);
- else
- shf_snprintf(buf, buflen, "%*d %*d %s",
- ki->num_width, i,
- ki->name_width, sigtraps[i].signal,
- sigtraps[i].mess);
- return buf;
-}
-
-
-int
-c_kill(wp)
- char **wp;
-{
- Trap *t = (Trap *) 0;
- char *p;
- int lflag = 0;
- int i, n, rv, sig;
-
- /* assume old style options if -digits or -UPPERCASE */
- if ((p = wp[1]) && *p == '-' && (digit(p[1]) || isupper(p[1]))) {
- if (!(t = gettrap(p + 1))) {
- bi_errorf("bad signal `%s'", p + 1);
- return 1;
- }
- i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2;
- } else {
- int optc;
-
- while ((optc = ksh_getopt(wp, &builtin_opt, "ls:")) != EOF)
- switch (optc) {
- case 'l':
- lflag = 1;
- break;
- case 's':
- if (!(t = gettrap(builtin_opt.optarg))) {
- bi_errorf("bad signal `%s'",
- builtin_opt.optarg);
- return 1;
- }
- case '?':
- return 1;
- }
- i = builtin_opt.optind;
- }
- if ((lflag && t) || (!wp[i] && !lflag)) {
- shf_fprintf(shl_out,
-"Usage: kill [ -s signame | -signum | -signame ] {pid|job}...\n\
- kill -l [exit_status]\n"
- );
- bi_errorf(null);
- return 1;
- }
-
- if (lflag) {
- if (wp[i]) {
- for (; wp[i]; i++) {
- if (!bi_getn(wp[i], &n))
- return 1;
- if (n > 128 && n < 128 + SIGNALS)
- n -= 128;
- if (n > 0 && n < SIGNALS && sigtraps[n].name)
- shprintf("%s\n", sigtraps[n].name);
- else
- shprintf("%d\n", n);
- }
- } else if (Flag(FPOSIX)) {
- p = null;
- for (i = 1; i < SIGNALS; i++, p = space)
- if (sigtraps[i].name)
- shprintf("%s%s", p, sigtraps[i].name);
- shprintf(newline);
- } else {
- int w, i;
- int mess_width;
- struct kill_info ki;
-
- for (i = SIGNALS, ki.num_width = 1; i >= 10; i /= 10)
- ki.num_width++;
- ki.name_width = mess_width = 0;
- for (i = 0; i < SIGNALS; i++) {
- w = sigtraps[i].name ? strlen(sigtraps[i].name)
- : ki.num_width;
- if (w > ki.name_width)
- ki.name_width = w;
- w = strlen(sigtraps[i].mess);
- if (w > mess_width)
- mess_width = w;
- }
-
- print_columns(shl_stdout, SIGNALS - 1,
- kill_fmt_entry, (void *) &ki,
- ki.num_width + ki.name_width + mess_width + 3);
- }
- return 0;
- }
- rv = 0;
- sig = t ? t->signal : SIGTERM;
- for (; (p = wp[i]); i++) {
- if (*p == '%') {
- if (j_kill(p, sig))
- rv = 1;
- } else if (!getn(p, &n)) {
- bi_errorf("%s: arguments must be jobs or process ids",
- p);
- rv = 1;
- } else {
- /* use killpg if < -1 since -1 does special things for
- * some non-killpg-endowed kills
- */
- if ((n < -1 ? killpg(-n, sig) : kill(n, sig)) < 0) {
- bi_errorf("%s: %s", p, strerror(errno));
- rv = 1;
- }
- }
- }
- return rv;
-}
-
-static Getopt user_opt; /* parsing state for getopts builtin command */
-static int getopts_noset; /* stop OPTIND assign from resetting state */
-
-void
-getopts_reset(val)
- int val;
-{
- if (!getopts_noset && val >= 1) {
- ksh_getopt_reset(&user_opt,
- GF_NONAME | (Flag(FPOSIX) ? 0 : GF_PLUSOPT));
- user_opt.optind = val;
- }
-}
-
-int
-c_getopts(wp)
- char **wp;
-{
- int argc;
- const char *options;
- const char *var;
- int optc;
- char buf[3];
- struct tbl *vq;
-
- if (ksh_getopt(wp, &builtin_opt, null) == '?')
- return 1;
- wp += builtin_opt.optind;
-
- options = *wp++;
- if (!options) {
- bi_errorf("missing options argument");
- return 1;
- }
-
- var = *wp++;
- if (!var) {
- bi_errorf("missing name argument");
- return 1;
- }
- if (!*var || *skip_varname(var, TRUE)) {
- bi_errorf("%s: is not an identifier", var);
- return 1;
- }
-
- if (e->loc->next == (struct block *) 0) {
- internal_errorf(0, "c_getopts: no argv");
- return 1;
- }
- /* Which arguments are we parsing... */
- if (*wp == (char *) 0)
- wp = e->loc->next->argv;
- else
- *--wp = e->loc->next->argv[0];
-
- /* Check that our saved state won't cause a core dump... */
- for (argc = 0; wp[argc]; argc++)
- ;
- if (user_opt.optind > argc
- || (user_opt.p != 0
- && user_opt.p > strlen(wp[user_opt.optind - 1])))
- {
- bi_errorf("arguments changed since last call");
- return 1;
- }
-
- user_opt.optarg = (char *) 0;
- optc = ksh_getopt(wp, &user_opt, options);
-
- if (optc >= 0 && optc != '?' && (user_opt.info & GI_PLUS)) {
- buf[0] = '+';
- buf[1] = optc;
- buf[2] = '\0';
- } else {
- /* POSIX says var is set to ? at end-of-options, at&t ksh
- * sets it to null - we go with POSIX...
- */
- buf[0] = optc < 0 ? '?' : optc;
- buf[1] = '\0';
- }
-
- /* at&t ksh does not change OPTIND if it was an unknown option.
- * Scripts counting on this are prone to break... (ie, don't count
- * on this staying).
- */
- if (optc != '?') {
- getopts_noset = 1;
- setint(global("OPTIND"), (long) user_opt.optind);
- getopts_noset = 0;
- }
-
- if (user_opt.optarg == (char *) 0)
- unset(global("OPTARG"), 0);
- else
- setstr(global("OPTARG"), user_opt.optarg);
-
- vq = global(var);
- if (vq->flag & RDONLY) {
- bi_errorf("%s is readonly", var);
- return 1;
- }
- if (Flag(FEXPORT))
- typeset(var, EXPORT, 0, 0, 0);
- setstr(vq, buf);
-
- return optc < 0 ? 1 : 0;
-}
-
-#ifdef EMACS
-int
-c_bind(wp)
- char **wp;
-{
- int rv = 0, macro = 0, list = 0;
- register char *cp;
- int optc;
-
- while ((optc = ksh_getopt(wp, &builtin_opt, "lm")) != EOF)
- switch (optc) {
- case 'l':
- list = 1;
- break;
- case 'm':
- macro = 1;
- break;
- case '?':
- return 1;
- }
- wp += builtin_opt.optind;
-
- if (*wp == NULL) /* list all */
- rv = x_bind((char*)NULL, (char*)NULL, 0, list);
-
- for (; *wp != NULL; wp++) {
- cp = strchr(*wp, '=');
- if (cp != NULL)
- *cp++ = '\0';
- if (x_bind(*wp, cp, macro, 0))
- rv = 1;
- }
-
- return rv;
-}
-#endif
-
-/* A leading = means assignments before command are kept;
- * a leading * means a POSIX special builtin;
- * a leading + means a POSIX regular builtin
- * (* and + should not be combined).
- */
-const struct builtin kshbuiltins [] = {
- {"+alias", c_alias}, /* no =: at&t manual wrong */
- {"+cd", c_cd},
- {"+command", c_command},
- {"echo", c_print},
- {"*=export", c_typeset},
-#ifdef HISTORY
- {"+fc", c_fc},
-#endif /* HISTORY */
- {"+getopts", c_getopts},
- {"+jobs", c_jobs},
- {"+kill", c_kill},
-#ifdef KSH
- {"let", c_let},
-#endif /* KSH */
- {"print", c_print},
- {"pwd", c_pwd},
- {"*=readonly", c_typeset},
- {"=typeset", c_typeset},
- {"+unalias", c_unalias},
- {"whence", c_whence},
-#ifdef JOBS
- {"+bg", c_fgbg},
- {"+fg", c_fgbg},
-#endif
-#ifdef EMACS
- {"bind", c_bind},
-#endif
- {NULL, NULL}
-};
diff --git a/bin/pdksh/c_sh.c b/bin/pdksh/c_sh.c
deleted file mode 100644
index 0691aa51af5..00000000000
--- a/bin/pdksh/c_sh.c
+++ /dev/null
@@ -1,787 +0,0 @@
-/* $OpenBSD: c_sh.c,v 1.6 1997/08/05 21:49:54 grr Exp $ */
-
-/*
- * built-in Bourne commands
- */
-
-#include "sh.h"
-#include "ksh_stat.h" /* umask() */
-#include "ksh_time.h"
-#include "ksh_times.h"
-
-static char *clocktos ARGS((clock_t t));
-
-/* :, false and true */
-int
-c_label(wp)
- char **wp;
-{
- return wp[0][0] == 'f' ? 1 : 0;
-}
-
-int
-c_shift(wp)
- char **wp;
-{
- register struct block *l = e->loc;
- register int n;
- long val;
- char *arg;
-
- if (ksh_getopt(wp, &builtin_opt, null) == '?')
- return 1;
- arg = wp[builtin_opt.optind];
-
- if (arg) {
- evaluate(arg, &val, FALSE);
- n = val;
- } else
- n = 1;
- if (n < 0) {
- bi_errorf("%s: bad number", arg);
- return (1);
- }
- if (l->argc < n) {
- bi_errorf("nothing to shift");
- return (1);
- }
- l->argv[n] = l->argv[0];
- l->argv += n;
- l->argc -= n;
- return 0;
-}
-
-int
-c_umask(wp)
- char **wp;
-{
- register int i;
- register char *cp;
- int symbolic = 0;
- int old_umask;
- int optc;
-
- while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != EOF)
- switch (optc) {
- case 'S':
- symbolic = 1;
- break;
- case '?':
- return 1;
- }
- cp = wp[builtin_opt.optind];
- if (cp == NULL) {
- old_umask = umask(0);
- umask(old_umask);
- if (symbolic) {
- char buf[18];
- int j;
-
- old_umask = ~old_umask;
- cp = buf;
- for (i = 0; i < 3; i++) {
- *cp++ = "ugo"[i];
- *cp++ = '=';
- for (j = 0; j < 3; j++)
- if (old_umask & (1 << (8 - (3*i + j))))
- *cp++ = "rwx"[j];
- *cp++ = ',';
- }
- cp[-1] = '\0';
- shprintf("%s\n", buf);
- } else
- shprintf("%#3.3o\n", old_umask);
- } else {
- int new_umask;
-
- if (digit(*cp)) {
- for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++)
- new_umask = new_umask * 8 + (*cp - '0');
- if (*cp) {
- bi_errorf("bad number");
- return 1;
- }
- } else {
- /* symbolic format */
- int positions, new_val;
- char op;
-
- old_umask = umask(0);
- umask(old_umask); /* in case of error */
- old_umask = ~old_umask;
- new_umask = old_umask;
- positions = 0;
- while (*cp) {
- while (*cp && strchr("augo", *cp))
- switch (*cp++) {
- case 'a': positions |= 0111; break;
- case 'u': positions |= 0100; break;
- case 'g': positions |= 0010; break;
- case 'o': positions |= 0001; break;
- }
- if (!positions)
- positions = 0111; /* default is a */
- if (!strchr("=+-", op = *cp))
- break;
- cp++;
- new_val = 0;
- while (*cp && strchr("rwxugoXs", *cp))
- switch (*cp++) {
- case 'r': new_val |= 04; break;
- case 'w': new_val |= 02; break;
- case 'x': new_val |= 01; break;
- case 'u': new_val |= old_umask >> 6;
- break;
- case 'g': new_val |= old_umask >> 3;
- break;
- case 'o': new_val |= old_umask >> 0;
- break;
- case 'X': if (old_umask & 0111)
- new_val |= 01;
- break;
- case 's': /* ignored */
- break;
- }
- new_val = (new_val & 07) * positions;
- switch (op) {
- case '-':
- new_umask &= ~new_val;
- break;
- case '=':
- new_umask = new_val
- | (new_umask & ~(positions * 07));
- break;
- case '+':
- new_umask |= new_val;
- }
- if (*cp == ',') {
- positions = 0;
- cp++;
- } else if (!strchr("=+-", *cp))
- break;
- }
- if (*cp) {
- bi_errorf("bad mask");
- return 1;
- }
- new_umask = ~new_umask;
- }
- umask(new_umask);
- }
- return 0;
-}
-
-int
-c_dot(wp)
- char **wp;
-{
- char *file, *cp;
- char **argv;
- int argc;
- int i;
-
- if (ksh_getopt(wp, &builtin_opt, null) == '?')
- return 1;
-
- if ((cp = wp[builtin_opt.optind]) == NULL)
- return 0;
- file = search(cp, path, R_OK, (int *) 0);
- if (file == NULL) {
- bi_errorf("%s: not found", cp);
- return 1;
- }
-
- /* Set positional parameters? */
- if (wp[builtin_opt.optind + 1]) {
- argv = wp + builtin_opt.optind;
- argv[0] = e->loc->argv[0]; /* preserve $0 */
- for (argc = 0; argv[argc + 1]; argc++)
- ;
- } else {
- argc = 0;
- argv = (char **) 0;
- }
- i = include(file, argc, argv, 0);
- if (i < 0) { /* should not happen */
- bi_errorf("%s: %s", cp, strerror(errno));
- return 1;
- }
- return i;
-}
-
-int
-c_wait(wp)
- char **wp;
-{
- int UNINITIALIZED(rv);
- int sig;
-
- if (ksh_getopt(wp, &builtin_opt, null) == '?')
- return 1;
- wp += builtin_opt.optind;
- if (*wp == (char *) 0) {
- while (waitfor((char *) 0, &sig) >= 0)
- ;
- rv = sig;
- } else {
- for (; *wp; wp++)
- rv = waitfor(*wp, &sig);
- if (rv < 0)
- rv = sig ? sig : 127; /* magic exit code: bad job-id */
- }
- return rv;
-}
-
-int
-c_read(wp)
- char **wp;
-{
- register int c = 0;
- int expand = 1, history = 0;
- int expanding;
- int ecode = 0;
- register char *cp;
- int fd = 0;
- struct shf *shf;
- int optc;
- const char *emsg;
- XString cs, xs;
- struct tbl *vp;
- char UNINITIALIZED(*xp);
-
- while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != EOF)
- switch (optc) {
-#ifdef KSH
- case 'p':
- if ((fd = coproc_getfd(R_OK, &emsg)) < 0) {
- bi_errorf("-p: %s", emsg);
- return 1;
- }
- break;
-#endif /* KSH */
- case 'r':
- expand = 0;
- break;
- case 's':
- history = 1;
- break;
- case 'u':
- if (!*(cp = builtin_opt.optarg))
- fd = 0;
- else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) {
- bi_errorf("-u: %s: %s", cp, emsg);
- return 1;
- }
- break;
- case '?':
- return 1;
- }
- wp += builtin_opt.optind;
-
- if (*wp == NULL)
- *--wp = "REPLY";
-
- /* Since we can't necessarily seek backwards on non-regular files,
- * don't buffer them so we can't read too much.
- */
- shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare);
-
- if ((cp = strchr(*wp, '?')) != NULL) {
- *cp = 0;
- if (isatty(fd)) {
- /* at&t ksh says it prints prompt on fd if it's open
- * for writing and is a tty, but it doesn't do it
- * (it also doesn't check the interactive flag,
- * as is indicated in the Kornshell book).
- */
- shellf("%s", cp+1);
- }
- }
-
-#ifdef KSH
- /* If we are reading from the co-process for the first time,
- * make sure the other side of the pipe is closed first. This allows
- * the detection of eof.
- *
- * This is not compatiable with at&t ksh... the fd is kept so another
- * coproc can be started with same ouput, however, this means eof
- * can't be detected... This is why it is closed here.
- * If this call is removed, remove the eof check below, too.
- * coproc_readw_close(fd);
- */
-#endif /* KSH */
-
- if (history)
- Xinit(xs, xp, 128, ATEMP);
- expanding = 0;
- Xinit(cs, cp, 128, ATEMP);
- for (; *wp != NULL; wp++) {
- for (cp = Xstring(cs, cp); ; ) {
- if (c == '\n' || c == EOF)
- break;
- while (1) {
- c = shf_getc(shf);
- if (c == '\0'
-#ifdef OS2
- || c == '\r'
-#endif /* OS2 */
- )
- continue;
- if (c == EOF && shf_error(shf)
- && shf_errno(shf) == EINTR)
- {
- /* Was the offending signal one that
- * would normally kill a process?
- * If so, pretend the read was killed.
- */
- ecode = fatal_trap_check();
-
- /* non fatal (eg, CHLD), carry on */
- if (!ecode) {
- shf_clearerr(shf);
- continue;
- }
- }
- break;
- }
- if (history) {
- Xcheck(xs, xp);
- Xput(xs, xp, c);
- }
- Xcheck(cs, cp);
- if (expanding) {
- expanding = 0;
- if (c == '\n') {
- c = 0;
- if (Flag(FTALKING) && isatty(fd)) {
- /* set prompt in case this is
- * called from .profile or $ENV
- */
- set_prompt(PS2, (Source *) 0);
- pprompt(prompt, 0);
- }
- } else if (c != EOF)
- Xput(cs, cp, c);
- continue;
- }
- if (expand && c == '\\') {
- expanding = 1;
- continue;
- }
- if (c == '\n' || c == EOF)
- break;
- if (ctype(c, C_IFS)) {
- if (Xlength(cs, cp) == 0 && ctype(c, C_IFSWS))
- continue;
- if (wp[1])
- break;
- }
- Xput(cs, cp, c);
- }
- /* strip trailing IFS white space from last variable */
- if (!wp[1])
- while (Xlength(cs, cp) && ctype(cp[-1], C_IFS)
- && ctype(cp[-1], C_IFSWS))
- cp--;
- Xput(cs, cp, '\0');
- vp = global(*wp);
- if (vp->flag & RDONLY) {
- shf_flush(shf);
- bi_errorf("%s is read only", *wp);
- return 1;
- }
- if (Flag(FEXPORT))
- typeset(*wp, EXPORT, 0, 0, 0);
- setstr(vp, Xstring(cs, cp));
- }
-
- shf_flush(shf);
- if (history) {
- Xput(xs, xp, '\0');
- source->line++;
- histsave(source->line, Xstring(xs, xp), 1);
- Xfree(xs, xp);
- }
-#ifdef KSH
- /* if this is the co-process fd, close the file descriptor
- * (can get eof if and only if all processes are have died, ie,
- * coproc.njobs is 0 and the pipe is closed).
- */
- if (c == EOF && !ecode)
- coproc_read_close(fd);
-#endif /* KSH */
-
- return ecode ? ecode : c == EOF;
-}
-
-int
-c_eval(wp)
- char **wp;
-{
- register struct source *s;
-
- if (ksh_getopt(wp, &builtin_opt, null) == '?')
- return 1;
- s = pushs(SWORDS, ATEMP);
- s->u.strv = wp + builtin_opt.optind;
- return shell(s, FALSE);
-}
-
-int
-c_trap(wp)
- char **wp;
-{
- int i;
- char *s;
- register Trap *p;
-
- if (ksh_getopt(wp, &builtin_opt, null) == '?')
- return 1;
- wp += builtin_opt.optind;
-
- if (*wp == NULL) {
- int anydfl = 0;
-
- for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) {
- if (p->trap == NULL)
- anydfl = 1;
- else {
- shprintf("trap -- ");
- print_value_quoted(p->trap);
- shprintf(" %s\n", p->name);
- }
- }
-#if 0 /* this is ugly and not clear POSIX needs it */
- /* POSIX may need this so output of trap can be saved and
- * used to restore trap conditions
- */
- if (anydfl) {
- shprintf("trap -- -");
- for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
- if (p->trap == NULL && p->name)
- shprintf(" %s", p->name);
- shprintf(newline);
- }
-#endif
- return 0;
- }
-
- s = (gettrap(*wp) == NULL) ? *wp++ : NULL; /* get command */
- if (s != NULL && s[0] == '-' && s[1] == '\0')
- s = NULL;
-
- /* set/clear traps */
- while (*wp != NULL) {
- p = gettrap(*wp++);
- if (p == NULL) {
- bi_errorf("bad signal %s", wp[-1]);
- return 1;
- }
- settrap(p, s);
- }
- return 0;
-}
-
-int
-c_exitreturn(wp)
- char **wp;
-{
- int how = LEXIT;
- char *arg;
-
- if (ksh_getopt(wp, &builtin_opt, null) == '?')
- return 1;
- arg = wp[builtin_opt.optind];
-
- if (arg != NULL && !getn(arg, &exstat)) {
- exstat = 1;
- warningf(TRUE, "%s: bad number", arg);
- }
- if (wp[0][0] == 'r') { /* return */
- struct env *ep;
-
- /* need to tell if this is exit or return so trap exit will
- * work right (POSIX)
- */
- for (ep = e; ep; ep = ep->oenv)
- if (STOP_RETURN(ep->type)) {
- how = LRETURN;
- break;
- }
- }
-
- if (how == LEXIT && !really_exit && j_stopped_running()) {
- really_exit = 1;
- how = LSHELL;
- }
-
- quitenv(); /* get rid of any i/o redirections */
- unwind(how);
- /*NOTREACHED*/
- return 0;
-}
-
-int
-c_brkcont(wp)
- char **wp;
-{
- int n, quit;
- struct env *ep, *last_ep = (struct env *) 0;
- char *arg;
-
- if (ksh_getopt(wp, &builtin_opt, null) == '?')
- return 1;
- arg = wp[builtin_opt.optind];
-
- if (!arg)
- n = 1;
- else if (!bi_getn(arg, &n))
- return 1;
- quit = n;
- if (quit <= 0) {
- /* at&t ksh does this for non-interactive shells only - weird */
- bi_errorf("%s: bad value", arg);
- return 1;
- }
-
- /* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */
- for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv)
- if (ep->type == E_LOOP) {
- if (--quit == 0)
- break;
- ep->flags |= EF_BRKCONT_PASS;
- last_ep = ep;
- }
-
- if (quit) {
- /* at&t ksh doesn't print a message - just does what it
- * can. We print a message 'cause it helps in debugging
- * scripts, but don't generate an error (ie, keep going).
- */
- if (n == quit) {
- warningf(TRUE, "%s: cannot %s", wp[0], wp[0]);
- return 0;
- }
- /* POSIX says if n is too big, the last enclosing loop
- * shall be used. Doesn't say to print an error but we
- * do anyway 'cause the user messed up.
- */
- last_ep->flags &= ~EF_BRKCONT_PASS;
- warningf(TRUE, "%s: can only %s %d level(s)",
- wp[0], wp[0], n - quit);
- }
-
- unwind(*wp[0] == 'b' ? LBREAK : LCONTIN);
- /*NOTREACHED*/
-}
-
-int
-c_set(wp)
- char **wp;
-{
- int argi, setargs;
- struct block *l = e->loc;
- register char **owp = wp;
-
- if (wp[1] == NULL) {
- static const char *const args [] = { "set", "-", NULL };
- return c_typeset((char **) args);
- }
-
- argi = parse_args(wp, OF_SET, &setargs);
- if (argi < 0)
- return 1;
- /* set $# and $* */
- if (setargs) {
- owp = wp += argi - 1;
- wp[0] = l->argv[0]; /* save $0 */
- while (*++wp != NULL)
- *wp = str_save(*wp, &l->area);
- l->argc = wp - owp - 1;
- l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area);
- for (wp = l->argv; (*wp++ = *owp++) != NULL; )
- ;
- }
- /* POSIX says set exit status is 0, but old scripts that use
- * getopt(1), use the construct: set -- `getopt ab:c "$@"`
- * which assumes the exit value set will be that of the ``
- * (subst_exstat is cleared in execute() so that it will be 0
- * if there are no command substitutions).
- */
- return Flag(FPOSIX) ? 0 : subst_exstat;
-}
-
-int
-c_unset(wp)
- char **wp;
-{
- register char *id;
- int optc, unset_var = 1;
- int ret = 0;
-
- while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != EOF)
- switch (optc) {
- case 'f':
- unset_var = 0;
- break;
- case 'v':
- unset_var = 1;
- break;
- case '?':
- return 1;
- }
- wp += builtin_opt.optind;
- for (; (id = *wp) != NULL; wp++)
- if (unset_var) { /* unset variable */
- struct tbl *vp = global(id);
-
- if (!(vp->flag & ISSET))
- ret = 1;
- if ((vp->flag&RDONLY)) {
- bi_errorf("%s is read only", vp->name);
- return 1;
- }
- unset(vp, strchr(id, '[') ? 1 : 0);
- } else { /* unset function */
- if (define(id, (struct op *) NULL))
- ret = 1;
- }
- return ret;
-}
-
-int
-c_times(wp)
- char **wp;
-{
- struct tms all;
-
- (void) ksh_times(&all);
- shprintf("Shell: %8s user ", clocktos(all.tms_utime));
- shprintf("%8s system\n", clocktos(all.tms_stime));
- shprintf("Kids: %8s user ", clocktos(all.tms_cutime));
- shprintf("%8s system\n", clocktos(all.tms_cstime));
-
- return 0;
-}
-
-/*
- * time pipeline (really a statement, not a built-in command)
- */
-int
-timex(t, f)
- struct op *t;
- int f;
-{
- int rv;
- struct tms t0, t1;
- clock_t t0t, t1t;
- extern clock_t j_usrtime, j_systime; /* computed by j_wait */
-
- j_usrtime = j_systime = 0;
- t0t = ksh_times(&t0);
- rv = execute(t->left, f);
- t1t = ksh_times(&t1);
-
- shf_fprintf(shl_out, "%8s real ", clocktos(t1t - t0t));
- shf_fprintf(shl_out, "%8s user ",
- clocktos(t1.tms_utime - t0.tms_utime + j_usrtime));
- shf_fprintf(shl_out, "%8s system ",
- clocktos(t1.tms_stime - t0.tms_stime + j_systime));
- shf_fprintf(shl_out, newline);
-
- return rv;
-}
-
-static char *
-clocktos(t)
- clock_t t;
-{
- static char temp[20];
- register int i;
- register char *cp = temp + sizeof(temp);
-
- if (CLK_TCK != 100) /* convert to 1/100'ths */
- t = (t < 1000000000/CLK_TCK) ?
- (t * 100) / CLK_TCK : (t / CLK_TCK) * 100;
-
- *--cp = '\0';
- *--cp = 's';
- for (i = -2; i <= 0 || t > 0; i++) {
- if (i == 0)
- *--cp = '.';
- *--cp = '0' + (char)(t%10);
- t /= 10;
- }
- return cp;
-}
-
-/* exec with no args - args case is taken care of in comexec() */
-int
-c_exec(wp)
- char ** wp;
-{
- int i;
-
- /* make sure redirects stay in place */
- if (e->savefd != NULL) {
- for (i = 0; i < NUFILE; i++) {
- if (e->savefd[i] > 0)
- close(e->savefd[i]);
- /* keep anything > 2 private */
- if (!Flag(FSH) && i > 2 && e->savefd[i])
- fd_clexec(i);
- }
- e->savefd = NULL;
- }
- return 0;
-}
-
-/* dummy function, special case in comexec() */
-int
-c_builtin(wp)
- char ** wp;
-{
- return 0;
-}
-
-extern int c_test ARGS((char **wp)); /* in c_test.c */
-extern int c_ulimit ARGS((char **wp)); /* in c_ulimit.c */
-
-/* A leading = means assignments before command are kept;
- * a leading * means a POSIX special builtin;
- * a leading + means a POSIX regular builtin
- * (* and + should not be combined).
- */
-const struct builtin shbuiltins [] = {
- {"*=.", c_dot},
- {"*=:", c_label},
- {"[", c_test},
- {"*=break", c_brkcont},
- {"=builtin", c_builtin},
- {"*=continue", c_brkcont},
- {"*=eval", c_eval},
- {"*=exec", c_exec},
- {"*=exit", c_exitreturn},
- {"+false", c_label},
- {"*=return", c_exitreturn},
- {"*=set", c_set},
- {"*=shift", c_shift},
- {"=times", c_times},
- {"*=trap", c_trap},
- {"+=wait", c_wait},
- {"+read", c_read},
- {"test", c_test},
- {"+true", c_label},
- {"ulimit", c_ulimit},
- {"+umask", c_umask},
- {"*=unset", c_unset},
-#ifdef OS2
- /* In OS2, the first line of a file can be "extproc name", which
- * tells the command interpreter (cmd.exe) to use name to execute
- * the file. For this to be useful, ksh must ignore commands
- * starting with extproc and this does the trick...
- */
- {"extproc", c_label},
-#endif /* OS2 */
- {NULL, NULL}
-};
diff --git a/bin/pdksh/c_test.c b/bin/pdksh/c_test.c
deleted file mode 100644
index 16703ff4960..00000000000
--- a/bin/pdksh/c_test.c
+++ /dev/null
@@ -1,616 +0,0 @@
-/* $OpenBSD: c_test.c,v 1.4 1997/06/19 13:58:38 kstailey Exp $ */
-
-/*
- * test(1); version 7-like -- author Erik Baalbergen
- * modified by Eric Gisin to be used as built-in.
- * modified by Arnold Robbins to add SVR3 compatibility
- * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
- * modified by Michael Rendell to add Korn's [[ .. ]] expressions.
- * modified by J.T. Conklin to add POSIX compatibility.
- */
-
-#include "sh.h"
-#include "ksh_stat.h"
-#include "c_test.h"
-
-/* test(1) accepts the following grammar:
- oexpr ::= aexpr | aexpr "-o" oexpr ;
- aexpr ::= nexpr | nexpr "-a" aexpr ;
- nexpr ::= primary | "!" nexpr ;
- primary ::= unary-operator operand
- | operand binary-operator operand
- | operand
- | "(" oexpr ")"
- ;
-
- unary-operator ::= "-a"|"-r"|"-w"|"-x"|"-e"|"-f"|"-d"|"-c"|"-b"|"-p"|
- "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|
- "-L"|"-h"|"-S"|"-H";
-
- binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
- "-nt"|"-ot"|"-ef"|
- "<"|">" # rules used for [[ .. ]] expressions
- ;
- operand ::= <any thing>
-*/
-
-#define T_ERR_EXIT 2 /* POSIX says > 1 for errors */
-
-struct t_op {
- char op_text[4];
- Test_op op_num;
-};
-static const struct t_op u_ops [] = {
- {"-a", TO_FILAXST },
- {"-b", TO_FILBDEV },
- {"-c", TO_FILCDEV },
- {"-d", TO_FILID },
- {"-e", TO_FILEXST },
- {"-f", TO_FILREG },
- {"-G", TO_FILGID },
- {"-g", TO_FILSETG },
- {"-h", TO_FILSYM },
- {"-H", TO_FILCDF },
- {"-k", TO_FILSTCK },
- {"-L", TO_FILSYM },
- {"-n", TO_STNZE },
- {"-O", TO_FILUID },
- {"-o", TO_OPTION },
- {"-p", TO_FILFIFO },
- {"-r", TO_FILRD },
- {"-s", TO_FILGZ },
- {"-S", TO_FILSOCK },
- {"-t", TO_FILTT },
- {"-u", TO_FILSETU },
- {"-w", TO_FILWR },
- {"-x", TO_FILEX },
- {"-z", TO_STZER },
- {"", TO_NONOP }
- };
-static const struct t_op b_ops [] = {
- {"=", TO_STEQL },
-#ifdef KSH
- {"==", TO_STEQL },
-#endif /* KSH */
- {"!=", TO_STNEQ },
- {"<", TO_STLT },
- {">", TO_STGT },
- {"-eq", TO_INTEQ },
- {"-ne", TO_INTNE },
- {"-gt", TO_INTGT },
- {"-ge", TO_INTGE },
- {"-lt", TO_INTLT },
- {"-le", TO_INTLE },
- {"-ef", TO_FILEQ },
- {"-nt", TO_FILNT },
- {"-ot", TO_FILOT },
- {"", TO_NONOP }
- };
-
-static int test_stat ARGS((const char *path, struct stat *statb));
-static int test_eaccess ARGS((const char *path, int mode));
-static int test_oexpr ARGS((Test_env *te, int do_eval));
-static int test_aexpr ARGS((Test_env *te, int do_eval));
-static int test_nexpr ARGS((Test_env *te, int do_eval));
-static int test_primary ARGS((Test_env *te, int do_eval));
-static int ptest_isa ARGS((Test_env *te, Test_meta meta));
-static const char *ptest_getopnd ARGS((Test_env *te, Test_op op, int do_eval));
-static int ptest_eval ARGS((Test_env *te, Test_op op, const char *opnd1,
- const char *opnd2, int do_eval));
-static void ptest_error ARGS((Test_env *te, int offset, const char *msg));
-
-int
-c_test(wp)
- char **wp;
-{
- int argc;
- int res;
- Test_env te;
-
- te.flags = 0;
- te.isa = ptest_isa;
- te.getopnd = ptest_getopnd;
- te.eval = ptest_eval;
- te.error = ptest_error;
-
- for (argc = 0; wp[argc]; argc++)
- ;
-
- if (strcmp(wp[0], "[") == 0) {
- if (strcmp(wp[--argc], "]") != 0) {
- bi_errorf("missing ]");
- return T_ERR_EXIT;
- }
- }
-
- te.pos.wp = wp + 1;
- te.wp_end = wp + argc;
-
- /*
- * Handle the special cases from POSIX.2, section 4.62.4.
- * Implementation of all the rules isn't necessary since
- * our parser does the right thing for the ommited steps.
- */
- if (argc <= 5) {
- char **owp = wp;
- int invert = 0;
- Test_op op;
- const char *opnd1, *opnd2;
-
- while (--argc >= 0) {
- if ((*te.isa)(&te, TM_END))
- return !0;
- if (argc == 3) {
- opnd1 = (*te.getopnd)(&te, TO_NONOP, 1);
- if ((op = (Test_op) (*te.isa)(&te, TM_BINOP))) {
- opnd2 = (*te.getopnd)(&te, op, 1);
- res = (*te.eval)(&te, op, opnd1, opnd2,
- 1);
- if (te.flags & TEF_ERROR)
- return T_ERR_EXIT;
- if (invert & 1)
- res = !res;
- return !res;
- }
- /* back up to opnd1 */
- te.pos.wp--;
- }
- if (argc == 1) {
- opnd1 = (*te.getopnd)(&te, TO_NONOP, 1);
- res = (*te.eval)(&te, TO_STNZE, opnd1,
- (char *) 0, 1);
- if (invert & 1)
- res = !res;
- return !res;
- }
- if ((*te.isa)(&te, TM_NOT)) {
- invert++;
- } else
- break;
- }
- te.pos.wp = owp + 1;
- }
-
- return test_parse(&te);
-}
-
-/*
- * Generic test routines.
- */
-
-Test_op
-test_isop(te, meta, s)
- Test_env *te;
- Test_meta meta;
- const char *s;
-{
- char sc1;
- const struct t_op *otab;
-
- otab = meta == TM_UNOP ? u_ops : b_ops;
- if (*s) {
- sc1 = s[1];
- for (; otab->op_text[0]; otab++)
- if (sc1 == otab->op_text[1]
- && strcmp(s, otab->op_text) == 0
- && ((te->flags & TEF_DBRACKET)
- || (otab->op_num != TO_STLT
- && otab->op_num != TO_STGT)))
- return otab->op_num;
- }
- return TO_NONOP;
-}
-
-int
-test_eval(te, op, opnd1, opnd2, do_eval)
- Test_env *te;
- Test_op op;
- const char *opnd1;
- const char *opnd2;
- int do_eval;
-{
- int res;
- int not;
- struct stat b1, b2;
-
- if (!do_eval)
- return 0;
-
- switch ((int) op) {
- /*
- * Unary Operators
- */
- case TO_STNZE: /* -n */
- return *opnd1 != '\0';
- case TO_STZER: /* -z */
- return *opnd1 == '\0';
- case TO_OPTION: /* -o */
- if ((not = *opnd1 == '!'))
- opnd1++;
- if ((res = option(opnd1)) < 0)
- res = 0;
- else {
- res = Flag(res);
- if (not)
- res = !res;
- }
- return res;
- case TO_FILRD: /* -r */
- return test_eaccess(opnd1, R_OK) == 0;
- case TO_FILWR: /* -w */
- return test_eaccess(opnd1, W_OK) == 0;
- case TO_FILEX: /* -x */
- return test_eaccess(opnd1, X_OK) == 0;
- case TO_FILAXST: /* -a */
- return test_stat(opnd1, &b1) == 0;
- case TO_FILEXST: /* -e */
- /* at&t ksh does not appear to do the /dev/fd/ thing for
- * this (unless the os itself handles it)
- */
- return stat(opnd1, &b1) == 0;
- case TO_FILREG: /* -r */
- return test_stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode);
- case TO_FILID: /* -d */
- return test_stat(opnd1, &b1) == 0 && S_ISDIR(b1.st_mode);
- case TO_FILCDEV: /* -c */
-#ifdef S_ISCHR
- return test_stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode);
-#else
- return 0;
-#endif
- case TO_FILBDEV: /* -b */
-#ifdef S_ISBLK
- return test_stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode);
-#else
- return 0;
-#endif
- case TO_FILFIFO: /* -p */
-#ifdef S_ISFIFO
- return test_stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode);
-#else
- return 0;
-#endif
- case TO_FILSYM: /* -h -L */
-#ifdef S_ISLNK
- return lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode);
-#else
- return 0;
-#endif
- case TO_FILSOCK: /* -S */
-#ifdef S_ISSOCK
- return test_stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode);
-#else
- return 0;
-#endif
- case TO_FILCDF:/* -H HP context dependent files (directories) */
-#ifdef S_ISCDF
- {
- /* Append a + to filename and check to see if result is a
- * setuid directory. CDF stuff in general is hookey, since
- * it breaks for the following sequence: echo hi > foo+;
- * mkdir foo; echo bye > foo/default; chmod u+s foo
- * (foo+ refers to the file with hi in it, there is no way
- * to get at the file with bye in it - please correct me if
- * I'm wrong about this).
- */
- int len = strlen(opnd1);
- char *p = str_nsave(opnd1, len + 1, ATEMP);
-
- p[len++] = '+';
- p[len] = '\0';
- return stat(p, &b1) == 0 && S_ISCDF(b1.st_mode);
- }
-#else
- return 0;
-#endif
- case TO_FILSETU: /* -u */
-#ifdef S_ISUID
- return test_stat(opnd1, &b1) == 0
- && (b1.st_mode & S_ISUID) == S_ISUID;
-#else
- return 0;
-#endif
- case TO_FILSETG: /* -g */
-#ifdef S_ISGID
- return test_stat(opnd1, &b1) == 0
- && (b1.st_mode & S_ISGID) == S_ISGID;
-#else
- return 0;
-#endif
- case TO_FILSTCK: /* -k */
- return test_stat(opnd1, &b1) == 0
- && (b1.st_mode & S_ISVTX) == S_ISVTX;
- case TO_FILGZ: /* -s */
- return test_stat(opnd1, &b1) == 0 && b1.st_size > 0L;
- case TO_FILTT: /* -t */
- if (opnd1 && !bi_getn(opnd1, &res)) {
- te->flags |= TEF_ERROR;
- res = 0;
- } else
- res = isatty(opnd1 ? res : 0);
- return res;
- case TO_FILUID: /* -O */
- return test_stat(opnd1, &b1) == 0 && b1.st_uid == geteuid();
- case TO_FILGID: /* -G */
- return test_stat(opnd1, &b1) == 0 && b1.st_gid == getegid();
- /*
- * Binary Operators
- */
- case TO_STEQL: /* = */
- if (te->flags & TEF_DBRACKET)
- return gmatch(opnd1, opnd2, FALSE);
- return strcmp(opnd1, opnd2) == 0;
- case TO_STNEQ: /* != */
- if (te->flags & TEF_DBRACKET)
- return !gmatch(opnd1, opnd2, FALSE);
- return strcmp(opnd1, opnd2) != 0;
- case TO_STLT: /* < */
- return strcmp(opnd1, opnd2) < 0;
- case TO_STGT: /* > */
- return strcmp(opnd1, opnd2) > 0;
- case TO_INTEQ: /* -eq */
- case TO_INTNE: /* -ne */
- case TO_INTGE: /* -ge */
- case TO_INTGT: /* -gt */
- case TO_INTLE: /* -le */
- case TO_INTLT: /* -lt */
- {
- long v1, v2;
-
- if (!evaluate(opnd1, &v1, TRUE)
- || !evaluate(opnd2, &v2, TRUE))
- {
- /* error already printed.. */
- te->flags |= TEF_ERROR;
- return 1;
- }
- switch ((int) op) {
- case TO_INTEQ:
- return v1 == v2;
- case TO_INTNE:
- return v1 != v2;
- case TO_INTGE:
- return v1 >= v2;
- case TO_INTGT:
- return v1 > v2;
- case TO_INTLE:
- return v1 <= v2;
- case TO_INTLT:
- return v1 < v2;
- }
- }
- case TO_FILNT: /* -nt */
- return stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0
- && b1.st_mtime > b2.st_mtime;
- case TO_FILOT: /* -ot */
- return stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0
- && b1.st_mtime < b2.st_mtime;
- case TO_FILEQ: /* -ef */
- return stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0
- && b1.st_dev == b2.st_dev
- && b1.st_ino == b2.st_ino;
- }
- (*te->error)(te, 0, "internal error: unknown op");
- return 1;
-}
-
-/* Nasty kludge to handle Korn's bizarre /dev/fd hack */
-static int
-test_stat(path, statb)
- const char *path;
- struct stat *statb;
-{
-#if !defined(HAVE_DEV_FD)
- int fd;
-
- if (strncmp(path, "/dev/fd/", 8) == 0 && getn(path + 8, &fd))
- return fstat(fd, statb);
-#endif /* !HAVE_DEV_FD */
-
- return stat(path, statb);
-}
-
-/* Another nasty kludge to handle Korn's bizarre /dev/fd hack */
-static int
-test_eaccess(path, mode)
- const char *path;
- int mode;
-{
-#if !defined(HAVE_DEV_FD)
- int fd;
-
- if (strncmp(path, "/dev/fd/", 8) == 0 && getn(path + 8, &fd)) {
- int flags;
-
- if ((flags = fcntl(fd, F_GETFL, 0)) < 0
- || (mode & X_OK)
- || ((mode & W_OK) && (flags & O_ACCMODE) == O_RDONLY)
- || ((mode & R_OK) && (flags & O_ACCMODE) == O_WRONLY))
- return -1;
- return 0;
- }
-#endif /* !HAVE_DEV_FD */
-
- return eaccess(path, mode);
-}
-
-int
-test_parse(te)
- Test_env *te;
-{
- int res;
-
- res = test_oexpr(te, 1);
-
- if (!(te->flags & TEF_ERROR) && !(*te->isa)(te, TM_END))
- (*te->error)(te, 0, "unexpected operator/operand");
-
- return (te->flags & TEF_ERROR) ? T_ERR_EXIT : !res;
-}
-
-static int
-test_oexpr(te, do_eval)
- Test_env *te;
- int do_eval;
-{
- int res;
-
- res = test_aexpr(te, do_eval);
- if (res)
- do_eval = 0;
- if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_OR))
- return test_oexpr(te, do_eval) || res;
- return res;
-}
-
-static int
-test_aexpr(te, do_eval)
- Test_env *te;
- int do_eval;
-{
- int res;
-
- res = test_nexpr(te, do_eval);
- if (!res)
- do_eval = 0;
- if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_AND))
- return test_aexpr(te, do_eval) && res;
- return res;
-}
-
-static int
-test_nexpr(te, do_eval)
- Test_env *te;
- int do_eval;
-{
- if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_NOT))
- return !test_nexpr(te, do_eval);
- return test_primary(te, do_eval);
-}
-
-static int
-test_primary(te, do_eval)
- Test_env *te;
- int do_eval;
-{
- const char *opnd1, *opnd2;
- int res;
- Test_op op;
-
- if (te->flags & TEF_ERROR)
- return 0;
- if ((*te->isa)(te, TM_OPAREN)) {
- res = test_oexpr(te, do_eval);
- if (te->flags & TEF_ERROR)
- return 0;
- if (!(*te->isa)(te, TM_CPAREN)) {
- (*te->error)(te, 0, "missing closing paren");
- return 0;
- }
- return res;
- }
- if ((op = (Test_op) (*te->isa)(te, TM_UNOP))) {
- /* unary expression */
- opnd1 = (*te->getopnd)(te, op, do_eval);
- if (!opnd1) {
- (*te->error)(te, -1, "missing argument");
- return 0;
- }
-
- return (*te->eval)(te, op, opnd1, (const char *) 0, do_eval);
- }
- opnd1 = (*te->getopnd)(te, TO_NONOP, do_eval);
- if (!opnd1) {
- (*te->error)(te, 0, "expression expected");
- return 0;
- }
- if ((op = (Test_op) (*te->isa)(te, TM_BINOP))) {
- /* binary expression */
- opnd2 = (*te->getopnd)(te, op, do_eval);
- if (!opnd2) {
- (*te->error)(te, -1, "missing second argument");
- return 0;
- }
-
- return (*te->eval)(te, op, opnd1, opnd2, do_eval);
- }
- if (te->flags & TEF_DBRACKET) {
- (*te->error)(te, -1, "missing expression operator");
- return 0;
- }
- return (*te->eval)(te, TO_STNZE, opnd1, (const char *) 0, do_eval);
-}
-
-/*
- * Plain test (test and [ .. ]) specific routines.
- */
-
-/* Test if the current token is a whatever. Accepts the current token if
- * it is. Returns 0 if it is not, non-zero if it is (in the case of
- * TM_UNOP and TM_BINOP, the returned value is a Test_op).
- */
-static int
-ptest_isa(te, meta)
- Test_env *te;
- Test_meta meta;
-{
- /* Order important - indexed by Test_meta values */
- static const char *const tokens[] = {
- "-o", "-a", "!", "(", ")"
- };
- int ret;
-
- if (te->pos.wp >= te->wp_end)
- return meta == TM_END;
-
- if (meta == TM_UNOP || meta == TM_BINOP)
- ret = (int) test_isop(te, meta, *te->pos.wp);
- else if (meta == TM_END)
- ret = 0;
- else
- ret = strcmp(*te->pos.wp, tokens[(int) meta]) == 0;
-
- /* Accept the token? */
- if (ret)
- te->pos.wp++;
-
- return ret;
-}
-
-static const char *
-ptest_getopnd(te, op, do_eval)
- Test_env *te;
- Test_op op;
- int do_eval;
-{
- if (te->pos.wp >= te->wp_end)
- return op == TO_FILTT ? "1" : (const char *) 0;
- return *te->pos.wp++;
-}
-
-static int
-ptest_eval(te, op, opnd1, opnd2, do_eval)
- Test_env *te;
- Test_op op;
- const char *opnd1;
- const char *opnd2;
- int do_eval;
-{
- return test_eval(te, op, opnd1, opnd2, do_eval);
-}
-
-static void
-ptest_error(te, offset, msg)
- Test_env *te;
- int offset;
- const char *msg;
-{
- const char *op = te->pos.wp + offset >= te->wp_end ?
- (const char *) 0 : te->pos.wp[offset];
-
- te->flags |= TEF_ERROR;
- if (op)
- bi_errorf("%s: %s", op, msg);
- else
- bi_errorf("%s", msg);
-}
diff --git a/bin/pdksh/c_test.h b/bin/pdksh/c_test.h
deleted file mode 100644
index 0caf40b3dfc..00000000000
--- a/bin/pdksh/c_test.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* $OpenBSD: c_test.h,v 1.1 1996/08/14 06:19:10 downsj Exp $ */
-
-/* Various types of operations. Keeping things grouped nicely
- * (unary,binary) makes switch() statements more efficeint.
- */
-enum Test_op {
- TO_NONOP = 0, /* non-operator */
- /* unary operators */
- TO_STNZE, TO_STZER, TO_OPTION,
- TO_FILAXST,
- TO_FILEXST,
- TO_FILREG, TO_FILBDEV, TO_FILCDEV, TO_FILSYM, TO_FILFIFO, TO_FILSOCK,
- TO_FILCDF, TO_FILID, TO_FILGID, TO_FILSETG, TO_FILSTCK, TO_FILUID,
- TO_FILRD, TO_FILGZ, TO_FILTT, TO_FILSETU, TO_FILWR, TO_FILEX,
- /* binary operators */
- TO_STEQL, TO_STNEQ, TO_STLT, TO_STGT, TO_INTEQ, TO_INTNE, TO_INTGT,
- TO_INTGE, TO_INTLT, TO_INTLE, TO_FILEQ, TO_FILNT, TO_FILOT
-};
-typedef enum Test_op Test_op;
-
-/* Used by Test_env.isa() (order important - used to index *_tokens[] arrays) */
-enum Test_meta {
- TM_OR, /* -o or || */
- TM_AND, /* -a or && */
- TM_NOT, /* ! */
- TM_OPAREN, /* ( */
- TM_CPAREN, /* ) */
- TM_UNOP, /* unary operator */
- TM_BINOP, /* binary operator */
- TM_END /* end of input */
-};
-typedef enum Test_meta Test_meta;
-
-#define TEF_ERROR BIT(0) /* set if we've hit an error */
-#define TEF_DBRACKET BIT(1) /* set if [[ .. ]] test */
-
-typedef struct test_env Test_env;
-struct test_env {
- int flags; /* TEF_* */
- union {
- char **wp; /* used by ptest_* */
- XPtrV *av; /* used by dbtestp_* */
- } pos;
- char **wp_end; /* used by ptest_* */
- int (*isa) ARGS((Test_env *te, Test_meta meta));
- const char *(*getopnd) ARGS((Test_env *te, Test_op op, int do_eval));
- int (*eval) ARGS((Test_env *te, Test_op op, const char *opnd1,
- const char *opnd2, int do_eval));
- void (*error) ARGS((Test_env *te, int offset, const char *msg));
-};
-
-Test_op test_isop ARGS((Test_env *te, Test_meta meta, const char *s));
-int test_eval ARGS((Test_env *te, Test_op op, const char *opnd1,
- const char *opnd2, int do_eval));
-int test_parse ARGS((Test_env *te));
diff --git a/bin/pdksh/c_ulimit.c b/bin/pdksh/c_ulimit.c
deleted file mode 100644
index b96c10bf5b8..00000000000
--- a/bin/pdksh/c_ulimit.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/* $OpenBSD: c_ulimit.c,v 1.3 1997/06/19 13:58:39 kstailey Exp $ */
-
-/*
- ulimit -- handle "ulimit" builtin
-
- Reworked to use getrusage() and ulimit() at once (as needed on
- some schizophenic systems, eg, HP-UX 9.01), made argument parsing
- conform to at&t ksh, added autoconf support. Michael Rendell, May, '94
-
- Eric Gisin, September 1988
- Adapted to PD KornShell. Removed AT&T code.
-
- last edit: 06-Jun-1987 D A Gwyn
-
- This started out as the BRL UNIX System V system call emulation
- for 4.nBSD, and was later extended by Doug Kingston to handle
- the extended 4.nBSD resource limits. It now includes the code
- that was originally under case SYSULIMIT in source file "xec.c".
-*/
-
-#include "sh.h"
-#include "ksh_time.h"
-#ifdef HAVE_SYS_RESOURCE_H
-# include <sys/resource.h>
-#endif /* HAVE_SYS_RESOURCE_H */
-#ifdef HAVE_ULIMIT_H
-# include <ulimit.h>
-#else /* HAVE_ULIMIT_H */
-# ifdef HAVE_ULIMIT
-extern long ulimit();
-# endif /* HAVE_ULIMIT */
-#endif /* HAVE_ULIMIT_H */
-
-#define SOFT 0x1
-#define HARD 0x2
-
-int
-c_ulimit(wp)
- char **wp;
-{
- static const struct limits {
- const char *name;
- enum { RLIMIT, ULIMIT } which;
- int gcmd; /* get command */
- int scmd; /* set command (or -1, if no set command) */
- int factor; /* multiply by to get rlim_{cur,max} values */
- char option;
- } limits[] = {
- /* Do not use options -H, -S or -a */
-#ifdef RLIMIT_CPU
- { "time(cpu-seconds)", RLIMIT, RLIMIT_CPU, RLIMIT_CPU, 1, 't' },
-#endif
-#ifdef RLIMIT_FSIZE
- { "file(blocks)", RLIMIT, RLIMIT_FSIZE, RLIMIT_FSIZE, 512, 'f' },
-#else /* RLIMIT_FSIZE */
-# ifdef UL_GETFSIZE /* x/open */
- { "file(blocks)", ULIMIT, UL_GETFSIZE, UL_SETFSIZE, 1, 'f' },
-# else /* UL_GETFSIZE */
-# ifdef UL_GFILLIM /* svr4/xenix */
- { "file(blocks)", ULIMIT, UL_GFILLIM, UL_SFILLIM, 1, 'f' },
-# else /* UL_GFILLIM */
- { "file(blocks)", ULIMIT, 1, 2, 1, 'f' },
-# endif /* UL_GFILLIM */
-# endif /* UL_GETFSIZE */
-#endif /* RLIMIT_FSIZE */
-#ifdef RLIMIT_CORE
- { "coredump(blocks)", RLIMIT, RLIMIT_CORE, RLIMIT_CORE, 512, 'c' },
-#endif
-#ifdef RLIMIT_DATA
- { "data(kbytes)", RLIMIT, RLIMIT_DATA, RLIMIT_DATA, 1024, 'd' },
-#endif
-#ifdef RLIMIT_STACK
- { "stack(kbytes)", RLIMIT, RLIMIT_STACK, RLIMIT_STACK, 1024, 's' },
-#endif
-#ifdef RLIMIT_MEMLOCK
- { "lockedmem(kbytes)", RLIMIT, RLIMIT_MEMLOCK, RLIMIT_MEMLOCK, 1024, 'l' },
-#endif
-#ifdef RLIMIT_RSS
- { "memory(kbytes)", RLIMIT, RLIMIT_RSS, RLIMIT_RSS, 1024, 'm' },
-#endif
-#ifdef RLIMIT_NOFILE
- { "nofiles(descriptors)", RLIMIT, RLIMIT_NOFILE, RLIMIT_NOFILE, 1, 'n' },
-#else /* RLIMIT_NOFILE */
-# ifdef UL_GDESLIM /* svr4/xenix */
- { "nofiles(descriptors)", ULIMIT, UL_GDESLIM, -1, 1, 'n' },
-# endif /* UL_GDESLIM */
-#endif /* RLIMIT_NOFILE */
-#ifdef RLIMIT_NPROC
- { "processes", RLIMIT, RLIMIT_NPROC, RLIMIT_NPROC, 1, 'p' },
-#endif
-#ifdef RLIMIT_VMEM
- { "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' },
-#else /* RLIMIT_VMEM */
- /* These are not quite right - really should subtract etext or something */
-# ifdef UL_GMEMLIM /* svr4/xenix */
- { "vmemory(maxaddr)", ULIMIT, UL_GMEMLIM, -1, 1, 'v' },
-# else /* UL_GMEMLIM */
-# ifdef UL_GETBREAK /* osf/1 */
- { "vmemory(maxaddr)", ULIMIT, UL_GETBREAK, -1, 1, 'v' },
-# else /* UL_GETBREAK */
-# ifdef UL_GETMAXBRK /* hpux */
- { "vmemory(maxaddr)", ULIMIT, UL_GETMAXBRK, -1, 1, 'v' },
-# endif /* UL_GETMAXBRK */
-# endif /* UL_GETBREAK */
-# endif /* UL_GMEMLIM */
-#endif /* RLIMIT_VMEM */
-#ifdef RLIMIT_SWAP
- { "swap(kbytes)", RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' },
-#endif
- { (char *) 0 }
- };
- static char options[3 + NELEM(limits)];
- rlim_t UNINITIALIZED(val);
- int how = SOFT | HARD;
- const struct limits *l;
- int set, all = 0;
- int optc, what;
-#ifdef HAVE_SETRLIMIT
- struct rlimit limit;
-#endif /* HAVE_SETRLIMIT */
-
- if (!options[0]) {
- /* build options string on first call - yuck */
- char *p = options;
-
- *p++ = 'H'; *p++ = 'S'; *p++ = 'a';
- for (l = limits; l->name; l++)
- *p++ = l->option;
- *p = '\0';
- }
- what = 'f';
- while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
- switch (optc) {
- case 'H':
- how = HARD;
- break;
- case 'S':
- how = SOFT;
- break;
- case 'a':
- all = 1;
- break;
- case '?':
- return 1;
- default:
- what = optc;
- }
-
- for (l = limits; l->name && l->option != what; l++)
- ;
- if (!l->name) {
- internal_errorf(0, "ulimit: %c", what);
- return 1;
- }
-
- wp += builtin_opt.optind;
- set = *wp ? 1 : 0;
- if (set) {
- char *p = *wp;
-
- if (all || wp[1]) {
- bi_errorf("too many arguments");
- return 1;
- }
-#ifdef RLIM_INFINITY
- if (strcmp(p, "unlimited") == 0)
- val = RLIM_INFINITY;
- else
-#endif /* RLIM_INFINITY */
- {
- long rval;
-
- if (!evaluate(p, &rval, TRUE))
- return 1;
- val = rval * l->factor;
- }
- }
- if (all) {
- for (l = limits; l->name; l++) {
-#ifdef HAVE_SETRLIMIT
- if (l->which == RLIMIT) {
- getrlimit(l->gcmd, &limit);
- if (how & SOFT)
- val = limit.rlim_cur;
- else if (how & HARD)
- val = limit.rlim_max;
- } else
-#endif /* HAVE_SETRLIMIT */
-#ifdef HAVE_ULIMIT
- {
- val = ulimit(l->gcmd, (rlim_t) 0);
- }
-#else /* HAVE_ULIMIT */
- ;
-#endif /* HAVE_ULIMIT */
- shprintf("%-20s ", l->name);
-#ifdef RLIM_INFINITY
- if (val == RLIM_INFINITY)
- shprintf("unlimited\n");
- else
-#endif /* RLIM_INFINITY */
- {
- val /= l->factor;
- shprintf("%ld\n", (long) val);
- }
- }
- return 0;
- }
-#ifdef HAVE_SETRLIMIT
- if (l->which == RLIMIT) {
- getrlimit(l->gcmd, &limit);
- if (set) {
- if (how & SOFT)
- limit.rlim_cur = val;
- if (how & HARD)
- limit.rlim_max = val;
- if (setrlimit(l->scmd, &limit) < 0) {
- bi_errorf("bad limit: %s", strerror(errno));
- return 1;
- }
- } else {
- if (how & SOFT)
- val = limit.rlim_cur;
- else if (how & HARD)
- val = limit.rlim_max;
- }
- } else
-#endif /* HAVE_SETRLIMIT */
-#ifdef HAVE_ULIMIT
- {
- if (set) {
- if (l->scmd == -1) {
- bi_errorf("can't change limit");
- return 1;
- } else if (ulimit(l->scmd, val) < 0) {
- bi_errorf("bad limit: %s", strerror(errno));
- return 1;
- }
- } else
- val = ulimit(l->gcmd, (rlim_t) 0);
- }
-#else /* HAVE_ULIMIT */
- ;
-#endif /* HAVE_ULIMIT */
- if (!set) {
-#ifdef RLIM_INFINITY
- if (val == RLIM_INFINITY)
- shprintf("unlimited\n");
- else
-#endif /* RLIM_INFINITY */
- {
- val /= l->factor;
- shprintf("%ld\n", (long) val);
- }
- }
- return 0;
-}
diff --git a/bin/pdksh/conf-end.h b/bin/pdksh/conf-end.h
deleted file mode 100644
index 8b65cb7d1df..00000000000
--- a/bin/pdksh/conf-end.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* $OpenBSD: conf-end.h,v 1.2 1996/08/25 12:37:58 downsj Exp $ */
-
-/*
- * End of configuration stuff for PD ksh.
- */
-
-#if defined(EMACS) || defined(VI)
-# define EDIT
-#else
-# undef EDIT
-#endif
-
-/* Super small configuration-- no editing. */
-#if defined(EDIT) && defined(NOEDIT)
-# undef EDIT
-# undef EMACS
-# undef VI
-#endif
-
-/* Editing implies history */
-#if defined(EDIT) && !defined(HISTORY)
-# define HISTORY
-#endif /* EDIT */
-
-/*
- * if you don't have mmap() you can't use Peter Collinson's history
- * mechanism. If that is the case, then define EASY_HISTORY
- */
-#if defined(HISTORY) && (!defined(COMPLEX_HISTORY) || !defined(HAVE_MMAP) || !defined(HAVE_FLOCK))
-# undef COMPLEX_HISTORY
-# define EASY_HISTORY /* sjg's trivial history file */
-#endif
-
-/* Can we safely catch sigchld and wait for processes? */
-#if (defined(HAVE_WAITPID) || defined(HAVE_WAIT3)) \
- && (defined(POSIX_SIGNALS) || defined(BSD42_SIGNALS))
-# define JOB_SIGS
-#endif
-
-#if !defined(JOB_SIGS) || !(defined(POSIX_PGRP) || defined(BSD_PGRP))
-# undef JOBS /* if no JOB_SIGS, no job control support */
-#endif
-
-/* pdksh assumes system calls return EINTR if a signal happened (this so
- * the signal handler doesn't have to longjmp()). I don't know if this
- * happens (or can be made to happen) with sigset() et. al. (the bsd41 signal
- * routines), so, the autoconf stuff checks what they do and defines
- * SIGNALS_DONT_INTERRUPT if signals don't interrupt read().
- * If SIGNALS_DONT_INTERRUPT isn't defined and your compiler chokes on this,
- * delete the hash in front of the error (and file a bug report).
- */
-#ifdef SIGNALS_DONT_INTERRUPT
- # error pdksh needs interruptable system calls.
-#endif /* SIGNALS_DONT_INTERRUPT */
-
-#ifdef HAVE_GCC_FUNC_ATTR
-# define GCC_FUNC_ATTR(x) __attribute__((x))
-# define GCC_FUNC_ATTR2(x,y) __attribute__((x,y))
-#else
-# define GCC_FUNC_ATTR(x)
-# define GCC_FUNC_ATTR2(x,y)
-#endif /* HAVE_GCC_FUNC_ATTR */
diff --git a/bin/pdksh/config.h b/bin/pdksh/config.h
deleted file mode 100644
index c949a254ee2..00000000000
--- a/bin/pdksh/config.h
+++ /dev/null
@@ -1,351 +0,0 @@
-/* $OpenBSD: config.h,v 1.2 1996/08/25 11:56:34 downsj Exp $ */
-
-/* config.h. Generated automatically by configure. */
-/* config.h.in. Generated automatically from configure.in by autoheader. */
-/*
- * This file, acconfig.h, which is a part of pdksh (the public domain ksh),
- * is placed in the public domain. It comes with no licence, warranty
- * or guarantee of any kind (i.e., at your own risk).
- */
-
-#ifndef CONFIG_H
-#define CONFIG_H
-
-
-/* Define if on AIX 3.
- System headers sometimes define this.
- We just want to avoid a redefinition error message. */
-#ifndef _ALL_SOURCE
-/* #undef _ALL_SOURCE */
-#endif
-
-/* Define if the closedir function returns void instead of int. */
-/* #undef CLOSEDIR_VOID */
-
-/* Define to empty if the keyword does not work. */
-/* #undef const */
-
-
-/* Define to `int' if <sys/types.h> doesn't define. */
-/* #undef gid_t */
-
-/* Define if you have a working `mmap' system call. */
-#define HAVE_MMAP 1
-
-/* Define if your struct stat has st_rdev. */
-#define HAVE_ST_RDEV 1
-
-/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
-#define HAVE_SYS_WAIT_H 1
-
-/* Define if you have <unistd.h>. */
-#define HAVE_UNISTD_H 1
-
-/* Define if on MINIX. */
-/* #undef _MINIX */
-
-/* Define to `int' if <sys/types.h> doesn't define. */
-/* #undef mode_t */
-
-/* Define to `long' if <sys/types.h> doesn't define. */
-/* #undef off_t */
-
-/* Define to `int' if <sys/types.h> doesn't define. */
-/* #undef pid_t */
-
-/* Define if the system does not provide POSIX.1 features except
- with this defined. */
-/* #undef _POSIX_1_SOURCE */
-
-/* Define if you need to in order for stat and other things to work. */
-/* #undef _POSIX_SOURCE */
-
-/* Define as the return type of signal handlers (int or void). */
-#define RETSIGTYPE void
-
-/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
-/* #undef STAT_MACROS_BROKEN */
-
-/* Define if `sys_siglist' is declared by <signal.h>. */
-#define SYS_SIGLIST_DECLARED 1
-
-/* Define if you can safely include both <sys/time.h> and <time.h>. */
-#define TIME_WITH_SYS_TIME 1
-
-/* Define to `int' if <sys/types.h> doesn't define. */
-/* #undef uid_t */
-
-/* Define if the closedir function returns void instead of int. */
-/* #undef VOID_CLOSEDIR */
-
-/* Define if your kernal doesn't handle scripts starting with #! */
-/* #undef SHARPBANG */
-
-/* Define if dup2() preserves the close-on-exec flag (ultrix does this) */
-/* #undef DUP2_BROKEN */
-
-/* Define as the return value of signal handlers (0 or ). */
-#define RETSIGVAL
-
-/* Define if you have posix signal routines (sigaction(), et. al.) */
-#define POSIX_SIGNALS 1
-
-/* Define if you have BSD4.2 signal routines (sigsetmask(), et. al.) */
-/* #undef BSD42_SIGNALS */
-
-/* Define if you have BSD4.1 signal routines (sigset(), et. al.) */
-/* #undef BSD41_SIGNALS */
-
-/* Define if you have v7 signal routines (signal(), signal reset on delivery) */
-/* #undef V7_SIGNALS */
-
-/* Define to use the fake posix signal routines (sigact.[ch]) */
-/* #undef USE_FAKE_SIGACT */
-
-/* Define if signals don't interrupt read() */
-/* #undef SIGNALS_DONT_INTERRUPT */
-
-/* Define if you have bsd versions of the setpgrp() and getpgrp() routines */
-/* #undef BSD_PGRP */
-
-/* Define if you have POSIX versions of the setpgid() and getpgrp() routines */
-#define POSIX_PGRP 1
-
-/* Define if you have sysV versions of the setpgrp() and getpgrp() routines */
-/* #undef SYSV_PGRP */
-
-/* Define if you don't have setpgrp(), setpgid() or getpgrp() routines */
-/* #undef NO_PGRP */
-
-/* Define to char if your compiler doesn't like the void keyword */
-/* #undef void */
-
-/* Define to nothing if compiler doesn't like the volatile keyword */
-/* #undef volatile */
-
-/* Define if C compiler groks function prototypes */
-#define HAVE_PROTOTYPES 1
-
-/* Define if C compiler groks __attribute__((...)) (const, noreturn, format) */
-#define HAVE_GCC_FUNC_ATTR 1
-
-/* Define to 32-bit signed integer type if <sys/types.h> doesn't define */
-/* #undef clock_t */
-
-/* Define to the type of struct rlimit fields if the rlim_t type is missing */
-/* #undef rlim_t */
-
-/* Define if time() is declared in <time.h> */
-#define TIME_DECLARED 1
-
-/* Define to `unsigned' if <signal.h> doesn't define */
-/* #undef sigset_t */
-
-/* Define if sys_errlist[] and sys_nerr are in the C library */
-#define HAVE_SYS_ERRLIST 1
-
-/* Define if sys_errlist[] and sys_nerr are defined in <errno.h> */
-#define SYS_ERRLIST_DECLARED 1
-
-/* Define if sys_siglist[] is in the C library */
-#define HAVE_SYS_SIGLIST 1
-
-/* Define if you have a sane <termios.h> header file */
-#define HAVE_TERMIOS_H 1
-
-/* Define if you have a memset() function in your C library */
-#define HAVE_MEMSET 1
-
-/* Define if you have a memmove() function in your C library */
-#define HAVE_MEMMOVE 1
-
-/* Define if you have a bcopy() function in your C library */
-/* #undef HAVE_BCOPY */
-
-/* Define if you have a lstat() function in your C library */
-#define HAVE_LSTAT 1
-
-/* Define if you have a sane <termio.h> header file */
-/* #undef HAVE_TERMIO_H */
-
-/* Define if you don't have times() or if it always returns 0 */
-/* #undef TIMES_BROKEN */
-
-/* Define if opendir() will open non-directory files */
-/* #undef OPENDIR_DOES_NONDIR */
-
-/* Define if the pgrp of setpgrp() can't be the pid of a zombie process */
-/* #undef NEED_PGRP_SYNC */
-
-/* Define if you arg running SCO unix */
-/* #undef OS_SCO */
-
-/* Define if you arg running ISC unix */
-/* #undef OS_ISC */
-
-/* Define if you arg running OS2 with the EMX library */
-/* #undef OS2 */
-
-/* Define if you have a POSIX.1 compatiable <sys/wait.h> */
-#define POSIX_SYS_WAIT 1
-
-/* Define if your OS maps references to /dev/fd/n to file descriptor n */
-#define HAVE_DEV_FD 1
-
-/* Default PATH (see comments in configure.in for more details) */
-#define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb"
-
-/* Include ksh features? (see comments in configure.in for more details) */
-/* #define KSH 1 */
-
-/* Include emacs editing? (see comments in configure.in for more details) */
-#define EMACS 1
-
-/* Include vi editing? (see comments in configure.in for more details) */
-#define VI 1
-
-/* Include job control? (see comments in configure.in for more details) */
-#define JOBS 1
-
-/* Include brace-expansion? (see comments in configure.in for more details) */
-#define BRACE_EXPAND 1
-
-/* Include any history? (see comments in configure.in for more details) */
-#define HISTORY 1
-
-/* Include complex history? (see comments in configure.in for more details) */
-/* #undef COMPLEX_HISTORY */
-
-/* Strict POSIX behaviour? (see comments in configure.in for more details) */
-/* #undef POSIXLY_CORRECT */
-
-/* Specify default $ENV? (see comments in configure.in for more details) */
-/* #undef DEFAULT_ENV */
-
-/* Include shl(1) support? (see comments in configure.in for more details) */
-/* #undef SWTCH */
-
-/* Include game-of-life? (see comments in configure.in for more details) */
-/* #undef SILLY */
-
-/* The number of bytes in a int. */
-#define SIZEOF_INT 4
-
-/* The number of bytes in a long. */
-#if defined(alpha)
-#define SIZEOF_LONG 8
-#else
-#define SIZEOF_LONG 4
-#endif
-
-/* Define if you have the _setjmp function. */
-/* #undef HAVE__SETJMP */
-
-/* Define if you have the confstr function. */
-#define HAVE_CONFSTR 1
-
-/* Define if you have the flock function. */
-#define HAVE_FLOCK 1
-
-/* Define if you have the getgroups function. */
-/* #undef HAVE_GETGROUPS */
-
-/* Define if you have the getrusage function. */
-/* #undef HAVE_GETRUSAGE */
-
-/* Define if you have the getwd function. */
-#define HAVE_GETWD 1
-
-/* Define if you have the killpg function. */
-#define HAVE_KILLPG 1
-
-/* Define if you have the nice function. */
-#define HAVE_NICE 1
-
-/* Define if you have the setrlimit function. */
-#define HAVE_SETRLIMIT 1
-
-/* Define if you have the sigsetjmp function. */
-#define HAVE_SIGSETJMP 1
-
-/* Define if you have the strcasecmp function. */
-#define HAVE_STRCASECMP 1
-
-/* Define if you have the strerror function. */
-#define HAVE_STRERROR 1
-
-/* Define if you have the strstr function. */
-#define HAVE_STRSTR 1
-
-/* Define if you have the sysconf function. */
-#define HAVE_SYSCONF 1
-
-/* Define if you have the tcsetpgrp function. */
-#define HAVE_TCSETPGRP 1
-
-/* Define if you have the ulimit function. */
-/* #undef HAVE_ULIMIT */
-
-/* Define if you have the wait3 function. */
-#define HAVE_WAIT3 1
-
-/* Define if you have the waitpid function. */
-#define HAVE_WAITPID 1
-
-/* Define if you have the <dirent.h> header file. */
-#define HAVE_DIRENT_H 1
-
-/* Define if you have the <fcntl.h> header file. */
-#define HAVE_FCNTL_H 1
-
-/* Define if you have the <limits.h> header file. */
-#define HAVE_LIMITS_H 1
-
-/* Define if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define if you have the <ndir.h> header file. */
-/* #undef HAVE_NDIR_H */
-
-/* Define if you have the <paths.h> header file. */
-#define HAVE_PATHS_H 1
-
-/* Define if you have the <stddef.h> header file. */
-#define HAVE_STDDEF_H 1
-
-/* Define if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define if you have the <sys/dir.h> header file. */
-/* #undef HAVE_SYS_DIR_H */
-
-/* Define if you have the <sys/ndir.h> header file. */
-/* #undef HAVE_SYS_NDIR_H */
-
-/* Define if you have the <sys/param.h> header file. */
-#define HAVE_SYS_PARAM_H 1
-
-/* Define if you have the <sys/resource.h> header file. */
-#define HAVE_SYS_RESOURCE_H 1
-
-/* Define if you have the <sys/time.h> header file. */
-#define HAVE_SYS_TIME_H 1
-
-/* Define if you have the <sys/wait.h> header file. */
-#define HAVE_SYS_WAIT_H 1
-
-/* Define if you have the <ulimit.h> header file. */
-/* #undef HAVE_ULIMIT_H */
-
-/* Define if you have the <values.h> header file. */
-/* #undef HAVE_VALUES_H */
-
-/* Need to use a separate file to keep the configure script from commenting
- * out the undefs....
- */
-#include "conf-end.h"
-
-#endif /* CONFIG_H */
diff --git a/bin/pdksh/edit.c b/bin/pdksh/edit.c
deleted file mode 100644
index 2d4b96b4d0f..00000000000
--- a/bin/pdksh/edit.c
+++ /dev/null
@@ -1,1013 +0,0 @@
-/* $OpenBSD: edit.c,v 1.6 1997/06/19 13:58:39 kstailey Exp $ */
-
-/*
- * Command line editing - common code
- *
- */
-
-#include "config.h"
-#ifdef EDIT
-
-#include "sh.h"
-#include "tty.h"
-#define EXTERN
-#include "edit.h"
-#undef EXTERN
-#ifdef OS_SCO /* SCO Unix 3.2v4.1 */
-# include <sys/stream.h> /* needed for <sys/ptem.h> */
-# include <sys/ptem.h> /* needed for struct winsize */
-#endif /* OS_SCO */
-#include <sys/ioctl.h>
-#include <ctype.h>
-#include "ksh_stat.h"
-
-
-#if defined(TIOCGWINSZ)
-static RETSIGTYPE x_sigwinch ARGS((int sig));
-static int got_sigwinch;
-static void check_sigwinch ARGS((void));
-#endif /* TIOCGWINSZ */
-
-static int x_file_glob ARGS((int flags, const char *str, int slen,
- char ***wordsp));
-static int x_command_glob ARGS((int flags, const char *str, int slen,
- char ***wordsp));
-static int x_locate_word ARGS((const char *buf, int buflen, int pos,
- int *startp, int *is_command));
-
-static char vdisable_c;
-
-
-/* Called from main */
-void
-x_init()
-{
- /* set to -1 to force initial binding */
- edchars.erase = edchars.kill = edchars.intr = edchars.quit
- = edchars.eof = -1;
- /* default value for deficient systems */
- edchars.werase = 027; /* ^W */
-
-#ifdef TIOCGWINSZ
-# ifdef SIGWINCH
- if (setsig(&sigtraps[SIGWINCH], x_sigwinch, SS_RESTORE_ORIG|SS_SHTRAP))
- sigtraps[SIGWINCH].flags |= TF_SHELL_USES;
-# endif /* SIGWINCH */
- got_sigwinch = 1; /* force initial check */
- check_sigwinch();
-#endif /* TIOCGWINSZ */
-
-#ifdef EMACS
- x_init_emacs();
-#endif /* EMACS */
-
- /* Bizarreness to figure out how to disable
- * a struct termios.c_cc[] char
- */
-#ifdef _POSIX_VDISABLE
- if (_POSIX_VDISABLE >= 0)
- vdisable_c = (char) _POSIX_VDISABLE;
- else
- /* `feature not available' */
- vdisable_c = (char) 0377;
-#else
-# if defined(HAVE_PATHCONF) && defined(_PC_VDISABLE)
- vdisable_c = fpathconf(tty_fd, _PC_VDISABLE);
-# else
- vdisable_c = (char) 0377; /* default to old BSD value */
-# endif
-#endif /* _POSIX_VDISABLE */
-}
-
-#if defined(TIOCGWINSZ)
-static RETSIGTYPE
-x_sigwinch(sig)
- int sig;
-{
- got_sigwinch = 1;
- return RETSIGVAL;
-}
-
-static void
-check_sigwinch ARGS((void))
-{
- if (got_sigwinch) {
- struct winsize ws;
-
- got_sigwinch = 0;
- if (procpid == kshpid && ioctl(tty_fd, TIOCGWINSZ, &ws) >= 0) {
- struct tbl *vp;
-
- /* Do NOT export COLUMNS/LINES. Many applications
- * check COLUMNS/LINES before checking ws.ws_col/row,
- * so if the app is started with C/L in the environ
- * and the window is then resized, the app won't
- * see the change cause the environ doesn't change.
- */
- if (ws.ws_col) {
- x_cols = ws.ws_col < MIN_COLS ? MIN_COLS
- : ws.ws_col;
-
- if ((vp = typeset("COLUMNS", 0, 0, 0, 0)))
- setint(vp, (long) ws.ws_col);
- }
- if (ws.ws_row
- && (vp = typeset("LINES", 0, 0, 0, 0)))
- setint(vp, (long) ws.ws_row);
- }
- }
-}
-#endif /* TIOCGWINSZ */
-
-/*
- * read an edited command line
- */
-int
-x_read(buf, len)
- char *buf;
- size_t len;
-{
- int i;
-
-#if defined(TIOCGWINSZ)
- if (got_sigwinch)
- check_sigwinch();
-#endif /* TIOCGWINSZ */
-
- x_mode(TRUE);
-#ifdef EMACS
- if (Flag(FEMACS) || Flag(FGMACS))
- i = x_emacs(buf, len);
- else
-#endif
-#ifdef VI
- if (Flag(FVI))
- i = x_vi(buf, len);
- else
-#endif
- i = -1; /* internal error */
- x_mode(FALSE);
- return i;
-}
-
-/* tty I/O */
-
-int
-x_getc()
-{
-#ifdef OS2
- unsigned char c = _read_kbd(0, 1, 0);
- return c == 0 ? 0xE0 : c;
-#else /* OS2 */
- char c;
- int n;
-
- while ((n = blocking_read(0, &c, 1)) < 0 && errno == EINTR)
- if (trap) {
- x_mode(FALSE);
- runtraps(0);
- x_mode(TRUE);
- }
- if (n != 1)
- return -1;
- return (int) (unsigned char) c;
-#endif /* OS2 */
-}
-
-void
-x_flush()
-{
- shf_flush(shl_out);
-}
-
-void
-x_putc(c)
- int c;
-{
- shf_putc(c, shl_out);
-}
-
-void
-x_puts(s)
- const char *s;
-{
- while (*s != 0)
- shf_putc(*s++, shl_out);
-}
-
-bool_t
-x_mode(onoff)
- bool_t onoff;
-{
- static bool_t x_cur_mode;
- bool_t prev;
-
- if (x_cur_mode == onoff)
- return x_cur_mode;
- prev = x_cur_mode;
- x_cur_mode = onoff;
-
- if (onoff) {
- TTY_state cb;
- X_chars oldchars;
-
- oldchars = edchars;
- cb = tty_state;
-
-#if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H)
- edchars.erase = cb.c_cc[VERASE];
- edchars.kill = cb.c_cc[VKILL];
- edchars.intr = cb.c_cc[VINTR];
- edchars.quit = cb.c_cc[VQUIT];
- edchars.eof = cb.c_cc[VEOF];
-# ifdef VWERASE
- edchars.werase = cb.c_cc[VWERASE];
-# endif
-# ifdef _CRAY2 /* brain-damaged terminal handler */
- cb.c_lflag &= ~(ICANON|ECHO);
- /* rely on print routine to map '\n' to CR,LF */
-# else
- cb.c_iflag &= ~(INLCR|ICRNL);
-# ifdef _BSD_SYSV /* need to force CBREAK instead of RAW (need CRMOD on output) */
- cb.c_lflag &= ~(ICANON|ECHO);
-# else
-# ifdef SWTCH /* need CBREAK to handle swtch char */
- cb.c_lflag &= ~(ICANON|ECHO);
- cb.c_lflag |= ISIG;
- cb.c_cc[VINTR] = vdisable_c;
- cb.c_cc[VQUIT] = vdisable_c;
-# else
- cb.c_lflag &= ~(ISIG|ICANON|ECHO);
-# endif
-# endif
-# ifdef VLNEXT
- /* osf/1 processes lnext when ~icanon */
- cb.c_cc[VLNEXT] = vdisable_c;
-# endif /* VLNEXT */
-# ifdef VDISCARD
- /* sunos 4.1.x & osf/1 processes discard(flush) when ~icanon */
- cb.c_cc[VDISCARD] = vdisable_c;
-# endif /* VDISCARD */
- cb.c_cc[VTIME] = 0;
- cb.c_cc[VMIN] = 1;
-# endif /* _CRAY2 */
-#else
- /* Assume BSD tty stuff. */
- edchars.erase = cb.sgttyb.sg_erase;
- edchars.kill = cb.sgttyb.sg_kill;
- cb.sgttyb.sg_flags &= ~ECHO;
- cb.sgttyb.sg_flags |= CBREAK;
-# ifdef TIOCGATC
- edchars.intr = cb.lchars.tc_intrc;
- edchars.quit = cb.lchars.tc_quitc;
- edchars.eof = cb.lchars.tc_eofc;
- edchars.werase = cb.lchars.tc_werasc;
- cb.lchars.tc_suspc = -1;
- cb.lchars.tc_dsuspc = -1;
- cb.lchars.tc_lnextc = -1;
- cb.lchars.tc_statc = -1;
- cb.lchars.tc_intrc = -1;
- cb.lchars.tc_quitc = -1;
- cb.lchars.tc_rprntc = -1;
-# else
- edchars.intr = cb.tchars.t_intrc;
- edchars.quit = cb.tchars.t_quitc;
- edchars.eof = cb.tchars.t_eofc;
- cb.tchars.t_intrc = -1;
- cb.tchars.t_quitc = -1;
-# ifdef TIOCGLTC
- edchars.werase = cb.ltchars.t_werasc;
- cb.ltchars.t_suspc = -1;
- cb.ltchars.t_dsuspc = -1;
- cb.ltchars.t_lnextc = -1;
- cb.ltchars.t_rprntc = -1;
-# endif
-# endif /* TIOCGATC */
-#endif /* HAVE_TERMIOS_H || HAVE_TERMIO_H */
-
- set_tty(tty_fd, &cb, TF_WAIT);
-
- if (memcmp(&edchars, &oldchars, sizeof(edchars)) != 0) {
-#ifdef EMACS
- x_emacs_keys(&edchars);
-#endif
- }
- } else
- /* TF_WAIT doesn't seem to be necessary when leaving xmode */
- set_tty(tty_fd, &tty_state, TF_NONE);
-
- return prev;
-}
-
-/* NAME:
- * promptlen - calculate the length of PS1 etc.
- *
- * DESCRIPTION:
- * This function is based on a fix from guy@demon.co.uk
- * It fixes a bug in that if PS1 contains '!', the length
- * given by strlen() is probably wrong.
- *
- * RETURN VALUE:
- * length
- */
-int
-promptlen(cp, spp)
- const char *cp;
- const char **spp;
-{
- int count = 0;
- const char *sp = cp;
- char delimiter = 0;
- int indelimit = 0;
-
- /* Undocumented AT&T ksh feature:
- * If the second char in the prompt string is \r then the first char
- * is taken to be a non-printing delimiter and any chars between two
- * instances of the delimiter are not considered to be part of the
- * prompt length
- */
- if (*cp && cp[1] == '\r') {
- delimiter = *cp;
- cp += 2;
- }
-
- for (; *cp; cp++) {
- if (indelimit && *cp != delimiter)
- ;
- else if (*cp == '\n' || *cp == '\r') {
- count = 0;
- sp = cp + 1;
- } else if (*cp == '\t') {
- count = (count | 7) + 1;
- } else if (*cp == '\b') {
- if (count > 0)
- count--;
- } else if (*cp == delimiter)
- indelimit = !indelimit;
- else
- count++;
- }
- if (spp)
- *spp = sp;
- return count;
-}
-
-void
-set_editmode(ed)
- const char *ed;
-{
- static const enum sh_flag edit_flags[] = {
-#ifdef EMACS
- FEMACS, FGMACS,
-#endif
-#ifdef VI
- FVI,
-#endif
- };
- char *rcp;
- int i;
-
- if ((rcp = ksh_strrchr_dirsep(ed)))
- ed = ++rcp;
- for (i = 0; i < NELEM(edit_flags); i++)
- if (strstr(ed, options[(int) edit_flags[i]].name)) {
- change_flag(edit_flags[i], OF_SPECIAL, 1);
- return;
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* Misc common code for vi/emacs */
-
-/* Handle the commenting/uncommenting of a line.
- * Returns:
- * 1 if a carriage return is indicated (comment added)
- * 0 if no return (comment removed)
- * -1 if there is an error (not enough room for comment chars)
- * If successful, *lenp contains the new length. Note: cursor should be
- * moved to the start of the line after (un)commenting.
- */
-int
-x_do_comment(buf, bsize, lenp)
- char *buf;
- int bsize;
- int *lenp;
-{
- int i, j;
- int len = *lenp;
-
- if (len == 0)
- return 1; /* somewhat arbitrary - it's what at&t ksh does */
-
- /* Already commented? */
- if (buf[0] == '#') {
- int saw_nl = 0;
-
- for (j = 0, i = 1; i < len; i++) {
- if (!saw_nl || buf[i] != '#')
- buf[j++] = buf[i];
- saw_nl = buf[i] == '\n';
- }
- *lenp = j;
- return 0;
- } else {
- int n = 1;
-
- /* See if there's room for the #'s - 1 per \n */
- for (i = 0; i < len; i++)
- if (buf[i] == '\n')
- n++;
- if (len + n >= bsize)
- return -1;
- /* Now add them... */
- for (i = len, j = len + n; --i >= 0; ) {
- if (buf[i] == '\n')
- buf[--j] = '#';
- buf[--j] = buf[i];
- }
- buf[0] = '#';
- *lenp += n;
- return 1;
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* Common file/command completion code for vi/emacs */
-
-
-static char *add_glob ARGS((const char *str, int slen));
-static void glob_table ARGS((const char *pat, XPtrV *wp, struct table *tp));
-static void glob_path ARGS((int flags, const char *pat, XPtrV *wp,
- const char *path));
-
-#if 0 /* not used... */
-int x_complete_word ARGS((const char *str, int slen, int is_command,
- int *multiple, char **ret));
-int
-x_complete_word(str, slen, is_command, nwordsp, ret)
- const char *str;
- int slen;
- int is_command;
- int *nwordsp;
- char **ret;
-{
- int nwords;
- int prefix_len;
- char **words;
-
- nwords = (is_command ? x_command_glob : x_file_glob)(XCF_FULLPATH,
- str, slen, &words);
- *nwordsp = nwords;
- if (nwords == 0) {
- *ret = (char *) 0;
- return -1;
- }
-
- prefix_len = x_longest_prefix(nwords, words);
- *ret = str_nsave(words[0], prefix_len, ATEMP);
- x_free_words(nwords, words);
- return prefix_len;
-}
-#endif /* 0 */
-
-void
-x_print_expansions(nwords, words, is_command)
- int nwords;
- char *const *words;
- int is_command;
-{
- int use_copy = 0;
- int prefix_len;
- XPtrV l;
-
- /* Check if all matches are in the same directory (in this
- * case, we want to omitt the directory name)
- */
- if (!is_command
- && (prefix_len = x_longest_prefix(nwords, words)) > 0)
- {
- int i;
-
- /* Special case for 1 match (prefix is whole word) */
- if (nwords == 1)
- prefix_len = x_basename(words[0], (char *) 0);
- /* Any (non-trailing) slashes in non-common word suffixes? */
- for (i = 0; i < nwords; i++)
- if (x_basename(words[i] + prefix_len, (char *) 0)
- > prefix_len)
- break;
- /* All in same directory? */
- if (i == nwords) {
- while (prefix_len > 0
- && !ISDIRSEP(words[0][prefix_len - 1]))
- prefix_len--;
- use_copy = 1;
- XPinit(l, nwords + 1);
- for (i = 0; i < nwords; i++)
- XPput(l, words[i] + prefix_len);
- XPput(l, (char *) 0);
- }
- }
-
- /*
- * Enumerate expansions
- */
- x_putc('\r');
- x_putc('\n');
- pr_menu(use_copy ? (char **) XPptrv(l) : words);
-
- if (use_copy)
- XPfree(l); /* not x_free_words() */
-}
-
-/*
- * Do file globbing:
- * - appends * to (copy of) str if no globbing chars found
- * - does expansion, checks for no match, etc.
- * - sets *wordsp to array of matching strings
- * - returns number of matching strings
- */
-static int
-x_file_glob(flags, str, slen, wordsp)
- int flags;
- const char *str;
- int slen;
- char ***wordsp;
-{
- char *toglob;
- char **words;
- int nwords;
- XPtrV w;
- struct source *s, *sold;
-
- if (slen < 0)
- return 0;
-
- toglob = add_glob(str, slen);
-
- /*
- * Convert "foo*" (toglob) to an array of strings (words)
- */
- sold = source;
- s = pushs(SWSTR, ATEMP);
- s->start = s->str = toglob;
- source = s;
- if (yylex(ONEWORD) != LWORD) {
- source = sold;
- internal_errorf(0, "fileglob: substitute error");
- return 0;
- }
- source = sold;
- XPinit(w, 32);
- expand(yylval.cp, &w, DOGLOB|DOTILDE|DOMARKDIRS);
- XPput(w, NULL);
- words = (char **) XPclose(w);
-
- for (nwords = 0; words[nwords]; nwords++)
- ;
- if (nwords == 1) {
- struct stat statb;
-
- /* Check if globbing failed (returned glob pattern),
- * but be careful (E.g. toglob == "ab*" when the file
- * "ab*" exists is not an error).
- * Also, check for empty result - happens if we tried
- * to glob something which evaluated to an empty
- * string (e.g., "$FOO" when there is no FOO, etc).
- */
- if ((strcmp(words[0], toglob) == 0
- && stat(words[0], &statb) < 0)
- || words[0][0] == '\0')
- {
- x_free_words(nwords, words);
- nwords = 0;
- }
- }
- afree(toglob, ATEMP);
-
- *wordsp = nwords ? words : (char **) 0;
-
- return nwords;
-}
-
-/* Data structure used in x_command_glob() */
-struct path_order_info {
- char *word;
- int base;
- int path_order;
-};
-
-/* Compare routine used in x_command_glob() */
-static int
-path_order_cmp(aa, bb)
- const void *aa;
- const void *bb;
-{
- const struct path_order_info *a = (const struct path_order_info *) aa;
- const struct path_order_info *b = (const struct path_order_info *) bb;
- int t;
-
- t = FILECMP(a->word + a->base, b->word + b->base);
- return t ? t : a->path_order - b->path_order;
-}
-
-static int
-x_command_glob(flags, str, slen, wordsp)
- int flags;
- const char *str;
- int slen;
- char ***wordsp;
-{
- char *toglob;
- char *pat;
- char *fpath;
- int nwords;
- XPtrV w;
- struct block *l;
-
- if (slen < 0)
- return 0;
-
- toglob = add_glob(str, slen);
-
- /* Convert "foo*" (toglob) to a pattern for future use */
- pat = evalstr(toglob, DOPAT|DOTILDE);
- afree(toglob, ATEMP);
-
- XPinit(w, 32);
-
- glob_table(pat, &w, &keywords);
- glob_table(pat, &w, &aliases);
- glob_table(pat, &w, &builtins);
- for (l = e->loc; l; l = l->next)
- glob_table(pat, &w, &l->funs);
-
- glob_path(flags, pat, &w, path);
- if ((fpath = str_val(global("FPATH"))) != null)
- glob_path(flags, pat, &w, fpath);
-
- nwords = XPsize(w);
-
- if (!nwords) {
- *wordsp = (char **) 0;
- XPfree(w);
- return 0;
- }
-
- /* Sort entries */
- if (flags & XCF_FULLPATH) {
- /* Sort by basename, then path order */
- struct path_order_info *info;
- struct path_order_info *last_info = 0;
- char **words = (char **) XPptrv(w);
- int path_order = 0;
- int i;
-
- info = (struct path_order_info *)
- alloc(sizeof(struct path_order_info) * nwords, ATEMP);
- for (i = 0; i < nwords; i++) {
- info[i].word = words[i];
- info[i].base = x_basename(words[i], (char *) 0);
- if (!last_info || info[i].base != last_info->base
- || FILENCMP(words[i],
- last_info->word, info[i].base) != 0)
- {
- last_info = &info[i];
- path_order++;
- }
- info[i].path_order = path_order;
- }
- qsort(info, nwords, sizeof(struct path_order_info),
- path_order_cmp);
- for (i = 0; i < nwords; i++)
- words[i] = info[i].word;
- afree((void *) info, ATEMP);
- } else {
- /* Sort and remove duplicate entries */
- char **words = (char **) XPptrv(w);
- int i, j;
-
- qsortp(XPptrv(w), (size_t) nwords, xstrcmp);
-
- for (i = j = 0; i < nwords - 1; i++) {
- if (strcmp(words[i], words[i + 1]))
- words[j++] = words[i];
- else
- afree(words[i], ATEMP);
- }
- words[j++] = words[i];
- nwords = j;
- w.cur = (void **) &words[j];
- }
-
- XPput(w, NULL);
- *wordsp = (char **) XPclose(w);
-
- return nwords;
-}
-
-#define IS_WORDC(c) !isspace(c)
-
-static int
-x_locate_word(buf, buflen, pos, startp, is_commandp)
- const char *buf;
- int buflen;
- int pos;
- int *startp;
- int *is_commandp;
-{
- int p;
- int start, end;
-
- /* Bad call? Probably should report error */
- if (pos < 0 || pos > buflen) {
- *startp = pos;
- *is_commandp = 0;
- return 0;
- }
-
- if (pos == buflen) {
- if (pos == 0) { /* empty buffer? */
- *startp = pos;
- *is_commandp = 1;
- return 0;
- }
- pos--;
- }
-
- start = pos;
- /* Keep going backwards to start of word (has effect of allowing
- * one blank after the end of a word)
- */
- for (; start > 0 && IS_WORDC(buf[start - 1]); start--)
- ;
- /* Go forwards to end of word */
- for (end = start; end < buflen && IS_WORDC(buf[end]); end++)
- ;
-
- if (is_commandp) {
- int iscmd;
-
- /* Figure out if this is a command */
- for (p = start - 1; p >= 0 && isspace(buf[p]); p--)
- ;
- iscmd = p < 0 || strchr(";|&()", buf[p]);
- if (iscmd) {
- /* If command has a /, path, etc. is not searched;
- * only current directory is searched, which is just
- * like file globbing.
- */
- for (p = start; p < end; p++)
- if (ISDIRSEP(buf[p]))
- break;
- iscmd = p == end;
- }
- *is_commandp = iscmd;
- }
-
- *startp = start;
-
- return end - start;
-}
-
-int
-x_cf_glob(flags, buf, buflen, pos, startp, endp, wordsp, is_commandp)
- int flags;
- const char *buf;
- int buflen;
- int pos;
- int *startp;
- int *endp;
- char ***wordsp;
- int *is_commandp;
-{
- int len;
- int nwords;
- char **words;
- int is_command;
-
- len = x_locate_word(buf, buflen, pos, startp, &is_command);
- if (!(flags & XCF_COMMAND))
- is_command = 0;
- /* Don't do command globing on zero length strings - it takes too
- * long and isn't very useful. File globs are more likely to be
- * useful, so allow these.
- */
- if (len == 0 && is_command)
- return 0;
-
- nwords = (is_command ? x_command_glob : x_file_glob)(flags,
- buf + *startp, len, &words);
- if (nwords == 0) {
- *wordsp = (char **) 0;
- return 0;
- }
-
- if (is_commandp)
- *is_commandp = is_command;
- *wordsp = words;
- *endp = *startp + len;
-
- return nwords;
-}
-
-/* Given a string, copy it and possibly add a '*' to the end. The
- * new string is returned.
- */
-static char *
-add_glob(str, slen)
- const char *str;
- int slen;
-{
- char *toglob;
- char *s;
- bool_t saw_slash = FALSE;
-
- if (slen < 0)
- return (char *) 0;
-
- toglob = str_nsave(str, slen + 1, ATEMP); /* + 1 for "*" */
- toglob[slen] = '\0';
-
- /*
- * If the pathname contains a wildcard (an unquoted '*',
- * '?', or '[') or parameter expansion ('$'), or a ~username
- * with no trailing slash, then it is globbed based on that
- * value (i.e., without the appended '*').
- */
- for (s = toglob; *s; s++) {
- if (*s == '\\' && s[1])
- s++;
- else if (*s == '*' || *s == '[' || *s == '?' || *s == '$'
- || (s[1] == '(' /*)*/ && strchr("*+?@!", *s)))
- break;
- else if (ISDIRSEP(*s))
- saw_slash = TRUE;
- }
- if (!*s && (*toglob != '~' || saw_slash)) {
- toglob[slen] = '*';
- toglob[slen + 1] = '\0';
- }
-
- return toglob;
-}
-
-/*
- * Find longest common prefix
- */
-int
-x_longest_prefix(nwords, words)
- int nwords;
- char *const *words;
-{
- int i, j;
- int prefix_len;
- char *p;
-
- if (nwords <= 0)
- return 0;
-
- prefix_len = strlen(words[0]);
- for (i = 1; i < nwords; i++)
- for (j = 0, p = words[i]; j < prefix_len; j++)
- if (FILECHCONV(p[j]) != FILECHCONV(words[0][j])) {
- prefix_len = j;
- break;
- }
- return prefix_len;
-}
-
-void
-x_free_words(nwords, words)
- int nwords;
- char **words;
-{
- int i;
-
- for (i = 0; i < nwords; i++)
- if (words[i])
- afree(words[i], ATEMP);
- afree(words, ATEMP);
-}
-
-/* Return the offset of the basename of string s (which ends at se - need not
- * be null terminated). Trailing slashes are ignored. If s is just a slash,
- * then the offset is 0 (actually, length - 1).
- * s Return
- * /etc 1
- * /etc/ 1
- * /etc// 1
- * /etc/fo 5
- * foo 0
- * /// 2
- * 0
- */
-int
-x_basename(s, se)
- const char *s;
- const char *se;
-{
- const char *p;
-
- if (se == (char *) 0)
- se = s + strlen(s);
- if (s == se)
- return 0;
-
- /* Skip trailing slashes */
- for (p = se - 1; p > s && ISDIRSEP(*p); p--)
- ;
- for (; p > s && !ISDIRSEP(*p); p--)
- ;
- if (ISDIRSEP(*p) && p + 1 < se)
- p++;
-
- return p - s;
-}
-
-/*
- * Apply pattern matching to a table: all table entries that match a pattern
- * are added to wp.
- */
-static void
-glob_table(pat, wp, tp)
- const char *pat;
- XPtrV *wp;
- struct table *tp;
-{
- struct tstate ts;
- struct tbl *te;
-
- for (twalk(&ts, tp); (te = tnext(&ts)); ) {
- if (gmatch(te->name, pat, FALSE))
- XPput(*wp, str_save(te->name, ATEMP));
- }
-}
-
-static void
-glob_path(flags, pat, wp, path)
- int flags;
- const char *pat;
- XPtrV *wp;
- const char *path;
-{
- const char *sp, *p;
- char *xp;
- int pathlen;
- int patlen;
- int oldsize, newsize, i, j;
- char **words;
- XString xs;
-
- patlen = strlen(pat) + 1;
- sp = path;
- Xinit(xs, xp, patlen + 128, ATEMP);
- while (sp) {
- xp = Xstring(xs, xp);
- if (!(p = strchr(sp, PATHSEP)))
- p = sp + strlen(sp);
- pathlen = p - sp;
- if (pathlen) {
- /* Copy sp into xp, stuffing any MAGIC characters
- * on the way
- */
- const char *s = sp;
-
- XcheckN(xs, xp, pathlen * 2);
- while (s < p) {
- if (ISMAGIC(*s))
- *xp++ = MAGIC;
- *xp++ = *s++;
- }
- *xp++ = DIRSEP;
- pathlen++;
- }
- sp = p;
- XcheckN(xs, xp, patlen);
- memcpy(xp, pat, patlen);
-
- oldsize = XPsize(*wp);
- glob_str(Xstring(xs, xp), wp, 0);
- newsize = XPsize(*wp);
-
- /* Check that each match is executable... */
- words = (char **) XPptrv(*wp);
- for (i = j = oldsize; i < newsize; i++) {
- if (search_access(words[i], X_OK, (int *) 0) >= 0) {
- words[j] = words[i];
- if (!(flags & XCF_FULLPATH))
- memmove(words[j], words[j] + pathlen,
- strlen(words[j] + pathlen) + 1);
- j++;
- } else
- afree(words[i], ATEMP);
- }
- wp->cur = (void **) &words[j];
-
- if (!*sp++)
- break;
- }
- Xfree(xs, xp);
-}
-
-#endif /* EDIT */
diff --git a/bin/pdksh/edit.h b/bin/pdksh/edit.h
deleted file mode 100644
index fd29701cc06..00000000000
--- a/bin/pdksh/edit.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/* $OpenBSD: edit.h,v 1.2 1996/08/19 20:08:48 downsj Exp $ */
-
-/* NAME:
- * edit.h - globals for edit modes
- *
- * DESCRIPTION:
- * This header defines various global edit objects.
- *
- * SEE ALSO:
- *
- *
- * RCSid:
- * $From: edit.h,v 1.2 1994/05/19 18:32:40 michael Exp michael $
- *
- */
-
-/* some useful #defines */
-#ifdef EXTERN
-# define I__(i) = i
-#else
-# define I__(i)
-# define EXTERN extern
-# define EXTERN_DEFINED
-#endif
-
-#define BEL 0x07
-
-/* tty driver characters we are interested in */
-typedef struct {
- int erase;
- int kill;
- int werase;
- int intr;
- int quit;
- int eof;
-} X_chars;
-
-EXTERN X_chars edchars;
-
-/* x_fc_glob() flags */
-#define XCF_COMMAND BIT(0) /* Do command completion */
-#define XCF_FILE BIT(1) /* Do file completion */
-#define XCF_FULLPATH BIT(2) /* command completion: store full path */
-#define XCF_COMMAND_FILE (XCF_COMMAND|XCF_FILE)
-
-/* edit.c */
-int x_getc ARGS((void));
-void x_flush ARGS((void));
-void x_putc ARGS((int c));
-void x_puts ARGS((const char *s));
-bool_t x_mode ARGS((bool_t onoff));
-int promptlen ARGS((const char *cp, const char **spp));
-int x_do_comment ARGS((char *buf, int bsize, int *lenp));
-void x_print_expansions ARGS((int nwords, char *const *words, int is_command));
-int x_cf_glob ARGS((int flags, const char *buf, int buflen, int pos, int *startp,
- int *endp, char ***wordsp, int *is_commandp));
-int x_longest_prefix ARGS((int nwords, char *const *words));
-int x_basename ARGS((const char *s, const char *se));
-void x_free_words ARGS((int nwords, char **words));
-/* emacs.c */
-int x_emacs ARGS((char *buf, size_t len));
-void x_init_emacs ARGS((void));
-void x_emacs_keys ARGS((X_chars *ec));
-/* vi.c */
-int x_vi ARGS((char *buf, size_t len));
-
-
-#ifdef DEBUG
-# define D__(x) x
-#else
-# define D__(x)
-#endif
-
-/* This lot goes at the END */
-/* be sure not to interfere with anyone else's idea about EXTERN */
-#ifdef EXTERN_DEFINED
-# undef EXTERN_DEFINED
-# undef EXTERN
-#endif
-#undef I__
-/*
- * Local Variables:
- * version-control:t
- * comment-column:40
- * End:
- */
diff --git a/bin/pdksh/emacs-gen.sh b/bin/pdksh/emacs-gen.sh
deleted file mode 100644
index 97449de8fa4..00000000000
--- a/bin/pdksh/emacs-gen.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/sh
-# $OpenBSD: emacs-gen.sh,v 1.1 1996/08/14 06:19:10 downsj Exp $
-
-case $# in
-1) file=$1;;
-*)
- echo "$0: Usage: $0 path-to-emacs.c" 1>&2
- exit 1
-esac;
-
-if [ ! -r "$file" ] ;then
- echo "$0: can't read $file" 1>&2
- exit 1
-fi
-
-cat << E_O_F || exit 1
-/*
- * NOTE: THIS FILE WAS GENERATED AUTOMATICALLY FROM $file
- *
- * DO NOT BOTHER EDITING THIS FILE
- */
-E_O_F
-
-# Pass 1: print out lines before @START-FUNC-TAB@
-# and generate defines and function declarations,
-sed -e '1,/@START-FUNC-TAB@/d' -e '/@END-FUNC-TAB@/,$d' < $file |
- awk 'BEGIN { nfunc = 0; }
- /^[ ]*#/ {
- print $0;
- next;
- }
- {
- fname = $2;
- c = substr(fname, length(fname), 1);
- if (c == ",")
- fname = substr(fname, 1, length(fname) - 1);
- if (fname != "0") {
- printf "#define XFUNC_%s %d\n", substr(fname, 3, length(fname) - 2), nfunc;
- printf "static int %s ARGS((int c));\n", fname;
- nfunc++;
- }
- }' || exit 1
-
-exit 0
diff --git a/bin/pdksh/emacs.c b/bin/pdksh/emacs.c
deleted file mode 100644
index db515363a1d..00000000000
--- a/bin/pdksh/emacs.c
+++ /dev/null
@@ -1,2182 +0,0 @@
-/* $OpenBSD: emacs.c,v 1.4 1997/06/19 13:58:39 kstailey Exp $ */
-
-/*
- * Emacs-like command line editing and history
- *
- * created by Ron Natalie at BRL
- * modified by Doug Kingston, Doug Gwyn, and Lou Salkind
- * adapted to PD ksh by Eric Gisin
- */
-
-#include "config.h"
-#ifdef EMACS
-
-#include "sh.h"
-#include "ksh_stat.h"
-#include "ksh_dir.h"
-#include <ctype.h>
-#include "edit.h"
-
-static Area aedit;
-#define AEDIT &aedit /* area for kill ring and macro defns */
-
-#undef CTRL /* _BSD brain damage */
-#define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */
-#define UNCTRL(x) ((x) == 0x7F ? '?' : (x) | 0x40) /* ASCII */
-
-
-/* values returned by keyboard functions */
-#define KSTD 0
-#define KEOL 1 /* ^M, ^J */
-#define KINTR 2 /* ^G, ^C */
-
-struct x_ftab {
- int (*xf_func) ARGS((int c));
- const char *xf_name;
- short xf_flags;
-};
-
-/* index into struct x_ftab x_ftab[] - small is good */
-typedef unsigned char Findex;
-
-struct x_defbindings {
- Findex xdb_func; /* XFUNC_* */
- char xdb_tab;
- unsigned char xdb_char;
-};
-
-#define XF_ARG 1 /* command takes number prefix */
-#define XF_NOBIND 2 /* not allowed to bind to function */
-#define XF_PREFIX 4 /* function sets prefix */
-
-/* Separator for completion */
-#define is_cfs(c) (c == ' ' || c == '\t' || c == '"' || c == '\'')
-#define is_mfs(c) (!(isalnum(c) || c == '_' || c == '$')) /* Separator for motion */
-
-#ifdef OS2
- /* Deal with 8 bit chars & an extra prefix for function key (these two
- * changes increase memory usage from 9,216 bytes to 24,416 bytes...)
- */
-# define CHARMASK 0xFF /* 8-bit ASCII character mask */
-# define X_TABSZ 256 /* size of keydef tables etc */
-# define X_NTABS 4 /* normal, meta1, meta2, meta3 */
-static int x_prefix3 = 0xE0;
-#else /* OS2 */
-# define CHARMASK 0x7F /* 7-bit ASCII character mask */
-# define X_TABSZ 128 /* size of keydef tables etc */
-# define X_NTABS 3 /* normal, meta1, meta2 */
-#endif /* OS2 */
-
-/* Arguments for do_complete()
- * 0 = enumerate M-= complete as much as possible and then list
- * 1 = complete M-Esc
- * 2 = list M-?
- */
-typedef enum { CT_LIST, /* list the possible completions */
- CT_COMPLETE, /* complete to longest prefix */
- CT_COMPLIST /* complete and then list (if non-exact) */
- } Comp_type;
-
-/* { from 4.9 edit.h */
-/*
- * The following are used for my horizontal scrolling stuff
- */
-static char *xbuf; /* beg input buffer */
-static char *xend; /* end input buffer */
-static char *xcp; /* current position */
-static char *xep; /* current end */
-static char *xbp; /* start of visible portion of input buffer */
-static char *xlp; /* last char visible on screen */
-static int x_adj_ok;
-/*
- * we use x_adj_done so that functions can tell
- * whether x_adjust() has been called while they are active.
- */
-static int x_adj_done;
-
-static int xx_cols;
-static int x_col;
-static int x_displen;
-static int x_arg; /* general purpose arg */
-static int x_arg_defaulted;/* x_arg not explicitly set; defaulted to 1 */
-
-static int xlp_valid;
-/* end from 4.9 edit.h } */
-
-static int x_prefix1 = CTRL('['), x_prefix2 = CTRL('X');
-static char **x_histp; /* history position */
-static int x_nextcmd; /* for newline-and-next */
-static char *xmp; /* mark pointer */
-static Findex x_last_command;
-static Findex (*x_tab)[X_TABSZ]; /* key definition */
-static char *(*x_atab)[X_TABSZ]; /* macro definitions */
-#define KILLSIZE 20
-static char *killstack[KILLSIZE];
-static int killsp, killtp;
-static int x_curprefix;
-static char *macroptr;
-static int prompt_skip;
-
-static int x_ins ARGS((char *cp));
-static void x_delete ARGS((int nc, int force_push));
-static int x_bword ARGS((void));
-static int x_fword ARGS((void));
-static void x_goto ARGS((char *cp));
-static void x_bs ARGS((int c));
-static int x_size_str ARGS((char *cp));
-static int x_size ARGS((int c));
-static void x_zots ARGS((char *str));
-static void x_zotc ARGS((int c));
-static void x_load_hist ARGS((char **hp));
-static int x_search ARGS((char *pat, int sameline, int offset));
-static int x_match ARGS((char *str, char *pat));
-static void x_redraw ARGS((int limit));
-static void x_push ARGS((int nchars));
-static char * x_mapin ARGS((const char *cp));
-static char * x_mapout ARGS((int c));
-static void x_print ARGS((int prefix, int key));
-static void x_adjust ARGS((void));
-static void x_e_ungetc ARGS((int c));
-static int x_e_getc ARGS((void));
-static void x_e_putc ARGS((int c));
-static void x_e_puts ARGS((const char *s));
-static int x_comment ARGS((int c));
-static int x_fold_case ARGS((int c));
-static char *x_lastcp ARGS((void));
-static void do_complete ARGS((int flags, Comp_type type));
-
-
-/* The lines between START-FUNC-TAB .. END-FUNC-TAB are run through a
- * script (emacs-gen.sh) that generates emacs.out which contains:
- * - function declarations for x_* functions
- * - defines of the form XFUNC_<name> where <name> is function
- * name, sans leading x_.
- * Note that the script treats #ifdef and { 0, 0, 0} specially - use with
- * caution.
- */
-#include "emacs.out"
-static const struct x_ftab x_ftab[] = {
-/* @START-FUNC-TAB@ */
- { x_abort, "abort", 0 },
- { x_beg_hist, "beginning-of-history", 0 },
- { x_comp_comm, "complete-command", 0 },
- { x_comp_file, "complete-file", 0 },
- { x_complete, "complete", 0 },
- { x_del_back, "delete-char-backward", XF_ARG },
- { x_del_bword, "delete-word-backward", XF_ARG },
- { x_del_char, "delete-char-forward", XF_ARG },
- { x_del_fword, "delete-word-forward", XF_ARG },
- { x_del_line, "kill-line", 0 },
- { x_draw_line, "redraw", 0 },
- { x_end_hist, "end-of-history", 0 },
- { x_end_of_text, "eot", 0 },
- { x_enumerate, "list", 0 },
- { x_eot_del, "eot-or-delete", XF_ARG },
- { x_error, "error", 0 },
- { x_goto_hist, "goto-history", XF_ARG },
- { x_ins_string, "macro-string", XF_NOBIND },
- { x_insert, "auto-insert", XF_ARG },
- { x_kill, "kill-to-eol", XF_ARG },
- { x_kill_region, "kill-region", 0 },
- { x_list_comm, "list-command", 0 },
- { x_list_file, "list-file", 0 },
- { x_literal, "quote", 0 },
- { x_meta1, "prefix-1", XF_PREFIX },
- { x_meta2, "prefix-2", XF_PREFIX },
- { x_meta_yank, "yank-pop", 0 },
- { x_mv_back, "backward-char", XF_ARG },
- { x_mv_begin, "beginning-of-line", 0 },
- { x_mv_bword, "backward-word", XF_ARG },
- { x_mv_end, "end-of-line", 0 },
- { x_mv_forw, "forward-char", XF_ARG },
- { x_mv_fword, "forward-word", XF_ARG },
- { x_newline, "newline", 0 },
- { x_next_com, "down-history", XF_ARG },
- { x_nl_next_com, "newline-and-next", 0 },
- { x_noop, "no-op", 0 },
- { x_prev_com, "up-history", XF_ARG },
- { x_prev_histword, "prev-hist-word", XF_ARG },
- { x_search_char_forw, "search-character-forward", XF_ARG },
- { x_search_char_back, "search-character-backward", XF_ARG },
- { x_search_hist, "search-history", 0 },
- { x_set_mark, "set-mark-command", 0 },
- { x_stuff, "stuff", 0 },
- { x_stuffreset, "stuff-reset", 0 },
- { x_transpose, "transpose-chars", 0 },
- { x_version, "version", 0 },
- { x_xchg_point_mark, "exchange-point-and-mark", 0 },
- { x_yank, "yank", 0 },
- { x_comp_list, "complete-list", 0 },
- { x_expand, "expand-file", 0 },
- { x_fold_capitialize, "capitalize-word", XF_ARG },
- { x_fold_lower, "downcase-word", XF_ARG },
- { x_fold_upper, "upcase-word", XF_ARG },
- { x_set_arg, "set-arg", XF_NOBIND },
- { x_comment, "comment", 0 },
-#ifdef SILLY
- { x_game_of_life, "play-game-of-life", 0 },
-#else
- { 0, 0, 0 },
-#endif
-#ifdef DEBUG
- { x_debug_info, "debug-info", 0 },
-#else
- { 0, 0, 0 },
-#endif
-#ifdef OS2
- { x_meta3, "prefix-3", XF_PREFIX },
-#else
- { 0, 0, 0 },
-#endif
-/* @END-FUNC-TAB@ */
- };
-
-static struct x_defbindings const x_defbindings[] = {
- { XFUNC_del_back, 0, CTRL('?') },
- { XFUNC_del_bword, 1, CTRL('?') },
- { XFUNC_eot_del, 0, CTRL('D') },
- { XFUNC_del_back, 0, CTRL('H') },
- { XFUNC_del_bword, 1, CTRL('H') },
- { XFUNC_del_bword, 1, 'h' },
- { XFUNC_mv_bword, 1, 'b' },
- { XFUNC_mv_fword, 1, 'f' },
- { XFUNC_del_fword, 1, 'd' },
- { XFUNC_mv_back, 0, CTRL('B') },
- { XFUNC_mv_forw, 0, CTRL('F') },
- { XFUNC_search_char_forw, 0, CTRL(']') },
- { XFUNC_search_char_back, 1, CTRL(']') },
- { XFUNC_newline, 0, CTRL('M') },
- { XFUNC_newline, 0, CTRL('J') },
- { XFUNC_end_of_text, 0, CTRL('_') },
- { XFUNC_abort, 0, CTRL('G') },
- { XFUNC_prev_com, 0, CTRL('P') },
- { XFUNC_next_com, 0, CTRL('N') },
- { XFUNC_nl_next_com, 0, CTRL('O') },
- { XFUNC_search_hist, 0, CTRL('R') },
- { XFUNC_beg_hist, 1, '<' },
- { XFUNC_end_hist, 1, '>' },
- { XFUNC_goto_hist, 1, 'g' },
- { XFUNC_mv_end, 0, CTRL('E') },
- { XFUNC_mv_begin, 0, CTRL('A') },
- { XFUNC_draw_line, 0, CTRL('L') },
- { XFUNC_meta1, 0, CTRL('[') },
- { XFUNC_meta2, 0, CTRL('X') },
- { XFUNC_kill, 0, CTRL('K') },
- { XFUNC_yank, 0, CTRL('Y') },
- { XFUNC_meta_yank, 1, 'y' },
- { XFUNC_literal, 0, CTRL('^') },
- { XFUNC_comment, 1, '#' },
-#if defined(BRL) && defined(TIOCSTI)
- { XFUNC_stuff, 0, CTRL('T') },
-#else
- { XFUNC_transpose, 0, CTRL('T') },
-#endif
- { XFUNC_complete, 1, CTRL('[') },
- { XFUNC_comp_list, 1, '=' },
- { XFUNC_enumerate, 1, '?' },
- { XFUNC_expand, 1, '*' },
- { XFUNC_comp_file, 1, CTRL('X') },
- { XFUNC_comp_comm, 2, CTRL('[') },
- { XFUNC_list_comm, 2, '?' },
- { XFUNC_list_file, 2, CTRL('Y') },
- { XFUNC_set_mark, 1, ' ' },
- { XFUNC_kill_region, 0, CTRL('W') },
- { XFUNC_xchg_point_mark, 2, CTRL('X') },
- { XFUNC_version, 0, CTRL('V') },
-#ifdef DEBUG
- { XFUNC_debug_info, 1, CTRL('H') },
-#endif
- { XFUNC_prev_histword, 1, '.' },
- { XFUNC_prev_histword, 1, '_' },
- { XFUNC_set_arg, 1, '0' },
- { XFUNC_set_arg, 1, '1' },
- { XFUNC_set_arg, 1, '2' },
- { XFUNC_set_arg, 1, '3' },
- { XFUNC_set_arg, 1, '4' },
- { XFUNC_set_arg, 1, '5' },
- { XFUNC_set_arg, 1, '6' },
- { XFUNC_set_arg, 1, '7' },
- { XFUNC_set_arg, 1, '8' },
- { XFUNC_set_arg, 1, '9' },
- { XFUNC_fold_upper, 1, 'U' },
- { XFUNC_fold_upper, 1, 'u' },
- { XFUNC_fold_lower, 1, 'L' },
- { XFUNC_fold_lower, 1, 'l' },
- { XFUNC_fold_capitialize, 1, 'C' },
- { XFUNC_fold_capitialize, 1, 'c' },
-#ifdef OS2
- { XFUNC_meta3, 0, 0xE0 },
- { XFUNC_mv_back, 3, 'K' },
- { XFUNC_mv_forw, 3, 'M' },
- { XFUNC_next_com, 3, 'P' },
- { XFUNC_prev_com, 3, 'H' },
-#else /* OS2 */
- /* These for ansi arrow keys: arguablely shouldn't be here by
- * default, but its simpler/faster/smaller than using termcap
- * entries.
- */
- { XFUNC_meta2, 1, '[' },
- { XFUNC_prev_com, 2, 'A' },
- { XFUNC_next_com, 2, 'B' },
- { XFUNC_mv_forw, 2, 'C' },
- { XFUNC_mv_back, 2, 'D' },
-#endif /* OS2 */
-};
-
-int
-x_emacs(buf, len)
- char *buf;
- size_t len;
-{
- int c;
- const char *p;
- int i;
- Findex f;
-
- xbp = xbuf = buf; xend = buf + len;
- xlp = xcp = xep = buf;
- *xcp = 0;
- xlp_valid = TRUE;
- xmp = NULL;
- x_curprefix = 0;
- macroptr = (char *) 0;
- x_histp = histptr + 1;
- x_last_command = XFUNC_error;
-
- xx_cols = x_cols;
- x_col = promptlen(prompt, &p);
- prompt_skip = p - prompt;
- x_adj_ok = 1;
- x_displen = xx_cols - 2 - x_col;
- x_adj_done = 0;
-
- pprompt(prompt, 0);
-
- if (x_nextcmd >= 0) {
- int off = source->line - x_nextcmd;
- if (histptr - history >= off)
- x_load_hist(histptr - off);
- x_nextcmd = -1;
- }
-
- while (1) {
- x_flush();
- if ((c = x_e_getc()) < 0)
- return 0;
-
- f = x_curprefix == -1 ? XFUNC_insert
- : x_tab[x_curprefix][c&CHARMASK];
-
- if (!(x_ftab[f].xf_flags & XF_PREFIX)
- && x_last_command != XFUNC_set_arg)
- {
- x_arg = 1;
- x_arg_defaulted = 1;
- }
- i = c | (x_curprefix << 8);
- x_curprefix = 0;
- switch (i = (*x_ftab[f].xf_func)(i)) {
- case KSTD:
- if (!(x_ftab[f].xf_flags & XF_PREFIX))
- x_last_command = f;
- break;
- case KEOL:
- i = xep - xbuf;
- return i;
- case KINTR: /* special case for interrupt */
- trapsig(SIGINT);
- x_mode(FALSE);
- unwind(LSHELL);
- }
- }
-}
-
-static int
-x_insert(c)
- int c;
-{
- char str[2];
-
- /*
- * Should allow tab and control chars.
- */
- if (c == 0) {
- x_e_putc(BEL);
- return KSTD;
- }
- str[0] = c;
- str[1] = '\0';
- while (x_arg--)
- x_ins(str);
- return KSTD;
-}
-
-static int
-x_ins_string(c)
- int c;
-{
- if (macroptr) {
- x_e_putc(BEL);
- return KSTD;
- }
- macroptr = x_atab[c>>8][c & CHARMASK];
- if (macroptr && !*macroptr) {
- /* XXX bell? */
- macroptr = (char *) 0;
- }
- return KSTD;
-}
-
-static int
-x_do_ins(cp, len)
- const char *cp;
- int len;
-{
- if (xep+len >= xend) {
- x_e_putc(BEL);
- return -1;
- }
-
- memmove(xcp+len, xcp, xep - xcp + 1);
- memmove(xcp, cp, len);
- xcp += len;
- xep += len;
- return 0;
-}
-
-static int
-x_ins(s)
- char *s;
-{
- char *cp = xcp;
- register int adj = x_adj_done;
-
- if (x_do_ins(s, strlen(s)) < 0)
- return -1;
- /*
- * x_zots() may result in a call to x_adjust()
- * we want xcp to reflect the new position.
- */
- xlp_valid = FALSE;
- x_lastcp();
- x_adj_ok = (xcp >= xlp);
- x_zots(cp);
- if (adj == x_adj_done) /* has x_adjust() been called? */
- {
- /* no */
- for (cp = xlp; cp > xcp; )
- x_bs(*--cp);
- }
-
- x_adj_ok = 1;
- return 0;
-}
-
-static int
-x_del_back(c)
- int c;
-{
- int col = xcp - xbuf;
-
- if (col == 0) {
- x_e_putc(BEL);
- return KSTD;
- }
- if (x_arg > col)
- x_arg = col;
- x_goto(xcp - x_arg);
- x_delete(x_arg, FALSE);
- return KSTD;
-}
-
-static int
-x_del_char(c)
- int c;
-{
- int nleft = xep - xcp;
-
- if (!nleft) {
- x_e_putc(BEL);
- return KSTD;
- }
- if (x_arg > nleft)
- x_arg = nleft;
- x_delete(x_arg, FALSE);
- return KSTD;
-}
-
-/* Delete nc chars to the right of the cursor (including cursor position) */
-static void
-x_delete(nc, force_push)
- int nc;
- int force_push;
-{
- int i,j;
- char *cp;
-
- if (nc == 0)
- return;
- if (xmp != NULL && xmp > xcp) {
- if (xcp + nc > xmp)
- xmp = xcp;
- else
- xmp -= nc;
- }
-
- /*
- * This lets us yank a word we have deleted.
- */
- if (nc > 1 || force_push)
- x_push(nc);
-
- xep -= nc;
- cp = xcp;
- j = 0;
- i = nc;
- while (i--) {
- j += x_size(*cp++);
- }
- memmove(xcp, xcp+nc, xep - xcp + 1); /* Copies the null */
- x_adj_ok = 0; /* don't redraw */
- x_zots(xcp);
- /*
- * if we are already filling the line,
- * there is no need to ' ','\b'.
- * But if we must, make sure we do the minimum.
- */
- if ((i = xx_cols - 2 - x_col) > 0)
- {
- j = (j < i) ? j : i;
- i = j;
- while (i--)
- x_e_putc(' ');
- i = j;
- while (i--)
- x_e_putc('\b');
- }
- /*x_goto(xcp);*/
- x_adj_ok = 1;
- xlp_valid = FALSE;
- for (cp = x_lastcp(); cp > xcp; )
- x_bs(*--cp);
-
- return;
-}
-
-static int
-x_del_bword(c)
- int c;
-{
- x_delete(x_bword(), FALSE);
- return KSTD;
-}
-
-static int
-x_mv_bword(c)
- int c;
-{
- (void)x_bword();
- return KSTD;
-}
-
-static int
-x_mv_fword(c)
- int c;
-{
- x_goto(xcp + x_fword());
- return KSTD;
-}
-
-static int
-x_del_fword(c)
- int c;
-{
- x_delete(x_fword(), FALSE);
- return KSTD;
-}
-
-static int
-x_bword()
-{
- int nc = 0;
- register char *cp = xcp;
-
- if (cp == xbuf) {
- x_e_putc(BEL);
- return 0;
- }
- while (x_arg--)
- {
- while (cp != xbuf && is_mfs(cp[-1]))
- {
- cp--;
- nc++;
- }
- while (cp != xbuf && !is_mfs(cp[-1]))
- {
- cp--;
- nc++;
- }
- }
- x_goto(cp);
- return nc;
-}
-
-static int
-x_fword()
-{
- int nc = 0;
- register char *cp = xcp;
-
- if (cp == xep) {
- x_e_putc(BEL);
- return 0;
- }
- while (x_arg--)
- {
- while (cp != xep && is_mfs(*cp))
- {
- cp++;
- nc++;
- }
- while (cp != xep && !is_mfs(*cp))
- {
- cp++;
- nc++;
- }
- }
- return nc;
-}
-
-static void
-x_goto(cp)
- register char *cp;
-{
- if (cp < xbp || cp >= (xbp + x_displen))
- {
- /* we are heading off screen */
- xcp = cp;
- x_adjust();
- }
- else
- {
- if (cp < xcp) /* move back */
- {
- while (cp < xcp)
- x_bs(*--xcp);
- }
- else
- {
- if (cp > xcp) /* move forward */
- {
- while (cp > xcp)
- x_zotc(*xcp++);
- }
- }
- }
-}
-
-static void
-x_bs(c)
- int c;
-{
- register i;
- i = x_size(c);
- while (i--)
- x_e_putc('\b');
-}
-
-static int
-x_size_str(cp)
- register char *cp;
-{
- register size = 0;
- while (*cp)
- size += x_size(*cp++);
- return size;
-}
-
-static int
-x_size(c)
- int c;
-{
- if (c=='\t')
- return 4; /* Kludge, tabs are always four spaces. */
- if (c < ' ' || c == 0x7F) /* ASCII control char */
- return 2;
- return 1;
-}
-
-static void
-x_zots(str)
- register char *str;
-{
- register int adj = x_adj_done;
-
- x_lastcp();
- while (*str && str < xlp && adj == x_adj_done)
- x_zotc(*str++);
-}
-
-static void
-x_zotc(c)
- int c;
-{
- if (c == '\t') {
- /* Kludge, tabs are always four spaces. */
- x_e_puts(" ");
- } else if (c < ' ' || c == 0x7F) { /* ASCII */
- x_e_putc('^');
- x_e_putc(UNCTRL(c));
- } else
- x_e_putc(c);
-}
-
-static int
-x_mv_back(c)
- int c;
-{
- int col = xcp - xbuf;
-
- if (col == 0) {
- x_e_putc(BEL);
- return KSTD;
- }
- if (x_arg > col)
- x_arg = col;
- x_goto(xcp - x_arg);
- return KSTD;
-}
-
-static int
-x_mv_forw(c)
- int c;
-{
- int nleft = xep - xcp;
-
- if (!nleft) {
- x_e_putc(BEL);
- return KSTD;
- }
- if (x_arg > nleft)
- x_arg = nleft;
- x_goto(xcp + x_arg);
- return KSTD;
-}
-
-static int
-x_search_char_forw(c)
- int c;
-{
- char *cp = xcp;
-
- *xep = '\0';
- c = x_e_getc();
- while (x_arg--) {
- if (c < 0
- || ((cp = (cp == xep) ? NULL : strchr(cp + 1, c)) == NULL
- && (cp = strchr(xbuf, c)) == NULL))
- {
- x_e_putc(BEL);
- return KSTD;
- }
- }
- x_goto(cp);
- return KSTD;
-}
-
-static int
-x_search_char_back(c)
- int c;
-{
- char *cp = xcp, *p;
-
- c = x_e_getc();
- for (; x_arg--; cp = p)
- for (p = cp; ; ) {
- if (p-- == xbuf)
- p = xep;
- if (c < 0 || p == cp) {
- x_e_putc(BEL);
- return KSTD;
- }
- if (*p == c)
- break;
- }
- x_goto(cp);
- return KSTD;
-}
-
-static int
-x_newline(c)
- int c;
-{
- x_e_putc('\r');
- x_e_putc('\n');
- x_flush();
- *xep++ = '\n';
- return KEOL;
-}
-
-static int
-x_end_of_text(c)
- int c;
-{
- return KEOL;
-}
-
-static int x_beg_hist(c) int c; { x_load_hist(history); return KSTD;}
-
-static int x_end_hist(c) int c; { x_load_hist(histptr); return KSTD;}
-
-static int x_prev_com(c) int c; { x_load_hist(x_histp - x_arg); return KSTD;}
-
-static int x_next_com(c) int c; { x_load_hist(x_histp + x_arg); return KSTD;}
-
-/* Goto a particular history number obtained from argument.
- * If no argument is given history 1 is probably not what you
- * want so we'll simply go to the oldest one.
- */
-static int
-x_goto_hist(c)
- int c;
-{
- if (x_arg_defaulted)
- x_load_hist(history);
- else
- x_load_hist(histptr + x_arg - source->line);
- return KSTD;
-}
-
-static void
-x_load_hist(hp)
- register char **hp;
-{
- int oldsize;
-
- if (hp < history || hp > histptr) {
- x_e_putc(BEL);
- return;
- }
- x_histp = hp;
- oldsize = x_size_str(xbuf);
- (void)strcpy(xbuf, *hp);
- xbp = xbuf;
- xep = xcp = xbuf + strlen(*hp);
- xlp_valid = FALSE;
- if (xep > x_lastcp())
- x_goto(xep);
- else
- x_redraw(oldsize);
-}
-
-static int
-x_nl_next_com(c)
- int c;
-{
- x_nextcmd = source->line - (histptr - x_histp) + 1;
- return (x_newline(c));
-}
-
-static int
-x_eot_del(c)
- int c;
-{
- if (xep == xbuf && x_arg_defaulted)
- return (x_end_of_text(c));
- else
- return (x_del_char(c));
-}
-
-/* reverse incremental history search */
-static int
-x_search_hist(c)
- int c;
-{
- int offset = -1; /* offset of match in xbuf, else -1 */
- char pat [256+1]; /* pattern buffer */
- register char *p = pat;
- Findex f;
-
- *p = '\0';
- while (1) {
- if (offset < 0) {
- x_e_puts("\nI-search: ");
- x_e_puts(pat);
- }
- x_flush();
- if ((c = x_e_getc()) < 0)
- return KSTD;
- f = x_tab[0][c&CHARMASK];
- if (c == CTRL('['))
- break;
- else if (f == XFUNC_search_hist)
- offset = x_search(pat, 0, offset);
- else if (f == XFUNC_del_back) {
- if (p == pat) {
- offset = -1;
- break;
- }
- if (p > pat)
- *--p = '\0';
- if (p == pat)
- offset = -1;
- else
- offset = x_search(pat, 1, offset);
- continue;
- } else if (f == XFUNC_insert) {
- /* add char to pattern */
- /* overflow check... */
- if (p >= &pat[sizeof(pat) - 1]) {
- x_e_putc(BEL);
- continue;
- }
- *p++ = c, *p = '\0';
- if (offset >= 0) {
- /* already have partial match */
- offset = x_match(xbuf, pat);
- if (offset >= 0) {
- x_goto(xbuf + offset + (p - pat) - (*pat == '^'));
- continue;
- }
- }
- offset = x_search(pat, 0, offset);
- } else { /* other command */
- x_e_ungetc(c);
- break;
- }
- }
- if (offset < 0)
- x_redraw(-1);
- return KSTD;
-}
-
-/* search backward from current line */
-static int
-x_search(pat, sameline, offset)
- char *pat;
- int sameline;
- int offset;
-{
- register char **hp;
- int i;
-
- for (hp = x_histp - (sameline ? 0 : 1) ; hp >= history; --hp) {
- i = x_match(*hp, pat);
- if (i >= 0) {
- if (offset < 0)
- x_e_putc('\n');
- x_load_hist(hp);
- x_goto(xbuf + i + strlen(pat) - (*pat == '^'));
- return i;
- }
- }
- x_e_putc(BEL);
- x_histp = histptr;
- return -1;
-}
-
-/* return position of first match of pattern in string, else -1 */
-static int
-x_match(str, pat)
- char *str, *pat;
-{
- if (*pat == '^') {
- return (strncmp(str, pat+1, strlen(pat+1)) == 0) ? 0 : -1;
- } else {
- char *q = strstr(str, pat);
- return (q == NULL) ? -1 : q - str;
- }
-}
-
-static int
-x_del_line(c)
- int c;
-{
- int i, j;
-
- *xep = 0;
- i = xep- xbuf;
- j = x_size_str(xbuf);
- xcp = xbuf;
- x_push(i);
- xlp = xbp = xep = xbuf;
- xlp_valid = TRUE;
- *xcp = 0;
- xmp = NULL;
- x_redraw(j);
- return KSTD;
-}
-
-static int
-x_mv_end(c)
- int c;
-{
- x_goto(xep);
- return KSTD;
-}
-
-static int
-x_mv_begin(c)
- int c;
-{
- x_goto(xbuf);
- return KSTD;
-}
-
-static int
-x_draw_line(c)
- int c;
-{
- x_redraw(-1);
- return KSTD;
-
-}
-
-/* Redraw (part of) the line. If limit is < 0, the everything is redrawn
- * on a NEW line, otherwise limit is the screen column up to which needs
- * redrawing.
- */
-static void
-x_redraw(limit)
- int limit;
-{
- int i, j;
- char *cp;
-
- x_adj_ok = 0;
- if (limit == -1)
- x_e_putc('\n');
- else
- x_e_putc('\r');
- x_flush();
- if (xbp == xbuf)
- {
- pprompt(prompt + prompt_skip, 0);
- x_col = promptlen(prompt, (const char **) 0);
- }
- x_displen = xx_cols - 2 - x_col;
- xlp_valid = FALSE;
- cp = x_lastcp();
- x_zots(xbp);
- if (xbp != xbuf || xep > xlp)
- limit = xx_cols;
- if (limit >= 0)
- {
- if (xep > xlp)
- i = 0; /* we fill the line */
- else
- i = limit - (xlp - xbp);
-
- for (j = 0; j < i && x_col < (xx_cols - 2); j++)
- x_e_putc(' ');
- i = ' ';
- if (xep > xlp) /* more off screen */
- {
- if (xbp > xbuf)
- i = '*';
- else
- i = '>';
- }
- else
- if (xbp > xbuf)
- i = '<';
- x_e_putc(i);
- j++;
- while (j--)
- x_e_putc('\b');
- }
- for (cp = xlp; cp > xcp; )
- x_bs(*--cp);
- x_adj_ok = 1;
- D__(x_flush();)
- return;
-}
-
-static int
-x_transpose(c)
- int c;
-{
- char tmp;
-
- /* What transpose is meant to do seems to be up for debate. This
- * is a general summary of the options; the text is abcd with the
- * upper case character or underscore indicating the cursor positiion:
- * Who Before After Before After
- * at&t ksh in emacs mode: abCd abdC abcd_ (bell)
- * at&t ksh in gmacs mode: abCd baCd abcd_ abdc_
- * gnu emacs: abCd acbD abcd_ abdc_
- * Pdksh currently goes with GNU behavior since I believe this is the
- * most common version of emacs, unless in gmacs mode, in which case
- * it does the at&t ksh gmacs mdoe.
- * This should really be broken up into 3 functions so users can bind
- * to the one they want.
- */
- if (xcp == xbuf) {
- x_e_putc(BEL);
- return KSTD;
- } else if (xcp == xep || Flag(FGMACS)) {
- if (xcp - xbuf == 1) {
- x_e_putc(BEL);
- return KSTD;
- }
- /* Gosling/Unipress emacs style: Swap two characters before the
- * cursor, do not change cursor position
- */
- x_bs(xcp[-1]);
- x_bs(xcp[-2]);
- x_zotc(xcp[-1]);
- x_zotc(xcp[-2]);
- tmp = xcp[-1];
- xcp[-1] = xcp[-2];
- xcp[-2] = tmp;
- } else {
- /* GNU emacs style: Swap the characters before and under the
- * cursor, move cursor position along one.
- */
- x_bs(xcp[-1]);
- x_zotc(xcp[0]);
- x_zotc(xcp[-1]);
- tmp = xcp[-1];
- xcp[-1] = xcp[0];
- xcp[0] = tmp;
- x_bs(xcp[0]);
- x_goto(xcp + 1);
- }
- return KSTD;
-}
-
-static int
-x_literal(c)
- int c;
-{
- x_curprefix = -1;
- return KSTD;
-}
-
-static int
-x_meta1(c)
- int c;
-{
- x_curprefix = 1;
- return KSTD;
-}
-
-static int
-x_meta2(c)
- int c;
-{
- x_curprefix = 2;
- return KSTD;
-}
-
-#ifdef OS2
-static int
-x_meta3(c)
- int c;
-{
- x_curprefix = 3;
- return KSTD;
-}
-#endif /* OS2 */
-
-static int
-x_kill(c)
- int c;
-{
- int col = xcp - xbuf;
- int lastcol = xep - xbuf;
- int ndel;
-
- if (x_arg_defaulted)
- x_arg = lastcol;
- else if (x_arg > lastcol)
- x_arg = lastcol;
- ndel = x_arg - col;
- if (ndel < 0) {
- x_goto(xbuf + x_arg);
- ndel = -ndel;
- }
- x_delete(ndel, TRUE);
- return KSTD;
-}
-
-static void
-x_push(nchars)
- int nchars;
-{
- char *cp = str_nsave(xcp, nchars, AEDIT);
- if (killstack[killsp])
- afree((void *)killstack[killsp], AEDIT);
- killstack[killsp] = cp;
- killsp = (killsp + 1) % KILLSIZE;
-}
-
-static int
-x_yank(c)
- int c;
-{
- if (killsp == 0)
- killtp = KILLSIZE;
- else
- killtp = killsp;
- killtp --;
- if (killstack[killtp] == 0) {
- x_e_puts("\nnothing to yank");
- x_redraw(-1);
- return KSTD;
- }
- xmp = xcp;
- x_ins(killstack[killtp]);
- return KSTD;
-}
-
-static int
-x_meta_yank(c)
- int c;
-{
- int len;
- if (x_last_command != XFUNC_yank && x_last_command != XFUNC_meta_yank) {
- x_e_puts("\nyank something first");
- x_redraw(-1);
- return KSTD;
- }
- len = strlen(killstack[killtp]);
- x_goto(xcp - len);
- x_delete(len, FALSE);
- do {
- if (killtp == 0)
- killtp = KILLSIZE - 1;
- else
- killtp--;
- } while (killstack[killtp] == 0);
- x_ins(killstack[killtp]);
- return KSTD;
-}
-
-static int
-x_abort(c)
- int c;
-{
- /* x_zotc(c); */
- xlp = xep = xcp = xbp = xbuf;
- xlp_valid = TRUE;
- *xcp = 0;
- return KINTR;
-}
-
-static int
-x_error(c)
- int c;
-{
- x_e_putc(BEL);
- return KSTD;
-}
-
-static int
-x_stuffreset(c)
- int c;
-{
-#ifdef TIOCSTI
- (void)x_stuff(c);
- return KINTR;
-#else
- x_zotc(c);
- xlp = xcp = xep = xbp = xbuf;
- xlp_valid = TRUE;
- *xcp = 0;
- x_redraw(-1);
- return KSTD;
-#endif
-}
-
-static int
-x_stuff(c)
- int c;
-{
-#if 0 || defined TIOCSTI
- char ch = c;
- bool_t savmode = x_mode(FALSE);
-
- (void)ioctl(TTY, TIOCSTI, &ch);
- (void)x_mode(savmode);
- x_redraw(-1);
-#endif
- return KSTD;
-}
-
-static char *
-x_mapin(cp)
- const char *cp;
-{
- char *new, *op;
-
- op = new = str_save(cp, ATEMP);
- while (*cp) {
- /* XXX -- should handle \^ escape? */
- if (*cp == '^') {
- cp++;
-#ifdef OS2
- if (*cp == '0') /* To define function keys */
- *op++ = 0xE0;
- else
-#endif /* OS2 */
- if (*cp >= '?') /* includes '?'; ASCII */
- *op++ = CTRL(*cp);
- else {
- *op++ = '^';
- cp--;
- }
- } else
- *op++ = *cp;
- cp++;
- }
- *op = '\0';
-
- return new;
-}
-
-static char *
-x_mapout(c)
- int c;
-{
- static char buf[8];
- register char *p = buf;
-
- if (c < ' ' || c == 0x7F) { /* ASCII */
- *p++ = '^';
- *p++ = (c == 0x7F) ? '?' : (c | 0x40);
-#ifdef OS2
- } else if (c == 0xE0) {
- *p++ = '^';
- *p++ = '0';
-#endif /* OS2 */
- } else
- *p++ = c;
- *p = 0;
- return buf;
-}
-
-static void
-x_print(prefix, key)
- int prefix, key;
-{
- if (prefix == 1)
- shprintf("%s", x_mapout(x_prefix1));
- if (prefix == 2)
- shprintf("%s", x_mapout(x_prefix2));
-#ifdef OS2
- if (prefix == 3)
- shprintf("%s", x_mapout(x_prefix3));
-#endif /* OS2 */
- shprintf("%s = ", x_mapout(key));
- if (x_tab[prefix][key] != XFUNC_ins_string)
- shprintf("%s\n", x_ftab[x_tab[prefix][key]].xf_name);
- else
- shprintf("'%s'\n", x_atab[prefix][key]);
-}
-
-int
-x_bind(a1, a2, macro, list)
- const char *a1, *a2;
- int macro; /* bind -m */
- int list; /* bind -l */
-{
- Findex f;
- int prefix, key;
- char *sp = NULL;
- char *m1, *m2;
-
- if (x_tab == NULL) {
- bi_errorf("cannot bind, not a tty");
- return 1;
- }
-
- /* List function names */
- if (list) {
- for (f = 0; f < NELEM(x_ftab); f++)
- if (x_ftab[f].xf_name
- && !(x_ftab[f].xf_flags & XF_NOBIND))
- shprintf("%s\n", x_ftab[f].xf_name);
- return 0;
- }
-
- if (a1 == NULL) {
- for (prefix = 0; prefix < X_NTABS; prefix++)
- for (key = 0; key < X_TABSZ; key++) {
- f = x_tab[prefix][key];
- if (f == XFUNC_insert || f == XFUNC_error
- || (macro && f != XFUNC_ins_string))
- continue;
- x_print(prefix, key);
- }
- return 0;
- }
-
- m1 = x_mapin(a1);
- prefix = key = 0;
- for (;; m1++) {
- key = *m1 & CHARMASK;
- if (x_tab[prefix][key] == XFUNC_meta1)
- prefix = 1;
- else if (x_tab[prefix][key] == XFUNC_meta2)
- prefix = 2;
-#ifdef OS2
- else if (x_tab[prefix][key] == XFUNC_meta3)
- prefix = 3;
-#endif /* OS2 */
- else
- break;
- }
-
- if (a2 == NULL) {
- x_print(prefix, key);
- return 0;
- }
-
- if (*a2 == 0)
- f = XFUNC_insert;
- else if (!macro) {
- for (f = 0; f < NELEM(x_ftab); f++)
- if (x_ftab[f].xf_name
- && strcmp(x_ftab[f].xf_name, a2) == 0)
- break;
- if (f == NELEM(x_ftab) || x_ftab[f].xf_flags & XF_NOBIND) {
- bi_errorf("%s: no such function", a2);
- return 1;
- }
-#if 0 /* This breaks the bind commands that map arrow keys */
- if (f == XFUNC_meta1)
- x_prefix1 = key;
- if (f == XFUNC_meta2)
- x_prefix2 = key;
-#endif /* 0 */
- } else {
- f = XFUNC_ins_string;
- m2 = x_mapin(a2);
- sp = str_save(m2, AEDIT);
- }
-
- if (x_tab[prefix][key] == XFUNC_ins_string && x_atab[prefix][key])
- afree((void *)x_atab[prefix][key], AEDIT);
- x_tab[prefix][key] = f;
- x_atab[prefix][key] = sp;
-
- return 0;
-}
-
-void
-x_init_emacs()
-{
- register int i, j;
-
- ainit(AEDIT);
- x_nextcmd = -1;
-
- x_tab = (Findex (*)[X_TABSZ]) alloc(sizeofN(*x_tab, X_NTABS), AEDIT);
- for (j = 0; j < X_TABSZ; j++)
- x_tab[0][j] = XFUNC_insert;
- for (i = 1; i < X_NTABS; i++)
- for (j = 0; j < X_TABSZ; j++)
- x_tab[i][j] = XFUNC_error;
- for (i = 0; i < NELEM(x_defbindings); i++)
- x_tab[x_defbindings[i].xdb_tab][x_defbindings[i].xdb_char]
- = x_defbindings[i].xdb_func;
-
- x_atab = (char *(*)[X_TABSZ]) alloc(sizeofN(*x_atab, X_NTABS), AEDIT);
- for (i = 1; i < X_NTABS; i++)
- for (j = 0; j < X_TABSZ; j++)
- x_atab[i][j] = NULL;
-}
-
-void
-x_emacs_keys(ec)
- X_chars *ec;
-{
- x_tab[0][ec->erase] = XFUNC_del_back;
- x_tab[0][ec->kill] = XFUNC_del_line;
- x_tab[0][ec->werase] = XFUNC_del_bword;
- x_tab[0][ec->intr] = XFUNC_abort;
- x_tab[0][ec->quit] = XFUNC_noop;
- x_tab[1][ec->erase] = XFUNC_del_bword;
-}
-
-static int
-x_set_mark(c)
- int c;
-{
- xmp = xcp;
- return KSTD;
-}
-
-static int
-x_kill_region(c)
- int c;
-{
- int rsize;
- char *xr;
-
- if (xmp == NULL) {
- x_e_putc(BEL);
- return KSTD;
- }
- if (xmp > xcp) {
- rsize = xmp - xcp;
- xr = xcp;
- } else {
- rsize = xcp - xmp;
- xr = xmp;
- }
- x_goto(xr);
- x_delete(rsize, TRUE);
- xmp = xr;
- return KSTD;
-}
-
-static int
-x_xchg_point_mark(c)
- int c;
-{
- char *tmp;
-
- if (xmp == NULL) {
- x_e_putc(BEL);
- return KSTD;
- }
- tmp = xmp;
- xmp = xcp;
- x_goto( tmp );
- return KSTD;
-}
-
-static int
-x_version(c)
- int c;
-{
- char *o_xbuf = xbuf, *o_xend = xend;
- char *o_xbp = xbp, *o_xep = xep, *o_xcp = xcp;
- int lim = x_lastcp() - xbp;
-
- xbuf = xbp = xcp = (char *) ksh_version + 4;
- xend = xep = (char *) ksh_version + 4 + strlen(ksh_version + 4);
- x_redraw(lim);
- x_flush();
-
- c = x_e_getc();
- xbuf = o_xbuf;
- xend = o_xend;
- xbp = o_xbp;
- xep = o_xep;
- xcp = o_xcp;
- x_redraw(strlen(ksh_version));
-
- if (c < 0)
- return KSTD;
- /* This is what at&t ksh seems to do... Very bizarre */
- if (c != ' ')
- x_e_ungetc(c);
-
- return KSTD;
-}
-
-static int
-x_noop(c)
- int c;
-{
- return KSTD;
-}
-
-#ifdef SILLY
-static int
-x_game_of_life(c)
- int c;
-{
- char newbuf [256+1];
- register char *ip, *op;
- int i, len;
-
- i = xep - xbuf;
- *xep = 0;
- len = x_size_str(xbuf);
- xcp = xbp = xbuf;
- memmove(newbuf+1, xbuf, i);
- newbuf[0] = 'A';
- newbuf[i] = 'A';
- for (ip = newbuf+1, op = xbuf; --i >= 0; ip++, op++) {
- /* Empty space */
- if (*ip < '@' || *ip == '_' || *ip == 0x7F) {
- /* Two adults, make whoopee */
- if (ip[-1] < '_' && ip[1] < '_') {
- /* Make kid look like parents. */
- *op = '`' + ((ip[-1] + ip[1])/2)%32;
- if (*op == 0x7F) /* Birth defect */
- *op = '`';
- }
- else
- *op = ' '; /* nothing happens */
- continue;
- }
- /* Child */
- if (*ip > '`') {
- /* All alone, dies */
- if (ip[-1] == ' ' && ip[1] == ' ')
- *op = ' ';
- else /* Gets older */
- *op = *ip-'`'+'@';
- continue;
- }
- /* Adult */
- /* Overcrowded, dies */
- if (ip[-1] >= '@' && ip[1] >= '@') {
- *op = ' ';
- continue;
- }
- *op = *ip;
- }
- *op = 0;
- x_redraw(len);
- return KSTD;
-}
-#endif
-
-/*
- * File/command name completion routines
- */
-
-
-static int
-x_comp_comm(c)
- int c;
-{
- do_complete(XCF_COMMAND, CT_COMPLETE);
- return KSTD;
-}
-static int
-x_list_comm(c)
- int c;
-{
- do_complete(XCF_COMMAND, CT_LIST);
- return KSTD;
-}
-static int
-x_complete(c)
- int c;
-{
- do_complete(XCF_COMMAND_FILE, CT_COMPLETE);
- return KSTD;
-}
-static int
-x_enumerate(c)
- int c;
-{
- do_complete(XCF_COMMAND_FILE, CT_LIST);
- return KSTD;
-}
-static int
-x_comp_file(c)
- int c;
-{
- do_complete(XCF_FILE, CT_COMPLETE);
- return KSTD;
-}
-static int
-x_list_file(c)
- int c;
-{
- do_complete(XCF_FILE, CT_LIST);
- return KSTD;
-}
-static int
-x_comp_list(c)
- int c;
-{
- do_complete(XCF_COMMAND_FILE, CT_COMPLIST);
- return KSTD;
-}
-static int
-x_expand(c)
- int c;
-{
- char **words;
- int nwords = 0;
- int start, end;
- int is_command;
- int i;
-
- nwords = x_cf_glob(XCF_FILE,
- xbuf, xep - xbuf, xcp - xbuf,
- &start, &end, &words, &is_command);
-
- if (nwords == 0) {
- x_e_putc(BEL);
- return KSTD;
- }
-
- x_goto(xbuf + start);
- x_delete(end - start, FALSE);
- for (i = 0; i < nwords; i++)
- if (x_ins(words[i]) < 0 || (i < nwords - 1 && x_ins(space) < 0))
- {
- x_e_putc(BEL);
- return KSTD;
- }
-
- return KSTD;
-}
-
-/* type == 0 for list, 1 for complete and 2 for complete-list */
-static void
-do_complete(flags, type)
- int flags; /* XCF_{COMMAND,FILE,COMMAND_FILE} */
- Comp_type type;
-{
- char **words;
- int nwords = 0;
- int start, end;
- int is_command;
- int do_glob = 1;
- Comp_type t = type;
- char *comp_word = (char *) 0;
-
- if (type == CT_COMPLIST) {
- do_glob = 0;
- /* decide what we will do */
- nwords = x_cf_glob(flags,
- xbuf, xep - xbuf, xcp - xbuf,
- &start, &end, &words, &is_command);
- if (nwords > 0) {
- if (nwords > 1) {
- int len = x_longest_prefix(nwords, words);
-
- t = CT_LIST;
- /* Do completion if prefix matches original
- * prefix (ie, no globbing chars), otherwise
- * don't bother
- */
- if (strncmp(words[0], xbuf + start, end - start)
- == 0)
- comp_word = str_nsave(words[0], len,
- ATEMP);
- else
- type = CT_LIST;
- /* Redo globing to show full paths if this
- * is a command.
- */
- if (is_command) {
- do_glob = 1;
- x_free_words(nwords, words);
- }
- } else
- type = t = CT_COMPLETE;
- }
- }
- if (do_glob)
- nwords = x_cf_glob(flags | (t == CT_LIST ? XCF_FULLPATH : 0),
- xbuf, xep - xbuf, xcp - xbuf,
- &start, &end, &words, &is_command);
- if (nwords == 0) {
- x_e_putc(BEL);
- return;
- }
- switch (type) {
- case CT_LIST:
- x_print_expansions(nwords, words, is_command);
- x_redraw(0);
- break;
-
- case CT_COMPLIST:
- /* Only get here if nwords > 1 && comp_word is set */
- {
- int olen = end - start;
- int nlen = strlen(comp_word);
-
- x_print_expansions(nwords, words, is_command);
- xcp = xbuf + end;
- x_do_ins(comp_word + olen, nlen - olen);
- x_redraw(0);
- }
- break;
-
- case CT_COMPLETE:
- {
- int nlen = x_longest_prefix(nwords, words);
-
- if (nlen > 0) {
- x_goto(xbuf + start);
- x_delete(end - start, FALSE);
- words[0][nlen] = '\0';
- x_ins(words[0]);
- /* If single match is not a directory, add a
- * space to the end...
- */
- if (nwords == 1
- && !ISDIRSEP(words[0][nlen - 1]))
- x_ins(space);
- } else
- x_e_putc(BEL);
- }
- break;
- }
-}
-
-/* NAME:
- * x_adjust - redraw the line adjusting starting point etc.
- *
- * DESCRIPTION:
- * This function is called when we have exceeded the bounds
- * of the edit window. It increments x_adj_done so that
- * functions like x_ins and x_delete know that we have been
- * called and can skip the x_bs() stuff which has already
- * been done by x_redraw.
- *
- * RETURN VALUE:
- * None
- */
-
-static void
-x_adjust()
-{
- x_adj_done++; /* flag the fact that we were called. */
- /*
- * we had a problem if the prompt length > xx_cols / 2
- */
- if ((xbp = xcp - (x_displen / 2)) < xbuf)
- xbp = xbuf;
- xlp_valid = FALSE;
- x_redraw(xx_cols);
- x_flush();
-}
-
-static int unget_char = -1;
-
-static void
-x_e_ungetc(c)
- int c;
-{
- unget_char = c;
-}
-
-static int
-x_e_getc()
-{
- int c;
-
- if (unget_char >= 0) {
- c = unget_char;
- unget_char = -1;
- } else {
- if (macroptr) {
- c = *macroptr++;
- if (!*macroptr)
- macroptr = (char *) 0;
- } else
- c = x_getc();
- }
-
- return c <= CHARMASK ? c : (c & CHARMASK);
-}
-
-static void
-x_e_putc(c)
- int c;
-{
- if (c == '\r' || c == '\n')
- x_col = 0;
- if (x_col < xx_cols)
- {
- x_putc(c);
- switch(c)
- {
- case BEL:
- break;
- case '\r':
- case '\n':
- break;
- case '\b':
- x_col--;
- break;
- default:
- x_col++;
- break;
- }
- }
- if (x_adj_ok && (x_col < 0 || x_col >= (xx_cols - 2)))
- {
- x_adjust();
- }
-}
-
-#ifdef DEBUG
-static int
-x_debug_info(c)
- int c;
-{
- x_flush();
- shellf("\nksh debug:\n");
- shellf("\tx_col == %d,\t\tx_cols == %d,\tx_displen == %d\n",
- x_col, xx_cols, x_displen);
- shellf("\txcp == 0x%lx,\txep == 0x%lx\n", (long) xcp, (long) xep);
- shellf("\txbp == 0x%lx,\txbuf == 0x%lx\n", (long) xbp, (long) xbuf);
- shellf("\txlp == 0x%lx\n", (long) xlp);
- shellf("\txlp == 0x%lx\n", (long) x_lastcp());
- shellf(newline);
- x_redraw(-1);
- return 0;
-}
-#endif
-
-static void
-x_e_puts(s)
- const char *s;
-{
- register int adj = x_adj_done;
-
- while (*s && adj == x_adj_done)
- x_e_putc(*s++);
-}
-
-/* NAME:
- * x_set_arg - set an arg value for next function
- *
- * DESCRIPTION:
- * This is a simple implementation of M-[0-9].
- *
- * RETURN VALUE:
- * KSTD
- */
-
-static int
-x_set_arg(c)
- int c;
-{
- int n = 0;
- int first = 1;
-
- c &= CHARMASK; /* strip command prefix */
- for (; c >= 0 && isdigit(c); c = x_e_getc(), first = 0)
- n = n * 10 + (c - '0');
- if (c < 0 || first) {
- x_e_putc(BEL);
- x_arg = 1;
- x_arg_defaulted = 1;
- } else {
- x_e_ungetc(c);
- x_arg = n;
- x_arg_defaulted = 0;
- }
- return KSTD;
-}
-
-
-/* Comment or uncomment the current line. */
-static int
-x_comment(c)
- int c;
-{
- int oldsize = x_size_str(xbuf);
- int len = xep - xbuf;
- int ret = x_do_comment(xbuf, xend - xbuf, &len);
-
- if (ret < 0)
- x_e_putc(BEL);
- else {
- xep = xbuf + len;
- *xep = '\0';
- xcp = xbp = xbuf;
- x_redraw(oldsize);
- if (ret > 0)
- return x_newline('\n');
- }
- return KSTD;
-}
-
-
-/* NAME:
- * x_prev_histword - recover word from prev command
- *
- * DESCRIPTION:
- * This function recovers the last word from the previous
- * command and inserts it into the current edit line. If a
- * numeric arg is supplied then the n'th word from the
- * start of the previous command is used.
- *
- * Bound to M-.
- *
- * RETURN VALUE:
- * KSTD
- */
-
-static int
-x_prev_histword(c)
- int c;
-{
- register char *rcp;
- char *cp;
- char **hp;
-
- hp = x_histp-1;
- if (hp < history || hp > histptr)
- {
- x_e_putc(BEL);
- return KSTD;
- }
- cp = *hp;
- if (x_arg_defaulted) {
- rcp = &cp[strlen(cp) - 1];
- /*
- * ignore white-space after the last word
- */
- while (rcp > cp && is_cfs(*rcp))
- rcp--;
- while (rcp > cp && !is_cfs(*rcp))
- rcp--;
- if (is_cfs(*rcp))
- rcp++;
- x_ins(rcp);
- } else {
- int c;
-
- rcp = cp;
- /*
- * ignore white-space at start of line
- */
- while (*rcp && is_cfs(*rcp))
- rcp++;
- while (x_arg-- > 1)
- {
- while (*rcp && !is_cfs(*rcp))
- rcp++;
- while (*rcp && is_cfs(*rcp))
- rcp++;
- }
- cp = rcp;
- while (*rcp && !is_cfs(*rcp))
- rcp++;
- c = *rcp;
- *rcp = '\0';
- x_ins(cp);
- *rcp = c;
- }
- return KSTD;
-}
-
-/* Uppercase N(1) words */
-static int
-x_fold_upper(c)
- int c;
-{
- return x_fold_case('U');
-}
-
-/* Lowercase N(1) words */
-static int
-x_fold_lower(c)
- int c;
-{
- return x_fold_case('L');
-}
-
-/* Lowercase N(1) words */
-static int
-x_fold_capitialize(c)
- int c;
-{
- return x_fold_case('C');
-}
-
-/* NAME:
- * x_fold_case - convert word to UPPER/lower/Capitial case
- *
- * DESCRIPTION:
- * This function is used to implement M-U,M-u,M-L,M-l,M-C and M-c
- * to UPPER case, lower case or Capitalize words.
- *
- * RETURN VALUE:
- * None
- */
-
-static int
-x_fold_case(c)
- int c;
-{
- char *cp = xcp;
-
- if (cp == xep) {
- x_e_putc(BEL);
- return KSTD;
- }
- while (x_arg--) {
- /*
- * fisrt skip over any white-space
- */
- while (cp != xep && is_mfs(*cp))
- cp++;
- /*
- * do the first char on its own since it may be
- * a different action than for the rest.
- */
- if (cp != xep) {
- if (c == 'L') { /* lowercase */
- if (isupper(*cp))
- *cp = tolower(*cp);
- } else { /* uppercase, capitialize */
- if (islower(*cp))
- *cp = toupper(*cp);
- }
- cp++;
- }
- /*
- * now for the rest of the word
- */
- while (cp != xep && !is_mfs(*cp)) {
- if (c == 'U') { /* uppercase */
- if (islower(*cp))
- *cp = toupper(*cp);
- } else { /* lowercase, capitialize */
- if (isupper(*cp))
- *cp = tolower(*cp);
- }
- cp++;
- }
- }
- x_goto(cp);
- return KSTD;
-}
-
-/* NAME:
- * x_lastcp - last visible char
- *
- * SYNOPSIS:
- * x_lastcp()
- *
- * DESCRIPTION:
- * This function returns a pointer to that char in the
- * edit buffer that will be the last displayed on the
- * screen. The sequence:
- *
- * for (cp = x_lastcp(); cp > xcp; cp)
- * x_bs(*--cp);
- *
- * Will position the cursor correctly on the screen.
- *
- * RETURN VALUE:
- * cp or NULL
- */
-
-static char *
-x_lastcp()
-{
- register char *rcp;
- register int i;
-
- if (!xlp_valid)
- {
- for (i = 0, rcp = xbp; rcp < xep && i < x_displen; rcp++)
- i += x_size(*rcp);
- xlp = rcp;
- }
- xlp_valid = TRUE;
- return (xlp);
-}
-
-#endif /* EDIT */
diff --git a/bin/pdksh/eval.c b/bin/pdksh/eval.c
deleted file mode 100644
index 292294d08ee..00000000000
--- a/bin/pdksh/eval.c
+++ /dev/null
@@ -1,1361 +0,0 @@
-/* $OpenBSD: eval.c,v 1.4 1997/06/19 13:58:40 kstailey Exp $ */
-
-/*
- * Expansion - quoting, separation, substitution, globbing
- */
-
-#include "sh.h"
-#include <pwd.h>
-#include "ksh_dir.h"
-#include "ksh_stat.h"
-
-/*
- * string expansion
- *
- * first pass: quoting, IFS separation, ~, ${}, $() and $(()) substitution.
- * second pass: alternation ({,}), filename expansion (*?[]).
- */
-
-/* expansion generator state */
-typedef struct Expand {
- /* int type; */ /* see expand() */
- const char *str; /* string */
- union {
- const char **strv;/* string[] */
- struct shf *shf;/* file */
- } u; /* source */
- struct tbl *var; /* variable in ${var..} */
- short split; /* split "$@" / call waitlast $() */
-} Expand;
-
-#define XBASE 0 /* scanning original */
-#define XSUB 1 /* expanding ${} string */
-#define XARGSEP 2 /* ifs0 between "$*" */
-#define XARG 3 /* expanding $*, $@ */
-#define XCOM 4 /* expanding $() */
-#define XNULLSUB 5 /* "$@" when $# is 0 (don't generate word) */
-
-/* States used for field splitting */
-#define IFS_WORD 0 /* word has chars (or quotes) */
-#define IFS_WS 1 /* have seen IFS white-space */
-#define IFS_NWS 2 /* have seen IFS non-white-space */
-
-static int varsub ARGS((Expand *xp, char *sp, char *word, int *stypep));
-static int comsub ARGS((Expand *xp, char *cp));
-static char *trimsub ARGS((char *str, char *pat, int how));
-static void glob ARGS((char *cp, XPtrV *wp, int markdirs));
-static void globit ARGS((XString *xs, char **xpp, char *sp, XPtrV *wp,
- int check));
-static char *maybe_expand_tilde ARGS((char *p, XString *dsp, char **dpp,
- int isassign));
-static char *tilde ARGS((char *acp));
-static char *homedir ARGS((char *name));
-#ifdef BRACE_EXPAND
-static void alt_expand ARGS((XPtrV *wp, char *start, char *exp_start,
- char *end, int fdo));
-#endif
-
-/* compile and expand word */
-char *
-substitute(cp, f)
- const char *cp;
- int f;
-{
- struct source *s, *sold;
-
- sold = source;
- s = pushs(SWSTR, ATEMP);
- s->start = s->str = cp;
- source = s;
- if (yylex(ONEWORD) != LWORD)
- internal_errorf(1, "substitute");
- source = sold;
- afree(s, ATEMP);
- return evalstr(yylval.cp, f);
-}
-
-/*
- * expand arg-list
- */
-char **
-eval(ap, f)
- register char **ap;
- int f;
-{
- XPtrV w;
-
- if (*ap == NULL)
- return ap;
- XPinit(w, 32);
- XPput(w, NULL); /* space for shell name */
-#ifdef SHARPBANG
- XPput(w, NULL); /* and space for one arg */
-#endif
- while (*ap != NULL)
- expand(*ap++, &w, f);
- XPput(w, NULL);
-#ifdef SHARPBANG
- return (char **) XPclose(w) + 2;
-#else
- return (char **) XPclose(w) + 1;
-#endif
-}
-
-/*
- * expand string
- */
-char *
-evalstr(cp, f)
- char *cp;
- int f;
-{
- XPtrV w;
-
- XPinit(w, 1);
- expand(cp, &w, f);
- cp = (XPsize(w) == 0) ? null : (char*) *XPptrv(w);
- XPfree(w);
- return cp;
-}
-
-/*
- * expand string - return only one component
- * used from iosetup to expand redirection files
- */
-char *
-evalonestr(cp, f)
- register char *cp;
- int f;
-{
- XPtrV w;
-
- XPinit(w, 1);
- expand(cp, &w, f);
- switch (XPsize(w)) {
- case 0:
- cp = null;
- break;
- case 1:
- cp = (char*) *XPptrv(w);
- break;
- default:
- cp = evalstr(cp, f&~DOGLOB);
- break;
- }
- XPfree(w);
- return cp;
-}
-
-/* for nested substitution: ${var:=$var2} */
-typedef struct SubType {
- short stype; /* [=+-?%#] action after expanded word */
- short base; /* begin position of expanded word */
- short f; /* saved value of f (DOPAT, etc) */
- struct tbl *var; /* variable for ${var..} */
- short quote; /* saved value of quote (for ${..[%#]..}) */
- struct SubType *prev; /* old type */
- struct SubType *next; /* poped type (to avoid re-allocating) */
-} SubType;
-
-void
-expand(cp, wp, f)
- char *cp; /* input word */
- register XPtrV *wp; /* output words */
- int f; /* DO* flags */
-{
- register int UNINITIALIZED(c);
- register int type; /* expansion type */
- register int quote = 0; /* quoted */
- XString ds; /* destination string */
- register char *dp, *sp; /* dest., source */
- int fdo, word; /* second pass flags; have word */
- int doblank; /* field spliting of parameter/command subst */
- Expand x; /* expansion variables */
- SubType st_head, *st;
- int UNINITIALIZED(newlines); /* For trailing newlines in COMSUB */
- int saw_eq, tilde_ok;
- int make_magic;
-
- if (cp == NULL)
- internal_errorf(1, "expand(NULL)");
- /* for alias, readonly, set, typeset commands */
- if ((f & DOVACHECK) && is_wdvarassign(cp)) {
- f &= ~(DOVACHECK|DOBLANK|DOGLOB|DOTILDE);
- f |= DOASNTILDE;
- }
- if (Flag(FNOGLOB))
- f &= ~DOGLOB;
- if (Flag(FMARKDIRS))
- f |= DOMARKDIRS;
-#ifdef BRACE_EXPAND
- if (Flag(FBRACEEXPAND) && (f & DOGLOB))
- f |= DOBRACE_;
-#endif /* BRACE_EXPAND */
-
- Xinit(ds, dp, 128, ATEMP); /* init dest. string */
- type = XBASE;
- sp = cp;
- fdo = 0;
- saw_eq = 0;
- tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0; /* must be 1/0 */
- doblank = 0;
- make_magic = 0;
- word = (f&DOBLANK) ? IFS_WS : IFS_WORD;
- st_head.next = (SubType *) 0;
- st = &st_head;
-
- while (1) {
- Xcheck(ds, dp);
-
- switch (type) {
- case XBASE: /* original prefixed string */
- c = *sp++;
- switch (c) {
- case EOS:
- c = 0;
- break;
- case CHAR:
- c = *sp++;
- break;
- case QCHAR:
- quote |= 2; /* temporary quote */
- c = *sp++;
- break;
- case OQUOTE:
- word = IFS_WORD;
- tilde_ok = 0;
- quote = 1;
- continue;
- case CQUOTE:
- quote = 0;
- continue;
- case COMSUB:
- tilde_ok = 0;
- if (f & DONTRUNCOMMAND) {
- word = IFS_WORD;
- *dp++ = '$'; *dp++ = '(';
- while (*sp != '\0') {
- Xcheck(ds, dp);
- *dp++ = *sp++;
- }
- *dp++ = ')';
- } else {
- type = comsub(&x, sp);
- if (type == XCOM && (f&DOBLANK))
- doblank++;
- sp = strchr(sp, 0) + 1;
- newlines = 0;
- }
- continue;
- case EXPRSUB:
- word = IFS_WORD;
- tilde_ok = 0;
- if (f & DONTRUNCOMMAND) {
- *dp++ = '$'; *dp++ = '('; *dp++ = '(';
- while (*sp != '\0') {
- Xcheck(ds, dp);
- *dp++ = *sp++;
- }
- *dp++ = ')'; *dp++ = ')';
- } else {
- struct tbl v;
- char *p;
-
- v.flag = DEFINED|ISSET|INTEGER;
- v.type = 10; /* not default */
- v.name[0] = '\0';
- v_evaluate(&v, substitute(sp, 0),
- FALSE);
- sp = strchr(sp, 0) + 1;
- for (p = str_val(&v); *p; ) {
- Xcheck(ds, dp);
- *dp++ = *p++;
- }
- }
- continue;
- case OSUBST: /* ${{#}var{:}[=+-?#%]word} */
- /* format is:
- * OSUBST plain-variable-part \0
- * compiled-word-part CSUBST
- * This is were all syntax checking gets done...
- */
- {
- char *varname = sp;
- int stype;
-
- sp = strchr(sp, '\0') + 1; /* skip variable */
- type = varsub(&x, varname, sp, &stype);
- if (type < 0) {
- char endc;
- char *str, *end;
-
- end = (char *) wdscan(sp, CSUBST);
- endc = *end;
- *end = EOS;
- str = snptreef((char *) 0, 64, "%S",
- varname - 1);
- *end = endc;
- errorf("%s: bad substitution", str);
- }
- if (f&DOBLANK)
- doblank++;
- tilde_ok = 0;
- if (type == XBASE) { /* expand? */
- if (!st->next) {
- SubType *newst;
-
- newst = (SubType *) alloc(
- sizeof(SubType), ATEMP);
- newst->next = (SubType *) 0;
- newst->prev = st;
- st->next = newst;
- }
- st = st->next;
- st->stype = stype;
- st->base = Xsavepos(ds, dp);
- st->f = f;
- st->var = x.var;
- st->quote = quote;
- /* skip qualifier(s) */
- if (stype) {
- sp += 2;
- /* :[-+=?] or double [#%] */
- if (stype & 0x80)
- sp += 2;
- }
- switch (stype & 0x7f) {
- case '#':
- case '%':
- /* ! DOBLANK,DOBRACE_,DOTILDE */
- f = DOPAT | (f&DONTRUNCOMMAND)
- | DOTEMP_;
- quote = 0;
- break;
- case '=':
- /* Enabling tilde expansion
- * after :'s here is
- * non-standard ksh, but is
- * consistent with rules for
- * other assignments. Not
- * sure what POSIX thinks of
- * this.
- * Not doing tilde expansion
- * for integer variables is a
- * non-POSIX thing - makes
- * sense though, since ~ is
- * a arithmetic operator.
- */
-#if !defined(__hppa) || __GNUC__ != 2 /* gcc 2.3.3 on hp-pa dies on this - ifdef goes away as soon as I get a new version of gcc.. */
- if (!(x.var->flag & INTEGER))
- f |= DOASNTILDE|DOTILDE;
- f |= DOTEMP_;
-#else
- f |= DOTEMP_|DOASNTILDE|DOTILDE;
-#endif
- /* These will be done after the
- * value has been assigned.
- */
- f &= ~(DOBLANK|DOGLOB|DOBRACE_);
- tilde_ok = 1;
- break;
- case '?':
- f &= ~DOBLANK;
- f |= DOTEMP_;
- /* fall through */
- default:
- /* Enable tilde expansion */
- tilde_ok = 1;
- f |= DOTILDE;
- }
- } else
- /* skip word */
- sp = (char *) wdscan(sp, CSUBST);
- continue;
- }
- case CSUBST: /* only get here if expanding word */
- tilde_ok = 0; /* in case of ${unset:-} */
- *dp = '\0';
- quote = st->quote;
- f = st->f;
- if (f&DOBLANK)
- doblank--;
- switch (st->stype&0x7f) {
- case '#':
- case '%':
- dp = Xrestpos(ds, dp, st->base);
- /* Must use st->var since calling
- * global would break things
- * like x[i+=1].
- */
- x.str = trimsub(str_val(st->var),
- dp, st->stype);
- type = XSUB;
- if (f&DOBLANK)
- doblank++;
- st = st->prev;
- continue;
- case '=':
- if (st->var->flag & RDONLY)
- /* XXX POSIX says this is only
- * fatal for special builtins
- */
- errorf("%s: is read only",
- st->var->name);
- /* Restore our position and substitute
- * the value of st->var (may not be
- * the assigned value in the presence
- * of integer/right-adj/etc attributes).
- */
- dp = Xrestpos(ds, dp, st->base);
- /* Must use st->var since calling
- * global would cause with things
- * like x[i+=1] to be evaluated twice.
- */
- setstr(st->var, debunk(
- (char *) alloc(strlen(dp) + 1,
- ATEMP), dp));
- x.str = str_val(st->var);
- type = XSUB;
- if (f&DOBLANK)
- doblank++;
- st = st->prev;
- continue;
- case '?':
- {
- char *s = Xrestpos(ds, dp, st->base);
-
- errorf("%s: %s", st->var->name,
- dp == s ?
- "parameter null or not set"
- : (debunk(s, s), s));
- }
- }
- st = st->prev;
- type = XBASE;
- continue;
-
- case OPAT: /* open pattern: *(foo|bar) */
- /* Next char is the type of pattern */
- make_magic = 1;
- c = *sp++ + 0x80;
- break;
-
- case SPAT: /* pattern seperator (|) */
- make_magic = 1;
- c = '|';
- break;
-
- case CPAT: /* close pattern */
- make_magic = 1;
- c = /*(*/ ')';
- break;
- }
- break;
-
- case XNULLSUB:
- /* Special case for "$@" (and "${foo[@]}") - no
- * word is generated if $# is 0 (unless there is
- * other stuff inside the quotes).
- */
- type = XBASE;
- if (f&DOBLANK) {
- doblank--;
- /* not really correct: x=; "$x$@" should
- * generate a null argument and
- * set A; "${@:+}" shouldn't.
- */
- if (dp == Xstring(ds, dp))
- word = IFS_WS;
- }
- continue;
-
- case XSUB:
- if ((c = *x.str++) == 0) {
- type = XBASE;
- if (f&DOBLANK)
- doblank--;
- continue;
- }
- break;
-
- case XARGSEP:
- type = XARG;
- quote = 1;
- case XARG:
- if ((c = *x.str++) == '\0') {
- /* force null words to be created so
- * set -- '' 2 ''; foo "$@" will do
- * the right thing
- */
- if (quote && x.split)
- word = IFS_WORD;
- if ((x.str = *x.u.strv++) == NULL) {
- type = XBASE;
- if (f&DOBLANK)
- doblank--;
- continue;
- }
- c = ifs0;
- if (c == 0) {
- if (quote && !x.split)
- continue;
- c = ' ';
- }
- if (quote && x.split) {
- /* terminate word for "$@" */
- type = XARGSEP;
- quote = 0;
- }
- }
- break;
-
- case XCOM:
- if (newlines) { /* Spit out saved nl's */
- c = '\n';
- --newlines;
- } else {
- while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
- if (c == '\n')
- newlines++; /* Save newlines */
- if (newlines && c != EOF) {
- shf_ungetc(c, x.u.shf);
- c = '\n';
- --newlines;
- }
- }
- if (c == EOF) {
- newlines = 0;
- shf_close(x.u.shf);
- if (x.split)
- subst_exstat = waitlast();
- type = XBASE;
- if (f&DOBLANK)
- doblank--;
- continue;
- }
- break;
- }
-
- /* check for end of word or IFS separation */
- if (c == 0 || (!quote && (f & DOBLANK) && doblank && !make_magic
- && ctype(c, C_IFS)))
- {
- /* How words are broken up:
- * | value of c
- * word | ws nws 0
- * -----------------------------------
- * IFS_WORD w/WS w/NWS w
- * IFS_WS -/WS w/NWS -
- * IFS_NWS -/NWS w/NWS w
- * (w means generate a word)
- * Note that IFS_NWS/0 generates a word (at&t ksh
- * doesn't do this, but POSIX does).
- */
- if (word == IFS_WORD
- || (!ctype(c, C_IFSWS) && (c || word == IFS_NWS)))
- {
- char *p;
-
- *dp++ = '\0';
- p = Xclose(ds, dp);
-#ifdef BRACE_EXPAND
- if (fdo & DOBRACE_)
- /* also does globbing */
- alt_expand(wp, p, p,
- p + Xlength(ds, (dp - 1)),
- fdo | (f & DOMARKDIRS));
- else
-#endif /* BRACE_EXPAND */
- if (fdo & DOGLOB)
- glob(p, wp, f & DOMARKDIRS);
- else if ((f & DOPAT) || !(fdo & DOMAGIC_))
- XPput(*wp, p);
- else
- XPput(*wp, debunk(p, p));
- fdo = 0;
- saw_eq = 0;
- tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0;
- if (c != 0)
- Xinit(ds, dp, 128, ATEMP);
- }
- if (c == 0)
- return;
- if (word != IFS_NWS)
- word = ctype(c, C_IFSWS) ? IFS_WS : IFS_NWS;
- } else {
- /* age tilde_ok info - ~ code tests second bit */
- tilde_ok <<= 1;
- /* mark any special second pass chars */
- if (!quote)
- switch (c) {
- case '[':
- case NOT:
- case '-':
- case ']':
- /* For character classes - doesn't hurt
- * to have magic !,-,]'s outside of
- * [...] expressions.
- */
- if (f & (DOPAT | DOGLOB)) {
- fdo |= DOMAGIC_;
- if (c == '[')
- fdo |= f & DOGLOB;
- *dp++ = MAGIC;
- }
- break;
- case '*':
- case '?':
- if (f & (DOPAT | DOGLOB)) {
- fdo |= DOMAGIC_ | (f & DOGLOB);
- *dp++ = MAGIC;
- }
- break;
-#ifdef BRACE_EXPAND
- case OBRACE:
- case ',':
- case CBRACE:
- if ((f & DOBRACE_) && (c == OBRACE
- || (fdo & DOBRACE_)))
- {
- fdo |= DOBRACE_|DOMAGIC_;
- *dp++ = MAGIC;
- }
- break;
-#endif /* BRACE_EXPAND */
- case '=':
- /* Note first unquoted = for ~ */
- if (!(f & DOTEMP_) && !saw_eq) {
- saw_eq = 1;
- tilde_ok = 1;
- }
- break;
- case PATHSEP: /* : */
- /* Note unquoted : for ~ */
- if (!(f & DOTEMP_) && (f & DOASNTILDE))
- tilde_ok = 1;
- break;
- case '~':
- /* tilde_ok is reset whenever
- * any of ' " $( $(( ${ } are seen.
- * Note that tilde_ok must be preserved
- * through the sequence ${A=a=}~
- */
- if (type == XBASE
- && (f & (DOTILDE|DOASNTILDE))
- && (tilde_ok & 2))
- {
- char *p, *dp_x;
-
- dp_x = dp;
- p = maybe_expand_tilde(sp,
- &ds, &dp_x,
- f & DOASNTILDE);
- if (p) {
- if (dp != dp_x)
- word = IFS_WORD;
- dp = dp_x;
- sp = p;
- continue;
- }
- }
- break;
- }
- else
- quote &= ~2; /* undo temporary */
-
- if (make_magic) {
- make_magic = 0;
- fdo |= DOMAGIC_ | (f & DOGLOB);
- *dp++ = MAGIC;
- } else if (ISMAGIC(c)) {
- fdo |= DOMAGIC_;
- *dp++ = MAGIC;
- }
- *dp++ = c; /* save output char */
- word = IFS_WORD;
- }
- }
-}
-
-/*
- * Prepare to generate the string returned by ${} substitution.
- */
-static int
-varsub(xp, sp, word, stypep)
- Expand *xp;
- char *sp;
- char *word;
- int *stypep;
-{
- int c;
- int state; /* next state: XBASE, XARG, XSUB, XNULLSUB */
- int stype; /* substitution type */
- char *p;
- struct tbl *vp;
-
- if (sp[0] == '\0') /* Bad variable name */
- return -1;
-
- xp->var = (struct tbl *) 0;
-
- /* ${#var}, string length or array size */
- if (sp[0] == '#' && (c = sp[1]) != '\0') {
- int zero_ok = 0;
-
- /* Can't have any modifiers for ${#...} */
- if (*word != CSUBST)
- return -1;
- sp++;
- /* Check for size of array */
- if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') {
- c = 0;
- vp = global(arrayname(sp));
- if (vp->flag & (ISSET|ARRAY))
- zero_ok = 1;
- for (; vp; vp = vp->u.array)
- if (vp->flag&ISSET)
- c = vp->index+1;
- } else if (c == '*' || c == '@')
- c = e->loc->argc;
- else {
- p = str_val(global(sp));
- zero_ok = p != null;
- c = strlen(p);
- }
- if (Flag(FNOUNSET) && c == 0 && !zero_ok)
- errorf("%s: parameter not set", sp);
- *stypep = 0; /* unqualified variable/string substitution */
- xp->str = str_save(ulton((unsigned long)c, 10), ATEMP);
- return XSUB;
- }
-
- /* Check for qualifiers in word part */
- stype = 0;
- c = *word == CHAR ? word[1] : 0;
- if (c == ':') {
- stype = 0x80;
- c = word[2] == CHAR ? word[3] : 0;
- }
- if (ctype(c, C_SUBOP1))
- stype |= c;
- else if (stype) /* :, :# or :% is not ok */
- return -1;
- else if (ctype(c, C_SUBOP2)) {
- stype = c;
- if (word[2] == CHAR && c == word[3])
- stype |= 0x80;
- }
- if (!stype && *word != CSUBST)
- return -1;
- *stypep = stype;
-
- c = sp[0];
- if (c == '*' || c == '@') {
- switch (stype & 0x7f) {
- case '=': /* can't assign to a vector */
- case '%': /* can't trim a vector */
- case '#':
- return -1;
- }
- if (e->loc->argc == 0) {
- xp->str = null;
- state = c == '@' ? XNULLSUB : XSUB;
- } else {
- xp->u.strv = (const char **) e->loc->argv + 1;
- xp->str = *xp->u.strv++;
- xp->split = c == '@'; /* $@ */
- state = XARG;
- }
- } else {
- if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') {
- XPtrV wv;
-
- switch (stype & 0x7f) {
- case '=': /* can't assign to a vector */
- case '%': /* can't trim a vector */
- case '#':
- return -1;
- }
- XPinit(wv, 32);
- vp = global(arrayname(sp));
- for (; vp; vp = vp->u.array) {
- if (!(vp->flag&ISSET))
- continue;
- XPput(wv, str_val(vp));
- }
- if (XPsize(wv) == 0) {
- xp->str = null;
- state = p[1] == '@' ? XNULLSUB : XSUB;
- XPfree(wv);
- } else {
- XPput(wv, 0);
- xp->u.strv = (const char **) XPptrv(wv);
- xp->str = *xp->u.strv++;
- xp->split = p[1] == '@'; /* ${foo[@]} */
- state = XARG;
- }
- } else {
- /* Can't assign things like $! or $1 */
- if ((stype & 0x7f) == '='
- && (ctype(*sp, C_VAR1) || digit(*sp)))
- return -1;
- xp->var = global(sp);
- xp->str = str_val(xp->var);
- state = XSUB;
- }
- }
-
- c = stype&0x7f;
- /* test the compiler's code generator */
- if (ctype(c, C_SUBOP2) ||
- (((stype&0x80) ? *xp->str=='\0' : xp->str==null) ? /* undef? */
- c == '=' || c == '-' || c == '?' : c == '+'))
- state = XBASE; /* expand word instead of variable value */
- if (Flag(FNOUNSET) && xp->str == null
- && (ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
- errorf("%s: parameter not set", sp);
- return state;
-}
-
-/*
- * Run the command in $(...) and read its output.
- */
-static int
-comsub(xp, cp)
- register Expand *xp;
- char *cp;
-{
- Source *s, *sold;
- register struct op *t;
- struct shf *shf;
-
- s = pushs(SSTRING, ATEMP);
- s->start = s->str = cp;
- sold = source;
- t = compile(s);
- source = sold;
-
- if (t == NULL)
- return XBASE;
-
- if (t != NULL && t->type == TCOM && /* $(<file) */
- *t->args == NULL && *t->vars == NULL && t->ioact != NULL) {
- register struct ioword *io = *t->ioact;
- char *name;
-
- if ((io->flag&IOTYPE) != IOREAD)
- errorf("funny $() command: %s",
- snptreef((char *) 0, 32, "%R", io));
- shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0,
- SHF_MAPHI|SHF_CLEXEC);
- if (shf == NULL)
- errorf("%s: cannot open $() input", name);
- xp->split = 0; /* no waitlast() */
- } else {
- int ofd1, pv[2];
- openpipe(pv);
- shf = shf_fdopen(pv[0], SHF_RD, (struct shf *) 0);
- ofd1 = savefd(1, 0); /* fd 1 may be closed... */
- ksh_dup2(pv[1], 1, FALSE);
- close(pv[1]);
- execute(t, XFORK|XXCOM|XPIPEO);
- restfd(1, ofd1);
- startlast();
- xp->split = 1; /* waitlast() */
- }
-
- xp->u.shf = shf;
- return XCOM;
-}
-
-/*
- * perform #pattern and %pattern substitution in ${}
- */
-
-static char *
-trimsub(str, pat, how)
- register char *str;
- char *pat;
- int how;
-{
- register char *end = strchr(str, 0);
- register char *p, c;
-
- switch (how&0xff) { /* UCHAR_MAX maybe? */
- case '#': /* shortest at begining */
- for (p = str; p <= end; p++) {
- c = *p; *p = '\0';
- if (gmatch(str, pat, FALSE)) {
- *p = c;
- return p;
- }
- *p = c;
- }
- break;
- case '#'|0x80: /* longest match at begining */
- for (p = end; p >= str; p--) {
- c = *p; *p = '\0';
- if (gmatch(str, pat, FALSE)) {
- *p = c;
- return p;
- }
- *p = c;
- }
- break;
- case '%': /* shortest match at end */
- for (p = end; p >= str; p--) {
- if (gmatch(p, pat, FALSE))
- return str_nsave(str, p - str, ATEMP);
- }
- break;
- case '%'|0x80: /* longest match at end */
- for (p = str; p <= end; p++) {
- if (gmatch(p, pat, FALSE))
- return str_nsave(str, p - str, ATEMP);
- }
- break;
- }
-
- return str; /* no match, return string */
-}
-
-/*
- * glob
- * Name derived from V6's /etc/glob, the program that expanded filenames.
- */
-
-/* XXX cp not const 'cause slashes are temporarily replaced with nulls... */
-static void
-glob(cp, wp, markdirs)
- char *cp;
- register XPtrV *wp;
- int markdirs;
-{
- int oldsize = XPsize(*wp);
-
- if (glob_str(cp, wp, markdirs) == 0)
- XPput(*wp, debunk(cp, cp));
- else
- qsortp(XPptrv(*wp) + oldsize, (size_t)(XPsize(*wp) - oldsize),
- xstrcmp);
-}
-
-#define GF_NONE 0
-#define GF_EXCHECK BIT(0) /* do existance check on file */
-#define GF_GLOBBED BIT(1) /* some globbing has been done */
-#define GF_MARKDIR BIT(2) /* add trailing / to directories */
-
-/* Apply file globbing to cp and store the matching files in wp. Returns
- * the number of matches found.
- */
-int
-glob_str(cp, wp, markdirs)
- char *cp;
- XPtrV *wp;
- int markdirs;
-{
- int oldsize = XPsize(*wp);
- XString xs;
- char *xp;
-
- Xinit(xs, xp, 256, ATEMP);
- globit(&xs, &xp, cp, wp, markdirs ? GF_MARKDIR : GF_NONE);
- Xfree(xs, xp);
-
- return XPsize(*wp) - oldsize;
-}
-
-static void
-globit(xs, xpp, sp, wp, check)
- XString *xs; /* dest string */
- char **xpp; /* ptr to dest end */
- char *sp; /* source path */
- register XPtrV *wp; /* output list */
- int check; /* GF_* flags */
-{
- register char *np; /* next source component */
- char *xp = *xpp;
- char *se;
- char odirsep;
-
- /* This to allow long expansions to be interrupted */
- intrcheck();
-
- if (sp == NULL) { /* end of source path */
- /* We only need to check if the file exists if a pattern
- * is followed by a non-pattern (eg, foo*x/bar; no check
- * is needed for foo* since the match must exist) or if
- * any patterns were expanded and the markdirs option is set.
- * Symlinks make things a bit tricky...
- */
- if ((check & GF_EXCHECK)
- || ((check & GF_MARKDIR) && (check & GF_GLOBBED)))
- {
-#define stat_check() (stat_done ? stat_done : \
- (stat_done = stat(Xstring(*xs, xp), &statb) < 0 \
- ? -1 : 1))
- struct stat lstatb, statb;
- int stat_done = 0; /* -1: failed, 1 ok */
-
- if (lstat(Xstring(*xs, xp), &lstatb) < 0)
- return;
- /* special case for systems which strip trailing
- * slashes from regular files (eg, /etc/passwd/).
- * SunOS 4.1.3 does this...
- */
- if ((check & GF_EXCHECK) && xp > Xstring(*xs, xp)
- && ISDIRSEP(xp[-1]) && !S_ISDIR(lstatb.st_mode)
-#ifdef S_ISLNK
- && (!S_ISLNK(lstatb.st_mode)
- || stat_check() < 0
- || !S_ISDIR(statb.st_mode))
-#endif /* S_ISLNK */
- )
- return;
- /* Possibly tack on a trailing / if there isn't already
- * one and if the file is a directory or a symlink to a
- * directory
- */
- if (((check & GF_MARKDIR) && (check & GF_GLOBBED))
- && xp > Xstring(*xs, xp) && !ISDIRSEP(xp[-1])
- && (S_ISDIR(lstatb.st_mode)
-#ifdef S_ISLNK
- || (S_ISLNK(lstatb.st_mode)
- && stat_check() > 0
- && S_ISDIR(statb.st_mode))
-#endif /* S_ISLNK */
- ))
- {
- *xp++ = DIRSEP;
- *xp = '\0';
- }
- }
-#ifdef OS2 /* Done this way to avoid bug in gcc 2.7.2... */
- /* Ugly kludge required for command
- * completion - see how search_access()
- * is implemented for OS/2...
- */
-# define KLUDGE_VAL 4
-#else /* OS2 */
-# define KLUDGE_VAL 0
-#endif /* OS2 */
- XPput(*wp, str_nsave(Xstring(*xs, xp), Xlength(*xs, xp)
- + KLUDGE_VAL, ATEMP));
- return;
- }
-
- if (xp > Xstring(*xs, xp))
- *xp++ = DIRSEP;
- while (ISDIRSEP(*sp)) {
- Xcheck(*xs, xp);
- *xp++ = *sp++;
- }
- np = ksh_strchr_dirsep(sp);
- if (np != NULL) {
- se = np;
- odirsep = *np; /* don't assume DIRSEP, can be multiple kinds */
- *np++ = '\0';
- } else {
- odirsep = '\0'; /* keep gcc quiet */
- se = sp + strlen(sp);
- }
-
-
- /* Check if sp needs globbing - done to avoid pattern checks for strings
- * containing MAGIC characters, open ['s without the matching close ],
- * etc. (otherwise opendir() will be called which may fail because the
- * directory isn't readable - if no globbing is needed, only execute
- * permission should be required (as per POSIX)).
- */
- if (!has_globbing(sp, se)) {
- XcheckN(*xs, xp, se - sp + 1);
- debunk(xp, sp);
- xp += strlen(xp);
- *xpp = xp;
- globit(xs, xpp, np, wp, check);
- } else {
- DIR *dirp;
- struct dirent *d;
- char *name;
- int len;
- int prefix_len;
-
- /* xp = *xpp; copy_non_glob() may have re-alloc'd xs */
- *xp = '\0';
- prefix_len = Xlength(*xs, xp);
- dirp = ksh_opendir(prefix_len ? Xstring(*xs, xp) : ".");
- if (dirp == NULL)
- goto Nodir;
- while ((d = readdir(dirp)) != NULL) {
- name = d->d_name;
- if (name[0] == '.' &&
- (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
- continue; /* always ignore . and .. */
- if ((*name == '.' && *sp != '.')
- || !gmatch(name, sp, TRUE))
- continue;
-
- len = NLENGTH(d) + 1;
- XcheckN(*xs, xp, len);
- memcpy(xp, name, len);
- *xpp = xp + len - 1;
- globit(xs, xpp, np, wp,
- (check & GF_MARKDIR) | GF_GLOBBED
- | (np ? GF_EXCHECK : GF_NONE));
- xp = Xstring(*xs, xp) + prefix_len;
- }
- closedir(dirp);
- Nodir:;
- }
-
- if (np != NULL)
- *--np = odirsep;
-}
-
-#if 0
-/* Check if p contains something that needs globbing; if it does, 0 is
- * returned; if not, p is copied into xs/xp after stripping any MAGICs
- */
-static int copy_non_glob ARGS((XString *xs, char **xpp, char *p));
-static int
-copy_non_glob(xs, xpp, p)
- XString *xs;
- char **xpp;
- char *p;
-{
- char *xp;
- int len = strlen(p);
-
- XcheckN(*xs, *xpp, len);
- xp = *xpp;
- for (; *p; p++) {
- if (ISMAGIC(*p)) {
- int c = *++p;
-
- if (c == '*' || c == '?')
- return 0;
- if (*p == '[') {
- char *q = p + 1;
-
- if (ISMAGIC(*q) && q[1] == NOT)
- q += 2;
- if (ISMAGIC(*q) && q[1] == ']')
- q += 2;
- for (; *q; q++)
- if (ISMAGIC(*q) && *++q == ']')
- return 0;
- /* pass a literal [ through */
- }
- /* must be a MAGIC-MAGIC, or MAGIC-!, MAGIC--, etc. */
- }
- *xp++ = *p;
- }
- *xp = '\0';
- *xpp = xp;
- return 1;
-}
-#endif /* 0 */
-
-/* remove MAGIC from string */
-char *
-debunk(dp, sp)
- char *dp;
- const char *sp;
-{
- char *d, *s;
-
- if ((s = strchr(sp, MAGIC))) {
- memcpy(dp, sp, s - sp);
- for (d = dp + (s - sp); *s; s++)
- if (!ISMAGIC(*s) || !(*++s & 0x80)
- || !strchr("*+?@!", *s & 0x7f))
- *d++ = *s;
- else {
- /* extended pattern operators: *+?@! */
- *d++ = *s & 0x7f;
- *d++ = '(';
- }
- *d = '\0';
- } else if (dp != sp)
- strcpy(dp, sp);
- return dp;
-}
-
-/* Check if p is an unquoted name, possibly followed by a / or :. If so
- * puts the expanded version in *dcp,dp and returns a pointer in p just
- * past the name, otherwise returns 0.
- */
-static char *
-maybe_expand_tilde(p, dsp, dpp, isassign)
- char *p;
- XString *dsp;
- char **dpp;
- int isassign;
-{
- XString ts;
- char *dp = *dpp;
- char *tp, *r;
-
- Xinit(ts, tp, 16, ATEMP);
- /* : only for DOASNTILDE form */
- while (p[0] == CHAR && !ISDIRSEP(p[1])
- && (!isassign || p[1] != PATHSEP))
- {
- Xcheck(ts, tp);
- *tp++ = p[1];
- p += 2;
- }
- *tp = '\0';
- r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ? tilde(Xstring(ts, tp)) : (char *) 0;
- Xfree(ts, tp);
- if (r) {
- while (*r) {
- Xcheck(*dsp, dp);
- if (ISMAGIC(*r))
- *dp++ = MAGIC;
- *dp++ = *r++;
- }
- *dpp = dp;
- r = p;
- }
- return r;
-}
-
-/*
- * tilde expansion
- *
- * based on a version by Arnold Robbins
- */
-
-static char *
-tilde(cp)
- char *cp;
-{
- char *dp;
-
- if (cp[0] == '\0')
- dp = str_val(global("HOME"));
- else if (cp[0] == '+' && cp[1] == '\0')
- dp = str_val(global("PWD"));
- else if (cp[0] == '-' && cp[1] == '\0')
- dp = str_val(global("OLDPWD"));
- else
- dp = homedir(cp);
- /* If HOME, PWD or OLDPWD are not set, don't expand ~ */
- if (dp == null)
- dp = (char *) 0;
- return dp;
-}
-
-/*
- * map userid to user's home directory.
- * note that 4.3's getpw adds more than 6K to the shell,
- * and the YP version probably adds much more.
- * we might consider our own version of getpwnam() to keep the size down.
- */
-
-static char *
-homedir(name)
- char *name;
-{
- register struct tbl *ap;
-
- ap = tenter(&homedirs, name, hash(name));
- if (!(ap->flag & ISSET)) {
-#ifdef OS2
- /* No usernames in OS2 - punt */
- return NULL;
-#else /* OS2 */
- struct passwd *pw;
-
- pw = getpwnam(name);
- if (pw == NULL)
- return NULL;
- ap->val.s = str_save(pw->pw_dir, APERM);
- ap->flag |= DEFINED|ISSET|ALLOC;
-#endif /* OS2 */
- }
- return ap->val.s;
-}
-
-#ifdef BRACE_EXPAND
-static void
-alt_expand(wp, start, exp_start, end, fdo)
- XPtrV *wp;
- char *start, *exp_start;
- char *end;
- int fdo;
-{
- int UNINITIALIZED(count);
- char *brace_start, *brace_end, *UNINITIALIZED(comma);
- char *field_start;
- char *p;
-
- /* search for open brace */
- for (p = exp_start; (p = strchr(p, MAGIC)) && p[1] != OBRACE; p += 2)
- ;
- brace_start = p;
-
- /* find matching close brace, if any */
- if (p) {
- comma = (char *) 0;
- count = 1;
- for (p += 2; *p && count; p++) {
- if (ISMAGIC(*p)) {
- if (*++p == OBRACE)
- count++;
- else if (*p == CBRACE)
- --count;
- else if (*p == ',' && count == 1)
- comma = p;
- }
- }
- }
- /* no valid expansions... */
- if (!p || count != 0) {
- /* Note that given a{{b,c} we do not expand anything (this is
- * what at&t ksh does. This may be changed to do the {b,c}
- * expansion. }
- */
- if (fdo & DOGLOB)
- glob(start, wp, fdo & DOMARKDIRS);
- else
- XPput(*wp, debunk(start, start));
- return;
- }
- brace_end = p;
- if (!comma) {
- alt_expand(wp, start, brace_end, end, fdo);
- return;
- }
-
- /* expand expression */
- field_start = brace_start + 2;
- count = 1;
- for (p = brace_start + 2; p != brace_end; p++) {
- if (ISMAGIC(*p)) {
- if (*++p == OBRACE)
- count++;
- else if ((*p == CBRACE && --count == 0)
- || (*p == ',' && count == 1))
- {
- char *new;
- int l1, l2, l3;
-
- l1 = brace_start - start;
- l2 = (p - 1) - field_start;
- l3 = end - brace_end;
- new = (char *) alloc(l1 + l2 + l3 + 1, ATEMP);
- memcpy(new, start, l1);
- memcpy(new + l1, field_start, l2);
- memcpy(new + l1 + l2, brace_end, l3);
- new[l1 + l2 + l3] = '\0';
- alt_expand(wp, new, new + l1,
- new + l1 + l2 + l3, fdo);
- field_start = p + 1;
- }
- }
- }
- return;
-}
-#endif /* BRACE_EXPAND */
diff --git a/bin/pdksh/exec.c b/bin/pdksh/exec.c
deleted file mode 100644
index 7c98d956239..00000000000
--- a/bin/pdksh/exec.c
+++ /dev/null
@@ -1,1671 +0,0 @@
-/* $OpenBSD: exec.c,v 1.10 1997/09/12 04:38:05 millert Exp $ */
-
-/*
- * execute command tree
- */
-
-#include "sh.h"
-#include "c_test.h"
-#include <ctype.h>
-#include "ksh_stat.h"
-
-/* Does ps4 get parameter substitutions done? */
-#ifdef KSH
-# define PS4_SUBSTITUTE(s) substitute((s), 0)
-#else
-# define PS4_SUBSTITUTE(s) (s)
-#endif /* KSH */
-
-static int comexec ARGS((struct op *t, struct tbl *volatile tp, char **ap,
- int volatile flags));
-static void scriptexec ARGS((struct op *tp, char **ap));
-static int call_builtin ARGS((struct tbl *tp, char **wp));
-static int iosetup ARGS((struct ioword *iop, struct tbl *tp));
-static int herein ARGS((char *hname, int sub));
-#ifdef KSH
-static char *do_selectargs ARGS((char **ap, bool_t print_menu));
-#endif /* KSH */
-#ifdef KSH
-static int dbteste_isa ARGS((Test_env *te, Test_meta meta));
-static const char *dbteste_getopnd ARGS((Test_env *te, Test_op op,
- int do_eval));
-static int dbteste_eval ARGS((Test_env *te, Test_op op, const char *opnd1,
- const char *opnd2, int do_eval));
-static void dbteste_error ARGS((Test_env *te, int offset, const char *msg));
-#endif /* KSH */
-#ifdef OS2
-static int search_access1 ARGS((const char *path, int mode, int *errnop));
-#endif /* OS2 */
-
-
-/*
- * handle systems that don't have F_SETFD
- */
-#ifndef F_SETFD
-# ifndef MAXFD
-# define MAXFD 64
-# endif
-/* a bit field would be smaller, but this will work */
-static char clexec_tab[MAXFD+1];
-#endif
-
-/*
- * we now use this function always.
- */
-int
-fd_clexec(fd)
- int fd;
-{
-#ifndef F_SETFD
- if (fd >= 0 && fd < sizeof(clexec_tab)) {
- clexec_tab[fd] = 1;
- return 0;
- }
- return -1;
-#else
- return fcntl(fd, F_SETFD, 1);
-#endif
-}
-
-
-/*
- * execute command tree
- */
-int
-execute(t, flags)
- struct op * volatile t;
- volatile int flags; /* if XEXEC don't fork */
-{
- int i;
- volatile int rv = 0;
- int pv[2];
- char ** volatile ap;
- char *s, *cp;
- struct ioword **iowp;
- struct tbl *tp = NULL;
-
- if (t == NULL)
- return 0;
-
- /* Is this the end of a pipeline? If so, we want to evaluate the
- * command arguments
- bool_t eval_done = FALSE;
- if ((flags&XFORK) && !(flags&XEXEC) && (flags&XPCLOSE)) {
- eval_done = TRUE;
- tp = eval_execute_args(t, &ap);
- }
- */
- if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
- return exchild(t, flags, -1); /* run in sub-process */
-
- newenv(E_EXEC);
- if (trap)
- runtraps(0);
-
- if (t->type == TCOM) {
- /* Clear subst_exstat before argument expansion. Used by
- * null commands (see comexec()) and by c_set().
- */
- subst_exstat = 0;
-
- /* POSIX says expand command words first, then redirections,
- * and assignments last..
- */
- ap = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE);
- if (Flag(FXTRACE) && ap[0]) {
- shf_fprintf(shl_out, "%s",
- PS4_SUBSTITUTE(str_val(global("PS4"))));
- for (i = 0; ap[i]; i++)
- shf_fprintf(shl_out, "%s%s", ap[i],
- ap[i + 1] ? space : newline);
- shf_flush(shl_out);
- }
- if (ap[0])
- tp = findcom(ap[0], FC_BI|FC_FUNC);
- }
-
- if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {
- e->savefd = (short *) alloc(sizeofN(short, NUFILE), ATEMP);
- /* initialize to not redirected */
- memset(e->savefd, 0, sizeofN(short, NUFILE));
- }
-
- /* do redirection, to be restored in quitenv() */
- if (t->ioact != NULL)
- for (iowp = t->ioact; *iowp != NULL; iowp++) {
- if (iosetup(*iowp, tp) < 0) {
- exstat = rv = 1;
- /* Redirection failures for special commands
- * cause (non-interactive) shell to exit.
- */
- if (tp && tp->type == CSHELL
- && (tp->flag & SPEC_BI))
- errorf(null);
- /* Deal with FERREXIT, quitenv(), etc. */
- goto Break;
- }
- }
-
- switch(t->type) {
- case TCOM:
- rv = comexec(t, tp, ap, flags);
- break;
-
- case TPAREN:
- rv = execute(t->left, flags|XFORK);
- break;
-
- case TPIPE:
- flags |= XFORK;
- flags &= ~XEXEC;
- e->savefd[0] = savefd(0, 0);
- (void) ksh_dup2(e->savefd[0], 0, FALSE); /* stdin of first */
- e->savefd[1] = savefd(1, 0);
- while (t->type == TPIPE) {
- openpipe(pv);
- (void) ksh_dup2(pv[1], 1, FALSE); /* stdout of curr */
- /* Let exchild() close pv[0] in child
- * (if this isn't done, commands like
- * (: ; cat /etc/termcap) | sleep 1
- * will hang forever).
- */
- exchild(t->left, flags|XPIPEO|XCCLOSE, pv[0]);
- (void) ksh_dup2(pv[0], 0, FALSE); /* stdin of next */
- closepipe(pv);
- flags |= XPIPEI;
- t = t->right;
- }
- restfd(1, e->savefd[1]); /* stdout of last */
- e->savefd[1] = 0; /* no need to re-restore this */
- /* Let exchild() close 0 in parent, after fork, before wait */
- i = exchild(t, flags|XPCLOSE, 0);
- if (!(flags&XBGND) && !(flags&XXCOM))
- rv = i;
- break;
-
- case TLIST:
- while (t->type == TLIST) {
- execute(t->left, flags & XERROK);
- t = t->right;
- }
- rv = execute(t, flags & XERROK);
- break;
-
-#ifdef KSH
- case TCOPROC:
- {
-# ifdef JOB_SIGS
- sigset_t omask;
-# endif /* JOB_SIGS */
-
-# ifdef JOB_SIGS
- /* Block sigchild as we are using things changed in the
- * signal handler
- */
- sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
- e->type = E_ERRH;
- i = ksh_sigsetjmp(e->jbuf, 0);
- if (i) {
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
- quitenv();
- unwind(i);
- /*NOTREACHED*/
- }
-# endif /* JOB_SIGS */
- /* Already have a (live) co-process? */
- if (coproc.job && coproc.write >= 0)
- errorf("coprocess already exists");
-
- /* Can we re-use the existing co-process pipe? */
- coproc_cleanup(TRUE);
-
- /* do this before opening pipes, in case these fail */
- e->savefd[0] = savefd(0, 0);
- e->savefd[1] = savefd(1, 0);
-
- openpipe(pv);
- ksh_dup2(pv[0], 0, FALSE);
- close(pv[0]);
- coproc.write = pv[1];
- coproc.job = (void *) 0;
-
- if (coproc.readw >= 0)
- ksh_dup2(coproc.readw, 1, FALSE);
- else {
- openpipe(pv);
- coproc.read = pv[0];
- ksh_dup2(pv[1], 1, FALSE);
- coproc.readw = pv[1]; /* closed before first read */
- coproc.njobs = 0;
- /* create new coprocess id */
- ++coproc.id;
- }
-# ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
- e->type = E_EXEC; /* no more need for error handler */
-# endif /* JOB_SIGS */
-
- /* exchild() closes coproc.* in child after fork,
- * will also increment coproc.njobs when the
- * job is actually created.
- */
- flags &= ~XEXEC;
- exchild(t->left, flags|XBGND|XFORK|XCOPROC|XCCLOSE,
- coproc.readw);
- break;
- }
-#endif /* KSH */
-
- case TASYNC:
- /* XXX non-optimal, I think - "(foo &)", forks for (),
- * forks again for async... parent should optimize
- * this to "foo &"...
- */
- rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK);
- break;
-
- case TOR:
- case TAND:
- rv = execute(t->left, XERROK);
- if (t->right != NULL && (rv == 0) == (t->type == TAND))
- rv = execute(t->right, flags & XERROK);
- else
- flags |= XERROK;
- break;
-
- case TBANG:
- rv = !execute(t->right, XERROK);
- break;
-
-#ifdef KSH
- case TDBRACKET:
- {
- Test_env te;
-
- te.flags = TEF_DBRACKET;
- te.pos.wp = t->args;
- te.isa = dbteste_isa;
- te.getopnd = dbteste_getopnd;
- te.eval = dbteste_eval;
- te.error = dbteste_error;
-
- rv = test_parse(&te);
- break;
- }
-#endif /* KSH */
-
- case TFOR:
-#ifdef KSH
- case TSELECT:
- {
- volatile bool_t is_first = TRUE;
-#endif /* KSH */
- ap = (t->vars != NULL) ?
- eval(t->vars, DOBLANK|DOGLOB|DOTILDE)
- : e->loc->argv + 1;
- e->type = E_LOOP;
- while (1) {
- i = ksh_sigsetjmp(e->jbuf, 0);
- if (!i)
- break;
- if ((e->flags&EF_BRKCONT_PASS)
- || (i != LBREAK && i != LCONTIN))
- {
- quitenv();
- unwind(i);
- } else if (i == LBREAK) {
- rv = 0;
- goto Break;
- }
- }
- rv = 0; /* in case of a continue */
- if (t->type == TFOR) {
- struct tbl *vq;
-
- while (*ap != NULL) {
- vq = global(t->str);
- if (vq->flag & RDONLY)
- errorf("%s is read only", t->str);
- setstr(vq, *ap++);
- rv = execute(t->left, flags & XERROK);
- }
- }
-#ifdef KSH
- else { /* TSELECT */
- struct tbl *vq;
-
- for (;;) {
- if (!(cp = do_selectargs(ap, is_first))) {
- rv = 1;
- break;
- }
- is_first = FALSE;
- vq = global(t->str);
- if (vq->flag & RDONLY)
- errorf("%s is read only", t->str);
- setstr(vq, cp);
- rv = execute(t->left, flags & XERROK);
- }
- }
- }
-#endif /* KSH */
- break;
-
- case TWHILE:
- case TUNTIL:
- e->type = E_LOOP;
- while (1) {
- i = ksh_sigsetjmp(e->jbuf, 0);
- if (!i)
- break;
- if ((e->flags&EF_BRKCONT_PASS)
- || (i != LBREAK && i != LCONTIN))
- {
- quitenv();
- unwind(i);
- } else if (i == LBREAK) {
- rv = 0;
- goto Break;
- }
- }
- rv = 0; /* in case of a continue */
- while ((execute(t->left, XERROK) == 0) == (t->type == TWHILE))
- rv = execute(t->right, flags & XERROK);
- break;
-
- case TIF:
- case TELIF:
- if (t->right == NULL)
- break; /* should be error */
- rv = execute(t->left, XERROK) == 0 ?
- execute(t->right->left, flags & XERROK) :
- execute(t->right->right, flags & XERROK);
- break;
-
- case TCASE:
- cp = evalstr(t->str, DOTILDE);
- for (t = t->left; t != NULL && t->type == TPAT; t = t->right)
- for (ap = t->vars; *ap; ap++)
- if ((s = evalstr(*ap, DOTILDE|DOPAT))
- && gmatch(cp, s, FALSE))
- goto Found;
- break;
- Found:
- rv = execute(t->left, flags & XERROK);
- break;
-
- case TBRACE:
- rv = execute(t->left, flags & XERROK);
- break;
-
- case TFUNCT:
- rv = define(t->str, t);
- break;
-
- case TTIME:
- rv = timex(t, flags);
- break;
-
- case TEXEC: /* an eval'd TCOM */
- s = t->args[0];
- ap = makenv();
-#ifndef F_SETFD
- for (i = 0; i < sizeof(clexec_tab); i++)
- if (clexec_tab[i]) {
- close(i);
- clexec_tab[i] = 0;
- }
-#endif
- restoresigs();
- cleanup_proc_env();
- ksh_execve(t->str, t->args, ap);
- if (errno == ENOEXEC)
- scriptexec(t, ap);
- else
- errorf("%s: %s", s, strerror(errno));
- }
- Break:
- exstat = rv;
-
- quitenv(); /* restores IO */
- if ((flags&XEXEC))
- exit(rv); /* exit child */
- if (rv != 0 && !(flags & XERROK)) {
- if (Flag(FERREXIT))
- unwind(LERROR);
- trapsig(SIGERR_);
- }
- return rv;
-}
-
-/*
- * execute simple command
- */
-
-static int
-comexec(t, tp, ap, flags)
- struct op *t;
- struct tbl *volatile tp;
- register char **ap;
- int volatile flags;
-{
- int i;
- int rv = 0;
- register char *cp;
- register char **lastp;
- static struct op texec; /* Must be static (XXX but why?) */
- int type_flags;
- int keepasn_ok;
- int fcflags = FC_BI|FC_FUNC|FC_PATH;
-
-#ifdef __GNUC__
- (void)&rv;
-#endif
-
- /* snag the last argument for $_ XXX not the same as at&t ksh,
- * which only seems to set $_ after a newline (but not in
- * functions/dot scripts, but in interactive and scipt) -
- * perhaps save last arg here and set it in shell()?.
- */
- if (!Flag(FSH) && *(lastp = ap)) {
- while (*++lastp)
- ;
- setstr(typeset("_", LOCAL, 0, 0, 0), *--lastp);
- }
-
- /* Deal with the shell builtins builtin, exec and command since
- * they can be followed by other commands. This must be done before
- * we know if we should create a local block, which must be done
- * before we can do a path search (in case the assignments change
- * PATH).
- * Odd cases:
- * FOO=bar exec > /dev/null FOO is kept but not exported
- * FOO=bar exec foobar FOO is exported
- * FOO=bar command exec > /dev/null FOO is neither kept nor exported
- * FOO=bar command FOO is neither kept nor exported
- * PATH=... foobar use new PATH in foobar search
- */
- keepasn_ok = 1;
- while (tp && tp->type == CSHELL) {
- fcflags = FC_BI|FC_FUNC|FC_PATH;/* undo effects of command */
- if (tp->val.f == c_builtin) {
- if ((cp = *++ap) == NULL) {
- tp = NULL;
- break;
- }
- tp = findcom(cp, FC_BI);
- if (tp == NULL)
- errorf("builtin: %s: not a builtin", cp);
- continue;
- } else if (tp->val.f == c_exec) {
- if (ap[1] == NULL)
- break;
- ap++;
- flags |= XEXEC;
- } else if (tp->val.f == c_command) {
- int optc, saw_p = 0;
-
- /* Ugly dealing with options in two places (here and
- * in c_command(), but such is life)
- */
- ksh_getopt_reset(&builtin_opt, 0);
- while ((optc = ksh_getopt(ap, &builtin_opt, ":p"))
- == 'p')
- saw_p = 1;
- if (optc != EOF)
- break; /* command -vV or something */
- /* don't look for functions */
- fcflags = FC_BI|FC_PATH;
- if (saw_p) {
- if (Flag(FRESTRICTED)) {
- warningf(TRUE,
- "command -p: restricted");
- rv = 1;
- goto Leave;
- }
- fcflags |= FC_DEFPATH;
- }
- ap += builtin_opt.optind;
- /* POSIX says special builtins lose their status
- * if accessed using command.
- */
- keepasn_ok = 0;
- if (!ap[0]) {
- /* ensure command with no args exits with 0 */
- subst_exstat = 0;
- break;
- }
- } else
- break;
- tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
- }
- if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN))))
- type_flags = 0;
- else {
- /* create new variable/function block */
- newblock();
- /* ksh functions don't keep assignments, POSIX functions do. */
- if (keepasn_ok && tp && tp->type == CFUNC
- && !(tp->flag & FKSH))
- type_flags = 0;
- else
- type_flags = LOCAL|LOCAL_COPY|EXPORT;
- }
- if (Flag(FEXPORT))
- type_flags |= EXPORT;
- for (i = 0; t->vars[i]; i++) {
- cp = evalstr(t->vars[i], DOASNTILDE);
- if (Flag(FXTRACE)) {
- if (i == 0)
- shf_fprintf(shl_out, "%s",
- PS4_SUBSTITUTE(str_val(global("PS4"))));
- shf_fprintf(shl_out, "%s%s", cp,
- t->vars[i + 1] ? space : newline);
- if (!t->vars[i + 1])
- shf_flush(shl_out);
- }
- typeset(cp, type_flags, 0, 0, 0);
- }
-
- if ((cp = *ap) == NULL) {
- rv = subst_exstat;
- goto Leave;
- } else if (!tp) {
- if (Flag(FRESTRICTED) && ksh_strchr_dirsep(cp)) {
- warningf(TRUE, "%s: restricted", cp);
- rv = 1;
- goto Leave;
- }
- tp = findcom(cp, fcflags);
- }
-
- switch (tp->type) {
- case CSHELL: /* shell built-in */
- rv = call_builtin(tp, ap);
- break;
-
- case CFUNC: /* function call */
- {
- volatile int old_xflag;
- volatile Tflag old_inuse;
- const char *volatile old_kshname;
-
- if (!(tp->flag & ISSET)) {
- struct tbl *ftp;
-
- if (!tp->u.fpath) {
- if (tp->u2.errno_) {
- warningf(TRUE,
- "%s: can't find function definition file - %s",
- cp, strerror(tp->u2.errno_));
- rv = 126;
- } else {
- warningf(TRUE,
- "%s: can't find function definition file", cp);
- rv = 127;
- }
- break;
- }
- if (include(tp->u.fpath, 0, (char **) 0, 0) < 0) {
- warningf(TRUE,
- "%s: can't open function definition file %s - %s",
- cp, tp->u.fpath, strerror(errno));
- rv = 127;
- break;
- }
- if (!(ftp = findfunc(cp, hash(cp), FALSE))
- || !(ftp->flag & ISSET))
- {
- warningf(TRUE,
- "%s: function not defined by %s",
- cp, tp->u.fpath);
- rv = 127;
- break;
- }
- tp = ftp;
- }
-
- /* ksh functions set $0 to function name, POSIX functions leave
- * $0 unchanged.
- */
- old_kshname = kshname;
- if (tp->flag & FKSH)
- kshname = ap[0];
- e->loc->argv = ap;
- for (i = 0; *ap++ != NULL; i++)
- ;
- e->loc->argc = i - 1;
- getopts_reset(1);
-
- old_xflag = Flag(FXTRACE);
- Flag(FXTRACE) = tp->flag & TRACE ? TRUE : FALSE;
-
- old_inuse = tp->flag & FINUSE;
- tp->flag |= FINUSE;
-
- e->type = E_FUNC;
- i = ksh_sigsetjmp(e->jbuf, 0);
- if (i == 0) {
- /* seems odd to pass XERROK here, but at&t ksh does */
- exstat = execute(tp->val.t, flags & XERROK);
- i = LRETURN;
- }
- kshname = old_kshname;
- Flag(FXTRACE) = old_xflag;
- tp->flag = (tp->flag & ~FINUSE) | old_inuse;
- /* Were we deleted while executing? If so, free the execution
- * tree. todo: Unfortunately, the table entry is never re-used
- * until the lookup table is expanded.
- */
- if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {
- if (tp->flag & ALLOC) {
- tp->flag &= ~ALLOC;
- tfree(tp->val.t, tp->areap);
- }
- tp->flag = 0;
- }
- switch (i) {
- case LRETURN:
- case LERROR:
- rv = exstat;
- break;
- case LINTR:
- case LEXIT:
- case LLEAVE:
- case LSHELL:
- quitenv();
- unwind(i);
- /*NOTREACHED*/
- default:
- quitenv();
- internal_errorf(1, "CFUNC %d", i);
- }
- break;
- }
-
- case CEXEC: /* executable command */
- case CTALIAS: /* tracked alias */
- if (!(tp->flag&ISSET)) {
- /* errno_ will be set if the named command was found
- * but could not be executed (permissions, no execute
- * bit, directory, etc). Print out a (hopefully)
- * useful error message and set the exit status to 126.
- */
- if (tp->u2.errno_) {
- warningf(TRUE, "%s: cannot execute - %s", cp,
- strerror(tp->u2.errno_));
- rv = 126; /* POSIX */
- } else {
- warningf(TRUE, "%s: not found", cp);
- rv = 127;
- }
- break;
- }
-
- if (!Flag(FSH)) {
- /* set $_ to program's full path */
- setstr(typeset("_", LOCAL|EXPORT, 0, 0, 0), tp->val.s);
- }
-
- if (flags&XEXEC) {
- j_exit();
- if (!(flags&XBGND) || Flag(FMONITOR)) {
- setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG);
- setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG);
- }
- }
-
- /* to fork we set up a TEXEC node and call execute */
- texec.type = TEXEC;
- texec.left = t; /* for tprint */
- texec.str = tp->val.s;
- texec.args = ap;
- rv = exchild(&texec, flags, -1);
- break;
- }
- Leave:
- if (flags & XEXEC) {
- exstat = rv;
- unwind(LLEAVE);
- }
- return rv;
-}
-
-static void
-scriptexec(tp, ap)
- register struct op *tp;
- register char **ap;
-{
- char *shell;
-
- shell = str_val(global(EXECSHELL_STR));
- if (shell && *shell)
- shell = search(shell, path, X_OK, (int *) 0);
- if (!shell || !*shell)
- shell = EXECSHELL;
-
- *tp->args-- = tp->str;
-#ifdef SHARPBANG
- {
- char buf[LINE];
- register char *cp;
- register int fd, n;
-
- buf[0] = '\0';
- if ((fd = open(tp->str, O_RDONLY)) >= 0) {
- if ((n = read(fd, buf, LINE - 1)) > 0)
- buf[n] = '\0';
- (void) close(fd);
- }
- if ((buf[0] == '#' && buf[1] == '!' && (cp = &buf[2]))
-# ifdef OS2
- || (strncmp(buf, "extproc", 7) == 0 && isspace(buf[7])
- && (cp = &buf[7]))
-# endif /* OS2 */
- )
- {
- while (*cp && (*cp == ' ' || *cp == '\t'))
- cp++;
- if (*cp && *cp != '\n') {
- char *a0 = cp, *a1 = (char *) 0;
-# ifdef OS2
- char *a2 = cp;
-# endif /* OS2 */
-
- while (*cp && *cp != '\n' && *cp != ' '
- && *cp != '\t')
- {
-# ifdef OS2
- /* Allow shell search without prepended path
- * if shell with / in pathname cannot be found.
- * Use / explicitly so \ can be used if explicit
- * needs to be forced.
- */
- if (*cp == '/')
- a2 = cp + 1;
-# endif /* OS2 */
- cp++;
- }
- if (*cp && *cp != '\n') {
- *cp++ = '\0';
- while (*cp
- && (*cp == ' ' || *cp == '\t'))
- cp++;
- if (*cp && *cp != '\n') {
- a1 = cp;
- /* all one argument */
- while (*cp && *cp != '\n')
- cp++;
- }
- }
- if (*cp == '\n') {
- *cp = '\0';
- if (a1)
- *tp->args-- = a1;
-# ifdef OS2
- if (a0 != a2 && search_access(a0, X_OK, (int *) 0))
- a0 = a2;
-# endif /* OS2 */
- shell = a0;
- }
- }
-# ifdef OS2
- } else {
- /* Use ksh documented shell default if present
- * else use OS2_SHELL which is assumed to need
- * the /c option and '\' as dir separater.
- */
- char *p = shell;
-
- shell = str_val(global("EXECSHELL"));
- if (shell && *shell)
- shell = search(shell, path, X_OK, (int *) 0);
- if (!shell || !*shell) {
- shell = p;
- *tp->args-- = "/c";
- for (p = tp->str; *p; p++)
- if (*p == '/')
- *p = '\\';
- }
-# endif /* OS2 */
- }
- }
-#endif /* SHARPBANG */
- *tp->args = shell;
-
- ksh_execve(tp->args[0], tp->args, ap);
-
- /* report both the program that was run and the bogus shell */
- errorf("%s: %s: %s", tp->str, shell, strerror(errno));
-}
-
-int
-shcomexec(wp)
- register char **wp;
-{
- register struct tbl *tp;
-
- tp = tsearch(&builtins, *wp, hash(*wp));
- if (tp == NULL)
- internal_errorf(1, "shcomexec: %s", *wp);
- return call_builtin(tp, wp);
-}
-
-/*
- * Search function tables for a function. If create set, a table entry
- * is created if none is found.
- */
-struct tbl *
-findfunc(name, h, create)
- const char *name;
- unsigned int h;
- int create;
-{
- struct block *l;
- struct tbl *tp = (struct tbl *) 0;
-
- for (l = e->loc; l; l = l->next) {
- tp = tsearch(&l->funs, name, h);
- if (tp)
- break;
- if (!l->next && create) {
- tp = tenter(&l->funs, name, h);
- tp->flag = DEFINED;
- tp->type = CFUNC;
- tp->val.t = (struct op *) 0;
- break;
- }
- }
- return tp;
-}
-
-/*
- * define function. Returns 1 if function is being undefined (t == 0) and
- * function did not exist, returns 0 otherwise.
- */
-int
-define(name, t)
- const char *name;
- struct op *t;
-{
- struct tbl *tp;
- int was_set = 0;
-
- while (1) {
- tp = findfunc(name, hash(name), TRUE);
-
- if (tp->flag & ISSET)
- was_set = 1;
- /* If this function is currently being executed, we zap this
- * table entry so findfunc() won't see it
- */
- if (tp->flag & FINUSE) {
- tp->name[0] = '\0';
- tp->flag &= ~DEFINED; /* ensure it won't be found */
- tp->flag |= FDELETE;
- } else
- break;
- }
-
- if (tp->flag & ALLOC) {
- tp->flag &= ~(ISSET|ALLOC);
- tfree(tp->val.t, tp->areap);
- }
-
- if (t == NULL) { /* undefine */
- tdelete(tp);
- return was_set ? 0 : 1;
- }
-
- tp->val.t = tcopy(t->left, tp->areap);
- tp->flag |= (ISSET|ALLOC);
- if (t->u.ksh_func)
- tp->flag |= FKSH;
-
- return 0;
-}
-
-/*
- * add builtin
- */
-void
-builtin(name, func)
- const char *name;
- int (*func) ARGS((char **));
-{
- register struct tbl *tp;
- Tflag flag;
-
- /* see if any flags should be set for this builtin */
- for (flag = 0; ; name++) {
- if (*name == '=') /* command does variable assignment */
- flag |= KEEPASN;
- else if (*name == '*') /* POSIX special builtin */
- flag |= SPEC_BI;
- else if (*name == '+') /* POSIX regular builtin */
- flag |= REG_BI;
- else
- break;
- }
-
- tp = tenter(&builtins, name, hash(name));
- tp->flag = DEFINED | flag;
- tp->type = CSHELL;
- tp->val.f = func;
-}
-
-/*
- * find command
- * either function, hashed command, or built-in (in that order)
- */
-struct tbl *
-findcom(name, flags)
- const char *name;
- int flags; /* FC_* */
-{
- static struct tbl temp;
- unsigned int h = hash(name);
- struct tbl *tp = NULL, *tbi;
- int insert = Flag(FTRACKALL); /* insert if not found */
- char *fpath; /* for function autoloading */
- char *npath;
-
- if (ksh_strchr_dirsep(name) != NULL) {
- insert = 0;
- /* prevent FPATH search below */
- flags &= ~FC_FUNC;
- goto Search;
- }
- tbi = (flags & FC_BI) ? tsearch(&builtins, name, h) : NULL;
- /* POSIX says special builtins first, then functions, then
- * POSIX regular builtins, then search path...
- */
- if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
- tp = tbi;
- if (!tp && (flags & FC_FUNC)) {
- tp = findfunc(name, h, FALSE);
- if (tp && !(tp->flag & ISSET)) {
- if ((fpath = str_val(global("FPATH"))) == null) {
- tp->u.fpath = (char *) 0;
- tp->u2.errno_ = 0;
- } else
- tp->u.fpath = search(name, fpath, R_OK,
- &tp->u2.errno_);
- }
- }
- if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
- tp = tbi;
- /* todo: posix says non-special/non-regular builtins must
- * be triggered by some user-controllable means like a
- * special directory in PATH. Requires modifications to
- * the search() function. Tracked aliases should be
- * modified to allow tracking of builtin commands.
- * This should be under control of the FPOSIX flag.
- * If this is changed, also change c_whence...
- */
- if (!tp && (flags & FC_UNREGBI) && tbi)
- tp = tbi;
- if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
- tp = tsearch(&taliases, name, h);
- if (tp && (tp->flag & ISSET) && eaccess(tp->val.s, X_OK) != 0) {
- if (tp->flag & ALLOC) {
- tp->flag &= ~ALLOC;
- afree(tp->val.s, APERM);
- }
- tp->flag &= ~ISSET;
- }
- }
-
- Search:
- if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET)))
- && (flags & FC_PATH))
- {
- if (!tp) {
- if (insert && !(flags & FC_DEFPATH)) {
- tp = tenter(&taliases, name, h);
- tp->type = CTALIAS;
- } else {
- tp = &temp;
- tp->type = CEXEC;
- }
- tp->flag = DEFINED; /* make ~ISSET */
- }
- npath = search(name, flags & FC_DEFPATH ? def_path : path,
- X_OK, &tp->u2.errno_);
- if (npath) {
- tp->val.s = tp == &temp ? npath : str_save(npath, APERM);
- tp->flag |= ISSET|ALLOC;
- } else if ((flags & FC_FUNC)
- && (fpath = str_val(global("FPATH"))) != null
- && (npath = search(name, fpath, R_OK,
- &tp->u2.errno_)) != (char *) 0)
- {
- /* An undocumented feature of at&t ksh is that it
- * searches FPATH if a command is not found, even
- * if the command hasn't been set up as an autoloaded
- * function (ie, no typeset -uf).
- */
- tp = &temp;
- tp->type = CFUNC;
- tp->flag = DEFINED; /* make ~ISSET */
- tp->u.fpath = npath;
- }
- }
- return tp;
-}
-
-/*
- * flush executable commands with relative paths
- */
-void
-flushcom(all)
- int all; /* just relative or all */
-{
- struct tbl *tp;
- struct tstate ts;
-
- for (twalk(&ts, &taliases); (tp = tnext(&ts)) != NULL; )
- if ((tp->flag&ISSET) && (all || !ISDIRSEP(tp->val.s[0]))) {
- if (tp->flag&ALLOC) {
- tp->flag &= ~(ALLOC|ISSET);
- afree(tp->val.s, APERM);
- }
- tp->flag = ~ISSET;
- }
-}
-
-/* Check if path is something we want to find. Returns -1 for failure. */
-int
-search_access(path, mode, errnop)
- const char *path;
- int mode;
- int *errnop; /* set if candidate found, but not suitable */
-{
-#ifndef OS2
- int ret, err = 0;
- struct stat statb;
-
- if (stat(path, &statb) < 0)
- return -1;
- ret = eaccess(path, mode);
- if (ret < 0)
- err = errno; /* File exists, but we can't access it */
- else if (mode == X_OK && (!S_ISREG(statb.st_mode)
- /* This 'cause access() says root can execute everything */
- || !(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
- {
- ret = -1;
- err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
- }
- if (err && errnop)
- *errnop = err;
- return ret;
-#else /* !OS2 */
- /*
- * NOTE: ASSUMES path can be modified and has enough room at the
- * end of the string for a suffix (ie, 4 extra characters).
- * Certain code knows this (eg, eval.c(globit()),
- * exec.c(search())).
- */
- static char *xsuffixes[] = { ".ksh", ".exe", ".", ".sh", ".cmd",
- ".com", ".bat", (char *) 0
- };
- static char *rsuffixes[] = { ".ksh", ".", ".sh", ".cmd", ".bat",
- (char *) 0
- };
- int i;
- char *mpath = (char *) path;
- char *tp = mpath + strlen(mpath);
- char *p;
- char **sfx;
-
- /* If a suffix has been specified, check if it is one of the
- * suffixes that indicate the file is executable - if so, change
- * the access test to R_OK...
- * This code assumes OS/2 files can have only one suffix...
- */
- if ((p = strrchr((p = ksh_strrchr_dirsep(mpath)) ? p : mpath, '.'))) {
- if (mode == X_OK)
- mode = R_OK;
- return search_access1(mpath, mode, errnop);
- }
- /* Try appending the various suffixes. Different suffixes for
- * read and execute 'cause we don't want to read an executable...
- */
- sfx = mode == R_OK ? rsuffixes : xsuffixes;
- for (i = 0; sfx[i]; i++) {
- strcpy(tp, p = sfx[i]);
- if (search_access1(mpath, R_OK, errnop) == 0)
- return 0;
- *tp = '\0';
- }
- return -1;
-#endif /* !OS2 */
-}
-
-#ifdef OS2
-static int
-search_access1(path, mode, errnop)
- const char *path;
- int mode;
- int *errnop; /* set if candidate found, but not suitable */
-{
- int ret, err = 0;
- struct stat statb;
-
- if (stat(path, &statb) < 0)
- return -1;
- ret = eaccess(path, mode);
- if (ret < 0)
- err = errno; /* File exists, but we can't access it */
- else if (!S_ISREG(statb.st_mode)) {
- ret = -1;
- err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
- }
- if (err && errnop)
- *errnop = err;
- return ret;
-}
-#endif /* OS2 */
-
-/*
- * search for command with PATH
- */
-char *
-search(name, path, mode, errnop)
- const char *name;
- const char *path;
- int mode; /* R_OK or X_OK */
- int *errnop; /* set if candidate found, but not suitable */
-{
- const char *sp, *p;
- char *xp;
- XString xs;
- int namelen;
-
- if (errnop)
- *errnop = 0;
-#ifdef OS2
- /* Xinit() allocates 8 additional bytes, so appended suffixes won't
- * overflow the memory.
- */
- namelen = strlen(name) + 1;
- Xinit(xs, xp, namelen, ATEMP);
- memcpy(Xstring(xs, xp), name, namelen);
-
- if (ksh_strchr_dirsep(name)) {
- if (search_access(Xstring(xs, xp), mode, errnop) >= 0)
- return Xstring(xs, xp); /* not Xclose() - see above */
- Xfree(xs, xp);
- return NULL;
- }
-
- /* Look in current context always. (os2 style) */
- if (search_access(Xstring(xs, xp), mode, errnop) == 0)
- return Xstring(xs, xp); /* not Xclose() - xp may be wrong */
-#else /* OS2 */
- if (ksh_strchr_dirsep(name)) {
- if (search_access(name, mode, errnop) == 0)
- return (char *) name;
- return NULL;
- }
-
- namelen = strlen(name) + 1;
- Xinit(xs, xp, 128, ATEMP);
-#endif /* OS2 */
-
- sp = path;
- while (sp != NULL) {
- xp = Xstring(xs, xp);
- if (!(p = strchr(sp, PATHSEP)))
- p = sp + strlen(sp);
- if (p != sp) {
- XcheckN(xs, xp, p - sp);
- memcpy(xp, sp, p - sp);
- xp += p - sp;
- *xp++ = DIRSEP;
- }
- sp = p;
- XcheckN(xs, xp, namelen);
- memcpy(xp, name, namelen);
- if (search_access(Xstring(xs, xp), mode, errnop) == 0)
-#ifdef OS2
- return Xstring(xs, xp); /* Not Xclose() - see above */
-#else /* OS2 */
- return Xclose(xs, xp + namelen);
-#endif /* OS2 */
- if (*sp++ == '\0')
- sp = NULL;
- }
- Xfree(xs, xp);
- return NULL;
-}
-
-static int
-call_builtin(tp, wp)
- struct tbl *tp;
- char **wp;
-{
- int rv;
-
- builtin_argv0 = wp[0];
- builtin_flag = tp->flag;
- shf_reopen(1, SHF_WR, shl_stdout);
- shl_stdout_ok = 1;
- ksh_getopt_reset(&builtin_opt, GF_ERROR);
- rv = (*tp->val.f)(wp);
- shf_flush(shl_stdout);
- shl_stdout_ok = 0;
- builtin_flag = 0;
- builtin_argv0 = (char *) 0;
- return rv;
-}
-
-/*
- * set up redirection, saving old fd's in e->savefd
- */
-static int
-iosetup(iop, tp)
- register struct ioword *iop;
- struct tbl *tp;
-{
- register int u = -1;
- char *cp = iop->name;
- int iotype = iop->flag & IOTYPE;
- int do_open = 1, do_close = 0, UNINITIALIZED(flags);
- struct ioword iotmp;
- struct stat statb;
-
- if (iotype != IOHERE)
- cp = evalonestr(cp, DOTILDE|(Flag(FTALKING) ? DOGLOB : 0));
-
- /* Used for tracing and error messages to print expanded cp */
- iotmp = *iop;
- iotmp.name = (iotype == IOHERE) ? (char *) 0 : cp;
- iotmp.flag |= IONAMEXP;
-
- if (Flag(FXTRACE))
- shellf("%s%s\n",
- PS4_SUBSTITUTE(str_val(global("PS4"))),
- snptreef((char *) 0, 32, "%R", &iotmp));
-
- switch (iotype) {
- case IOREAD:
- flags = O_RDONLY;
- break;
-
- case IOCAT:
- flags = O_WRONLY | O_APPEND | O_CREAT;
- break;
-
- case IOWRITE:
- flags = O_WRONLY | O_CREAT | O_TRUNC;
- if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB)
- && (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode)))
- flags |= O_EXCL;
- break;
-
- case IORDWR:
- flags = O_RDWR | O_CREAT;
- break;
-
- case IOHERE:
- do_open = 0;
- /* herein() returns -2 if error has been printed */
- u = herein(cp, iop->flag & IOEVAL);
- /* cp may have wrong name */
- break;
-
- case IODUP:
- {
- const char *emsg;
-
- do_open = 0;
- if (*cp == '-' && !cp[1]) {
- u = 1009; /* prevent error return below */
- do_close = 1;
- } else if ((u = check_fd(cp,
- X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
- &emsg)) < 0)
- {
- warningf(TRUE, "%s: %s",
- snptreef((char *) 0, 32, "%R", &iotmp), emsg);
- return -1;
- }
- break;
- }
- }
- if (do_open) {
- if (Flag(FRESTRICTED) && (flags & O_CREAT)) {
- warningf(TRUE, "%s: restricted", cp);
- return -1;
- }
- u = open(cp, flags, 0666);
-#ifdef OS2
- if (u < 0 && strcmp(cp, "/dev/null") == 0)
- u = open("nul", flags, 0666);
-#endif /* OS2 */
- }
- if (u < 0) {
- /* herein() may already have printed message */
- if (u == -1)
- warningf(TRUE, "cannot %s %s: %s",
- iotype == IODUP ? "dup"
- : (iotype == IOREAD || iotype == IOHERE) ?
- "open" : "create", cp, strerror(errno));
- return -1;
- }
- /* Do not save if it has already been redirected (i.e. "cat >x >y"). */
- if (e->savefd[iop->unit] == 0)
- /* c_exec() assumes e->savefd[fd] set for any redirections.
- * Ask savefd() not to close iop->unit - allows error messages
- * to be seen if iop->unit is 2; also means we can't lose
- * the fd (eg, both dup2 below and dup2 in restfd() failing).
- */
- e->savefd[iop->unit] = savefd(iop->unit, 1);
-
- if (do_close)
- close(iop->unit);
- else if (u != iop->unit) {
- if (ksh_dup2(u, iop->unit, TRUE) < 0) {
- warningf(TRUE,
- "could not finish (dup) redirection %s: %s",
- snptreef((char *) 0, 32, "%R", &iotmp),
- strerror(errno));
- if (iotype != IODUP)
- close(u);
- return -1;
- }
- if (iotype != IODUP)
- close(u);
-#ifdef KSH
- /* Touching any co-process fd in an empty exec
- * causes the shell to close its copies
- */
- else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
- if (iop->flag & IORDUP) /* possible exec <&p */
- coproc_read_close(u);
- else /* possible exec >&p */
- coproc_write_close(u);
- }
-#endif /* KSH */
- }
- if (u == 2) /* Clear any write errors */
- shf_reopen(2, SHF_WR, shl_out);
- return 0;
-}
-
-/*
- * open here document temp file.
- * if unquoted here, expand here temp file into second temp file.
- */
-static int
-herein(hname, sub)
- char *hname;
- int sub;
-{
- int fd;
-
- /* ksh -c 'cat << EOF' can cause this... */
- if (hname == (char *) 0) {
- warningf(TRUE, "here document missing");
- return -2; /* special to iosetup(): don't print error */
- }
- if (sub) {
- char *cp;
- struct source *s, *volatile osource = source;
- struct temp *h;
- struct shf *volatile shf;
- int i;
-
- /* must be before newenv() 'cause shf uses ATEMP */
- shf = shf_open(hname, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
- if (shf == NULL)
- return -1;
- newenv(E_ERRH);
- i = ksh_sigsetjmp(e->jbuf, 0);
- if (i) {
- if (shf)
- shf_close(shf);
- source = osource;
- quitenv(); /* after shf_close() due to alloc */
- return -2; /* special to iosetup(): don't print error */
- }
- /* set up yylex input from here file */
- s = pushs(SFILE, ATEMP);
- s->u.shf = shf;
- source = s;
- if (yylex(ONEWORD) != LWORD)
- internal_errorf(1, "herein: yylex");
- shf_close(shf);
- shf = (struct shf *) 0;
- cp = evalstr(yylval.cp, 0);
-
- /* write expanded input to another temp file */
- h = maketemp(ATEMP);
- h->next = e->temps; e->temps = h;
- if (!(shf = h->shf) || (fd = open(h->name, O_RDONLY, 0)) < 0)
- /* shf closeed by error handler */
- errorf("%s: %s", h->name, strerror(errno));
- shf_puts(cp, shf);
- if (shf_close(shf) == EOF) {
- close(fd);
- shf = (struct shf *) 0;
- errorf("error writing %s: %s", h->name,
- strerror(errno));
- }
- shf = (struct shf *) 0;
-
- quitenv();
- } else {
- fd = open(hname, O_RDONLY, 0);
- if (fd < 0)
- return -1;
- }
-
- return fd;
-}
-
-#if defined(KSH) || defined(EDIT)
-/*
- * ksh special - the select command processing section
- * print the args in column form - assuming that we can
- */
-static char *
-do_selectargs(ap, print_menu)
- register char **ap;
- bool_t print_menu;
-{
- static const char *const read_args[] = {
- "read", "-r", "REPLY", (char *) 0
- };
- char *s;
- int i, argct;
-
- for (argct = 0; ap[argct]; argct++)
- ;
- while (1) {
- /* Menu is printed if
- * - this is the first time around the select loop
- * - the user enters a blank line
- * - the REPLY parameter is empty
- */
- if (print_menu || !*str_val(global("REPLY")))
- pr_menu(ap);
- shellf("%s", str_val(global("PS3")));
- if (call_builtin(findcom("read", FC_BI), (char **) read_args))
- return (char *) 0;
- s = str_val(global("REPLY"));
- if (*s) {
- i = atoi(s);
- return (i >= 1 && i <= argct) ? ap[i - 1] : null;
- }
- print_menu = 1;
- }
-}
-
-struct select_menu_info {
- char *const *args;
- int arg_width;
- int num_width;
-} info;
-
-static char *select_fmt_entry ARGS((void *arg, int i, char *buf, int buflen));
-
-/* format a single select menu item */
-static char *
-select_fmt_entry(arg, i, buf, buflen)
- void *arg;
- int i;
- char *buf;
- int buflen;
-{
- struct select_menu_info *smi = (struct select_menu_info *) arg;
-
- shf_snprintf(buf, buflen, "%*d) %s",
- smi->num_width, i + 1, smi->args[i]);
- return buf;
-}
-
-/*
- * print a select style menu
- */
-int
-pr_menu(ap)
- char *const *ap;
-{
- struct select_menu_info smi;
- char *const *pp;
- int nwidth, dwidth;
- int i, n;
-
- /* Width/column calculations were done once and saved, but this
- * means select can't be used recursively so we re-calculate each
- * time (could save in a structure that is returned, but its probably
- * not worth the bother).
- */
-
- /*
- * get dimensions of the list
- */
- for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) {
- i = strlen(*pp);
- nwidth = (i > nwidth) ? i : nwidth;
- }
- /*
- * we will print an index of the form
- * %d)
- * in front of each entry
- * get the max width of this
- */
- for (i = n, dwidth = 1; i >= 10; i /= 10)
- dwidth++;
-
- smi.args = ap;
- smi.arg_width = nwidth;
- smi.num_width = dwidth;
- print_columns(shl_out, n, select_fmt_entry, (void *) &smi,
- dwidth + nwidth + 2);
-
- return n;
-}
-#endif /* KSH || EDIT */
-#ifdef KSH
-
-/*
- * [[ ... ]] evaluation routines
- */
-
-extern const char *const dbtest_tokens[];
-extern const char db_close[];
-
-/* Test if the current token is a whatever. Accepts the current token if
- * it is. Returns 0 if it is not, non-zero if it is (in the case of
- * TM_UNOP and TM_BINOP, the returned value is a Test_op).
- */
-static int
-dbteste_isa(te, meta)
- Test_env *te;
- Test_meta meta;
-{
- int ret = 0;
- int uqword;
- char *p;
-
- if (!*te->pos.wp)
- return meta == TM_END;
-
- /* unquoted word? */
- for (p = *te->pos.wp; *p == CHAR; p += 2)
- ;
- uqword = *p == EOS;
-
- if (meta == TM_UNOP || meta == TM_BINOP) {
- if (uqword) {
- char buf[8]; /* longer than the longest operator */
- char *q = buf;
- for (p = *te->pos.wp; *p == CHAR
- && q < &buf[sizeof(buf) - 1];
- p += 2)
- *q++ = p[1];
- *q = '\0';
- ret = (int) test_isop(te, meta, buf);
- }
- } else if (meta == TM_END)
- ret = 0;
- else
- ret = uqword
- && strcmp(*te->pos.wp, dbtest_tokens[(int) meta]) == 0;
-
- /* Accept the token? */
- if (ret)
- te->pos.wp++;
-
- return ret;
-}
-
-static const char *
-dbteste_getopnd(te, op, do_eval)
- Test_env *te;
- Test_op op;
- int do_eval;
-{
- char *s = *te->pos.wp;
-
- if (!s)
- return (char *) 0;
-
- te->pos.wp++;
-
- if (!do_eval)
- return null;
-
- if (op == TO_STEQL || op == TO_STNEQ)
- s = evalstr(s, DOTILDE | DOPAT);
- else
- s = evalstr(s, DOTILDE);
-
- return s;
-}
-
-static int
-dbteste_eval(te, op, opnd1, opnd2, do_eval)
- Test_env *te;
- Test_op op;
- const char *opnd1;
- const char *opnd2;
- int do_eval;
-{
- return test_eval(te, op, opnd1, opnd2, do_eval);
-}
-
-static void
-dbteste_error(te, offset, msg)
- Test_env *te;
- int offset;
- const char *msg;
-{
- te->flags |= TEF_ERROR;
- internal_errorf(0, "dbteste_error: %s (offset %d)", msg, offset);
-}
-#endif /* KSH */
diff --git a/bin/pdksh/expand.h b/bin/pdksh/expand.h
deleted file mode 100644
index d0ab5937c1d..00000000000
--- a/bin/pdksh/expand.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* $OpenBSD: expand.h,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
-
-/*
- * Expanding strings
- */
-
-
-#if 0 /* Usage */
- XString xs;
- char *xp;
-
- Xinit(xs, xp, 128, ATEMP); /* allocate initial string */
- while ((c = generate()) {
- Xcheck(xs, xp); /* expand string if neccessary */
- Xput(xs, xp, c); /* add character */
- }
- return Xclose(xs, xp); /* resize string */
-/*
- * NOTE:
- * The Xcheck and Xinit macros have a magic + 8 in the lengths. This is
- * so that you can put up to 4 characters in a XString before calling
- * Xcheck. (See yylex in lex.c)
- */
-#endif /* 0 */
-
-typedef struct XString {
- char *end, *beg; /* end, begin of string */
- size_t len; /* length */
- Area *areap; /* area to allocate/free from */
-} XString;
-
-typedef char * XStringP;
-
-/* initialize expandable string */
-#define Xinit(xs, xp, length, area) do { \
- (xs).len = length; \
- (xs).areap = (area); \
- (xs).beg = alloc((xs).len + 8, (xs).areap); \
- (xs).end = (xs).beg + (xs).len; \
- xp = (xs).beg; \
- } while (0)
-
-/* stuff char into string */
-#define Xput(xs, xp, c) (*xp++ = (c))
-
-/* check if there are at least n bytes left */
-#define XcheckN(xs, xp, n) do { \
- int more = ((xp) + (n)) - (xs).end; \
- if (more > 0) \
- xp = Xcheck_grow_(&xs, xp, more); \
- } while (0)
-
-/* check for overflow, expand string */
-#define Xcheck(xs, xp) XcheckN(xs, xp, 1)
-
-/* free string */
-#define Xfree(xs, xp) afree((void*) (xs).beg, (xs).areap)
-
-/* close, return string */
-#define Xclose(xs, xp) (char*) aresize((void*)(xs).beg, \
- (size_t)((xp) - (xs).beg), (xs).areap)
-/* begin of string */
-#define Xstring(xs, xp) ((xs).beg)
-
-#define Xnleft(xs, xp) ((xs).end - (xp)) /* may be less than 0 */
-#define Xlength(xs, xp) ((xp) - (xs).beg)
-#define Xsize(xs, xp) ((xs).end - (xs).beg)
-#define Xsavepos(xs, xp) ((xp) - (xs).beg)
-#define Xrestpos(xs, xp, n) ((xs).beg + (n))
-
-char * Xcheck_grow_ ARGS((XString *xsp, char *xp, int more));
-
-/*
- * expandable vector of generic pointers
- */
-
-typedef struct XPtrV {
- void **cur; /* next avail pointer */
- void **beg, **end; /* begin, end of vector */
-} XPtrV;
-
-#define XPinit(x, n) do { \
- register void **vp__; \
- vp__ = (void**) alloc(sizeofN(void*, n), ATEMP); \
- (x).cur = (x).beg = vp__; \
- (x).end = vp__ + n; \
- } while (0)
-
-#define XPput(x, p) do { \
- if ((x).cur >= (x).end) { \
- int n = XPsize(x); \
- (x).beg = (void**) aresize((void*) (x).beg, \
- sizeofN(void*, n*2), ATEMP); \
- (x).cur = (x).beg + n; \
- (x).end = (x).cur + n; \
- } \
- *(x).cur++ = (p); \
- } while (0)
-
-#define XPptrv(x) ((x).beg)
-#define XPsize(x) ((x).cur - (x).beg)
-
-#define XPclose(x) (void**) aresize((void*)(x).beg, \
- sizeofN(void*, XPsize(x)), ATEMP)
-
-#define XPfree(x) afree((void*) (x).beg, ATEMP)
diff --git a/bin/pdksh/expr.c b/bin/pdksh/expr.c
deleted file mode 100644
index 775d7ee44dd..00000000000
--- a/bin/pdksh/expr.c
+++ /dev/null
@@ -1,596 +0,0 @@
-/* $OpenBSD: expr.c,v 1.4 1997/06/19 13:58:41 kstailey Exp $ */
-
-/*
- * Korn expression evaluation
- */
-/*
- * todo: better error handling: if in builtin, should be builtin error, etc.
- */
-
-#include "sh.h"
-#include <ctype.h>
-
-
-/* The order of these enums is constrained by the order of opinfo[] */
-enum token {
- /* some (long) unary operators */
- O_PLUSPLUS = 0, O_MINUSMINUS,
- /* binary operators */
- O_EQ, O_NE,
- /* assignments are assumed to be in range O_ASN .. O_BORASN */
- O_ASN, O_TIMESASN, O_DIVASN, O_MODASN, O_PLUSASN, O_MINUSASN,
- O_LSHIFTASN, O_RSHIFTASN, O_BANDASN, O_BXORASN, O_BORASN,
- O_LSHIFT, O_RSHIFT,
- O_LE, O_GE, O_LT, O_GT,
- O_LAND,
- O_LOR,
- O_TIMES, O_DIV, O_MOD,
- O_PLUS, O_MINUS,
- O_BAND,
- O_BXOR,
- O_BOR,
- O_TERN,
- O_COMMA,
- /* things after this aren't used as binary operators */
- /* unary that are not also binaries */
- O_BNOT, O_LNOT,
- /* misc */
- OPEN_PAREN, CLOSE_PAREN, CTERN,
- /* things that don't appear in the opinfo[] table */
- VAR, LIT, END, BAD
- };
-#define IS_BINOP(op) (((int)op) >= O_EQ && ((int)op) <= O_COMMA)
-#define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
-
-enum prec {
- P_PRIMARY = 0, /* VAR, LIT, (), ~ ! - + */
- P_MULT, /* * / % */
- P_ADD, /* + - */
- P_SHIFT, /* << >> */
- P_RELATION, /* < <= > >= */
- P_EQUALITY, /* == != */
- P_BAND, /* & */
- P_BXOR, /* ^ */
- P_BOR, /* | */
- P_LAND, /* && */
- P_LOR, /* || */
- P_TERN, /* ?: */
- P_ASSIGN, /* = *= /= %= += -= <<= >>= &= ^= |= */
- P_COMMA /* , */
- };
-#define MAX_PREC P_COMMA
-
-struct opinfo {
- char name[4];
- int len; /* name length */
- enum prec prec; /* precidence: lower is higher */
-};
-
-/* Tokens in this table must be ordered so the longest are first
- * (eg, += before +). If you change something, change the order
- * of enum token too.
- */
-static const struct opinfo opinfo[] = {
- { "++", 2, P_PRIMARY }, /* before + */
- { "--", 2, P_PRIMARY }, /* before - */
- { "==", 2, P_EQUALITY }, /* before = */
- { "!=", 2, P_EQUALITY }, /* before ! */
- { "=", 1, P_ASSIGN }, /* keep assigns in a block */
- { "*=", 2, P_ASSIGN },
- { "/=", 2, P_ASSIGN },
- { "%=", 2, P_ASSIGN },
- { "+=", 2, P_ASSIGN },
- { "-=", 2, P_ASSIGN },
- { "<<=", 3, P_ASSIGN },
- { ">>=", 3, P_ASSIGN },
- { "&=", 2, P_ASSIGN },
- { "^=", 2, P_ASSIGN },
- { "|=", 2, P_ASSIGN },
- { "<<", 2, P_SHIFT },
- { ">>", 2, P_SHIFT },
- { "<=", 2, P_RELATION },
- { ">=", 2, P_RELATION },
- { "<", 1, P_RELATION },
- { ">", 1, P_RELATION },
- { "&&", 2, P_LAND },
- { "||", 2, P_LOR },
- { "*", 1, P_MULT },
- { "/", 1, P_MULT },
- { "%", 1, P_MULT },
- { "+", 1, P_ADD },
- { "-", 1, P_ADD },
- { "&", 1, P_BAND },
- { "^", 1, P_BXOR },
- { "|", 1, P_BOR },
- { "?", 1, P_TERN },
- { ",", 1, P_COMMA },
- { "~", 1, P_PRIMARY },
- { "!", 1, P_PRIMARY },
- { "(", 1, P_PRIMARY },
- { ")", 1, P_PRIMARY },
- { ":", 1, P_PRIMARY },
- { "", 0, P_PRIMARY } /* end of table */
- };
-
-
-typedef struct expr_state Expr_state;
-struct expr_state {
- const char *expression; /* expression being evaluated */
- const char *tokp; /* lexical position */
- enum token tok; /* token from token() */
- int noassign; /* don't do assigns (for ?:,&&,||) */
- struct tbl *val; /* value from token() */
- struct tbl *evaling; /* variable that is being recursively
- * expanded (EXPRINEVAL flag set)
- */
- Expr_state *volatile prev; /* previous state */
-};
-
-enum error_type { ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE,
- ET_LVALUE, ET_RDONLY, ET_STR };
-
-static Expr_state *es;
-
-static void evalerr ARGS((enum error_type type, const char *str))
- GCC_FUNC_ATTR(noreturn);
-static struct tbl *evalexpr ARGS((enum prec prec));
-static void token ARGS((void));
-static struct tbl *do_ppmm ARGS((enum token op, struct tbl *vasn,
- bool_t is_prefix));
-static void assign_check ARGS((enum token op, struct tbl *vasn));
-static struct tbl *tempvar ARGS((void));
-static struct tbl *intvar ARGS((struct tbl *vp));
-
-/*
- * parse and evalute expression
- */
-int
-evaluate(expr, rval, error_ok)
- const char *expr;
- long *rval;
- int error_ok;
-{
- struct tbl v;
- int ret;
-
- v.flag = DEFINED|INTEGER;
- v.type = 0;
- ret = v_evaluate(&v, expr, error_ok);
- *rval = v.val.i;
- return ret;
-}
-
-/*
- * parse and evalute expression, storing result in vp.
- */
-int
-v_evaluate(vp, expr, error_ok)
- struct tbl *vp;
- const char *expr;
- volatile int error_ok;
-{
- struct tbl *v;
- Expr_state curstate;
- int i;
-
- /* save state to allow recursive calls */
- curstate.expression = curstate.tokp = expr;
- curstate.noassign = 0;
- curstate.prev = es;
- curstate.evaling = (struct tbl *) 0;
- es = &curstate;
-
- newenv(E_ERRH);
- i = ksh_sigsetjmp(e->jbuf, 0);
- if (i) {
- /* Clear EXPRINEVAL in of any variables we were playing with */
- if (curstate.evaling)
- curstate.evaling->flag &= ~EXPRINEVAL;
- quitenv();
- es = curstate.prev;
- if (i == LAEXPR) {
- if (error_ok)
- return 0;
- errorf(null);
- }
- unwind(i);
- /*NOTREACHED*/
- }
-
- token();
-#if 1 /* ifdef-out to disallow empty expressions to be treated as 0 */
- if (es->tok == END) {
- es->tok = LIT;
- es->val = tempvar();
- }
-#endif /* 0 */
- v = intvar(evalexpr(MAX_PREC));
-
- if (es->tok != END)
- evalerr(ET_UNEXPECTED, (char *) 0);
-
- if (vp->flag & INTEGER)
- setint_v(vp, v);
- else
- setstr(vp, str_val(v));
-
- es = curstate.prev;
- quitenv();
-
- return 1;
-}
-
-static void
-evalerr(type, str)
- enum error_type type;
- const char *str;
-{
- char tbuf[2];
- const char *s;
-
- switch (type) {
- case ET_UNEXPECTED:
- switch (es->tok) {
- case VAR:
- s = es->val->name;
- break;
- case LIT:
- s = str_val(es->val);
- break;
- case END:
- s = "end of expression";
- break;
- case BAD:
- tbuf[0] = *es->tokp;
- tbuf[1] = '\0';
- s = tbuf;
- break;
- default:
- s = opinfo[(int)es->tok].name;
- }
- warningf(TRUE, "%s: unexpected `%s'", es->expression, s);
- break;
-
- case ET_BADLIT:
- warningf(TRUE, "%s: bad number `%s'", es->expression, str);
- break;
-
- case ET_RECURSIVE:
- warningf(TRUE, "%s: expression recurses on parameter `%s'",
- es->expression, str);
- break;
-
- case ET_LVALUE:
- warningf(TRUE, "%s: %s requires lvalue",
- es->expression, str);
- break;
-
- case ET_RDONLY:
- warningf(TRUE, "%s: %s applied to read only variable",
- es->expression, str);
- break;
-
- default: /* keep gcc happy */
- case ET_STR:
- warningf(TRUE, "%s: %s", es->expression, str);
- break;
- }
- unwind(LAEXPR);
-}
-
-static struct tbl *
-evalexpr(prec)
- enum prec prec;
-{
- register struct tbl *vl, UNINITIALIZED(*vr), *vasn;
- register enum token op;
- long UNINITIALIZED(res);
-
- if (prec == P_PRIMARY) {
- op = es->tok;
- if (op == O_BNOT || op == O_LNOT || op == O_MINUS
- || op == O_PLUS)
- {
- token();
- vl = intvar(evalexpr(P_PRIMARY));
- if (op == O_BNOT)
- vl->val.i = ~vl->val.i;
- else if (op == O_LNOT)
- vl->val.i = !vl->val.i;
- else if (op == O_MINUS)
- vl->val.i = -vl->val.i;
- /* op == O_PLUS is a no-op */
- } else if (op == OPEN_PAREN) {
- token();
- vl = evalexpr(MAX_PREC);
- if (es->tok != CLOSE_PAREN)
- evalerr(ET_STR, "missing )");
- token();
- } else if (op == O_PLUSPLUS || op == O_MINUSMINUS) {
- token();
- vl = do_ppmm(op, es->val, TRUE);
- token();
- } else if (op == VAR || op == LIT) {
- vl = es->val;
- token();
- } else {
- evalerr(ET_UNEXPECTED, (char *) 0);
- /*NOTREACHED*/
- }
- if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) {
- vl = do_ppmm(es->tok, vl, FALSE);
- token();
- }
- return vl;
- }
- vl = evalexpr(((int) prec) - 1);
- for (op = es->tok; IS_BINOP(op) && opinfo[(int) op].prec == prec;
- op = es->tok)
- {
- token();
- vasn = vl;
- if (op != O_ASN) /* vl may not have a value yet */
- vl = intvar(vl);
- if (IS_ASSIGNOP(op)) {
- assign_check(op, vasn);
- vr = intvar(evalexpr(P_ASSIGN));
- } else if (op != O_TERN && op != O_LAND && op != O_LOR)
- vr = intvar(evalexpr(((int) prec) - 1));
- if ((op == O_DIV || op == O_MOD || op == O_DIVASN
- || op == O_MODASN) && vr->val.i == 0)
- {
- if (es->noassign)
- vr->val.i = 1;
- else
- evalerr(ET_STR, "zero divisor");
- }
- switch ((int) op) {
- case O_TIMES:
- case O_TIMESASN:
- res = vl->val.i * vr->val.i;
- break;
- case O_DIV:
- case O_DIVASN:
- res = vl->val.i / vr->val.i;
- break;
- case O_MOD:
- case O_MODASN:
- res = vl->val.i % vr->val.i;
- break;
- case O_PLUS:
- case O_PLUSASN:
- res = vl->val.i + vr->val.i;
- break;
- case O_MINUS:
- case O_MINUSASN:
- res = vl->val.i - vr->val.i;
- break;
- case O_LSHIFT:
- case O_LSHIFTASN:
- res = vl->val.i << vr->val.i;
- break;
- case O_RSHIFT:
- case O_RSHIFTASN:
- res = vl->val.i >> vr->val.i;
- break;
- case O_LT:
- res = vl->val.i < vr->val.i;
- break;
- case O_LE:
- res = vl->val.i <= vr->val.i;
- break;
- case O_GT:
- res = vl->val.i > vr->val.i;
- break;
- case O_GE:
- res = vl->val.i >= vr->val.i;
- break;
- case O_EQ:
- res = vl->val.i == vr->val.i;
- break;
- case O_NE:
- res = vl->val.i != vr->val.i;
- break;
- case O_BAND:
- case O_BANDASN:
- res = vl->val.i & vr->val.i;
- break;
- case O_BXOR:
- case O_BXORASN:
- res = vl->val.i ^ vr->val.i;
- break;
- case O_BOR:
- case O_BORASN:
- res = vl->val.i | vr->val.i;
- break;
- case O_LAND:
- if (!vl->val.i)
- es->noassign++;
- vr = intvar(evalexpr(((int) prec) - 1));
- res = vl->val.i && vr->val.i;
- if (!vl->val.i)
- es->noassign--;
- break;
- case O_LOR:
- if (vl->val.i)
- es->noassign++;
- vr = intvar(evalexpr(((int) prec) - 1));
- res = vl->val.i || vr->val.i;
- if (vl->val.i)
- es->noassign--;
- break;
- case O_TERN:
- {
- int e = vl->val.i != 0;
- if (!e)
- es->noassign++;
- vl = evalexpr(MAX_PREC);
- if (!e)
- es->noassign--;
- if (es->tok != CTERN)
- evalerr(ET_STR, "missing :");
- token();
- if (e)
- es->noassign++;
- vr = evalexpr(P_TERN);
- if (e)
- es->noassign--;
- vl = e ? vl : vr;
- }
- break;
- case O_ASN:
- res = vr->val.i;
- break;
- case O_COMMA:
- res = vr->val.i;
- break;
- }
- if (IS_ASSIGNOP(op)) {
- vr->val.i = res;
- if (vasn->flag & INTEGER)
- setint_v(vasn, vr);
- else
- setint(vasn, res);
- vl = vr;
- } else if (op != O_TERN)
- vl->val.i = res;
- }
- return vl;
-}
-
-static void
-token()
-{
- register const char *cp;
- register int c;
- char *tvar;
-
- /* skip white space */
- for (cp = es->tokp; (c = *cp), isspace(c); cp++)
- ;
- es->tokp = cp;
-
- if (c == '\0')
- es->tok = END;
- else if (letter(c)) {
- for (; letnum(c); c = *cp)
- cp++;
- if (c == '[') {
- int len;
-
- len = array_ref_len(cp);
- if (len == 0)
- evalerr(ET_STR, "missing ]");
- cp += len;
- }
- if (es->noassign) {
- es->val = tempvar();
- es->val->flag |= EXPRLVALUE;
- } else {
- tvar = str_nsave(es->tokp, cp - es->tokp, ATEMP);
- es->val = global(tvar);
- afree(tvar, ATEMP);
- }
- es->tok = VAR;
- } else if (digit(c)) {
- for (; c != '_' && (letnum(c) || c == '#'); c = *cp++)
- ;
- tvar = str_nsave(es->tokp, --cp - es->tokp, ATEMP);
- es->val = tempvar();
- es->val->flag &= ~INTEGER;
- es->val->type = 0;
- es->val->val.s = tvar;
- if (setint_v(es->val, es->val) == NULL)
- evalerr(ET_BADLIT, tvar);
- afree(tvar, ATEMP);
- es->tok = LIT;
- } else {
- int i, n0;
-
- for (i = 0; (n0 = opinfo[i].name[0]); i++)
- if (c == n0
- && strncmp(cp, opinfo[i].name, opinfo[i].len) == 0)
- {
- es->tok = (enum token) i;
- cp += opinfo[i].len;
- break;
- }
- if (!n0)
- es->tok = BAD;
- }
- es->tokp = cp;
-}
-
-/* Do a ++ or -- operation */
-static struct tbl *
-do_ppmm(op, vasn, is_prefix)
- enum token op;
- struct tbl *vasn;
- bool_t is_prefix;
-{
- struct tbl *vl;
- int oval;
-
- assign_check(op, vasn);
-
- vl = intvar(vasn);
- oval = op == O_PLUSPLUS ? vl->val.i++ : vl->val.i--;
- if (vasn->flag & INTEGER)
- setint_v(vasn, vl);
- else
- setint(vasn, vl->val.i);
- if (!is_prefix) /* undo the inc/dec */
- vl->val.i = oval;
-
- return vl;
-}
-
-static void
-assign_check(op, vasn)
- enum token op;
- struct tbl *vasn;
-{
- if (vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE))
- evalerr(ET_LVALUE, opinfo[op].name);
- else if (vasn->flag & RDONLY)
- evalerr(ET_RDONLY, opinfo[op].name);
-}
-
-static struct tbl *
-tempvar()
-{
- register struct tbl *vp;
-
- vp = (struct tbl*) alloc(sizeof(struct tbl), ATEMP);
- vp->flag = ISSET|INTEGER;
- vp->type = 0;
- vp->areap = ATEMP;
- vp->val.i = 0;
- vp->name[0] = '\0';
- return vp;
-}
-
-/* cast (string) variable to temporary integer variable */
-static struct tbl *
-intvar(vp)
- register struct tbl *vp;
-{
- register struct tbl *vq;
-
- /* try to avoid replacing a temp var with another temp var */
- if (vp->name[0] == '\0'
- && (vp->flag & (ISSET|INTEGER|EXPRLVALUE)) == (ISSET|INTEGER))
- return vp;
-
- vq = tempvar();
- if (setint_v(vq, vp) == NULL) {
- if (vp->flag & EXPRINEVAL)
- evalerr(ET_RECURSIVE, vp->name);
- es->evaling = vp;
- vp->flag |= EXPRINEVAL;
- v_evaluate(vq, str_val(vp), FALSE);
- vp->flag &= ~EXPRINEVAL;
- es->evaling = (struct tbl *) 0;
- }
- return vq;
-}
diff --git a/bin/pdksh/history.c b/bin/pdksh/history.c
deleted file mode 100644
index f9c4b28e2e7..00000000000
--- a/bin/pdksh/history.c
+++ /dev/null
@@ -1,1193 +0,0 @@
-/* $OpenBSD: history.c,v 1.7 1997/06/19 13:58:42 kstailey Exp $ */
-
-/*
- * command history
- *
- * only implements in-memory history.
- */
-
-/*
- * This file contains
- * a) the original in-memory history mechanism
- * b) a simple file saving history mechanism done by sjg@zen
- * define EASY_HISTORY to get this
- * c) a more complicated mechanism done by pc@hillside.co.uk
- * that more closely follows the real ksh way of doing
- * things. You need to have the mmap system call for this
- * to work on your system
- */
-
-#include "sh.h"
-#include "ksh_stat.h"
-
-#ifdef HISTORY
-# ifdef EASY_HISTORY
-
-# ifndef HISTFILE
-# ifdef OS2
-# define HISTFILE "history.ksh"
-# else /* OS2 */
-# define HISTFILE ".pdksh_hist"
-# endif /* OS2 */
-# endif
-
-# else
-/* Defines and includes for the complicated case */
-
-# include <sys/file.h>
-# include <sys/mman.h>
-
-/*
- * variables for handling the data file
- */
-static int histfd;
-static int hsize;
-
-static int hist_count_lines ARGS((unsigned char *, int));
-static int hist_shrink ARGS((unsigned char *, int));
-static unsigned char *hist_skip_back ARGS((unsigned char *,int *,int));
-static void histload ARGS((Source *, unsigned char *, int));
-static void histinsert ARGS((Source *, int, unsigned char *));
-static void writehistfile ARGS((int, char *));
-static int sprinkle ARGS((int));
-
-# ifdef MAP_FILE
-# define MAP_FLAGS (MAP_FILE|MAP_PRIVATE)
-# else
-# define MAP_FLAGS MAP_PRIVATE
-# endif
-
-# endif /* of EASY_HISTORY */
-
-static int hist_execute ARGS((char *cmd));
-static int hist_replace ARGS((char **hp, const char *pat, const char *rep,
- int global));
-static char **hist_get ARGS((const char *str, int approx, int allow_cur));
-static char **hist_get_newest ARGS((int allow_cur));
-static char **hist_get_oldest ARGS(());
-static void histbackup ARGS((void));
-
-static char **current; /* current postition in history[] */
-static int curpos; /* current index in history[] */
-static char *hname; /* current name of history file */
-static int hstarted; /* set after hist_init() called */
-static Source *hist_source;
-
-
-int
-c_fc(wp)
- char **wp;
-{
- struct shf *shf;
- struct temp UNINITIALIZED(*tf);
- char *p, *editor = (char *) 0;
- int gflag = 0, lflag = 0, nflag = 0, sflag = 0, rflag = 0;
- int optc;
- char *first = (char *) 0, *last = (char *) 0;
- char **hfirst, **hlast, **hp;
-
- while ((optc = ksh_getopt(wp, &builtin_opt, "e:glnrs0,1,2,3,4,5,6,7,8,9,")) != EOF)
- switch (optc) {
- case 'e':
- p = builtin_opt.optarg;
- if (strcmp(p, "-") == 0)
- sflag++;
- else {
- editor = str_nsave(p, strlen(p) + 4, ATEMP);
- strcat(editor, " $_");
- }
- break;
- case 'g': /* non-at&t ksh */
- gflag++;
- break;
- case 'l':
- lflag++;
- break;
- case 'n':
- nflag++;
- break;
- case 'r':
- rflag++;
- break;
- case 's': /* posix version of -e - */
- sflag++;
- break;
- /* kludge city - accept -num as -- -num (kind of) */
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- p = shf_smprintf("-%c%s",
- optc, builtin_opt.optarg);
- if (!first)
- first = p;
- else if (!last)
- last = p;
- else {
- bi_errorf("too many arguments");
- return 1;
- }
- break;
- case '?':
- return 1;
- }
- wp += builtin_opt.optind;
-
- /* Substitute and execute command */
- if (sflag) {
- char *pat = (char *) 0, *rep = (char *) 0;
-
- if (editor || lflag || nflag || rflag) {
- bi_errorf("can't use -e, -l, -n, -r with -s (-e -)");
- return 1;
- }
-
- /* Check for pattern replacement argument */
- if (*wp && **wp && (p = strchr(*wp + 1, '='))) {
- pat = str_save(*wp, ATEMP);
- p = pat + (p - *wp);
- *p++ = '\0';
- rep = p;
- wp++;
- }
- /* Check for search prefix */
- if (!first && (first = *wp))
- wp++;
- if (last || *wp) {
- bi_errorf("too many arguments");
- return 1;
- }
-
- hp = first ? hist_get(first, FALSE, FALSE)
- : hist_get_newest(FALSE);
- if (!hp)
- return 1;
- return hist_replace(hp, pat, rep, gflag);
- }
-
- if (editor && (lflag || nflag)) {
- bi_errorf("can't use -l, -n with -e");
- return 1;
- }
-
- if (!first && (first = *wp))
- wp++;
- if (!last && (last = *wp))
- wp++;
- if (*wp) {
- bi_errorf("too many arguments");
- return 1;
- }
- if (!first) {
- hfirst = lflag ? hist_get("-16", TRUE, TRUE)
- : hist_get_newest(FALSE);
- if (!hfirst)
- return 1;
- /* can't fail if hfirst didn't fail */
- hlast = hist_get_newest(FALSE);
- } else {
- /* POSIX says not an error if first/last out of bounds
- * when range is specified; at&t ksh and pdksh allow out of
- * bounds for -l as well.
- */
- hfirst = hist_get(first, (lflag || last) ? TRUE : FALSE,
- lflag ? TRUE : FALSE);
- if (!hfirst)
- return 1;
- hlast = last ? hist_get(last, TRUE, lflag ? TRUE : FALSE)
- : (lflag ? hist_get_newest(FALSE) : hfirst);
- if (!hlast)
- return 1;
- }
- if (hfirst > hlast) {
- char **temp;
-
- temp = hfirst; hfirst = hlast; hlast = temp;
- rflag = !rflag; /* POSIX */
- }
-
- /* List history */
- if (lflag) {
- char *s, *t;
- const char *nfmt = nflag ? "\t" : "%d\t";
-
- for (hp = rflag ? hlast : hfirst;
- hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1)
- {
- shf_fprintf(shl_stdout, nfmt,
- hist_source->line - (int) (histptr - hp));
- /* print multi-line commands correctly */
- for (s = *hp; (t = strchr(s, '\n')); s = t)
- shf_fprintf(shl_stdout, "%.*s\t", ++t - s, s);
- shf_fprintf(shl_stdout, "%s\n", s);
- }
- shf_flush(shl_stdout);
- return 0;
- }
-
- /* Run editor on selected lines, then run resulting commands */
-
- tf = maketemp(ATEMP);
- tf->next = e->temps; e->temps = tf;
- if (!(shf = tf->shf)) {
- bi_errorf("cannot create temp file %s - %s",
- tf->name, strerror(errno));
- return 1;
- }
- for (hp = rflag ? hlast : hfirst;
- hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1)
- shf_fprintf(shf, "%s\n", *hp);
- if (shf_close(shf) == EOF) {
- bi_errorf("error writing temporary file - %s", strerror(errno));
- return 1;
- }
-
- if (!Flag(FSH))
- setstr(local("_", FALSE), tf->name);
-
- /* XXX: source should not get trashed by this.. */
- {
- Source *sold = source;
- int ret;
-
- ret = command(editor ? editor : "${FCEDIT:-/bin/ed} $_");
- source = sold;
- if (ret)
- return ret;
- }
-
- {
- struct stat statb;
- XString xs;
- char *xp;
- int n;
-
- if (!(shf = shf_open(tf->name, O_RDONLY, 0, 0))) {
- bi_errorf("cannot open temp file %s", tf->name);
- return 1;
- }
-
- n = fstat(shf_fileno(shf), &statb) < 0 ? 128
- : statb.st_size + 1;
- Xinit(xs, xp, n, hist_source->areap);
- while ((n = shf_read(xp, Xnleft(xs, xp), shf)) > 0) {
- xp += n;
- if (Xnleft(xs, xp) <= 0)
- XcheckN(xs, xp, Xlength(xs, xp));
- }
- if (n < 0) {
- bi_errorf("error reading temp file %s - %s",
- tf->name, strerror(shf_errno(shf)));
- shf_close(shf);
- return 1;
- }
- shf_close(shf);
- *xp = '\0';
- strip_nuls(Xstring(xs, xp), Xlength(xs, xp));
- return hist_execute(Xstring(xs, xp));
- }
-}
-
-/* Save cmd in history, execute cmd (cmd gets trashed) */
-static int
-hist_execute(cmd)
- char *cmd;
-{
- Source *sold;
- int ret;
- char *p, *q;
-
- histbackup();
-
- for (p = cmd; p; p = q) {
- if ((q = strchr(p, '\n'))) {
- *q++ = '\0'; /* kill the newline */
- if (!*q) /* ignore trailing newline */
- q = (char *) 0;
- }
-#ifdef EASY_HISTORY
- if (p != cmd)
- histappend(p, TRUE);
- else
-#endif /* EASY_HISTORY */
- histsave(++(hist_source->line), p, 1);
-
- shellf("%s\n", p); /* POSIX doesn't say this is done... */
- if ((p = q)) /* restore \n (trailing \n not restored) */
- q[-1] = '\n';
- }
-
- /* Commands are executed here instead of pushing them onto the
- * input 'cause posix says the redirection and variable assignments
- * in
- * X=y fc -e - 42 2> /dev/null
- * are to effect the repeated commands environment.
- */
- /* XXX: source should not get trashed by this.. */
- sold = source;
- ret = command(cmd);
- source = sold;
- return ret;
-}
-
-static int
-hist_replace(hp, pat, rep, global)
- char **hp;
- const char *pat;
- const char *rep;
- int global;
-{
- char *line;
-
- if (!pat)
- line = str_save(*hp, ATEMP);
- else {
- char *s, *s1;
- int pat_len = strlen(pat);
- int rep_len = strlen(rep);
- int len;
- XString xs;
- char *xp;
- int any_subst = 0;
-
- Xinit(xs, xp, 128, ATEMP);
- for (s = *hp; (s1 = strstr(s, pat))
- && (!any_subst || global) ; s = s1 + pat_len)
- {
- any_subst = 1;
- len = s1 - s;
- XcheckN(xs, xp, len + rep_len);
- memcpy(xp, s, len); /* first part */
- xp += len;
- memcpy(xp, rep, rep_len); /* replacement */
- xp += rep_len;
- }
- if (!any_subst) {
- bi_errorf("substitution failed");
- return 1;
- }
- len = strlen(s) + 1;
- XcheckN(xs, xp, len);
- memcpy(xp, s, len);
- xp += len;
- line = Xclose(xs, xp);
- }
- return hist_execute(line);
-}
-
-/*
- * get pointer to history given pattern
- * pattern is a number or string
- */
-static char **
-hist_get(str, approx, allow_cur)
- const char *str;
- int approx;
- int allow_cur;
-{
- char **hp = (char **) 0;
- int n;
-
- if (getn(str, &n)) {
- hp = histptr + (n < 0 ? n : (n - hist_source->line));
- if (hp < history) {
- if (approx)
- hp = hist_get_oldest();
- else {
- bi_errorf("%s: not in history", str);
- hp = (char **) 0;
- }
- } else if (hp > histptr) {
- if (approx)
- hp = hist_get_newest(allow_cur);
- else {
- bi_errorf("%s: not in history", str);
- hp = (char **) 0;
- }
- } else if (!allow_cur && hp == histptr) {
- bi_errorf("%s: invalid range", str);
- hp = (char **) 0;
- }
- } else {
- int anchored = *str == '?' ? (++str, 0) : 1;
-
- /* the -1 is to avoid the current fc command */
- n = findhist(histptr - history - 1, 0, str, anchored);
- if (n < 0) {
- bi_errorf("%s: not in history", str);
- hp = (char **) 0;
- } else
- hp = &history[n];
- }
- return hp;
-}
-
-/* Return a pointer to the newest command in the history */
-static char **
-hist_get_newest(allow_cur)
- int allow_cur;
-{
- if (histptr < history || (!allow_cur && histptr == history)) {
- bi_errorf("no history (yet)");
- return (char **) 0;
- }
- if (allow_cur)
- return histptr;
- return histptr - 1;
-}
-
-/* Return a pointer to the newest command in the history */
-static char **
-hist_get_oldest()
-{
- if (histptr <= history) {
- bi_errorf("no history (yet)");
- return (char **) 0;
- }
- return history;
-}
-
-/******************************/
-/* Back up over last histsave */
-/******************************/
-static void
-histbackup()
-{
- static int last_line = -1;
-
- if (histptr >= history && last_line != hist_source->line) {
- hist_source->line--;
- afree((void*)*histptr, APERM);
- histptr--;
- last_line = hist_source->line;
- }
-}
-
-/*
- * Return the current position.
- */
-char **
-histpos()
-{
- return current;
-}
-
-int
-histN()
-{
- return curpos;
-}
-
-int
-histnum(n)
- int n;
-{
- int last = histptr - history;
-
- if (n < 0 || n >= last) {
- current = histptr;
- curpos = last;
- return last;
- } else {
- current = &history[n];
- curpos = n;
- return n;
- }
-}
-
-/*
- * This will become unecessary if hist_get is modified to allow
- * searching from positions other than the end, and in either
- * direction.
- */
-int
-findhist(start, fwd, str, anchored)
- int start;
- int fwd;
- const char *str;
- int anchored;
-{
- char **hp;
- int maxhist = histptr - history;
- int incr = fwd ? 1 : -1;
- int len = strlen(str);
-
- if (start < 0 || start >= maxhist)
- start = maxhist;
-
- hp = &history[start];
- for (; hp >= history && hp <= histptr; hp += incr)
- if ((anchored && strncmp(*hp, str, len) == 0)
- || (!anchored && strstr(*hp, str)))
- return hp - history;
-
- return -1;
-}
-
-/*
- * set history
- * this means reallocating the dataspace
- */
-void
-sethistsize(n)
- int n;
-{
- if (n > 0 && n != histsize) {
- int cursize = histptr - history;
-
- /* save most recent history */
- if (n < cursize) {
- memmove(history, histptr - n, n * sizeof(char *));
- cursize = n;
- }
-
- history = (char **)aresize(history, n*sizeof(char *), APERM);
-
- histsize = n;
- histptr = history + cursize;
- }
-}
-
-/*
- * set history file
- * This can mean reloading/resetting/starting history file
- * maintenance
- */
-void
-sethistfile(name)
- const char *name;
-{
- /* if not started then nothing to do */
- if (hstarted == 0)
- return;
-
- /* if the name is the same as the name we have */
- if (hname && strcmp(hname, name) == 0)
- return;
-
- /*
- * its a new name - possibly
- */
-# ifdef EASY_HISTORY
- if (hname) {
- afree(hname, APERM);
- hname = NULL;
- }
-# else
- if (histfd) {
- /* yes the file is open */
- (void) close(histfd);
- histfd = 0;
- hsize = 0;
- afree(hname, APERM);
- hname = NULL;
- /* let's reset the history */
- histptr = history - 1;
- hist_source->line = 0;
- }
-# endif
-
- hist_init(hist_source);
-}
-
-/*
- * initialise the history vector
- */
-void
-init_histvec()
-{
- if (history == (char **)NULL) {
- histsize = HISTORYSIZE;
- history = (char **)alloc(histsize*sizeof (char *), APERM);
- histptr = history - 1;
- }
-}
-
-# ifdef EASY_HISTORY
-/*
- * save command in history
- */
-void
-histsave(lno, cmd, dowrite)
- int lno; /* ignored (compatibility with COMPLEX_HISTORY) */
- const char *cmd;
- int dowrite; /* ignored (compatibility with COMPLEX_HISTORY) */
-{
- register char **hp = histptr;
- char *cp;
-
- if (++hp >= history + histsize) { /* remove oldest command */
- afree((void*)history[0], APERM);
- memmove(history, history + 1,
- sizeof(history[0]) * (histsize - 1));
- hp = &history[histsize - 1];
- }
- *hp = str_save(cmd, APERM);
- /* trash trailing newline but allow imbedded newlines */
- cp = *hp + strlen(*hp);
- if (cp > *hp && cp[-1] == '\n')
- cp[-1] = '\0';
- histptr = hp;
-}
-
-/*
- * Append an entry to the last saved command. Used for multiline
- * commands
- */
-void
-histappend(cmd, nl_seperate)
- const char *cmd;
- int nl_seperate;
-{
- int hlen, clen;
- char *p;
-
- hlen = strlen(*histptr);
- clen = strlen(cmd);
- if (clen > 0 && cmd[clen-1] == '\n')
- clen--;
- p = *histptr = (char *) aresize(*histptr, hlen + clen + 2, APERM);
- p += hlen;
- if (nl_seperate)
- *p++ = '\n';
- memcpy(p, cmd, clen);
- p[clen] = '\0';
-}
-
-/*
- * 92-04-25 <sjg@zen>
- * A simple history file implementation.
- * At present we only save the history when we exit.
- * This can cause problems when there are multiple shells are
- * running under the same user-id. The last shell to exit gets
- * to save its history.
- */
-void
-hist_init(s)
- Source *s;
-{
- char *f;
- FILE *fh;
-
- if (Flag(FTALKING) == 0)
- return;
-
- hstarted = 1;
-
- hist_source = s;
-
- if ((f = str_val(global("HISTFILE"))) == NULL || *f == '\0') {
-# if 1 /* Don't use history file unless the user asks for it */
- hname = NULL;
- return;
-# else
- char *home = str_val(global("HOME"));
- int len;
-
- if (home == NULL)
- home = null;
- f = HISTFILE;
- hname = alloc(len = strlen(home) + strlen(f) + 2, APERM);
- shf_snprintf(hname, len, "%s/%s", home, f);
-# endif
- } else
- hname = str_save(f, APERM);
-
- if ((fh = fopen(hname, "r"))) {
- int pos = 0, nread = 0;
- int contin = 0; /* continuation of previous command */
- char *end;
- char hline[LINE + 1];
-
- while (1) {
- if (pos >= nread) {
- pos = 0;
- nread = fread(hline, 1, LINE, fh);
- if (nread <= 0)
- break;
- hline[nread] = '\0';
- }
- end = strchr(hline + pos, 0); /* will always succeed */
- if (contin)
- histappend(hline + pos, 0);
- else {
- hist_source->line++;
- histsave(0, hline + pos, 0);
- }
- pos = end - hline + 1;
- contin = end == &hline[nread];
- }
- fclose(fh);
- }
-}
-
-/*
- * save our history.
- * We check that we do not have more than we are allowed.
- * If the history file is read-only we do nothing.
- * Handy for having all shells start with a useful history set.
- */
-
-void
-hist_finish()
-{
- static int once;
- FILE *fh;
- register int i;
- register char **hp;
-
- if (once++)
- return;
- /* check how many we have */
- i = histptr - history;
- if (i >= histsize)
- hp = &histptr[-histsize];
- else
- hp = history;
- if (hname && (fh = fopen(hname, "w")))
- {
- for (i = 0; hp + i <= histptr && hp[i]; i++)
- fprintf(fh, "%s%c", hp[i], '\0');
- fclose(fh);
- }
-}
-
-# else /* EASY_HISTORY */
-
-/*
- * Routines added by Peter Collinson BSDI(Europe)/Hillside Systems to
- * a) permit HISTSIZE to control number of lines of history stored
- * b) maintain a physical history file
- *
- * It turns out that there is a lot of ghastly hackery here
- */
-
-
-/*
- * save command in history
- */
-void
-histsave(lno, cmd, dowrite)
- int lno;
- const char *cmd;
- int dowrite;
-{
- register char **hp;
- char *c, *cp;
-
- c = str_save(cmd, APERM);
- if ((cp = strchr(c, '\n')) != NULL)
- *cp = '\0';
-
- if (histfd && dowrite)
- writehistfile(lno, c);
-
- hp = histptr;
-
- if (++hp >= history + histsize) { /* remove oldest command */
- afree((void*)*history, APERM);
- for (hp = history; hp < history + histsize - 1; hp++)
- hp[0] = hp[1];
- }
- *hp = c;
- histptr = hp;
-}
-
-/*
- * Write history data to a file nominated by HISTFILE
- * if HISTFILE is unset then history still happens, but
- * the data is not written to a file
- * All copies of ksh looking at the file will maintain the
- * same history. This is ksh behaviour.
- *
- * This stuff uses mmap()
- * if your system ain't got it - then you'll have to undef HISTORYFILE
- */
-
-/*
- * Open a history file
- * Format is:
- * Bytes 1, 2: HMAGIC - just to check that we are dealing with
- * the correct object
- * Then follows a number of stored commands
- * Each command is
- * <command byte><command number(4 bytes)><bytes><null>
- */
-# define HMAGIC1 0xab
-# define HMAGIC2 0xcd
-# define COMMAND 0xff
-
-void
-hist_init(s)
- Source *s;
-{
- unsigned char *base;
- int lines;
- int fd;
-
- if (Flag(FTALKING) == 0)
- return;
-
- hstarted = 1;
-
- hist_source = s;
-
- hname = str_val(global("HISTFILE"));
- if (hname == NULL)
- return;
- hname = str_save(hname, APERM);
-
- retry:
- /* we have a file and are interactive */
- if ((fd = open(hname, O_RDWR|O_CREAT|O_APPEND, 0600)) < 0)
- return;
-
- histfd = savefd(fd, 0);
-
- (void) flock(histfd, LOCK_EX);
-
- hsize = lseek(histfd, 0L, SEEK_END);
-
- if (hsize == 0) {
- /* add magic */
- if (sprinkle(histfd)) {
- hist_finish();
- return;
- }
- }
- else if (hsize > 0) {
- /*
- * we have some data
- */
- base = (unsigned char *)mmap(0, hsize, PROT_READ, MAP_FLAGS, histfd, 0);
- /*
- * check on its validity
- */
- if ((int)base == -1 || *base != HMAGIC1 || base[1] != HMAGIC2) {
- if ((int)base != -1)
- munmap((caddr_t)base, hsize);
- hist_finish();
- unlink(hname);
- goto retry;
- }
- if (hsize > 2) {
- lines = hist_count_lines(base+2, hsize-2);
- if (lines > histsize) {
- /* we need to make the file smaller */
- if (hist_shrink(base, hsize))
- unlink(hname);
- munmap((caddr_t)base, hsize);
- hist_finish();
- goto retry;
- }
- }
- histload(hist_source, base+2, hsize-2);
- munmap((caddr_t)base, hsize);
- }
- (void) flock(histfd, LOCK_UN);
- hsize = lseek(histfd, 0L, SEEK_END);
-}
-
-typedef enum state {
- shdr, /* expecting a header */
- sline, /* looking for a null byte to end the line */
- sn1, /* bytes 1 to 4 of a line no */
- sn2, sn3, sn4,
-} State;
-
-static int
-hist_count_lines(base, bytes)
- register unsigned char *base;
- register int bytes;
-{
- State state = shdr;
- register lines = 0;
-
- while (bytes--) {
- switch (state)
- {
- case shdr:
- if (*base == COMMAND)
- state = sn1;
- break;
- case sn1:
- state = sn2; break;
- case sn2:
- state = sn3; break;
- case sn3:
- state = sn4; break;
- case sn4:
- state = sline; break;
- case sline:
- if (*base == '\0')
- lines++, state = shdr;
- }
- base++;
- }
- return lines;
-}
-
-/*
- * Shrink the history file to histsize lines
- */
-static int
-hist_shrink(oldbase, oldbytes)
- unsigned char *oldbase;
- int oldbytes;
-{
- int fd;
- char nfile[1024];
- struct stat statb;
- unsigned char *nbase = oldbase;
- int nbytes = oldbytes;
-
- nbase = hist_skip_back(nbase, &nbytes, histsize);
- if (nbase == NULL)
- return 1;
- if (nbase == oldbase)
- return 0;
-
- /*
- * create temp file
- */
- (void) shf_snprintf(nfile, sizeof(nfile), "%s.%d", hname, procpid);
- if ((fd = creat(nfile, 0600)) < 0)
- return 1;
-
- if (sprinkle(fd)) {
- close(fd);
- unlink(nfile);
- return 1;
- }
- if (write(fd, nbase, nbytes) != nbytes) {
- close(fd);
- unlink(nfile);
- return 1;
- }
- /*
- * worry about who owns this file
- */
- if (fstat(histfd, &statb) >= 0)
- fchown(fd, statb.st_uid, statb.st_gid);
- close(fd);
-
- /*
- * rename
- */
- if (rename(nfile, hname) < 0)
- return 1;
- return 0;
-}
-
-
-/*
- * find a pointer to the data `no' back from the end of the file
- * return the pointer and the number of bytes left
- */
-static unsigned char *
-hist_skip_back(base, bytes, no)
- unsigned char *base;
- int *bytes;
- int no;
-{
- register int lines = 0;
- register unsigned char *ep;
-
- for (ep = base + *bytes; --ep > base; ) {
- /* this doesn't really work: the 4 byte line number that is
- * encoded after the COMMAND byte can itself contain the
- * COMMAND byte....
- */
- for (; ep > base && *ep != COMMAND; ep--)
- ;
- if (ep == base)
- break;
- if (++lines == no) {
- *bytes = *bytes - ((char *)ep - (char *)base);
- return ep;
- }
- }
- return NULL;
-}
-
-/*
- * load the history structure from the stored data
- */
-static void
-histload(s, base, bytes)
- Source *s;
- register unsigned char *base;
- register int bytes;
-{
- State state;
- int lno;
- unsigned char *line;
-
- for (state = shdr; bytes-- > 0; base++) {
- switch (state) {
- case shdr:
- if (*base == COMMAND)
- state = sn1;
- break;
- case sn1:
- lno = (((*base)&0xff)<<24);
- state = sn2;
- break;
- case sn2:
- lno |= (((*base)&0xff)<<16);
- state = sn3;
- break;
- case sn3:
- lno |= (((*base)&0xff)<<8);
- state = sn4;
- break;
- case sn4:
- lno |= (*base)&0xff;
- line = base+1;
- state = sline;
- break;
- case sline:
- if (*base == '\0') {
- /* worry about line numbers */
- if (histptr >= history && lno-1 != s->line) {
- /* a replacement ? */
- histinsert(s, lno, line);
- }
- else {
- s->line = lno;
- histsave(lno, (char *)line, 0);
- }
- state = shdr;
- }
- }
- }
-}
-
-/*
- * Insert a line into the history at a specified number
- */
-static void
-histinsert(s, lno, line)
- Source *s;
- int lno;
- unsigned char *line;
-{
- register char **hp;
-
- if (lno >= s->line-(histptr-history) && lno <= s->line) {
- hp = &histptr[lno-s->line];
- if (*hp)
- afree((void*)*hp, APERM);
- *hp = str_save((char *)line, APERM);
- }
-}
-
-/*
- * write a command to the end of the history file
- * This *MAY* seem easy but it's also necessary to check
- * that the history file has not changed in size.
- * If it has - then some other shell has written to it
- * and we should read those commands to update our history
- */
-static void
-writehistfile(lno, cmd)
- int lno;
- char *cmd;
-{
- int sizenow;
- unsigned char *base;
- unsigned char *new;
- int bytes;
- char hdr[5];
-
- (void) flock(histfd, LOCK_EX);
- sizenow = lseek(histfd, 0L, SEEK_END);
- if (sizenow != hsize) {
- /*
- * Things have changed
- */
- if (sizenow > hsize) {
- /* someone has added some lines */
- bytes = sizenow - hsize;
- base = (unsigned char *)mmap(0, sizenow, PROT_READ, MAP_FLAGS, histfd, 0);
- if ((int)base == -1)
- goto bad;
- new = base + hsize;
- if (*new != COMMAND) {
- munmap((caddr_t)base, sizenow);
- goto bad;
- }
- hist_source->line--;
- histload(hist_source, new, bytes);
- hist_source->line++;
- lno = hist_source->line;
- munmap((caddr_t)base, sizenow);
- hsize = sizenow;
- } else {
- /* it has shrunk */
- /* but to what? */
- /* we'll give up for now */
- goto bad;
- }
- }
- /*
- * we can write our bit now
- */
- hdr[0] = COMMAND;
- hdr[1] = (lno>>24)&0xff;
- hdr[2] = (lno>>16)&0xff;
- hdr[3] = (lno>>8)&0xff;
- hdr[4] = lno&0xff;
- (void) write(histfd, hdr, 5);
- (void) write(histfd, cmd, strlen(cmd)+1);
- hsize = lseek(histfd, 0L, SEEK_END);
- (void) flock(histfd, LOCK_UN);
- return;
-bad:
- hist_finish();
-}
-
-void
-hist_finish()
-{
- (void) flock(histfd, LOCK_UN);
- (void) close(histfd);
- histfd = 0;
-}
-
-/*
- * add magic to the history file
- */
-static int
-sprinkle(fd)
- int fd;
-{
- static char mag[] = { HMAGIC1, HMAGIC2 };
-
- return(write(fd, mag, 2) != 2);
-}
-
-# endif
-#else /* HISTORY */
-
-/* No history to be compiled in: dummy routines to avoid lots more ifdefs */
-void
-init_histvec()
-{
-}
-void
-hist_init(s)
- Source *s;
-{
-}
-void
-hist_finish()
-{
-}
-void
-histsave(lno, cmd, dowrite)
- int lno;
- const char *cmd;
- int dowrite;
-{
- errorf("history not enabled");
-}
-#endif /* HISTORY */
diff --git a/bin/pdksh/io.c b/bin/pdksh/io.c
deleted file mode 100644
index 4a2f1cc88e2..00000000000
--- a/bin/pdksh/io.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/* $OpenBSD: io.c,v 1.4 1997/06/19 13:58:42 kstailey Exp $ */
-
-/*
- * shell buffered IO and formatted output
- */
-
-#include <ctype.h>
-#include "sh.h"
-#include "ksh_stat.h"
-
-/*
- * formatted output functions
- */
-
-
-/* A shell error occured (eg, syntax error, etc.) */
-void
-#ifdef HAVE_PROTOTYPES
-errorf(const char *fmt, ...)
-#else
-errorf(fmt, va_alist)
- const char *fmt;
- va_dcl
-#endif
-{
- va_list va;
-
- shl_stdout_ok = 0; /* debugging: note that stdout not valid */
- exstat = 1;
- if (*fmt) {
- error_prefix(TRUE);
- SH_VA_START(va, fmt);
- shf_vfprintf(shl_out, fmt, va);
- va_end(va);
- shf_putchar('\n', shl_out);
- }
- shf_flush(shl_out);
- unwind(LERROR);
-}
-
-/* like errorf(), but no unwind is done */
-void
-#ifdef HAVE_PROTOTYPES
-warningf(int fileline, const char *fmt, ...)
-#else
-warningf(fileline, fmt, va_alist)
- int fileline;
- const char *fmt;
- va_dcl
-#endif
-{
- va_list va;
-
- error_prefix(fileline);
- SH_VA_START(va, fmt);
- shf_vfprintf(shl_out, fmt, va);
- va_end(va);
- shf_putchar('\n', shl_out);
- shf_flush(shl_out);
-}
-
-/* Used by built-in utilities to prefix shell and utility name to message
- * (also unwinds environments for special builtins).
- */
-void
-#ifdef HAVE_PROTOTYPES
-bi_errorf(const char *fmt, ...)
-#else
-bi_errorf(fmt, va_alist)
- const char *fmt;
- va_dcl
-#endif
-{
- va_list va;
-
- shl_stdout_ok = 0; /* debugging: note that stdout not valid */
- exstat = 1;
- if (*fmt) {
- error_prefix(TRUE);
- /* not set when main() calls parse_args() */
- if (builtin_argv0)
- shf_fprintf(shl_out, "%s: ", builtin_argv0);
- SH_VA_START(va, fmt);
- shf_vfprintf(shl_out, fmt, va);
- va_end(va);
- shf_putchar('\n', shl_out);
- }
- shf_flush(shl_out);
- /* POSIX special builtins and ksh special builtins cause
- * non-interactive shells to exit.
- * XXX odd use of KEEPASN; also may not want LERROR here
- */
- if ((builtin_flag & SPEC_BI)
- || (Flag(FPOSIX) && (builtin_flag & KEEPASN)))
- {
- builtin_argv0 = (char *) 0;
- unwind(LERROR);
- }
-}
-
-/* Called when something that shouldn't happen does */
-void
-#ifdef HAVE_PROTOTYPES
-internal_errorf(int jump, const char *fmt, ...)
-#else
-internal_errorf(jump, fmt, va_alist)
- int jump;
- const char *fmt;
- va_dcl
-#endif
-{
- va_list va;
-
- error_prefix(TRUE);
- shf_fprintf(shl_out, "internal error: ");
- SH_VA_START(va, fmt);
- shf_vfprintf(shl_out, fmt, va);
- va_end(va);
- shf_putchar('\n', shl_out);
- shf_flush(shl_out);
- if (jump)
- unwind(LERROR);
-}
-
-/* used by error reporting functions to print "ksh: .kshrc[25]: " */
-void
-error_prefix(fileline)
- int fileline;
-{
- shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-'));
- if (fileline && source && source->file != NULL) {
- shf_fprintf(shl_out, "%s[%d]: ", source->file,
- source->errline > 0 ? source->errline : source->line);
- source->errline = 0;
- }
-}
-
-/* printf to shl_out (stderr) with flush */
-void
-#ifdef HAVE_PROTOTYPES
-shellf(const char *fmt, ...)
-#else
-shellf(fmt, va_alist)
- const char *fmt;
- va_dcl
-#endif
-{
- va_list va;
-
- SH_VA_START(va, fmt);
- shf_vfprintf(shl_out, fmt, va);
- va_end(va);
- shf_flush(shl_out);
-}
-
-/* printf to shl_stdout (stdout) */
-void
-#ifdef HAVE_PROTOTYPES
-shprintf(const char *fmt, ...)
-#else
-shprintf(fmt, va_alist)
- const char *fmt;
- va_dcl
-#endif
-{
- va_list va;
-
- if (!shl_stdout_ok)
- internal_errorf(1, "shl_stdout not valid");
- SH_VA_START(va, fmt);
- shf_vfprintf(shl_stdout, fmt, va);
- va_end(va);
-}
-
-/* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */
-int
-can_seek(fd)
- int fd;
-{
- struct stat statb;
-
- return fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ?
- SHF_UNBUF : 0;
-}
-
-struct shf shf_iob[3];
-
-void
-initio()
-{
- shf_fdopen(1, SHF_WR, shl_stdout); /* force buffer allocation */
- shf_fdopen(2, SHF_WR, shl_out);
- shf_fdopen(2, SHF_WR, shl_spare); /* force buffer allocation */
-}
-
-/* A dup2() with error checking */
-int
-ksh_dup2(ofd, nfd, errok)
- int ofd;
- int nfd;
- int errok;
-{
- int ret = dup2(ofd, nfd);
-
- if (ret < 0 && errno != EBADF && !errok)
- errorf("too many files open in shell");
-
-#ifdef DUP2_BROKEN
- /* Ultrix systems like to preserve the close-on-exec flag */
- if (ret >= 0)
- (void) fcntl(nfd, F_SETFD, 0);
-#endif /* DUP2_BROKEN */
-
- return ret;
-}
-
-/*
- * move fd from user space (0<=fd<10) to shell space (fd>=10),
- * set close-on-exec flag.
- */
-int
-savefd(fd, noclose)
- int fd;
- int noclose;
-{
- int nfd;
-
- if (fd < FDBASE) {
- nfd = ksh_dupbase(fd, FDBASE);
- if (nfd < 0)
- if (errno == EBADF)
- return -1;
- else
- errorf("too many files open in shell");
- if (!noclose)
- close(fd);
- } else
- nfd = fd;
- fd_clexec(nfd);
- return nfd;
-}
-
-void
-restfd(fd, ofd)
- int fd, ofd;
-{
- if (fd == 2)
- shf_flush(&shf_iob[fd]);
- if (ofd < 0) /* original fd closed */
- close(fd);
- else {
- ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */
- close(ofd);
- }
-}
-
-void
-openpipe(pv)
- register int *pv;
-{
- if (pipe(pv) < 0)
- errorf("can't create pipe - try again");
- pv[0] = savefd(pv[0], 0);
- pv[1] = savefd(pv[1], 0);
-}
-
-void
-closepipe(pv)
- register int *pv;
-{
- close(pv[0]);
- close(pv[1]);
-}
-
-/* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn
- * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
- */
-int
-check_fd(name, mode, emsgp)
- char *name;
- int mode;
- const char **emsgp;
-{
- int fd, fl;
-
- if (isdigit(name[0]) && !name[1]) {
- fd = name[0] - '0';
- if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) {
- if (emsgp)
- *emsgp = "bad file descriptor";
- return -1;
- }
- fl &= O_ACCMODE;
-#ifdef OS2
- if (mode == W_OK ) {
- if (setmode(fd, O_TEXT) == -1) {
- if (emsgp)
- *emsgp = "couldn't set write mode";
- return -1;
- }
- } else if (mode == R_OK)
- if (setmode(fd, O_BINARY) == -1) {
- if (emsgp)
- *emsgp = "couldn't set read mode";
- return -1;
- }
-#else /* OS2 */
- /* X_OK is a kludge to disable this check for dups (x<&1):
- * historical shells never did this check (XXX don't know what
- * posix has to say).
- */
- if (!(mode & X_OK) && fl != O_RDWR
- && (((mode & R_OK) && fl != O_RDONLY)
- || ((mode & W_OK) && fl != O_WRONLY)))
- {
- if (emsgp)
- *emsgp = (fl == O_WRONLY) ?
- "fd not open for reading"
- : "fd not open for writing";
- return -1;
- }
-#endif /* OS2 */
- return fd;
- }
-#ifdef KSH
- else if (name[0] == 'p' && !name[1])
- return coproc_getfd(mode, emsgp);
-#endif /* KSH */
- if (emsgp)
- *emsgp = "illegal file descriptor name";
- return -1;
-}
-
-#ifdef KSH
-/* Called once from main */
-void
-coproc_init()
-{
- coproc.read = coproc.readw = coproc.write = -1;
- coproc.njobs = 0;
- coproc.id = 0;
-}
-
-/* Called by c_read() when eof is read - close fd if it is the co-process fd */
-void
-coproc_read_close(fd)
- int fd;
-{
- if (coproc.read >= 0 && fd == coproc.read) {
- coproc_readw_close(fd);
- close(coproc.read);
- coproc.read = -1;
- }
-}
-
-/* Called by c_read() and by iosetup() to close the other side of the
- * read pipe, so reads will actually terminate.
- */
-void
-coproc_readw_close(fd)
- int fd;
-{
- if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
- close(coproc.readw);
- coproc.readw = -1;
- }
-}
-
-/* Called by c_print when a write to a fd fails with EPIPE and by iosetup
- * when co-process input is dup'd
- */
-void
-coproc_write_close(fd)
- int fd;
-{
- if (coproc.write >= 0 && fd == coproc.write) {
- close(coproc.write);
- coproc.write = -1;
- }
-}
-
-/* Called to check for existance of/value of the co-process file descriptor.
- * (Used by check_fd() and by c_read/c_print to deal with -p option).
- */
-int
-coproc_getfd(mode, emsgp)
- int mode;
- const char **emsgp;
-{
- int fd = (mode & R_OK) ? coproc.read : coproc.write;
-
- if (fd >= 0)
- return fd;
- if (emsgp)
- *emsgp = "no coprocess";
- return -1;
-}
-
-/* called to close file descriptors related to the coprocess (if any)
- * Should be called with SIGCHLD blocked.
- */
-void
-coproc_cleanup(reuse)
- int reuse;
-{
- /* This to allow co-processes to share output pipe */
- if (!reuse || coproc.readw < 0 || coproc.read < 0) {
- if (coproc.read >= 0) {
- close(coproc.read);
- coproc.read = -1;
- }
- if (coproc.readw >= 0) {
- close(coproc.readw);
- coproc.readw = -1;
- }
- }
- if (coproc.write >= 0) {
- close(coproc.write);
- coproc.write = -1;
- }
-}
-#endif /* KSH */
-
-/*
- * temporary files
- */
-
-struct temp *
-maketemp(ap)
- Area *ap;
-{
- static unsigned int inc;
- struct temp *tp;
- int len;
- int fd;
- char *path;
- const char *tmp;
-
- tmp = tmpdir ? tmpdir : "/tmp";
- /* The 20 + 20 is a paranoid worst case for pid/inc */
- len = strlen(tmp) + 3 + 20 + 20 + 1;
- tp = (struct temp *) alloc(sizeof(struct temp) + len, ap);
- tp->name = path = (char *) &tp[1];
- tp->shf = (struct shf *) 0;
- while (1) {
- /* Note that temp files need to fit 8.3 DOS limits */
- shf_snprintf(path, len, "%s/sh%05u.%03x",
- tmp, (unsigned) procpid, inc++);
- /* Mode 0600 to be paranoid, O_TRUNC in case O_EXCL isn't
- * really there.
- */
- fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600);
- if (fd >= 0) {
- tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
- break;
- }
- if (errno != EINTR
-#ifdef EEXIST
- && errno != EEXIST
-#endif /* EEXIST */
-#ifdef EISDIR
- && errno != EISDIR
-#endif /* EISDIR */
- )
- /* Error must be printed by called: don't know here if
- * errorf() or bi_errorf() should be used.
- */
- break;
- }
- tp->next = NULL;
- tp->pid = procpid;
- return tp;
-}
diff --git a/bin/pdksh/jobs.c b/bin/pdksh/jobs.c
deleted file mode 100644
index e79f2ac731c..00000000000
--- a/bin/pdksh/jobs.c
+++ /dev/null
@@ -1,1844 +0,0 @@
-/* $OpenBSD: jobs.c,v 1.6 1997/06/19 13:58:43 kstailey Exp $ */
-
-/*
- * Process and job control
- */
-
-/*
- * Reworked/Rewritten version of Eric Gisin's/Ron Natalie's code by
- * Larry Bouzane (larry@cs.mun.ca) and hacked again by
- * Michael Rendell (michael@cs.mun.ca)
- *
- * The interface to the rest of the shell should probably be changed
- * to allow use of vfork() when available but that would be way too much
- * work :)
- *
- * Notes regarding the copious ifdefs:
- * - JOB_SIGS is independent of JOBS - it is defined if there are modern
- * signal and wait routines available. This is prefered, even when
- * JOBS is not defined, since the shell will not otherwise notice when
- * background jobs die until the shell waits for a foreground process
- * to die.
- * - TTY_PGRP defined iff JOBS is defined - defined if there are tty
- * process groups
- * - NEED_PGRP_SYNC defined iff JOBS is defined - see comment below
- */
-
-#include "sh.h"
-#include "ksh_stat.h"
-#include "ksh_wait.h"
-#include "ksh_times.h"
-#include "tty.h"
-
-/* Start of system configuration stuff */
-
-/* We keep CHILD_MAX zombie processes around (exact value isn't critical) */
-#ifndef CHILD_MAX
-# if defined(HAVE_SYSCONF) && defined(_SC_CHILD_MAX)
-# define CHILD_MAX sysconf(_SC_CHILD_MAX)
-# else /* _SC_CHILD_MAX */
-# ifdef _POSIX_CHILD_MAX
-# define CHILD_MAX ((_POSIX_CHILD_MAX) * 2)
-# else /* _POSIX_CHILD_MAX */
-# define CHILD_MAX 20
-# endif /* _POSIX_CHILD_MAX */
-# endif /* _SC_CHILD_MAX */
-#endif /* !CHILD_MAX */
-
-#ifdef JOBS
-# if defined(HAVE_TCSETPGRP) || defined(TIOCSPGRP)
-# define TTY_PGRP
-# endif
-# ifdef BSD_PGRP
-# define setpgid setpgrp
-# define getpgID() getpgrp(0)
-# else
-# define getpgID() getpgrp()
-# endif
-# if defined(TTY_PGRP) && !defined(HAVE_TCSETPGRP)
-int tcsetpgrp ARGS((int fd, pid_t grp));
-int tcgetpgrp ARGS((int fd));
-
-int
-tcsetpgrp(fd, grp)
- int fd;
- pid_t grp;
-{
- return ioctl(fd, TIOCSPGRP, &grp);
-}
-
-int
-tcgetpgrp(fd)
- int fd;
-{
- int r, grp;
-
- if ((r = ioctl(fd, TIOCGPGRP, &grp)) < 0)
- return r;
- return grp;
-}
-# endif /* !HAVE_TCSETPGRP && TIOCSPGRP */
-#else /* JOBS */
-/* These so we can use ifdef xxx instead of if defined(JOBS) && defined(xxx) */
-# undef TTY_PGRP
-# undef NEED_PGRP_SYNC
-#endif /* JOBS */
-
-/* End of system configuration stuff */
-
-
-/* Order important! */
-#define PRUNNING 0
-#define PEXITED 1
-#define PSIGNALLED 2
-#define PSTOPPED 3
-
-typedef struct proc Proc;
-struct proc {
- Proc *next; /* next process in pipeline (if any) */
- int state;
- WAIT_T status; /* wait status */
- pid_t pid; /* process id */
- char command[48]; /* process command string */
-};
-
-/* Notify/print flag - j_print() argument */
-#define JP_NONE 0 /* don't print anything */
-#define JP_SHORT 1 /* print signals processes were killed by */
-#define JP_MEDIUM 2 /* print [job-num] -/+ command */
-#define JP_LONG 3 /* print [job-num] -/+ pid command */
-#define JP_PGRP 4 /* print pgrp */
-
-/* put_job() flags */
-#define PJ_ON_FRONT 0 /* at very front */
-#define PJ_PAST_STOPPED 1 /* just past any stopped jobs */
-
-/* Job.flags values */
-#define JF_STARTED 0x001 /* set when all processes in job are started */
-#define JF_WAITING 0x002 /* set if j_waitj() is waiting on job */
-#define JF_W_ASYNCNOTIFY 0x004 /* set if waiting and async notification ok */
-#define JF_XXCOM 0x008 /* set for `command` jobs */
-#define JF_FG 0x010 /* running in foreground (also has tty pgrp) */
-#define JF_SAVEDTTY 0x020 /* j->ttystate is valid */
-#define JF_CHANGED 0x040 /* process has changed state */
-#define JF_KNOWN 0x080 /* $! referenced */
-#define JF_ZOMBIE 0x100 /* known, unwaited process */
-#define JF_REMOVE 0x200 /* flaged for removal (j_jobs()/j_noityf()) */
-#define JF_USETTYMODE 0x400 /* tty mode saved if process exits normally */
-
-typedef struct job Job;
-struct job {
- Job *next; /* next job in list */
- int job; /* job number: %n */
- int flags; /* see JF_* */
- int state; /* job state */
- int status; /* exit status of last process */
- pid_t pgrp; /* process group of job */
- pid_t ppid; /* pid of process that forked job */
- INT32 age; /* number of jobs started */
- clock_t systime; /* system time used by job */
- clock_t usrtime; /* user time used by job */
- Proc *proc_list; /* process list */
- Proc *last_proc; /* last process in list */
-#ifdef KSH
- Coproc_id coproc_id; /* 0 or id of coprocess output pipe */
-#endif /* KSH */
-#ifdef TTY_PGRP
- TTY_state ttystate; /* saved tty state for stopped jobs */
-#endif /* TTY_PGRP */
-};
-
-/* Flags for j_waitj() */
-#define JW_NONE 0x00
-#define JW_INTERRUPT 0x01 /* ^C will stop the wait */
-#define JW_ASYNCNOTIFY 0x02 /* asynchronous notification during wait ok */
-#define JW_STOPPEDWAIT 0x04 /* wait even if job stopped */
-
-/* Error codes for j_lookup() */
-#define JL_OK 0
-#define JL_NOSUCH 1 /* no such job */
-#define JL_AMBIG 2 /* %foo or %?foo is ambiguous */
-#define JL_INVALID 3 /* non-pid, non-% job id */
-
-static const char *const lookup_msgs[] = {
- null,
- "no such job",
- "ambiguous",
- "argument must be %job or process id",
- (char *) 0
- };
-clock_t j_systime, j_usrtime; /* user and system time of last j_waitjed job */
-
-static Job *job_list; /* job list */
-static Job *last_job;
-static Job *async_job;
-static pid_t async_pid;
-
-static int nzombie; /* # of zombies owned by this process */
-static INT32 njobs; /* # of jobs started */
-static int child_max; /* CHILD_MAX */
-
-
-#ifdef JOB_SIGS
-/* held_sigchld is set if sigchld occurs before a job is completely started */
-static int held_sigchld;
-#endif /* JOB_SIGS */
-
-#ifdef JOBS
-static struct shf *shl_j;
-#endif /* JOBS */
-
-#ifdef NEED_PGRP_SYNC
-/* On some systems, the kernel doesn't count zombie processes when checking
- * if a process group is valid, which can cause problems in creating the
- * pipeline "cmd1 | cmd2": if cmd1 can die (and go into the zombie state)
- * before cmd2 is started, the kernel doesn't allow the setpgid() for cmd2
- * to succeed. Solution is to create a pipe between the parent and the first
- * process; the first process doesn't do anything until the pipe is closed
- * and the parent doesn't close the pipe until all the processes are started.
- */
-static int j_sync_pipe[2];
-static int j_sync_open;
-#endif /* NEED_PGRP_SYNC */
-
-#ifdef TTY_PGRP
-static int ttypgrp_ok; /* set if can use tty pgrps */
-static pid_t restore_ttypgrp = -1;
-static pid_t our_pgrp;
-static int const tt_sigs[] = { SIGTSTP, SIGTTIN, SIGTTOU };
-#endif /* TTY_PGRP */
-
-static void j_set_async ARGS((Job *j));
-static void j_startjob ARGS((Job *j));
-static int j_waitj ARGS((Job *j, int flags, const char *where));
-static RETSIGTYPE j_sigchld ARGS((int sig));
-static void j_print ARGS((Job *j, int how, struct shf *shf));
-static Job *j_lookup ARGS((const char *cp, int *ecodep));
-static Job *new_job ARGS((void));
-static Proc *new_proc ARGS((void));
-static void check_job ARGS((Job *j));
-static void put_job ARGS((Job *j, int where));
-static void remove_job ARGS((Job *j, const char *where));
-static void kill_job ARGS((Job *j));
-static void fill_command ARGS((char *c, int len, struct op *t));
-
-/* initialize job control */
-void
-j_init(mflagset)
- int mflagset;
-{
- child_max = CHILD_MAX; /* so syscon() isn't always being called */
-
-#ifdef JOB_SIGS
- sigemptyset(&sm_default);
- sigprocmask(SIG_SETMASK, &sm_default, (sigset_t *) 0);
-
- sigemptyset(&sm_sigchld);
- sigaddset(&sm_sigchld, SIGCHLD);
-
- setsig(&sigtraps[SIGCHLD], j_sigchld,
- SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
-#else /* JOB_SIGS */
- /* Make sure SIGCHLD isn't ignored - can do odd things under SYSV */
- setsig(&sigtraps[SIGCHLD], SIG_DFL, SS_RESTORE_ORIG|SS_FORCE);
-#endif /* JOB_SIGS */
-
-#ifdef JOBS
- if (!mflagset && Flag(FTALKING))
- Flag(FMONITOR) = 1;
-
- /* shl_j is used to do asynchronous notification (used in
- * an interrupt handler, so need a distinct shf)
- */
- shl_j = shf_fdopen(2, SHF_WR, (struct shf *) 0);
-
-# ifdef TTY_PGRP
- if (Flag(FMONITOR) || Flag(FTALKING)) {
- int i;
-
- /* the TF_SHELL_USES test is a kludge that lets us know if
- * if the signals have been changed by the shell.
- */
- for (i = NELEM(tt_sigs); --i >= 0; ) {
- sigtraps[tt_sigs[i]].flags |= TF_SHELL_USES;
- /* j_change() sets this to SS_RESTORE_DFL if FMONITOR */
- setsig(&sigtraps[tt_sigs[i]], SIG_IGN,
- SS_RESTORE_IGN|SS_FORCE);
- }
- }
-# endif /* TTY_PGRP */
-
- /* j_change() calls tty_init() */
- if (Flag(FMONITOR))
- j_change();
- else
-#endif /* JOBS */
- if (Flag(FTALKING))
- tty_init(TRUE);
-}
-
-/* job cleanup before shell exit */
-void
-j_exit()
-{
- /* kill stopped, and possibly running, jobs */
- Job *j;
- int killed = 0;
-
- for (j = job_list; j != (Job *) 0; j = j->next) {
- if (j->ppid == procpid
- && (j->state == PSTOPPED
- || (j->state == PRUNNING
- && ((j->flags & JF_FG)
- || (Flag(FLOGIN) && !Flag(FNOHUP)
- && procpid == kshpid)))))
- {
- killed = 1;
- killpg(j->pgrp, SIGHUP);
-#ifdef JOBS
- if (j->state == PSTOPPED)
- killpg(j->pgrp, SIGCONT);
-#endif /* JOBS */
- }
- }
- if (killed)
- sleep(1);
- j_notify();
-
-#ifdef JOBS
-# ifdef TTY_PGRP
- if (kshpid == procpid && restore_ttypgrp >= 0) {
- /* Need to restore the tty pgrp to what it was when the
- * shell started up, so that the process that started us
- * will be able to access the tty when we are done.
- * Also need to restore our process group in case we are
- * about to do an exec so that both our parent and the
- * process we are to become will be able to access the tty.
- */
- tcsetpgrp(tty_fd, restore_ttypgrp);
- setpgid(0, restore_ttypgrp);
- }
-# endif /* TTY_PGRP */
- if (Flag(FMONITOR)) {
- Flag(FMONITOR) = 0;
- j_change();
- }
-#endif /* JOBS */
-}
-
-#ifdef JOBS
-/* turn job control on or off according to Flag(FMONITOR) */
-void
-j_change()
-{
- int i;
-
- if (Flag(FMONITOR)) {
- /* Don't call get_tty() 'til we own the tty process group */
- tty_init(FALSE);
-
-# ifdef TTY_PGRP
- /* no controlling tty, no SIGT* */
- ttypgrp_ok = tty_fd >= 0 && tty_devtty;
-
- if (ttypgrp_ok && (our_pgrp = getpgID()) < 0) {
- warningf(FALSE, "j_init: getpgrp() failed: %s",
- strerror(errno));
- ttypgrp_ok = 0;
- }
- if (ttypgrp_ok) {
- setsig(&sigtraps[SIGTTIN], SIG_DFL,
- SS_RESTORE_ORIG|SS_FORCE);
- /* wait to be given tty (POSIX.1, B.2, job control) */
- while (1) {
- pid_t ttypgrp;
-
- if ((ttypgrp = tcgetpgrp(tty_fd)) < 0) {
- warningf(FALSE,
- "j_init: tcgetpgrp() failed: %s",
- strerror(errno));
- ttypgrp_ok = 0;
- break;
- }
- if (ttypgrp == our_pgrp)
- break;
- kill(0, SIGTTIN);
- }
- }
- for (i = NELEM(tt_sigs); --i >= 0; )
- setsig(&sigtraps[tt_sigs[i]], SIG_IGN,
- SS_RESTORE_DFL|SS_FORCE);
- if (ttypgrp_ok && our_pgrp != kshpid) {
- if (setpgid(0, kshpid) < 0) {
- warningf(FALSE,
- "j_init: setpgid() failed: %s",
- strerror(errno));
- ttypgrp_ok = 0;
- } else {
- if (tcsetpgrp(tty_fd, kshpid) < 0) {
- warningf(FALSE,
- "j_init: tcsetpgrp() failed: %s",
- strerror(errno));
- ttypgrp_ok = 0;
- } else
- restore_ttypgrp = our_pgrp;
- our_pgrp = kshpid;
- }
- }
-# if defined(NTTYDISC) && defined(TIOCSETD) && !defined(HAVE_TERMIOS_H) && !defined(HAVE_TERMIO_H)
- if (ttypgrp_ok) {
- int ldisc = NTTYDISC;
-
- if (ioctl(tty_fd, TIOCSETD, &ldisc) < 0)
- warningf(FALSE,
- "j_init: can't set new line discipline: %s",
- strerror(errno));
- }
-# endif /* NTTYDISC && TIOCSETD */
- if (!ttypgrp_ok)
- warningf(FALSE, "warning: won't have full job control");
-# endif /* TTY_PGRP */
- if (tty_fd >= 0)
- get_tty(tty_fd, &tty_state);
- } else {
-# ifdef TTY_PGRP
- ttypgrp_ok = 0;
- if (Flag(FTALKING))
- for (i = NELEM(tt_sigs); --i >= 0; )
- setsig(&sigtraps[tt_sigs[i]], SIG_IGN,
- SS_RESTORE_IGN|SS_FORCE);
- else
- for (i = NELEM(tt_sigs); --i >= 0; ) {
- if (sigtraps[tt_sigs[i]].flags & (TF_ORIG_IGN
- |TF_ORIG_DFL))
- setsig(&sigtraps[tt_sigs[i]],
- (sigtraps[tt_sigs[i]].flags & TF_ORIG_IGN) ? SIG_IGN : SIG_DFL,
- SS_RESTORE_ORIG|SS_FORCE);
- }
-# endif /* TTY_PGRP */
- if (!Flag(FTALKING))
- tty_close();
- }
-}
-#endif /* JOBS */
-
-/* execute tree in child subprocess */
-int
-exchild(t, flags, close_fd)
- struct op *t;
- int flags;
- int close_fd; /* used if XPCLOSE or XCCLOSE */
-{
- static Proc *last_proc; /* for pipelines */
-
- int i;
-#ifdef JOB_SIGS
- sigset_t omask;
-#endif /* JOB_SIGS */
- Proc *p;
- Job *j;
- int rv = 0;
- int forksleep;
- int orig_flags = flags;
- int ischild;
-
- flags &= ~(XFORK|XPCLOSE|XCCLOSE|XCOPROC);
- if (flags & XEXEC)
- return execute(t, flags);
-
-#ifdef JOB_SIGS
- /* no SIGCHLD's while messing with job and process lists */
- sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-#endif /* JOB_SIGS */
-
- p = new_proc();
- p->next = (Proc *) 0;
- p->state = PRUNNING;
- WSTATUS(p->status) = 0;
- p->pid = 0;
-
- /* link process into jobs list */
- if (flags&XPIPEI) { /* continuing with a pipe */
- j = last_job;
- last_proc->next = p;
- last_proc = p;
- } else {
-#ifdef NEED_PGRP_SYNC
- if (j_sync_open) { /* should never happen */
- j_sync_open = 0;
- closepipe(j_sync_pipe);
- }
- /* don't do the sync pipe business if there is no pipeline */
- if (flags & XPIPEO) {
- openpipe(j_sync_pipe);
- j_sync_open = 1;
- }
-#endif /* NEED_PGRP_SYNC */
- j = new_job(); /* fills in j->job */
- /* we don't consider XXCOM's foreground since they don't get
- * tty process group and we don't save or restore tty modes.
- */
- j->flags = (flags & XXCOM) ? JF_XXCOM
- : ((flags & XBGND) ? 0 : (JF_FG|JF_USETTYMODE));
- j->usrtime = j->systime = 0;
- j->state = PRUNNING;
- j->pgrp = 0;
- j->ppid = procpid;
- j->age = ++njobs;
- j->proc_list = p;
-#ifdef KSH
- j->coproc_id = 0;
-#endif /* KSH */
- last_job = j;
- last_proc = p;
- put_job(j, PJ_PAST_STOPPED);
- }
-
- fill_command(p->command, sizeof(p->command), t);
-
- /* create child process */
- forksleep = 1;
- while ((i = fork()) < 0 && errno == EAGAIN && forksleep < 32) {
- if (intrsig) /* allow user to ^C out... */
- break;
- sleep(forksleep);
- forksleep <<= 1;
- }
- if (i < 0) {
- kill_job(j);
- remove_job(j, "fork failed");
-#ifdef NEED_PGRP_SYNC
- if (j_sync_open) {
- closepipe(j_sync_pipe);
- j_sync_open = 0;
- }
-#endif /* NEED_PGRP_SYNC */
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
- errorf("cannot fork - try again");
- }
- ischild = i == 0;
- if (ischild)
- p->pid = procpid = getpid();
- else
- p->pid = i;
-
-#ifdef JOBS
- /* job control set up */
- if (Flag(FMONITOR) && !(flags&XXCOM)) {
- int dotty = 0;
-# ifdef NEED_PGRP_SYNC
- int first_child_sync = 0;
-# endif /* NEED_PGRP_SYNC */
-
-# ifdef NEED_PGRP_SYNC
- if (j_sync_open) {
- /*
- * The Parent closes 0, keeps 1 open 'til the whole
- * pipeline is started. The First child closes 1,
- * keeps 0 open (reads from it). The remaining
- * children just have to close 1 (parent has already
- * closeed 0).
- */
- if (j->pgrp == 0) { /* First process */
- close(j_sync_pipe[ischild]);
- j_sync_pipe[ischild] = -1;
- first_child_sync = ischild;
- } else if (ischild) {
- j_sync_open = 0;
- closepipe(j_sync_pipe);
- }
- }
-# endif /* NEED_PGRP_SYNC */
- if (j->pgrp == 0) { /* First process */
- j->pgrp = p->pid;
- dotty = 1;
- }
-
- /* set pgrp in both parent and child to deal with race
- * condition
- */
- setpgid(p->pid, j->pgrp);
-# ifdef TTY_PGRP
- /* YYY: should this be
- if (ttypgrp_ok && ischild && !(flags&XBGND))
- tcsetpgrp(tty_fd, j->pgrp);
- instead? (see also YYY below)
- */
- if (ttypgrp_ok && dotty && !(flags & XBGND))
- tcsetpgrp(tty_fd, j->pgrp);
-# endif /* TTY_PGRP */
-# ifdef NEED_PGRP_SYNC
- if (first_child_sync) {
- char c;
- while (read(j_sync_pipe[0], &c, 1) == -1
- && errno == EINTR)
- ;
- close(j_sync_pipe[0]);
- j_sync_open = 0;
- }
-# endif /* NEED_PGRP_SYNC */
- }
-#endif /* JOBS */
-
- /* used to close pipe input fd */
- if (close_fd >= 0 && (((orig_flags & XPCLOSE) && !ischild)
- || ((orig_flags & XCCLOSE) && ischild)))
- close(close_fd);
- if (ischild) { /* child */
-#ifdef KSH
- /* Do this before restoring signal */
- if (orig_flags & XCOPROC)
- coproc_cleanup(FALSE);
-#endif /* KSH */
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
- cleanup_parents_env();
-#ifdef TTY_PGRP
- /* If FMONITOR or FTALKING is set, these signals are ignored,
- * if neither FMONITOR nor FTALKING are set, the signals have
- * their inherited values.
- */
- if (Flag(FMONITOR) && !(flags & XXCOM)) {
- for (i = NELEM(tt_sigs); --i >= 0; )
- setsig(&sigtraps[tt_sigs[i]], SIG_DFL,
- SS_RESTORE_DFL|SS_FORCE);
- }
-#endif /* TTY_PGRP */
-#ifdef HAVE_NICE
- if (Flag(FBGNICE) && (flags & XBGND))
- nice(4);
-#endif /* HAVE_NICE */
- if ((flags & XBGND) && !Flag(FMONITOR)) {
- setsig(&sigtraps[SIGINT], SIG_IGN,
- SS_RESTORE_IGN|SS_FORCE);
- setsig(&sigtraps[SIGQUIT], SIG_IGN,
- SS_RESTORE_IGN|SS_FORCE);
- if (!(orig_flags & (XPIPEI | XCOPROC))) {
- int fd = open("/dev/null", 0);
- (void) ksh_dup2(fd, 0, TRUE);
- close(fd);
- }
- }
- remove_job(j, "child"); /* in case of `jobs` command */
- nzombie = 0;
-#ifdef JOBS
- ttypgrp_ok = 0;
- Flag(FMONITOR) = 0;
-#endif /* JOBS */
- Flag(FTALKING) = 0;
- tty_close();
- cleartraps();
- execute(t, flags|XEXEC); /* no return */
- internal_errorf(0, "exchild: execute() returned");
- unwind(LLEAVE);
- /* NOTREACHED */
- }
-
- /* shell (parent) stuff */
- if (!(flags & XPIPEO)) { /* last process in a job */
-#ifdef TTY_PGRP
- /* YYY: Is this needed? (see also YYY above)
- if (Flag(FMONITOR) && !(flags&(XXCOM|XBGND)))
- tcsetpgrp(tty_fd, j->pgrp);
- */
-#endif /* TTY_PGRP */
- j_startjob(j);
-#ifdef KSH
- if (orig_flags & XCOPROC) {
- j->coproc_id = coproc.id;
- coproc.njobs++; /* n jobs using co-process output */
- coproc.job = (void *) j; /* j using co-process input */
- }
-#endif /* KSH */
- if (flags & XBGND) {
- j_set_async(j);
- if (Flag(FTALKING)) {
- shf_fprintf(shl_out, "[%d]", j->job);
- for (p = j->proc_list; p; p = p->next)
- shf_fprintf(shl_out, " %d", p->pid);
- shf_putchar('\n', shl_out);
- shf_flush(shl_out);
- }
- } else
- rv = j_waitj(j, JW_NONE, "jw:last proc");
- }
-
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
-
- return rv;
-}
-
-/* start the last job: only used for `command` jobs */
-void
-startlast()
-{
-#ifdef JOB_SIGS
- sigset_t omask;
-
- sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-#endif /* JOB_SIGS */
-
- if (last_job) { /* no need to report error - waitlast() will do it */
- /* ensure it isn't removed by check_job() */
- last_job->flags |= JF_WAITING;
- j_startjob(last_job);
- }
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
-}
-
-/* wait for last job: only used for `command` jobs */
-int
-waitlast()
-{
- int rv;
- Job *j;
-#ifdef JOB_SIGS
- sigset_t omask;
-
- sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-#endif /* JOB_SIGS */
-
- j = last_job;
- if (!j || !(j->flags & JF_STARTED)) {
- if (!j)
- warningf(TRUE, "waitlast: no last job");
- else
- internal_errorf(0, "waitlast: not started");
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
- return 125; /* not so arbitrary, non-zero value */
- }
-
- rv = j_waitj(j, JW_NONE, "jw:waitlast");
-
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
-
- return rv;
-}
-
-/* wait for child, interruptable. */
-int
-waitfor(cp, sigp)
- const char *cp;
- int *sigp;
-{
- int rv;
- Job *j;
- int ecode;
- int flags = JW_INTERRUPT|JW_ASYNCNOTIFY;
-#ifdef JOB_SIGS
- sigset_t omask;
-
- sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-#endif /* JOB_SIGS */
-
- *sigp = 0;
-
- if (cp == (char *) 0) {
- /* wait for an unspecified job - always returns 0, so
- * don't have to worry about exited/signaled jobs
- */
- for (j = job_list; j; j = j->next)
- /* at&t ksh will wait for stopped jobs - we don't */
- if (j->ppid == procpid && j->state == PRUNNING)
- break;
- if (!j) {
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
- return -1;
- }
- } else if ((j = j_lookup(cp, &ecode))) {
- /* don't report normal job completion */
- flags &= ~JW_ASYNCNOTIFY;
- if (j->ppid != procpid) {
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
- return -1;
- }
- } else {
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
- if (ecode == JL_NOSUCH)
- return -1;
- bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
- }
-
- /* at&t ksh will wait for stopped jobs - we don't */
- rv = j_waitj(j, flags, "jw:waitfor");
-
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
-
- if (rv < 0) /* we were interrupted */
- *sigp = 128 + -rv;
-
- return rv;
-}
-
-/* kill (built-in) a job */
-int
-j_kill(cp, sig)
- const char *cp;
- int sig;
-{
- Job *j;
- Proc *p;
- int rv = 0;
- int ecode;
-#ifdef JOB_SIGS
- sigset_t omask;
-
- sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-#endif /* JOB_SIGS */
-
- if ((j = j_lookup(cp, &ecode)) == (Job *) 0) {
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
- bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
- return 1;
- }
-
- if (j->pgrp == 0) { /* started when !Flag(FMONITOR) */
- for (p=j->proc_list; p != (Proc *) 0; p = p->next)
- if (kill(p->pid, sig) < 0) {
- bi_errorf("%s: %s", cp, strerror(errno));
- rv = 1;
- }
- } else {
-#ifdef JOBS
- if (j->state == PSTOPPED && (sig == SIGTERM || sig == SIGHUP))
- (void) killpg(j->pgrp, SIGCONT);
-#endif /* JOBS */
- if (killpg(j->pgrp, sig) < 0) {
- bi_errorf("%s: %s", cp, strerror(errno));
- rv = 1;
- }
- }
-
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
-
- return rv;
-}
-
-#ifdef JOBS
-/* fg and bg built-ins: called only if Flag(FMONITOR) set */
-int
-j_resume(cp, bg)
- const char *cp;
- int bg;
-{
- Job *j;
- Proc *p;
- int ecode;
- int running;
- int rv = 0;
- sigset_t omask;
-
- sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-
- if ((j = j_lookup(cp, &ecode)) == (Job *) 0) {
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
- bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
- return 1;
- }
-
- if (j->pgrp == 0) {
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
- bi_errorf("job not job-controlled");
- return 1;
- }
-
- if (bg)
- shprintf("[%d] ", j->job);
-
- running = 0;
- for (p = j->proc_list; p != (Proc *) 0; p = p->next) {
- if (p->state == PSTOPPED) {
- p->state = PRUNNING;
- WSTATUS(p->status) = 0;
- running = 1;
- }
- shprintf("%s%s", p->command, p->next ? "| " : null);
- }
- shprintf(newline);
- shf_flush(shl_stdout);
- if (running)
- j->state = PRUNNING;
-
- put_job(j, PJ_PAST_STOPPED);
- if (bg)
- j_set_async(j);
- else {
-# ifdef TTY_PGRP
- /* attach tty to job */
- if (j->state == PRUNNING) {
- if (ttypgrp_ok && (j->flags & JF_SAVEDTTY)) {
- set_tty(tty_fd, &j->ttystate, TF_NONE);
- }
- if (ttypgrp_ok && tcsetpgrp(tty_fd, j->pgrp) < 0) {
- if (j->flags & JF_SAVEDTTY)
- set_tty(tty_fd, &tty_state, TF_NONE);
- sigprocmask(SIG_SETMASK, &omask,
- (sigset_t *) 0);
- bi_errorf("1st tcsetpgrp(%d, %d) failed: %s",
- tty_fd, (int) j->pgrp, strerror(errno));
- return 1;
- }
- }
-# endif /* TTY_PGRP */
- j->flags |= JF_FG;
- j->flags &= ~JF_KNOWN;
- if (j == async_job)
- async_job = (Job *) 0;
- }
-
- if (j->state == PRUNNING && killpg(j->pgrp, SIGCONT) < 0) {
- int err = errno;
-
- if (!bg) {
- j->flags &= ~JF_FG;
-# ifdef TTY_PGRP
- if (ttypgrp_ok && (j->flags & JF_SAVEDTTY))
- set_tty(tty_fd, &tty_state, TF_NONE);
- if (ttypgrp_ok && tcsetpgrp(tty_fd, our_pgrp) < 0) {
- warningf(TRUE,
- "fg: 2nd tcsetpgrp(%d, %d) failed: %s",
- tty_fd, (int) our_pgrp,
- strerror(errno));
- }
-# endif /* TTY_PGRP */
- }
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
- bi_errorf("cannot continue job %s: %s",
- cp, strerror(err));
- return 1;
- }
- if (!bg) {
-# ifdef TTY_PGRP
- if (ttypgrp_ok) {
- j->flags &= ~JF_SAVEDTTY;
- }
-# endif /* TTY_PGRP */
- rv = j_waitj(j, JW_NONE, "jw:resume");
- }
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
- return rv;
-}
-#endif /* JOBS */
-
-/* are there any running or stopped jobs ? */
-int
-j_stopped_running()
-{
- Job *j;
- int which = 0;
-
- for (j = job_list; j != (Job *) 0; j = j->next) {
-#ifdef JOBS
- if (j->ppid == procpid && j->state == PSTOPPED)
- which |= 1;
-#endif /* JOBS */
- if (Flag(FLOGIN) && !Flag(FNOHUP) && procpid == kshpid
- && j->ppid == procpid && j->state == PRUNNING)
- which |= 2;
- }
- if (which) {
- shellf("You have %s%s%s jobs\n",
- which & 1 ? "stopped" : "",
- which == 3 ? " and " : "",
- which & 2 ? "running" : "");
- return 1;
- }
-
- return 0;
-}
-
-/* list jobs for jobs built-in */
-int
-j_jobs(cp, slp, nflag)
- const char *cp;
- int slp; /* 0: short, 1: long, 2: pgrp */
- int nflag;
-{
- Job *j, *tmp;
- int how;
- int zflag = 0;
-#ifdef JOB_SIGS
- sigset_t omask;
-
- sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-#endif /* JOB_SIGS */
-
- if (nflag < 0) { /* kludge: print zombies */
- nflag = 0;
- zflag = 1;
- }
- if (cp) {
- int ecode;
-
- if ((j = j_lookup(cp, &ecode)) == (Job *) 0) {
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
- bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
- return 1;
- }
- } else
- j = job_list;
- how = slp == 0 ? JP_MEDIUM : (slp == 1 ? JP_LONG : JP_PGRP);
- for (; j; j = j->next) {
- if ((!(j->flags & JF_ZOMBIE) || zflag)
- && (!nflag || (j->flags & JF_CHANGED)))
- {
- j_print(j, how, shl_stdout);
- if (j->state == PEXITED || j->state == PSIGNALLED)
- j->flags |= JF_REMOVE;
- }
- if (cp)
- break;
- }
- /* Remove jobs after printing so there won't be multiple + or - jobs */
- for (j = job_list; j; j = tmp) {
- tmp = j->next;
- if (j->flags & JF_REMOVE)
- remove_job(j, "jobs");
- }
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
- return 0;
-}
-
-/* list jobs for top-level notification */
-void
-j_notify()
-{
- Job *j, *tmp;
-#ifdef JOB_SIGS
- sigset_t omask;
-
- sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-#endif /* JOB_SIGS */
- for (j = job_list; j; j = j->next) {
-#ifdef JOBS
- if (Flag(FMONITOR) && (j->flags & JF_CHANGED))
- j_print(j, JP_MEDIUM, shl_out);
-#endif /* JOBS */
- /* Remove job after doing reports so there aren't
- * multiple +/- jobs.
- */
- if (j->state == PEXITED || j->state == PSIGNALLED)
- j->flags |= JF_REMOVE;
- }
- for (j = job_list; j; j = tmp) {
- tmp = j->next;
- if (j->flags & JF_REMOVE)
- remove_job(j, "notify");
- }
- shf_flush(shl_out);
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
-}
-
-/* Return pid of last process in last asynchornous job */
-pid_t
-j_async()
-{
-#ifdef JOB_SIGS
- sigset_t omask;
-
- sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-#endif /* JOB_SIGS */
-
- if (async_job)
- async_job->flags |= JF_KNOWN;
-
-#ifdef JOB_SIGS
- sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-#endif /* JOB_SIGS */
-
- return async_pid;
-}
-
-/* Make j the last async process
- *
- * If jobs are compiled in then this routine expects sigchld to be blocked.
- */
-static void
-j_set_async(j)
- Job *j;
-{
- Job *jl, *oldest;
-
- if (async_job && (async_job->flags & (JF_KNOWN|JF_ZOMBIE)) == JF_ZOMBIE)
- remove_job(async_job, "async");
- if (!(j->flags & JF_STARTED)) {
- internal_errorf(0, "j_async: job not started");
- return;
- }
- async_job = j;
- async_pid = j->last_proc->pid;
- while (nzombie > child_max) {
- oldest = (Job *) 0;
- for (jl = job_list; jl; jl = jl->next)
- if (jl != async_job && (jl->flags & JF_ZOMBIE)
- && (!oldest || jl->age < oldest->age))
- oldest = jl;
- if (!oldest) {
- /* XXX debugging */
- if (!(async_job->flags & JF_ZOMBIE) || nzombie != 1) {
- internal_errorf(0, "j_async: bad nzombie (%d)", nzombie);
- nzombie = 0;
- }
- break;
- }
- remove_job(oldest, "zombie");
- }
-}
-
-/* Start a job: set STARTED, check for held signals and set j->last_proc
- *
- * If jobs are compiled in then this routine expects sigchld to be blocked.
- */
-static void
-j_startjob(j)
- Job *j;
-{
- Proc *p;
-
- j->flags |= JF_STARTED;
- for (p = j->proc_list; p->next; p = p->next)
- ;
- j->last_proc = p;
-
-#ifdef NEED_PGRP_SYNC
- if (j_sync_open) {
- j_sync_open = 0;
- closepipe(j_sync_pipe);
- }
-#endif /* NEED_PGRP_SYNC */
-#ifdef JOB_SIGS
- if (held_sigchld) {
- held_sigchld = 0;
- /* Don't call j_sigchld() as it may remove job... */
- kill(procpid, SIGCHLD);
- }
-#endif /* JOB_SIGS */
-}
-
-/*
- * wait for job to complete or change state
- *
- * If jobs are compiled in then this routine expects sigchld to be blocked.
- */
-static int
-j_waitj(j, flags, where)
- Job *j;
- int flags; /* see JW_* */
- const char *where;
-{
- int rv;
-
- /*
- * No auto-notify on the job we are waiting on.
- */
- j->flags |= JF_WAITING;
- if (flags & JW_ASYNCNOTIFY)
- j->flags |= JF_W_ASYNCNOTIFY;
-
- if (!Flag(FMONITOR))
- flags |= JW_STOPPEDWAIT;
-
- while ((volatile int) j->state == PRUNNING
- || ((flags & JW_STOPPEDWAIT)
- && (volatile int) j->state == PSTOPPED))
- {
-#ifdef JOB_SIGS
- sigsuspend(&sm_default);
-#else /* JOB_SIGS */
- j_sigchld(SIGCHLD);
-#endif /* JOB_SIGS */
- if (fatal_trap) {
- int oldf = j->flags & (JF_WAITING|JF_W_ASYNCNOTIFY);
- j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY);
- runtraps(TF_FATAL);
- j->flags |= oldf; /* not reached... */
- }
- if ((flags & JW_INTERRUPT) && (rv = trap_pending())) {
- j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY);
- return -rv;
- }
- }
- j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY);
-
- if (j->flags & JF_FG) {
- WAIT_T status;
-
- j->flags &= ~JF_FG;
-#ifdef TTY_PGRP
- if (Flag(FMONITOR) && ttypgrp_ok && j->pgrp) {
- if (tcsetpgrp(tty_fd, our_pgrp) < 0) {
- warningf(TRUE,
- "j_waitj: tcsetpgrp(%d, %d) failed: %s",
- tty_fd, (int) our_pgrp,
- strerror(errno));
- }
- if (j->state == PSTOPPED) {
- j->flags |= JF_SAVEDTTY;
- get_tty(tty_fd, &j->ttystate);
- }
- }
-#endif /* TTY_PGRP */
- if (tty_fd >= 0) {
- /* Only restore tty settings if job was originally
- * started in the foreground. Problems can be
- * caused by things like `more foobar &' which will
- * typically get and save the shell's vi/emacs tty
- * settings before setting up the tty for itself;
- * when more exits, it restores the `original'
- * settings, and things go down hill from there...
- */
- if (j->state == PEXITED && j->status == 0
- && (j->flags & JF_USETTYMODE))
- {
- get_tty(tty_fd, &tty_state);
- } else {
- set_tty(tty_fd, &tty_state,
- (j->state == PEXITED) ? 0 : TF_MIPSKLUDGE);
- /* Don't use tty mode if job is stopped and
- * later restarted and exits. Consider
- * the sequence:
- * vi foo (stopped)
- * ...
- * stty something
- * ...
- * fg (vi; ZZ)
- * mode should be that of the stty, not what
- * was before the vi started.
- */
- if (j->state == PSTOPPED)
- j->flags &= ~JF_USETTYMODE;
- }
- }
-#ifdef JOBS
- /* If it looks like user hit ^C to kill a job, pretend we got
- * one too to break out of for loops, etc. (at&t ksh does this
- * even when not monitoring, but this doesn't make sense since
- * a tty generated ^C goes to the whole process group)
- */
- status = j->last_proc->status;
- if (Flag(FMONITOR) && j->state == PSIGNALLED
- && WIFSIGNALED(status)
- && (sigtraps[WTERMSIG(status)].flags & TF_TTY_INTR))
- trapsig(WTERMSIG(status));
-#endif /* JOBS */
- }
-
- j_usrtime = j->usrtime;
- j_systime = j->systime;
- rv = j->status;
-
- if (!(flags & JW_ASYNCNOTIFY)
- && (!Flag(FMONITOR) || j->state != PSTOPPED))
- {
- j_print(j, JP_SHORT, shl_out);
- shf_flush(shl_out);
- }
- if (j->state != PSTOPPED
- && (!Flag(FMONITOR) || !(flags & JW_ASYNCNOTIFY)))
- remove_job(j, where);
-
- return rv;
-}
-
-/* SIGCHLD handler to reap children and update job states
- *
- * If jobs are compiled in then this routine expects sigchld to be blocked.
- */
-static RETSIGTYPE
-j_sigchld(sig)
- int sig;
-{
- int errno_ = errno;
- Job *j;
- Proc UNINITIALIZED(*p);
- int pid;
- WAIT_T status;
- struct tms t0, t1;
-
-#ifdef JOB_SIGS
- /* Don't wait for any processes if a job is partially started.
- * This is so we don't do away with the process group leader
- * before all the processes in a pipe line are started (so the
- * setpgid() won't fail)
- */
- for (j = job_list; j; j = j->next)
- if (j->ppid == procpid && !(j->flags & JF_STARTED)) {
- held_sigchld = 1;
- return RETSIGVAL;
- }
-#endif /* JOB_SIGS */
-
- ksh_times(&t0);
- do {
-#ifdef JOB_SIGS
- pid = ksh_waitpid(-1, &status, (WNOHANG|WUNTRACED));
-#else /* JOB_SIGS */
- pid = wait(&status);
-#endif /* JOB_SIGS */
-
- if (pid <= 0) /* return if would block (0) ... */
- break; /* ... or no children or interrupted (-1) */
-
- ksh_times(&t1);
-
- /* find job and process structures for this pid */
- for (j = job_list; j != (Job *) 0; j = j->next)
- for (p = j->proc_list; p != (Proc *) 0; p = p->next)
- if (p->pid == pid)
- goto found;
-found:
- if (j == (Job *) 0) {
- /* Can occur if process has kids, then execs shell
- warningf(TRUE, "bad process waited for (pid = %d)",
- pid);
- */
- t0 = t1;
- continue;
- }
-
- j->usrtime += t1.tms_cutime - t0.tms_cutime;
- j->systime += t1.tms_cstime - t0.tms_cstime;
- t0 = t1;
- p->status = status;
-#ifdef JOBS
- if (WIFSTOPPED(status))
- p->state = PSTOPPED;
- else
-#endif /* JOBS */
- if (WIFSIGNALED(status))
- p->state = PSIGNALLED;
- else
- p->state = PEXITED;
-
- check_job(j); /* check to see if entire job is done */
- }
-#ifdef JOB_SIGS
- while (1);
-#else /* JOB_SIGS */
- while (0);
-#endif /* JOB_SIGS */
-
- errno = errno_;
-
- return RETSIGVAL;
-}
-
-/*
- * Called only when a process in j has exited/stopped (ie, called only
- * from j_sigchld()). If no processes are running, the job status
- * and state are updated, asynchronous job notification is done and,
- * if unneeded, the job is removed.
- *
- * If jobs are compiled in then this routine expects sigchld to be blocked.
- */
-static void
-check_job(j)
- Job *j;
-{
- int jstate;
- Proc *p;
-
- /* XXX debugging (nasty - interrupt routine using shl_out) */
- if (!(j->flags & JF_STARTED)) {
- internal_errorf(0, "check_job: job started (flags 0x%x)",
- j->flags);
- return;
- }
-
- jstate = PRUNNING;
- for (p=j->proc_list; p != (Proc *) 0; p = p->next) {
- if (p->state == PRUNNING)
- return; /* some processes still running */
- if (p->state > jstate)
- jstate = p->state;
- }
- j->state = jstate;
-
- switch (j->last_proc->state) {
- case PEXITED:
- j->status = WEXITSTATUS(j->last_proc->status);
- break;
- case PSIGNALLED:
- j->status = 128 + WTERMSIG(j->last_proc->status);
- break;
- default:
- j->status = 0;
- break;
- }
-
-#ifdef KSH
- /* Note when co-process dies: can't be done in j_wait() nor
- * remove_job() since neither may be called for non-interactive
- * shells.
- */
- if (j->state == PEXITED || j->state == PSIGNALLED) {
- /* No need to keep co-process input any more
- * (at leasst, this is what ksh93d thinks)
- */
- if (coproc.job == j) {
- coproc.job = (void *) 0;
- /* XXX would be nice to get the closes out of here
- * so they aren't done in the signal handler.
- * Would mean a check in coproc_getfd() to
- * do "if job == 0 && write >= 0, close write".
- */
- coproc_write_close(coproc.write);
- }
- /* Do we need to keep the output? */
- if (j->coproc_id && j->coproc_id == coproc.id
- && --coproc.njobs == 0)
- coproc_readw_close(coproc.read);
- }
-#endif /* KSH */
-
- j->flags |= JF_CHANGED;
-#ifdef JOBS
- if (Flag(FMONITOR) && !(j->flags & JF_XXCOM)) {
- /* Only put stopped jobs at the front to avoid confusing
- * the user (don't want finished jobs effecting %+ or %-)
- */
- if (j->state == PSTOPPED)
- put_job(j, PJ_ON_FRONT);
- if (Flag(FNOTIFY)
- && (j->flags & (JF_WAITING|JF_W_ASYNCNOTIFY)) != JF_WAITING)
- {
- /* Look for the real file descriptor 2 */
- {
- struct env *ep;
- int fd = 2;
-
- for (ep = e; ep; ep = ep->oenv)
- if (ep->savefd && ep->savefd[2])
- fd = ep->savefd[2];
- shf_reopen(fd, SHF_WR, shl_j);
- }
- /* Can't call j_notify() as it removes jobs. The job
- * must stay in the job list as j_waitj() may be
- * running with this job.
- */
- j_print(j, JP_MEDIUM, shl_j);
- shf_flush(shl_j);
- if (!(j->flags & JF_WAITING) && j->state != PSTOPPED)
- remove_job(j, "notify");
- }
- }
-#endif /* JOBS */
- if (!Flag(FMONITOR) && !(j->flags & (JF_WAITING|JF_FG))
- && j->state != PSTOPPED)
- {
- if (j == async_job || (j->flags & JF_KNOWN)) {
- j->flags |= JF_ZOMBIE;
- j->job = -1;
- nzombie++;
- } else
- remove_job(j, "checkjob");
- }
-}
-
-/*
- * Print job status in either short, medium or long format.
- *
- * If jobs are compiled in then this routine expects sigchld to be blocked.
- */
-static void
-j_print(j, how, shf)
- Job *j;
- int how;
- struct shf *shf;
-{
- Proc *p;
- int state;
- WAIT_T status;
- int coredumped;
- char jobchar = ' ';
- char buf[64];
- const char *filler;
- int output = 0;
-
- if (how == JP_PGRP) {
- /* POSIX doesn't say what to do it there is no process
- * group leader (ie, !FMONITOR). We arbitrarily return
- * last pid (which is what $! returns).
- */
- shf_fprintf(shf, "%d\n", j->pgrp ? j->pgrp
- : (j->last_proc ? j->last_proc->pid : 0));
- return;
- }
- j->flags &= ~JF_CHANGED;
- filler = j->job > 10 ? "\n " : "\n ";
- if (j == job_list)
- jobchar = '+';
- else if (j == job_list->next)
- jobchar = '-';
-
- for (p = j->proc_list; p != (Proc *) 0;) {
- coredumped = 0;
- switch (p->state) {
- case PRUNNING:
- strcpy(buf, "Running");
- break;
- case PSTOPPED:
- strcpy(buf, sigtraps[WSTOPSIG(p->status)].mess);
- break;
- case PEXITED:
- if (how == JP_SHORT)
- buf[0] = '\0';
- else if (WEXITSTATUS(p->status) == 0)
- strcpy(buf, "Done");
- else
- shf_snprintf(buf, sizeof(buf), "Done (%d)",
- WEXITSTATUS(p->status));
- break;
- case PSIGNALLED:
- if (WIFCORED(p->status))
- coredumped = 1;
- /* kludge for not reporting `normal termination signals'
- * (ie, SIGINT, SIGPIPE)
- */
- if (how == JP_SHORT && !coredumped
- && (WTERMSIG(p->status) == SIGINT
- || WTERMSIG(p->status) == SIGPIPE)) {
- buf[0] = '\0';
- } else
- strcpy(buf, sigtraps[WTERMSIG(p->status)].mess);
- break;
- }
-
- if (how != JP_SHORT)
- if (p == j->proc_list)
- shf_fprintf(shf, "[%d] %c ", j->job, jobchar);
- else
- shf_fprintf(shf, "%s", filler);
-
- if (how == JP_LONG)
- shf_fprintf(shf, "%5d ", p->pid);
-
- if (how == JP_SHORT) {
- if (buf[0]) {
- output = 1;
- shf_fprintf(shf, "%s%s ",
- buf, coredumped ? " (core dumped)" : null);
- }
- } else {
- output = 1;
- shf_fprintf(shf, "%-20s %s%s%s", buf, p->command,
- p->next ? "|" : null,
- coredumped ? " (core dumped)" : null);
- }
-
- state = p->state;
- status = p->status;
- p = p->next;
- while (p && p->state == state
- && WSTATUS(p->status) == WSTATUS(status))
- {
- if (how == JP_LONG)
- shf_fprintf(shf, "%s%5d %-20s %s%s", filler, p->pid,
- space, p->command, p->next ? "|" : null);
- else if (how == JP_MEDIUM)
- shf_fprintf(shf, " %s%s", p->command,
- p->next ? "|" : null);
- p = p->next;
- }
- }
- if (output)
- shf_fprintf(shf, newline);
-}
-
-/* Convert % sequence to job
- *
- * If jobs are compiled in then this routine expects sigchld to be blocked.
- */
-static Job *
-j_lookup(cp, ecodep)
- const char *cp;
- int *ecodep;
-{
- Job *j, *last_match;
- Proc *p;
- int len, job = 0;
-
- if (digit(*cp)) {
- job = atoi(cp);
- /* Look for last_proc->pid (what $! returns) first... */
- for (j = job_list; j != (Job *) 0; j = j->next)
- if (j->last_proc && j->last_proc->pid == job)
- return j;
- /* ...then look for process group (this is non-POSIX),
- * but should not break anything (so FPOSIX isn't used).
- */
- for (j = job_list; j != (Job *) 0; j = j->next)
- if (j->pgrp && j->pgrp == job)
- return j;
- if (ecodep)
- *ecodep = JL_NOSUCH;
- return (Job *) 0;
- }
- if (*cp != '%') {
- if (ecodep)
- *ecodep = JL_INVALID;
- return (Job *) 0;
- }
- switch (*++cp) {
- case '\0': /* non-standard */
- case '+':
- case '%':
- if (job_list != (Job *) 0)
- return job_list;
- break;
-
- case '-':
- if (job_list != (Job *) 0 && job_list->next)
- return job_list->next;
- break;
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- job = atoi(cp);
- for (j = job_list; j != (Job *) 0; j = j->next)
- if (j->job == job)
- return j;
- break;
-
- case '?': /* %?string */
- last_match = (Job *) 0;
- for (j = job_list; j != (Job *) 0; j = j->next)
- for (p = j->proc_list; p != (Proc *) 0; p = p->next)
- if (strstr(p->command, cp+1) != (char *) 0) {
- if (last_match) {
- if (ecodep)
- *ecodep = JL_AMBIG;
- return (Job *) 0;
- }
- last_match = j;
- }
- if (last_match)
- return last_match;
- break;
-
- default: /* %string */
- len = strlen(cp);
- last_match = (Job *) 0;
- for (j = job_list; j != (Job *) 0; j = j->next)
- if (strncmp(cp, j->proc_list->command, len) == 0) {
- if (last_match) {
- if (ecodep)
- *ecodep = JL_AMBIG;
- return (Job *) 0;
- }
- last_match = j;
- }
- if (last_match)
- return last_match;
- break;
- }
- if (ecodep)
- *ecodep = JL_NOSUCH;
- return (Job *) 0;
-}
-
-static Job *free_jobs;
-static Proc *free_procs;
-
-/* allocate a new job and fill in the job number.
- *
- * If jobs are compiled in then this routine expects sigchld to be blocked.
- */
-static Job *
-new_job()
-{
- int i;
- Job *newj, *j;
-
- if (free_jobs != (Job *) 0) {
- newj = free_jobs;
- free_jobs = free_jobs->next;
- } else
- newj = (Job *) alloc(sizeof(Job), APERM);
-
- /* brute force method */
- for (i = 1; ; i++) {
- for (j = job_list; j && j->job != i; j = j->next)
- ;
- if (j == (Job *) 0)
- break;
- }
- newj->job = i;
-
- return newj;
-}
-
-/* Allocate new process strut
- *
- * If jobs are compiled in then this routine expects sigchld to be blocked.
- */
-static Proc *
-new_proc()
-{
- Proc *p;
-
- if (free_procs != (Proc *) 0) {
- p = free_procs;
- free_procs = free_procs->next;
- } else
- p = (Proc *) alloc(sizeof(Proc), APERM);
-
- return p;
-}
-
-/* Take job out of job_list and put old structures into free list.
- * Keeps nzombies, last_job and async_job up to date.
- *
- * If jobs are compiled in then this routine expects sigchld to be blocked.
- */
-static void
-remove_job(j, where)
- Job *j;
- const char *where;
-{
- Proc *p, *tmp;
- Job **prev, *curr;
-
- prev = &job_list;
- curr = *prev;
- for (; curr != (Job *) 0 && curr != j; prev = &curr->next, curr = *prev)
- ;
- if (curr != j) {
- internal_errorf(0, "remove_job: job not found (%s)", where);
- return;
- }
- *prev = curr->next;
-
- /* free up proc structures */
- for (p = j->proc_list; p != (Proc *) 0; ) {
- tmp = p;
- p = p->next;
- tmp->next = free_procs;
- free_procs = tmp;
- }
-
- if ((j->flags & JF_ZOMBIE) && j->ppid == procpid)
- --nzombie;
- j->next = free_jobs;
- free_jobs = j;
-
- if (j == last_job)
- last_job = (Job *) 0;
- if (j == async_job)
- async_job = (Job *) 0;
-}
-
-/* put j in a particular location (taking it out job_list if it is there
- * already)
- *
- * If jobs are compiled in then this routine expects sigchld to be blocked.
- */
-static void
-put_job(j, where)
- Job *j;
- int where;
-{
- Job **prev, *curr;
-
- /* Remove job from list (if there) */
- prev = &job_list;
- curr = job_list;
- for (; curr && curr != j; prev = &curr->next, curr = *prev)
- ;
- if (curr == j)
- *prev = curr->next;
-
- switch (where) {
- case PJ_ON_FRONT:
- j->next = job_list;
- job_list = j;
- break;
-
- case PJ_PAST_STOPPED:
- prev = &job_list;
- curr = job_list;
- for (; curr && curr->state == PSTOPPED; prev = &curr->next,
- curr = *prev)
- ;
- j->next = curr;
- *prev = j;
- break;
- }
-}
-
-/* nuke a job (called when unable to start full job).
- *
- * If jobs are compiled in then this routine expects sigchld to be blocked.
- */
-static void
-kill_job(j)
- Job *j;
-{
- Proc *p;
-
- for (p = j->proc_list; p != (Proc *) 0; p = p->next)
- if (p->pid != 0)
- (void) kill(p->pid, SIGKILL);
-}
-
-/* put a more useful name on a process than snptreef does (in certain cases) */
-static void
-fill_command(c, len, t)
- char *c;
- int len;
- struct op *t;
-{
- int alen;
- char **ap;
-
- if (t->type == TEXEC || t->type == TCOM) {
- if (t->type == TCOM)
- ap = eval(t->args, DOBLANK|DONTRUNCOMMAND);
- else
- ap = t->args;
- --len; /* save room for the null */
- while (len > 0 && *ap != (char *) 0) {
- alen = strlen(*ap);
- if (alen > len)
- alen = len;
- memcpy(c, *ap, alen);
- c += alen;
- len -= alen;
- if (len > 0) {
- *c++ = ' '; len--;
- }
- ap++;
- }
- *c = '\0';
- } else
- snptreef(c, len, "%T", t);
-}
diff --git a/bin/pdksh/ksh.1tbl b/bin/pdksh/ksh.1tbl
deleted file mode 100644
index 651f25fd765..00000000000
--- a/bin/pdksh/ksh.1tbl
+++ /dev/null
@@ -1,3298 +0,0 @@
-'\" t
-.\" $OpenBSD: ksh.1tbl,v 1.3 1996/11/21 08:18:19 downsj Exp $
-.\"{{{}}}
-.\"{{{ Notes about man page
-.\" - use the pseudo-macros .sh( and .sh) to begin and end sh-specific
-.\" text and .ksh( and .ksh) for ksh specific text.
-.\" - put i.e., e.g. and etc. in italics
-.\"}}}
-.\"{{{ To do
-.\" todo: Things not covered that should be:
-.\" - distinguish (POSIX) special built-in's, (POSIX) regular built-in's,
-.\" and sh/ksh weirdo built-in's (put S,R,X superscripts after command
-.\" name in built-in commands section?)
-.\" - need to be consistent about notation for `See section-name', `
-.\" See description of foobar command', `See section section-name', etc.
-.\" - need to use the term `external command' meaning `a command that is
-.\" executed using execve(2)' (as opposed to a built-in command or
-.\" function) for more clear description.
-.\"}}}
-.\"{{{ Title
-.TH KSH 1 "August 19, 1996" "" "User commands"
-.\"}}}
-.\"{{{ Name
-.SH NAME
-ksh \- Public domain Korn shell
-.\"}}}
-.\"{{{ Synopsis
-.SH SYNOPSIS
-.ad l
-\fBksh\fP
-[\fB\(+-abCefhikmnprsuvxX\fP] [\fB\(+-o\fP \fIoption\fP] [ [ \fB\-c\fP \fIcommand-string\fP [\fIcommand-name\fP] | \fB\-s\fP | \fIfile\fP ] [\fIargument\fP ...] ]
-.ad b
-.\"}}}
-.\"{{{ Description
-.SH DESCRIPTION
-\fBksh\fP is a command interpreter that is intended for both
-interactive and shell script use. Its command language is a superset
-of the \fIsh\fP(1) shell language.
-.\"{{{ Shell Startup
-.SS "Shell Startup"
-The following options can be specified only on the command line:
-.IP "\fB\-c\fP \fIcommand-string\fP"
-the shell executes the command(s) contained in \fIcommand-string\fP
-.IP \fB\-i\fP
-interactive mode \(em see below
-.IP \fB\-l\fP
-login shell \(em see below
-interactive mode \(em see below
-.IP \fB\-s\fP
-the shell reads commands from standard input; all non-option arguments
-are positional parameters
-.IP \fB\-r\fP
-restricted mode \(em see below
-.PP
-In addition to the above, the options described in the \fBset\fP built-in
-command can also be used on the command line.
-.PP
-If neither the \fB\-c\fP nor the \fB\-s\fP options are specified, the
-first non-option argument specifies the name of a file the shell reads
-commands from; if there are no non-option arguments, the shell reads
-commands from standard input.
-The name of the shell (\fIi.e.\fP, the contents of the \fB$0\fP) parameter
-is determined as follows: if the \fB\-c\fP option is used and there is
-a non-option argument, it is used as the name; if commands are being
-read from a file, the file is used as the name; otherwise the name
-the shell was called with (\fIi.e.\fP, argv[0]) is used.
-.PP
-A shell is \fBinteractive\fP if the \fB\-i\fP option is used or
-if both standard input and standard error are attached to a tty.
-An interactive shell has job control enabled (if available),
-ignores the INT, QUIT and TERM signals, and prints prompts before
-reading input (see \fBPS1\fP and \fBPS2\fP parameters).
-For non-interactive shells, the \fBtrackall\fP option is on by default
-(see \fBset\fP command below).
-.PP
-A shell is \fBrestricted\fP if the \fB\-r\fP option is used or if either
-the basename of the name the shell is invoked with or the \fBSHELL\fP
-parameter match the pattern *r*sh (\fIe.g.\fP, rsh, rksh, rpdksh, \fIetc.\fP).
-The following restrictions come into effect after the shell processes
-any profile and \fB$ENV\fP files:
-.nr P2 \n(PD
-.nr PD 0
-.IP \ \ \(bu
-the \fBcd\fP command is disabled
-.IP \ \ \(bu
-the \fBSHELL\fP, \fBENV\fP and \fBPATH\fP parameters can't be changed
-.IP \ \ \(bu
-command names can't be specified with absolute or relative paths
-.IP \ \ \(bu
-the \fB\-p\fP option of the \fBcommand\fP built-in can't be used
-.IP \ \ \(bu
-redirections that create files can't be used (\fIi.e.\fP, \fB>\fP,
-\fB>|\fP, \fB>>\fP, \fB<>\fP)
-.nr PD \n(P2
-.PP
-A shell is \fBprivileged\fP if the \fB\-p\fP option is used or if
-the real user-id or group-id does not match the effective user-id
-or group-id (see \fIgetuid\fP(2), \fIgetgid\fP(2)).
-A privileged shell does not process $HOME/.profile nor the \fBENV\fP
-parameter (see below), instead the file /etc/suid_profile is processed.
-Clearing the privileged option causes the shell to set its effective
-user-id (group-id) to its real user-id (group-id).
-.PP
-If the basename of the name the shell is called with (\fIi.e.\fP, argv[0])
-starts with \fB\-\fP or if the \fB\-l\fP option is used, the shell is assumed
-to be a login shell and the shell reads and executes the contents of
-\fB/etc/profile\fP and \fB$HOME/.profile\fP if they exist and are readable.
-.PP
-If the \fBENV\fP parameter is set when the shell starts (or, in the
-case of login shells, after any profiles are processed), its value
-is subjected to parameter, command, arithmetic and tilde substitution and
-the resulting file (if any) is read and executed.
-If \fBENV\fP parameter is not set (and not null) and pdksh was compiled
-with the \fBDEFAULT_ENV\fP macro defined, the file named in that macro
-is included (after the above mentioned substitutions have been performed).
-.PP
-The exit status of the shell is 127 if the command file specified
-on the command line could not be opened, or non-zero if a fatal syntax
-error occurred during the execution of a script.
-In the absence of fatal errors, the exit status is that of the last
-command executed, or zero, if no command is executed.
-.\"}}}
-.\"{{{ Command Syntax
-.SS "Command Syntax"
-.\"{{{ words and tokens
-The shell begins parsing its input by breaking it into \fIword\fPs.
-Words, which are sequences of characters, are delimited by unquoted
-\fIwhite-space\fP characters (space, tab and newline) or \fImeta-characters\fP
-(\fB<\fP, \fB>\fP, \fB|\fP, \fB;\fP, \fB&\fP, \fB(\fP and \fB)\fP).
-Aside from delimiting words, spaces and tabs are ignored, while
-newlines usually delimit commands.
-The meta-characters are used in building the following tokens:
-\fB<\fP, \fB<&\fP, \fB<<\fP, \fB>\fP, \fB>&\fP, \fB>>\fP, \fIetc.\fP are
-used to specify redirections (see Input/Output Redirection below);
-\fB|\fP is used to create pipelines;
-\fB|&\fP is used to create co-processes (see Co-Processes below);
-\fB;\fP is used to separate commands;
-\fB&\fP is used to create asynchronous pipelines;
-\fB&&\fP and \fB||\fP are used to specify conditional execution;
-\fB;;\fP is used in \fBcase\fP statements;
-\fB((\fP .. \fB))\fP are used in arithmetic expressions;
-and lastly,
-\fB(\fP .. \fB)\fP are used to create subshells.
-.PP
-White-space and meta-characters can be quoted individually using
-backslash (\fB\e\fP), or in groups using double (\fB"\fP) or single (\fB'\fP)
-quotes.
-Note that the following characters are also treated specially by the shell and
-must be quoted if they are to represent themselves:
-\fB\e\fP, \fB"\fP, \fB'\fP, \fB#\fP, \fB$\fP, \fB`\fP, \fB~\fP, \fB{\fP,
-\fB}\fP, \fB*\fP, \fB?\fP and \fB[\fP.
-The first three of these are the above mentioned quoting characters
-(see Quoting below);
-\fB#\fP, if used at the beginning of a word, introduces a comment \(em everything
-after the \fB#\fP up to the nearest newline is ignored;
-\fB$\fP is used to introduce parameter, command and arithmetic substitutions
-(see Substitution below);
-\fB`\fP introduces an old-style command substitution
-(see Substitution below);
-\fB~\fP begins a directory expansion (see Tilde Expansion below);
-\fB{\fP and \fB}\fP delimit \fIcsh\fP(1) style alternations
-(see Brace Expansion below);
-and, finally, \fB*\fP, \fB?\fP and \fB[\fP are used in file name generation
-(see File Name Patterns below).
-.\"}}}
-.\"{{{ simple-command
-.PP
-As words and tokens are parsed, the shell builds commands, of which
-there are two basic types: \fIsimple-commands\fP, typically programs
-that are executed, and \fIcompound-commands\fP, such as \fBfor\fP and
-\fBif\fP statements, grouping constructs and function definitions.
-.PP
-A simple-command consists of some combination of parameter assignments (see
-Parameters below), input/output redirections (see Input/Output Redirections
-below), and command words; the only restriction is that parameter assignments
-come before any command words.
-The command words, if any, define the command that is to be executed and its
-arguments.
-The command may be a shell built-in command, a function or an \fIexternal
-command\fP, \fIi.e.\fP, a separate executable file that is located using the
-\fBPATH\fP parameter (see Command Execution below).
-Note that all command constructs have an \fIexit status\fP: for external
-commands, this is related to the status returned by \fIwait\fP(2) (if the
-command could not be found, the exit status is 127, if it could not be
-executed, the exit status is 126);
-the exit status of other command constructs (built-in commands, functions,
-compound-commands, pipelines, lists, \fIetc.\fP) are all well defined and are
-described where the construct is described.
-The exit status of a command consisting only of parameter assignments is that
-of the last command substitution performed during the parameter assignment
-or zero if there were no command substitutions.
-.\"}}}
-.\"{{{ pipeline
-.PP
-Commands can be chained together using the \fB|\fP token to
-form \fIpipelines\fP, in which the standard output of each command but
-the last is piped (see \fIpipe\fP(2)) to the standard input of the following
-command.
-The exit status of a pipeline is that of its last command.
-A pipeline may be prefixed by the \fB!\fP reserved word which
-causes the exit status of the pipeline to be logically
-complemented: if the original status was 0 the complemented status will
-be 1, and if the original status was not 0, then the complemented
-status will be 0.
-.\"}}}
-.\"{{{ lists
-.PP
-\fILists\fP of commands can be created by separating pipelines by
-any of the following tokens: \fB&&\fP, \fB||\fP, \fB&\fP, \fB|&\fP and \fB;\fP.
-The first two are for conditional execution: \fIcmd1\fP \fB&&\fP \fIcmd2\fP
-executes \fIcmd2\fP only if the exit status of \fIcmd1\fP is zero;
-\fB||\fP is the opposite \(em \fIcmd2\fP is executed only if the exit status
-of \fIcmd1\fP is non-zero.
-\fB&&\fP and \fB||\fP have equal precedence which is higher than that of
-\fB&\fP, \fB|&\fP and \fB;\fP, which also have equal precedence.
-The \fB&\fP token causes the preceding command to be executed asynchronously,
-that is, the shell starts the command, but does not wait for it to complete
-(the shell does keep track of the status of asynchronous commands \(em see
-Job Control below).
-When an asynchronous command is started when job control is disabled
-(\fIi.e.\fP, in most scripts), the command is started with signals INT
-and QUIT ignored and with input redirected from /dev/null
-(however, redirections specified in the asynchronous command have precedence).
-The \fB|&\fP operator starts a \fIco-process\fP which is special kind of
-asynchronous process (see Co-Processes below).
-Note that a command must follow the \fB&&\fP and \fB||\fP operators, while
-a command need not follow \fB&\fP, \fB|&\fP and \fB;\fP.
-The exit status of a list is that of the last command executed, with the
-exception of asynchronous lists, for which the exit status is 0.
-.\"}}}
-.\"{{{ compound-commands
-.PP
-Compound commands are created using the following reserved words \(em these
-words are only recognized if they are unquoted and if they are used as
-the first word of a command (\fIi.e.\fP, they can't be preceded by parameter
-assignments or redirections):
-.TS
-center;
-lfB lfB lfB lfB lfB .
-case else function then !
-do esac if time [[
-done fi in until {
-elif for select while }
-.TE
-\fBNote:\fP Some shells (but not this one) execute control structure commands
-in a subshell when one or more of their file descriptors are redirected, so
-any environment changes inside them may fail.
-To be portable, the \fBexec\fP statement should be used instead to redirect
-file descriptors before the control structure.
-.PP
-In the following compound command descriptions, command lists (denoted as
-\fIlist\fP) that are followed by reserved words must end with a
-semi-colon, a newline or a (syntactically correct) reserved word.
-For example,
-.RS
-\fB{ echo foo; echo bar; }\fP
-.br
-\fB{ echo foo; echo bar<newline>}\fP
-.br
-\fB{ { echo foo; echo bar; } }\fP
-.RE
-are all valid, but
-.RS
-\fB{ echo foo; echo bar }\fP
-.RE
-is not.
-.\"{{{ ( list )
-.IP "\fB(\fP \fIlist\fP \fB)\fP"
-Execute \fIlist\fP in a subshell. There is no implicit way to pass
-environment changes from a subshell back to its parent.
-.\"}}}
-.\"{{{ { list }
-.IP "\fB{\fP \fIlist\fP \fB}\fP"
-Compound construct; \fIlist\fP is executed, but not in a subshell.
-Note that \fB{\fP and \fB}\fP are reserved words, not meta-characters.
-.\"}}}
-.\"{{{ case word in [ [ ( ] pattern [ | pattern ] ... ) list ;; ] ... esac
-.IP "\fBcase\fP \fIword\fP \fBin\fP [ [\fB(\fP] \fIpattern\fP [\fB|\fP \fIpattern\fP] ... \fB)\fP \fIlist\fP \fB;;\fP ] ... \fBesac\fP"
-The \fBcase\fP statement attempts to match \fIword\fP against the specified
-\fIpattern\fPs; the \fIlist\fP associated with the first successfully matched
-pattern is executed. Patterns used in \fBcase\fP statements are the same as
-those used for file name patterns except that the restrictions regarding
-\fB\&.\fP and \fB/\fP are dropped. Note that any unquoted space before and
-after a pattern is stripped; any space with a pattern must be quoted. Both the
-word and the patterns are subject to parameter, command, and arithmetic
-substitution as well as tilde substitution.
-For historical reasons, open and close braces may be used instead
-of \fBin\fP and \fBesac\fP (\fIe.g.\fP, \fBcase $foo { *) echo bar; }\fP).
-The exit status of a \fBcase\fP statement is that of the executed \fIlist\fP;
-if no \fIlist\fP is executed, the exit status is zero.
-.\"}}}
-.\"{{{ for name [ in word ... term ] do list done
-.IP "\fBfor\fP \fIname\fP [ \fBin\fP \fIword\fP ... \fIterm\fP ] \fBdo\fP \fIlist\fP \fBdone\fP"
-where \fIterm\fP is either a newline or a \fB;\fP.
-For each \fIword\fP in the specified word list, the parameter \fIname\fP is
-set to the word and \fIlist\fP is executed. If \fBin\fP is not used to
-specify a word list, the positional parameters (\fB"$1"\fP, \fB"$2"\fP,
-\fIetc.\fP) are used instead.
-For historical reasons, open and close braces may be used instead
-of \fBdo\fP and \fBdone\fP (\fIe.g.\fP, \fBfor i; { echo $i; }\fP).
-The exit status of a \fBfor\fP statement is the last exit status
-of \fIlist\fP; if \fIlist\fP is never executed, the exit status is zero.
-.\"}}}
-.\"{{{ if list then list [ elif list then list ] ... [ else list ] fi
-.IP "\fBif\fP \fIlist\fP \fBthen\fP \fIlist\fP [\fBelif\fP \fIlist\fP \fBthen\fP \fIlist\fP] ... [\fBelse\fP \fIlist\fP] \fBfi\fP"
-If the exit status of the first \fIlist\fP is zero, the second \fIlist\fP
-is executed; otherwise the \fIlist\fP following the \fBelif\fP, if any, is
-executed with similar consequences. If all the lists following the \fBif\fP
-and \fBelif\fPs fail (\fIi.e.\fP, exit with non-zero status), the \fIlist\fP
-following the \fBelse\fP is executed.
-The exit status of an \fBif\fP statement is that
-of non-conditional \fIlist\fP that is executed; if no non-conditional
-\fIlist\fP is executed, the exit status is zero.
-.\"}}}
-.\"{{{ select name [ in word ... ] do list done
-.IP "\fBselect\fP \fIname\fP [ \fBin\fP \fIword\fP ... \fIterm\fP ] \fBdo\fP \fIlist\fP \fBdone\fP"
-where \fIterm\fP is either a newline or a \fB;\fP.
-The \fBselect\fP statement provides an automatic method of presenting
-the user with a menu and selecting from it.
-An enumerated list of the specified \fIwords\fP is printed on standard
-error, followed by a prompt (\fBPS3\fP, normally `\fB#? \fP').
-A number corresponding to one of the enumerated words is then read
-from standard input, \fIname\fP is set to the selected word (or is
-unset if the selection is not valid), \fBREPLY\fP
-is set to what was read (leading/trailing space is stripped),
-and \fIlist\fP is executed.
-If a blank line (\fIi.e.\fP, zero or more \fBIFS\fP characters) is entered,
-the menu is re-printed without executing \fIlist\fP.
-When \fIlist\fP completes, the enumerated list is printed if \fBREPLY\fP
-is null, the prompt is printed and so on.
-This process is continues until an end-of-file is read, an interrupt is
-received or a break statement is executed inside the loop.
-If \fBin\fP \fIword\fP \fB\&...\fP is omitted, the positional parameters
-are used (\fIi.e.\fP, \fB"$1"\fP, \fB"$2"\fP, \fIetc.\fP).
-For historical reasons, open and close braces may be used instead
-of \fBdo\fP and \fBdone\fP (\fIe.g.\fP, \fBselect i; { echo $i; }\fP).
-The exit status of a \fBselect\fP statement is zero if a break statement
-is used to exit the loop, non-zero otherwise.
-.\"}}}
-.\"{{{ until list do list done
-.IP "\fBuntil\fP \fIlist\fP \fBdo\fP \fIlist\fP \fBdone\fP"
-This works like \fBwhile\fP, except that the body is executed only while the
-exit status of the first \fIlist\fP is non-zero.
-.\"}}}
-.\"{{{ while list do list done
-.IP "\fBwhile\fP \fIlist\fP \fBdo\fP \fIlist\fP \fBdone\fP"
-A \fBwhile\fP is a prechecked loop. Its body is executed as often
-as the exit status of the first \fIlist\fP is zero.
-The exit status of a \fBwhile\fP statement is the last exit status
-of the \fIlist\fP in the body of the loop; if the body is not executed,
-the exit status is zero.
-.\"}}}
-.\"{{{ function name { list }
-.IP "\fBfunction\fP \fIname\fP \fB{\fP \fIlist\fP \fB}\fP"
-Defines the function \fIname\fP.
-See Functions below.
-Note that redirections specified after a function definition are
-performed whenever the function is executed, not when the function
-definition is executed.
-.\"}}}
-.\"{{{ name () command
-.IP "\fIname\fP \fB()\fP \fIcommand\fP"
-Mostly the same as \fBfunction\fP.
-See Functions below.
-.\"}}}
-.\"{{{ (( expression ))
-.IP "\fB((\fP \fIexpression\fP \fB))\fP"
-The arithmetic expression \fIexpression\fP is evaluated;
-equivalent to \fBlet "\fP\fIexpression\fP\fB"\fP.
-See Arithmetic Expressions and the \fBlet\fP command below.
-.\"}}}
-.\"{{{ [[ expression ]]
-.IP "\fB[[\fP \fIexpression\fP \fB]]\fP"
-Similar to the \fBtest\fP and \fB[\fP \&... \fB]\fP commands (described later),
-with the following exceptions:
-.RS
-.nr P2 \n(PD
-.nr PD 0
-.IP \ \ \(bu
-Field splitting and file name generation are not performed on
-arguments.
-.IP \ \ \(bu
-The \fB\-a\fP (and) and \fB\-o\fP (or) operators are replaced with
-\fB&&\fP and \fB||\fP, respectively.
-.IP \ \ \(bu
-Operators (\fIe.g.\fP, \fB\-f\fP, \fB=\fP, \fB!\fP, \fIetc.\fP) must be unquoted.
-.IP \ \ \(bu
-The second operand of \fB!=\fP and \fB=\fP
-expressions are patterns (\fIe.g.\fP, the comparison in
-.ce
-\fB[[ foobar = f*r ]]\fP
-succeeds).
-.IP \ \ \(bu
-There are two additional binary operators: \fB<\fP and \fB>\fP
-which return true if their first string operand is less than,
-or greater than, their second string operand, respectively.
-.IP \ \ \(bu
-The single argument form
-of \fBtest\fP, which tests if the argument has non-zero length, is not valid
-- explicit operators must be always be used, \fIe.g.\fP, instead of
-.ce
-\fB[\fP \fIstr\fP \fB]\fP
-use
-.ce
-\fB[[ \-n \fP\fIstr\fP\fB ]]\fP
-.IP \ \ \(bu
-Parameter, command and arithmetic substitutions are performed as
-expressions are evaluated and lazy expression evaluation is used for
-the \fB&&\fP and \fB||\fP operators.
-This means that in the statement
-.ce
-\fB[[ -r foo && $(< foo) = b*r ]]\fP
-the \fB$(< foo)\fP is evaluated if and only if the file \fBfoo\fP exists
-and is readable.
-.nr PD \n(P2
-.RE
-.\"}}}
-.\"}}}
-.\"}}}
-.\"{{{ Quoting
-.SS Quoting
-Quoting is used to prevent the shell from treating characters or words
-specially.
-There are three methods of quoting: First, \fB\e\fP quotes
-the following character, unless it is at the end of a line, in which
-case both the \fB\e\fP and the newline are stripped.
-Second, a single quote (\fB'\fP) quotes everything up to the next single
-quote (this may span lines).
-Third, a double quote (\fB"\fP) quotes all characters,
-except \fB$\fP, \fB`\fP and \fB\e\fP, up to the next unquoted double quote.
-\fB$\fP and \fB`\fP inside double quotes have their usual meaning (\fIi.e.\fP,
-parameter, command or arithmetic substitution) except no field splitting
-is carried out on the results of double-quoted substitutions.
-If a \fB\e\fP inside a double-quoted string is followed by \fB\e\fP, \fB$\fP,
-\fB`\fP or \fB"\fP, it is replaced by the second character; if it is
-followed by a newline, both the \fB\e\fP and the newline are stripped;
-otherwise, both the \fB\e\fP and the character following are unchanged.
-.PP
-Note: see POSIX Mode below for a special rule regarding sequences
-of the form \fB"\fP...\fB`\fP...\fB\e"\fP...\fB`\fP..\fB"\fP.
-.\"}}}
-.\"{{{ Aliases
-.SS "Aliases"
-There are two types of aliases: normal command aliases and tracked
-aliases. Command aliases are normally used as a short hand for a long
-or often used command. The shell expands command aliases (\fIi.e.\fP,
-substitutes the alias name for its value) when it reads the first word
-of a command. An expanded alias is re-processed to check for more
-aliases. If a command alias ends in a space or tab, the following word
-is also checked for alias expansion. The alias expansion process stops
-when a word that is not an alias is found, when a quoted word is found
-or when an alias word that is currently being expanded is found.
-.PP
-The following command aliases are defined automatically by the shell:
-.ft B
-.RS
-autoload='typeset \-fu'
-.br
-functions='typeset \-f'
-.br
-hash='alias \-t'
-.br
-history='fc \-l'
-.br
-integer='typeset \-i'
-.br
-local='typeset'
-.br
-login='exec login'
-.br
-newgrp='exec newgrp'
-.br
-nohup='nohup '
-.br
-r='fc \-e \-'
-.br
-stop='kill \-STOP'
-.br
-suspend='kill \-STOP $$'
-.br
-type='whence \-v'
-.RE
-.ft P
-.PP
-Tracked aliases allow the shell to remember where it found a particular
-command. The first time the shell does a path search for a command that
-is marked as a tracked alias, it saves the full path of the command.
-The next time the command is executed, the shell checks the saved path
-to see that it is still valid, and if so, avoids repeating the path
-search. Tracked aliases can be listed and created using \fBalias
-\-t\fP. Note that changing the \fBPATH\fP parameter clears the saved
-paths for all tracked aliases. If the \fBtrackall\fP option is set (\fIi.e.\fP,
-\fBset \-o trackall\fP or \fBset \-h\fP), the shell tracks all
-commands. This option is set automatically for non-interactive shells.
-For interactive shells, only the following commands are automatically
-tracked: \fBcat\fP, \fBcc\fP, \fBchmod\fP, \fBcp\fP, \fBdate\fP, \fBed\fP,
-\fBemacs\fP, \fBgrep\fP, \fBls\fP, \fBmail\fP, \fBmake\fP, \fBmv\fP,
-\fBpr\fP, \fBrm\fP, \fBsed\fP, \fBsh\fP, \fBvi\fP and \fBwho\fP.
-.\"}}}
-.\"{{{ Substitution
-.SS "Substitution"
-The first step the shell takes in executing a simple-command is to
-perform substitutions on the words of the command.
-There are three kinds of substitution: parameter, command and arithmetic.
-Parameter substitutions, which are described in detail in the next section,
-take the form \fB$name\fP or \fB${\fP...\fB}\fP; command substitutions take
-the form \fB$(\fP\fIcommand\fP\fB)\fP or \fB`\fP\fIcommand\fP\fB`\fP;
-and arithmetic substitutions take the form \fB$((\fP\fIexpression\fP\fB))\fP.
-.PP
-If a substitution appears outside of double quotes, the results of the
-substitution are generally subject to word or field splitting according to
-the current value of the \fBIFS\fP parameter.
-The \fBIFS\fP parameter specifies a list of characters which
-are used to break a string up into several words;
-any characters from the set space, tab and newline that appear in the
-IFS characters are called \fIIFS white space\fP.
-Sequences of one or more IFS white space characters, in combination with
-zero or one non-IFS white space characters delimit a field.
-As a special case, leading and trailing IFS white space is stripped (\fIi.e.\fP,
-no leading or trailing empty field is created by it); leading or trailing
-non-IFS white space does create an empty field.
-Example: if \fBIFS\fP is set to `<space>:', the sequence of characters
-`<space>A<space>:<space><space>B::D' contains four fields: `A', `B', `' and `D'.
-Note that if the \fBIFS\fP parameter is set to the null string, no
-field splitting is done; if the parameter is unset, the default value
-of space, tab and newline is used.
-.PP
-The results of substitution are, unless otherwise specified, also subject
-to brace expansion and file name expansion (see the relevant sections
-below).
-.PP
-A command substitution is replaced by the output generated by the specified
-command, which is run in a subshell.
-For \fB$(\fP\fIcommand\fP\fB)\fP substitutions, normal quoting rules
-are used when \fIcommand\fP is parsed, however, for the
-\fB`\fP\fIcommand\fP\fB`\fP form, a \fB\e\fP followed by any of
-\fB$\fP, \fB`\fP or \fB\e\fP is stripped (a \fB\e\fP followed by any other
-character is unchanged).
-As a special case in command substitutions, a command of the form
-\fB<\fP \fIfile\fP is interpreted to mean substitute the contents
-of \fIfile\fP ($(< foo) has the same effect as $(cat foo), but it
-is carried out more efficiently because no process is started).
-.br
-.\"todo: fix this( $(..) parenthesis counting).
-NOTE: \fB$(\fP\fIcommand\fP\fB)\fP expressions are currently parsed by
-finding the matching parenthesis, regardless of quoting. This will hopefully
-be fixed soon.
-.PP
-Arithmetic substitutions are replaced by the value of the specified
-expression.
-For example, the command \fBecho $((2+3*4))\fP prints 14.
-See Arithmetic Expressions for a description of an \fIexpression\fP.
-.\"}}}
-.\"{{{ Parameters
-.SS "Parameters"
-Parameters are shell variables; they can be assigned values and
-their values can be accessed using a parameter substitution.
-A parameter name is either one of the special single punctuation or digit
-character parameters described below, or a letter followed by zero or more
-letters or digits (`_' counts as a letter).
-Parameter substitutions take the form \fB$\fP\fIname\fP or
-\fB${\fP\fIname\fP\fB}\fP, where \fIname\fP is a parameter name.
-If substitution is performed on a parameter that is not set, a null
-string is substituted unless the \fBnounset\fP option (\fBset \-o nounset\fP
-or \fBset \-u\fP) is set, in which case an error occurs.
-.PP
-.\"{{{ parameter assignment
-Parameters can be assigned values in a number of ways.
-First, the shell implicitly sets some parameters like \fB#\fP, \fBPWD\fP,
-etc.; this is the only way the special single character parameters are
-set.
-Second, parameters are imported from the shell's environment at startup.
-Third, parameters can be assigned values on the command line, for example,
-`\fBFOO=bar\fP' sets the parameter FOO to bar; multiple parameter
-assignments can be given on a single command line and they can
-be followed by a simple-command, in which case the assignments are
-in effect only for the duration of the command (such assignments are
-also exported, see below for implications of this).
-Note that both the parameter name and the \fB=\fP must be unquoted for
-the shell to recognize a parameter assignment.
-The fourth way of setting a parameter is with the \fBexport\fP, \fBreadonly\fP
-and \fBtypeset\fP commands; see their descriptions in the Command Execution
-section.
-Fifth, \fBfor\fP and \fBselect\fP loops set parameters as well as
-the \fBgetopts\fP, \fBread\fP and \fBset \-A\fP commands.
-Lastly, parameters can be assigned values using assignment operators
-inside arithmetic expressions (see Arithmetic Expressions below) or
-using the \fB${\fP\fIname\fP\fB=\fP\fIvalue\fP\fB}\fP form
-of parameter substitution (see below).
-.\"}}}
-.PP
-.\"{{{ environment
-Parameters with the export attribute (set using the \fBexport\fP or
-\fBtypeset \-x\fP commands, or by parameter assignments followed by simple
-commands) are put in the environment (see \fIenviron\fP(5)) of commands
-run by the shell as \fIname\fP\fB=\fP\fIvalue\fP pairs.
-The order in which parameters appear in the environment of a command
-is unspecified.
-When the shell starts up, it extracts parameters and their values from its
-environment and automatically sets the export attribute for those parameters.
-.\"}}}
-.\"{{{ ${name[:][-+=?]word}
-.PP
-Modifiers can be applied to the \fB${\fP\fIname\fP\fB}\fP form of parameter
-substitution:
-.IP \fB${\fP\fIname\fP\fB:-\fP\fIword\fP\fB}\fP
-if \fIname\fP is set and not null, it is substituted, otherwise \fIword\fP is
-substituted.
-.IP \fB${\fP\fIname\fP\fB:+\fP\fIword\fP\fB}\fP
-if \fIname\fP is set and not null, \fIword\fP is substituted, otherwise nothing is substituted.
-.IP \fB${\fP\fIname\fP\fB:=\fP\fIword\fP\fB}\fP
-if \fIname\fP is set and not null, it is substituted, otherwise it is
-assigned \fIword\fP and the resulting value of \fIname\fP is substituted.
-.IP \fB${\fP\fIname\fP\fB:?\fP\fIword\fP\fB}\fP
-if \fIname\fP is set and not null, it is substituted, otherwise \fIword\fP
-is printed on standard error (preceded by \fIname\fP:) and an error occurs
-(normally causing termination of a shell script, function or \&.-script).
-If word is omitted the string `parameter null or not set' is used instead.
-.PP
-In the above modifiers, the \fB:\fP can be omitted, in which case the
-conditions only depend on \fIname\fP being set (as opposed to set and
-not null).
-If \fIword\fP is needed, parameter, command, arithmetic and tilde substitution
-are performed on it; if \fIword\fP is not needed, it is not evaluated.
-.\"}}}
-.PP
-The following forms of parameter substitution can also be used:
-.\"{{{ ${#name}
-.IP \fB${#\fP\fIname\fP\fB}\fP
-The number of positional parameters if \fIname\fP is \fB*\fP, \fB@\fP or
-is not specified,
-or the length of the string value of parameter \fIname\fP.
-.\"}}}
-.\"{{{ ${#name[*]}, ${#name[@]}
-.IP "\fB${#\fP\fIname\fP\fB[*]}\fP, \fB${#\fP\fIname\fP\fB[@]}\fP"
-The number of elements in the array \fIname\fP.
-.\"}}}
-.\"{{{ ${name#pattern}, ${name##pattern}
-.IP "\fB${\fP\fIname\fP\fB#\fP\fIpattern\fP\fB}\fP, \fB${\fP\fIname\fP\fB##\fP\fIpattern\fP\fB}\fP"
-If \fIpattern\fP matches the beginning of the value of parameter \fIname\fP,
-the matched text is deleted from the result of substitution. A single
-\fB#\fP results in the shortest match, two \fB#\fP's results in the
-longest match.
-.\"}}}
-.\"{{{ ${name%pattern}, ${name%%pattern}
-.IP "\fB${\fP\fIname\fP\fB%\fP\fIpattern\fP\fB}\fP, \fB${\fP\fIname\fP\fB%%\fP\fIpattern\fP\fB}\fP"
-Like \fB${\fP..\fB#\fP..\fB}\fP substitution, but it deletes from the end of the
-value.
-.\"}}}
-.\"{{{ special shell parameters
-.PP
-The following special parameters are implicitly set by the shell and cannot be
-set directly using assignments:
-.\"{{{ !
-.IP \fB!\fP
-Process id of the last background process started. If no background
-processes have been started, the parameter is not set.
-.\"}}}
-.\"{{{ #
-.IP \fB#\fP
-The number of positional parameters (\fIi.e.\fP, \fB$1\fP, \fB$2\fP,
-\fIetc.\fP).
-.\"}}}
-.\"{{{ $
-.IP \fB$\fP
-The process ID of the shell, or the PID of the original shell if
-it is a subshell.
-.\"}}}
-.\"{{{ -
-.IP \fB\-\fP
-The concatenation of the current single letter options
-(see \fBset\fP command below for list of options).
-.\"}}}
-.\"{{{ ?
-.IP \fB?\fP
-The exit status of the last non-asynchronous command executed.
-If the last command was killed by a signal, \fB$?\fP is set to 128 plus
-the signal number.
-.\"}}}
-.\"{{{ 0
-.IP "\fB0\fP"
-The name the shell was invoked with (\fIi.e.\fP, \fBargv[0]\fP), or the
-\fBcommand-name\fP if it was invoked with the \fB\-c\fP option and the
-\fBcommand-name\fP was supplied, or the \fIfile\fP argument, if it was
-supplied.
-If the \fBposix\fP option is not set, \fB$0\fP is the name of the current
-function or script.
-.\"}}}
-.\"{{{ 1-9
-.IP "\fB1\fP ... \fB9\fP"
-The first nine positional parameters that were supplied to the shell,
-function or \fB.\fP-script.
-Further positional parameters may be accessed using
-\fB${\fP\fInumber\fP\fB}\fP.
-.\"}}}
-.\"{{{ *
-.IP \fB*\fP
-All positional parameters (except parameter 0),
-\fIi.e.\fP, \fB$1 $2 $3\fP....
-If used outside of double quotes, parameters are separate words
-(which are subjected to word splitting); if used within double quotes,
-parameters are separated by the first character of the \fBIFS\fP parameter
-(or the empty string if \fBIFS\fP is null).
-.\"}}}
-.\"{{{ @
-.IP \fB@\fP
-Same as \fB$*\fP, unless it is used inside double quotes, in which case
-a separate word is generated for each positional parameter \- if there
-are no positional parameters, no word is generated ("$@" can be used
-to access arguments, verbatim, without loosing null arguments or
-splitting arguments with spaces).
-.\"}}}
-.\"}}}
-.\"{{{ general shell parameters
-.PP
-The following parameters are set and/or used by the shell:
-.\"{{{ _
-.IP "\fB_\fP \fI(underscore)\fP"
-In interactive use, this parameter is set to the last word of the
-previous command. When a command is executed, this parameter is set to
-the full path of the command and is placed in the command's environment.
-When \fBMAILPATH\fP messages are evaluated, this parameter contains
-the name of the file that changed (see \fBMAILPATH\fP parameter below).
-.\"}}}
-.\"{{{ CDPATH
-.IP \fBCDPATH\fP
-Search path for the \fBcd\fP built-in command. Works the same way as
-\fBPATH\fP for those directories not beginning with \fB/\fP in \fBcd\fP
-commands.
-Note that if CDPATH is set and does not contain \fB.\fP nor an empty path,
-the current directory is not searched.
-.\"}}}
-.\"{{{ COLUMNS
-.IP \fBCOLUMNS\fP
-Set to the number of columns on the terminal or window.
-Currently set to the \fBcols\fP value as reported by \fIstty\fP(1) if that
-value is non-zero.
-This parameter is used by the interactive line editing modes, and by
-\fBselect\fP, \fBset \-o\fP and \fBkill \-l\fP commands
-to format information in columns.
-.\"}}}
-.\"{{{ EDITOR
-.IP \fBEDITOR\fP
-If the \fBVISUAL\fP parameter is not set, this parameter controls the
-command line editing mode for interactive shells.
-See \fBVISUAL\fP parameter below for how this works.
-.\"}}}
-.\"{{{ ENV
-.IP \fBENV\fP
-If this parameter is found to be set after any profile files are
-executed, the expanded value is used as a shell start-up file. It
-typically contains function and alias definitions.
-.\"}}}
-.\"{{{ ERRNO
-.IP \fBERRNO\fP
-Integer value of the shell's errno variable \(em indicates the reason
-the last system call failed.
-.\" todo: ERRNO variable
-.sp
-Not implemented yet.
-.\"}}}
-.\"{{{ EXECSHELL
-.IP \fBEXECSHELL\fP
-If set, this parameter is assumed to contain the shell that is to be
-used to execute commands that \fIexecve\fP(2) fails to execute and
-which do not start with a `\fB#!\fP \fIshell\fP' sequence.
-.\"}}}
-.\"{{{ FCEDIT
-.IP \fBFCEDIT\fP
-The editor used by the \fBfc\fP command (see below).
-.\"}}}
-.\"{{{ FPATH
-.IP \fBFPATH\fP
-Like \fBPATH\fP, but used when an undefined function is executed to locate
-the file defining the function.
-It is also searched when a command can't be found using \fBPATH\fP.
-See Functions below for more information.
-.\"}}}
-.\"{{{ HISTFILE
-.IP \fBHISTFILE\fP
-The name of the file used to store history.
-When assigned to, history is loaded from the specified file.
-Also, several invocations of the
-shell running on the same machine will share history if their
-\fBHISTFILE\fP parameters all point at the same file.
-.br
-NOTE: if HISTFILE isn't set, no history file is used. This is
-different from the original Korn shell, which uses \fB$HOME/.sh_history\fP;
-in future, pdksh may also use a default history file.
-.\"}}}
-.\"{{{ HISTSIZE
-.IP \fBHISTSIZE\fP
-The number of commands normally stored for history, default 128.
-.\"}}}
-.\"{{{ HOME
-.IP \fBHOME\fP
-The default directory for the \fBcd\fP command and the value
-substituted for an unqualified \fB~\fP (see Tilde Expansion below).
-.\"}}}
-.\"{{{ IFS
-.IP \fBIFS\fP
-Internal field separator, used during substitution and by the \fBread\fP
-command, to split values into distinct arguments; normally set to
-space, tab and newline. See Substitution above for details.
-.br
-\fBNote:\fP this parameter is not imported from the environment
-when the shell is started.
-.\"}}}
-.\"{{{ KSH_VERSION
-.IP \fBKSH_VERSION\fP
-The version of shell and the date the version was created (readonly).
-See also the version commands in Emacs Interactive Input Line Editing
-and Vi Interactive Input Line Editing, below.
-.\"}}}
-.\"{{{ SH_VERSION
-.\"}}}
-.\"{{{ LINENO
-.IP \fBLINENO\fP
-The line number of the function or shell script that is currently being
-executed.
-.\" todo: LINENO variable
-.sp
-Not implemented yet.
-.\"}}}
-.\"{{{ LINES
-.IP \fBLINES\fP
-Set to the number of lines on the terminal or window.
-.\"Currently set to the \fBrows\fP value as reported by \fIstty\fP(1) if that
-.\"value is non-zero.
-.\" todo: LINES variable
-.sp
-Not implemented yet.
-.\"}}}
-.\"{{{ MAIL
-.IP \fBMAIL\fP
-If set, the user will be informed of the arrival of mail in the named
-file. This parameter is ignored if the \fBMAILPATH\fP parameter is set.
-.\"}}}
-.\"{{{ MAILCHECK
-.IP \fBMAILCHECK\fP
-How often, in seconds, the shell will check for mail in the file(s)
-specified by \fBMAIL\fP or \fBMAILPATH\fP. If 0, the shell checks
-before each prompt. The default is 600 (10 minutes).
-.\"}}}
-.\"{{{ MAILPATH
-.IP \fBMAILPATH\fP
-A list of files to be checked for mail. The list is colon separated,
-and each file may be followed by a \fB?\fP and a message to be printed
-if new mail has arrived. Command, parameter and arithmetic substitution is
-performed on the message, and, during substitution, the parameter \fB$_\fP
-contains the name of the file.
-The default message is \fByou have mail in $_\fP.
-.\"}}}
-.\"{{{ OLDPWD
-.IP \fBOLDPWD\fP
-The previous working directory.
-Unset if \fBcd\fP has not successfully changed directories since the
-shell started, or if the shell doesn't know where it is.
-.\"}}}
-.\"{{{ OPTARG
-.IP \fBOPTARG\fP
-When using \fBgetopts\fP, it contains the argument for a parsed option,
-if it requires one.
-.\"}}}
-.\"{{{ OPTIND
-.IP \fBOPTIND\fP
-The index of the last argument processed when using \fBgetopts\fP.
-Assigning 1 to this parameter causes \fBgetopts\fP to
-process arguments from the beginning the next time it is invoked.
-.\"}}}
-.\"{{{ PATH
-.IP \fBPATH\fP
-A colon separated list of directories that are searched when looking
-for commands and \fB.\fP'd files.
-An empty string resulting from a leading or trailing colon, or two adjacent
-colons is treated as a `.', the current directory.
-.\"}}}
-.\"{{{ POSIXLY_CORRECT
-.IP \fBPOSIXLY_CORRECT\fP
-If set, this parameter causes the \fBposix\fP option to be enabled.
-See POSIX Mode below.
-.\"}}}
-.\"{{{ PPID
-.IP \fBPPID\fP
-The process ID of the shell's parent (readonly).
-.\"}}}
-.\"{{{ PS1
-.IP \fBPS1\fP
-\fBPS1\fP is the primary prompt for interactive shells.
-Parameter, command and arithmetic substitutions are performed, and
-\fB!\fP is replaced with the current command number (see \fBfc\fP
-command below). A literal ! can be put in the prompt by placing !! in PS1.
-Note that since the command line editors try to figure out how long the
-prompt is (so they know how far it is to edge of the screen),
-escape codes in the prompt tend to mess things up.
-You can tell the shell not to count certain sequences (such as escape codes)
-by prefixing your prompt with a non-printing character (such as control-A)
-followed by a carriage return and then delimiting the escape codes with
-this non-printing character.
-If you don't have any non-printing characters, you're out of luck...
-BTW, don't blame me for this hack; it's in the original ksh.
-Default is `\fB$\ \fP' for non-root users, `\fB#\ \fP' for root..
-.\"}}}
-.\"{{{ PS2
-.IP \fBPS2\fP
-Secondary prompt string, by default `\fB>\fP ', used when more input is
-needed to complete a command.
-.\"}}}
-.\"{{{ PS3
-.IP \fBPS3\fP
-Prompt used by \fBselect\fP statement when reading a menu selection.
-Default is `\fB#?\ \fP'.
-.\"}}}
-.\"{{{ PS4
-.IP \fBPS4\fP
-Used to prefix commands that are printed during execution tracing
-(see \fBset \-x\fP command below).
-Parameter, command and arithmetic substitutions are performed
-before it is printed.
-Default is `\fB+\ \fP'.
-.\"}}}
-.\"{{{ PWD
-.IP \fBPWD\fP
-The current working directory. Maybe unset or null if shell doesn't
-know where it is.
-.\"}}}
-.\"{{{ RANDOM
-.IP \fBRANDOM\fP
-A simple random number generator. Every time \fBRANDOM\fP is
-referenced, it is assigned the next number in a random number series.
-The point in the series can be set by assigning a number to
-\fBRANDOM\fP (see \fIrand\fP(3)).
-.\"}}}
-.\"{{{ REPLY
-.IP \fBREPLY\fP
-Default parameter for the \fBread\fP command if no names are given.
-Also used in \fBselect\fP loops to store the value that is read from
-standard input.
-.\"}}}
-.\"{{{ SECONDS
-.IP \fBSECONDS\fP
-The number of seconds since the shell started or, if the parameter has been
-assigned an integer value, the number of seconds since the assignment plus
-the value that was assigned.
-.\"}}}
-.\"{{{ TMOUT
-.IP \fBTMOUT\fP
-If set to a positive integer in an interactive shell, it specifies
-the maximum number of seconds the shell will wait for input after
-printing the primary prompt (\fBPS1\fP). If the time is exceeded, the
-shell exits.
-.\"}}}
-.\"{{{ TMPDIR
-.IP \fBTMPDIR\fP
-The directory shell temporary files are created in. If this parameter
-is not set, or does not contain the absolute path of a writable
-directory, temporary files are created in \fB/tmp\fP.
-.\"}}}
-.\"{{{ VISUAL
-.IP \fBVISUAL\fP
-If set, this parameter controls the command line editing mode for
-interactive shells. If the last component of the path specified in this
-parameter contains the string \fBvi\fP, \fBemacs\fP or \fBgmacs\fP, the
-vi, emacs or gmacs (Gosling emacs) editing mode is enabled, respectively.
-.\"}}}
-.\"}}}
-.\"}}}
-.\"{{{ Tilde Expansion
-.SS "Tilde Expansion"
-Tilde expansion, which is done in parallel with parameter substitution,
-is done on words starting with an unquoted \fB~\fP. The characters
-following the tilde, up to the first \fB/\fP, if any, are assumed to be
-a login name. If the login name is empty, \fB+\fP or \fB\-\fP, the
-value of the \fBHOME\fP, \fBPWD\fP, or \fBOLDPWD\fP parameter is
-substituted, respectively. Otherwise, the password file is searched for
-the login name, and the tilde expression is substituted with the
-user's home directory. If the login name is not found in the password
-file or if any quoting or parameter substitution occurs in the login name,
-no substitution is performed.
-.PP
-In parameter assignments (those preceding a simple-command or those
-occurring in the arguments of \fBalias\fP, \fBexport\fP, \fBreadonly\fP,
-and \fBtypeset\fP), tilde expansion is done after any unquoted colon
-(\fB:\fP), and login names are also delimited by colons.
-.PP
-The home directory of previously expanded login names are cached and
-re-used. The \fBalias \-d\fP command may be used to list, change and
-add to this cache (\fIe.g.\fP, `alias \-d fac=/usr/local/facilities; cd
-~fac/bin').
-.\"}}}
-.\"{{{ Brace Expansion
-.SS "Brace Expansion (alternation)"
-Brace expressions, which take the form
-.RS
-\fIprefix\fP\fB{\fP\fIstr\fP1\fB,\fP...\fB,\fP\fIstr\fPN\fB}\fP\fIsuffix\fP
-.RE
-are expanded to N words, each of which is the concatenation of
-\fIprefix\fP, \fIstr\fPi and \fIsuffix\fP
-(\fIe.g.\fP, `a{c,b{X,Y},d}e' expands to four word: ace, abXe, abYe, and ade).
-As noted in the example, brace expressions can be nested and the resulting
-words are not sorted.
-Brace expressions must contain an unquoted comma (\fB,\fP) for expansion
-to occur (\fIi.e.\fP, \fB{}\fP and \fB{foo}\fP are not expanded).
-Brace expansion is carried out after parameter substitution and before
-file name generation.
-.\"}}}
-.\"{{{ File Name Patterns
-.SS "File Name Patterns"
-.PP
-A file name pattern is a word containing one or more unquoted \fB?\fP or
-\fB*\fP characters or \fB[\fP..\fB]\fP sequences. Once brace expansion has
-been performed, the shell replaces file name patterns with the sorted names
-of all the files that match the pattern (if no files match, the word is
-left unchanged). The pattern elements have the following meaning:
-.IP \fB?\fP
-matches any single character.
-.IP \fB*\fP
-matches any sequence of characters.
-.IP \fB[\fP..\fB]\fP
-matches any of the characters inside the brackets. Ranges of characters
-can be specified by separating two characters by a \fB\-\fP, \fIe.g.\fP,
-\fB[a0\-9]\fP matches the letter \fBa\fP or any digit.
-In order to represent itself, a
-\fB\-\fP must either be quoted or the first or last character in the character
-list. Similarly, a \fB]\fP must be quoted or the first character in the list
-if it is represent itself instead of the end of the list. Also, a \fB!\fP
-appearing at the start of the list has special meaning (see below), so to
-represent itself it must be quoted or appear later in the list.
-.IP \fB[!\fP..\fB]\fP
-like \fB[\fP..\fB]\fP, except it matches any character not inside the brackets.
-.IP "\fB*(\fP\fIpattern\fP\fB|\fP ... \fP|\fP\fIpattern\fP\fB)\fP"
-matches any string of characters that matches zero or more occurances
-of the specified patterns.
-Example: the pattern \fB*(foo|bar)\fP matches the strings
-`', `foo', `bar', `foobarfoo', \fIetc.\fP.
-.IP "\fB+(\fP\fIpattern\fP\fB|\fP ... \fP|\fP\fIpattern\fP\fB)\fP"
-matches any string of characters that matches one or more occurances
-of the specified patterns.
-Example: the pattern \fB+(foo|bar)\fP matches the strings
-`foo', `bar', `foobarfoo', \fIetc.\fP.
-.IP "\fB?(\fP\fIpattern\fP\fB|\fP ... \fP|\fP\fIpattern\fP\fB)\fP"
-matches the empty string or a string that matches one of the
-specified patterns.
-Example: the pattern \fB?(foo|bar)\fP only matches the strings
-`', `foo' and `bar'.
-.IP "\fB@(\fP\fIpattern\fP\fB|\fP ... \fP|\fP\fIpattern\fP\fB)\fP"
-matches a string that matches one of the
-specified patterns.
-Example: the pattern \fB@(foo|bar)\fP only matches the strings
-`foo' and `bar'.
-.IP "\fB!(\fP\fIpattern\fP\fB|\fP ... \fP|\fP\fIpattern\fP\fB)\fP"
-matches any string that does not match one of the specified
-patterns.
-Examples: the pattern \fB!(foo|bar)\fP matches all strings except
-`foo' and `bar'; the pattern \fB!(*)\fP matches no strings;
-the pattern \fB!(?)*\fP matches all strings (think about it).
-.PP
-Note that pdksh currently never matches \fB.\fP and \fB..\fP, but the original
-ksh, Bourne sh and bash do, so this may have to change (too bad).
-.PP
-Note that none of the above pattern elements match either a period (\fB.\fP)
-at the start of a file name or a slash (\fB/\fP), even if they are explicitly
-used in a \fB[\fP..\fB]\fP sequence; also, the names \fB.\fP and \fB..\fP
-are never matched, even by the pattern \fB.*\fP.
-.PP
-If the \fBmarkdirs\fP option is set, any directories that result from
-file name generation are marked with a trailing \fB/\fP.
-.PP
-.\" todo: implement this ([[:alpha:]], \fIetc.\fP)
-The POSIX character classes (\fIi.e.\fP,
-\fB[:\fP\fIclass-name\fP\fB:]\fP inside a \fB[\fP..\fB]\fP expression)
-are not yet implemented.
-.\"}}}
-.\"{{{ Input/Output Redirection
-.SS "Input/Output Redirection"
-When a command is executed, its standard input, standard output and
-standard error (file descriptors 0, 1 and 2, respectively) are normally
-inherited from the shell.
-Three exceptions to this are commands in pipelines, for which standard input
-and/or standard output are those set up by the pipeline, asynchronous commands
-created when job control is disabled, for which standard input is initially
-set to be from \fB/dev/null\fP, and commands for which any of the following
-redirections have been specified:
-.IP "\fB>\fP \fIfile\fP"
-standard output is redirected to \fIfile\fP. If \fIfile\fP does not exist,
-it is created; if it does exist, is a regular file and the \fBnoclobber\fP
-option is set, an error occurs, otherwise the file is truncated.
-Note that this means the command \fIcmd < foo > foo\fP will open
-\fIfoo\fP for reading and then truncate it when it opens it for writing,
-before \fIcmd\fP gets a chance to actually read \fIfoo\fP.
-.IP "\fB>|\fP \fIfile\fP"
-same as \fB>\fP, except the file is truncated, even if the \fBnoclobber\fP
-option is set.
-.IP "\fB>>\fP \fIfile\fP"
-same as \fB>\fP, except the file an existing file is appended to instead
-of being truncated. Also, the file is opened in append mode, so writes
-always go to the end of the file (see \fIopen\fP(2)).
-.IP "\fB<\fP \fIfile\fP"
-standard input is redirected from \fIfile\fP, which is opened for reading.
-.IP "\fB<>\fP \fIfile\fP"
-same as \fB<\fP, except the file is opened for reading and writing.
-.IP "\fB<<\fP \fImarker\fP"
-after reading the command line containing this kind of redirection (called a
-here document), the shell copies lines from the command source into a temporary
-file until a line matching \fImarker\fP is read.
-When the command is executed, standard input is redirected from the temporary
-file.
-If \fImarker\fP contains no quoted characters, the contents of the
-temporary file are processed as if enclosed in double quotes each time
-the command is executed, so parameter, command and arithmetic substitutions
-are performed, along with backslash (\fB\e\fP) escapes for
-\fB$\fP, \fB`\fP, \fB\e\fP and \fB\enewline\fP.
-If multiple here documents are used on the same command line, they are
-saved in order.
-.IP "\fB<<-\fP \fImarker\fP"
-same as \fB<<\fP, except leading tabs are stripped from lines in the
-here document.
-.IP "\fB<&\fP \fIfd\fP"
-standard input is duplicated from file descriptor \fIfd\fP.
-\fIfd\fP can be a single digit, indicating the number of an existing
-file descriptor, the letter \fBp\fP, indicating the file descriptor
-associated with the output of the current co-process, or
-the character \fB\-\fP, indicating standard input is to be closed.
-.IP "\fB>&\fP \fIfd\fP"
-same as \fB<&\fP, except the operation is done on standard output.
-.PP
-In any of the above redirections, the file descriptor that is redirected
-(\fIi.e.\fP, standard input or standard output) can be explicitly given by
-preceding the redirection with a single digit.
-Parameter, command and arithmetic substitutions, tilde substitutions and
-file name generation are all performed on the \fIfile\fP, \fImarker\fP and
-\fIfd\fP arguments of redirections.
-Note however, that the results of any file name generation are only used
-if a single file is matched; if multiple files match, the word with the
-unexpanded file name generation characters is used.
-Note that in restricted shells, redirections which can create files cannot
-be used.
-.PP
-For simple-commands, redirections may appear anywhere in the command, for
-compound-commands (\fBif\fP statements, \fIetc.\fP), any redirections must
-appear at the end.
-Redirections are processed after pipelines are created and in the order they
-are given, so
-.RS
-\fBcat /foo/bar 2>&1 > /dev/null | cat \-n\fP
-.RE
-will print an error with a line number prepended to it.
-.\"}}}
-.\"{{{ Arithmetic Expressions
-.SS "Arithmetic Expressions"
-Integer arithmetic expressions can be used
-with the \fBlet\fP command,
-inside \fB$((\fP..\fB))\fP expressions,
-inside array references (\fIe.g.\fP, \fIname\fP\fB[\fP\fIexpr\fP\fB]\fP),
-as numeric arguments to the \fBtest\fP command,
-and as the value of an assignment to an integer parameter.
-.PP
-Expression may contain alpha-numeric parameter identifiers, array
-references, and integer constants and may be combined with the
-following C operators (listed and grouped in increasing order of precedence).
-.TP
-Unary operators:
-\fB+ \- ! ~ ++ --\fP
-.TP
-Binary operators:
-\fB,\fP
-.br
-\fB= *= /= %= += \-= <<= >>= &= ^= |=\fP
-.br
-\fB||\fP
-.br
-\fB&&\fP
-.br
-\fB|\fP
-.br
-\fB^\fP
-.br
-\fB&\fP
-.br
-\fB== !=\fP
-.br
-\fB< <= >= >\fP
-.br
-\fB<< >>\fP
-.br
-\fB+ \-\fP
-.br
-\fB* / %\fP
-.TP
-Ternary operator:
-\fB?:\fP (precedence is immediately higher than assignment)
-.TP
-Grouping operators:
-\fB( )\fP
-.PP
-Integer constants may be specified with arbitrary bases using the notation
-\fIbase\fP\fB#\fP\fInumber\fP, where \fIbase\fP is a decimal integer specifying
-the base, and \fInumber\fP is a number in the specified base.
-.LP
-The operators are evaluated as follows:
-.RS
-.IP "unary \fB+\fP"
-result is the argument (included for completeness).
-.IP "unary \fB\-\fP"
-negation.
-.IP "\fB!\fP"
-logical not; the result is 1 if argument is zero, 0 if not.
-.IP "\fB~\fP"
-arithmetic (bit-wise) not.
-.IP "\fB++\fP"
-increment; must be applied to a parameter (not a literal or other
-expression) - the parameter is incremented by 1.
-When used as a prefix operator, the result is the incremented value of
-the parameter, when used as a postfix operator, the result is the
-original value of the parameter.
-.IP "\fB++\fP"
-similar to \fB++\fP, except the paramter is decremented by 1.
-.IP "\fB,\fP"
-seperates two arithmetic expressions; the left hand side is evaluated first,
-then the right. The result is value of the expression on the right hand side.
-.IP "\fB=\fP"
-assignment; variable on the left is set to the value on the right.
-.IP "\fB*= /= %= += \-= <<= >>= &= ^= |=\fP"
-assignment operators; \fI<var> <op>\fP\fB=\fP \fI<expr>\fP is the same as
-\fI<var>\fP \fB=\fP \fI<var> <op>\fP \fB(\fP \fI<expr>\fP \fB)\fP.
-.IP "\fB||\fP"
-logical or; the result is 1 if either argument is non-zero, 0 if not.
-The right argument is evaluated only if the left argument is zero.
-.IP "\fB&&\fP"
-logical and; the result is 1 if both arguments are non-zero, 0 if not.
-The right argument is evaluated only if the left argument is non-zero.
-.IP "\fB|\fP"
-arithmetic (bit-wise) or.
-.IP "\fB^\fP"
-arithmetic (bit-wise) exclusive-or.
-.IP "\fB&\fP"
-arithmetic (bit-wise) and.
-.IP "\fB==\fP"
-equal; the result is 1 if both arguments are equal, 0 if not.
-.IP "\fB!=\fP"
-not equal; the result is 0 if both arguments are equal, 1 if not.
-.IP "\fB<\fP"
-less than; the result is 1 if the left argument is less than the right,
-0 if not.
-.IP "\fB<= >= >\fP"
-less than or equal, greater than or equal, greater than. See <.
-.IP "\fB<< >>\fP"
-shift left (right); the result is the left argument with its bits shifted
-left (right) by the amount given in the right argument.
-.IP "\fB+ - * /\fP"
-addition, subtraction, multiplication, and division.
-.IP "\fB%\fP"
-remainder; the result is the remainder of the division of the left argument
-by the right. The sign of the result is unspecified if either argument
-is negative.
-.IP "\fI<arg1>\fP \fB?\fP \fI<arg2>\fP \fB:\fP \fI<arg3>\fP"
-if \fI<arg1>\fP is non-zero, the result is \fI<arg2>\fP,
-otherwise \fI<arg3>\fP.
-.RE
-.\"}}}
-.\"{{{ Co-Processes
-.SS "Co-Processes"
-A co-process, which is a pipeline created with the \fB|&\fP operator,
-is an asynchronous process that the shell can both write to
-(using \fBprint \-p\fP) and read from (using \fBread \-p\fP).
-The input and output of the co-process can also be manipulated
-using \fB>&p\fP and \fB<&p\fP redirections, respectively.
-Once a co-process has been started, another can't be started until
-the co-process exits, or until the co-process input has been redirected using
-an \fBexec \fP\fIn\fP\fB>&p\fP redirection.
-If a co-process's input is redirected in this way, the next
-co-process to be started will share the output with the first co-process,
-unless the output of the initial co-process has been redirected using an
-\fBexec \fP\fIn\fP\fB<&p\fP redirection.
-.PP
-Some notes concerning co-processes:
-.nr P2 \n(PD
-.nr PD 0
-.IP \ \ \(bu
-the only way to close the co-process input (so the co-process reads
-an end-of-file) is to redirect the input to a numbered file descriptor
-and then close that file descriptor (\fIe.g.\fP, \fBexec 3>&p;exec 3>&-\fP).
-.IP \ \ \(bu
-in order for co-processes to share a common output, the shell must keep
-the write portion of the output pipe open.
-This means that end of file will not be detected until all co-processes
-sharing the co-process output have exited (when they all exit, the shell
-closes its copy of the pipe).
-This can be avoided by redirecting the output to a numbered
-file descriptor (as this also causes the shell to close its copy).
-Note that this behaviour is slightly different from the original Korn shell
-which closes its copy of the write portion of the co-processs output when the
-most recently started co-process (instead of when all sharing co-processes)
-exits.
-.IP \ \ \(bu
-\fBprint \-p\fP will ignore SIGPIPE signals during writes
-if the signal is not being trapped or ignored; the same is not true if
-the co-process input has been duplicated to another file descriptor and
-\fBprint \-u\fP\fIn\fP is used.
-.nr PD \n(P2
-.\"}}}
-.\"{{{ Functions
-.SS "Functions"
-Functions are defined using either Korn shell \fBfunction\fP \fIname\fP
-syntax or the Bourne/POSIX shell \fIname\fP\fB()\fP syntax
-(see below for the difference between the two forms).
-Functions are like \fB.\fP-scripts in that they are executed in
-the current environment, however, unlike \fB.\fP-scripts, shell arguments
-(\fIi.e.\fP, positional parameters, \fB$1\fP, \fIetc.\fP) are never visible
-inside them.
-When the shell is determining the location of a command, functions are
-searched after special built-in commands, and before regular and non-regular
-built-ins, and before the \fBPATH\fP is searched.
-.PP
-An existing function may be deleted using \fBunset \-f\fP \fIfunction-name\fP.
-A list of functions can be obtained using \fBtypeset +f\fP and the
-function definitions can be listed using \fBtypeset \-f\fP.
-\fBautoload\fP (which is an alias for \fBtypeset \-fu\fP) may be used to
-create undefined functions; when an undefined function is executed, the
-shell searches the path specified in the \fBFPATH\fP parameter for a file
-with the same name as the function, which, if found is read and executed.
-If after executing the file, the named function is found to be defined, the
-function is executed, otherwise, the normal command search is continued
-(\fIi.e.\fP, the shell searches the regular built-in command table
-and \fBPATH\fP).
-Note that if a command is not found using \fBPATH\fP, an attempt is
-made to autoload a function using \fBFPATH\fP (this is an undocumented
-feature of the original Korn shell).
-.PP
-Functions can have two attributes, trace and export, which can be set
-with \fBtypeset \-ft\fP and \fBtypeset \-fx\fP, respectively.
-When a traced function is executed, the shell's \fBxtrace\fP option is turned
-on for the functions duration, otherwise the \fBxtrace\fP option is turned off.
-The export attribute of functions is currently not used. In the original
-Korn shell, exported functions are visible to shell scripts that are executed.
-.PP
-Since functions are executed in the current shell environment, parameter
-assignments made inside functions are visible after the function completes.
-If this is not the desired effect, the \fBtypeset\fP command can be used
-inside a function to create a local parameter.
-Note that special parameters (\fIe.g.\fP, \fB$$\fP, \fB$!\fP) can't be
-scoped in this way.
-.PP
-The exit status of a function is that of the last command executed in
-the function.
-A function can be made to finish immediately using the \fBreturn\fP command;
-this may also be used to explicitly specify the exit status.
-.PP
-Functions defined with the \fBfunction\fP reserved word are
-treated differently in the following ways from functions defined with
-the \fB()\fP notation:
-.nr P2 \n(PD
-.nr PD 0
-.IP \ \ \(bu
-the \fB$0\fP parameter is set to the name of the function
-(Bourne-style functions leave \fB$0\fP untouched).
-.IP \ \ \(bu
-parameter assignments preceeding function calls are not kept in
-the shell environment
-(executing Bourne-style functions will keep assignments).
-.nr PD \n(P2
-In the future, the following differences will also be added:
-.nr P2 \n(PD
-.nr PD 0
-.IP \ \ \(bu
-A separate trap/signal environment will be used during the execution of
-functions.
-This will mean that traps set inside a function will not affect the shell's
-traps and signals that are not ignored in the shell (but may be trapped) will
-have their default effect in a function.
-.IP \ \ \(bu
-The EXIT trap, if set in a function, will be executed after the function
-returns.
-.nr PD \n(P2
-.\"}}}
-.\"{{{ POSIX mode
-.SS "POSIX Mode"
-The shell is intended to be POSIX compliant, however, in some cases, POSIX
-behaviour is contrary either to the original Korn shell behaviour or to
-user convenience.
-How the shell behaves in these cases is determined by the state of
-the posix option (\fBset \-o posix\fP) \(em if it is on, the POSIX behaviour
-is followed, otherwise it is not.
-The \fBposix\fP option is set automatically when the shell starts up
-if the environment contains the \fBPOSIXLY_CORRECT\fP parameter.
-(The shell can also be compiled so that it is in POSIX mode by default,
-however this is usually not desirable).
-.PP
-The following is a list of things that are affected by the state of
-the \fBposix\fP option:
-.nr P2 \n(PD
-.nr PD 0
-.IP \ \ \(bu
-\fB\e"\fP inside double quoted \fB`\fP..\fB`\fP command substitutions:
-in posix mode, the \fB\e"\fP is interpreted when the command is interpreted;
-in non-posix mode, the backslash is stripped before the command substitution
-is interpreted. For example, \fBecho "`echo \e"hi\e"`"\fP produces `"hi"' in
-posix mode, `hi' in non-posix mode. To avoid problems, use the \fB$(...\fP)
-form of command substitution.
-.IP \ \ \(bu
-\fBkill \-l\fP output: in posix mode, signal names are listed one a single line;
-in non-posix mode, signal numbers, names and descriptions are printed in
-columns.
-In future, a new option (\fB\-v\fP perhaps) will be added to distinguish
-the two behaviours.
-.IP \ \ \(bu
-\fBfg\fP exit status: in posix mode, the exit status is 0 if no errors occur;
-in non-posix mode, the exit status is that of the last foregrounded job.
-.IP \ \ \(bu
-\fBgetopts\fP: in posix mode, options must start with a \fB\-\fP; in non-posix
-mode, options can start with either \fB\-\fP or \fB+\fP.
-.IP \ \ \(bu
-brace expansion (also known as alternation): in posix mode, brace expansion
-is disabled; in non-posix mode, brace expansion enabled.
-Note that \fBset \-o posix\fP (or setting the \fBPOSIXLY_CORRECT\fP parameter)
-automatically turns the \fBbraceexpand\fP option off, however it can be
-explicitly turned on later.
-.IP \ \ \(bu
-\fBset \-\fP: in posix mode, this does not clear the \fBverbose\fP or
-\fBxtrace\fP options; in non-posix mode, it does.
-.IP \ \ \(bu
-\fBset\fP exit status: in posix mode, the exit status of set is 0
-if there are no errors; in non-posix mode, the exit status is that of
-any command substitutions performed in generating the set command.
-For example, `\fBset \-\- `false`; echo $?\fP' prints 0 in posix mode,
-1 in non-posix mode. This construct is used in most shell scripts that
-use the old \fIgetopt\fP(1) command.
-.IP \ \ \(bu
-argument expansion of \fBalias\fP, \fBexport\fP, \fBreadonly\fP, and
-\fBtypeset\fP commands: in posix mode, normal argument expansion done;
-in non-posix mode, field splitting, file globing, brace expansion and
-(normal) tilde expansion are turned off, and assignment tilde expansion
-is turned on.
-.IP \ \ \(bu
-signal specification: in posix mode, signals can be specified as digits only
-if signal numbers match POSIX values (\fIi.e.\fP, HUP=1, INT=2, QUIT=3, ABRT=6,
-KILL=9, ALRM=14, and TERM=15); in non-posix mode, signals can be always digits.
-.IP \ \ \(bu
-alias expansion: in posix mode, alias expansion is only carried out when
-reading command words; in non-posix mode, alias expansion is carried out
-on any word following an alias that ended in a space.
-For example, the following for loop
-.RS
-.ft B
-alias a='for ' i='j'
-.br
-a i in 1 2; do echo i=$i j=$j; done
-.ft P
-.RE
-uses parameter \fBi\fP in posix mode, \fBj\fP in non-posix mode.
-.nr PD \n(P2
-.\"}}}
-.\"{{{ Command Execution (built-in commands)
-.SS "Command Execution"
-After evaluation of command line arguments, redirections and parameter
-assignments, the type of command is determined: a special built-in,
-a function, a regular built-in or the name of a file to execute found
-using the \fBPATH\fP parameter.
-The checks are made in the above order.
-Special built-in commands differ from other commands in that
-the \fBPATH\fP parameter is not used to find them, an error
-during their execution can cause a non-interactive shell to exit and
-parameter assignments that are specified before the command are
-kept after the command completes.
-Just to confuse things, if the posix option is turned off (see \fBset\fP
-command below) some special commands are very special in that
-no field splitting, file globing, brace expansion nor tilde expansion
-is preformed on arguments that look like assignments.
-Regular built-in commands are different only in that the \fBPATH\fP
-parameter is not used to find them.
-.PP
-The original ksh and POSIX differ somewhat in which commands are considered
-special or regular:
-.IP "POSIX special commands"
-.TS
-lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB .
-\&. continue exit return trap
-: eval export set unset
-break exec readonly shift
-.TE
-.IP "Additional ksh special commands"
-.TS
-lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB .
-builtin times typeset
-.TE
-.IP "Very special commands (non-posix mode)"
-.TS
-lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB .
-alias readonly set typeset
-.TE
-.IP "POSIX regular commands"
-.TS
-lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB .
-alias command fg kill umask
-bg false getopts read unalias
-cd fc jobs true wait
-.TE
-.IP "Additional ksh regular commands"
-.TS
-lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB .
-[ let pwd ulimit
-echo print test whence
-.TE
-.PP
-In the future, the additional ksh special and regular commands may
-be treated differently from the POSIX special and regular commands.
-.PP
-Once the type of the command has been determined, any command line parameter
-assignments are performed and exported for the duration of the command.
-.PP
-The following describes the special and regular built-in commands:
-.\"{{{ . file [ arg1 ... ]
-.IP "\fB\&.\fP \fIfile\fP [\fIarg1\fP ...]"
-Execute the commands in \fIfile\fP in the current environment.
-The file is searched for in the directories of \fBPATH\fP.
-If arguments are given, the positional parameters may be used to
-access them while \fIfile\fP is being executed.
-If no arguments are given, the positional parameters are those of the
-environment the command is used in.
-.\"}}}
-.\"{{{ : [ ... ]
-.IP "\fB:\fP [ ... ]"
-The null command.
-Exit status is set to zero.
-.\"}}}
-.\"{{{ alias [ -d | -t [ -r ] ] [-x] [name1[=value1] ...]
-.IP "\fBalias\fP [ \fB\-d\fP | \fB\-t\fP [\fB\-r\fP] ] [\fB\-x\fP] [\fIname1\fP[\fB=\fP\fIvalue1\fP] ...]"
-Without arguments, \fBalias\fP lists all aliases and their values. For
-any name without a value, its value is listed. Any name with a value
-defines an alias (see Aliases above).
-.sp
-The \fB\-x\fP option sets the export attribute of an alias, or, if no
-names are given, lists the aliases with the export attribute
-(exporting an alias currently has no affect).
-.sp
-The \fB\-t\fP option indicates that tracked aliases are to be listed/set
-(values specified on the command line are ignored for tracked aliases).
-The \fB\-r\fP option indicates that all tracked aliases are to be reset.
-.sp
-The \fB\-d\fP causes directory aliases, which are used in tilde expansion,
-to be listed or set (see Tilde Expansion above).
-.\"}}}
-.\"{{{ bg [job ...]
-.IP "\fBbg\fP [\fIjob\fP ...]"
-Resume the specified stopped job(s) in the background.
-If no jobs are specified, \fB%+\fP is assumed.
-This command is only available on systems which support job control.
-See Job Control below for more information.
-.\"}}}
-.\"{{{ bind [-l] [-m] [key[=editing-command] ...]
-.IP "\fBbind\fP [\fB\-m\fP] [\fIkey\fP[\fB=\fP\fIediting-command\fP] ...]"
-Set or view the current emacs command editing key bindings/macros.
-See Emacs Interactive Input Line Editing below for a complete description.
-.\"}}}
-.\"{{{ break [level]
-.IP "\fBbreak\fP [\fIlevel\fP]"
-\fBbreak\fP exits the \fIlevel\fPth inner most for, select, until, or while
-loop.
-\fIlevel\fP defaults to 1.
-.\"}}}
-.\"{{{ builtin command [arg1 ...]
-.IP "\fBbuiltin\fP \fIcommand\fP [\fIarg1\fP ...]"
-Execute the built-in command \fIcommand\fP.
-.\"}}}
-.\"{{{ cd [-LP] [dir]
-.IP "\fBcd\fP [\fB\-LP\fP] [\fIdir\fP]"
-Set the working directory to \fIdir\fP. If the parameter \fBCDPATH\fP
-is set, it lists the search path for the directory containing
-\fIdir\fP. A null path means the current directory. If \fIdir\fP is
-missing, the home directory \fB$HOME\fP is used. If \fIdir\fP is
-\fB\-\fP, the previous working directory is used (see OLDPWD parameter).
-If \fB\-L\fP option (logical path) is used or if the \fBphysical\fP option
-(see \fBset\fP command below) isn't set, references to \fB..\fP in \fIdir\fP
-are relative to the path used get to the directory.
-If \fB\-P\fP option (physical path) is used or if the \fBphysical\fP option
-is set, \fB..\fP is relative to the filesystem directory tree.
-The \fBPWD\fP and \fBOLDPWD\fP parameters are updated to reflect the
-current and old wording directory, respectively.
-.\"}}}
-.\"{{{ cd [-LP] old new
-.IP "\fBcd\fP [\fB\-LP\fP] \fIold new\fP"
-The string \fInew\fP is substituted for \fIold\fP in the current
-directory, and the shell attempts to change to the new directory.
-.\"}}}
-.\"{{{ command [ -pvV ] cmd [arg1 ...]
-.IP "\fBcommand\fP [\fB\-pvV\fP] \fIcmd\fP [\fIarg1\fP ...]"
-If neither the \fB\-v\fP nor \fB\-V\fP options are given,
-\fIcmd\fP
-is executed exactly as if the \fBcommand\fP had not been specified,
-with two exceptions: first, \fIcmd\fP cannot be a shell function, and
-second, special built-in commands lose their specialness (\fIi.e.\fP,
-redirection and utility errors do not cause the shell to exit, and command
-assignments are not permanent).
-If the \fB\-p\fP option is given, a default search path is used instead of
-the current value of \fBPATH\fP (the actual value of the default path is
-system dependent: on POSIXish systems, it is the value returned by
-.ce
-\fBgetconf CS_PATH\fP
-).
-.sp
-If the \fB\-v\fP option is given, instead of executing \fIcmd\fP, information
-about what would be executed is given (and the same is done for
-\fIarg1\fP ...):
-for special and regular built-in commands and functions,
-their names are simply printed,
-for aliases, a command that defines them is printed,
-and for commands found by searching the \fBPATH\fP parameter,
-the full path of the command is printed.
-If no command is be found, (\fIi.e.\fP, the path search fails), nothing
-is printed and \fBcommand\fP exits with a non-zero status.
-The \fB\-V\fP option is like the \fB\-v\fP option, except it is more verbose.
-.\"}}}
-.\"{{{ continue [levels]
-.IP "\fBcontinue\fP [\fIlevels\fP]"
-\fBcontinue\fP jumps to the beginning of the \fIlevel\fPth inner most for,
-select, until, or while loop.
-\fIlevel\fP defaults to 1.
-.\"}}}
-.\"{{{ echo [-neE] [arg ...]
-.IP "\fBecho\fP [\fB\-neE\fP] [\fIarg\fP ...]"
-Prints its arguments (separated by spaces) followed by a newline, to
-standard out.
-The newline is suppressed if any of the arguments contain the backslash
-sequence \fB\ec\fP.
-See \fBprint\fP command below for a list of other backslash sequences
-that are recognized.
-.sp
-The options are provided for compatibility with BSD shell scripts:
-\fB\-n\fP suppresses the trailing newline, \fB\-e\fP enables backslash
-interpretation (a no-op, since this is normally done), and \fB\-E\fP which
-suppresses backslash interpretation.
-.\"}}}
-.\"{{{ eval command ...
-.IP "\fBeval\fP \fIcommand ...\fP"
-The arguments are concatenated (with spaces between them) to form
-a single string which the shell then parses and executes
-in the current environment.
-.\"}}}
-.\"{{{ exec [command [arg ...]]
-.IP "\fBexec\fP [\fIcommand\fP [\fIarg\fP ...]]"
-The command is executed without forking, replacing the shell process.
-.sp
-If no arguments are given, any IO redirection is permanent and the shell
-is not replaced.
-Any file descriptors greater than 2 which are opened or \fIdup\fP(2)-ed
-in this way are not made available to other executed commands (\fIi.e.\fP,
-commands that are not built-in to the shell).
-.\"}}}
-.\"{{{ exit [status]
-.IP "\fBexit\fP [\fIstatus\fP]"
-The shell exits with the specified exit status.
-If \fIstatus\fP is not specified, the exit status is the current
-value of the \fB?\fP parameter.
-.\"}}}
-.\"{{{ export [-p] [parameter[=value] ...]
-.IP "\fBexport\fP [\fB\-p\fP] [\fIparameter\fP[\fB=\fP\fIvalue\fP]] ..."
-Sets the export attribute of the named parameters.
-Exported parameters are passed in the environment to executed commands.
-If values are specified, the named parameters also assigned.
-.sp
-If no parameters are specified, the names of all parameters with the export
-attribute are printed one per line, unless the \fB\-p\fP option is used,
-in which case \fBexport\fP commands defining all exported
-parameters, including their values, are printed.
-.\"}}}
-.\"{{{ false
-.IP "\fBfalse\fP"
-A command that exits with a non-zero status.
-.\"}}}
-.\"{{{ fc [-e editor | -l [-n]] [-r] [first [ last ]]
-.IP "\fBfc\fP [\fB\-e\fP \fIeditor\fP | \fB\-l\fP [\fB\-n\fP]] [\fB\-r\fP] [\fIfirst\fP [\fIlast\fP]]"
-\fIfirst\fP and \fIlast\fP select commands from the history.
-Commands can be selected by
-history number, or a string specifying the most recent command starting
-with that string. The \fB\-l\fP option lists the command on stdout,
-and \fB\-n\fP inhibits the default command numbers. The \fB\-r\fP
-option reverses the order of the list. Without \fB\-l\fP, the selected
-commands are edited by the editor specified with the \fB\-e\fP
-option, or if no \fB\-e\fP is specified, the editor specified by the
-\fBFCEDIT\fP parameter (if this parameter is not set, \fB/bin/ed\fP is used),
-and then executed by the shell.
-.\"}}}
-.\"{{{ fc [-e - | -s] [-g] [old=new] [prefix]
-.IP "\fBfc\fP [\fB\-e \-\fP | \fB\-s\fP] [\fB\-g\fP] [\fIold\fP\fB=\fP\fInew\fP] [\fIprefix\fP]"
-Re-execute the selected command (the previous command by default) after
-performing the optional substitution of \fIold\fP with \fInew\fP. If
-\fB\-g\fP is specified, all occurrences of \fIold\fP are replaced with
-\fInew\fP. This command is usually accessed with the predefined alias
-\fBr='fc \-e \-'\fP.
-.\"}}}
-.\"{{{ fg [job ...]
-.IP "\fBfg\fP [\fIjob\fP ...]"
-Resume the specified job(s) in the foreground.
-If no jobs are specified, \fB%+\fP is assumed.
-This command is only available on systems which support job control.
-See Job Control below for more information.
-.\"}}}
-.\"{{{ getopts optstring name [arg ...]
-.IP "\fBgetopts\fP \fIoptstring\fP \fIname\fP [\fIarg\fP ...]"
-\fBgetopts\fP is used by shell procedures to parse the specified arguments
-(or positional parameters, if no arguments are given) and to check for legal
-options.
-\fIoptstring\fP contains the option letters that
-\fBgetopts\fP is to recognize. If a letter is followed by a colon, the
-option is expected to have an argument.
-Arguments containing options must all start with either a \fB\-\fP or
-a \fB+\fP, options that do not take arguments may be grouped in a single
-argument.
-If an option takes an argument and the option character is not the last
-character of the argument it is found in, the remainder of the argument
-is taken to be the option's argument, otherwise, the next argument is
-the option's argument.
-.sp
-Each time \fBgetopts\fP is invoked, it places the next option in
-the shell parameter \fIname\fP and the index of the next argument to be
-processed in the shell parameter \fBOPTIND\fP.
-If the option was introduced with a \fB+\fP, the option placed in
-\fIname\fP is prefixed with a \fB+\fP.
-When an option requires an argument, \fBgetopts\fP places it in the
-shell parameter \fBOPTARG\fP.
-When an illegal option or a missing option argument is
-encountered a question mark or a colon is placed in \fIname\fP
-(indicating an illegal option or missing argument, respectively)
-and \fBOPTARG\fP is set to the option character that caused the problem.
-An error message is also printed to standard error if \fIoptstring\fP
-does not begin with a colon.
-.sp
-When the end of the options is encountered, \fBgetopts\fP exits with a
-non-zero exit status.
-Options end at the first (non-option argument) argument that does not
-start with a \-, or when a \fB\-\-\fP argument is encountered.
-.sp
-Option parsing can be reset by setting \fBOPTIND\fP to 1 (this is done
-automatically whenever the shell or a shell procedure is invoked).
-.sp
-Warning: Changing the value of the shell parameter \fBOPTIND\fP to
-a value other than 1, or parsing different sets of arguments without
-resetting \fBOPTIND\fP may lead to unexpected results.
-.\"}}}
-.\"{{{ hash [-r] [name ...]
-.IP "\fBhash\fP [\fB\-r\fP] [\fIname ...\fP]"
-Without arguments, any hashed executable command pathnames are listed.
-The \fB\-r\fP option causes all hashed commands to be removed
-from the hash table.
-Each \fIname\fP is searched as if it where a command name and added to the
-hash table if it is an executable command.
-.\"}}}
-.\"{{{ jobs [-lpn] [job ...]
-.IP "\fBjobs\fP [\fB\-lpn\fP] [\fIjob\fP ...]"
-Display information about the specified jobs; if no jobs are specified,
-all jobs are displayed.
-The \fB\-n\fP option causes information to be displayed only for jobs
-that have changed state since the last notification.
-If the \fB\-l\fP option is used, the process-id of each process in a job
-is also listed.
-The \fB\-p\fP option causes only the process group of each job to be printed.
-See Job Control below for the format of \fIjob\fP and the displayed job.
-.\"}}}
-.\"{{{ kill [-s signame | -signum | -signame] { job | pid | -pgrp } ...
-.IP "\fBkill\fP [\fB\-s\fP \fIsigname\fP | \fB\-signum\fP | \fB\-signame\fP ] { \fIjob\fP | \fIpid\fP | \fB\-\fP\fIpgrp\fP } ..."
-Send the specified signal to the specified jobs, process ids, or process groups.
-If no signal is specified, the signal TERM is sent.
-If a job is specified, the signal is sent to the job's process group.
-See Job Control below for the format of \fIjob\fP.
-.\"}}}
-.\"{{{ kill -l [exit-status ...]
-.IP "\fBkill \-l\fP [\fIexit-status\fP ...]"
-Print the name of the signal that killed a process which exited with
-the specified \fIexit-status\fPes.
-If no arguments are specified, a list of all the signals, their numbers and
-a short description of them are printed.
-.\"}}}
-.\"{{{ let [expression ...]
-.IP "\fBlet\fP [\fIexpression\fP ...]"
-Each expression is evaluated, see Arithmetic Expressions above.
-If all expressions are successfully evaluated, the exit status
-is 0 (1) if the last expression evaluated to non-zero (zero).
-If an error occurs during the parsing or evaluation of an expression,
-the exit status is greater than 1.
-Since expressions may need to be
-quoted, \fB((\fP \fIexpr\fP \fB))\fP is syntactic sugar for \fBlet
-"\fP\fIexpr\fP\fB"\fP.
-.\"}}}
-.\"{{{ print [-nprsun | -R [-en]] [argument ...]
-.IP "\fBprint\fP [\fB\-nprsu\fP\fIn\fP | \fB\-R\fP [\fB\-en\fP]] [\fIargument ...\fP]"
-\fBPrint\fP prints its arguments on the standard output, separated by
-spaces, and terminated with a newline. The \fB\-n\fP option suppresses
-the newline. By default, certain C escapes are translated. These
-include \eb, \ef, \en, \er, \et, \ev, and \e0### (# is an octal digit, of
-which there may be 0 to 3).
-\ec is equivalent to using the \fB\-n\fP option. \e expansion may be
-inhibited with the \fB\-r\fP option.
-The \fB\-s\fP option prints to the history file instead of standard output,
-the \fB\-u\fP option prints to file descriptor \fIn\fP (\fIn\fP
-defaults to 1 if omitted), and the \fB\-p\fP option prints to the co-process
-(see Co-Processes above).
-.sp
-The \fB\-R\fP option is used to emulate, to some degree, the BSD echo
-command, which does not process \e sequences unless the \fB\-e\fP option
-is given.
-As above, the \fB\-n\fP option suppresses the trailing newline.
-.\"}}}
-.\"{{{ pwd [-LP]
-.IP "\fBpwd\fP [\fB\-LP\fP]"
-Print the present working directory.
-If \fB\-L\fP option is used or if the \fBphysical\fP option
-(see \fBset\fP command below) isn't set, the logical path is printed
-(\fIi.e.\fP, the path used to \fBcd\fP to the current directory).
-If \fB\-P\fP option (physical path) is used or if the \fBphysical\fP option
-is set, the path determined from the filesystem (by following \fB..\fP
-directories to the root directory) is printed.
-.\"}}}
-.\"{{{ read [-prsun] [parameter ...]
-.IP "\fBread\fP [\fB\-prsu\fP\fIn\fP] [\fIparameter ...\fP]"
-Reads a line of input from standard input, separate the line into fields using
-the \fBIFS\fP parameter (see Substitution above), and assign each field to the
-specified parameters.
-If there are more parameters than fields, the extra parameters are set to null,
-or alternatively, if there are more fields than parameters, the last parameter
-is assigned the remaining fields (inclusive of any separating spaces).
-If no parameters are specified, the \fBREPLY\fP parameter is used.
-If the input line ends in a backslash and the \fB\-r\fP option was not used, the
-backslash and newline are stripped and more input is read.
-If no input is read, \fBread\fP exits with a non-zero status.
-.sp
-The first parameter may have a question mark and a string appended to it, in
-which case the string is used as a prompt (printed to standard error before
-any input is read) if the input is a tty
-(\fIe.g.\fP, \fBread nfoo?'number of foos: '\fP).
-.sp
-The \fB\-u\fP\fIn\fP and \fB\-p\fP options cause input to be read
-from file descriptor \fIn\fP or the current co-process (see Co-Processes above
-for comments on this), respectively.
-If the \fB\-s\fP option is used, input is saved to the history file.
-.\"}}}
-.\"{{{ readonly [-p] [parameter[=value] ...]
-.IP "\fBreadonly\fP [\fB\-p\fP] [\fIparameter\fP[\fB=\fP\fIvalue\fP]] ..."
-Sets the readonly attribute of the named parameters. If values are given,
-parameters are set to them before setting the attribute.
-Once a parameter is made readonly, it cannot be unset and its value cannot
-be changed.
-.sp
-If no parameters are specified, the names of all parameters with the readonly
-attribute are printed one per line, unless the \fB\-p\fP option is used,
-in which case \fBreadonly\fP commands defining all readonly
-parameters, including their values, are printed.
-.\"}}}
-.\"{{{ return [status]
-.IP "\fBreturn\fP [\fIstatus\fP]"
-Returns from a function or \fB.\fP script, with exit status \fIstatus\fP.
-If no \fIstatus\fP is given, the exit status of the last executed command
-is used.
-If used outside of a function or \fB.\fP script, it has the same effect
-as \fBexit\fP.
-Note that pdksh treats both profile and \fB$ENV\fP files as \fB.\fP scripts,
-while the original Korn shell only treats profiles as \fB.\fP scripts.
-.\"}}}
-.\"{{{ set [+-abCefhkmnpsuvxX] [+-o [option]] [+-A name] [--] [arg ...]
-.IP "\fBset\fP [\fB\(+-abCefhkmnpsuvxX\fP] [\fB\(+-o\fP [\fIoption\fP]] [\fB\(+-A\fP \fIname\fP] [\fB\-\-\fP] [\fIarg\fP ...]"
-The set command can be used to set (\fB\-\fP) or clear (\fB+\fP) shell options,
-set the positional parameters, or set an array parameter.
-Options can be changed using the \fB\(+-o\fP \fIoption\fP syntax,
-where \fIoption\fP is the long name of an option, or using
-the \fB\(+-\fP\fIletter\fP syntax, where \fIletter\fP is the
-option's single letter name (not all options have a single letter name).
-The following table lists both option letters (if they exist) and long names
-along with a description of what the option does.
-.sp
-.TS
-expand;
-afB lfB lw(3i).
-\-A T{
-Sets the elements of the array parameter \fIname\fP to \fIarg\fP ...;
-If \fB\-A\fP is used, the array is reset (\fIi.e.\fP, emptied) first;
-if \fB+A\fP is used, the first N elements are set (where N is the number
-of \fIarg\fPs), the rest are left untouched.
-T}
-\-a allexport T{
-all new parameters are created with the export attribute
-T}
-\-b notify T{
-Print job notification messages asynchronously, instead of just before the
-prompt.
-Only used if job control is enabled (\fB\-m\fP).
-T}
-\-C noclobber T{
-Prevent \fB>\fP redirection from overwriting existing files (\fB>|\fP must
-be used to force an overwrite).
-T}
-\-e errexit T{
-Exit (after executing the \fBERR\fP trap) as soon as an error occurs or
-a command fails (\fIi.e.\fP, exits with a non-zero status).
-This does not apply to commands whose exit status is explicitly tested by a
-shell construct such as \fBif\fP, \fBuntil\fP, \fBwhile\fP, \fB&&\fP or
-\fB||\fP statements.
-T}
-\-f noglob T{
-Do not expand file name patterns.
-T}
-\-h trackall T{
-Create tracked aliases for all executed commands (see Aliases above).
-On by default for non-interactive shells.
-T}
-\-i interactive T{
-Enable interactive mode \- this can only be set/unset when the shell is
-invoked.
-T}
-\-k keyword T{
-Parameter assignments are recognized anywhere in a command.
-T}
-\-l login T{
-The shell is a login shell \- this can only be set/unset when the shell is
-invoked (see Shell Startup above).
-T}
-\-m monitor T{
-Enable job control (default for interactive shells).
-T}
-\-n noexec T{
-Do not execute any commands \- useful for checking the syntax of scripts
-(ignored if interactive).
-T}
-\-p privileged T{
-Set automatically if, when the shell starts, the read uid or gid does not
-match the effective uid or gid, respectively.
-See Shell Startup above for a description of what this
-means.
-T}
--r restricted T{
-Enable restricted mode \(em this option can only be used when the shell is
-invoked. See Shell Startup above for a description of what this
-means.
-T}
-\-s stdin T{
-If used when the shell is invoked, commands are read from standard input.
-Set automatically if the shell is invoked with no arguments.
-.sp
-When \fB\-s\fP is used in the \fBset\fP command, it causes the specified
-arguments to be sorted before assigning them to the positional parameters
-(or to array \fIname\fP, if \fB\-A\fP is used).
-T}
-\-u nounset T{
-Referencing of an unset parameter is treated as an error, unless
-one of the \fB\-\fP, \fB+\fP or \fB=\fP modifiers is used.
-T}
-\-v verbose T{
-Write shell input to standard error as it is read.
-T}
-\-x xtrace T{
-Print commands and parameter assignments when they are executed,
-preceded by the value of \fBPS4\fP.
-T}
-\-X markdirs T{
-Mark directories with a trailing \fB/\fP during file name generation.
-T}
- bgnice T{
-Background jobs are run with lower priority.
-T}
- braceexpand T{
-Enable brace expansion (aka, alternation).
-T}
- emacs T{
-Enable BRL emacs-like command line editing (interactive shells only);
-see Emacs Interactive Input Line Editing.
-T}
- gmacs T{
-Enable gmacs-like (Gosling emacs) command line editing (interactive shells
-only);
-currently identical to emacs editing except that transpose (^T) acts
-slightly differently.
-T}
- ignoreeof T{
-The shell will not exit on when end-of-file is read, \fBexit\fP must be used.
-T}
- nohup T{
-Do not kill running jobs with a \fBHUP\fP signal when a login shell exists.
-Currently set by default, but this will change in the future to be compatible
-with the original Korn shell (which doesn't have this option, but does
-send the \fBHUP\fP signal).
-T}
- nolog T{
-No effect \- in the original Korn shell, this prevents function definitions
-from being stored in the history file.
-T}
- physical T{
-Causes the \fBcd\fP and \fBpwd\fP commands to use `physical'
-(\fIi.e.\fP, the filesystem's) \fB..\fP directories instead of `logical'
-directories (\fIi.e.\fP, the shell handles \fB..\fP, which allows the user
-to be obliveous of symlink links to directories).
-Clear by default. Note that setting
-this option does not effect the current value of the \fBPWD\fP parameter;
-only the \fBcd\fP command changes \fBPWD\fP.
-See the \fBcd\fP and \fBpwd\fP commands above for more details.
-T}
- posix T{
-Enable posix mode. See POSIX Mode above.
-T}
- vi T{
-Enable vi-like command line editing (interactive shells only).
-T}
- viraw T{
-No effect \- in the original Korn shell, unless viraw was set, the vi command
-line mode would let the tty driver do the work until ESC (^[) was entered.
-pdksh is always in viraw mode.
-T}
- vi-esccomplete T{
-In vi command line editing, do command / file name completion when
-escape (^[) is entered in command mode.
-T}
- vi-show8 T{
-Prefix characters with the eighth bit set with `M-'.
-If this option is not set, characters in the range
-128-160 are printed as is, which may cause problems.
-T}
- vi-tabcomplete T{
-In vi command line editing, do command / file name completion when
-tab (^I) is entered in insert mode.
-T}
-.TE
-.sp
-These options can also be used upon invocation of the shell. The current
-set of options (with single letter names) can be found in the
-parameter \fB\-\fP.
-\fBset -o\fP with no option name will list all the options and whether each
-is on or off; \fBset +o\fP will print the long names of all options that
-are currently on.
-.sp
-Remaining arguments, if any, are positional parameters and are assigned,
-in order, to the
-positional parameters (\fIi.e.\fP, \fB1\fP, \fB2\fP, \fIetc.\fP).
-If options are ended with \fB\-\-\fP and there are no remaining arguments,
-all positional parameters are cleared.
-If no options or arguments are given, then the values of all names are printed.
-For unknown historical reasons, a lone \fB\-\fP option is treated specially:
-it clears both the \fB\-x\fP and \fB\-v\fP options.
-.\"}}}
-.\"{{{ shift [number]
-.IP "\fBshift\fP [\fInumber\fP]"
-The positional parameters \fInumber\fP+1, \fInumber\fP+2 \fIetc.\fP\& are
-renamed to \fB1\fP, \fB2\fP, \fIetc.\fP
-\fInumber\fP defaults to 1.
-.\"}}}
-.\"{{{ test expression, [ expression ]
-.IP "\fBtest\fP \fIexpression\fP"
-.IP "\fB[\fP \fIexpression\fP \fB]\fP"
-\fBtest\fP evaluates the \fIexpression\fP and returns zero status if
-true, and 1 status if false and greater than 1 if there was an error.
-It is normally used as the
-condition command of \fBif\fP and \fBwhile\fP statements.
-The following basic expressions are available:
-.sp
-.TS
-afB ltw(2.8i).
-\fIstr\fP T{
-\fIstr\fP has non-zero length. Note that there is the potential
-for problems if \fIstr\fP turns out to be an operator (\fIe.g.\fP, \fB-r\fP)
-- it is generally better to use a test like
-.RS
-\fB[ X"\fP\fIstr\fP\fB" != X ]\fP
-.RE
-instead (double quotes are used in case \fIstr\fP contains spaces or file
-globing characters).
-T}
-\-r \fIfile\fP T{
-\fIfile\fP exists and is readable
-T}
-\-w \fIfile\fP T{
-\fIfile\fP exists and is writable
-T}
-\-x \fIfile\fP T{
-\fIfile\fP exists and is executable
-T}
-\-a \fIfile\fP T{
-\fIfile\fP exists
-T}
-\-e \fIfile\fP T{
-\fIfile\fP exists
-T}
-\-f \fIfile\fP T{
-\fIfile\fP is a regular file
-T}
-\-d \fIfile\fP T{
-\fIfile\fP is a directory
-T}
-\-c \fIfile\fP T{
-\fIfile\fP is a character special device
-T}
-\-b \fIfile\fP T{
-\fIfile\fP is a block special device
-T}
-\-p \fIfile\fP T{
-\fIfile\fP is a named pipe
-T}
-\-u \fIfile\fP T{
-\fIfile\fP's mode has setuid bit set
-T}
-\-g \fIfile\fP T{
-\fIfile\fP's mode has setgid bit set
-T}
-\-k \fIfile\fP T{
-\fIfile\fP's mode has sticky bit set
-T}
-\-s \fIfile\fP T{
-\fIfile\fP is not empty
-T}
-\-O \fIfile\fP T{
-\fIfile\fP's owner is the shell's effective user-ID
-T}
-\-G \fIfile\fP T{
-\fIfile\fP's group is the shell's effective group-ID
-T}
-\-h \fIfile\fP T{
-\fIfile\fP is a symbolic link
-T}
-\-H \fIfile\fP T{
-\fIfile\fP is a context dependent directory (only useful on HP-UX)
-T}
-\-L \fIfile\fP T{
-\fIfile\fP is a symbolic link
-T}
-\-S \fIfile\fP T{
-\fIfile\fP is a socket
-T}
-\-o \fIoption\fP T{
-shell \fIoption\fP is set (see \fBset\fP command above for list of options).
-As a non-standard extension, if the option starts with a \fB!\fP, the test
-is negated; the test always fails if option doesn't exist (thus
-.RS
-\fB[ -o \fP\fIfoo\fP \fB-o -o !\fP\fIfoo\fP \fB]\fP
-.RE
-returns true if and only if option \fIfoo\fP exists).
-T}
-\fIfile\fP \-nt \fIfile\fP T{
-first \fIfile\fP is newer than second \fIfile\fP
-T}
-\fIfile\fP \-ot \fIfile\fP T{
-first \fIfile\fP is older than second \fIfile\fP
-T}
-\fIfile\fP \-ef \fIfile\fP T{
-first \fIfile\fP is the same file as second \fIfile\fP
-T}
-\-t [\fIfd\fP] T{
-file descriptor is a tty device.
-Default value of \fIfd\fP is 1.
-T}
-\fIstring\fP T{
-\fIstring\fP is not empty
-T}
-\-z \fIstring\fP T{
-\fIstring\fP is empty
-T}
-\-n \fIstring\fP T{
-\fIstring\fP is not empty
-T}
-\fIstring\fP = \fIstring\fP T{
-strings are equal
-T}
-\fIstring\fP == \fIstring\fP T{
-strings are equal
-T}
-\fIstring\fP != \fIstring\fP T{
-strings are not equal
-T}
-\fInumber\fP \-eq \fInumber\fP T{
-numbers compare equal
-T}
-\fInumber\fP \-ne \fInumber\fP T{
-numbers compare not equal
-T}
-\fInumber\fP \-ge \fInumber\fP T{
-numbers compare greater than or equal
-T}
-\fInumber\fP \-gt \fInumber\fP T{
-numbers compare greater than
-T}
-\fInumber\fP \-le \fInumber\fP T{
-numbers compare less than or equal
-T}
-\fInumber\fP \-lt \fInumber\fP T{
-numbers compare less than
-T}
-.TE
-.sp
-The above basic expressions, in which unary operators have precedence over
-binary operators, may be combined with the following operators
-(listed in increasing order of precedence):
-.sp
-.TS
-afB l.
-\fIexpr\fP \-o \fIexpr\fP logical or
-\fIexpr\fP \-a \fIexpr\fP logical and
-! \fIexpr\fP logical not
-( \fIexpr\fP ) grouping
-.TE
-.sp
-On operating systems not supporting \fB/dev/fd/\fP\fIn\fP devices
-(where \fIn\fP is a file descriptor number),
-the \fBtest\fP command will attempt to fake it for all tests that
-operate on files (except the \fB-e\fP test).
-I.e., \fB[ -w /dev/fd/2 ]\fP tests if file descriptor 2 is writable.
-.sp
-Note that some special rules are applied (courtesy of POSIX) if the
-number of arguments to \fBtest\fP or \fB[\fP \&... \fB]\fP is less than
-five: if leading \fB!\fP arguments can be stripped such that only one
-argument remains then a string length test is performed (again, even if
-the argument is a unary operator);
-if leading \fB!\fP arguments can be stripped such that three
-arguments remain and the second argument is a binary operator, then the
-binary operation is performed (even if first argument is a unary
-operator, including an unstripped \fB!\fP).
-.sp
-\fBNote:\fP A common mistake is to use \fBif [ $foo = bar ]\fP which
-fails if parameter \fBfoo\fP is null or unset, if it has embedded spaces
-(\fIi.e.\fP, \fBIFS\fP characters), or if it is a unary operator like \fB!\fP or
-\fB\-n\fP. Use tests like \fBif [ "X$foo" = Xbar ]\fP instead.
-.\"}}}
-.\"{{{ times
-.IP \fBtimes\fP
-Print the accumulated user and system times used by the shell and by
-processes which have exited that the shell started.
-.\"}}}
-.\"{{{ trap [handler signal ...]
-.IP "\fBtrap\fP [\fIhandler\fP \fIsignal ...\fP]"
-Sets trap handler that is to be executed when any of the specified signals
-are received.
-\fBHandler\fP is either a null string, indicating the signals are to
-be ignored, a minus (\fB\-\fP), indicating that the default action is to
-be taken for the signals (see signal(2 or 3)), or a string containing shell
-commands to be evaluated and executed at the first opportunity (\fIi.e.\fP,
-when the current command completes, or before printing the next \fBPS1\fP
-prompt) after receipt of one of the signals.
-\fBSignal\fP is the name of a signal (\fIe.g.\fP, PIPE or ALRM) or the number
-of the signal (see \fBkill \-l\fP command above).
-There are two special signals: \fBEXIT\fP (also known as \fB0\fP), which
-is executed when the shell is about to exit, and \fBERR\fP which is
-executed after an error occurs (an error is something that would cause
-the shell to exit if the \fB\-e\fP or \fBerrexit\fP option were set \(em
-see \fBset\fP command above).
-\fBEXIT\fP handlers are executed in the environment of the last executed
-command.
-Note that for non-interactive shells, the trap handler cannot be changed for
-signals that were ignored when the shell started.
-.sp
-With no arguments, \fBtrap\fP lists, as a series of \fBtrap\fP commands,
-the current state of the traps that have been set since the shell started.
-.sp
-.\" todo: add these features (trap DEBUG, trap ERR/EXIT in function)
-The original Korn shell's \fBDEBUG\fP trap and the handling of \fBERR\fP and
-\fBEXIT\fP traps in functions are not yet implemented.
-.\"}}}
-.\"{{{ true
-.IP \fBtrue\fP
-A command that exits with a zero value.
-.\"}}}
-.\"{{{ typeset [[+-Ulrtux] [-L[n]] [-R[n]] [-Z[n]] [-i[n]] | -f [-tux]] [name[=value] ...]
-.IP "\fBtypeset\fP [[\(+-Ulrtux] [\fB\-L\fP[\fIn\fP]] [\fB\-R\fP[\fIn\fP]] [\fB\-Z\fP[\fIn\fP]] [\fB\-i\fP[\fIn\fP]] | \fB\-f\fP [\fB\-tux\fP]] [\fIname\fP[\fB=\fP\fIvalue\fP] ...]"
-Display or set parameter attributes.
-With no \fIname\fP arguments, parameter attributes are displayed: if no options
-arg used, the current attributes of all parameters are printed as typeset
-commands; if an option is given (or \fB\-\fP with no option letter)
-all parameters and their values with the specified attributes are printed;
-if options are introduced with \fB+\fP, parameter values are not printed.
-.sp
-If \fIname\fP arguments are given, the attributes of the named parameters
-are set (\fB\-\fP) or cleared (\fB+\fP).
-Values for parameters may optionally be specified.
-If typeset is used inside a function, any newly created parameters are local
-to the function.
-.sp
-When \fB\-f\fP is used, typeset operates on the attributes of functions.
-As with parameters, if no \fIname\fPs are given, functions are listed
-with their values (\fIi.e.\fP, definitions) unless options are introduced with
-\fB+\fP, in which case only the function names are reported.
-.sp
-.TS
-expand;
-afB lw(4.5i).
-\-L\fIn\fP T{
-Left justify attribute: \fIn\fP specifies the field width.
-If \fIn\fP is not specified, the current width of a parameter (or the
-width of its first assigned value) is used.
-Leading white space (and zeros, if used with the \fB\-Z\fP option) is stripped.
-If necessary, values are either truncated or space padded to fit the
-field width.
-T}
-\-R\fIn\fP T{
-Right justify attribute: \fIn\fP specifies the field width.
-If \fIn\fP is not specified, the current width of a parameter (or the
-width of its first assigned value) is used.
-Trailing white space are stripped.
-If necessary, values are either stripped of leading characters
-or space padded to make them fit the field width.
-T}
-\-Z\fIn\fP T{
-Zero fill attribute: if not combined with \fB\-L\fP, this is the
-same as \fB\-R\fP, except zero padding is used instead of space padding.
-T}
-\-i\fIn\fP T{
-integer attribute:
-\fIn\fP specifies the base to use when displaying the integer
-(if not specified, the base given in the first assignment is used).
-Parameters with this attribute may be assigned values containing
-arithmetic expressions.
-T}
-\-U T{
-unsigned integer attribute: integers are printed as unsigned values
-(only useful when combined with the \fB\-i\fP option).
-This option is not in the original Korn shell.
-T}
-\-f T{
-Function mode: display or set functions and their attributes, instead of
-parameters.
-T}
-\-l T{
-Lower case attribute: all upper case characters in values are converted to
-lower case.
-(In the original Korn shell, this parameter meant `long integer' when used
-with the \fB\-i\fP option).
-T}
-\-r T{
-Readonly attribute: parameters with the this attribute may not be assigned to
-or unset.
-Once this attribute is set, it can not be turned off.
-T}
-\-t T{
-Tag attribute: has no meaning to the shell; provided for application use.
-.sp
-For functions, \fB\-t\fP is the trace attribute.
-When functions with the trace attribute are executed, the \fBxtrace\fP (\fB\-x\fP) shell option is temporarily turned on.
-T}
-\-u T{
-Upper case attribute: all lower case characters in values are converted to
-upper case.
-(In the original Korn shell, this parameter meant `unsigned integer' when used
-with the \fB\-i\fP option, which meant upper case letters would never be used
-for bases greater than 10. See the \fB\-U\fP option).
-.sp
-For functions, \fB\-u\fP is the undefined attribute. See Functions above
-for the implications of this.
-T}
-\-x T{
-Export attribute: parameters (or functions) are placed in the environment of
-any executed commands. Exported functions are not implemented yet.
-T}
-.TE
-.\"}}}
-.\"{{{ ulimit [-acdfHlmnpsStvw] [value]
-.IP "\fBulimit\fP [\fB\-acdfHlmnpsStvw\fP] [\fIvalue\fP]"
-Display or set process limits.
-If no options are used, the file size limit (\fB\-f\fP) is assumed.
-\fBvalue\fP, if specified, may be either be an arithmetic expression or the
-word \fBunlimited\fP.
-The limits affect the shell and any processes created by the shell after
-a limit is imposed.
-Note that some systems may not allow limits to be increased once they
-are set.
-Also note that the types of limits available are system dependent \- some
-systems have only the \fB\-f\fP limit.
-.RS
-.IP \fB\-a\fP
-Displays all limits; unless \fB\-H\fP is used, soft limits are displayed.
-.IP \fB\-H\fP
-Set the hard limit only (default is to set both hard and soft limits).
-.IP \fB\-S\fP
-Set the soft limit only (default is to set both hard and soft limits).
-.IP \fB\-c\fP
-Impose a size limit of \fIn\fP blocks on the size of core dumps.
-.IP \fB\-d\fP
-Impose a size limit of \fIn\fP kbytes on the size of the data area.
-.IP \fB\-f\fP
-Impose a size limit of \fIn\fP blocks on files written by the shell and
-its child processes (files of any size may be read).
-.IP \fB\-l\fP
-Impose a limit of \fIn\fP kbytes on the amount of locked (wired) physical
-memory.
-.IP \fB\-m\fP
-Impose a limit of \fIn\fP kbytes on the amount of physical memory used.
-.IP \fB\-n\fP
-Impose a limit of \fIn\fP file descriptors that can be open at once.
-.IP \fB\-p\fP
-Impose a limit of \fIn\fP processes that can be run by the user at any one
-time.
-.IP \fB\-s\fP
-Impose a size limit of \fIn\fP kbytes on the size of the stack area.
-.IP \fB\-t\fP
-Impose a time limit of \fIn\fP cpu seconds to be used by each process.
-.IP \fB\-v\fP
-Impose a limit of \fIn\fP kbytes on the amount of virtual memory used;
-on some systems this is the maximum allowable virtual address (in bytes,
-not kbytes).
-.IP \fB\-w\fP
-Impose a limit of \fIn\fP kbytes on the amount of swap space used.
-.PP
-As far as \fBulimit\fP is concerned, a block is 512 bytes.
-.RE
-.\"}}}
-.\"{{{ umask [-S] [mask]
-.IP "\fBumask\fP [\fB\-S\fP] [\fImask\fP]"
-.RS
-Display or set the file permission creation mask, or umask (see \fIumask\fP(2)).
-If the \fB\-S\fP option is used, the mask displayed or set is symbolic,
-otherwise it is an octal number.
-.sp
-Symbolic masks are like those used by \fIchmod\fP(1):
-.RS
-[\fBugoa\fP]{{\fB=+-\fP}{\fBrwx\fP}*}+[\fB,\fP...]
-.RE
-in which the first group of characters is the \fIwho\fP part, the second
-group is the \fIop\fP part, and the last group is the \fIperm\fP part.
-The \fIwho\fP part specifies which part of the umask is to be modified.
-The letters mean:
-.RS
-.IP \fBu\fP
-the user permissions
-.IP \fBg\fP
-the group permissions
-.IP \fBo\fP
-the other permissions (non-user, non-group)
-.IP \fBa\fP
-all permissions (user, group and other)
-.RE
-.sp
-The \fIop\fP part indicates how the \fIwho\fP permissions are to be modified:
-.RS
-.IP \fB=\fP
-set
-.IP \fB+\fP
-added to
-.IP \fB\-\fP
-removed from
-.RE
-.sp
-The \fIperm\fP part specifies which permissions are to be set, added or removed:
-.RS
-.IP \fBr\fP
-read permission
-.IP \fBw\fP
-write permission
-.IP \fBx\fP
-execute permission
-.RE
-.sp
-When symbolic masks are used, they describe what permissions may
-be made available (as opposed to octal masks in which a set bit means
-the corresponding bit is to be cleared).
-Example: `ug=rwx,o=' sets the mask so files will not be readable, writable
-or executable by `others', and is equivalent (on most systems) to the octal
-mask `07'.
-.RE
-.\"}}}
-.\"{{{ unalias [-adt] name ...
-.IP "\fBunalias\fP [\fB\-adt\fP] [\fIname1\fP ...]"
-The aliases for the given names are removed.
-If the \fB\-a\fP option is used, all aliases are removed.
-If the \fB\-t\fP or \fB\-d\fP options are used, the indicated operations
-are carried out on tracked or directory aliases, respectively.
-.\"}}}
-.\"{{{ unset [-fv] parameter ...
-.IP "\fBunset\fP [\fB\-fv\fP] \fIparameter\fP ..."
-Unset the named parameters (\fB\-v\fP, the default) or functions (\fB\-f\fP).
-The exit status is non-zero if any of the parameters were already unset,
-zero otherwise.
-.\"}}}
-.\"{{{ wait [job]
-.IP "\fBwait\fP [\fIjob\fP]"
-Wait for the specified job(s) to finish.
-The exit status of wait is that of the last specified job:
-if the last job is killed by a signal, the exit status is 128 + the
-number of the signal (see \fBkill \-l\fP \fIexit-status\fP above); if the last
-specified job can't be found (because it never existed, or had already
-finished), the exit status of wait is 127.
-See Job Control below for the format of \fIjob\fP.
-\fBWait\fP will return if a signal for which a trap has been set is received,
-or if a HUP, INT or QUIT signal is received.
-.sp
-If no jobs are specified, \fBwait\fP waits for all currently running jobs
-(if any) to finish and exits with a zero status.
-If job monitoring is enabled, the completion status of jobs is
-printed (this is not the case when jobs are explicitly specified).
-.\"}}}
-.\"{{{ whence [-pv] [name ...]
-.IP "\fBwhence\fP [\fB\-pv\fP] [name ...]"
-For each name, the type of command is listed (reserved word, built-in, alias,
-function, tracked alias or executable).
-If the \fB\-p\fP option is used, a path search done even if \fIname\fP
-is a reserved word, alias, \fIetc.\fP
-Without the \fB\-v\fP option, \fBwhence\fP is similar to \fBcommand \-v\fP
-except that \fBwhence\fP will find reserved words and won't print aliases
-as alias commands;
-with the \fB\-v\fP option, \fBwhence\fP is the same as \fBcommand \-V\fP.
-Note that for \fBwhence\fP, the \fB\-p\fP option does not affect the search
-path used, as it does for \fBcommand\fP.
-If the type of one or more of the names could not be determined, the
-exit status is non-zero.
-.\"}}}
-.\"}}}
-.\"{{{ job control (and its built-in commands)
-.SS "Job Control"
-Job control refers to the shell's ability to monitor and control \fBjobs\fP,
-which are processes or groups of processes created for commands or pipelines.
-At a minimum, the shell keeps track of the status of the background
-(\fIi.e.\fP, asynchronous) jobs that currently exist; this information can be
-displayed using the \fBjobs\fP command.
-If job control is fully enabled (using \fBset \-m\fP or
-\fBset \-o monitor\fP), as it is for interactive shells,
-the processes of a job are placed in their own process group,
-foreground jobs can be stopped by typing the suspend character from the
-terminal (normally ^Z),
-jobs can be restarted in either the foreground
-or background, using the \fBfg\fP and \fBbg\fP commands, respectively,
-and the state of the terminal is saved or restored when a foreground
-job is stopped or restarted, respectively.
-.sp
-Note that only commands that create processes (\fIe.g.\fP,
-asynchronous commands, subshell commands, and non-built-in,
-non-function commands) can be stopped; commands like \fBread\fP cannot be.
-.sp
-When a job is created, it is assigned a job-number.
-For interactive shells, this number is printed inside \fB[\fP..\fB]\fP,
-followed by the process-ids of the processes in the job when an asynchronous
-command is run.
-A job may be referred to in \fBbg\fP, \fBfg\fP, \fBjobs\fP, \fBkill\fP and
-\fBwait\fP commands either by the process id of the last process in the
-command pipeline (as stored in the \fB$!\fP parameter) or by prefixing the
-job-number with a percent sign (\fB%\fP).
-Other percent sequences can also be used to refer to jobs:
-.sp
-.TS
-expand;
-afB lw(4.5i).
-%+ T{
-The most recently stopped job, or, if there are no stopped jobs, the oldest
-running job.
-T}
-%%\fR, \fP% T{
-Same as \fB%+\fP.
-T}
-%\- T{
-The job that would be the \fB%+\fP job, if the later did not exist.
-T}
-%\fIn\fP T{
-The job with job-number \fIn\fP.
-T}
-%?\fIstring\fP T{
-The job containing the string \fIstring\fP (an error occurs if multiple jobs
-are matched).
-T}
-%\fIstring\fP T{
-The job starting with string \fIstring\fP (an error occurs if multiple jobs
-are matched).
-T}
-.TE
-.sp
-When a job changes state (\fIe.g.\fP, a background job finishes or foreground
-job is stopped), the shell prints the following status information:
-.RS
-\fB[\fP\fInumber\fP\fB]\fP \fIflag status command\fP
-.RE
-where
-.IP "\ \fInumber\fP"
-is the job-number of the job.
-.IP "\ \fIflag\fP"
-is \fB+\fP or \fB-\fP if the job is the \fB%+\fP or \fB%-\fP job,
-respectively, or space if it is neither.
-.IP "\ \fIstatus\fP"
-indicates the current state of the job and can be
-.RS
-.IP "\fBRunning\fP"
-the job has neither stopped or exited (note that running does not
-necessarily mean consuming CPU time \(em the process could be blocked waiting
-for some event).
-.IP "\fBDone\fP [\fB(\fP\fInumber\fP\fB)\fP]"
-the job exited. \fInumber\fP is the exit status of the job, which is
-omitted if the status is zero.
-.IP "\fBStopped\fP [\fB(\fP\fIsignal\fP\fB)\fP]"
-the job was stopped by the indicated \fIsignal\fP (if no signal is given,
-the job was stopped by SIGTSTP).
-.IP "\fIsignal-description\fP [\fB(core dumped)\fP]"
-the job was killed by a signal (\fIe.g.\fP, Memory\ fault,
-Hangup, \fIetc.\fP \(em use
-\fBkill \-l\fP for a list of signal descriptions).
-The \fB(core\ dumped)\fP message indicates the process created a core file.
-.RE
-.IP "\ \fIcommand\fP"
-is the command that created the process.
-If there are multiple processes in the job, then each process will
-have a line showing its \fIcommand\fP and possibly its \fIstatus\fP,
-if it is different from the status of the previous process.
-.PP
-When an attempt is made to exit the shell while there are jobs in
-the stopped state, the shell warns the user that there are stopped jobs
-and does not exit.
-If another attempt is immediately made to exit the shell, the stopped
-jobs are sent a \fBHUP\fP signal and the shell exits.
-Similarly, if the \fBnohup\fP option is not set and there are running
-jobs when an attempt is made to exit a login shell, the shell warns the
-user and does not exit.
-If another attempt is immediately made to exit the shell, the running
-jobs are sent a \fBHUP\fP signal and the shell exits.
-.\"}}}
-.\"{{{ Emacs Interactive Input Line Editing
-.SS "Emacs Interactive Input Line Editing"
-When the \fBemacs\fP option is set, interactive input line editing is
-enabled. \fBWarning\fP: This mode is slightly different from the emacs
-mode in the original Korn shell and the 8th bit is stripped in emacs mode.
-In this mode various editing commands (typically bound to one or more
-control characters) cause immediate actions without waiting for a
-new-line. Several editing commands are bound to particular control
-characters when the shell is invoked; these bindings can be changed
-using the following commands:
-.\"{{{ bind
-.IP \fBbind\fP
-The current bindings are listed.
-.\"}}}
-.\"{{{ bind string=[editing-command]
-.IP "\fBbind\fP \fIstring\fP\fB=\fP[\fIediting-command\fP]"
-The specified editing command is bound to the given \fBstring\fP, which
-should consist of a control character (which may be written using caret
-notation \fB^\fP\fIX\fP), optionally preceded by one of the two prefix
-characters. Future input of the \fIstring\fP will cause the editing
-command to be immediately invoked. Note that although only two prefix
-characters (usually ESC and ^X) are supported, some multi-character
-sequences can be supported. The following binds the arrow keys on
-an ANSI terminal, or xterm (these are in the default bindings). Of course
-some escape sequences won't work out quite this nicely:
-.sp
-.RS
-\fBbind '^[['=prefix\-2
-.br
-bind '^XA'=up\-history
-.br
-bind '^XB'=down\-history
-.br
-bind '^XC'=forward\-char
-.br
-bind '^XD'=backward\-char\fP
-.RE
-.\"}}}
-.\"{{{ bind -l
-.IP "\fBbind \-l\fP"
-Lists the names of the functions to which keys may be bound.
-.\"}}}
-.\"{{{ bind -m string=[substitute]
-.IP "\fBbind \-m\fP \fIstring\fP\fB=\fP[\fIsubstitute\fP]"
-The specified input \fIstring\fP will afterwards be immediately
-replaced by the given \fIsubstitute\fP string, which may contain
-editing commands.
-.\"}}}
-.PP
-The following is a list of editing commands available.
-Each description starts with the name of the command,
-a \fIn\fP, if the command can be prefixed with a count,
-and any keys the command is bound to by default (written using
-caret notation, \fIe.g.\fP, ASCII ESC character is written as ^[).
-A count prefix for a command is entered using the sequence
-\fB^[\fP\fIn\fP, where \fIn\fP is a sequence of 1 or more digits;
-unless otherwise specified, if a count is omitted, it defaults to 1.
-Note that editing command names are
-used only with the \fBbind\fP command. Furthermore, many editing
-commands are useful only on terminals with a visible cursor. The
-default bindings were chosen to resemble corresponding EMACS key
-bindings. The users tty characters (\fIe.g.\fP, ERASE) are bound to
-reasonable substitutes and override the default bindings.
-.\"{{{ abort ^G
-.IP "\fBabort ^G\fP"
-Useful as a response to a request for a \fBsearch-history\fP pattern in
-order to abort the search.
-.\"}}}
-.\"{{{ auto-insert n
-.IP "\fBauto-insert\fP \fIn\fP"
-Simply causes the character to appear as literal input. Most ordinary
-characters are bound to this.
-.\"}}}
-.\"{{{ backward-char n ^B
-.IP "\fBbackward-char\fP \fIn\fP \fB^B\fP"
-Moves the cursor backward \fIn\fP characters.
-.\"}}}
-.\"{{{ backward-word n ^[B
-.IP "\fBbackward-word\fP \fIn\fP \fB^[B\fP"
-Moves the cursor backward to the beginning of a word; words consist
-of alphanumerics, underscore (_) and dollar ($).
-.\"}}}
-.\"{{{ beginning-of-history ^[<
-.IP "\fBbeginning-of-history ^[<\fP"
-Moves to the beginning of the history.
-.\"}}}
-.\"{{{ beginning-of-line ^A
-.IP "\fBbeginning-of-line ^A\fP"
-Moves the cursor to the beginning of the edited input line.
-.\"}}}
-.\"{{{ capitalize-word n ^[c, ^[C
-.IP "\fBcapitalize-word\fP \fIn\fP \fB^[c\fP, \fB^[C\fP"
-Uppercase the first character in the next \fIn\fP words,
-leaving the cursor past the end of the last word.
-.\"}}}
-.\"{{{ comment ^[#
-If the current line does not begin with a comment character, one
-is added at the beginning of the line and the line is entered (as if
-return had been pressed), otherwise the existing comment characters
-are removed and the cursor is placed at the beginning of the line.
-.\"}}}
-.\"{{{ complete ^[^[
-.IP "\fBcomplete ^[^[\fP"
-Automatically completes as much as is unique of the command name
-or the file name containing the cursor. If the entire remaining command
-or file name is unique a space is printed after its completion, unless
-it is a directory name in which case \fB/\fP is appended. If there is
-no command or file name with the current partial word as its
-prefix, a bell character is output (usually causing a audio beep).
-.\"}}}
-.\"{{{ complete-command ^X^[
-.IP "\fBcomplete-command ^X^[\fP"
-Automatically completes as much as is unique of the command name
-having the partial word up to the cursor as its prefix, as in the
-\fBcomplete\fP command described above.
-.\"}}}
-.\"{{{ complete-file ^[^X
-.IP "\fBcomplete-file ^[^X\fP"
-Automatically completes as much as is unique of the file name having
-the partial word up to the cursor as its prefix, as in the
-\fBcomplete\fP command described above.
-.\"}}}
-.\"{{{ complete-list ^[=
-.IP "\fBcomplete-list ^[=\fP"
-List the possible completions for the current word.
-.\"}}}
-.\"{{{ delete-char-backward n ERASE, ^?, ^H
-.IP "\fBdelete-char-backward\fP \fIn\fP \fBERASE\fP, \fB^?\fP, \fB^H\fP"
-Deletes \fIn\fP characters before the cursor.
-.\"}}}
-.\"{{{ delete-char-forward n
-.IP "\fBdelete-char-forward\fP \fIn\fP"
-Deletes \fIn\fP characters after the cursor.
-.\"}}}
-.\"{{{ delete-word-backward n ^[ERASE, ^[^?, ^[^H, ^[h
-.IP "\fBdelete-word-backward\fP \fIn\fP \fB^[ERASE\fP, \fB^[^?\fP, \fB^[^H\fP, \fB^[h\fP"
-Deletes \fIn\fP words before the cursor.
-.\"}}}
-.\"{{{ delete-word-forward n ^[d
-.IP "\fBdelete-word-forward\fP \fIn\fP \fB^[d\fP"
-Deletes characters after the cursor up to the end of \fIn\fP words.
-.\"}}}
-.\"{{{ down-history n ^N
-.IP "\fBdown-history\fP \fIn\fP \fB^N\fP"
-Scrolls the history buffer forward \fIn\fP lines (later). Each input line
-originally starts just after the last entry in the history buffer, so
-\fBdown-history\fP is not useful until either \fBsearch-history\fP or
-\fBup-history\fP has been performed.
-.\"}}}
-.\"{{{ downcase-word n ^[L, ^[l
-.IP "\fBdowncase-word\fP \fIn\fP \fB^[L\fP, \fB^[l\fP"
-Lowercases the next \fIn\fP words.
-.\"}}}
-.\"{{{ end-of-history ^[>
-.IP "\fBend-of-history ^[>\fP"
-Moves to the end of the history.
-.\"}}}
-.\"{{{ end-of-line ^E
-.IP "\fBend-of-line ^E\fP"
-Moves the cursor to the end of the input line.
-.\"}}}
-.\"{{{ eot ^_
-.IP "\fBeot ^_\fP"
-Acts as an end-of-file; this is useful because edit-mode input disables
-normal terminal input canonicalization.
-.\"}}}
-.\"{{{ eot-or-delete n ^D
-.IP "\fBeot-or-delete\fP \fIn\fP \fB^D\fP"
-Acts as eot if alone on a line; otherwise acts as delete-char-forward.
-.\"}}}
-.\"{{{ error
-.IP "\fBerror\fP"
-Error (ring the bell).
-.\"}}}
-.\"{{{ exchange-point-and-mark ^X^X
-.IP "\fBexchange-point-and-mark ^X^X\fP"
-Places the cursor where the mark is, and sets the mark to where the
-cursor was.
-.\"}}}
-.\"{{{ expand-file ^[*
-.IP "\fBexpand-file ^[*\fP"
-Appends a * to the current word and replaces the word with
-the result of performing file globbing on the word.
-If no files match the pattern, the bell is rung.
-.\"}}}
-.\"{{{ forward-char n ^F
-.IP "\fBforward-char\fP \fIn\fP \fB^F\fP"
-Moves the cursor forward \fIn\fP characters.
-.\"}}}
-.\"{{{ forward-word n ^[f
-.IP "\fBforward-word\fP \fIn\fP \fB^[f\fP"
-Moves the cursor forward to the end of the \fIn\fPth word.
-.\"}}}
-.\"{{{ goto-history n ^[g
-.IP "\fBgoto-history\fP \fIn\fP \fB^[g\fP"
-Goes to history number \fIn\fP.
-.\"}}}
-.\"{{{ kill-line KILL
-.IP "\fBkill-line KILL\fP"
-Deletes the entire input line.
-.\"}}}
-.\"{{{ kill-region ^W
-.IP "\fBkill-region ^W\fP"
-Deletes the input between the cursor and the mark.
-.\"}}}
-.\"{{{ kill-to-eol n ^K
-.IP "\fBkill-to-eol\fP \fIn\fP \fB^K\fP"
-Deletes the input from the cursor to the end of the line if \fIn\fP is
-not specified, otherwise deletes characters between the cursor and
-column \fIn\fP.
-.\"}}}
-.\"{{{ list ^[?
-.IP "\fBlist ^[?\fP"
-Prints a sorted, columnated list of command names or file names
-(if any) that can complete the partial word containing the cursor.
-Directory names have \fB/\fP appended to them.
-.\"}}}
-.\"{{{ list-command ^X?
-.IP "\fBlist-command ^X?\fP"
-Prints a sorted, columnated list of command names (if any) that
-can complete the partial word containing the cursor.
-.\"}}}
-.\"{{{ list-file ^X^Y
-.IP "\fBlist-file ^X^Y\fP"
-Prints a sorted, columnated list of file names (if any) that can
-complete the partial word containing the cursor. File type indicators
-are appended as described under \fBlist\fP above.
-.\"}}}
-.\"{{{ newline ^J and ^M
-.IP "\fBnewline ^J\fP, \fB^M\fP"
-Causes the current input line to be processed by the shell. The
-current cursor position may be anywhere on the line.
-.\"}}}
-.\"{{{ newline-and-next ^O
-.IP "\fBnewline-and-next ^O\fP"
-Causes the current input line to be processed by the shell, and
-the next line from history becomes the current line. This is
-only useful after an up-history or search-history.
-.\"}}}
-.\"{{{ no-op QUIT
-.IP "\fBno-op QUIT\fP"
-This does nothing.
-.\"}}}
-.\"{{{ prefix-1 ^[
-.IP "\fBprefix-1 ^[\fP"
-Introduces a 2-character command sequence.
-.\"}}}
-.\"{{{ prefix-2 ^X and ^[[
-.IP "\fBprefix-2 ^X\fP"
-.IP "\fBprefix-2 ^[[\fP"
-Introduces a 2-character command sequence.
-.\"}}}
-.\"{{{ prev-hist-word ^[. ^[_
-.IP "\fBprev-hist-word\fP \fIn\fP \fB^[.\fP, \fB^[_\fP"
-The last (\fIn\fPth) word of the previous command is inserted at the cursor.
-.\"}}}
-.\"{{{ quote ^^
-.IP "\fBquote ^^\fP"
-The following character is taken literally rather than as an editing
-command.
-.\"}}}
-.\"{{{ redraw ^L
-.IP "\fBredraw ^L\fP"
-Reprints the prompt string and the current input line.
-.\"}}}
-.\"{{{ search-character-backward n ^[^]
-.IP "\fBsearch-character-backward\fP \fIn\fP \fB^[^]\fP"
-Search backward in the current line for the \fIn\fPth occurance of the
-next character typed.
-.\"}}}
-.\"{{{ search-character-forward n ^]
-.IP "\fBsearch-character-forward\fP \fIn\fP \fB^]\fP"
-Search forward in the current line for the \fIn\fPth occurance of the
-next character typed.
-.\"}}}
-.\"{{{ search-history ^R
-.IP "\fBsearch-history ^R\fP"
-Enter incremental search mode. The internal history list is searched
-backwards for commands matching the input. An initial \fB^\fP in the
-search string anchors the search. The abort key will leave search mode.
-Other commands will be executed after leaving search mode. Successive
-\fBsearch-history\fP commands continue searching backward to the next
-previous occurrence of the pattern. The history buffer retains only a
-finite number of lines; the oldest are discarded as necessary.
-.\"}}}
-.\"{{{ set-mark-command ^[<space>
-.IP "\fBset-mark-command ^[\fP<space>"
-Set the mark at the cursor position.
-.\"}}}
-.\"{{{ stuff
-.IP "\fBstuff\fP"
-On systems supporting it, pushes the bound character back onto the
-terminal input where it may receive special processing by the terminal
-handler. This is useful for the BRL \fB^T\fP mini-systat feature, for
-example.
-.\"}}}
-.\"{{{ stuff-reset
-.IP "\fBstuff-reset\fP"
-Acts like \fBstuff\fP, then aborts input the same as an interrupt.
-.\"}}}
-.\"{{{ transport-chars ^T
-.IP "\fBtranspose-chars ^T\fP"
-If at the end of line, or if the \fBgmacs\fP option is set,
-this exchanges the two previous characters; otherwise, it
-exchanges the previous and current characters and moves the cursor
-one character to the right.
-.\"}}}
-.\"{{{ up-history n ^P
-.IP "\fBup-history\fP \fIn\fP \fB^P\fP"
-Scrolls the history buffer backward \fIn\fP lines (earlier).
-.\"}}}
-.\"{{{ upcase-word n ^[U, ^[u
-.IP "\fBupcase-word\fP \fIn\fP \fB^[U\fP, \fB^[u\fP"
-Uppercases the next \fIn\fP words.
-.\"}}}
-.\"{{{ version ^V
-.IP "\fBversion ^V\fP"
-Display the version of ksh. The current edit buffer is restored as soon
-as any key is pressed (the key is then processed, unless it is a space).
-.\"}}}
-.\"{{{ yank ^Y
-.IP "\fByank ^Y\fP"
-Inserts the most recently killed text string at the current cursor position.
-.\"}}}
-.\"{{{ yank-pop ^[y
-.IP "\fByank-pop ^[y\fP"
-Immediately after a \fByank\fP, replaces the inserted text string with
-the next previous killed text string.
-.\"}}}
-.\"}}}
-.\"{{{ Vi Interactive Input Line Editing
-.\"{{{ introduction
-.SS "Vi Interactive Input Line Editing"
-The vi command line editor in ksh has basically the same commands as the
-vi editor (see \fIvi\fP(1)), with the following exceptions:
-.nr P2 \n(PD
-.IP \ \ \(bu
-you start out in insert mode,
-.IP \ \ \(bu
-there are file name and command completion commands
-(\fB=\fP, \fB\e\fP, \fB*\fP, \fB^X\fP, \fB^E\fP, \fB^F\fP and,
-optionally, \fB<tab>\fP),
-.IP \ \ \(bu
-the \fB_\fP command is different (in ksh it is the last argument command,
-in vi it goes to the start of the current line),
-.IP \ \ \(bu
-the \fB/\fP and \fBG\fP commands move in the opposite direction as the \fBj\fP
-command
-.IP \ \ \(bu
-and commands which don't make sense in a single line editor are not available
-(\fIe.g.\fP, screen movement commands, ex \fB:\fP commands, \fIetc.\fP).
-.nr PD \n(P2
-.LP
-Note that the \fB^X\fP stands for control-X; also \fB<esc>\fP, \fB<space>\fP
-and \fB<tab>\fP are used for escape, space and tab, respectively (no kidding).
-.\"}}}
-.\"{{{ modes
-.PP
-Like vi, there are two modes: insert mode and command mode.
-In insert mode, most characters are simply put in the buffer at the
-current cursor position as they are typed, however, some characters
-are treated specially.
-In particular, the following characters are taken from current tty settings
-(see \fIstty\fP(1)) and have their usual meaning (normal values are in
-parentheses):
-kill (\fB^U\fP), erase (\fB^?\fP), werase (\fB^W\fP), eof (\fB^D\fP),
-intr (\fB^C\fP) and quit (\fB^\e\fP).
-In addition to the above, the following characters are also treated
-specially in insert mode:
-.TS
-expand;
-afB lw(4.5i).
-^H T{
-erases previous character
-T}
-^V T{
-literal next: the next character typed is not treated specially (can be
-used to insert the characters being described here)
-T}
-^J ^M T{
-end of line: the current line is read, parsed and executed by the shell
-T}
-<esc> T{
-puts the editor in command mode (see below)
-T}
-^E T{
-command and file name enumeration (see below)
-T}
-^F T{
-command and file name completion (see below).
-If used twice in a row, the list of possible completions is displayed;
-if used a third time, the completion is undone.
-T}
-^X T{
-command and file name expansion (see below)
-T}
-<tab> T{
-optional file name and command completion (see \fB^F\fP above), enabled with
-\fBset \-o vi-tabcomplete\fP
-T}
-.TE
-.\"}}}
-.\"{{{ display
-.PP
-If a line is longer that the screen width (see \fBCOLUMNS\fP parameter),
-a \fB>\fP, \fB+\fP or \fB<\fP character is displayed in the last column
-indicating that there are more characters after, before and after, or
-before the current position, respectively.
-The line is scrolled horizontally as necessary.
-.\"}}}
-.\"{{{ command mode
-.PP
-In command mode, each character is interpreted as a command.
-Characters that don't correspond to commands, are illegal combinations of
-commands or are commands that can't be carried out all cause beeps.
-In the following command descriptions, a \fIn\fP indicates the
-command may be prefixed by a number (\fIe.g.\fP, \fB10l\fP moves right 10
-characters); if no number prefix is used, \fIn\fP is assumed to be 1
-unless otherwise specified.
-The term `current position' refers to the position between the cursor
-and the character preceding the cursor.
-A `word' is a sequence of letters, digits and underscore characters or a
-sequence of non-letter, non-digit, non-underscore, non-white-space characters
-(\fIe.g.\fP, ab2*&^ contains two words) and a `big-word' is a sequence of
-non-white-space characters.
-.\"{{{ Special ksh vi commands
-.IP "Special ksh vi commands"
-The following commands are not in, or are different from, the normal vi file
-editor:
-.RS
-.IP "\fIn\fP\fB_\fP"
-insert a space followed by the \fIn\fPth big-word from the last command in the
-history at the current position and enter insert mode; if \fIn\fP is not
-specified, the last word is inserted.
-.IP "\fB#\fP"
-insert the comment character (\fB#\fP) at the start of the current line and
-return the line to the shell (equivalent to \fBI#^J\fP).
-.IP "\fIn\fP\fBg\fP"
-like \fBG\fP, except if \fIn\fP is not specified, it goes to the most recent
-remembered line.
-.IP "\fIn\fP\fBv\fP"
-edit line \fIn\fP using the vi editor;
-if \fIn\fP is not specified, the current line is edited.
-The actual command executed is
-`\fBfc \-e ${VISUAL:-${EDITOR:-vi}}\fP \fIn\fP'.
-.IP "\fB*\fP and \fB^X\fP"
-command or file name expansion is applied to the current big-word
-(with an appended *, if the word contains no file globing characters) - the
-big-word is replaced with the resulting words.
-If the current big-word is the first on the line (or follows one
-of the following characters: \fB;\fP, \fB|\fP, \fB&\fP, \fB(\fP, \fB)\fP)
-and does not contain a slash (\fB/\fP) then command expansion is done,
-otherwise file name expansion is done.
-Command expansion will match the big-word against all aliases, functions
-and built-in commands as well as any executable files found by searching
-the directories in the \fBPATH\fP parameter.
-File name expansion matches the big-word against the files in the
-current directory.
-After expansion, the cursor is placed just past the last word and the editor
-is in insert mode.
-.IP "\fIn\fP\fB\e\fP, \fIn\fP\fB^F\fP, \fIn\fP\fB<tab>\fP and \fIn\fP\fB<esc>\fP"
-command/file name completion:
-replace the current big-word with the longest unique
-match obtained after performing command/file name expansion.
-\fB<tab>\fP is only recognized if the \fBvi-tabcomplete\fP option is set,
-while \fB<esc>\fP is only recognized if the \fBvi-esccomplete\fP option
-is set (see \fBset \-o\fP).
-If \fIn\fP is specified, the \fIn\fPth possible
-completion is selected (as reported by the command/file name enumeration
-command).
-.IP "\fB=\fP and \fB^E\fP"
-command/file name enumeration: list all the commands or files that match
-the current big-word.
-.IP "\fB^V\fP"
-display the version of pdksh; it is displayed until another key is pressed
-(this key is ignored).
-.IP "\fB@\fP\fIc\fP"
-macro expansion: execute the commands found in the alias _\fIc\fP.
-.RE
-.\"}}}
-.\"{{{ Intra-line movement commands
-.IP "Intra-line movement commands"
-.RS
-.IP "\fIn\fP\fBh\fP and \fIn\fP\fB^H\fP"
-move left \fIn\fP characters.
-.IP "\fIn\fP\fBl\fP and \fIn\fP\fB<space>\fP"
-move right \fIn\fP characters.
-.IP "\fB0\fP"
-move to column 0.
-.IP "\fB^\fP"
-move to the first non white-space character.
-.IP "\fIn\fP\fB|\fP"
-move to column \fIn\fP.
-.IP "\fB$\fP"
-move to the last character.
-.IP "\fIn\fP\fBb\fP"
-move back \fIn\fP words.
-.IP "\fIn\fP\fBB\fP"
-move back \fIn\fP big-words.
-.IP "\fIn\fP\fBe\fP"
-move forward to the end the word, \fIn\fP times.
-.IP "\fIn\fP\fBE\fP"
-move forward to the end the big-word, \fIn\fP times.
-.IP "\fIn\fP\fBw\fP"
-move forward \fIn\fP words.
-.IP "\fIn\fP\fBW\fP"
-move forward \fIn\fP big-words.
-.IP "\fB%\fP"
-find match: the editor looks forward for the nearest parenthesis,
-bracket or brace and then moves the to the matching parenthesis, bracket or
-brace.
-.IP "\fIn\fP\fBf\fP\fIc\fP"
-move forward to the \fIn\fPth occurrence of the character \fIc\fP.
-.IP "\fIn\fP\fBF\fP\fIc\fP"
-move backward to the \fIn\fPth occurrence of the character \fIc\fP.
-.IP "\fIn\fP\fBt\fP\fIc\fP"
-move forward to just before the \fIn\fPth occurrence of the character \fIc\fP.
-.IP "\fIn\fP\fBT\fP\fIc\fP"
-move backward to just before the \fIn\fPth occurrence of the character \fIc\fP.
-.IP "\fIn\fP\fB;\fP"
-repeats the last \fBf\fP, \fBF\fP, \fBt\fP or \fBT\fP command.
-.IP "\fIn\fP\fB,\fP"
-repeats the last \fBf\fP, \fBF\fP, \fBt\fP or \fBT\fP command, but moves
-in the opposite direction.
-.RE
-.\"}}}
-.\"{{{ Inter-line movement commands
-.IP "Inter-line movement commands"
-.RS
-.IP "\fIn\fP\fBj\fP and \fIn\fP\fB+\fP and \fIn\fP\fB^N\fP"
-move to the \fIn\fPth next line in the history.
-.IP "\fIn\fP\fBk\fP and \fIn\fP\fB-\fP and \fIn\fP\fB^P\fP"
-move to the \fIn\fPth previous line in the history.
-.IP "\fIn\fP\fBG\fP"
-move to line \fIn\fP in the history; if \fIn\fP is not specified, the
-number first remembered line is used.
-.IP "\fIn\fP\fBg\fP"
-like \fBG\fP, except if \fIn\fP is not specified, it goes to the most recent
-remembered line.
-.IP "\fIn\fP\fB/\fP\fIstring\fP"
-search backward through the history for the \fIn\fPth line containing
-\fIstring\fP; if \fIstring\fP starts with \fB^\fP, the remainder of the
-string must appear at the start of the history line for it to match.
-.IP "\fIn\fP\fB?\fP\fIstring\fP"
-same as \fB/\fP, except it searches forward through the history.
-.IP "\fIn\fP\fBn\fP"
-search for the \fIn\fPth occurrence of the last search string; the
-direction of the search is the same as the last search.
-.IP "\fIn\fP\fBN\fP"
-search for the \fIn\fPth occurrence of the last search string; the
-direction of the search is the opposite of the last search.
-.RE
-.\"}}}
-.\"{{{ Edit commands
-.IP "Edit commands"
-.RS
-.IP "\fIn\fP\fBa\fP"
-append text \fIn\fP times: goes into insert mode just after the current
-position.
-The append is only replicated if command mode is re-entered (\fIi.e.\fP,
-<esc> is used).
-.IP "\fIn\fP\fBA\fP"
-same as \fBa\fP, except it appends at the end of the line.
-.IP "\fIn\fP\fBi\fP"
-insert text \fIn\fP times: goes into insert mode at the current
-position.
-The insertion is only replicated if command mode is re-entered (\fIi.e.\fP,
-<esc> is used).
-.IP "\fIn\fP\fBI\fP"
-same as \fBi\fP, except the insertion is done just before the first non-blank
-character.
-.IP "\fIn\fP\fBs\fP"
-substitute the next \fIn\fP characters (\fIi.e.\fP, delete the characters
-and go into insert mode).
-.IP "\fBS\fP"
-substitute whole line: all characters from the first non-blank character
-to the end of line are deleted and insert mode is entered.
-.IP "\fIn\fP\fBc\fP\fImove-cmd\fP"
-change from the current position to the position resulting from \fIn\fP
-\fImove-cmd\fPs (\fIi.e.\fP, delete the indicated region and go into insert
-mode);
-if \fImove-cmd\fP is \fBc\fP, the line starting from the first non-blank
-character is changed.
-.IP "\fBC\fP"
-change from the current position to the end of the line (\fIi.e.\fP, delete to
-the end of the line and go into insert mode).
-.IP "\fIn\fP\fBx\fP"
-delete the next \fIn\fP characters.
-.IP "\fIn\fP\fBX\fP"
-delete the previous \fIn\fP characters.
-.IP "\fBD\fP"
-delete to the end of the line.
-.IP "\fIn\fP\fBd\fP\fImove-cmd\fP"
-delete from the current position to the position resulting from
-\fIn\fP \fImove-cmd\fPs;
-\fImove-cmd\fP is a movement command (see above) or \fBd\fP, in which case
-the current line is deleted.
-.IP "\fIn\fP\fBr\fP\fIc\fP"
-replace the next \fIn\fP characters with the character \fIc\fP.
-.IP "\fIn\fP\fBR\fP"
-replace: enter insert mode but overwrite existing characters instead of
-inserting before existing characters. The replacement is repeated \fIn\fP
-times.
-.IP "\fIn\fP\fB~\fP"
-change the case of the next \fIn\fP characters.
-.IP "\fIn\fP\fBy\fP\fImove-cmd\fP"
-yank from the current position to the position resulting from \fIn\fP
-\fImove-cmd\fPs into the yank buffer; if \fImove-cmd\fP is \fBy\fP, the
-whole line is yanked.
-.IP "\fBY\fP"
-yank from the current position to the end of the line.
-.IP "\fIn\fP\fBp\fP"
-paste the contents of the yank buffer just after the current position,
-\fIn\fP times.
-.IP "\fIn\fP\fBP\fP"
-same as \fBp\fP, except the buffer is pasted at the current position.
-.RE
-.\"}}}
-.\"{{{ Miscellaneous vi commands
-.IP "Miscellaneous vi commands"
-.RS
-.IP "\fB^J\fP and \fB^M\fP"
-the current line is read, parsed and executed by the shell.
-.IP "\fB^L\fP and \fB^R\fP"
-redraw the current line.
-.IP "\fIn\fP\fB.\fP"
-redo the last edit command \fIn\fP times.
-.IP "\fBu\fP"
-undo the last edit command.
-.IP "\fBU\fP"
-undo all changes that have been made to the current line.
-.IP "\fIintr\fP and \fIquit\fP"
-the interrupt and quit terminal characters cause the current line to
-be deleted and a new prompt to be printed.
-.RE
-.\"Has all vi commands except:
-.\" movement: { } [[ ]] ^E ^Y ^U ^D ^F ^B H L M ()
-.\" tag commands: ^T ^]
-.\" mark commands: m ` '
-.\" named-buffer commands: " @
-.\" file/shell/ex-commands: Q ZZ ^^ : ! &
-.\" multi-line change commands: o O J
-.\" shift commands: << >>
-.\" status command: ^G
-.\"}}}
-.\"}}}
-.\"}}}
-.\"}}}
-.\"{{{ Files
-.SH FILES
-~/.profile
-.br
-/etc/profile
-.br
-/etc/suid_profile
-.\"}}}
-.\"{{{ Bugs
-.SH BUGS
-Any bugs in pdksh should be reported to pdksh@cs.mun.ca. Please
-include the version of pdksh (echo $KSH_VERSION shows it), the machine,
-operating system and compiler you are using and a description of how to
-repeat the bug (a small shell script that demonstrates the bug is
-best). The following, if relevant (if you are not sure, include them),
-can also helpful: options you are using (both options.h options and set
-\-o options) and a copy of your config.h (the file generated by the
-configure script). New versions of pdksh can be obtained from
-ftp.cs.mun.ca:pub/pdksh/.
-.\"}}}
-.\"{{{ Authors
-.SH AUTHORS
-This shell is based on the public domain 7th edition Bourne shell clone by
-Charles Forsyth and parts of the BRL shell by Doug A.\& Gwyn, Doug Kingston,
-Ron Natalie, Arnold Robbins, Lou Salkind and others. The first release
-was created by Eric Gisin, and it was subsequently maintained by
-John R.\& MacMillan (chance!john@sq.sq.com), and
-Simon J.\& Gerraty (sjg@zen.void.oz.au). The current maintainer is
-Michael Rendell (michael@cs.mun.ca).
-The CONTRIBUTORS file in the source distribution contains a more complete
-list of people and their part in the shell's development.
-.\"}}}
-.\"{{{ See also
-.SH "SEE ALSO"
-awk(1),
-sh(1),
-csh(1), ed(1), getconf(1), getopt(1), sed(1), stty(1), vi(1),
-dup(2), execve(2), getgid(2), getuid(2), open(2), pipe(2), wait(2),
-getopt(3), rand(3), signal(3), system(3),
-environ(5)
-.PP
-.IR "The KornShell Command and Programming Language" ,
-Morris Bolsky and David Korn, 1989, ISBN 0-13-516972-0.
-.PP
-.\" XXX ISBN missing
-.IR "UNIX Shell Programming" ,
-Stephen G.\& Kochan, Patrick H.\& Wood, Hayden.
-.PP
-.IR "IEEE Standard for information Technology \- Portable Operating System Interface (POSIX) \- Part 2: Shell and Utilities" ,
-IEEE Inc, 1993, ISBN 1-55937-255-9.
-.\"}}}
diff --git a/bin/pdksh/ksh_dir.h b/bin/pdksh/ksh_dir.h
deleted file mode 100644
index 34c981fedc1..00000000000
--- a/bin/pdksh/ksh_dir.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* $OpenBSD: ksh_dir.h,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
-
-/* Wrapper around the ugly dir includes/ifdefs */
-
-#if defined(HAVE_DIRENT_H)
-# include <dirent.h>
-# define NLENGTH(dirent) (strlen(dirent->d_name))
-#else
-# define dirent direct
-# define NLENGTH(dirent) (dirent->d_namlen)
-# ifdef HAVE_SYS_NDIR_H
-# include <sys/ndir.h>
-# endif /* HAVE_SYS_NDIR_H */
-# ifdef HAVE_SYS_DIR_H
-# include <sys/dir.h>
-# endif /* HAVE_SYSDIR_H */
-# ifdef HAVE_NDIR_H
-# include <ndir.h>
-# endif /* HAVE_NDIR_H */
-#endif /* HAVE_DIRENT_H */
-
-#ifdef OPENDIR_DOES_NONDIR
-extern DIR *ksh_opendir ARGS((const char *d));
-#else /* OPENDIR_DOES_NONDIR */
-# define ksh_opendir(d) opendir(d)
-#endif /* OPENDIR_DOES_NONDIR */
diff --git a/bin/pdksh/ksh_limval.h b/bin/pdksh/ksh_limval.h
deleted file mode 100644
index 828c0f82577..00000000000
--- a/bin/pdksh/ksh_limval.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* $OpenBSD: ksh_limval.h,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
-
-/* Wrapper around the values.h/limits.h includes/ifdefs */
-
-#ifdef HAVE_VALUES_H
-# include <values.h>
-#endif /* HAVE_VALUES_H */
-/* limits.h is included in sh.h */
-
-#ifndef DMAXEXP
-# define DMAXEXP 128 /* should be big enough */
-#endif
-
-#ifndef BITSPERBYTE
-# ifdef CHAR_BIT
-# define BITSPERBYTE CHAR_BIT
-# else
-# define BITSPERBYTE 8 /* probably true.. */
-# endif
-#endif
-
-#ifndef BITS
-# define BITS(t) (BITSPERBYTE * sizeof(t))
-#endif
diff --git a/bin/pdksh/ksh_stat.h b/bin/pdksh/ksh_stat.h
deleted file mode 100644
index 1abcc7cb1fc..00000000000
--- a/bin/pdksh/ksh_stat.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* $OpenBSD: ksh_stat.h,v 1.3 1996/10/01 02:05:39 downsj Exp $ */
-
-/* Wrapper around the ugly sys/stat includes/ifdefs */
-
-/* assumes <sys/types.h> already included */
-#include <sys/stat.h>
-
-#ifndef HAVE_LSTAT
-# define lstat(path, buf) stat(path, buf)
-#endif /* HAVE_LSTAT */
-
-#ifdef STAT_MACROS_BROKEN
-# undef S_ISREG
-# undef S_ISDIR
-# undef S_ISCHR
-# undef S_ISBLK
-# undef S_ISFIFO
-# undef S_ISSOCK
-# undef S_ISLNK
-#endif /* STAT_MACROS_BROKEN */
-
-#if !defined(S_ISREG) && defined(S_IFREG)
-# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
-#endif /* S_ISREG */
-#if !defined(S_ISDIR) && defined(S_IFDIR)
-# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
-#endif /* S_ISDIR */
-#if !defined(S_ISCHR) && defined(S_IFCHR)
-# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
-#endif /* S_ISCHR */
-#if !defined(S_ISBLK) && defined(S_IFBLK)
-# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
-#endif /* S_ISBLK */
-#if !defined(S_ISFIFO) && defined(S_IFIFO)
-# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
-#endif /* S_ISFIFO */
-#if !defined(S_ISLNK) && defined(S_IFLNK)
-# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
-#endif /* S_ISLNK */
-#if !defined(S_ISSOCK) && defined(S_IFSOCK)
-# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
-#endif /* S_ISSOCK */
-#if !defined(S_ISCDF) && defined(S_CDF)
-# define S_ISCDF(m) (S_ISDIR(m) && ((m) & S_CDF))
-#endif /* S_ISSOCK */
-
-#ifndef S_ISVTX
-# define S_ISVTX 01000 /* sticky bit */
-#endif /* S_ISVTX */
-
-#ifndef S_IXUSR
-# define S_IXUSR 00100 /* user execute bit */
-#endif /* S_IXUSR */
-#ifndef S_IXGRP
-# define S_IXGRP 00010 /* user execute bit */
-#endif /* S_IXGRP */
-#ifndef S_IXOTH
-# define S_IXOTH 00001 /* user execute bit */
-#endif /* S_IXOTH */
diff --git a/bin/pdksh/ksh_time.h b/bin/pdksh/ksh_time.h
deleted file mode 100644
index ee8dc9b9128..00000000000
--- a/bin/pdksh/ksh_time.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* $OpenBSD: ksh_time.h,v 1.2 1996/10/01 02:05:40 downsj Exp $ */
-
-#ifndef KSH_TIME_H
-# define KSH_TIME_H
-
-/* Wrapper around the ugly time.h,sys/time.h includes/ifdefs */
-
-#ifdef TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else /* TIME_WITH_SYS_TIME */
-# ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif /* TIME_WITH_SYS_TIME */
-
-#ifndef TIME_DECLARED
-extern time_t time ARGS((time_t *));
-#endif
-
-#ifndef CLK_TCK
-# define CLK_TCK 60 /* 60HZ */
-#endif
-#endif /* KSH_TIME_H */
diff --git a/bin/pdksh/ksh_times.h b/bin/pdksh/ksh_times.h
deleted file mode 100644
index ec7b97eedf5..00000000000
--- a/bin/pdksh/ksh_times.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* $OpenBSD: ksh_times.h,v 1.2 1996/10/01 02:05:41 downsj Exp $ */
-
-#ifndef KSH_TIMES_H
-# define KSH_TIMES_H
-
-/* Needed for clock_t on some systems (ie, NeXT in non-posix mode) */
-#include "ksh_time.h"
-
-#include <sys/times.h>
-
-#ifdef TIMES_BROKEN
-extern clock_t ksh_times ARGS((struct tms *));
-#else /* TIMES_BROKEN */
-# define ksh_times times
-#endif /* TIMES_BROKEN */
-
-#ifdef HAVE_TIMES
-extern clock_t times ARGS((struct tms *));
-#endif /* HAVE_TIMES */
-#endif /* KSH_TIMES_H */
diff --git a/bin/pdksh/ksh_wait.h b/bin/pdksh/ksh_wait.h
deleted file mode 100644
index a077b90f16b..00000000000
--- a/bin/pdksh/ksh_wait.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* $OpenBSD: ksh_wait.h,v 1.3 1997/06/19 13:58:43 kstailey Exp $ */
-
-/* Wrapper around the ugly sys/wait includes/ifdefs */
-
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-
-#ifndef POSIX_SYS_WAIT
-/* Get rid of system macros (which probably use union wait) */
-# undef WIFCORED
-# undef WIFEXITED
-# undef WEXITSTATUS
-# undef WIFSIGNALED
-# undef WTERMSIG
-# undef WIFSTOPPED
-# undef WSTOPSIG
-#endif /* POSIX_SYS_WAIT */
-
-typedef int WAIT_T;
-
-#ifndef WIFCORED
-# define WIFCORED(s) ((s) & 0x80)
-#endif
-#define WSTATUS(s) (s)
-
-#ifndef WIFEXITED
-# define WIFEXITED(s) (((s) & 0xff) == 0)
-#endif
-#ifndef WEXITSTATUS
-# define WEXITSTATUS(s) (((s) >> 8) & 0xff)
-#endif
-#ifndef WIFSIGNALED
-# define WIFSIGNALED(s) (((s) & 0xff) != 0 && ((s) & 0xff) != 0x7f)
-#endif
-#ifndef WTERMSIG
-# define WTERMSIG(s) ((s) & 0x7f)
-#endif
-#ifndef WIFSTOPPED
-# define WIFSTOPPED(s) (((s) & 0xff) == 0x7f)
-#endif
-#ifndef WSTOPSIG
-# define WSTOPSIG(s) (((s) >> 8) & 0xff)
-#endif
-
-#if !defined(HAVE_WAITPID) && defined(HAVE_WAIT3)
- /* always used with p == -1 */
-# define ksh_waitpid(p, s, o) wait3((s), (o), (struct rusage *) 0)
-#else /* !HAVE_WAITPID && HAVE_WAIT3 */
-# define ksh_waitpid(p, s, o) waitpid((p), (s), (o))
-#endif /* !HAVE_WAITPID && HAVE_WAIT3 */
diff --git a/bin/pdksh/lex.c b/bin/pdksh/lex.c
deleted file mode 100644
index 5db0c81accd..00000000000
--- a/bin/pdksh/lex.c
+++ /dev/null
@@ -1,1281 +0,0 @@
-/* $OpenBSD: lex.c,v 1.10 1997/09/12 04:39:32 millert Exp $ */
-
-/*
- * lexical analysis and source input
- */
-
-#include "sh.h"
-#include <ctype.h>
-
-static void readhere ARGS((struct ioword *iop));
-static int getsc__ ARGS((void));
-static void getsc_line ARGS((Source *s));
-static char *get_brace_var ARGS((XString *wsp, char *wp));
-static int arraysub ARGS((char **strp));
-static const char *ungetsc ARGS((int c));
-static int getsc_bn ARGS((void));
-static void gethere ARGS((void));
-
-static int backslash_skip;
-static int ignore_backslash_newline;
-
-/* optimized getsc_bn() */
-#define getsc() (*source->str != '\0' && *source->str != '\\' \
- && !backslash_skip ? *source->str++ : getsc_bn())
-/* optimized getsc__() */
-#define getsc_() ((*source->str != '\0') ? *source->str++ : getsc__())
-
-
-/*
- * Lexical analyzer
- *
- * tokens are not regular expressions, they are LL(1).
- * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
- * hence the state stack.
- */
-
-int
-yylex(cf)
- int cf;
-{
- register int c, state;
- char states [64], *statep = states; /* XXX overflow check */
- XString ws; /* expandable output word */
- register char *wp; /* output word pointer */
- register char *sp, *dp;
- char UNINITIALIZED(*ddparen_start);
- int istate;
- int UNINITIALIZED(c2);
- int UNINITIALIZED(nparen), UNINITIALIZED(csstate);
- int UNINITIALIZED(ndparen);
- int UNINITIALIZED(indquotes);
-
-
- Again:
- Xinit(ws, wp, 64, ATEMP);
-
- backslash_skip = 0;
- ignore_backslash_newline = 0;
-
- if (cf&ONEWORD)
- istate = SWORD;
-#ifdef KSH
- else if (cf&LETEXPR) {
- *wp++ = OQUOTE; /* enclose arguments in (double) quotes */
- istate = SDPAREN;
- ndparen = 0;
- }
-#endif /* KSH */
- else { /* normal lexing */
- istate = (cf & HEREDELIM) ? SHEREDELIM : SBASE;
- while ((c = getsc()) == ' ' || c == '\t')
- ;
- if (c == '#') {
- ignore_backslash_newline++;
- while ((c = getsc()) != '\0' && c != '\n')
- ;
- ignore_backslash_newline--;
- }
- ungetsc(c);
- }
- if (source->flags & SF_ALIAS) { /* trailing ' ' in alias definition */
- source->flags &= ~SF_ALIAS;
- /* In POSIX mode, a trailing space only counts if we are
- * parsing a simple command
- */
- if (!Flag(FPOSIX) || (cf & CMDWORD))
- cf |= ALIAS;
- }
-
- /* collect non-special or quoted characters to form word */
- for (*statep = state = istate;
- !((c = getsc()) == 0 || ((state == SBASE || state == SHEREDELIM)
- && ctype(c, C_LEX1))); )
- {
- Xcheck(ws, wp);
- switch (state) {
- case SBASE:
- if (c == '[' && (cf & (VARASN|ARRAYVAR))) {
- *wp = EOS; /* temporary */
- if (is_wdvarname(Xstring(ws, wp), FALSE))
- {
- char *p, *tmp;
-
- if (arraysub(&tmp)) {
- *wp++ = CHAR;
- *wp++ = c;
- for (p = tmp; *p; ) {
- Xcheck(ws, wp);
- *wp++ = CHAR;
- *wp++ = *p++;
- }
- afree(tmp, ATEMP);
- break;
- } else {
- Source *s;
-
- s = pushs(SREREAD,
- source->areap);
- s->start = s->str
- = s->u.freeme = tmp;
- s->next = source;
- source = s;
- }
- }
- *wp++ = CHAR;
- *wp++ = c;
- break;
- }
- /* fall through.. */
- Sbase1: /* includes *(...|...) pattern (*+?@!) */
-#ifdef KSH
- if (c == '*' || c == '@' || c == '+' || c == '?'
- || c == '!')
- {
- c2 = getsc();
- if (c2 == '(' /*)*/ ) {
- *wp++ = OPAT;
- *wp++ = c;
- *++statep = state = SPATTERN;
- break;
- }
- ungetsc(c2);
- }
-#endif /* KSH */
- /* fall through.. */
- Sbase2: /* doesn't include *(...|...) pattern (*+?@!) */
- switch (c) {
- case '\\':
- c = getsc();
-#ifdef OS2
- if (isalnum(c)) {
- *wp++ = CHAR, *wp++ = '\\';
- *wp++ = CHAR, *wp++ = c;
- } else
-#endif
- if (c) /* trailing \ is lost */
- *wp++ = QCHAR, *wp++ = c;
- break;
- case '\'':
- *++statep = state = SSQUOTE;
- *wp++ = OQUOTE;
- ignore_backslash_newline++;
- break;
- case '"':
- *++statep = state = SDQUOTE;
- *wp++ = OQUOTE;
- break;
- default:
- goto Subst;
- }
- break;
-
- Subst:
- switch (c) {
- case '\\':
- c = getsc();
- switch (c) {
- case '"': case '\\':
- case '$': case '`':
- *wp++ = QCHAR, *wp++ = c;
- break;
- default:
- Xcheck(ws, wp);
- if (c) { /* trailing \ is lost */
- *wp++ = CHAR, *wp++ = '\\';
- *wp++ = CHAR, *wp++ = c;
- }
- break;
- }
- break;
- case '$':
- c = getsc();
- if (c == '(') /*)*/ {
- c = getsc();
- if (c == '(') /*)*/ {
- *++statep = state = SDDPAREN;
- nparen = 2;
- ddparen_start = wp;
- *wp++ = EXPRSUB;
- } else {
- ungetsc(c);
- *++statep = state = SPAREN;
- nparen = 1;
- csstate = 0;
- *wp++ = COMSUB;
- }
- } else if (c == '{') /*}*/ {
- *wp++ = OSUBST;
- wp = get_brace_var(&ws, wp);
- /* If this is a trim operation,
- * wrap @(...) around the pattern
- * (allows easy handling of ${a#b|c})
- */
- c = getsc();
- if (c == '#' || c == '%') {
- *wp++ = CHAR, *wp++ = c;
- if ((c2 = getsc()) == c)
- *wp++ = CHAR, *wp++ = c;
- else
- ungetsc(c2);
- *wp++ = OPAT, *wp++ = '@';
- *++statep = state = STBRACE;
- } else {
- ungetsc(c);
- *++statep = state = SBRACE;
- }
- } else if (ctype(c, C_ALPHA)) {
- *wp++ = OSUBST;
- do {
- Xcheck(ws, wp);
- *wp++ = c;
- c = getsc();
- } while (ctype(c, C_ALPHA|C_DIGIT));
- *wp++ = '\0';
- *wp++ = CSUBST;
- ungetsc(c);
- } else if (ctype(c, C_DIGIT|C_VAR1)) {
- Xcheck(ws, wp);
- *wp++ = OSUBST;
- *wp++ = c;
- *wp++ = '\0';
- *wp++ = CSUBST;
- } else {
- *wp++ = CHAR, *wp++ = '$';
- ungetsc(c);
- }
- break;
- case '`':
- *++statep = state = SBQUOTE;
- *wp++ = COMSUB;
- /* Need to know if we are inside double quotes
- * since sh/at&t-ksh translate the \" to " in
- * "`..\"..`".
- */
- indquotes = 0;
- if (!Flag(FPOSIX))
- for (sp = statep; sp > states; --sp)
- if (*sp == SDQUOTE)
- indquotes = 1;
- break;
- default:
- *wp++ = CHAR, *wp++ = c;
- }
- break;
-
- case SSQUOTE:
- if (c == '\'') {
- state = *--statep;
- *wp++ = CQUOTE;
- ignore_backslash_newline--;
- } else
- *wp++ = QCHAR, *wp++ = c;
- break;
-
- case SDQUOTE:
- if (c == '"') {
- state = *--statep;
- *wp++ = CQUOTE;
- } else
- goto Subst;
- break;
-
- case SPAREN: /* $( .. ) */
- /* todo: deal with $(...) quoting properly
- * kludge to partly fake quoting inside $(..): doesn't
- * really work because nested $(..) or ${..} inside
- * double quotes aren't dealt with.
- */
- switch (csstate) {
- case 0: /* normal */
- switch (c) {
- case '(':
- nparen++;
- break;
- case ')':
- nparen--;
- break;
- case '\\':
- csstate = 1;
- break;
- case '"':
- csstate = 2;
- break;
- case '\'':
- csstate = 4;
- ignore_backslash_newline++;
- break;
- }
- break;
-
- case 1: /* backslash in normal mode */
- case 3: /* backslash in double quotes */
- --csstate;
- break;
-
- case 2: /* double quotes */
- if (c == '"')
- csstate = 0;
- else if (c == '\\')
- csstate = 3;
- break;
-
- case 4: /* single quotes */
- if (c == '\'') {
- csstate = 0;
- ignore_backslash_newline--;
- }
- break;
- }
- if (nparen == 0) {
- state = *--statep;
- *wp++ = 0; /* end of COMSUB */
- } else
- *wp++ = c;
- break;
-
- case SDDPAREN: /* $(( .. )) */
- /* todo: deal with $((...); (...)) properly */
- /* XXX should nest using existing state machine
- * (embed "..", $(...), etc.) */
- if (c == '(')
- nparen++;
- else if (c == ')') {
- nparen--;
- if (nparen == 1) {
- /*(*/
- if ((c2 = getsc()) == ')') {
- state = *--statep;
- *wp++ = 0; /* end of EXPRSUB */
- break;
- } else {
- ungetsc(c2);
- /* mismatched parenthesis -
- * assume we were really
- * parsing a $(..) expression
- */
- memmove(ddparen_start + 1,
- ddparen_start,
- wp - ddparen_start);
- *ddparen_start++ = COMSUB;
- *ddparen_start = '('; /*)*/
- wp++;
- csstate = 0;
- *statep = state = SPAREN;
- }
- }
- }
- *wp++ = c;
- break;
-
- case SBRACE:
- /*{*/
- if (c == '}') {
- state = *--statep;
- *wp++ = CSUBST;
- } else
- goto Sbase1;
- break;
-
- case STBRACE:
- /* same as SBRACE, except | is saved as SPAT and
- * CPAT is added at the end.
- */
- /*{*/
- if (c == '}') {
- state = *--statep;
- *wp++ = CPAT;
- *wp++ = CSUBST;
- } else if (c == '|') {
- *wp++ = SPAT;
- } else
- goto Sbase1;
- break;
-
- case SBQUOTE:
- if (c == '`') {
- *wp++ = 0;
- state = *--statep;
- } else if (c == '\\') {
- switch (c = getsc()) {
- case '\\':
- case '$': case '`':
- *wp++ = c;
- break;
- case '"':
- if (indquotes) {
- *wp++ = c;
- break;
- }
- /* fall through.. */
- default:
- if (c) { /* trailing \ is lost */
- *wp++ = '\\';
- *wp++ = c;
- }
- break;
- }
- } else
- *wp++ = c;
- break;
-
- case SWORD: /* ONEWORD */
- goto Subst;
-
-#ifdef KSH
- case SDPAREN: /* LETEXPR: (( ... )) */
- /*(*/
- if (c == ')') {
- if (ndparen > 0)
- --ndparen;
- /*(*/
- else if ((c2 = getsc()) == ')') {
- c = 0;
- *wp++ = CQUOTE;
- goto Done;
- } else
- ungetsc(c2);
- } else if (c == '(')
- /* parenthesis inside quotes and backslashes
- * are lost, but at&t ksh doesn't count them
- * either
- */
- ++ndparen;
- goto Sbase2;
-#endif /* KSH */
-
- case SHEREDELIM: /* <<,<<- delimiter */
- /* XXX chuck this state (and the next) - use
- * the existing states ($ and \`..` should be
- * stripped of their specialness after the
- * fact).
- */
- /* here delimiters need a special case since
- * $ and `..` are not to be treated specially
- */
- if (c == '\\') {
- c = getsc();
- if (c) { /* trailing \ is lost */
- *wp++ = QCHAR;
- *wp++ = c;
- }
- } else if (c == '\'') {
- *++statep = state = SSQUOTE;
- *wp++ = OQUOTE;
- ignore_backslash_newline++;
- } else if (c == '"') {
- state = SHEREDQUOTE;
- *wp++ = OQUOTE;
- } else {
- *wp++ = CHAR;
- *wp++ = c;
- }
- break;
-
- case SHEREDQUOTE: /* " in <<,<<- delimiter */
- if (c == '"') {
- *wp++ = CQUOTE;
- state = SHEREDELIM;
- } else {
- if (c == '\\') {
- switch (c = getsc()) {
- case '\\': case '"':
- case '$': case '`':
- break;
- default:
- if (c) { /* trailing \ lost */
- *wp++ = CHAR;
- *wp++ = '\\';
- }
- break;
- }
- }
- *wp++ = CHAR;
- *wp++ = c;
- }
- break;
-
- case SPATTERN: /* in *(...|...) pattern (*+?@!) */
- if ( /*(*/ c == ')') {
- *wp++ = CPAT;
- state = *--statep;
- } else if (c == '|')
- *wp++ = SPAT;
- else
- goto Sbase1;
- break;
- }
- }
-Done:
- Xcheck(ws, wp);
- if (state != istate)
- yyerror("no closing quote\n");
-
- /* This done to avoid tests for SHEREDELIM wherever SBASE tested */
- if (state == SHEREDELIM)
- state = SBASE;
-
- if ((c == '<' || c == '>') && state == SBASE) {
- char *cp = Xstring(ws, wp);
- if (Xlength(ws, wp) == 2 && cp[0] == CHAR && digit(cp[1])) {
- wp = cp; /* throw away word */
- c2/*unit*/ = cp[1] - '0';
- } else
- c2/*unit*/ = c == '>'; /* 0 for <, 1 for > */
- }
-
- if (wp == Xstring(ws, wp) && state == SBASE) {
- Xfree(ws, wp); /* free word */
- /* no word, process LEX1 character */
- switch (c) {
- default:
- return c;
-
- case '|':
- case '&':
- case ';':
- if ((c2 = getsc()) == c)
- c = (c == ';') ? BREAK :
- (c == '|') ? LOGOR :
- (c == '&') ? LOGAND :
- YYERRCODE;
-#ifdef KSH
- else if (c == '|' && c2 == '&')
- c = COPROC;
-#endif /* KSH */
- else
- ungetsc(c2);
- return c;
-
- case '>':
- case '<': {
- register struct ioword *iop;
-
- iop = (struct ioword *) alloc(sizeof(*iop), ATEMP);
- iop->unit = c2/*unit*/;
-
- c2 = getsc();
- /* <<, >>, <> are ok, >< is not */
- if (c == c2 || (c == '<' && c2 == '>')) {
- iop->flag = c == c2 ?
- (c == '>' ? IOCAT : IOHERE) : IORDWR;
- if (iop->flag == IOHERE)
- if ((c2 = getsc()) == '-')
- iop->flag |= IOSKIP;
- else
- ungetsc(c2);
- } else if (c2 == '&')
- iop->flag = IODUP | (c == '<' ? IORDUP : 0);
- else {
- iop->flag = c == '>' ? IOWRITE : IOREAD;
- if (c == '>' && c2 == '|')
- iop->flag |= IOCLOB;
- else
- ungetsc(c2);
- }
-
- iop->name = (char *) 0;
- iop->delim = (char *) 0;
- yylval.iop = iop;
- return REDIR;
- }
- case '\n':
- gethere();
- if (cf & CONTIN)
- goto Again;
- return c;
-
- case '(': /*)*/
-#ifdef KSH
- if (!Flag(FSH)) {
- if ((c2 = getsc()) == '(') /*)*/
- c = MDPAREN;
- else
- ungetsc(c2);
- }
-#endif /* KSH */
- return c;
- /*(*/
- case ')':
- return c;
- }
- }
-
- *wp++ = EOS; /* terminate word */
- yylval.cp = Xclose(ws, wp);
- if (state == SWORD
-#ifdef KSH
- || state == SDPAREN
-#endif /* KSH */
- ) /* ONEWORD? */
- return LWORD;
- ungetsc(c); /* unget terminator */
-
- /* copy word to unprefixed string ident */
- for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; )
- *dp++ = *sp++;
- /* Make sure the ident array stays '\0' paded */
- memset(dp, 0, (ident+IDENT) - dp + 1);
- if (c != EOS)
- *ident = '\0'; /* word is not unquoted */
-
- if (*ident != '\0' && (cf&(KEYWORD|ALIAS))) {
- struct tbl *p;
- int h = hash(ident);
-
- /* { */
- if ((cf & KEYWORD) && (p = tsearch(&keywords, ident, h))
- && (!(cf & ESACONLY) || p->val.i == ESAC || p->val.i == '}'))
- {
- afree(yylval.cp, ATEMP);
- return p->val.i;
- }
- if ((cf & ALIAS) && (p = tsearch(&aliases, ident, h))
- && (p->flag & ISSET))
- {
- register Source *s;
-
- for (s = source; s->type == SALIAS; s = s->next)
- if (s->u.tblp == p)
- return LWORD;
- /* push alias expansion */
- s = pushs(SALIAS, source->areap);
- s->start = s->str = p->val.s;
- s->u.tblp = p;
- s->next = source;
- source = s;
- afree(yylval.cp, ATEMP);
- goto Again;
- }
- }
-
- return LWORD;
-}
-
-static void
-gethere()
-{
- register struct ioword **p;
-
- for (p = heres; p < herep; p++)
- readhere(*p);
- herep = heres;
-}
-
-/*
- * read "<<word" text into temp file
- */
-
-static void
-readhere(iop)
- register struct ioword *iop;
-{
- struct shf *volatile shf;
- struct temp *h;
- register int c;
- char *volatile eof;
- char *eofp;
- int skiptabs;
- int i;
-
- eof = evalstr(iop->delim, 0);
-
- if (e->flags & EF_FUNC_PARSE) {
- h = maketemp(APERM);
- h->next = func_heredocs;
- func_heredocs = h;
- } else {
- h = maketemp(ATEMP);
- h->next = e->temps;
- e->temps = h;
- }
- iop->name = h->name;
- if (!(shf = h->shf))
- yyerror("cannot create temporary file %s - %s\n",
- h->name, strerror(errno));
-
- newenv(E_ERRH);
- i = ksh_sigsetjmp(e->jbuf, 0);
- if (i) {
- quitenv();
- shf_close(shf);
- unwind(i);
- }
-
- if (!(iop->flag & IOEVAL))
- ignore_backslash_newline++;
-
- for (;;) {
- eofp = eof;
- skiptabs = iop->flag & IOSKIP;
- while ((c = getsc()) != 0) {
- if (skiptabs) {
- if (c == '\t')
- continue;
- skiptabs = 0;
- }
- if (c != *eofp)
- break;
- eofp++;
- }
- /* Allow EOF here so commands with out trailing newlines
- * will work (eg, ksh -c '...', $(...), etc).
- */
- if (*eofp == '\0' && (c == 0 || c == '\n'))
- break;
- ungetsc(c);
- shf_write(eof, eofp - eof, shf);
- while ((c = getsc()) != '\n') {
- if (c == 0)
- yyerror("here document `%s' unclosed\n", eof);
- shf_putc(c, shf);
- }
- shf_putc(c, shf);
- }
- shf_flush(shf);
- if (shf_error(shf))
- yyerror("error saving here document `%s': %s\n",
- eof, strerror(shf_errno(shf)));
- /*XXX add similar checks for write errors everywhere */
- quitenv();
- shf_close(shf);
- if (!(iop->flag & IOEVAL))
- ignore_backslash_newline--;
-}
-
-void
-#ifdef HAVE_PROTOTYPES
-yyerror(const char *fmt, ...)
-#else
-yyerror(fmt, va_alist)
- const char *fmt;
- va_dcl
-#endif
-{
- va_list va;
-
- yynerrs++;
- /* pop aliases and re-reads */
- while (source->type == SALIAS || source->type == SREREAD)
- source = source->next;
- source->str = null; /* zap pending input */
-
- error_prefix(TRUE);
- SH_VA_START(va, fmt);
- shf_vfprintf(shl_out, fmt, va);
- va_end(va);
- errorf(null);
-}
-
-/*
- * input for yylex with alias expansion
- */
-
-Source *
-pushs(type, areap)
- int type;
- Area *areap;
-{
- register Source *s;
-
- s = (Source *) alloc(sizeof(Source), areap);
- s->type = type;
- s->str = null;
- s->start = NULL;
- s->line = 0;
- s->errline = 0;
- s->file = NULL;
- s->flags = 0;
- s->next = NULL;
- s->areap = areap;
- if (type == SFILE || type == SSTDIN) {
- char *dummy;
- Xinit(s->xs, dummy, 256, s->areap);
- } else
- memset(&s->xs, 0, sizeof(s->xs));
- return s;
-}
-
-static int
-getsc__()
-{
- register Source *s = source;
- register int c;
-
- while ((c = *s->str++) == 0) {
- s->str = NULL; /* return 0 for EOF by default */
- switch (s->type) {
- case SEOF:
- s->str = null;
- return 0;
-
- case SSTDIN:
- case SFILE:
- getsc_line(s);
- break;
-
- case SWSTR:
- break;
-
- case SSTRING:
- break;
-
- case SWORDS:
- s->start = s->str = *s->u.strv++;
- s->type = SWORDSEP;
- break;
-
- case SWORDSEP:
- if (*s->u.strv == NULL) {
- s->start = s->str = newline;
- s->type = SEOF;
- } else {
- s->start = s->str = space;
- s->type = SWORDS;
- }
- break;
-
- case SALIAS:
- if (s->flags & SF_ALIASEND) {
- /* pass on an unused SF_ALIAS flag */
- source = s->next;
- source->flags |= s->flags & SF_ALIAS;
- s = source;
- } else if (*s->u.tblp->val.s
- && isspace(strchr(s->u.tblp->val.s, 0)[-1]))
- {
- source = s = s->next; /* pop source stack */
- /* Note that this alias ended with a space,
- * enabling alias expansion on the following
- * word.
- */
- s->flags |= SF_ALIAS;
- } else {
- /* At this point, we need to keep the current
- * alias in the source list so recursive
- * aliases can be detected and we also need
- * to return the next character. Do this
- * by temporarily popping the alias to get
- * the next character and then put it back
- * in the source list with the SF_ALIASEND
- * flag set.
- */
- source = s->next; /* pop source stack */
- source->flags |= s->flags & SF_ALIAS;
- c = getsc__();
- if (c) {
- s->flags |= SF_ALIASEND;
- s->ugbuf[0] = c; s->ugbuf[1] = '\0';
- s->start = s->str = s->ugbuf;
- s->next = source;
- source = s;
- } else {
- s = source;
- /* avoid reading eof twice */
- s->str = NULL;
- break;
- }
- }
- continue;
-
- case SREREAD:
- if (s->start != s->ugbuf) /* yuck */
- afree(s->u.freeme, ATEMP);
- source = s = s->next;
- continue;
- }
- if (s->str == NULL) {
- s->type = SEOF;
- s->start = s->str = null;
- return '\0';
- }
- if (s->flags & SF_ECHO) {
- shf_puts(s->str, shl_out);
- shf_flush(shl_out);
- }
- }
- return c;
-}
-
-static void
-getsc_line(s)
- Source *s;
-{
- char *xp = Xstring(s->xs, xp);
- int interactive = Flag(FTALKING) && s->type == SSTDIN;
- int have_tty = interactive && (s->flags & SF_TTY);
-
- /* Done here to ensure nothing odd happens when a timeout occurs */
- XcheckN(s->xs, xp, LINE);
- *xp = '\0';
- s->start = s->str = xp;
-
-#ifdef KSH
- if (have_tty && ksh_tmout) {
- ksh_tmout_state = TMOUT_READING;
- alarm(ksh_tmout);
- }
-#endif /* KSH */
-#ifdef EDIT
- if (have_tty && (0
-# ifdef VI
- || Flag(FVI)
-# endif /* VI */
-# ifdef EMACS
- || Flag(FEMACS) || Flag(FGMACS)
-# endif /* EMACS */
- ))
- {
- int nread;
-
- nread = x_read(xp, LINE);
- if (nread < 0) /* read error */
- nread = 0;
- xp[nread] = '\0';
- xp += nread;
- }
- else
-#endif /* EDIT */
- {
- if (interactive) {
- pprompt(prompt, 0);
-#ifdef OS2
- setmode (0, O_TEXT);
-#endif /* OS2 */
- } else
- s->line++;
-
- while (1) {
- char *p = shf_getse(xp, Xnleft(s->xs, xp), s->u.shf);
-
- if (!p && shf_error(s->u.shf)
- && shf_errno(s->u.shf) == EINTR)
- {
- shf_clearerr(s->u.shf);
- if (trap)
- runtraps(0);
- continue;
- }
- if (!p || (xp = p, xp[-1] == '\n'))
- break;
- /* double buffer size */
- xp++; /* move past null so doubling works... */
- XcheckN(s->xs, xp, Xlength(s->xs, xp));
- xp--; /* ...and move back again */
- }
-#ifdef OS2
- setmode(0, O_BINARY);
-#endif /* OS2 */
- /* flush any unwanted input so other programs/builtins
- * can read it. Not very optimal, but less error prone
- * than flushing else where, dealing with redirections,
- * etc..
- * todo: reduce size of shf buffer (~128?) if SSTDIN
- */
- if (s->type == SSTDIN)
- shf_flush(s->u.shf);
- }
- /* XXX: temporary kludge to restore source after a
- * trap may have been executed.
- */
- source = s;
-#ifdef KSH
- if (have_tty && ksh_tmout)
- {
- ksh_tmout_state = TMOUT_EXECUTING;
- alarm(0);
- }
-#endif /* KSH */
- s->start = s->str = Xstring(s->xs, xp);
- strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp));
- /* Note: if input is all nulls, this is not eof */
- if (Xlength(s->xs, xp) == 0) { /* EOF */
- if (s->type == SFILE)
- shf_fdclose(s->u.shf);
- s->str = NULL;
- } else if (interactive) {
-#ifdef HISTORY
- char *p = Xstring(s->xs, xp);
- if (cur_prompt == PS1)
- while (*p && ctype(*p, C_IFS) && ctype(*p, C_IFSWS))
- p++;
- if (*p) {
-# ifdef EASY_HISTORY
- if (cur_prompt == PS2)
- histappend(Xstring(s->xs, xp), 1);
- else
-# endif /* EASY_HISTORY */
- {
- s->line++;
- histsave(s->line, s->str, 1);
- }
- }
-#endif /* HISTORY */
- }
- if (interactive)
- set_prompt(PS2, (Source *) 0);
-}
-
-void
-set_prompt(to, s)
- int to;
- Source *s;
-{
- cur_prompt = to;
-
- switch (to) {
- case PS1: /* command */
-#ifdef KSH
- /* Substitute ! and !! here, before substitutions are done
- * so ! in expanded variables are not expanded.
- * NOTE: this is not what at&t ksh does (it does it after
- * substitutions, POSIX doesn't say which is to be done.
- */
- {
- struct shf *shf;
- char *ps1;
- Area *saved_atemp;
-#ifdef __GNUC__
- (void)&ps1;
-#endif
- ps1 = str_val(global("PS1"));
- shf = shf_sopen((char *) 0, strlen(ps1) * 2,
- SHF_WR | SHF_DYNAMIC, (struct shf *) 0);
- while (*ps1) {
- if (*ps1 != '!' || *++ps1 == '!')
- shf_putchar(*ps1++, shf);
- else
- shf_fprintf(shf, "%d",
- s ? s->line + 1 : 0);
- }
- ps1 = shf_sclose(shf);
- saved_atemp = ATEMP;
- newenv(E_ERRH);
- if (ksh_sigsetjmp(e->jbuf, 0)) {
- prompt = safe_prompt;
- /* Don't print an error - assume it has already
- * been printed. Reason is we may have forked
- * to run a command and the child may be
- * unwinding its stack through this code as it
- * exits.
- */
- } else
- prompt = str_save(substitute(ps1, 0),
- saved_atemp);
- quitenv();
- }
-#else /* KSH */
- prompt = str_val(global("PS1"));
-#endif /* KSH */
- break;
-
- case PS2: /* command continuation */
- prompt = str_val(global("PS2"));
- break;
- }
-}
-
-/* See also related routine, promptlen() in edit.c */
-void
-pprompt(cp, ntruncate)
- const char *cp;
- int ntruncate;
-{
-#if 0
- char nbuf[32];
- int c;
-
- while (*cp != 0) {
- if (*cp != '!')
- c = *cp++;
- else if (*++cp == '!')
- c = *cp++;
- else {
- int len;
- char *p;
-
- shf_snprintf(p = nbuf, sizeof(nbuf), "%d",
- source->line + 1);
- len = strlen(nbuf);
- if (ntruncate) {
- if (ntruncate >= len) {
- ntruncate -= len;
- continue;
- }
- p += ntruncate;
- len -= ntruncate;
- ntruncate = 0;
- }
- shf_write(p, len, shl_out);
- continue;
- }
- if (ntruncate)
- --ntruncate;
- else
- shf_putc(c, shl_out);
- }
-#endif /* 0 */
- shf_puts(cp + ntruncate, shl_out);
- shf_flush(shl_out);
-}
-
-/* Read the variable part of a ${...} expression (ie, up to but not including
- * the :[-+?=#%] or close-brace.
- */
-static char *
-get_brace_var(wsp, wp)
- XString *wsp;
- char *wp;
-{
- enum parse_state {
- PS_INITIAL, PS_SAW_HASH, PS_IDENT,
- PS_NUMBER, PS_VAR1, PS_END
- }
- state;
- char c;
-
- state = PS_INITIAL;
- while (1) {
- c = getsc();
- /* State machine to figure out where the variable part ends. */
- switch (state) {
- case PS_INITIAL:
- if (c == '#') {
- state = PS_SAW_HASH;
- break;
- }
- /* fall through.. */
- case PS_SAW_HASH:
- if (letter(c))
- state = PS_IDENT;
- else if (digit(c))
- state = PS_NUMBER;
- else if (ctype(c, C_VAR1))
- state = PS_VAR1;
- else
- state = PS_END;
- break;
- case PS_IDENT:
- if (!letnum(c)) {
- state = PS_END;
- if (c == '[') {
- char *tmp, *p;
-
- if (!arraysub(&tmp))
- yyerror("missing ]\n");
- *wp++ = c;
- for (p = tmp; *p; ) {
- Xcheck(*wsp, wp);
- *wp++ = *p++;
- }
- afree(tmp, ATEMP);
- c = getsc(); /* the ] */
- }
- }
- break;
- case PS_NUMBER:
- if (!digit(c))
- state = PS_END;
- break;
- case PS_VAR1:
- state = PS_END;
- break;
- case PS_END: /* keep gcc happy */
- break;
- }
- if (state == PS_END) {
- *wp++ = '\0'; /* end of variable part */
- ungetsc(c);
- break;
- }
- Xcheck(*wsp, wp);
- *wp++ = c;
- }
- return wp;
-}
-
-/*
- * Save an array subscript - returns true if matching bracket found, false
- * if eof or newline was found.
- * (Returned string double null terminated)
- */
-static int
-arraysub(strp)
- char **strp;
-{
- XString ws;
- char *wp;
- char c;
- int depth = 1; /* we are just past the initial [ */
-
- Xinit(ws, wp, 32, ATEMP);
-
- do {
- c = getsc();
- Xcheck(ws, wp);
- *wp++ = c;
- if (c == '[')
- depth++;
- else if (c == ']')
- depth--;
- } while (depth > 0 && c && c != '\n');
-
- *wp++ = '\0';
- *strp = Xclose(ws, wp);
-
- return depth == 0 ? 1 : 0;
-}
-
-/* Unget a char: handles case when we are already at the start of the buffer */
-static const char *
-ungetsc(c)
- int c;
-{
- if (backslash_skip)
- backslash_skip--;
- /* Don't unget eof... */
- if (source->str == null && c == '\0')
- return source->str;
- if (source->str > source->start)
- source->str--;
- else {
- Source *s;
-
- s = pushs(SREREAD, source->areap);
- s->ugbuf[0] = c; s->ugbuf[1] = '\0';
- s->start = s->str = s->ugbuf;
- s->next = source;
- source = s;
- }
- return source->str;
-}
-
-
-/* Called to get a char that isn't a \newline sequence. */
-static int
-getsc_bn ARGS((void))
-{
- int c, c2;
-
- if (ignore_backslash_newline)
- return getsc_();
-
- if (backslash_skip == 1) {
- backslash_skip = 2;
- return getsc_();
- }
-
- backslash_skip = 0;
-
- while (1) {
- c = getsc_();
- if (c == '\\') {
- if ((c2 = getsc_()) == '\n')
- /* ignore the \newline; get the next char... */
- continue;
- ungetsc(c2);
- backslash_skip = 1;
- }
- return c;
- }
-}
diff --git a/bin/pdksh/lex.h b/bin/pdksh/lex.h
deleted file mode 100644
index bca6446d268..00000000000
--- a/bin/pdksh/lex.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/* $OpenBSD: lex.h,v 1.3 1996/10/13 21:32:20 downsj Exp $ */
-
-/*
- * Source input, lexer and parser
- */
-
-/* $From: lex.h,v 1.4 1994/05/31 13:34:34 michael Exp $ */
-
-#define IDENT 64
-
-typedef struct source Source;
-struct source {
- const char *str; /* input pointer */
- int type; /* input type */
- char const *start; /* start of current buffer */
- union {
- char **strv; /* string [] */
- struct shf *shf; /* shell file */
- struct tbl *tblp; /* alias (SALIAS) */
- char *freeme; /* also for SREREAD */
- } u;
- char ugbuf[2]; /* buffer for ungetsc() (SREREAD) and
- * alias (SALIAS) */
- int line; /* line number */
- int errline; /* line the error occured on (0 if not set) */
- const char *file; /* input file name */
- int flags; /* SF_* */
- Area *areap;
- XString xs; /* input buffer */
- Source *next; /* stacked source */
-};
-
-/* Source.type values */
-#define SEOF 0 /* input EOF */
-#define SFILE 1 /* file input */
-#define SSTDIN 2 /* read stdin */
-#define SSTRING 3 /* string */
-#define SWSTR 4 /* string without \n */
-#define SWORDS 5 /* string[] */
-#define SWORDSEP 6 /* string[] seperator */
-#define SALIAS 7 /* alias expansion */
-#define SREREAD 8 /* read ahead to be re-scanned */
-
-/* Source.flags values */
-#define SF_ECHO BIT(0) /* echo input to shlout */
-#define SF_ALIAS BIT(1) /* faking space at end of alias */
-#define SF_ALIASEND BIT(2) /* faking space at end of alias */
-#define SF_TTY BIT(3) /* type == SSTDIN & it is a tty */
-
-/*
- * states while lexing word
- */
-#define SBASE 0 /* outside any lexical constructs */
-#define SWORD 1 /* implicit quoting for substitute() */
-#ifdef KSH
-#define SDPAREN 2 /* inside (( )), implicit quoting */
-#endif /* KSH */
-#define SSQUOTE 3 /* inside '' */
-#define SDQUOTE 4 /* inside "" */
-#define SBRACE 5 /* inside ${} */
-#define SPAREN 6 /* inside $() */
-#define SBQUOTE 7 /* inside `` */
-#define SDDPAREN 8 /* inside $(( )) */
-#define SHEREDELIM 9 /* parsing <<,<<- delimiter */
-#define SHEREDQUOTE 10 /* parsing " in <<,<<- delimiter */
-#define SPATTERN 11 /* parsing *(...|...) pattern (*+?@!) */
-#define STBRACE 12 /* parsing ${..[#%]..} */
-
-typedef union {
- int i;
- char *cp;
- char **wp;
- struct op *o;
- struct ioword *iop;
-} YYSTYPE;
-
-/* If something is added here, add it to tokentab[] in syn.c as well */
-#define LWORD 256
-#define LOGAND 257 /* && */
-#define LOGOR 258 /* || */
-#define BREAK 259 /* ;; */
-#define IF 260
-#define THEN 261
-#define ELSE 262
-#define ELIF 263
-#define FI 264
-#define CASE 265
-#define ESAC 266
-#define FOR 267
-#define SELECT 268
-#define WHILE 269
-#define UNTIL 270
-#define DO 271
-#define DONE 272
-#define IN 273
-#define FUNCTION 274
-#define TIME 275
-#define REDIR 276
-#ifdef KSH
-#define MDPAREN 277 /* (( )) */
-#endif /* KSH */
-#define BANG 278 /* ! */
-#define DBRACKET 279 /* [[ .. ]] */
-#define COPROC 280 /* |& */
-#define YYERRCODE 300
-
-/* flags to yylex */
-#define CONTIN BIT(0) /* skip new lines to complete command */
-#define ONEWORD BIT(1) /* single word for substitute() */
-#define ALIAS BIT(2) /* recognize alias */
-#define KEYWORD BIT(3) /* recognize keywords */
-#define LETEXPR BIT(4) /* get expression inside (( )) */
-#define VARASN BIT(5) /* check for var=word */
-#define ARRAYVAR BIT(6) /* parse x[1 & 2] as one word */
-#define ESACONLY BIT(7) /* only accept esac keyword */
-#define CMDWORD BIT(8) /* parsing simple command (alias related) */
-#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
-
-#define HERES 10 /* max << in line */
-
-EXTERN Source *source; /* yyparse/yylex source */
-EXTERN YYSTYPE yylval; /* result from yylex */
-EXTERN int yynerrs;
-EXTERN struct ioword *heres [HERES], **herep;
-EXTERN char ident [IDENT+1];
-
-#ifdef HISTORY
-# define HISTORYSIZE 128 /* size of saved history */
-
-EXTERN char **history; /* saved commands */
-EXTERN char **histptr; /* last history item */
-EXTERN int histsize; /* history size */
-#endif /* HISTORY */
diff --git a/bin/pdksh/mail.c b/bin/pdksh/mail.c
deleted file mode 100644
index 79ff7aee0f6..00000000000
--- a/bin/pdksh/mail.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/* $OpenBSD: mail.c,v 1.6 1997/11/16 12:07:28 niklas Exp $ */
-
-/*
- * Mailbox checking code by Robert J. Gibson, adapted for PD ksh by
- * John R. MacMillan
- */
-
-#include "config.h"
-
-#ifdef KSH
-#include "sh.h"
-#include "ksh_stat.h"
-#include "ksh_time.h"
-
-#define MBMESSAGE "you have mail in $_"
-
-typedef struct mbox {
- struct mbox *mb_next; /* next mbox in list */
- char *mb_path; /* path to mail file */
- char *mb_msg; /* to announce arrival of new mail */
- time_t mb_mtime; /* mtime of mail file */
-} mbox_t;
-
-/*
- * $MAILPATH is a linked list of mboxes. $MAIL is a treated as a
- * special case of $MAILPATH, where the list has only one node. The
- * same list is used for both since they are exclusive.
- */
-
-static mbox_t *mplist;
-static mbox_t mbox;
-static time_t mlastchkd; /* when mail was last checked */
-
-static void munset ARGS((mbox_t *mlist)); /* free mlist and mval */
-static mbox_t * mballoc ARGS((char *p, char *m)); /* allocate a new mbox */
-static void mprintit ARGS((mbox_t *mbp));
-
-void
-mcheck()
-{
- register mbox_t *mbp;
- time_t now;
- long mailcheck;
- struct tbl *vp;
- struct stat stbuf;
-
- if (getint(global("MAILCHECK"), &mailcheck) < 0)
- return;
-
- now = time((time_t *) 0);
- if (mlastchkd == 0)
- mlastchkd = now;
- if (now - mlastchkd >= mailcheck) {
- mlastchkd = now;
-
- vp = global("MAILPATH");
- if (vp && (vp->flag & ISSET))
- mbp = mplist;
- else if ((vp = global("MAIL")) && (vp->flag & ISSET))
- mbp = &mbox;
- else
- mbp = NULL;
-
- while (mbp) {
- if (mbp->mb_path && stat(mbp->mb_path, &stbuf) == 0
- && S_ISREG(stbuf.st_mode))
- {
- if (stbuf.st_size
- && mbp->mb_mtime != stbuf.st_mtime
- && stbuf.st_atime <= stbuf.st_mtime)
- mprintit(mbp);
- mbp->mb_mtime = stbuf.st_mtime;
- } else {
- /*
- * Some mail readers remove the mail
- * file if all mail is read. If file
- * does not exist, assume this is the
- * case and set mtime to zero.
- */
- mbp->mb_mtime = 0;
- }
- mbp = mbp->mb_next;
- }
- }
-}
-
-void
-mbset(p)
- register char *p;
-{
- struct stat stbuf;
-
- if (mbox.mb_msg)
- afree((void *)mbox.mb_msg, APERM);
- mbox.mb_path = p;
- mbox.mb_msg = NULL;
- if (p && stat(p,&stbuf) == 0 && S_ISREG(stbuf.st_mode))
- mbox.mb_mtime = stbuf.st_mtime;
- else
- mbox.mb_mtime = 0;
-}
-
-void
-mpset(mptoparse)
- register char *mptoparse;
-{
- register mbox_t *mbp;
- register char *mpath, *mmsg, *mval;
- char *p;
-
- munset( mplist );
- mplist = NULL;
- mval = str_save(mptoparse, APERM);
- while (mval) {
- mpath = mval;
- if ((mval = strchr(mval, PATHSEP)) != NULL) {
- *mval = '\0', mval++;
- }
- /* POSIX/bourne-shell say file%message */
- for (p = mpath; (mmsg = strchr(p, '%')); ) {
- /* a literal percent? (POSIXism) */
- if (mmsg[-1] == '\\') {
- /* use memmove() to avoid overlap problems */
- memmove(mmsg - 1, mmsg, strlen(mmsg) + 1);
- p = mmsg + 1;
- continue;
- }
- break;
- }
- /* at&t ksh says file?message */
- if (!mmsg && !Flag(FPOSIX))
- mmsg = strchr(mpath, '?');
- if (mmsg) {
- *mmsg = '\0';
- mmsg++;
- }
- mbp = mballoc(mpath, mmsg);
- mbp->mb_next = mplist;
- mplist = mbp;
- }
-}
-
-static void
-munset(mlist)
-register mbox_t *mlist;
-{
- register mbox_t *mbp;
-
- while (mlist != NULL) {
- mbp = mlist;
- mlist = mbp->mb_next;
- if (!mlist)
- afree((void *)mbp->mb_path, APERM);
- afree((void *)mbp, APERM);
- }
-}
-
-static mbox_t *
-mballoc(p, m)
- char *p;
- char *m;
-{
- struct stat stbuf;
- register mbox_t *mbp;
-
- mbp = (mbox_t *)alloc(sizeof(mbox_t), APERM);
- mbp->mb_next = NULL;
- mbp->mb_path = p;
- mbp->mb_msg = m;
- if (stat(mbp->mb_path, &stbuf) == 0 && S_ISREG(stbuf.st_mode))
- mbp->mb_mtime = stbuf.st_mtime;
- else
- mbp->mb_mtime = 0;
- return(mbp);
-}
-
-static void
-mprintit( mbp )
-mbox_t *mbp;
-{
- struct tbl *vp;
-
-#if 0
- /*
- * I doubt this $_ overloading is bad in /bin/sh mode. Anyhow, we
- * crash as the code looks now if we do not set vp. Now, this is
- * easy to fix too, but I'd like to see what POSIX says before doing
- * a change like that.
- */
- if (!Flag(FSH))
-#endif
- setstr((vp = local("_", FALSE)), mbp->mb_path);
-
- shellf("%s\n", substitute(mbp->mb_msg ? mbp->mb_msg : MBMESSAGE, 0));
-
- unset(vp, 0);
-}
-#endif /* KSH */
diff --git a/bin/pdksh/main.c b/bin/pdksh/main.c
deleted file mode 100644
index d161fb9b3d0..00000000000
--- a/bin/pdksh/main.c
+++ /dev/null
@@ -1,820 +0,0 @@
-/* $OpenBSD: main.c,v 1.9 1997/09/12 00:32:53 deraadt Exp $ */
-
-/*
- * startup, main loop, enviroments and error handling
- */
-
-#define EXTERN /* define EXTERNs in sh.h */
-
-#include "sh.h"
-#include "ksh_stat.h"
-#include "ksh_time.h"
-
-extern char **environ;
-
-/*
- * global data
- */
-
-static void reclaim ARGS((void));
-static void remove_temps ARGS((struct temp *tp));
-static int is_restricted ARGS((char *name));
-
-/*
- * shell initialization
- */
-
-static const char initifs [] = "IFS= \t\n"; /* must be R/W */
-
-static const char initsubs [] =
- "${PS2=> } ${PS3=#? } ${PS4=+ }";
-
-static const char version_param[] =
-#ifdef KSH
- "KSH_VERSION"
-#else /* KSH */
- "SH_VERSION"
-#endif /* KSH */
- ;
-
-static const char *const initcoms [] = {
- "typeset", "-x", "SHELL", "PATH", "HOME", NULL,
- "typeset", "-r", version_param, NULL,
- "typeset", "-ri", "PPID", NULL,
- "typeset", "-i", "OPTIND=1",
-#ifdef KSH
- "MAILCHECK=600", "RANDOM", "SECONDS=0", "TMOUT=0",
-#endif /* KSH */
- NULL,
- "alias",
- /* Standard ksh aliases */
- "hash=alias -t", /* not "alias -t --": hash -r needs to work */
- "type=whence -v",
-#ifdef JOBS
- "stop=kill -STOP",
- "suspend=kill -STOP $$",
-#endif
-#ifdef KSH
- "autoload=typeset -fu",
- "functions=typeset -f",
-# ifdef HISTORY
- "history=fc -l",
-# endif /* HISTORY */
- "integer=typeset -i",
- "nohup=nohup ",
- "local=typeset",
- "r=fc -e -",
-#endif /* KSH */
-#ifdef KSH
- /* Aliases that are builtin commands in at&t */
- "login=exec login",
- "newgrp=exec newgrp",
-#endif /* KSH */
- NULL,
- /* this is what at&t ksh seems to track, with the addition of emacs */
- "alias", "-tU",
- "cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
- "mail", "make", "mv", "pr", "rm", "sed", "sh", "vi", "who",
- NULL,
-#ifdef EXTRA_INITCOMS
- EXTRA_INITCOMS, NULL,
-#endif /* EXTRA_INITCOMS */
- NULL
-};
-
-int
-main(argc, argv)
- int argc;
- register char **argv;
-{
- register int i;
- int argi;
- Source *s;
- struct block *l;
- int restricted;
- char **wp;
- struct env env;
- int euid;
-
-#ifdef MEM_DEBUG
- chmem_push("+c", 1);
- /*chmem_push("+cd", 1);*/
-#endif
-
-#ifdef OS2
- setmode (0, O_BINARY);
- setmode (1, O_TEXT);
-#endif
-
- /* make sure argv[] is sane */
- if (!*argv) {
- static const char *empty_argv[] = {
- "pdksh", (char *) 0
- };
-
- argv = (char **) empty_argv;
- argc = 1;
- }
- kshname = *argv;
-
- ainit(&aperm); /* initialize permanent Area */
-
- /* set up base enviroment */
- memset(&env, 0, sizeof(env));
- env.type = E_NONE;
- ainit(&env.area);
- e = &env;
- newblock(); /* set up global l->vars and l->funs */
-
- /* Do this first so output routines (eg, errorf, shellf) can work */
- initio();
-
- initvar();
-
- initctypes();
-
- inittraps();
-
-#ifdef KSH
- coproc_init();
-#endif /* KSH */
-
- /* set up variable and command dictionaries */
- tinit(&taliases, APERM, 0);
- tinit(&aliases, APERM, 0);
- tinit(&homedirs, APERM, 0);
-
- /* define shell keywords */
- initkeywords();
-
- /* define built-in commands */
- tinit(&builtins, APERM, 64); /* must be 2^n (currently 40 builtins) */
- for (i = 0; shbuiltins[i].name != NULL; i++)
- builtin(shbuiltins[i].name, shbuiltins[i].func);
- for (i = 0; kshbuiltins[i].name != NULL; i++)
- builtin(kshbuiltins[i].name, kshbuiltins[i].func);
-
- init_histvec();
-
- def_path = DEFAULT__PATH;
-#if defined(HAVE_CONFSTR) && defined(_CS_PATH)
- {
- size_t len = confstr(_CS_PATH, (char *) 0, 0);
- char *new;
-
- if (len > 0) {
- confstr(_CS_PATH, new = alloc(len + 1, APERM), len + 1);
- def_path = new;
- }
- }
-#endif /* HAVE_CONFSTR && _CS_PATH */
- path = def_path;
-
-
- /* Turn on nohup by default for how - will change to off
- * by default once people are aware of its existance
- * (at&t ksh does not have a nohup option - it always sends
- * the hup).
- */
- Flag(FNOHUP) = 1;
-
- /* Turn on brace expansion by default. At&t ksh's that have
- * alternation always have it on. BUT, posix doesn't have
- * brace expansion, so set this before setting up FPOSIX
- * (change_flag() clears FBRACEEXPAND when FPOSIX is set).
- */
-#ifdef BRACE_EXPAND
- Flag(FBRACEEXPAND) = 1;
-#endif /* BRACE_EXPAND */
-
- /* set posix flag just before environment so that it will have
- * exactly the same effect as the POSIXLY_CORRECT environment
- * variable. If this needs to be done sooner to ensure correct posix
- * operation, an initial scan of the environment will also have
- * done sooner.
- */
-#ifdef POSIXLY_CORRECT
- change_flag(FPOSIX, OF_SPECIAL, 1);
-#endif /* POSIXLY_CORRECT */
-
- /* Check to see if we're /bin/sh. */
- if (!strcmp(&kshname[strlen(kshname) - 3], "/sh")
- || !strcmp(kshname, "sh") || !strcmp(kshname, "-sh"))
- Flag(FSH) = 1;
-
- /* import enviroment */
- if (environ != NULL)
- for (wp = environ; *wp != NULL; wp++)
- typeset(*wp, IMPORT|EXPORT, 0, 0, 0);
-
- kshpid = procpid = getpid();
- typeset(initifs, 0, 0, 0, 0); /* for security */
-
- /* assign default shell variable values */
- substitute(initsubs, 0);
-
- /* Figure out the current working directory and set $PWD */
- {
- struct stat s_pwd, s_dot;
- struct tbl *pwd_v = global("PWD");
- char *pwd = str_val(pwd_v);
- char *pwdx = pwd;
-
- /* Try to use existing $PWD if it is valid */
- if (!ISABSPATH(pwd)
- || stat(pwd, &s_pwd) < 0 || stat(".", &s_dot) < 0
- || s_pwd.st_dev != s_dot.st_dev
- || s_pwd.st_ino != s_dot.st_ino)
- pwdx = (char *) 0;
- set_current_wd(pwdx);
- if (current_wd[0])
- simplify_path(current_wd);
- /* Only set pwd if we know where we are or if it had a
- * bogus value
- */
- if (current_wd[0] || pwd != null)
- setstr(pwd_v, current_wd);
- }
- setint(global("PPID"), (long) getppid());
-#ifdef KSH
- setint(global("RANDOM"), (long) time((time_t *)0));
-#endif /* KSH */
- setstr(global(version_param), ksh_version);
-
- /* execute initialization statements */
- for (wp = (char**) initcoms; *wp != NULL; wp++) {
- shcomexec(wp);
- for (; *wp != NULL; wp++)
- ;
- }
-
- euid = geteuid();
- safe_prompt = euid ? "$ " : "# ";
- {
- struct tbl *vp = global("PS1");
-
- /* Set PS1 if it isn't set, or we are root and prompt doesn't
- * contain a #.
- */
- if (!(vp->flag & ISSET) || (!euid && !strchr(str_val(vp), '#')))
- setstr(vp, safe_prompt);
- }
-
- /* Set this before parsing arguments */
- Flag(FPRIVILEGED) = getuid() != euid || getgid() != getegid();
-
- /* this to note if monitor is set on command line (see below) */
- Flag(FMONITOR) = 127;
- argi = parse_args(argv, OF_CMDLINE, (int *) 0);
- if (argi < 0)
- exit(1);
-
- if (Flag(FCOMMAND)) {
- s = pushs(SSTRING, ATEMP);
- if (!(s->start = s->str = argv[argi++]))
- errorf("-c requires an argument");
- if (argv[argi])
- kshname = argv[argi++];
- } else if (argi < argc && !Flag(FSTDIN)) {
- s = pushs(SFILE, ATEMP);
-#ifdef OS2
- /* a bug in os2 extproc shell processing doesn't
- * pass full pathnames so we have to search for it.
- * This changes the behavior of 'ksh arg' to search
- * the users search path but it can't be helped.
- */
- s->file = search(argv[argi++], path, R_OK, (int *) 0);
- if (!s->file || !*s->file)
- s->file = argv[argi - 1];
-#else
- s->file = argv[argi++];
-#endif /* OS2 */
- s->u.shf = shf_open(s->file, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
- if (s->u.shf == NULL) {
- exstat = 127; /* POSIX */
- errorf("%s: %s", s->file, strerror(errno));
- }
- kshname = s->file;
- } else {
- Flag(FSTDIN) = 1;
- s = pushs(SSTDIN, ATEMP);
- s->file = "<stdin>";
- s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0),
- (struct shf *) 0);
- if (isatty(0) && isatty(2)) {
- Flag(FTALKING) = 1;
- /* The following only if isatty(0) */
- s->flags |= SF_TTY;
- s->u.shf->flags |= SHF_INTERRUPT;
- s->file = (char *) 0;
- }
- }
-
- /* This bizarreness is mandated by POSIX */
- {
- struct stat s_stdin;
-
- if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode))
- reset_nonblock(0);
- }
-
- /* initialize job control */
- i = Flag(FMONITOR) != 127;
- Flag(FMONITOR) = 0;
- j_init(i);
-#ifdef EDIT
- /* Do this after j_init(), as tty_fd is not initialized 'til then */
- if (Flag(FTALKING))
- x_init();
-#endif
-
- l = e->loc;
- l->argv = &argv[argi - 1];
- l->argc = argc - argi;
- l->argv[0] = (char *) kshname;
- getopts_reset(1);
-
- /* Disable during .profile/ENV reading */
- restricted = Flag(FRESTRICTED);
- Flag(FRESTRICTED) = 0;
-
- /* Do this before profile/$ENV so that if it causes problems in them,
- * user will know why things broke.
- */
- if (!current_wd[0] && Flag(FTALKING))
- warningf(FALSE, "Cannot determine current working directory");
-
- if (Flag(FLOGIN)) {
-#ifdef OS2
- char *profile;
-
- /* Try to find a profile - first see if $INIT has a value,
- * then try /etc/profile.ksh, then c:/usr/etc/profile.ksh.
- */
- if (!Flag(FPRIVILEGED)
- && strcmp(profile = substitute("$INIT/profile.ksh", 0),
- "/profile.ksh"))
- include(profile, 0, (char **) 0, 1);
- else if (include("/etc/profile.ksh", 0, (char **) 0, 1) < 0)
- include("c:/usr/etc/profile.ksh", 0, (char **) 0, 1);
- if (!Flag(FPRIVILEGED))
- include(substitute("$HOME/profile.ksh", 0), 0,
- (char **) 0, 1);
-#else /* OS2 */
- include(KSH_SYSTEM_PROFILE, 0, (char **) 0, 1);
- if (!Flag(FPRIVILEGED))
- include(substitute("$HOME/.profile", 0), 0,
- (char **) 0, 1);
-#endif /* OS2 */
- }
-
- if (Flag(FPRIVILEGED))
- include("/etc/suid_profile", 0, (char **) 0, 1);
- else {
- char *env_file;
-
-#ifndef KSH
- if (!Flag(FPOSIX))
- env_file = null;
- else
-#endif /* !KSH */
- /* include $ENV */
- env_file = str_val(global("ENV"));
-
-#ifdef DEFAULT_ENV
- /* If env isn't set, include default environment */
- if (env_file == null)
- env_file = DEFAULT_ENV;
-#endif /* DEFAULT_ENV */
- env_file = substitute(env_file, DOTILDE);
- if (*env_file != '\0')
- include(env_file, 0, (char **) 0, 1);
-#ifdef OS2
- else if (Flag(FTALKING))
- include(substitute("$HOME/kshrc.ksh", 0), 0,
- (char **) 0, 1);
-#endif /* OS2 */
- }
-
- if (is_restricted(argv[0]) || is_restricted(str_val(global("SHELL"))))
- restricted = 1;
- if (restricted) {
- static const char *const restr_com[] = {
- "typeset", "-r", "PATH",
- "ENV", "SHELL",
- (char *) 0
- };
- shcomexec((char **) restr_com);
- /* After typeset command... */
- Flag(FRESTRICTED) = 1;
- }
-
- if (Flag(FTALKING)) {
- hist_init(s);
-#ifdef KSH
- alarm_init();
-#endif /* KSH */
- } else
- Flag(FTRACKALL) = 1; /* set after ENV */
-
- shell(s, TRUE); /* doesn't return */
- return 0;
-}
-
-int
-include(name, argc, argv, intr_ok)
- const char *name;
- int argc;
- char **argv;
- int intr_ok;
-{
- register Source *volatile s = NULL;
- Source *volatile sold;
- struct shf *shf;
- char **volatile old_argv;
- volatile int old_argc;
- int i;
-
- shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
- if (shf == NULL)
- return -1;
-
- if (argv) {
- old_argv = e->loc->argv;
- old_argc = e->loc->argc;
- } else {
- old_argv = (char **) 0;
- old_argc = 0;
- }
- sold = source;
- newenv(E_INCL);
- i = ksh_sigsetjmp(e->jbuf, 0);
- if (i) {
- quitenv();
- source = sold;
- if (s)
- shf_close(s->u.shf);
- if (old_argv) {
- e->loc->argv = old_argv;
- e->loc->argc = old_argc;
- }
- switch (i) {
- case LRETURN:
- case LERROR:
- return exstat & 0xff; /* see below */
- case LINTR:
- /* intr_ok is set if we are including .profile or $ENV.
- * If user ^C's out, we don't want to kill the shell...
- */
- if (intr_ok && (exstat - 128) != SIGTERM)
- return 1;
- /* fall through... */
- case LEXIT:
- case LLEAVE:
- case LSHELL:
- unwind(i);
- /*NOREACHED*/
- default:
- internal_errorf(1, "include: %d", i);
- /*NOREACHED*/
- }
- }
- if (argv) {
- e->loc->argv = argv;
- e->loc->argc = argc;
- }
- s = pushs(SFILE, ATEMP);
- s->u.shf = shf;
- s->file = str_save(name, ATEMP);
- i = shell(s, FALSE);
- source = sold;
- shf_close(s->u.shf);
- quitenv();
- if (old_argv) {
- e->loc->argv = old_argv;
- e->loc->argc = old_argc;
- }
- return i & 0xff; /* & 0xff to ensure value not -1 */
-}
-
-int
-command(comm)
- const char *comm;
-{
- register Source *s;
-
- s = pushs(SSTRING, ATEMP);
- s->start = s->str = comm;
- return shell(s, FALSE);
-}
-
-/*
- * run the commands from the input source, returning status.
- */
-int
-shell(s, toplevel)
- Source *volatile s; /* input source */
- int volatile toplevel;
-{
- struct op *t;
- volatile int wastty = s->flags & SF_TTY;
- volatile int attempts = 13;
- volatile int interactive = Flag(FTALKING) && toplevel;
- int i;
-
- newenv(E_PARSE);
- if (interactive)
- really_exit = 0;
- i = ksh_sigsetjmp(e->jbuf, 0);
- if (i) {
- s->start = s->str = null;
- switch (i) {
- case LINTR: /* we get here if SIGINT not caught or ignored */
- case LERROR:
- case LSHELL:
- if (interactive) {
- if (i == LINTR)
- shellf(newline);
- /* Reset any eof that was read as part of a
- * multiline command.
- */
- if (Flag(FIGNOREEOF) && s->type == SEOF
- && wastty)
- s->type = SSTDIN;
- /* Used by exit command to get back to
- * top level shell. Kind of strange since
- * interactive is set if we are reading from
- * a tty, but to have stopped jobs, one only
- * needs FMONITOR set (not FTALKING/SF_TTY)...
- */
- break;
- }
- /* fall through... */
- case LEXIT:
- case LLEAVE:
- case LRETURN:
- quitenv();
- unwind(i); /* keep on going */
- /*NOREACHED*/
- default:
- quitenv();
- internal_errorf(1, "shell: %d", i);
- /*NOREACHED*/
- }
- }
-
- while (1) {
- if (trap)
- runtraps(0);
-
- if (s->next == NULL)
- if (Flag(FVERBOSE))
- s->flags |= SF_ECHO;
- else
- s->flags &= ~SF_ECHO;
-
- if (interactive) {
- j_notify();
-#ifdef KSH
- mcheck();
-#endif /* KSH */
- set_prompt(PS1, s);
- }
-
- t = compile(s);
- if (t != NULL && t->type == TEOF) {
- if (wastty && Flag(FIGNOREEOF) && --attempts > 0) {
- shellf("Use `exit' to leave ksh\n");
- s->type = SSTDIN;
- } else if (wastty && !really_exit
- && j_stopped_running())
- {
- really_exit = 1;
- s->type = SSTDIN;
- } else {
- /* this for POSIX, which says EXIT traps
- * shall be taken in the environment
- * immediately after the last command
- * executed.
- */
- if (toplevel)
- unwind(LEXIT);
- break;
- }
- }
-
- if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY)))
- exstat = execute(t, 0);
-
- if (t != NULL && t->type != TEOF && interactive && really_exit)
- really_exit = 0;
-
- reclaim();
- }
- quitenv();
- return exstat;
-}
-
-/* return to closest error handler or shell(), exit if none found */
-void
-unwind(i)
- int i;
-{
- /* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */
- if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR)
- && sigtraps[SIGEXIT_].trap))
- {
- runtrap(&sigtraps[SIGEXIT_]);
- i = LLEAVE;
- } else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) {
- runtrap(&sigtraps[SIGERR_]);
- i = LLEAVE;
- }
- while (1) {
- switch (e->type) {
- case E_PARSE:
- case E_FUNC:
- case E_INCL:
- case E_LOOP:
- case E_ERRH:
- ksh_siglongjmp(e->jbuf, i);
- /*NOTREACHED*/
-
- case E_NONE: /* bottom of the stack */
- {
- if (Flag(FTALKING))
- hist_finish();
- j_exit();
- remove_temps(func_heredocs);
- if (i == LINTR) {
- int sig = exstat - 128;
-
- /* ham up our death a bit (at&t ksh
- * only seems to do this for SIGTERM)
- * Don't do it for SIGQUIT, since we'd
- * dump a core..
- */
- if (sig == SIGINT || sig == SIGTERM) {
- setsig(&sigtraps[sig], SIG_DFL,
- SS_RESTORE_CURR|SS_FORCE);
- kill(0, sig);
- }
- }
- exit(exstat);
- /* NOTREACHED */
- }
-
- default:
- quitenv();
- }
- }
-}
-
-void
-newenv(type)
- int type;
-{
- register struct env *ep;
-
- ep = (struct env *) alloc(sizeof(*ep), ATEMP);
- ep->type = type;
- ep->flags = 0;
- ainit(&ep->area);
- ep->loc = e->loc;
- ep->savefd = NULL;
- ep->oenv = e;
- ep->temps = NULL;
- e = ep;
-}
-
-void
-quitenv()
-{
- register struct env *ep = e;
- register int fd;
-
- if (ep->oenv == NULL) /* cleanup_parents_env() was called */
- exit(exstat); /* exit child */
- if (ep->oenv->loc != ep->loc)
- popblock();
- if (ep->savefd != NULL) {
- for (fd = 0; fd < NUFILE; fd++)
- /* if ep->savefd[fd] < 0, means fd was closed */
- if (ep->savefd[fd])
- restfd(fd, ep->savefd[fd]);
- if (ep->savefd[2]) /* Clear any write errors */
- shf_reopen(2, SHF_WR, shl_out);
- }
- reclaim();
- e = e->oenv;
- afree(ep, ATEMP);
-}
-
-/* Called after a fork to cleanup stuff left over from parents environment */
-void
-cleanup_parents_env()
-{
- struct env *ep;
- int fd;
-
- /* Don't clean up temporary files - parent will probably need them.
- * Also, can't easily reclaim memory since variables, etc. could be
- * anywyere.
- */
-
- /* close all file descriptors hiding in savefd */
- for (ep = e; ep; ep = ep->oenv) {
- if (ep->savefd)
- for (fd = 0; fd < NUFILE; fd++)
- if (ep->savefd[fd] > 0)
- close(ep->savefd[fd]);
- }
- e->oenv = (struct env *) 0;
-}
-
-/* Called just before an execve cleanup stuff temporary files */
-void
-cleanup_proc_env()
-{
- struct env *ep;
-
- for (ep = e; ep; ep = ep->oenv)
- remove_temps(ep->temps);
- remove_temps(func_heredocs);
-}
-
-/* remove temp files and free ATEMP Area */
-static void
-reclaim()
-{
- remove_temps(e->temps);
- e->temps = NULL;
- afreeall(&e->area);
-}
-
-static void
-remove_temps(tp)
- struct temp *tp;
-{
-#ifdef OS2
- static struct temp *delayed_remove;
- struct temp *t, **tprev;
-
- if (delayed_remove) {
- for (tprev = &delayed_remove, t = delayed_remove; t; t = *tprev)
- /* No need to check t->pid here... */
- if (unlink(t->name) >= 0 || errno == ENOENT) {
- *tprev = t->next;
- afree(t, APERM);
- } else
- tprev = &t->next;
- }
-#endif /* OS2 */
-
- for (; tp != NULL; tp = tp->next)
- if (tp->pid == procpid) {
-#ifdef OS2
- /* OS/2 (and dos) do not allow files that are currently
- * open to be removed, so we cache it away for future
- * removal.
- * XXX should only do this if errno
- * is Efile-still-open-can't-remove
- * (but I don't know what that is...)
- */
- if (unlink(tp->name) < 0 && errno != ENOENT) {
- t = (struct temp *) alloc(
- sizeof(struct temp) + strlen(tp->name) + 1,
- APERM);
- memset(t, 0, sizeof(struct temp));
- strcpy(t->name, tp->name);
- t->next = delayed_remove;
- delayed_remove = t;
- }
-#else /* OS2 */
- unlink(tp->name);
-#endif /* OS2 */
- }
-}
-
-/* Returns true if name refers to a restricted shell */
-static int
-is_restricted(name)
- char *name;
-{
- char *p;
-
- if ((p = ksh_strrchr_dirsep(name)))
- name = p;
- /* accepts rsh, rksh, rpdksh, pdrksh, etc. */
- return (p = strchr(name, 'r')) && strstr(p, "sh");
-}
-
-void
-aerror(ap, msg)
- Area *ap;
- const char *msg;
-{
- internal_errorf(1, "alloc: %s", msg);
- errorf(null); /* this is never executed - keeps gcc quiet */
- /*NOTREACHED*/
-}
diff --git a/bin/pdksh/misc.c b/bin/pdksh/misc.c
deleted file mode 100644
index 5287f4e9dfa..00000000000
--- a/bin/pdksh/misc.c
+++ /dev/null
@@ -1,1318 +0,0 @@
-/* $OpenBSD: misc.c,v 1.6 1997/06/19 13:58:45 kstailey Exp $ */
-
-/*
- * Miscellaneous functions
- */
-
-#include "sh.h"
-#include <ctype.h> /* for FILECHCONV */
-#ifdef HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#ifndef UCHAR_MAX
-# define UCHAR_MAX 0xFF
-#endif
-
-short ctypes [UCHAR_MAX+1]; /* type bits for unsigned char */
-
-static int do_gmatch ARGS((const unsigned char *s, const unsigned char *p,
- const unsigned char *se, const unsigned char *pe,
- int isfile));
-static const unsigned char *cclass ARGS((const unsigned char *p, int sub));
-
-/*
- * Fast character classes
- */
-void
-setctypes(s, t)
- register const char *s;
- register int t;
-{
- register int i;
-
- if (t & C_IFS) {
- for (i = 0; i < UCHAR_MAX+1; i++)
- ctypes[i] &= ~C_IFS;
- ctypes[0] |= C_IFS; /* include \0 in C_IFS */
- }
- while (*s != 0)
- ctypes[(unsigned char) *s++] |= t;
-}
-
-void
-initctypes()
-{
- register int c;
-
- for (c = 'a'; c <= 'z'; c++)
- ctypes[c] |= C_ALPHA;
- for (c = 'A'; c <= 'Z'; c++)
- ctypes[c] |= C_ALPHA;
- ctypes['_'] |= C_ALPHA;
- setctypes("0123456789", C_DIGIT);
- setctypes(" \t\n|&;<>()", C_LEX1); /* \0 added automatically */
- setctypes("*@#!$-?", C_VAR1);
- setctypes(" \t\n", C_IFSWS);
- setctypes("=-+?", C_SUBOP1);
- setctypes("#%", C_SUBOP2);
- setctypes(" \n\t\"#$&'()*;<>?[\\`|", C_QUOTE);
-}
-
-/* convert unsigned long to base N string */
-
-char *
-ulton(n, base)
- register unsigned long n;
- int base;
-{
- register char *p;
- static char buf [20];
-
- p = &buf[sizeof(buf)];
- *--p = '\0';
- do {
- *--p = "0123456789ABCDEF"[n%base];
- n /= base;
- } while (n != 0);
- return p;
-}
-
-char *
-str_save(s, ap)
- register const char *s;
- Area *ap;
-{
- return s ? strcpy((char*) alloc((size_t)strlen(s)+1, ap), s) : NULL;
-}
-
-/* Allocate a string of size n+1 and copy upto n characters from the possibly
- * null terminated string s into it. Always returns a null terminated string
- * (unless n < 0).
- */
-char *
-str_nsave(s, n, ap)
- register const char *s;
- int n;
- Area *ap;
-{
- char *ns;
-
- if (n < 0)
- return 0;
- ns = alloc(n + 1, ap);
- ns[0] = '\0';
- return strncat(ns, s, n);
-}
-
-/* called from expand.h:XcheckN() to grow buffer */
-char *
-Xcheck_grow_(xsp, xp, more)
- XString *xsp;
- char *xp;
- int more;
-{
- char *old_beg = xsp->beg;
-
- xsp->len += more > xsp->len ? more : xsp->len;
- xsp->beg = aresize(xsp->beg, xsp->len + 8, xsp->areap);
- xsp->end = xsp->beg + xsp->len;
- return xsp->beg + (xp - old_beg);
-}
-
-const struct option options[] = {
- /* Special cases (see parse_args()): -A, -o, -s.
- * Options are sorted by their longnames - the order of these
- * entries MUST match the order of sh_flag F* enumerations in sh.h.
- */
- { "allexport", 'a', OF_ANY },
-#ifdef BRACE_EXPAND
- { "braceexpand", 0, OF_ANY }, /* non-standard */
-#endif
- { "bgnice", 0, OF_ANY },
- { null, 'c', OF_CMDLINE },
-#ifdef EMACS
- { "emacs", 0, OF_ANY },
-#endif
- { "errexit", 'e', OF_ANY },
-#ifdef EMACS
- { "gmacs", 0, OF_ANY },
-#endif
- { "ignoreeof", 0, OF_ANY },
- { "interactive",'i', OF_CMDLINE },
- { "keyword", 'k', OF_ANY },
- { "login", 'l', OF_CMDLINE },
- { "markdirs", 'X', OF_ANY },
-#ifdef JOBS
- { "monitor", 'm', OF_ANY },
-#else /* JOBS */
- { null, 'm', 0 }, /* so FMONITOR not ifdef'd */
-#endif /* JOBS */
- { "noclobber", 'C', OF_ANY },
- { "noexec", 'n', OF_ANY },
- { "noglob", 'f', OF_ANY },
- { "nohup", 0, OF_ANY },
- { "nolog", 0, OF_ANY }, /* no effect */
-#ifdef JOBS
- { "notify", 'b', OF_ANY },
-#endif /* JOBS */
- { "nounset", 'u', OF_ANY },
- { "physical", 0, OF_ANY }, /* non-standard */
- { "posix", 0, OF_ANY }, /* non-standard */
- { "privileged", 'p', OF_ANY },
- { "restricted", 'r', OF_CMDLINE },
- { "sh", 0, OF_ANY }, /* non-standard */
- { "stdin", 's', OF_CMDLINE }, /* pseudo non-standard */
- { "trackall", 'h', OF_ANY },
- { "verbose", 'v', OF_ANY },
-#ifdef VI
- { "vi", 0, OF_ANY },
- { "viraw", 0, OF_ANY }, /* no effect */
- { "vi-show8", 0, OF_ANY }, /* non-standard */
- { "vi-tabcomplete", 0, OF_ANY }, /* non-standard */
- { "vi-esccomplete", 0, OF_ANY }, /* non-standard */
-#endif
- { "xtrace", 'x', OF_ANY },
- { NULL, 0, 0 }
-};
-
-/*
- * translate -o option into F* constant (also used for test -o option)
- */
-int
-option(n)
- const char *n;
-{
- int i;
-
- for (i = 0; options[i].name; i++)
- if (strcmp(options[i].name, n) == 0)
- return i;
-
- return -1;
-}
-
-struct options_info {
- int opt_width;
- struct {
- const char *name;
- int flag;
- } opts[NELEM(options)];
-};
-
-static char *options_fmt_entry ARGS((void *arg, int i, char *buf, int buflen));
-static void printoptions ARGS((int verbose));
-
-/* format a single select menu item */
-static char *
-options_fmt_entry(arg, i, buf, buflen)
- void *arg;
- int i;
- char *buf;
- int buflen;
-{
- struct options_info *oi = (struct options_info *) arg;
-
- shf_snprintf(buf, buflen, "%-*s %s",
- oi->opt_width, oi->opts[i].name,
- Flag(oi->opts[i].flag) ? "on" : "off");
- return buf;
-}
-
-static void
-printoptions(verbose)
- int verbose;
-{
- int i;
-
- if (verbose) {
- struct options_info oi;
- int n, len;
-
- /* verbose version */
- shprintf("Current option settings\n");
-
- for (i = n = oi.opt_width = 0; options[i].name; i++)
- if (options[i].name[0]) {
- len = strlen(options[i].name);
- oi.opts[n].name = options[i].name;
- oi.opts[n++].flag = i;
- if (len > oi.opt_width)
- oi.opt_width = len;
- }
- print_columns(shl_stdout, n, options_fmt_entry, &oi,
- oi.opt_width + 5);
- } else {
- /* short version ala ksh93 */
- shprintf("set");
- for (i = 0; options[i].name; i++)
- if (Flag(i) && options[i].name[0])
- shprintf(" -o %s", options[i].name);
- shprintf(newline);
- }
-}
-
-char *
-getoptions()
-{
- int i;
- char m[FNFLAGS + 1];
- register char *cp = m;
-
- for (i = 0; options[i].name; i++)
- if (options[i].c && Flag(i))
- *cp++ = options[i].c;
- *cp = 0;
- return str_save(m, ATEMP);
-}
-
-/* change a Flag(*) value; takes care of special actions */
-void
-change_flag(f, what, newval)
- enum sh_flag f; /* flag to change */
- int what; /* what is changing the flag (command line vs set) */
- int newval;
-{
- int oldval;
-
- oldval = Flag(f);
- Flag(f) = newval;
-#ifdef JOBS
- if (f == FMONITOR) {
- if (what != OF_CMDLINE && newval != oldval)
- j_change();
- } else
-#endif /* JOBS */
-#ifdef EDIT
- if (0
-# ifdef VI
- || f == FVI
-# endif /* VI */
-# ifdef EMACS
- || f == FEMACS || f == FGMACS
-# endif /* EMACS */
- )
- {
- if (newval) {
-# ifdef VI
- Flag(FVI) = 0;
-# endif /* VI */
-# ifdef EMACS
- Flag(FEMACS) = Flag(FGMACS) = 0;
-# endif /* EMACS */
- Flag(f) = newval;
- }
- } else
-#endif /* EDIT */
- /* Turning off -p? */
- if (f == FPRIVILEGED && oldval && !newval) {
-#ifdef OS2
- ;
-#else /* OS2 */
- seteuid(getuid());
- setuid(getuid());
- setegid(getgid());
- setgid(getgid());
-#endif /* OS2 */
- } else if (f == FPOSIX && newval) {
-#ifdef BRACE_EXPAND
- Flag(FBRACEEXPAND) = 0
-#endif /* BRACE_EXPAND */
- ;
- }
-}
-
-/* parse command line & set command arguments. returns the index of
- * non-option arguments, -1 if there is an error.
- */
-int
-parse_args(argv, what, setargsp)
- char **argv;
- int what; /* OF_CMDLINE or OF_SET */
- int *setargsp;
-{
- static char cmd_opts[NELEM(options) + 3]; /* o:\0 */
- static char set_opts[NELEM(options) + 5]; /* Ao;s\0 */
- char *opts;
- char *array;
- Getopt go;
- int i, optc, set, sortargs = 0, arrayset = 0;
-
- /* First call? Build option strings... */
- if (cmd_opts[0] == '\0') {
- char *p;
-
- /* c is also in options[], but it needs a trailing : */
- strcpy(cmd_opts, "o:"); /* see cmd_opts[] declaration */
- p = cmd_opts + strlen(cmd_opts);
- for (i = 0; options[i].name; i++)
- if (options[i].c && (options[i].flags & OF_CMDLINE))
- *p++ = options[i].c;
- *p = '\0';
-
- strcpy(set_opts, "Ao;s"); /* see set_opts[] declaration */
- p = set_opts + strlen(set_opts);
- for (i = 0; options[i].name; i++)
- if (options[i].c && (options[i].flags & OF_SET))
- *p++ = options[i].c;
- *p = '\0';
- }
-
- if (what == OF_CMDLINE) {
- char *p;
- /* Set FLOGIN before parsing options so user can clear
- * flag using +l.
- */
- Flag(FLOGIN) = (argv[0][0] == '-'
- || ((p = ksh_strrchr_dirsep(argv[0]))
- && *++p == '-'));
- opts = cmd_opts;
- } else
- opts = set_opts;
- ksh_getopt_reset(&go, GF_ERROR|GF_PLUSOPT);
- while ((optc = ksh_getopt(argv, &go, opts)) != EOF) {
- set = (go.info & GI_PLUS) ? 0 : 1;
- switch (optc) {
- case 'A':
- arrayset = set ? 1 : -1;
- break;
-
- case 'o':
- if (go.optarg == (char *) 0) {
- /* lone -o: print options
- *
- * Note that on the command line, -o requires
- * an option (ie, can't get here if what is
- * OF_CMDLINE).
- */
- printoptions(set);
- break;
- }
- i = option(go.optarg);
- if (i >= 0 && set == Flag(i))
- /* Don't check the context if the flag
- * isn't changing - makes "set -o interactive"
- * work if you're already interactive. Needed
- * if the output of "set +o" is to be used.
- */
- ;
- else if (i >= 0 && (options[i].flags & what))
- change_flag((enum sh_flag) i, what, set);
- else {
- bi_errorf("%s: bad option", go.optarg);
- return -1;
- }
- break;
-
- case '?':
- return -1;
-
- default:
- /* -s: sort positional params (at&t ksh stupidity) */
- if (what == OF_SET && optc == 's') {
- sortargs = 1;
- break;
- }
- for (i = 0; options[i].name; i++)
- if (optc == options[i].c
- && (what & options[i].flags))
- {
- change_flag((enum sh_flag) i, what,
- set);
- break;
- }
- if (!options[i].name) {
- internal_errorf(1, "parse_args: `%c'", optc);
- return -1; /* not reached */
- }
- }
- }
- if (!(go.info & GI_MINUSMINUS) && argv[go.optind]
- && (argv[go.optind][0] == '-' || argv[go.optind][0] == '+')
- && argv[go.optind][1] == '\0')
- {
- /* lone - clears -v and -x flags */
- if (argv[go.optind][0] == '-' && !Flag(FPOSIX))
- Flag(FVERBOSE) = Flag(FXTRACE) = 0;
- /* set skips lone - or + option */
- go.optind++;
- }
- if (setargsp)
- /* -- means set $#/$* even if there are no arguments */
- *setargsp = !arrayset && ((go.info & GI_MINUSMINUS)
- || argv[go.optind]);
-
- if (arrayset) {
- array = argv[go.optind++];
- if (!array) {
- bi_errorf("-A: missing array name");
- return -1;
- }
- if (!*array || *skip_varname(array, FALSE)) {
- bi_errorf("%s: is not an identifier", array);
- return -1;
- }
- } else
- array = (char *) 0; /* keep gcc happy */
- if (sortargs) {
- for (i = go.optind; argv[i]; i++)
- ;
- qsortp((void **) &argv[go.optind], (size_t) (i - go.optind),
- xstrcmp);
- }
- if (arrayset) {
- set_array(array, arrayset, argv + go.optind);
- for (; argv[go.optind]; go.optind++)
- ;
- }
-
- return go.optind;
-}
-
-/* parse a decimal number: returns 0 if string isn't a number, 1 otherwise */
-int
-getn(as, ai)
- const char *as;
- int *ai;
-{
- const char *s;
- register int n;
- int sawdigit = 0;
-
- s = as;
- if (*s == '-' || *s == '+')
- s++;
- for (n = 0; digit(*s); s++, sawdigit = 1)
- n = n * 10 + (*s - '0');
- *ai = (*as == '-') ? -n : n;
- if (*s || !sawdigit)
- return 0;
- return 1;
-}
-
-/* getn() that prints error */
-int
-bi_getn(as, ai)
- const char *as;
- int *ai;
-{
- int rv = getn(as, ai);
-
- if (!rv)
- bi_errorf("%s: bad number", as);
- return rv;
-}
-
-/* -------- gmatch.c -------- */
-
-/*
- * int gmatch(string, pattern)
- * char *string, *pattern;
- *
- * Match a pattern as in sh(1).
- * pattern character are prefixed with MAGIC by expand.
- */
-
-int
-gmatch(s, p, isfile)
- const char *s, *p;
- int isfile;
-{
- const char *se, *pe;
-
- if (s == NULL || p == NULL)
- return 0;
- se = s + strlen(s);
- pe = p + strlen(p);
- /* isfile is false iff no syntax check has been done on
- * the pattern. If check fails, just to a strcmp().
- */
- if (!isfile && !has_globbing(p, pe)) {
- int len = pe - p + 1;
- char tbuf[64];
- char *t = len <= sizeof(tbuf) ? tbuf
- : (char *) alloc(len, ATEMP);
- debunk(t, p);
- return !strcmp(t, s);
- }
- return do_gmatch((const unsigned char *) s, (const unsigned char *) se,
- (const unsigned char *) p, (const unsigned char *) pe,
- isfile);
-}
-
-/* Returns if p is a syntacticly correct globbing pattern, false
- * if it contains no pattern characters or if there is a syntax error.
- * Syntax errors are:
- * - [ with no closing ]
- * - imballenced $(...) expression
- * - [...] and *(...) not nested (eg, [a$(b|]c), *(a[b|c]d))
- */
-/*XXX
-- if no magic,
- if dest given, copy to dst
- return ?
-- if magic && (no globbing || syntax error)
- debunk to dst
- return ?
-- return ?
-*/
-int
-has_globbing(xp, xpe)
- const char *xp, *xpe;
-{
- const unsigned char *p = (const unsigned char *) xp;
- const unsigned char *pe = (const unsigned char *) xpe;
- int c;
- int nest = 0, bnest = 0;
- int saw_glob = 0;
- int in_bracket = 0; /* inside [...] */
-
- for (; p < pe; p++) {
- if (!ISMAGIC(*p))
- continue;
- if ((c = *++p) == '*' || c == '?')
- saw_glob = 1;
- else if (c == '[') {
- if (!in_bracket) {
- saw_glob = 1;
- in_bracket = 1;
- if (ISMAGIC(p[1]) && p[2] == NOT)
- p += 2;
- if (ISMAGIC(p[1]) && p[2] == ']')
- p += 2;
- }
- /* XXX Do we need to check ranges here? POSIX Q */
- } else if (c == ']') {
- if (in_bracket) {
- if (bnest) /* [a*(b]) */
- return 0;
- in_bracket = 0;
- }
- } else if ((c & 0x80) && strchr("*+?@!", c & 0x7f)) {
- saw_glob = 1;
- if (in_bracket)
- bnest++;
- else
- nest++;
- } else if (c == '|') {
- if (in_bracket && !bnest) /* *(a[foo|bar]) */
- return 0;
- } else if (c == /*(*/ ')') {
- if (in_bracket) {
- if (!bnest--) /* *(a[b)c] */
- return 0;
- } else if (nest)
- nest--;
- }
- /* else must be a MAGIC-MAGIC, or MAGIC-!, MAGIC--, MAGIC-]
- MAGIC-{, MAGIC-,, MAGIC-} */
- }
- return saw_glob && !in_bracket && !nest;
-}
-
-/* Function must return either 0 or 1 (assumed by code for 0x80|'!') */
-static int
-do_gmatch(s, se, p, pe, isfile)
- const unsigned char *s, *p;
- const unsigned char *se, *pe;
- int isfile;
-{
- register int sc, pc;
- const unsigned char *prest, *psub, *pnext;
- const unsigned char *srest;
-
- if (s == NULL || p == NULL)
- return 0;
- while (p < pe) {
- pc = *p++;
- sc = s < se ? *s : '\0';
- s++;
- if (isfile) {
- sc = FILECHCONV(sc);
- pc = FILECHCONV(pc);
- }
- if (!ISMAGIC(pc)) {
- if (sc != pc)
- return 0;
- continue;
- }
- switch (*p++) {
- case '[':
- if (sc == 0 || (p = cclass(p, sc)) == NULL)
- return 0;
- break;
-
- case '?':
- if (sc == 0)
- return 0;
- break;
-
- case '*':
- if (p == pe)
- return 1;
- s--;
- do {
- if (do_gmatch(s, se, p, pe, isfile))
- return 1;
- } while (s++ < se);
- return 0;
-
-#ifdef KSH
- /* [*+?@!](pattern|pattern|..) */
- case 0x80|'+': /* matches one or more times */
- case 0x80|'*': /* matches zero or more times */
- if (!(prest = pat_scan(p, pe, 0)))
- return 0;
- s--;
- /* take care of zero matches */
- if (p[-1] == (0x80 | '*')
- && do_gmatch(s, se, prest, pe, isfile))
- return 1;
- for (psub = p; ; psub = pnext) {
- pnext = pat_scan(psub, pe, 1);
- for (srest = s; srest <= se; srest++) {
- if (do_gmatch(s, srest,
- psub, pnext - 2, isfile)
- && (do_gmatch(srest, se,
- prest, pe, isfile)
- || (s != srest
- && do_gmatch(srest, se,
- p - 2, pe, isfile))))
- return 1;
- }
- if (pnext == prest)
- break;
- }
- return 0;
-
- case 0x80|'?': /* matches zero or once */
- case 0x80|'@': /* matches one of the patterns */
- if (!(prest = pat_scan(p, pe, 0)))
- return 0;
- s--;
- /* Take care of zero matches */
- if (p[-1] == (0x80 | '?')
- && do_gmatch(s, se, prest, pe, isfile))
- return 1;
- for (psub = p; ; psub = pnext) {
- pnext = pat_scan(psub, pe, 1);
- srest = prest == pe ? se : s;
- for (; srest <= se; srest++) {
- if (do_gmatch(s, srest,
- psub, pnext - 2, isfile)
- && do_gmatch(srest, se,
- prest, pe, isfile))
- return 1;
- }
- if (pnext == prest)
- break;
- }
- return 0;
-
- case 0x80|'!': /* matches none of the patterns */
- if (!(prest = pat_scan(p, pe, 0)))
- return 0;
- s--;
- for (srest = s; srest <= se; srest++) {
- int matched = 0;
-
- for (psub = p; ; psub = pnext) {
- pnext = pat_scan(psub, pe, 1);
- if (do_gmatch(s, srest,
- psub, pnext - 2, isfile))
- {
- matched = 1;
- break;
- }
- if (pnext == prest)
- break;
- }
- if (!matched && do_gmatch(srest, se,
- prest, pe, isfile))
- return 1;
- }
- return 0;
-#endif /* KSH */
-
- default:
- if (sc != p[-1])
- return 0;
- break;
- }
- }
- return s == se;
-}
-
-static const unsigned char *
-cclass(p, sub)
- const unsigned char *p;
- register int sub;
-{
- register int c, d, not, found = 0;
- const unsigned char *orig_p = p;
-
- if ((not = (ISMAGIC(*p) && *++p == NOT)))
- p++;
- do {
- c = *p++;
- if (ISMAGIC(c)) {
- c = *p++;
- if ((c & 0x80) && !ISMAGIC(c))
- c &= 0x7f;/* extended pattern matching: *+?@! */
- }
- if (c == '\0')
- /* No closing ] - act as if the opening [ was quoted */
- return sub == '[' ? orig_p : NULL;
- if (ISMAGIC(p[0]) && p[1] == '-'
- && (!ISMAGIC(p[2]) || p[3] != ']'))
- {
- p += 2; /* MAGIC- */
- d = *p++;
- if (ISMAGIC(d)) {
- d = *p++;
- if ((d & 0x80) && !ISMAGIC(d))
- d &= 0x7f;
- }
- /* POSIX says this is an invalid expression */
- if (c > d)
- return NULL;
- } else
- d = c;
- if (c == sub || (c <= sub && sub <= d))
- found = 1;
- } while (!(ISMAGIC(p[0]) && p[1] == ']'));
-
- return (found != not) ? p+2 : NULL;
-}
-
-/* Look for next ) or | (if match_sep) in *(foo|bar) pattern */
-const unsigned char *
-pat_scan(p, pe, match_sep)
- const unsigned char *p;
- const unsigned char *pe;
- int match_sep;
-{
- int nest = 0;
-
- for (; p < pe; p++) {
- if (!ISMAGIC(*p))
- continue;
- if ((*++p == /*(*/ ')' && nest-- == 0)
- || (*p == '|' && match_sep && nest == 0))
- return ++p;
- if ((*p & 0x80) && strchr("*+?@!", *p & 0x7f))
- nest++;
- }
- return (const unsigned char *) 0;
-}
-
-
-/* -------- qsort.c -------- */
-
-/*
- * quick sort of array of generic pointers to objects.
- */
-static void qsort1 ARGS((void **base, void **lim, int (*f)(void *, void *)));
-
-void
-qsortp(base, n, f)
- void **base; /* base address */
- size_t n; /* elements */
- int (*f) ARGS((void *, void *)); /* compare function */
-{
- qsort1(base, base + n, f);
-}
-
-#define swap2(a, b) {\
- register void *t; t = *(a); *(a) = *(b); *(b) = t;\
-}
-#define swap3(a, b, c) {\
- register void *t; t = *(a); *(a) = *(c); *(c) = *(b); *(b) = t;\
-}
-
-static void
-qsort1(base, lim, f)
- void **base, **lim;
- int (*f) ARGS((void *, void *));
-{
- register void **i, **j;
- register void **lptr, **hptr;
- size_t n;
- int c;
-
- top:
- n = (lim - base) / 2;
- if (n == 0)
- return;
- hptr = lptr = base+n;
- i = base;
- j = lim - 1;
-
- for (;;) {
- if (i < lptr) {
- if ((c = (*f)(*i, *lptr)) == 0) {
- lptr --;
- swap2(i, lptr);
- continue;
- }
- if (c < 0) {
- i += 1;
- continue;
- }
- }
-
- begin:
- if (j > hptr) {
- if ((c = (*f)(*hptr, *j)) == 0) {
- hptr ++;
- swap2(hptr, j);
- goto begin;
- }
- if (c > 0) {
- if (i == lptr) {
- hptr ++;
- swap3(i, hptr, j);
- i = lptr += 1;
- goto begin;
- }
- swap2(i, j);
- j -= 1;
- i += 1;
- continue;
- }
- j -= 1;
- goto begin;
- }
-
- if (i == lptr) {
- if (lptr-base >= lim-hptr) {
- qsort1(hptr+1, lim, f);
- lim = lptr;
- } else {
- qsort1(base, lptr, f);
- base = hptr+1;
- }
- goto top;
- }
-
- lptr -= 1;
- swap3(j, lptr, i);
- j = hptr -= 1;
- }
-}
-
-int
-xstrcmp(p1, p2)
- void *p1, *p2;
-{
- return (strcmp((char *)p1, (char *)p2));
-}
-
-/* Initialize a Getopt structure */
-void
-ksh_getopt_reset(go, flags)
- Getopt *go;
- int flags;
-{
- go->optind = 1;
- go->optarg = (char *) 0;
- go->p = 0;
- go->flags = flags;
- go->info = 0;
- go->buf[1] = '\0';
-}
-
-
-/* getopt() used for shell built-in commands, the getopts command, and
- * command line options.
- * A leading ':' in options means don't print errors, instead return '?'
- * or ':' and set go->optarg to the offending option character.
- * If GF_ERROR is set (and option doesn't start with :), errors result in
- * a call to bi_errorf().
- *
- * Non-standard features:
- * - ';' is like ':' in options, except the argument is optional
- * (if it isn't present, optarg is set to 0).
- * Used for 'set -o'.
- * - ',' is like ':' in options, except the argument always immediately
- * follows the option character (optarg is set to the null string if
- * the option is missing).
- * Used for 'read -u2', 'print -u2' and fc -40.
- * - '#' is like ':' in options, expect that the argument is optional
- * and must start with a digit. If the argument doesn't start with a
- * digit, it is assumed to be missing and normal option processing
- * continues (optarg is set to 0 if the option is missing).
- * Used for 'typeset -LZ4'.
- * - accepts +c as well as -c IF the GF_PLUSOPT flag is present. If an
- * option starting with + is accepted, the GI_PLUS flag will be set
- * in go->info. Once a - or + has been seen, all other options must
- * start with the same character.
- */
-int
-ksh_getopt(argv, go, options)
- char **argv;
- Getopt *go;
- const char *options;
-{
- char c;
- char *o;
-
- if (go->p == 0 || (c = argv[go->optind - 1][go->p]) == '\0') {
- char *arg = argv[go->optind], flag = arg ? *arg : '\0';
-
- go->p = 1;
- if (flag == '-' && arg[1] == '-' && arg[2] == '\0') {
- go->optind++;
- go->p = 0;
- go->info |= GI_MINUSMINUS;
- return EOF;
- }
- if (arg == (char *) 0
- || ((flag != '-' || (go->info & GI_PLUS))
- && (!(go->flags & GF_PLUSOPT) || (go->info & GI_MINUS)
- || flag != '+'))
- || (c = arg[1]) == '\0')
- {
- go->p = 0;
- return EOF;
- }
- go->optind++;
- go->info |= flag == '-' ? GI_MINUS : GI_PLUS;
- }
- go->p++;
- if (c == '?' || c == ':' || c == ';' || c == ',' || c == '#'
- || !(o = strchr(options, c)))
- {
- if (options[0] == ':') {
- go->buf[0] = c;
- go->optarg = go->buf;
- } else {
- warningf(TRUE, "%s%s-%c: unknown option",
- (go->flags & GF_NONAME) ? "" : argv[0],
- (go->flags & GF_NONAME) ? "" : ": ", c);
- if (go->flags & GF_ERROR)
- bi_errorf(null);
- }
- return '?';
- }
- /* : means argument must be present, may be part of option argument
- * or the next argument
- * ; same as : but argument may be missing
- * , means argument is part of option argument, and may be null.
- */
- if (*++o == ':' || *o == ';') {
- if (argv[go->optind - 1][go->p])
- go->optarg = argv[go->optind - 1] + go->p;
- else if (argv[go->optind])
- go->optarg = argv[go->optind++];
- else if (*o == ';')
- go->optarg = (char *) 0;
- else {
- if (options[0] == ':') {
- go->buf[0] = c;
- go->optarg = go->buf;
- return ':';
- }
- warningf(TRUE, "%s%s-`%c' requires argument",
- (go->flags & GF_NONAME) ? "" : argv[0],
- (go->flags & GF_NONAME) ? "" : ": ", c);
- if (go->flags & GF_ERROR)
- bi_errorf(null);
- return '?';
- }
- go->p = 0;
- } else if (*o == ',') {
- /* argument is attatched to option character, even if null */
- go->optarg = argv[go->optind - 1] + go->p;
- go->p = 0;
- } else if (*o == '#') {
- /* argument is optional and may be attatched or unattatched
- * but must start with a digit. optarg is set to 0 if the
- * argument is missing.
- */
- if (argv[go->optind - 1][go->p]) {
- if (digit(argv[go->optind - 1][go->p])) {
- go->optarg = argv[go->optind - 1] + go->p;
- go->p = 0;
- } else
- go->optarg = (char *) 0;;
- } else {
- if (argv[go->optind] && digit(argv[go->optind][0])) {
- go->optarg = argv[go->optind++];
- go->p = 0;
- } else
- go->optarg = (char *) 0;;
- }
- }
- return c;
-}
-
-/* print variable/alias value using necessary quotes
- * (POSIX says they should be suitable for re-entry...)
- * No trailing newline is printed.
- */
-void
-print_value_quoted(s)
- const char *s;
-{
- const char *p;
- int inquote = 0;
-
- /* Test if any quotes are needed */
- for (p = s; *p; p++)
- if (ctype(*p, C_QUOTE))
- break;
- if (!*p) {
- shprintf("%s", s);
- return;
- }
- for (p = s; *p; p++) {
- if (*p == '\'') {
- shprintf("'\\'" + 1 - inquote);
- inquote = 0;
- } else {
- if (!inquote) {
- shprintf("'");
- inquote = 1;
- }
- shf_putc(*p, shl_stdout);
- }
- }
- if (inquote)
- shprintf("'");
-}
-
-/* Print things in columns and rows - func() is called to format the ith
- * element
- */
-void
-print_columns(shf, n, func, arg, max_width)
- struct shf *shf;
- int n;
- char *(*func) ARGS((void *, int, char *, int));
- void *arg;
- int max_width;
-{
- char *str = (char *) alloc(max_width + 1, ATEMP);
- int i;
- int r, c;
- int rows, cols;
- int nspace;
-
- /* max_width + 1 for the space. Note that no space
- * is printed after the last column to avoid problems
- * with terminals that have auto-wrap.
- */
- cols = x_cols / (max_width + 1);
- if (!cols)
- cols = 1;
- rows = (n + cols - 1) / cols;
- if (n && cols > rows) {
- int tmp = rows;
-
- rows = cols;
- cols = tmp;
- if (rows > n)
- rows = n;
- }
-
- nspace = (x_cols - max_width * cols) / cols;
- if (nspace <= 0)
- nspace = 1;
- for (r = 0; r < rows; r++) {
- for (c = 0; c < cols; c++) {
- i = c * rows + r;
- if (i < n) {
- shf_fprintf(shf, "%-*s",
- max_width,
- (*func)(arg, i, str, max_width + 1));
- if (c + 1 < cols)
- shf_fprintf(shf, "%*s", nspace, null);
- }
- }
- shf_putchar('\n', shf);
- }
- afree(str, ATEMP);
-}
-
-/* Strip any nul bytes from buf - returns new length (nbytes - # of nuls) */
-int
-strip_nuls(buf, nbytes)
- char *buf;
- int nbytes;
-{
- char *dst;
-
- /* nbytes check because some systems (older freebsd's) have a buggy
- * memchr()
- */
- if (nbytes && (dst = memchr(buf, '\0', nbytes))) {
- char *end = buf + nbytes;
- char *p, *q;
-
- for (p = dst; p < end; p = q) {
- /* skip a block of nulls */
- while (++p < end && *p == '\0')
- ;
- /* find end of non-null block */
- if (!(q = memchr(p, '\0', end - p)))
- q = end;
- memmove(dst, p, q - p);
- dst += q - p;
- }
- *dst = '\0';
- return dst - buf;
- }
- return nbytes;
-}
-
-/* Copy at most dsize-1 bytes from src to dst, ensuring dst is null terminated.
- * Returns dst.
- */
-char *
-str_zcpy(dst, src, dsize)
- char *dst;
- const char *src;
- int dsize;
-{
- if (dsize > 0) {
- int len = strlen(src);
-
- if (len >= dsize)
- len = dsize - 1;
- memcpy(dst, src, len);
- dst[len] = '\0';
- }
- return dst;
-}
-
-/* Like read(2), but if read fails due to non-blocking flag, resets flag
- * and restarts read.
- */
-int
-blocking_read(fd, buf, nbytes)
- int fd;
- char *buf;
- int nbytes;
-{
- int ret;
- int tried_reset = 0;
-
- while ((ret = read(fd, buf, nbytes)) < 0) {
- if (!tried_reset && (errno == EAGAIN
-#ifdef EWOULDBLOCK
- || errno == EWOULDBLOCK
-#endif /* EWOULDBLOCK */
- ))
- {
- int oerrno = errno;
- if (reset_nonblock(fd) > 0) {
- tried_reset = 1;
- continue;
- }
- errno = oerrno;
- }
- break;
- }
- return ret;
-}
-
-/* Reset the non-blocking flag on the specified file descriptor.
- * Returns -1 if there was an error, 0 if non-blocking wasn't set,
- * 1 if it was.
- */
-int
-reset_nonblock(fd)
- int fd;
-{
- int flags;
- int blocking_flags;
-
- if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
- return -1;
- /* With luck, the C compiler will reduce this to a constant */
- blocking_flags = 0;
-#ifdef O_NONBLOCK
- blocking_flags |= O_NONBLOCK;
-#endif /* O_NONBLOCK */
-#ifdef O_NDELAY
- blocking_flags |= O_NDELAY;
-#else /* O_NDELAY */
-# ifndef O_NONBLOCK
- blocking_flags |= FNDELAY; /* hope this exists... */
-# endif /* O_NONBLOCK */
-#endif /* O_NDELAY */
- if (!(flags & blocking_flags))
- return 0;
- flags &= ~blocking_flags;
- if (fcntl(fd, F_SETFL, flags) < 0)
- return -1;
- return 1;
-}
-
-
-#ifdef HAVE_SYS_PARAM_H
-# include <sys/param.h>
-#endif /* HAVE_SYS_PARAM_H */
-#ifndef MAXPATHLEN
-# define MAXPATHLEN PATH
-#endif /* MAXPATHLEN */
-
-/* Like getcwd(), except bsize is ignored if buf is 0 (MAXPATHLEN is used) */
-char *
-ksh_get_wd(buf, bsize)
- char *buf;
- int bsize;
-{
-#ifdef HAVE_GETWD
- extern char *getwd ARGS((char *));
- char *b;
- int len;
-
- if (buf && bsize > MAXPATHLEN)
- b = buf;
- else
- b = alloc(MAXPATHLEN + 1, ATEMP);
- if (!getwd(b)) {
- errno = EACCES;
- if (b != buf)
- afree(b, ATEMP);
- return (char *) 0;
- }
- len = strlen(b) + 1;
- if (!buf)
- b = aresize(b, len, ATEMP);
- else if (buf != b) {
- if (len > bsize) {
- errno = ERANGE;
- return (char *) 0;
- }
- memcpy(buf, b, len);
- afree(b, ATEMP);
- b = buf;
- }
-
- return b;
-#else /* HAVE_GETWD */
- char *b;
- char *ret;
-
- /* Assume getcwd() available */
- if (!buf) {
- bsize = MAXPATHLEN;
- b = alloc(MAXPATHLEN + 1, ATEMP);
- } else
- b = buf;
-
- ret = getcwd(b, bsize);
-
- if (!buf) {
- if (ret)
- ret = aresize(b, strlen(b) + 1, ATEMP);
- else
- afree(b, ATEMP);
- }
-
- return ret;
-#endif /* HAVE_GETWD */
-}
diff --git a/bin/pdksh/missing.c b/bin/pdksh/missing.c
deleted file mode 100644
index 7f507fe66b9..00000000000
--- a/bin/pdksh/missing.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/* $OpenBSD: missing.c,v 1.3 1997/06/19 13:58:45 kstailey Exp $ */
-
-/*
- * Routines which may be missing on some machines
- */
-
-#include "sh.h"
-#include "ksh_stat.h"
-#include "ksh_dir.h"
-
-
-#ifndef HAVE_MEMSET
-void *
-memset(d, c, n)
- void *d;
- int c;
- size_t n;
-{
- unsigned char *p = (unsigned char *) d;
-
- /* Not amazingly fast.. */
- for (; n > 0; --n)
- *p++ = c;
- return d;
-}
-#endif /* !HAVE_MEMSET */
-
-#if !defined(HAVE_MEMMOVE) && !defined(HAVE_BCOPY)
-void *
-memmove(d, s, n)
- void *d;
- const void *s;
- size_t n;
-{
- char *dp = (char *) d, *sp = (char *) s;
-
- if (n <= 0)
- ;
- else if (dp < sp)
- do
- *dp++ = *sp++;
- while (--n > 0);
- else if (dp > sp) {
- dp += n;
- sp += n;
- do
- *--dp = *--sp;
- while (--n > 0);
- }
- return d;
-}
-#endif /* !HAVE_MEMMOVE && !HAVE_BCOPY */
-
-
-#ifndef HAVE_STRCASECMP
-/*
- * Case insensitive string compare routines, same semantics as str[n]cmp()
- * (assumes ASCII..).
- */
-static const char ichars[256] = {
- 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
- 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
- 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
- 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
- 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
- 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
- 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
- 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
- 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
- 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
- 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
- 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
- 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
- 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
- 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
- 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
- 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
- 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
- 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
- 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
- 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
- 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
- };
-
-int
-strcasecmp(s1, s2)
- const char *s1;
- const char *s2;
-{
- const unsigned char *us1 = (const unsigned char *) s1;
- const unsigned char *us2 = (const unsigned char *) s2;
-
- while (ichars[*us1] == ichars[*us2++])
- if (!*us1++)
- return 0;
-
- return ichars[*us1] - ichars[*--us2];
-}
-
-int
-strncasecmp(s1, s2, n)
- const char *s1;
- const char *s2;
- int n;
-{
- const unsigned char *us1 = (const unsigned char *) s1;
- const unsigned char *us2 = (const unsigned char *) s2;
-
- while (--n >= 0 && ichars[*us1] == ichars[*us2++])
- if (!*us1++)
- return 0;
-
- return n < 0 ? 0 : ichars[*us1] - ichars[*--us2];
-}
-#endif /* HAVE_STRCASECMP */
-
-
-#ifndef HAVE_STRSTR
-char *
-strstr(s, p)
- const char *s;
- const char *p;
-{
- int len;
-
- if (s && p)
- for (len = strlen(p); *s; s++)
- if (*s == *p && strncmp(s, p, len) == 0)
- return (char *) s;
-
- return 0;
-}
-#endif /* HAVE_STRSTR */
-
-
-#ifndef HAVE_STRERROR
-char *
-strerror(err)
- int err;
-{
- static char buf[64];
-# ifdef HAVE_SYS_ERRLIST
-# ifndef SYS_ERRLIST_DECLARED
- extern int sys_nerr;
- extern char *sys_errlist[];
-# endif
- char *p;
-
- if (err < 0 || err >= sys_nerr)
- shf_snprintf(p = buf, sizeof(buf), "Unknown system error %d",
- err);
- else
- p = sys_errlist[err];
- return p;
-# else /* HAVE_SYS_ERRLIST */
- switch (err) {
- case EINVAL:
- return "Invalid argument";
- case EACCES:
- return "Permission denied";
- case ESRCH:
- return "No such process";
- case EPERM:
- return "Not owner";
- case ENOENT:
- return "No such file or directory";
- case ENOTDIR:
- return "Not a directory";
- case ENOEXEC:
- return "Exec format error";
- case ENOMEM:
- return "Not enough memory";
- case E2BIG:
- return "Argument list too long";
- default:
- shf_snprintf(buf, sizeof(buf), "Unknown system error %d", err);
- return buf;
- }
-# endif /* HAVE_SYS_ERRLIST */
-}
-#endif /* !HAVE_STRERROR */
-
-
-#ifdef TIMES_BROKEN
-# include "ksh_time.h"
-# include "ksh_times.h"
-# ifdef HAVE_GETRUSAGE
-# include <sys/resource.h>
-# else /* HAVE_GETRUSAGE */
-# include <sys/timeb.h>
-# endif /* HAVE_GETRUSAGE */
-
-clock_t
-ksh_times(tms)
- struct tms *tms;
-{
- static clock_t base_sec;
- clock_t rv;
-
-# ifdef HAVE_GETRUSAGE
- {
- struct timeval tv;
- struct rusage ru;
-
- getrusage(RUSAGE_SELF, &ru);
- tms->tms_utime = ru.ru_utime.tv_sec * CLK_TCK
- + ru.ru_utime.tv_usec * CLK_TCK / 1000000;
- tms->tms_stime = ru.ru_stime.tv_sec * CLK_TCK
- + ru.ru_stime.tv_usec * CLK_TCK / 1000000;
-
- getrusage(RUSAGE_CHILDREN, &ru);
- tms->tms_cutime = ru.ru_utime.tv_sec * CLK_TCK
- + ru.ru_utime.tv_usec * CLK_TCK / 1000000;
- tms->tms_cstime = ru.ru_stime.tv_sec * CLK_TCK
- + ru.ru_stime.tv_usec * CLK_TCK / 1000000;
-
- gettimeofday(&tv, (struct timezone *) 0);
- if (base_sec == 0)
- base_sec = tv.tv_sec;
- rv = (tv.tv_sec - base_sec) * CLK_TCK;
- rv += tv.tv_usec * CLK_TCK / 1000000;
- }
-# else /* HAVE_GETRUSAGE */
- /* Assume times() available, but always returns 0
- * (also assumes ftime() available)
- */
- {
- struct timeb tb;
-
- if (times(tms) == (clock_t) -1)
- return (clock_t) -1;
- ftime(&tb);
- if (base_sec == 0)
- base_sec = tb.time;
- rv = (tb.time - base_sec) * CLK_TCK;
- rv += tb.millitm * CLK_TCK / 1000;
- }
-# endif /* HAVE_GETRUSAGE */
- return rv;
-}
-#endif /* TIMES_BROKEN */
-
-#ifdef OPENDIR_DOES_NONDIR
-/* Prevent opendir() from attempting to open non-directories. Such
- * behavior can cause problems if it attempts to open special devices...
- */
-DIR *
-ksh_opendir(d)
- const char *d;
-{
- struct stat statb;
-
- if (stat(d, &statb) != 0)
- return (DIR *) 0;
- if (!S_ISDIR(statb.st_mode)) {
- errno = ENOTDIR;
- return (DIR *) 0;
- }
- return opendir(d);
-}
-#endif /* OPENDIR_DOES_NONDIR */
diff --git a/bin/pdksh/path.c b/bin/pdksh/path.c
deleted file mode 100644
index d0a08761d9a..00000000000
--- a/bin/pdksh/path.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/* $OpenBSD: path.c,v 1.3 1997/06/19 13:58:46 kstailey Exp $ */
-
-#include "sh.h"
-#include "ksh_stat.h"
-
-/*
- * Contains a routine to search a : seperated list of
- * paths (a la CDPATH) and make appropiate file names.
- * Also contains a routine to simplify .'s and ..'s out of
- * a path name.
- *
- * Larry Bouzane (larry@cs.mun.ca)
- */
-
-/*
- * $Log: path.c,v $
- * Revision 1.3 1997/06/19 13:58:46 kstailey
- * back out
- *
- * Revision 1.1.1.1 1996/08/14 06:19:11 downsj
- * Import pdksh 5.2.7.
- *
- * Revision 1.2 1994/05/19 18:32:40 michael
- * Merge complete, stdio replaced, various fixes. (pre autoconf)
- *
- * Revision 1.1 1994/04/06 13:14:03 michael
- * Initial revision
- *
- * Revision 4.2 1990/12/06 18:05:24 larry
- * Updated test code to reflect parameter change.
- * Fixed problem with /a/./.dir being simplified to /a and not /a/.dir due
- * to *(cur+2) == *f test instead of the correct cur+2 == f
- *
- * Revision 4.1 90/10/29 14:42:19 larry
- * base MUN version
- *
- * Revision 3.1.0.4 89/02/16 20:28:36 larry
- * Forgot to set *pathlist to NULL when last changed make_path().
- *
- * Revision 3.1.0.3 89/02/13 20:29:55 larry
- * Fixed up cd so that it knew when a node from CDPATH was used and would
- * print a message only when really necessary.
- *
- * Revision 3.1.0.2 89/02/13 17:51:22 larry
- * Merged with Eric Gisin's version.
- *
- * Revision 3.1.0.1 89/02/13 17:50:58 larry
- * *** empty log message ***
- *
- * Revision 3.1 89/02/13 17:49:28 larry
- * *** empty log message ***
- *
- */
-
-#ifdef S_ISLNK
-static char *do_phys_path ARGS((XString *xsp, char *xp, const char *path));
-#endif /* S_ISLNK */
-
-/*
- * Makes a filename into result using the following algorithm.
- * - make result NULL
- * - if file starts with '/', append file to result & set cdpathp to NULL
- * - if file starts with ./ or ../ append cwd and file to result
- * and set cdpathp to NULL
- * - if the first element of cdpathp doesnt start with a '/' xx or '.' xx
- * then cwd is appended to result.
- * - the first element of cdpathp is appended to result
- * - file is appended to result
- * - cdpathp is set to the start of the next element in cdpathp (or NULL
- * if there are no more elements.
- * The return value indicates whether a non-null element from cdpathp
- * was appened to result.
- */
-int
-make_path(cwd, file, cdpathp, xsp, phys_pathp)
- const char *cwd;
- const char *file;
- char **cdpathp; /* & of : seperated list */
- XString *xsp;
- int *phys_pathp;
-{
- int rval = 0;
- int use_cdpath = 1;
- char *plist;
- int len;
- int plen = 0;
- char *xp = Xstring(*xsp, xp);
-
- if (!file)
- file = null;
-
- if (!ISRELPATH(file)) {
- *phys_pathp = 0;
- use_cdpath = 0;
- } else {
- if (file[0] == '.') {
- char c = file[1];
-
- if (c == '.')
- c = file[2];
- if (ISDIRSEP(c) || c == '\0')
- use_cdpath = 0;
- }
-
- plist = *cdpathp;
- if (!plist)
- use_cdpath = 0;
- else if (use_cdpath) {
- char *pend;
-
- for (pend = plist; *pend && *pend != PATHSEP; pend++)
- ;
- plen = pend - plist;
- *cdpathp = *pend ? ++pend : (char *) 0;
- }
-
- if ((use_cdpath == 0 || !plen || ISRELPATH(plist))
- && (cwd && *cwd))
- {
- len = strlen(cwd);
- XcheckN(*xsp, xp, len);
- memcpy(xp, cwd, len);
- xp += len;
- if (!ISDIRSEP(cwd[len - 1]))
- Xput(*xsp, xp, DIRSEP);
- }
- *phys_pathp = Xlength(*xsp, xp);
- if (use_cdpath && plen) {
- XcheckN(*xsp, xp, plen);
- memcpy(xp, plist, plen);
- xp += plen;
- if (!ISDIRSEP(plist[plen - 1]))
- Xput(*xsp, xp, DIRSEP);
- rval = 1;
- }
- }
-
- len = strlen(file) + 1;
- XcheckN(*xsp, xp, len);
- memcpy(xp, file, len);
-
- if (!use_cdpath)
- *cdpathp = (char *) 0;
-
- return rval;
-}
-
-/*
- * Simplify pathnames containing "." and ".." entries.
- * ie, simplify_path("/a/b/c/./../d/..") returns "/a/b"
- */
-void
-simplify_path(path)
- char *path;
-{
- char *cur;
- char *t;
- int isrooted;
- char *very_start = path;
- char *start;
-
- if (!*path)
- return;
-
- if ((isrooted = ISROOTEDPATH(path)))
- very_start++;
-#ifdef OS2
- if (path[0] && path[1] == ':') /* skip a: */
- very_start += 2;
-#endif /* OS2 */
-
- /* Before After
- * /foo/ /foo
- * /foo/../../bar /bar
- * /foo/./blah/.. /foo
- * . .
- * .. ..
- * ./foo foo
- * foo/../../../bar ../../bar
- * OS2:
- * a:/foo/../.. a:/
- * a:. a:
- * a:.. a:..
- * a:foo/../../blah a:../blah
- */
-
- for (cur = t = start = very_start; ; ) {
- /* treat multiple '/'s as one '/' */
- while (ISDIRSEP(*t))
- t++;
-
- if (*t == '\0') {
- if (cur == path)
- /* convert empty path to dot */
- *cur++ = '.';
- *cur = '\0';
- break;
- }
-
- if (t[0] == '.') {
- if (!t[1] || ISDIRSEP(t[1])) {
- t += 1;
- continue;
- } else if (t[1] == '.' && (!t[2] || ISDIRSEP(t[2]))) {
- if (!isrooted && cur == start) {
- if (cur != very_start)
- *cur++ = DIRSEP;
- *cur++ = '.';
- *cur++ = '.';
- start = cur;
- } else if (cur != start)
- while (--cur > start && !ISDIRSEP(*cur))
- ;
- t += 2;
- continue;
- }
- }
-
- if (cur != very_start)
- *cur++ = DIRSEP;
-
- /* find/copy next component of pathname */
- while (*t && !ISDIRSEP(*t))
- *cur++ = *t++;
- }
-}
-
-
-void
-set_current_wd(path)
- char *path;
-{
- int len;
- char *p = path;
-
- if (!p && !(p = ksh_get_wd((char *) 0, 0)))
- p = null;
-
- len = strlen(p) + 1;
-
- if (len > current_wd_size)
- current_wd = aresize(current_wd, current_wd_size = len, APERM);
- memcpy(current_wd, p, len);
- if (p != path && p != null)
- afree(p, ATEMP);
-}
-
-#ifdef S_ISLNK
-char *
-get_phys_path(path)
- const char *path;
-{
- XString xs;
- char *xp;
-
- Xinit(xs, xp, strlen(path) + 1, ATEMP);
-
- xp = do_phys_path(&xs, xp, path);
-
- if (!xp)
- return (char *) 0;
-
- if (Xlength(xs, xp) == 0)
- Xput(xs, xp, DIRSEP);
- Xput(xs, xp, '\0');
-
- return Xclose(xs, xp);
-}
-
-static char *
-do_phys_path(xsp, xp, path)
- XString *xsp;
- char *xp;
- const char *path;
-{
- const char *p, *q;
- int len, llen;
- int savepos;
- char lbuf[PATH];
-
- Xcheck(*xsp, xp);
- for (p = path; p; p = q) {
- while (ISDIRSEP(*p))
- p++;
- if (!*p)
- break;
- len = (q = ksh_strchr_dirsep(p)) ? q - p : strlen(p);
- if (len == 1 && p[0] == '.')
- continue;
- if (len == 2 && p[0] == '.' && p[1] == '.') {
- while (xp > Xstring(*xsp, xp)) {
- xp--;
- if (ISDIRSEP(*xp))
- break;
- }
- continue;
- }
-
- savepos = Xsavepos(*xsp, xp);
- Xput(*xsp, xp, DIRSEP);
- XcheckN(*xsp, xp, len + 1);
- memcpy(xp, p, len);
- xp += len;
- *xp = '\0';
-
- llen = readlink(Xstring(*xsp, xp), lbuf, sizeof(lbuf) - 1);
- if (llen < 0) {
- /* EINVAL means it wasn't a symlink... */
- if (errno != EINVAL)
- return (char *) 0;
- continue;
- }
- lbuf[llen] = '\0';
-
- /* If absolute path, start from scratch.. */
- xp = ISABSPATH(lbuf) ? Xstring(*xsp, xp)
- : Xrestpos(*xsp, xp, savepos);
- if (!(xp = do_phys_path(xsp, xp, lbuf)))
- return (char *) 0;
- }
- return xp;
-}
-#endif /* S_ISLNK */
-
-#ifdef TEST
-
-main(argc, argv)
-{
- int rv;
- char *cp, cdpath[256], pwd[256], file[256], result[256];
-
- printf("enter CDPATH: "); gets(cdpath);
- printf("enter PWD: "); gets(pwd);
- while (1) {
- if (printf("Enter file: "), gets(file) == 0)
- return 0;
- cp = cdpath;
- do {
- rv = make_path(pwd, file, &cp, result, sizeof(result));
- printf("make_path returns (%d), \"%s\" ", rv, result);
- simplify_path(result);
- printf("(simpifies to \"%s\")\n", result);
- } while (cp);
- }
-}
-#endif /* TEST */
diff --git a/bin/pdksh/proto.h b/bin/pdksh/proto.h
deleted file mode 100644
index 608b451f593..00000000000
--- a/bin/pdksh/proto.h
+++ /dev/null
@@ -1,292 +0,0 @@
-/* $OpenBSD: proto.h,v 1.3 1996/11/21 07:59:34 downsj Exp $ */
-
-/*
- * prototypes for PD-KSH
- * originally generated using "cproto.c 3.5 92/04/11 19:28:01 cthuang "
- * $From: proto.h,v 1.3 1994/05/19 18:32:40 michael Exp michael $
- */
-
-/* alloc.c */
-Area * ainit ARGS((Area *ap));
-void afreeall ARGS((Area *ap));
-void * alloc ARGS((size_t size, Area *ap));
-void * aresize ARGS((void *ptr, size_t size, Area *ap));
-void afree ARGS((void *ptr, Area *ap));
-/* c_ksh.c */
-int c_hash ARGS((char **wp));
-int c_cd ARGS((char **wp));
-int c_pwd ARGS((char **wp));
-int c_print ARGS((char **wp));
-int c_whence ARGS((char **wp));
-int c_command ARGS((char **wp));
-int c_typeset ARGS((char **wp));
-int c_alias ARGS((char **wp));
-int c_unalias ARGS((char **wp));
-int c_let ARGS((char **wp));
-int c_jobs ARGS((char **wp));
-int c_fgbg ARGS((char **wp));
-int c_kill ARGS((char **wp));
-void getopts_reset ARGS((int val));
-int c_getopts ARGS((char **wp));
-int c_bind ARGS((char **wp));
-/* c_sh.c */
-int c_label ARGS((char **wp));
-int c_shift ARGS((char **wp));
-int c_umask ARGS((char **wp));
-int c_dot ARGS((char **wp));
-int c_wait ARGS((char **wp));
-int c_read ARGS((char **wp));
-int c_eval ARGS((char **wp));
-int c_trap ARGS((char **wp));
-int c_brkcont ARGS((char **wp));
-int c_exitreturn ARGS((char **wp));
-int c_set ARGS((char **wp));
-int c_unset ARGS((char **wp));
-int c_ulimit ARGS((char **wp));
-int c_times ARGS((char **wp));
-int timex ARGS((struct op *t, int f));
-int c_exec ARGS((char **wp));
-int c_builtin ARGS((char **wp));
-/* c_test.c */
-int c_test ARGS((char **wp));
-/* edit.c: most prototypes in edit.h */
-void x_init ARGS((void));
-int x_read ARGS((char *buf, size_t len));
-void set_editmode ARGS((const char *ed));
-/* emacs.c: most prototypes in edit.h */
-int x_bind ARGS((const char *a1, const char *a2, int macro,
- int list));
-/* eval.c */
-char * substitute ARGS((const char *cp, int f));
-char ** eval ARGS((char **ap, int f));
-char * evalstr ARGS((char *cp, int f));
-char * evalonestr ARGS((char *cp, int f));
-char *debunk ARGS((char *dp, const char *sp));
-void expand ARGS((char *cp, XPtrV *wp, int f));
-int glob_str ARGS((char *cp, XPtrV *wp, int markdirs));
-/* exec.c */
-int fd_clexec ARGS((int fd));
-int execute ARGS((struct op * volatile t, volatile int flags));
-int shcomexec ARGS((char **wp));
-struct tbl * findfunc ARGS((const char *name, unsigned int h, int create));
-int define ARGS((const char *name, struct op *t));
-void builtin ARGS((const char *name, int (*func)(char **)));
-struct tbl * findcom ARGS((const char *name, int flags));
-void flushcom ARGS((int all));
-char * search ARGS((const char *name, const char *path, int mode,
- int *errnop));
-int search_access ARGS((const char *path, int mode, int *errnop));
-int pr_menu ARGS((char *const *ap));
-/* expr.c */
-int evaluate ARGS((const char *expr, long *rval, int error_ok));
-int v_evaluate ARGS((struct tbl *vp, const char *expr, volatile int error_ok));
-/* history.c */
-void init_histvec ARGS((void));
-void hist_init ARGS((Source *s));
-void hist_finish ARGS((void));
-void histsave ARGS((int lno, const char *cmd, int dowrite));
-#ifdef HISTORY
-int c_fc ARGS((register char **wp));
-void sethistsize ARGS((int n));
-void sethistfile ARGS((const char *name));
-# ifdef EASY_HISTORY
-void histappend ARGS((const char *cmd, int nl_seperate));
-# endif
-char ** histpos ARGS((void));
-int histN ARGS((void));
-int histnum ARGS((int n));
-int findhist ARGS((int start, int fwd, const char *str,
- int anchored));
-#endif /* HISTORY */
-/* io.c */
-void errorf ARGS((const char *fmt, ...))
- GCC_FUNC_ATTR2(noreturn, format(printf, 1, 2));
-void warningf ARGS((int fileline, const char *fmt, ...))
- GCC_FUNC_ATTR(format(printf, 2, 3));
-void bi_errorf ARGS((const char *fmt, ...))
- GCC_FUNC_ATTR(format(printf, 1, 2));
-void internal_errorf ARGS((int jump, const char *fmt, ...))
- GCC_FUNC_ATTR(format(printf, 2, 3));
-void error_prefix ARGS((int fileline));
-void shellf ARGS((const char *fmt, ...))
- GCC_FUNC_ATTR(format(printf, 1, 2));
-void shprintf ARGS((const char *fmt, ...))
- GCC_FUNC_ATTR(format(printf, 1, 2));
-int can_seek ARGS((int fd));
-void initio ARGS((void));
-int ksh_dup2 ARGS((int ofd, int nfd, int errok));
-int savefd ARGS((int fd, int noclose));
-void restfd ARGS((int fd, int ofd));
-void openpipe ARGS((int *pv));
-void closepipe ARGS((int *pv));
-int check_fd ARGS((char *name, int mode, const char **emsgp));
-#ifdef KSH
-void coproc_init ARGS((void));
-void coproc_read_close ARGS((int fd));
-void coproc_readw_close ARGS((int fd));
-void coproc_write_close ARGS((int fd));
-int coproc_getfd ARGS((int mode, const char **emsgp));
-void coproc_cleanup ARGS((int reuse));
-#endif /* KSH */
-struct temp *maketemp ARGS((Area *ap));
-/* jobs.c */
-void j_init ARGS((int mflagset));
-void j_exit ARGS((void));
-void j_change ARGS((void));
-int exchild ARGS((struct op *t, int flags, int close_fd));
-void startlast ARGS((void));
-int waitlast ARGS((void));
-int waitfor ARGS((const char *cp, int *sigp));
-int j_kill ARGS((const char *cp, int sig));
-int j_resume ARGS((const char *cp, int bg));
-int j_jobs ARGS((const char *cp, int slp, int nflag));
-void j_notify ARGS((void));
-pid_t j_async ARGS((void));
-int j_stopped_running ARGS((void));
-/* lex.c */
-int yylex ARGS((int cf));
-void yyerror ARGS((const char *fmt, ...))
- GCC_FUNC_ATTR2(noreturn, format(printf, 1, 2));
-Source * pushs ARGS((int type, Area *areap));
-void set_prompt ARGS((int to, Source *s));
-void pprompt ARGS((const char *cp, int ntruncate));
-/* mail.c */
-#ifdef KSH
-void mcheck ARGS((void));
-void mbset ARGS((char *p));
-void mpset ARGS((char *mptoparse));
-#endif /* KSH */
-/* main.c */
-int include ARGS((const char *name, int argc, char **argv,
- int intr_ok));
-int command ARGS((const char *comm));
-int shell ARGS((Source *volatile s, int volatile toplevel));
-void unwind ARGS((int i)) GCC_FUNC_ATTR(noreturn);
-void newenv ARGS((int type));
-void quitenv ARGS((void));
-void cleanup_parents_env ARGS((void));
-void cleanup_proc_env ARGS((void));
-void aerror ARGS((Area *ap, const char *msg))
- GCC_FUNC_ATTR(noreturn);
-/* misc.c */
-void setctypes ARGS((const char *s, int t));
-void initctypes ARGS((void));
-char * ulton ARGS((unsigned long n, int base));
-char * str_save ARGS((const char *s, Area *ap));
-char * str_nsave ARGS((const char *s, int n, Area *ap));
-int option ARGS((const char *n));
-char * getoptions ARGS((void));
-void change_flag ARGS((enum sh_flag f, int what, int newval));
-int parse_args ARGS((char **argv, int what, int *setargsp));
-int getn ARGS((const char *as, int *ai));
-int bi_getn ARGS((const char *as, int *ai));
-char * strerror ARGS((int i));
-int gmatch ARGS((const char *s, const char *p, int isfile));
-int has_globbing ARGS((const char *xp, const char *xpe));
-const unsigned char *pat_scan ARGS((const unsigned char *p,
- const unsigned char *pe, int match_sep));
-void qsortp ARGS((void **base, size_t n, int (*f)(void *, void *)));
-int xstrcmp ARGS((void *p1, void *p2));
-void ksh_getopt_reset ARGS((Getopt *go, int));
-int ksh_getopt ARGS((char **argv, Getopt *go, const char *options));
-void print_value_quoted ARGS((const char *s));
-void print_columns ARGS((struct shf *shf, int n,
- char *(*func)(void *, int, char *, int),
- void *arg, int max_width));
-int strip_nuls ARGS((char *buf, int nbytes));
-char *str_zcpy ARGS((char *dst, const char *src, int dsize));
-int blocking_read ARGS((int fd, char *buf, int nbytes));
-int reset_nonblock ARGS((int fd));
-char *ksh_get_wd ARGS((char *buf, int bsize));
-/* path.c */
-int make_path ARGS((const char *cwd, const char *file,
- char **pathlist, XString *xsp, int *phys_pathp));
-void simplify_path ARGS((char *path));
-char *get_phys_path ARGS((const char *path));
-void set_current_wd ARGS((char *path));
-/* syn.c */
-void initkeywords ARGS((void));
-struct op * compile ARGS((Source *s));
-/* table.c */
-unsigned int hash ARGS((const char *n));
-void tinit ARGS((struct table *tp, Area *ap, int tsize));
-struct tbl * tsearch ARGS((struct table *tp, const char *n, unsigned int h));
-struct tbl * tenter ARGS((struct table *tp, const char *n, unsigned int h));
-void tdelete ARGS((struct tbl *p));
-void twalk ARGS((struct tstate *ts, struct table *tp));
-struct tbl * tnext ARGS((struct tstate *ts));
-struct tbl ** tsort ARGS((struct table *tp));
-/* trace.c */
-/* trap.c */
-void inittraps ARGS((void));
-#ifdef KSH
-void alarm_init ARGS((void));
-#endif /* KSH */
-Trap * gettrap ARGS((const char *name));
-RETSIGTYPE trapsig ARGS((int i));
-void intrcheck ARGS((void));
-int fatal_trap_check ARGS((void));
-int trap_pending ARGS((void));
-void runtraps ARGS((int intr));
-void runtrap ARGS((Trap *p));
-void cleartraps ARGS((void));
-void restoresigs ARGS((void));
-void settrap ARGS((Trap *p, char *s));
-int block_pipe ARGS((void));
-void restore_pipe ARGS((int restore_dfl));
-int setsig ARGS((Trap *p, handler_t f, int flags));
-void setexecsig ARGS((Trap *p, int restore));
-/* tree.c */
-int fptreef ARGS((struct shf *f, int indent, const char *fmt, ...));
-char * snptreef ARGS((char *s, int n, const char *fmt, ...));
-struct op * tcopy ARGS((struct op *t, Area *ap));
-char * wdcopy ARGS((const char *wp, Area *ap));
-char * wdscan ARGS((const char *wp, int c));
-void tfree ARGS((struct op *t, Area *ap));
-/* var.c */
-void newblock ARGS((void));
-void popblock ARGS((void));
-void initvar ARGS((void));
-struct tbl * global ARGS((const char *n));
-struct tbl * local ARGS((const char *n, bool_t copy));
-char * str_val ARGS((struct tbl *vp));
-long intval ARGS((struct tbl *vp));
-void setstr ARGS((struct tbl *vq, const char *s));
-struct tbl *setint_v ARGS((struct tbl *vq, struct tbl *vp));
-void setint ARGS((struct tbl *vq, long n));
-int getint ARGS((struct tbl *vp, long *nump));
-struct tbl * typeset ARGS((const char *var, Tflag set, Tflag clr, int field, int base));
-void unset ARGS((struct tbl *vp, int array_ref));
-char * skip_varname ARGS((const char *s, int aok));
-char *skip_wdvarname ARGS((const char *s, int aok));
-int is_wdvarname ARGS((const char *s, int aok));
-int is_wdvarassign ARGS((const char *s));
-char ** makenv ARGS((void));
-int array_ref_len ARGS((const char *cp));
-char * arrayname ARGS((const char *str));
-void set_array ARGS((const char *var, int reset, char **vals));
-/* version.c */
-/* vi.c: see edit.h */
-
-
-/* Hack to avoid billions of compile warnings on SunOS 4.1.x */
-#if defined(MUN) && defined(sun) && !defined(__svr4__)
-extern void bcopy ARGS((const void *src, void *dst, size_t size));
-extern int fclose ARGS((FILE *fp));
-extern int fprintf ARGS((FILE *fp, const char *fmt, ...));
-extern int fread ARGS((void *buf, int size, int num, FILE *fp));
-extern int ioctl ARGS((int fd, int request, void *arg));
-extern int killpg ARGS((int pgrp, int sig));
-extern int nice ARGS((int n));
-extern int readlink ARGS((const char *path, char *buf, int bufsize));
-extern int setpgrp ARGS((int pid, int pgrp));
-extern int strcasecmp ARGS((const char *s1, const char *s2));
-extern int tolower ARGS((int));
-extern int toupper ARGS((int));
-/* Include files aren't included yet */
-extern int getrlimit ARGS(( /* int resource, struct rlimit *rpl */ ));
-extern int getrusage ARGS(( /* int who, struct rusage *rusage */ ));
-extern int gettimeofday ARGS(( /* struct timeval *tv, struct timezone *tz */ ));
-extern int setrlimit ARGS(( /* int resource, struct rlimit *rlp */ ));
-extern int lstat ARGS(( /* const char *path, struct stat *buf */ ));
-#endif
diff --git a/bin/pdksh/sh.1tbl b/bin/pdksh/sh.1tbl
deleted file mode 100644
index 7d0eeacbc9e..00000000000
--- a/bin/pdksh/sh.1tbl
+++ /dev/null
@@ -1,2372 +0,0 @@
-'\" t
-.\" $OpenBSD: sh.1tbl,v 1.3 1997/08/05 21:49:56 grr Exp $
-.\"{{{}}}
-.\"{{{ Notes about man page
-.\" - use the pseudo-macros .sh( and .sh) to begin and end sh-specific
-.\" text and .ksh( and .ksh) for ksh specific text.
-.\" - put i.e., e.g. and etc. in italics
-.\"}}}
-.\"{{{ To do
-.\" todo: Things not covered that should be:
-.\" - distinguish (POSIX) special built-in's, (POSIX) regular built-in's,
-.\" and sh/ksh weirdo built-in's (put S,R,X superscripts after command
-.\" name in built-in commands section?)
-.\" - need to be consistent about notation for `See section-name', `
-.\" See description of foobar command', `See section section-name', etc.
-.\" - need to use the term `external command' meaning `a command that is
-.\" executed using execve(2)' (as opposed to a built-in command or
-.\" function) for more clear description.
-.\"}}}
-.\"{{{ Title
-.TH SH 1 "August 19, 1996" "" "User commands"
-.\"}}}
-.\"{{{ Name
-.SH NAME
-sh \- Public domain Bourne shell
-.\"}}}
-.\"{{{ Synopsis
-.SH SYNOPSIS
-.ad l
-\fBsh\fP
-[\fB\(+-abCefhikmnprsuvxX\fP] [\fB\(+-o\fP \fIoption\fP] [ [ \fB\-c\fP \fIcommand-string\fP [\fIcommand-name\fP] | \fB\-s\fP | \fIfile\fP ] [\fIargument\fP ...] ]
-.ad b
-.\"}}}
-.\"{{{ Description
-.SH DESCRIPTION
-\fBsh\fP is a reimplementation of the Bourne shell, a command
-interpreter for both interactive and script use.
-.\"{{{ Shell Startup
-.SS "Shell Startup"
-The following options can be specified only on the command line:
-.IP "\fB\-c\fP \fIcommand-string\fP"
-the shell executes the command(s) contained in \fIcommand-string\fP
-.IP \fB\-i\fP
-interactive mode \(em see below
-.IP \fB\-l\fP
-login shell \(em see below
-interactive mode \(em see below
-.IP \fB\-s\fP
-the shell reads commands from standard input; all non-option arguments
-are positional parameters
-.IP \fB\-r\fP
-restricted mode \(em see below
-.PP
-In addition to the above, the options described in the \fBset\fP built-in
-command can also be used on the command line.
-.PP
-If neither the \fB\-c\fP nor the \fB\-s\fP options are specified, the
-first non-option argument specifies the name of a file the shell reads
-commands from; if there are no non-option arguments, the shell reads
-commands from standard input.
-The name of the shell (\fIi.e.\fP, the contents of the \fB$0\fP) parameter
-is determined as follows: if the \fB\-c\fP option is used and there is
-a non-option argument, it is used as the name; if commands are being
-read from a file, the file is used as the name; otherwise the name
-the shell was called with (\fIi.e.\fP, argv[0]) is used.
-.PP
-A shell is \fBinteractive\fP if the \fB\-i\fP option is used or
-if both standard input and standard error are attached to a tty.
-An interactive shell has job control enabled (if available),
-ignores the INT, QUIT and TERM signals, and prints prompts before
-reading input (see \fBPS1\fP and \fBPS2\fP parameters).
-For non-interactive shells, the \fBtrackall\fP option is on by default
-(see \fBset\fP command below).
-.PP
-A shell is \fBrestricted\fP if the \fB\-r\fP option is used or if either
-the basename of the name the shell is invoked with or the \fBSHELL\fP
-parameter match the pattern *r*sh (\fIe.g.\fP, rsh, rksh, rpdksh, \fIetc.\fP).
-The following restrictions come into effect after the shell processes
-any profile and \fB$ENV\fP files:
-.nr P2 \n(PD
-.nr PD 0
-.IP \ \ \(bu
-the \fBcd\fP command is disabled
-.IP \ \ \(bu
-the \fBSHELL\fP, \fBENV\fP and \fBPATH\fP parameters can't be changed
-.IP \ \ \(bu
-command names can't be specified with absolute or relative paths
-.IP \ \ \(bu
-the \fB\-p\fP option of the \fBcommand\fP built-in can't be used
-.IP \ \ \(bu
-redirections that create files can't be used (\fIi.e.\fP, \fB>\fP,
-\fB>|\fP, \fB>>\fP, \fB<>\fP)
-.nr PD \n(P2
-.PP
-A shell is \fBprivileged\fP if the \fB\-p\fP option is used or if
-the real user-id or group-id does not match the effective user-id
-or group-id (see \fIgetuid\fP(2), \fIgetgid\fP(2)).
-A privileged shell does not process $HOME/.profile nor the \fBENV\fP
-parameter (see below), instead the file /etc/suid_profile is processed.
-Clearing the privileged option causes the shell to set its effective
-user-id (group-id) to its real user-id (group-id).
-.PP
-If the basename of the name the shell is called with (\fIi.e.\fP, argv[0])
-starts with \fB\-\fP or if the \fB\-l\fP option is used, the shell is assumed
-to be a login shell and the shell reads and executes the contents of
-\fB/etc/profile\fP and \fB$HOME/.profile\fP if they exist and are readable.
-.PP
-If the \fBENV\fP parameter is set when the shell starts (or, in the
-case of login shells, after any profiles are processed), its value
-is subjected to parameter, command, arithmetic and tilde substitution and
-the resulting file (if any) is read and executed.
-If \fBENV\fP parameter is not set (and not null) and pdksh was compiled
-with the \fBDEFAULT_ENV\fP macro defined, the file named in that macro
-is included (after the above mentioned substitutions have been performed).
-.PP
-The exit status of the shell is 127 if the command file specified
-on the command line could not be opened, or non-zero if a fatal syntax
-error occurred during the execution of a script.
-In the absence of fatal errors, the exit status is that of the last
-command executed, or zero, if no command is executed.
-.\"}}}
-.\"{{{ Command Syntax
-.SS "Command Syntax"
-.\"{{{ words and tokens
-The shell begins parsing its input by breaking it into \fIword\fPs.
-Words, which are sequences of characters, are delimited by unquoted
-\fIwhite-space\fP characters (space, tab and newline) or \fImeta-characters\fP
-(\fB<\fP, \fB>\fP, \fB|\fP, \fB;\fP, \fB&\fP, \fB(\fP and \fB)\fP).
-Aside from delimiting words, spaces and tabs are ignored, while
-newlines usually delimit commands.
-The meta-characters are used in building the following tokens:
-\fB<\fP, \fB<&\fP, \fB<<\fP, \fB>\fP, \fB>&\fP, \fB>>\fP, \fIetc.\fP are
-used to specify redirections (see Input/Output Redirection below);
-\fB|\fP is used to create pipelines;
-\fB;\fP is used to separate commands;
-\fB&\fP is used to create asynchronous pipelines;
-\fB&&\fP and \fB||\fP are used to specify conditional execution;
-\fB;;\fP is used in \fBcase\fP statements;
-and lastly,
-\fB(\fP .. \fB)\fP are used to create subshells.
-.PP
-White-space and meta-characters can be quoted individually using
-backslash (\fB\e\fP), or in groups using double (\fB"\fP) or single (\fB'\fP)
-quotes.
-Note that the following characters are also treated specially by the shell and
-must be quoted if they are to represent themselves:
-\fB\e\fP, \fB"\fP, \fB'\fP, \fB#\fP, \fB$\fP, \fB`\fP, \fB~\fP, \fB{\fP,
-\fB}\fP, \fB*\fP, \fB?\fP and \fB[\fP.
-The first three of these are the above mentioned quoting characters
-(see Quoting below);
-\fB#\fP, if used at the beginning of a word, introduces a comment \(em everything
-after the \fB#\fP up to the nearest newline is ignored;
-\fB$\fP is used to introduce parameter, command and arithmetic substitutions
-(see Substitution below);
-\fB`\fP introduces an old-style command substitution
-(see Substitution below);
-\fB~\fP begins a directory expansion (see Tilde Expansion below);
-\fB{\fP and \fB}\fP delimit \fIcsh\fP(1) style alternations
-(see Brace Expansion below);
-and, finally, \fB*\fP, \fB?\fP and \fB[\fP are used in file name generation
-(see File Name Patterns below).
-.\"}}}
-.\"{{{ simple-command
-.PP
-As words and tokens are parsed, the shell builds commands, of which
-there are two basic types: \fIsimple-commands\fP, typically programs
-that are executed, and \fIcompound-commands\fP, such as \fBfor\fP and
-\fBif\fP statements, grouping constructs and function definitions.
-.PP
-A simple-command consists of some combination of parameter assignments (see
-Parameters below), input/output redirections (see Input/Output Redirections
-below), and command words; the only restriction is that parameter assignments
-come before any command words.
-The command words, if any, define the command that is to be executed and its
-arguments.
-The command may be a shell built-in command, a function or an \fIexternal
-command\fP, \fIi.e.\fP, a separate executable file that is located using the
-\fBPATH\fP parameter (see Command Execution below).
-Note that all command constructs have an \fIexit status\fP: for external
-commands, this is related to the status returned by \fIwait\fP(2) (if the
-command could not be found, the exit status is 127, if it could not be
-executed, the exit status is 126);
-the exit status of other command constructs (built-in commands, functions,
-compound-commands, pipelines, lists, \fIetc.\fP) are all well defined and are
-described where the construct is described.
-The exit status of a command consisting only of parameter assignments is that
-of the last command substitution performed during the parameter assignment
-or zero if there were no command substitutions.
-.\"}}}
-.\"{{{ pipeline
-.PP
-Commands can be chained together using the \fB|\fP token to
-form \fIpipelines\fP, in which the standard output of each command but
-the last is piped (see \fIpipe\fP(2)) to the standard input of the following
-command.
-The exit status of a pipeline is that of its last command.
-A pipeline may be prefixed by the \fB!\fP reserved word which
-causes the exit status of the pipeline to be logically
-complemented: if the original status was 0 the complemented status will
-be 1, and if the original status was not 0, then the complemented
-status will be 0.
-.\"}}}
-.\"{{{ lists
-.PP
-\fILists\fP of commands can be created by separating pipelines by
-any of the following tokens: \fB&&\fP, \fB||\fP, \fB&\fP, \fB|&\fP and \fB;\fP.
-The first two are for conditional execution: \fIcmd1\fP \fB&&\fP \fIcmd2\fP
-executes \fIcmd2\fP only if the exit status of \fIcmd1\fP is zero;
-\fB||\fP is the opposite \(em \fIcmd2\fP is executed only if the exit status
-of \fIcmd1\fP is non-zero.
-\fB&&\fP and \fB||\fP have equal precedence which is higher than that of
-\fB&\fP, \fB|&\fP and \fB;\fP, which also have equal precedence.
-The \fB&\fP token causes the preceding command to be executed asynchronously,
-that is, the shell starts the command, but does not wait for it to complete
-(the shell does keep track of the status of asynchronous commands \(em see
-Job Control below).
-When an asynchronous command is started when job control is disabled
-(\fIi.e.\fP, in most scripts), the command is started with signals INT
-and QUIT ignored and with input redirected from /dev/null
-(however, redirections specified in the asynchronous command have precedence).
-Note that a command must follow the \fB&&\fP and \fB||\fP operators, while
-a command need not follow \fB&\fP, \fB|&\fP and \fB;\fP.
-The exit status of a list is that of the last command executed, with the
-exception of asynchronous lists, for which the exit status is 0.
-.\"}}}
-.\"{{{ compound-commands
-.PP
-Compound commands are created using the following reserved words \(em these
-words are only recognized if they are unquoted and if they are used as
-the first word of a command (\fIi.e.\fP, they can't be preceded by parameter
-assignments or redirections):
-.TS
-center;
-lfB lfB lfB lfB lfB .
-case else function then !
-do esac if time [[
-done fi in until {
-elif for select while }
-.TE
-\fBNote:\fP Some shells (but not this one) execute control structure commands
-in a subshell when one or more of their file descriptors are redirected, so
-any environment changes inside them may fail.
-To be portable, the \fBexec\fP statement should be used instead to redirect
-file descriptors before the control structure.
-.PP
-In the following compound command descriptions, command lists (denoted as
-\fIlist\fP) that are followed by reserved words must end with a
-semi-colon, a newline or a (syntactically correct) reserved word.
-For example,
-.RS
-\fB{ echo foo; echo bar; }\fP
-.br
-\fB{ echo foo; echo bar<newline>}\fP
-.br
-\fB{ { echo foo; echo bar; } }\fP
-.RE
-are all valid, but
-.RS
-\fB{ echo foo; echo bar }\fP
-.RE
-is not.
-.\"{{{ ( list )
-.IP "\fB(\fP \fIlist\fP \fB)\fP"
-Execute \fIlist\fP in a subshell. There is no implicit way to pass
-environment changes from a subshell back to its parent.
-.\"}}}
-.\"{{{ { list }
-.IP "\fB{\fP \fIlist\fP \fB}\fP"
-Compound construct; \fIlist\fP is executed, but not in a subshell.
-Note that \fB{\fP and \fB}\fP are reserved words, not meta-characters.
-.\"}}}
-.\"{{{ case word in [ [ ( ] pattern [ | pattern ] ... ) list ;; ] ... esac
-.IP "\fBcase\fP \fIword\fP \fBin\fP [ [\fB(\fP] \fIpattern\fP [\fB|\fP \fIpattern\fP] ... \fB)\fP \fIlist\fP \fB;;\fP ] ... \fBesac\fP"
-The \fBcase\fP statement attempts to match \fIword\fP against the specified
-\fIpattern\fPs; the \fIlist\fP associated with the first successfully matched
-pattern is executed. Patterns used in \fBcase\fP statements are the same as
-those used for file name patterns except that the restrictions regarding
-\fB\&.\fP and \fB/\fP are dropped. Note that any unquoted space before and
-after a pattern is stripped; any space with a pattern must be quoted. Both the
-word and the patterns are subject to parameter, command, and arithmetic
-substitution as well as tilde substitution.
-For historical reasons, open and close braces may be used instead
-of \fBin\fP and \fBesac\fP (\fIe.g.\fP, \fBcase $foo { *) echo bar; }\fP).
-The exit status of a \fBcase\fP statement is that of the executed \fIlist\fP;
-if no \fIlist\fP is executed, the exit status is zero.
-.\"}}}
-.\"{{{ for name [ in word ... term ] do list done
-.IP "\fBfor\fP \fIname\fP [ \fBin\fP \fIword\fP ... \fIterm\fP ] \fBdo\fP \fIlist\fP \fBdone\fP"
-where \fIterm\fP is either a newline or a \fB;\fP.
-For each \fIword\fP in the specified word list, the parameter \fIname\fP is
-set to the word and \fIlist\fP is executed. If \fBin\fP is not used to
-specify a word list, the positional parameters (\fB"$1"\fP, \fB"$2"\fP,
-\fIetc.\fP) are used instead.
-For historical reasons, open and close braces may be used instead
-of \fBdo\fP and \fBdone\fP (\fIe.g.\fP, \fBfor i; { echo $i; }\fP).
-The exit status of a \fBfor\fP statement is the last exit status
-of \fIlist\fP; if \fIlist\fP is never executed, the exit status is zero.
-.\"}}}
-.\"{{{ if list then list [ elif list then list ] ... [ else list ] fi
-.IP "\fBif\fP \fIlist\fP \fBthen\fP \fIlist\fP [\fBelif\fP \fIlist\fP \fBthen\fP \fIlist\fP] ... [\fBelse\fP \fIlist\fP] \fBfi\fP"
-If the exit status of the first \fIlist\fP is zero, the second \fIlist\fP
-is executed; otherwise the \fIlist\fP following the \fBelif\fP, if any, is
-executed with similar consequences. If all the lists following the \fBif\fP
-and \fBelif\fPs fail (\fIi.e.\fP, exit with non-zero status), the \fIlist\fP
-following the \fBelse\fP is executed.
-The exit status of an \fBif\fP statement is that
-of non-conditional \fIlist\fP that is executed; if no non-conditional
-\fIlist\fP is executed, the exit status is zero.
-.\"}}}
-.\"{{{ select name [ in word ... ] do list done
-.\"}}}
-.\"{{{ until list do list done
-.IP "\fBuntil\fP \fIlist\fP \fBdo\fP \fIlist\fP \fBdone\fP"
-This works like \fBwhile\fP, except that the body is executed only while the
-exit status of the first \fIlist\fP is non-zero.
-.\"}}}
-.\"{{{ while list do list done
-.IP "\fBwhile\fP \fIlist\fP \fBdo\fP \fIlist\fP \fBdone\fP"
-A \fBwhile\fP is a prechecked loop. Its body is executed as often
-as the exit status of the first \fIlist\fP is zero.
-The exit status of a \fBwhile\fP statement is the last exit status
-of the \fIlist\fP in the body of the loop; if the body is not executed,
-the exit status is zero.
-.\"}}}
-.\"{{{ function name { list }
-.IP "\fBfunction\fP \fIname\fP \fB{\fP \fIlist\fP \fB}\fP"
-Defines the function \fIname\fP.
-See Functions below.
-Note that redirections specified after a function definition are
-performed whenever the function is executed, not when the function
-definition is executed.
-.\"}}}
-.\"{{{ name () command
-.IP "\fIname\fP \fB()\fP \fIcommand\fP"
-Mostly the same as \fBfunction\fP.
-See Functions below.
-.\"}}}
-.\"{{{ (( expression ))
-.\"}}}
-.\"{{{ [[ expression ]]
-.\"}}}
-.\"}}}
-.\"}}}
-.\"{{{ Quoting
-.SS Quoting
-Quoting is used to prevent the shell from treating characters or words
-specially.
-There are three methods of quoting: First, \fB\e\fP quotes
-the following character, unless it is at the end of a line, in which
-case both the \fB\e\fP and the newline are stripped.
-Second, a single quote (\fB'\fP) quotes everything up to the next single
-quote (this may span lines).
-Third, a double quote (\fB"\fP) quotes all characters,
-except \fB$\fP, \fB`\fP and \fB\e\fP, up to the next unquoted double quote.
-\fB$\fP and \fB`\fP inside double quotes have their usual meaning (\fIi.e.\fP,
-parameter, command or arithmetic substitution) except no field splitting
-is carried out on the results of double-quoted substitutions.
-If a \fB\e\fP inside a double-quoted string is followed by \fB\e\fP, \fB$\fP,
-\fB`\fP or \fB"\fP, it is replaced by the second character; if it is
-followed by a newline, both the \fB\e\fP and the newline are stripped;
-otherwise, both the \fB\e\fP and the character following are unchanged.
-.PP
-Note: see POSIX Mode below for a special rule regarding sequences
-of the form \fB"\fP...\fB`\fP...\fB\e"\fP...\fB`\fP..\fB"\fP.
-.\"}}}
-.\"{{{ Aliases
-.SS "Aliases"
-There are two types of aliases: normal command aliases and tracked
-aliases. Command aliases are normally used as a short hand for a long
-or often used command. The shell expands command aliases (\fIi.e.\fP,
-substitutes the alias name for its value) when it reads the first word
-of a command. An expanded alias is re-processed to check for more
-aliases. If a command alias ends in a space or tab, the following word
-is also checked for alias expansion. The alias expansion process stops
-when a word that is not an alias is found, when a quoted word is found
-or when an alias word that is currently being expanded is found.
-.PP
-The following command aliases are defined automatically by the shell:
-.ft B
-.RS
-hash='alias \-t'
-.br
-type='whence \-v'
-.RE
-.ft P
-.PP
-Tracked aliases allow the shell to remember where it found a particular
-command. The first time the shell does a path search for a command that
-is marked as a tracked alias, it saves the full path of the command.
-The next time the command is executed, the shell checks the saved path
-to see that it is still valid, and if so, avoids repeating the path
-search. Tracked aliases can be listed and created using \fBalias
-\-t\fP. Note that changing the \fBPATH\fP parameter clears the saved
-paths for all tracked aliases. If the \fBtrackall\fP option is set (\fIi.e.\fP,
-\fBset \-o trackall\fP or \fBset \-h\fP), the shell tracks all
-commands. This option is set automatically for non-interactive shells.
-For interactive shells, only the following commands are automatically
-tracked: \fBcat\fP, \fBcc\fP, \fBchmod\fP, \fBcp\fP, \fBdate\fP, \fBed\fP,
-\fBemacs\fP, \fBgrep\fP, \fBls\fP, \fBmail\fP, \fBmake\fP, \fBmv\fP,
-\fBpr\fP, \fBrm\fP, \fBsed\fP, \fBsh\fP, \fBvi\fP and \fBwho\fP.
-.\"}}}
-.\"{{{ Substitution
-.SS "Substitution"
-The first step the shell takes in executing a simple-command is to
-perform substitutions on the words of the command.
-There are three kinds of substitution: parameter, command and arithmetic.
-Parameter substitutions, which are described in detail in the next section,
-take the form \fB$name\fP or \fB${\fP...\fB}\fP; command substitutions take
-the form \fB$(\fP\fIcommand\fP\fB)\fP or \fB`\fP\fIcommand\fP\fB`\fP;
-and arithmetic substitutions take the form \fB$((\fP\fIexpression\fP\fB))\fP.
-.PP
-If a substitution appears outside of double quotes, the results of the
-substitution are generally subject to word or field splitting according to
-the current value of the \fBIFS\fP parameter.
-The \fBIFS\fP parameter specifies a list of characters which
-are used to break a string up into several words;
-any characters from the set space, tab and newline that appear in the
-IFS characters are called \fIIFS white space\fP.
-Sequences of one or more IFS white space characters, in combination with
-zero or one non-IFS white space characters delimit a field.
-As a special case, leading and trailing IFS white space is stripped (\fIi.e.\fP,
-no leading or trailing empty field is created by it); leading or trailing
-non-IFS white space does create an empty field.
-.PP
-Example: if \fBIFS\fP is set to `<space>:', and VAR is set to
-`<space>A<space>:<space><space>B::D', the substitution for $VAR results
-in four fields: `A', `B', `' and `D'.
-Note that if the \fBIFS\fP parameter is set to the null string, no
-field splitting is done; if the parameter is unset, the default value
-of space, tab and newline is used.
-.PP
-Also, note that the field splitting applies only to immediate result of
-the substitution. Using the previous example, the substitution for $VAR:E
-results in the fields: `A', `B', `' and `D:E', not `A', `B', `', `D' and `E'.
-This behavior is POSIX compliant, but incompatible with some other shell
-implementations which do field splitting on the word which contained the
-substitution or use \fBIFS\fP\ as a general whitespace delimiter.
-.PP
-The results of substitution are, unless otherwise specified, also subject
-to brace expansion and file name expansion (see the relevant sections
-below).
-.PP
-A command substitution is replaced by the output generated by the specified
-command, which is run in a subshell.
-For \fB$(\fP\fIcommand\fP\fB)\fP substitutions, normal quoting rules
-are used when \fIcommand\fP is parsed, however, for the
-\fB`\fP\fIcommand\fP\fB`\fP form, a \fB\e\fP followed by any of
-\fB$\fP, \fB`\fP or \fB\e\fP is stripped (a \fB\e\fP followed by any other
-character is unchanged).
-As a special case in command substitutions, a command of the form
-\fB<\fP \fIfile\fP is interpreted to mean substitute the contents
-of \fIfile\fP ($(< foo) has the same effect as $(cat foo), but it
-is carried out more efficiently because no process is started).
-.br
-.\"todo: fix this( $(..) parenthesis counting).
-NOTE: \fB$(\fP\fIcommand\fP\fB)\fP expressions are currently parsed by
-finding the matching parenthesis, regardless of quoting. This will hopefully
-be fixed soon.
-.PP
-Arithmetic substitutions are replaced by the value of the specified
-expression.
-For example, the command \fBecho $((2+3*4))\fP prints 14.
-See Arithmetic Expressions for a description of an \fIexpression\fP.
-.\"}}}
-.\"{{{ Parameters
-.SS "Parameters"
-Parameters are shell variables; they can be assigned values and
-their values can be accessed using a parameter substitution.
-A parameter name is either one of the special single punctuation or digit
-character parameters described below, or a letter followed by zero or more
-letters or digits (`_' counts as a letter).
-Parameter substitutions take the form \fB$\fP\fIname\fP or
-\fB${\fP\fIname\fP\fB}\fP, where \fIname\fP is a parameter name.
-If substitution is performed on a parameter that is not set, a null
-string is substituted unless the \fBnounset\fP option (\fBset \-o nounset\fP
-or \fBset \-u\fP) is set, in which case an error occurs.
-.PP
-.\"{{{ parameter assignment
-Parameters can be assigned values in a number of ways.
-First, the shell implicitly sets some parameters like \fB#\fP, \fBPWD\fP,
-etc.; this is the only way the special single character parameters are
-set.
-Second, parameters are imported from the shell's environment at startup.
-Third, parameters can be assigned values on the command line, for example,
-`\fBFOO=bar\fP' sets the parameter FOO to bar; multiple parameter
-assignments can be given on a single command line and they can
-be followed by a simple-command, in which case the assignments are
-in effect only for the duration of the command (such assignments are
-also exported, see below for implications of this).
-Note that both the parameter name and the \fB=\fP must be unquoted for
-the shell to recognize a parameter assignment.
-The fourth way of setting a parameter is with the \fBexport\fP, \fBreadonly\fP
-and \fBtypeset\fP commands; see their descriptions in the Command Execution
-section.
-Fifth, \fBfor\fP and \fBselect\fP loops set parameters as well as
-the \fBgetopts\fP, \fBread\fP and \fBset \-A\fP commands.
-Lastly, parameters can be assigned values using assignment operators
-inside arithmetic expressions (see Arithmetic Expressions below) or
-using the \fB${\fP\fIname\fP\fB=\fP\fIvalue\fP\fB}\fP form
-of parameter substitution (see below).
-.\"}}}
-.PP
-.\"{{{ environment
-Parameters with the export attribute (set using the \fBexport\fP or
-\fBtypeset \-x\fP commands, or by parameter assignments followed by simple
-commands) are put in the environment (see \fIenviron\fP(5)) of commands
-run by the shell as \fIname\fP\fB=\fP\fIvalue\fP pairs.
-The order in which parameters appear in the environment of a command
-is unspecified.
-When the shell starts up, it extracts parameters and their values from its
-environment and automatically sets the export attribute for those parameters.
-.\"}}}
-.\"{{{ ${name[:][-+=?]word}
-.PP
-Modifiers can be applied to the \fB${\fP\fIname\fP\fB}\fP form of parameter
-substitution:
-.IP \fB${\fP\fIname\fP\fB:-\fP\fIword\fP\fB}\fP
-if \fIname\fP is set and not null, it is substituted, otherwise \fIword\fP is
-substituted.
-.IP \fB${\fP\fIname\fP\fB:+\fP\fIword\fP\fB}\fP
-if \fIname\fP is set and not null, \fIword\fP is substituted, otherwise nothing is substituted.
-.IP \fB${\fP\fIname\fP\fB:=\fP\fIword\fP\fB}\fP
-if \fIname\fP is set and not null, it is substituted, otherwise it is
-assigned \fIword\fP and the resulting value of \fIname\fP is substituted.
-.IP \fB${\fP\fIname\fP\fB:?\fP\fIword\fP\fB}\fP
-if \fIname\fP is set and not null, it is substituted, otherwise \fIword\fP
-is printed on standard error (preceded by \fIname\fP:) and an error occurs
-(normally causing termination of a shell script, function or \&.-script).
-If word is omitted the string `parameter null or not set' is used instead.
-.PP
-In the above modifiers, the \fB:\fP can be omitted, in which case the
-conditions only depend on \fIname\fP being set (as opposed to set and
-not null).
-If \fIword\fP is needed, parameter, command, arithmetic and tilde substitution
-are performed on it; if \fIword\fP is not needed, it is not evaluated.
-.\"}}}
-.PP
-The following forms of parameter substitution can also be used:
-.\"{{{ ${#name}
-.IP \fB${#\fP\fIname\fP\fB}\fP
-The number of positional parameters if \fIname\fP is \fB*\fP, \fB@\fP or
-is not specified,
-or the length of the string value of parameter \fIname\fP.
-.\"}}}
-.\"{{{ ${#name[*]}, ${#name[@]}
-.IP "\fB${#\fP\fIname\fP\fB[*]}\fP, \fB${#\fP\fIname\fP\fB[@]}\fP"
-The number of elements in the array \fIname\fP.
-.\"}}}
-.\"{{{ ${name#pattern}, ${name##pattern}
-.IP "\fB${\fP\fIname\fP\fB#\fP\fIpattern\fP\fB}\fP, \fB${\fP\fIname\fP\fB##\fP\fIpattern\fP\fB}\fP"
-If \fIpattern\fP matches the beginning of the value of parameter \fIname\fP,
-the matched text is deleted from the result of substitution. A single
-\fB#\fP results in the shortest match, two \fB#\fP's results in the
-longest match.
-.\"}}}
-.\"{{{ ${name%pattern}, ${name%%pattern}
-.IP "\fB${\fP\fIname\fP\fB%\fP\fIpattern\fP\fB}\fP, \fB${\fP\fIname\fP\fB%%\fP\fIpattern\fP\fB}\fP"
-Like \fB${\fP..\fB#\fP..\fB}\fP substitution, but it deletes from the end of the
-value.
-.\"}}}
-.\"{{{ special shell parameters
-.PP
-The following special parameters are implicitly set by the shell and cannot be
-set directly using assignments:
-.\"{{{ !
-.IP \fB!\fP
-Process id of the last background process started. If no background
-processes have been started, the parameter is not set.
-.\"}}}
-.\"{{{ #
-.IP \fB#\fP
-The number of positional parameters (\fIi.e.\fP, \fB$1\fP, \fB$2\fP,
-\fIetc.\fP).
-.\"}}}
-.\"{{{ $
-.IP \fB$\fP
-The process ID of the shell, or the PID of the original shell if
-it is a subshell.
-.\"}}}
-.\"{{{ -
-.IP \fB\-\fP
-The concatenation of the current single letter options
-(see \fBset\fP command below for list of options).
-.\"}}}
-.\"{{{ ?
-.IP \fB?\fP
-The exit status of the last non-asynchronous command executed.
-If the last command was killed by a signal, \fB$?\fP is set to 128 plus
-the signal number.
-.\"}}}
-.\"{{{ 0
-.IP "\fB0\fP"
-The name the shell was invoked with (\fIi.e.\fP, \fBargv[0]\fP), or the
-\fBcommand-name\fP if it was invoked with the \fB\-c\fP option and the
-\fBcommand-name\fP was supplied, or the \fIfile\fP argument, if it was
-supplied.
-If the \fBposix\fP option is not set, \fB$0\fP is the name of the current
-function or script.
-.\"}}}
-.\"{{{ 1-9
-.IP "\fB1\fP ... \fB9\fP"
-The first nine positional parameters that were supplied to the shell,
-function or \fB.\fP-script.
-Further positional parameters may be accessed using
-\fB${\fP\fInumber\fP\fB}\fP.
-.\"}}}
-.\"{{{ *
-.IP \fB*\fP
-All positional parameters (except parameter 0),
-\fIi.e.\fP, \fB$1 $2 $3\fP....
-If used outside of double quotes, parameters are separate words
-(which are subjected to word splitting); if used within double quotes,
-parameters are separated by the first character of the \fBIFS\fP parameter
-(or the empty string if \fBIFS\fP is null).
-.\"}}}
-.\"{{{ @
-.IP \fB@\fP
-Same as \fB$*\fP, unless it is used inside double quotes, in which case
-a separate word is generated for each positional parameter \- if there
-are no positional parameters, no word is generated ("$@" can be used
-to access arguments, verbatim, without loosing null arguments or
-splitting arguments with spaces).
-.\"}}}
-.\"}}}
-.\"{{{ general shell parameters
-.PP
-The following parameters are set and/or used by the shell:
-.\"{{{ CDPATH
-.IP \fBCDPATH\fP
-Search path for the \fBcd\fP built-in command. Works the same way as
-\fBPATH\fP for those directories not beginning with \fB/\fP in \fBcd\fP
-commands.
-Note that if CDPATH is set and does not contain \fB.\fP nor an empty path,
-the current directory is not searched.
-.\"}}}
-.\"{{{ COLUMNS
-.IP \fBCOLUMNS\fP
-Set to the number of columns on the terminal or window.
-Currently set to the \fBcols\fP value as reported by \fIstty\fP(1) if that
-value is non-zero.
-This parameter is used by the interactive line editing modes, and by
-\fBselect\fP, \fBset \-o\fP and \fBkill \-l\fP commands
-to format information in columns.
-.\"}}}
-.\"{{{ EDITOR
-.\"}}}
-.\"{{{ ENV
-.IP \fBENV\fP
-If this parameter is found to be set after any profile files are
-executed, the expanded value is used as a shell start-up file. It
-typically contains function and alias definitions.
-.\"}}}
-.\"{{{ ERRNO
-.IP \fBERRNO\fP
-Integer value of the shell's errno variable \(em indicates the reason
-the last system call failed.
-.\" todo: ERRNO variable
-.sp
-Not implemented yet.
-.\"}}}
-.\"{{{ EXECSHELL
-.IP \fBEXECSHELL\fP
-If set, this parameter is assumed to contain the shell that is to be
-used to execute commands that \fIexecve\fP(2) fails to execute and
-which do not start with a `\fB#!\fP \fIshell\fP' sequence.
-.\"}}}
-.\"{{{ FCEDIT
-.IP \fBFCEDIT\fP
-The editor used by the \fBfc\fP command (see below).
-.\"}}}
-.\"{{{ FPATH
-.IP \fBFPATH\fP
-Like \fBPATH\fP, but used when an undefined function is executed to locate
-the file defining the function.
-It is also searched when a command can't be found using \fBPATH\fP.
-See Functions below for more information.
-.\"}}}
-.\"{{{ HISTFILE
-.\"}}}
-.\"{{{ HISTSIZE
-.\"}}}
-.\"{{{ HOME
-.IP \fBHOME\fP
-The default directory for the \fBcd\fP command and the value
-substituted for an unqualified \fB~\fP (see Tilde Expansion below).
-.\"}}}
-.\"{{{ IFS
-.IP \fBIFS\fP
-Internal field separator, used during substitution and by the \fBread\fP
-command, to split values into distinct arguments; normally set to
-space, tab and newline. See Substitution above for details.
-.br
-\fBNote:\fP this parameter is not imported from the environment
-when the shell is started.
-.\"}}}
-.\"{{{ KSH_VERSION
-.\"}}}
-.\"{{{ SH_VERSION
-.IP \fBSH_VERSION\fP
-The version of shell and the date the version was created (readonly).
-.\"}}}
-.\"{{{ LINENO
-.IP \fBLINENO\fP
-The line number of the function or shell script that is currently being
-executed.
-.\" todo: LINENO variable
-.sp
-Not implemented yet.
-.\"}}}
-.\"{{{ LINES
-.IP \fBLINES\fP
-Set to the number of lines on the terminal or window.
-.\"Currently set to the \fBrows\fP value as reported by \fIstty\fP(1) if that
-.\"value is non-zero.
-.\" todo: LINES variable
-.sp
-Not implemented yet.
-.\"}}}
-.\"{{{ MAIL
-.\"}}}
-.\"{{{ MAILCHECK
-.\"}}}
-.\"{{{ MAILPATH
-.\"}}}
-.\"{{{ OLDPWD
-.IP \fBOLDPWD\fP
-The previous working directory.
-Unset if \fBcd\fP has not successfully changed directories since the
-shell started, or if the shell doesn't know where it is.
-.\"}}}
-.\"{{{ OPTARG
-.IP \fBOPTARG\fP
-When using \fBgetopts\fP, it contains the argument for a parsed option,
-if it requires one.
-.\"}}}
-.\"{{{ OPTIND
-.IP \fBOPTIND\fP
-The index of the last argument processed when using \fBgetopts\fP.
-Assigning 1 to this parameter causes \fBgetopts\fP to
-process arguments from the beginning the next time it is invoked.
-.\"}}}
-.\"{{{ PATH
-.IP \fBPATH\fP
-A colon separated list of directories that are searched when looking
-for commands and \fB.\fP'd files.
-An empty string resulting from a leading or trailing colon, or two adjacent
-colons is treated as a `.', the current directory.
-.\"}}}
-.\"{{{ POSIXLY_CORRECT
-.IP \fBPOSIXLY_CORRECT\fP
-If set, this parameter causes the \fBposix\fP option to be enabled.
-See POSIX Mode below.
-.\"}}}
-.\"{{{ PPID
-.IP \fBPPID\fP
-The process ID of the shell's parent (readonly).
-.\"}}}
-.\"{{{ PS1
-.IP \fBPS1\fP
-\fBPS1\fP is the primary prompt for interactive shells.
-The prompt is printed verbatim (\fIi.e.\fP, no substitutions are done).
-Default is `\fB$\ \fP' for non-root users, `\fB#\ \fP' for root..
-.\"}}}
-.\"{{{ PS2
-.IP \fBPS2\fP
-Secondary prompt string, by default `\fB>\fP ', used when more input is
-needed to complete a command.
-.\"}}}
-.\"{{{ PS3
-.\"}}}
-.\"{{{ PS4
-.IP \fBPS4\fP
-Used to prefix commands that are printed during execution tracing
-(see \fBset \-x\fP command below).
-The prompt is printed verbatim (\fIi.e.\fP, no substitutions are done).
-Default is `\fB+\ \fP'.
-.\"}}}
-.\"{{{ PWD
-.IP \fBPWD\fP
-The current working directory. Maybe unset or null if shell doesn't
-know where it is.
-.\"}}}
-.\"{{{ RANDOM
-.\"}}}
-.\"{{{ REPLY
-.IP \fBREPLY\fP
-Default parameter for the \fBread\fP command if no names are given.
-Also used in \fBselect\fP loops to store the value that is read from
-standard input.
-.\"}}}
-.\"{{{ SECONDS
-.\"}}}
-.\"{{{ TMOUT
-.\"}}}
-.\"{{{ TMPDIR
-.IP \fBTMPDIR\fP
-The directory shell temporary files are created in. If this parameter
-is not set, or does not contain the absolute path of a writable
-directory, temporary files are created in \fB/tmp\fP.
-.\"}}}
-.\"{{{ VISUAL
-.\"}}}
-.\"}}}
-.\"}}}
-.\"{{{ Tilde Expansion
-.SS "Tilde Expansion"
-Tilde expansion, which is done in parallel with parameter substitution,
-is done on words starting with an unquoted \fB~\fP. The characters
-following the tilde, up to the first \fB/\fP, if any, are assumed to be
-a login name. If the login name is empty, \fB+\fP or \fB\-\fP, the
-value of the \fBHOME\fP, \fBPWD\fP, or \fBOLDPWD\fP parameter is
-substituted, respectively. Otherwise, the password file is searched for
-the login name, and the tilde expression is substituted with the
-user's home directory. If the login name is not found in the password
-file or if any quoting or parameter substitution occurs in the login name,
-no substitution is performed.
-.PP
-In parameter assignments (those preceding a simple-command or those
-occurring in the arguments of \fBalias\fP, \fBexport\fP, \fBreadonly\fP,
-and \fBtypeset\fP), tilde expansion is done after any unquoted colon
-(\fB:\fP), and login names are also delimited by colons.
-.PP
-The home directory of previously expanded login names are cached and
-re-used. The \fBalias \-d\fP command may be used to list, change and
-add to this cache (\fIe.g.\fP, `alias \-d fac=/usr/local/facilities; cd
-~fac/bin').
-.\"}}}
-.\"{{{ Brace Expansion
-.\"}}}
-.\"{{{ File Name Patterns
-.SS "File Name Patterns"
-.PP
-A file name pattern is a word containing one or more unquoted \fB?\fP or
-\fB*\fP characters or \fB[\fP..\fB]\fP sequences. Once brace expansion has
-been performed, the shell replaces file name patterns with the sorted names
-of all the files that match the pattern (if no files match, the word is
-left unchanged). The pattern elements have the following meaning:
-.IP \fB?\fP
-matches any single character.
-.IP \fB*\fP
-matches any sequence of characters.
-.IP \fB[\fP..\fB]\fP
-matches any of the characters inside the brackets. Ranges of characters
-can be specified by separating two characters by a \fB\-\fP, \fIe.g.\fP,
-\fB[a0\-9]\fP matches the letter \fBa\fP or any digit.
-In order to represent itself, a
-\fB\-\fP must either be quoted or the first or last character in the character
-list. Similarly, a \fB]\fP must be quoted or the first character in the list
-if it is represent itself instead of the end of the list. Also, a \fB!\fP
-appearing at the start of the list has special meaning (see below), so to
-represent itself it must be quoted or appear later in the list.
-.IP \fB[!\fP..\fB]\fP
-like \fB[\fP..\fB]\fP, except it matches any character not inside the brackets.
-.PP
-Note that pdksh currently never matches \fB.\fP and \fB..\fP, but the original
-ksh, Bourne sh and bash do, so this may have to change (too bad).
-.PP
-Note that none of the above pattern elements match either a period (\fB.\fP)
-at the start of a file name or a slash (\fB/\fP), even if they are explicitly
-used in a \fB[\fP..\fB]\fP sequence; also, the names \fB.\fP and \fB..\fP
-are never matched, even by the pattern \fB.*\fP.
-.PP
-If the \fBmarkdirs\fP option is set, any directories that result from
-file name generation are marked with a trailing \fB/\fP.
-.PP
-.\" todo: implement this ([[:alpha:]], \fIetc.\fP)
-The POSIX character classes (\fIi.e.\fP,
-\fB[:\fP\fIclass-name\fP\fB:]\fP inside a \fB[\fP..\fB]\fP expression)
-are not yet implemented.
-.\"}}}
-.\"{{{ Input/Output Redirection
-.SS "Input/Output Redirection"
-When a command is executed, its standard input, standard output and
-standard error (file descriptors 0, 1 and 2, respectively) are normally
-inherited from the shell.
-Three exceptions to this are commands in pipelines, for which standard input
-and/or standard output are those set up by the pipeline, asynchronous commands
-created when job control is disabled, for which standard input is initially
-set to be from \fB/dev/null\fP, and commands for which any of the following
-redirections have been specified:
-.IP "\fB>\fP \fIfile\fP"
-standard output is redirected to \fIfile\fP. If \fIfile\fP does not exist,
-it is created; if it does exist, is a regular file and the \fBnoclobber\fP
-option is set, an error occurs, otherwise the file is truncated.
-Note that this means the command \fIcmd < foo > foo\fP will open
-\fIfoo\fP for reading and then truncate it when it opens it for writing,
-before \fIcmd\fP gets a chance to actually read \fIfoo\fP.
-.IP "\fB>|\fP \fIfile\fP"
-same as \fB>\fP, except the file is truncated, even if the \fBnoclobber\fP
-option is set.
-.IP "\fB>>\fP \fIfile\fP"
-same as \fB>\fP, except the file an existing file is appended to instead
-of being truncated. Also, the file is opened in append mode, so writes
-always go to the end of the file (see \fIopen\fP(2)).
-.IP "\fB<\fP \fIfile\fP"
-standard input is redirected from \fIfile\fP, which is opened for reading.
-.IP "\fB<>\fP \fIfile\fP"
-same as \fB<\fP, except the file is opened for reading and writing.
-.IP "\fB<<\fP \fImarker\fP"
-after reading the command line containing this kind of redirection (called a
-here document), the shell copies lines from the command source into a temporary
-file until a line matching \fImarker\fP is read.
-When the command is executed, standard input is redirected from the temporary
-file.
-If \fImarker\fP contains no quoted characters, the contents of the
-temporary file are processed as if enclosed in double quotes each time
-the command is executed, so parameter, command and arithmetic substitutions
-are performed, along with backslash (\fB\e\fP) escapes for
-\fB$\fP, \fB`\fP, \fB\e\fP and \fB\enewline\fP.
-If multiple here documents are used on the same command line, they are
-saved in order.
-.IP "\fB<<-\fP \fImarker\fP"
-same as \fB<<\fP, except leading tabs are stripped from lines in the
-here document.
-.IP "\fB<&\fP \fIfd\fP"
-standard input is duplicated from file descriptor \fIfd\fP.
-\fIfd\fP can be a single digit, indicating the number of an existing
-file descriptor, the letter \fBp\fP, indicating the file descriptor
-associated with the output of the current co-process, or
-the character \fB\-\fP, indicating standard input is to be closed.
-.IP "\fB>&\fP \fIfd\fP"
-same as \fB<&\fP, except the operation is done on standard output.
-.PP
-In any of the above redirections, the file descriptor that is redirected
-(\fIi.e.\fP, standard input or standard output) can be explicitly given by
-preceding the redirection with a single digit.
-Parameter, command and arithmetic substitutions, tilde substitutions and
-file name generation are all performed on the \fIfile\fP, \fImarker\fP and
-\fIfd\fP arguments of redirections.
-Note however, that the results of any file name generation are only used
-if a single file is matched; if multiple files match, the word with the
-unexpanded file name generation characters is used.
-Note that in restricted shells, redirections which can create files cannot
-be used.
-.PP
-For simple-commands, redirections may appear anywhere in the command, for
-compound-commands (\fBif\fP statements, \fIetc.\fP), any redirections must
-appear at the end.
-Redirections are processed after pipelines are created and in the order they
-are given, so
-.RS
-\fBcat /foo/bar 2>&1 > /dev/null | cat \-n\fP
-.RE
-will print an error with a line number prepended to it.
-.\"}}}
-.\"{{{ Arithmetic Expressions
-.SS "Arithmetic Expressions"
-Integer arithmetic expressions can be used
-inside \fB$((\fP..\fB))\fP expressions,
-inside array references (\fIe.g.\fP, \fIname\fP\fB[\fP\fIexpr\fP\fB]\fP),
-as numeric arguments to the \fBtest\fP command,
-and as the value of an assignment to an integer parameter.
-.PP
-Expression may contain alpha-numeric parameter identifiers, array
-references, and integer constants and may be combined with the
-following C operators (listed and grouped in increasing order of precedence).
-.TP
-Unary operators:
-\fB+ \- ! ~ ++ --\fP
-.TP
-Binary operators:
-\fB,\fP
-.br
-\fB= *= /= %= += \-= <<= >>= &= ^= |=\fP
-.br
-\fB||\fP
-.br
-\fB&&\fP
-.br
-\fB|\fP
-.br
-\fB^\fP
-.br
-\fB&\fP
-.br
-\fB== !=\fP
-.br
-\fB< <= >= >\fP
-.br
-\fB<< >>\fP
-.br
-\fB+ \-\fP
-.br
-\fB* / %\fP
-.TP
-Ternary operator:
-\fB?:\fP (precedence is immediately higher than assignment)
-.TP
-Grouping operators:
-\fB( )\fP
-.PP
-Integer constants may be specified with arbitrary bases using the notation
-\fIbase\fP\fB#\fP\fInumber\fP, where \fIbase\fP is a decimal integer specifying
-the base, and \fInumber\fP is a number in the specified base.
-.LP
-The operators are evaluated as follows:
-.RS
-.IP "unary \fB+\fP"
-result is the argument (included for completeness).
-.IP "unary \fB\-\fP"
-negation.
-.IP "\fB!\fP"
-logical not; the result is 1 if argument is zero, 0 if not.
-.IP "\fB~\fP"
-arithmetic (bit-wise) not.
-.IP "\fB++\fP"
-increment; must be applied to a parameter (not a literal or other
-expression) - the parameter is incremented by 1.
-When used as a prefix operator, the result is the incremented value of
-the parameter, when used as a postfix operator, the result is the
-original value of the parameter.
-.IP "\fB++\fP"
-similar to \fB++\fP, except the paramter is decremented by 1.
-.IP "\fB,\fP"
-seperates two arithmetic expressions; the left hand side is evaluated first,
-then the right. The result is value of the expression on the right hand side.
-.IP "\fB=\fP"
-assignment; variable on the left is set to the value on the right.
-.IP "\fB*= /= %= += \-= <<= >>= &= ^= |=\fP"
-assignment operators; \fI<var> <op>\fP\fB=\fP \fI<expr>\fP is the same as
-\fI<var>\fP \fB=\fP \fI<var> <op>\fP \fB(\fP \fI<expr>\fP \fB)\fP.
-.IP "\fB||\fP"
-logical or; the result is 1 if either argument is non-zero, 0 if not.
-The right argument is evaluated only if the left argument is zero.
-.IP "\fB&&\fP"
-logical and; the result is 1 if both arguments are non-zero, 0 if not.
-The right argument is evaluated only if the left argument is non-zero.
-.IP "\fB|\fP"
-arithmetic (bit-wise) or.
-.IP "\fB^\fP"
-arithmetic (bit-wise) exclusive-or.
-.IP "\fB&\fP"
-arithmetic (bit-wise) and.
-.IP "\fB==\fP"
-equal; the result is 1 if both arguments are equal, 0 if not.
-.IP "\fB!=\fP"
-not equal; the result is 0 if both arguments are equal, 1 if not.
-.IP "\fB<\fP"
-less than; the result is 1 if the left argument is less than the right,
-0 if not.
-.IP "\fB<= >= >\fP"
-less than or equal, greater than or equal, greater than. See <.
-.IP "\fB<< >>\fP"
-shift left (right); the result is the left argument with its bits shifted
-left (right) by the amount given in the right argument.
-.IP "\fB+ - * /\fP"
-addition, subtraction, multiplication, and division.
-.IP "\fB%\fP"
-remainder; the result is the remainder of the division of the left argument
-by the right. The sign of the result is unspecified if either argument
-is negative.
-.IP "\fI<arg1>\fP \fB?\fP \fI<arg2>\fP \fB:\fP \fI<arg3>\fP"
-if \fI<arg1>\fP is non-zero, the result is \fI<arg2>\fP,
-otherwise \fI<arg3>\fP.
-.RE
-.\"}}}
-.\"{{{ Co-Processes
-.\"}}}
-.\"{{{ Functions
-.SS "Functions"
-Functions are defined using either Korn shell \fBfunction\fP \fIname\fP
-syntax or the Bourne/POSIX shell \fIname\fP\fB()\fP syntax
-(see below for the difference between the two forms).
-Functions are like \fB.\fP-scripts in that they are executed in
-the current environment, however, unlike \fB.\fP-scripts, shell arguments
-(\fIi.e.\fP, positional parameters, \fB$1\fP, \fIetc.\fP) are never visible
-inside them.
-When the shell is determining the location of a command, functions are
-searched after special built-in commands, and before regular and non-regular
-built-ins, and before the \fBPATH\fP is searched.
-.PP
-An existing function may be deleted using \fBunset \-f\fP \fIfunction-name\fP.
-A list of functions can be obtained using \fBtypeset +f\fP and the
-function definitions can be listed using \fBtypeset \-f\fP.
-\fBautoload\fP (which is an alias for \fBtypeset \-fu\fP) may be used to
-create undefined functions; when an undefined function is executed, the
-shell searches the path specified in the \fBFPATH\fP parameter for a file
-with the same name as the function, which, if found is read and executed.
-If after executing the file, the named function is found to be defined, the
-function is executed, otherwise, the normal command search is continued
-(\fIi.e.\fP, the shell searches the regular built-in command table
-and \fBPATH\fP).
-Note that if a command is not found using \fBPATH\fP, an attempt is
-made to autoload a function using \fBFPATH\fP (this is an undocumented
-feature of the original Korn shell).
-.PP
-Functions can have two attributes, trace and export, which can be set
-with \fBtypeset \-ft\fP and \fBtypeset \-fx\fP, respectively.
-When a traced function is executed, the shell's \fBxtrace\fP option is turned
-on for the functions duration, otherwise the \fBxtrace\fP option is turned off.
-The export attribute of functions is currently not used. In the original
-Korn shell, exported functions are visible to shell scripts that are executed.
-.PP
-Since functions are executed in the current shell environment, parameter
-assignments made inside functions are visible after the function completes.
-If this is not the desired effect, the \fBtypeset\fP command can be used
-inside a function to create a local parameter.
-Note that special parameters (\fIe.g.\fP, \fB$$\fP, \fB$!\fP) can't be
-scoped in this way.
-.PP
-The exit status of a function is that of the last command executed in
-the function.
-A function can be made to finish immediately using the \fBreturn\fP command;
-this may also be used to explicitly specify the exit status.
-.PP
-Functions defined with the \fBfunction\fP reserved word are
-treated differently in the following ways from functions defined with
-the \fB()\fP notation:
-.nr P2 \n(PD
-.nr PD 0
-.IP \ \ \(bu
-the \fB$0\fP parameter is set to the name of the function
-(Bourne-style functions leave \fB$0\fP untouched).
-.IP \ \ \(bu
-parameter assignments preceeding function calls are not kept in
-the shell environment
-(executing Bourne-style functions will keep assignments).
-.nr PD \n(P2
-In the future, the following differences will also be added:
-.nr P2 \n(PD
-.nr PD 0
-.IP \ \ \(bu
-A separate trap/signal environment will be used during the execution of
-functions.
-This will mean that traps set inside a function will not affect the shell's
-traps and signals that are not ignored in the shell (but may be trapped) will
-have their default effect in a function.
-.IP \ \ \(bu
-The EXIT trap, if set in a function, will be executed after the function
-returns.
-.nr PD \n(P2
-.\"}}}
-.\"{{{ POSIX mode
-.SS "POSIX Mode"
-The shell is intended to be POSIX compliant, however, in some cases, POSIX
-behaviour is contrary either to the original Korn shell behaviour or to
-user convenience.
-How the shell behaves in these cases is determined by the state of
-the posix option (\fBset \-o posix\fP) \(em if it is on, the POSIX behaviour
-is followed, otherwise it is not.
-The \fBposix\fP option is set automatically when the shell starts up
-if the environment contains the \fBPOSIXLY_CORRECT\fP parameter.
-(The shell can also be compiled so that it is in POSIX mode by default,
-however this is usually not desirable).
-.PP
-The following is a list of things that are affected by the state of
-the \fBposix\fP option:
-.nr P2 \n(PD
-.nr PD 0
-.IP \ \ \(bu
-reading of \fB$ENV\fP: if not in posix mode, the \fBENV\fP parameter
-is not expanded and included when the shell starts.
-.IP \ \ \(bu
-\fB\e"\fP inside double quoted \fB`\fP..\fB`\fP command substitutions:
-in posix mode, the \fB\e"\fP is interpreted when the command is interpreted;
-in non-posix mode, the backslash is stripped before the command substitution
-is interpreted. For example, \fBecho "`echo \e"hi\e"`"\fP produces `"hi"' in
-posix mode, `hi' in non-posix mode. To avoid problems, use the \fB$(...\fP)
-form of command substitution.
-.IP \ \ \(bu
-\fBkill \-l\fP output: in posix mode, signal names are listed one a single line;
-in non-posix mode, signal numbers, names and descriptions are printed in
-columns.
-In future, a new option (\fB\-v\fP perhaps) will be added to distinguish
-the two behaviours.
-.IP \ \ \(bu
-\fBfg\fP exit status: in posix mode, the exit status is 0 if no errors occur;
-in non-posix mode, the exit status is that of the last foregrounded job.
-.IP \ \ \(bu
-\fBgetopts\fP: in posix mode, options must start with a \fB\-\fP; in non-posix
-mode, options can start with either \fB\-\fP or \fB+\fP.
-.IP \ \ \(bu
-brace expansion (also known as alternation): in posix mode, brace expansion
-is disabled; in non-posix mode, brace expansion enabled.
-Note that \fBset \-o posix\fP (or setting the \fBPOSIXLY_CORRECT\fP parameter)
-automatically turns the \fBbraceexpand\fP option off, however it can be
-explicitly turned on later.
-.IP \ \ \(bu
-\fBset \-\fP: in posix mode, this does not clear the \fBverbose\fP or
-\fBxtrace\fP options; in non-posix mode, it does.
-.IP \ \ \(bu
-\fBset\fP exit status: in posix mode, the exit status of set is 0
-if there are no errors; in non-posix mode, the exit status is that of
-any command substitutions performed in generating the set command.
-For example, `\fBset \-\- `false`; echo $?\fP' prints 0 in posix mode,
-1 in non-posix mode. This construct is used in most shell scripts that
-use the old \fIgetopt\fP(1) command.
-.IP \ \ \(bu
-argument expansion of \fBalias\fP, \fBexport\fP, \fBreadonly\fP, and
-\fBtypeset\fP commands: in posix mode, normal argument expansion done;
-in non-posix mode, field splitting, file globing, brace expansion and
-(normal) tilde expansion are turned off, and assignment tilde expansion
-is turned on.
-.IP \ \ \(bu
-signal specification: in posix mode, signals can be specified as digits only
-if signal numbers match POSIX values (\fIi.e.\fP, HUP=1, INT=2, QUIT=3, ABRT=6,
-KILL=9, ALRM=14, and TERM=15); in non-posix mode, signals can be always digits.
-.IP \ \ \(bu
-alias expansion: in posix mode, alias expansion is only carried out when
-reading command words; in non-posix mode, alias expansion is carried out
-on any word following an alias that ended in a space.
-For example, the following for loop
-.RS
-.ft B
-alias a='for ' i='j'
-.br
-a i in 1 2; do echo i=$i j=$j; done
-.ft P
-.RE
-uses parameter \fBi\fP in posix mode, \fBj\fP in non-posix mode.
-.nr PD \n(P2
-.\"}}}
-.\"{{{ Command Execution (built-in commands)
-.SS "Command Execution"
-After evaluation of command line arguments, redirections and parameter
-assignments, the type of command is determined: a special built-in,
-a function, a regular built-in or the name of a file to execute found
-using the \fBPATH\fP parameter.
-The checks are made in the above order.
-Special built-in commands differ from other commands in that
-the \fBPATH\fP parameter is not used to find them, an error
-during their execution can cause a non-interactive shell to exit and
-parameter assignments that are specified before the command are
-kept after the command completes.
-Just to confuse things, if the posix option is turned off (see \fBset\fP
-command below) some special commands are very special in that
-no field splitting, file globing, brace expansion nor tilde expansion
-is preformed on arguments that look like assignments.
-Regular built-in commands are different only in that the \fBPATH\fP
-parameter is not used to find them.
-.PP
-The original ksh and POSIX differ somewhat in which commands are considered
-special or regular:
-.IP "POSIX special commands"
-.TS
-lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB .
-\&. continue exit return trap
-: eval export set unset
-break exec readonly shift
-.TE
-.IP "Additional ksh special commands"
-.TS
-lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB .
-builtin times typeset
-.TE
-.IP "Very special commands (non-posix mode)"
-.TS
-lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB .
-alias readonly set typeset
-.TE
-.IP "POSIX regular commands"
-.TS
-lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB .
-alias command fg kill umask
-bg false getopts read unalias
-cd fc jobs true wait
-.TE
-.IP "Additional ksh regular commands"
-.TS
-lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB lw(8m)fB .
-[ let pwd ulimit
-echo print test whence
-.TE
-.PP
-In the future, the additional ksh special and regular commands may
-be treated differently from the POSIX special and regular commands.
-.PP
-Once the type of the command has been determined, any command line parameter
-assignments are performed and exported for the duration of the command.
-.PP
-The following describes the special and regular built-in commands:
-.\"{{{ . file [ arg1 ... ]
-.IP "\fB\&.\fP \fIfile\fP [\fIarg1\fP ...]"
-Execute the commands in \fIfile\fP in the current environment.
-The file is searched for in the directories of \fBPATH\fP.
-If arguments are given, the positional parameters may be used to
-access them while \fIfile\fP is being executed.
-If no arguments are given, the positional parameters are those of the
-environment the command is used in.
-.\"}}}
-.\"{{{ : [ ... ]
-.IP "\fB:\fP [ ... ]"
-The null command.
-Exit status is set to zero.
-.\"}}}
-.\"{{{ alias [ -d | -t [ -r ] ] [-x] [name1[=value1] ...]
-.IP "\fBalias\fP [ \fB\-d\fP | \fB\-t\fP [\fB\-r\fP] ] [\fB\-x\fP] [\fIname1\fP[\fB=\fP\fIvalue1\fP] ...]"
-Without arguments, \fBalias\fP lists all aliases and their values. For
-any name without a value, its value is listed. Any name with a value
-defines an alias (see Aliases above).
-.sp
-The \fB\-x\fP option sets the export attribute of an alias, or, if no
-names are given, lists the aliases with the export attribute
-(exporting an alias currently has no affect).
-.sp
-The \fB\-t\fP option indicates that tracked aliases are to be listed/set
-(values specified on the command line are ignored for tracked aliases).
-The \fB\-r\fP option indicates that all tracked aliases are to be reset.
-.sp
-The \fB\-d\fP causes directory aliases, which are used in tilde expansion,
-to be listed or set (see Tilde Expansion above).
-.\"}}}
-.\"{{{ bg [job ...]
-.IP "\fBbg\fP [\fIjob\fP ...]"
-Resume the specified stopped job(s) in the background.
-If no jobs are specified, \fB%+\fP is assumed.
-This command is only available on systems which support job control.
-See Job Control below for more information.
-.\"}}}
-.\"{{{ bind [-l] [-m] [key[=editing-command] ...]
-.IP "\fBbind\fP [\fB\-m\fP] [\fIkey\fP[\fB=\fP\fIediting-command\fP] ...]"
-Set or view the current emacs command editing key bindings/macros.
-See Emacs Interactive Input Line Editing below for a complete description.
-.\"}}}
-.\"{{{ break [level]
-.IP "\fBbreak\fP [\fIlevel\fP]"
-\fBbreak\fP exits the \fIlevel\fPth inner most for, select, until, or while
-loop.
-\fIlevel\fP defaults to 1.
-.\"}}}
-.\"{{{ builtin command [arg1 ...]
-.IP "\fBbuiltin\fP \fIcommand\fP [\fIarg1\fP ...]"
-Execute the built-in command \fIcommand\fP.
-.\"}}}
-.\"{{{ cd [-LP] [dir]
-.IP "\fBcd\fP [\fB\-LP\fP] [\fIdir\fP]"
-Set the working directory to \fIdir\fP. If the parameter \fBCDPATH\fP
-is set, it lists the search path for the directory containing
-\fIdir\fP. A null path means the current directory. If \fIdir\fP is
-missing, the home directory \fB$HOME\fP is used. If \fIdir\fP is
-\fB\-\fP, the previous working directory is used (see OLDPWD parameter).
-If \fB\-L\fP option (logical path) is used or if the \fBphysical\fP option
-(see \fBset\fP command below) isn't set, references to \fB..\fP in \fIdir\fP
-are relative to the path used get to the directory.
-If \fB\-P\fP option (physical path) is used or if the \fBphysical\fP option
-is set, \fB..\fP is relative to the filesystem directory tree.
-The \fBPWD\fP and \fBOLDPWD\fP parameters are updated to reflect the
-current and old wording directory, respectively.
-.\"}}}
-.\"{{{ cd [-LP] old new
-.IP "\fBcd\fP [\fB\-LP\fP] \fIold new\fP"
-The string \fInew\fP is substituted for \fIold\fP in the current
-directory, and the shell attempts to change to the new directory.
-.\"}}}
-.\"{{{ command [ -pvV ] cmd [arg1 ...]
-.IP "\fBcommand\fP [\fB\-p\fP] \fIcmd\fP [\fIarg1\fP ...]"
-\fIcmd\fP
-is executed exactly as if the \fBcommand\fP had not been specified,
-with two exceptions: first, \fIcmd\fP cannot be a shell function, and
-second, special built-in commands lose their specialness (\fIi.e.\fP,
-redirection and utility errors do not cause the shell to exit, and command
-assignments are not permanent).
-If the \fB\-p\fP option is given, a default search path is used instead of
-the current value of \fBPATH\fP (the actual value of the default path is
-system dependent: on POSIXish systems, it is the value returned by
-.ce
-\fBgetconf CS_PATH\fP
-).
-.sp
-.\"}}}
-.\"{{{ continue [levels]
-.IP "\fBcontinue\fP [\fIlevels\fP]"
-\fBcontinue\fP jumps to the beginning of the \fIlevel\fPth inner most for,
-select, until, or while loop.
-\fIlevel\fP defaults to 1.
-.\"}}}
-.\"{{{ echo [-neE] [arg ...]
-.IP "\fBecho\fP [\fB\-neE\fP] [\fIarg\fP ...]"
-Prints its arguments (separated by spaces) followed by a newline, to
-standard out.
-The newline is suppressed if any of the arguments contain the backslash
-sequence \fB\ec\fP.
-See \fBprint\fP command below for a list of other backslash sequences
-that are recognized.
-.sp
-The options are provided for compatibility with BSD shell scripts:
-\fB\-n\fP suppresses the trailing newline, \fB\-e\fP enables backslash
-interpretation (a no-op, since this is normally done), and \fB\-E\fP which
-suppresses backslash interpretation.
-.\"}}}
-.\"{{{ eval command ...
-.IP "\fBeval\fP \fIcommand ...\fP"
-The arguments are concatenated (with spaces between them) to form
-a single string which the shell then parses and executes
-in the current environment.
-.\"}}}
-.\"{{{ exec [command [arg ...]]
-.IP "\fBexec\fP [\fIcommand\fP [\fIarg\fP ...]]"
-The command is executed without forking, replacing the shell process.
-.sp
-If no arguments are given, any IO redirection is permanent and the shell
-is not replaced.
-.\"}}}
-.\"{{{ exit [status]
-.IP "\fBexit\fP [\fIstatus\fP]"
-The shell exits with the specified exit status.
-If \fIstatus\fP is not specified, the exit status is the current
-value of the \fB?\fP parameter.
-.\"}}}
-.\"{{{ export [-p] [parameter[=value] ...]
-.IP "\fBexport\fP [\fB\-p\fP] [\fIparameter\fP[\fB=\fP\fIvalue\fP]] ..."
-Sets the export attribute of the named parameters.
-Exported parameters are passed in the environment to executed commands.
-If values are specified, the named parameters also assigned.
-.sp
-If no parameters are specified, the names of all parameters with the export
-attribute are printed one per line, unless the \fB\-p\fP option is used,
-in which case \fBexport\fP commands defining all exported
-parameters, including their values, are printed.
-.\"}}}
-.\"{{{ false
-.IP "\fBfalse\fP"
-A command that exits with a non-zero status.
-.\"}}}
-.\"{{{ fc [-e editor | -l [-n]] [-r] [first [ last ]]
-.\"}}}
-.\"{{{ fc [-e - | -s] [-g] [old=new] [prefix]
-.IP "\fBfc\fP [\fB\-e \-\fP | \fB\-s\fP] [\fB\-g\fP] [\fIold\fP\fB=\fP\fInew\fP] [\fIprefix\fP]"
-Re-execute the selected command (the previous command by default) after
-performing the optional substitution of \fIold\fP with \fInew\fP. If
-\fB\-g\fP is specified, all occurrences of \fIold\fP are replaced with
-\fInew\fP. This command is usually accessed with the predefined alias
-\fBr='fc \-e \-'\fP.
-.\"}}}
-.\"{{{ fg [job ...]
-.IP "\fBfg\fP [\fIjob\fP ...]"
-Resume the specified job(s) in the foreground.
-If no jobs are specified, \fB%+\fP is assumed.
-This command is only available on systems which support job control.
-See Job Control below for more information.
-.\"}}}
-.\"{{{ getopts optstring name [arg ...]
-.IP "\fBgetopts\fP \fIoptstring\fP \fIname\fP [\fIarg\fP ...]"
-\fBgetopts\fP is used by shell procedures to parse the specified arguments
-(or positional parameters, if no arguments are given) and to check for legal
-options.
-\fIoptstring\fP contains the option letters that
-\fBgetopts\fP is to recognize. If a letter is followed by a colon, the
-option is expected to have an argument.
-Arguments containing options must all start with either a \fB\-\fP or
-a \fB+\fP, options that do not take arguments may be grouped in a single
-argument.
-If an option takes an argument and the option character is not the last
-character of the argument it is found in, the remainder of the argument
-is taken to be the option's argument, otherwise, the next argument is
-the option's argument.
-.sp
-Each time \fBgetopts\fP is invoked, it places the next option in
-the shell parameter \fIname\fP and the index of the next argument to be
-processed in the shell parameter \fBOPTIND\fP.
-If the option was introduced with a \fB+\fP, the option placed in
-\fIname\fP is prefixed with a \fB+\fP.
-When an option requires an argument, \fBgetopts\fP places it in the
-shell parameter \fBOPTARG\fP.
-When an illegal option or a missing option argument is
-encountered a question mark or a colon is placed in \fIname\fP
-(indicating an illegal option or missing argument, respectively)
-and \fBOPTARG\fP is set to the option character that caused the problem.
-An error message is also printed to standard error if \fIoptstring\fP
-does not begin with a colon.
-.sp
-When the end of the options is encountered, \fBgetopts\fP exits with a
-non-zero exit status.
-Options end at the first (non-option argument) argument that does not
-start with a \-, or when a \fB\-\-\fP argument is encountered.
-.sp
-Option parsing can be reset by setting \fBOPTIND\fP to 1 (this is done
-automatically whenever the shell or a shell procedure is invoked).
-.sp
-Warning: Changing the value of the shell parameter \fBOPTIND\fP to
-a value other than 1, or parsing different sets of arguments without
-resetting \fBOPTIND\fP may lead to unexpected results.
-.\"}}}
-.\"{{{ hash [-r] [name ...]
-.IP "\fBhash\fP [\fB\-r\fP] [\fIname ...\fP]"
-Without arguments, any hashed executable command pathnames are listed.
-The \fB\-r\fP option causes all hashed commands to be removed
-from the hash table.
-Each \fIname\fP is searched as if it where a command name and added to the
-hash table if it is an executable command.
-.\"}}}
-.\"{{{ jobs [-lpn] [job ...]
-.IP "\fBjobs\fP [\fB\-lpn\fP] [\fIjob\fP ...]"
-Display information about the specified jobs; if no jobs are specified,
-all jobs are displayed.
-The \fB\-n\fP option causes information to be displayed only for jobs
-that have changed state since the last notification.
-If the \fB\-l\fP option is used, the process-id of each process in a job
-is also listed.
-The \fB\-p\fP option causes only the process group of each job to be printed.
-See Job Control below for the format of \fIjob\fP and the displayed job.
-.\"}}}
-.\"{{{ kill [-s signame | -signum | -signame] { job | pid | -pgrp } ...
-.IP "\fBkill\fP [\fB\-s\fP \fIsigname\fP | \fB\-signum\fP | \fB\-signame\fP ] { \fIjob\fP | \fIpid\fP | \fB\-\fP\fIpgrp\fP } ..."
-Send the specified signal to the specified jobs, process ids, or process groups.
-If no signal is specified, the signal TERM is sent.
-If a job is specified, the signal is sent to the job's process group.
-See Job Control below for the format of \fIjob\fP.
-.\"}}}
-.\"{{{ kill -l [exit-status ...]
-.IP "\fBkill \-l\fP [\fIexit-status\fP ...]"
-Print the name of the signal that killed a process which exited with
-the specified \fIexit-status\fPes.
-If no arguments are specified, a list of all the signals, their numbers and
-a short description of them are printed.
-.\"}}}
-.\"{{{ let [expression ...]
-.\"}}}
-.\"{{{ print [-nprsun | -R [-en]] [argument ...]
-.IP "\fBprint\fP [\fB\-nprsu\fP\fIn\fP | \fB\-R\fP [\fB\-en\fP]] [\fIargument ...\fP]"
-\fBPrint\fP prints its arguments on the standard output, separated by
-spaces, and terminated with a newline. The \fB\-n\fP option suppresses
-the newline. By default, certain C escapes are translated. These
-include \eb, \ef, \en, \er, \et, \ev, and \e0### (# is an octal digit, of
-which there may be 0 to 3).
-\ec is equivalent to using the \fB\-n\fP option. \e expansion may be
-inhibited with the \fB\-r\fP option.
-The \fB\-s\fP option prints to the history file instead of standard output,
-the \fB\-u\fP option prints to file descriptor \fIn\fP (\fIn\fP
-defaults to 1 if omitted), and the \fB\-p\fP option prints to the co-process
-(see Co-Processes above).
-.sp
-The \fB\-R\fP option is used to emulate, to some degree, the BSD echo
-command, which does not process \e sequences unless the \fB\-e\fP option
-is given.
-As above, the \fB\-n\fP option suppresses the trailing newline.
-.\"}}}
-.\"{{{ pwd [-LP]
-.IP "\fBpwd\fP [\fB\-LP\fP]"
-Print the present working directory.
-If \fB\-L\fP option is used or if the \fBphysical\fP option
-(see \fBset\fP command below) isn't set, the logical path is printed
-(\fIi.e.\fP, the path used to \fBcd\fP to the current directory).
-If \fB\-P\fP option (physical path) is used or if the \fBphysical\fP option
-is set, the path determined from the filesystem (by following \fB..\fP
-directories to the root directory) is printed.
-.\"}}}
-.\"{{{ read [-prsun] [parameter ...]
-.IP "\fBread\fP [\fB\-prsu\fP\fIn\fP] [\fIparameter ...\fP]"
-Reads a line of input from standard input, separate the line into fields using
-the \fBIFS\fP parameter (see Substitution above), and assign each field to the
-specified parameters.
-If there are more parameters than fields, the extra parameters are set to null,
-or alternatively, if there are more fields than parameters, the last parameter
-is assigned the remaining fields (inclusive of any separating spaces).
-If no parameters are specified, the \fBREPLY\fP parameter is used.
-If the input line ends in a backslash and the \fB\-r\fP option was not used, the
-backslash and newline are stripped and more input is read.
-If no input is read, \fBread\fP exits with a non-zero status.
-.sp
-The first parameter may have a question mark and a string appended to it, in
-which case the string is used as a prompt (printed to standard error before
-any input is read) if the input is a tty
-(\fIe.g.\fP, \fBread nfoo?'number of foos: '\fP).
-.sp
-The \fB\-u\fP\fIn\fP and \fB\-p\fP options cause input to be read
-from file descriptor \fIn\fP or the current co-process (see Co-Processes above
-for comments on this), respectively.
-If the \fB\-s\fP option is used, input is saved to the history file.
-.\"}}}
-.\"{{{ readonly [-p] [parameter[=value] ...]
-.IP "\fBreadonly\fP [\fB\-p\fP] [\fIparameter\fP[\fB=\fP\fIvalue\fP]] ..."
-Sets the readonly attribute of the named parameters. If values are given,
-parameters are set to them before setting the attribute.
-Once a parameter is made readonly, it cannot be unset and its value cannot
-be changed.
-.sp
-If no parameters are specified, the names of all parameters with the readonly
-attribute are printed one per line, unless the \fB\-p\fP option is used,
-in which case \fBreadonly\fP commands defining all readonly
-parameters, including their values, are printed.
-.\"}}}
-.\"{{{ return [status]
-.IP "\fBreturn\fP [\fIstatus\fP]"
-Returns from a function or \fB.\fP script, with exit status \fIstatus\fP.
-If no \fIstatus\fP is given, the exit status of the last executed command
-is used.
-If used outside of a function or \fB.\fP script, it has the same effect
-as \fBexit\fP.
-Note that pdksh treats both profile and \fB$ENV\fP files as \fB.\fP scripts,
-while the original Korn shell only treats profiles as \fB.\fP scripts.
-.\"}}}
-.\"{{{ set [+-abCefhkmnpsuvxX] [+-o [option]] [+-A name] [--] [arg ...]
-.IP "\fBset\fP [\fB\(+-abCefhkmnpsuvxX\fP] [\fB\(+-o\fP [\fIoption\fP]] [\fB\(+-A\fP \fIname\fP] [\fB\-\-\fP] [\fIarg\fP ...]"
-The set command can be used to set (\fB\-\fP) or clear (\fB+\fP) shell options,
-set the positional parameters, or set an array parameter.
-Options can be changed using the \fB\(+-o\fP \fIoption\fP syntax,
-where \fIoption\fP is the long name of an option, or using
-the \fB\(+-\fP\fIletter\fP syntax, where \fIletter\fP is the
-option's single letter name (not all options have a single letter name).
-The following table lists both option letters (if they exist) and long names
-along with a description of what the option does.
-.sp
-.TS
-expand;
-afB lfB lw(3i).
-\-A T{
-Sets the elements of the array parameter \fIname\fP to \fIarg\fP ...;
-If \fB\-A\fP is used, the array is reset (\fIi.e.\fP, emptied) first;
-if \fB+A\fP is used, the first N elements are set (where N is the number
-of \fIarg\fPs), the rest are left untouched.
-T}
-\-a allexport T{
-all new parameters are created with the export attribute
-T}
-\-b notify T{
-Print job notification messages asynchronously, instead of just before the
-prompt.
-Only used if job control is enabled (\fB\-m\fP).
-T}
-\-C noclobber T{
-Prevent \fB>\fP redirection from overwriting existing files (\fB>|\fP must
-be used to force an overwrite).
-T}
-\-e errexit T{
-Exit (after executing the \fBERR\fP trap) as soon as an error occurs or
-a command fails (\fIi.e.\fP, exits with a non-zero status).
-This does not apply to commands whose exit status is explicitly tested by a
-shell construct such as \fBif\fP, \fBuntil\fP, \fBwhile\fP, \fB&&\fP or
-\fB||\fP statements.
-T}
-\-f noglob T{
-Do not expand file name patterns.
-T}
-\-h trackall T{
-Create tracked aliases for all executed commands (see Aliases above).
-On by default for non-interactive shells.
-T}
-\-i interactive T{
-Enable interactive mode \- this can only be set/unset when the shell is
-invoked.
-T}
-\-k keyword T{
-Parameter assignments are recognized anywhere in a command.
-T}
-\-l login T{
-The shell is a login shell \- this can only be set/unset when the shell is
-invoked (see Shell Startup above).
-T}
-\-m monitor T{
-Enable job control (default for interactive shells).
-T}
-\-n noexec T{
-Do not execute any commands \- useful for checking the syntax of scripts
-(ignored if interactive).
-T}
-\-p privileged T{
-Set automatically if, when the shell starts, the read uid or gid does not
-match the effective uid or gid, respectively.
-See Shell Startup above for a description of what this
-means.
-T}
--r restricted T{
-Enable restricted mode \(em this option can only be used when the shell is
-invoked. See Shell Startup above for a description of what this
-means.
-T}
-\-s stdin T{
-If used when the shell is invoked, commands are read from standard input.
-Set automatically if the shell is invoked with no arguments.
-.sp
-When \fB\-s\fP is used in the \fBset\fP command, it causes the specified
-arguments to be sorted before assigning them to the positional parameters
-(or to array \fIname\fP, if \fB\-A\fP is used).
-T}
-\-u nounset T{
-Referencing of an unset parameter is treated as an error, unless
-one of the \fB\-\fP, \fB+\fP or \fB=\fP modifiers is used.
-T}
-\-v verbose T{
-Write shell input to standard error as it is read.
-T}
-\-x xtrace T{
-Print commands and parameter assignments when they are executed,
-preceded by the value of \fBPS4\fP.
-T}
-\-X markdirs T{
-Mark directories with a trailing \fB/\fP during file name generation.
-T}
- bgnice T{
-Background jobs are run with lower priority.
-T}
- ignoreeof T{
-The shell will not exit on when end-of-file is read, \fBexit\fP must be used.
-T}
- nohup T{
-Do not kill running jobs with a \fBHUP\fP signal when a login shell exists.
-Currently set by default, but this will change in the future to be compatible
-with the original Korn shell (which doesn't have this option, but does
-send the \fBHUP\fP signal).
-T}
- nolog T{
-No effect \- in the original Korn shell, this prevents function definitions
-from being stored in the history file.
-T}
- physical T{
-Causes the \fBcd\fP and \fBpwd\fP commands to use `physical'
-(\fIi.e.\fP, the filesystem's) \fB..\fP directories instead of `logical'
-directories (\fIi.e.\fP, the shell handles \fB..\fP, which allows the user
-to be obliveous of symlink links to directories).
-Clear by default. Note that setting
-this option does not effect the current value of the \fBPWD\fP parameter;
-only the \fBcd\fP command changes \fBPWD\fP.
-See the \fBcd\fP and \fBpwd\fP commands above for more details.
-T}
- posix T{
-Enable posix mode. See POSIX Mode above.
-T}
- vi T{
-Enable vi-like command line editing (interactive shells only).
-T}
- viraw T{
-No effect \- in the original Korn shell, unless viraw was set, the vi command
-line mode would let the tty driver do the work until ESC (^[) was entered.
-pdksh is always in viraw mode.
-T}
- vi-esccomplete T{
-In vi command line editing, do command / file name completion when
-escape (^[) is entered in command mode.
-T}
- vi-show8 T{
-Prefix characters with the eighth bit set with `M-'.
-If this option is not set, characters in the range
-128-160 are printed as is, which may cause problems.
-T}
- vi-tabcomplete T{
-In vi command line editing, do command / file name completion when
-tab (^I) is entered in insert mode.
-T}
-.TE
-.sp
-These options can also be used upon invocation of the shell. The current
-set of options (with single letter names) can be found in the
-parameter \fB\-\fP.
-\fBset -o\fP with no option name will list all the options and whether each
-is on or off; \fBset +o\fP will print the long names of all options that
-are currently on.
-.sp
-Remaining arguments, if any, are positional parameters and are assigned,
-in order, to the
-positional parameters (\fIi.e.\fP, \fB1\fP, \fB2\fP, \fIetc.\fP).
-If options are ended with \fB\-\-\fP and there are no remaining arguments,
-all positional parameters are cleared.
-If no options or arguments are given, then the values of all names are printed.
-For unknown historical reasons, a lone \fB\-\fP option is treated specially:
-it clears both the \fB\-x\fP and \fB\-v\fP options.
-.\"}}}
-.\"{{{ shift [number]
-.IP "\fBshift\fP [\fInumber\fP]"
-The positional parameters \fInumber\fP+1, \fInumber\fP+2 \fIetc.\fP\& are
-renamed to \fB1\fP, \fB2\fP, \fIetc.\fP
-\fInumber\fP defaults to 1.
-.\"}}}
-.\"{{{ test expression, [ expression ]
-.IP "\fBtest\fP \fIexpression\fP"
-.IP "\fB[\fP \fIexpression\fP \fB]\fP"
-\fBtest\fP evaluates the \fIexpression\fP and returns zero status if
-true, and 1 status if false and greater than 1 if there was an error.
-It is normally used as the
-condition command of \fBif\fP and \fBwhile\fP statements.
-The following basic expressions are available:
-.sp
-.TS
-afB ltw(2.8i).
-\fIstr\fP T{
-\fIstr\fP has non-zero length. Note that there is the potential
-for problems if \fIstr\fP turns out to be an operator (\fIe.g.\fP, \fB-r\fP)
-- it is generally better to use a test like
-.RS
-\fB[ X"\fP\fIstr\fP\fB" != X ]\fP
-.RE
-instead (double quotes are used in case \fIstr\fP contains spaces or file
-globing characters).
-T}
-\-r \fIfile\fP T{
-\fIfile\fP exists and is readable
-T}
-\-w \fIfile\fP T{
-\fIfile\fP exists and is writable
-T}
-\-x \fIfile\fP T{
-\fIfile\fP exists and is executable
-T}
-\-a \fIfile\fP T{
-\fIfile\fP exists
-T}
-\-e \fIfile\fP T{
-\fIfile\fP exists
-T}
-\-f \fIfile\fP T{
-\fIfile\fP is a regular file
-T}
-\-d \fIfile\fP T{
-\fIfile\fP is a directory
-T}
-\-c \fIfile\fP T{
-\fIfile\fP is a character special device
-T}
-\-b \fIfile\fP T{
-\fIfile\fP is a block special device
-T}
-\-p \fIfile\fP T{
-\fIfile\fP is a named pipe
-T}
-\-u \fIfile\fP T{
-\fIfile\fP's mode has setuid bit set
-T}
-\-g \fIfile\fP T{
-\fIfile\fP's mode has setgid bit set
-T}
-\-k \fIfile\fP T{
-\fIfile\fP's mode has sticky bit set
-T}
-\-s \fIfile\fP T{
-\fIfile\fP is not empty
-T}
-\-O \fIfile\fP T{
-\fIfile\fP's owner is the shell's effective user-ID
-T}
-\-G \fIfile\fP T{
-\fIfile\fP's group is the shell's effective group-ID
-T}
-\-h \fIfile\fP T{
-\fIfile\fP is a symbolic link
-T}
-\-H \fIfile\fP T{
-\fIfile\fP is a context dependent directory (only useful on HP-UX)
-T}
-\-L \fIfile\fP T{
-\fIfile\fP is a symbolic link
-T}
-\-S \fIfile\fP T{
-\fIfile\fP is a socket
-T}
-\-o \fIoption\fP T{
-shell \fIoption\fP is set (see \fBset\fP command above for list of options).
-As a non-standard extension, if the option starts with a \fB!\fP, the test
-is negated; the test always fails if option doesn't exist (thus
-.RS
-\fB[ -o \fP\fIfoo\fP \fB-o -o !\fP\fIfoo\fP \fB]\fP
-.RE
-returns true if and only if option \fIfoo\fP exists).
-T}
-\fIfile\fP \-nt \fIfile\fP T{
-first \fIfile\fP is newer than second \fIfile\fP
-T}
-\fIfile\fP \-ot \fIfile\fP T{
-first \fIfile\fP is older than second \fIfile\fP
-T}
-\fIfile\fP \-ef \fIfile\fP T{
-first \fIfile\fP is the same file as second \fIfile\fP
-T}
-\-t [\fIfd\fP] T{
-file descriptor is a tty device.
-Default value of \fIfd\fP is 1.
-T}
-\fIstring\fP T{
-\fIstring\fP is not empty
-T}
-\-z \fIstring\fP T{
-\fIstring\fP is empty
-T}
-\-n \fIstring\fP T{
-\fIstring\fP is not empty
-T}
-\fIstring\fP = \fIstring\fP T{
-strings are equal
-T}
-\fIstring\fP != \fIstring\fP T{
-strings are not equal
-T}
-\fInumber\fP \-eq \fInumber\fP T{
-numbers compare equal
-T}
-\fInumber\fP \-ne \fInumber\fP T{
-numbers compare not equal
-T}
-\fInumber\fP \-ge \fInumber\fP T{
-numbers compare greater than or equal
-T}
-\fInumber\fP \-gt \fInumber\fP T{
-numbers compare greater than
-T}
-\fInumber\fP \-le \fInumber\fP T{
-numbers compare less than or equal
-T}
-\fInumber\fP \-lt \fInumber\fP T{
-numbers compare less than
-T}
-.TE
-.sp
-The above basic expressions, in which unary operators have precedence over
-binary operators, may be combined with the following operators
-(listed in increasing order of precedence):
-.sp
-.TS
-afB l.
-\fIexpr\fP \-o \fIexpr\fP logical or
-\fIexpr\fP \-a \fIexpr\fP logical and
-! \fIexpr\fP logical not
-( \fIexpr\fP ) grouping
-.TE
-.sp
-On operating systems not supporting \fB/dev/fd/\fP\fIn\fP devices
-(where \fIn\fP is a file descriptor number),
-the \fBtest\fP command will attempt to fake it for all tests that
-operate on files (except the \fB-e\fP test).
-I.e., \fB[ -w /dev/fd/2 ]\fP tests if file descriptor 2 is writable.
-.sp
-Note that some special rules are applied (courtesy of POSIX) if the
-number of arguments to \fBtest\fP or \fB[\fP \&... \fB]\fP is less than
-five: if leading \fB!\fP arguments can be stripped such that only one
-argument remains then a string length test is performed (again, even if
-the argument is a unary operator);
-if leading \fB!\fP arguments can be stripped such that three
-arguments remain and the second argument is a binary operator, then the
-binary operation is performed (even if first argument is a unary
-operator, including an unstripped \fB!\fP).
-.sp
-\fBNote:\fP A common mistake is to use \fBif [ $foo = bar ]\fP which
-fails if parameter \fBfoo\fP is null or unset, if it has embedded spaces
-(\fIi.e.\fP, \fBIFS\fP characters), or if it is a unary operator like \fB!\fP or
-\fB\-n\fP. Use tests like \fBif [ "X$foo" = Xbar ]\fP instead.
-.\"}}}
-.\"{{{ times
-.IP \fBtimes\fP
-Print the accumulated user and system times used by the shell and by
-processes which have exited that the shell started.
-.\"}}}
-.\"{{{ trap [handler signal ...]
-.IP "\fBtrap\fP [\fIhandler\fP \fIsignal ...\fP]"
-Sets trap handler that is to be executed when any of the specified signals
-are received.
-\fBHandler\fP is either a null string, indicating the signals are to
-be ignored, a minus (\fB\-\fP), indicating that the default action is to
-be taken for the signals (see signal(2 or 3)), or a string containing shell
-commands to be evaluated and executed at the first opportunity (\fIi.e.\fP,
-when the current command completes, or before printing the next \fBPS1\fP
-prompt) after receipt of one of the signals.
-\fBSignal\fP is the name of a signal (\fIe.g.\fP, PIPE or ALRM) or the number
-of the signal (see \fBkill \-l\fP command above).
-There are two special signals: \fBEXIT\fP (also known as \fB0\fP), which
-is executed when the shell is about to exit, and \fBERR\fP which is
-executed after an error occurs (an error is something that would cause
-the shell to exit if the \fB\-e\fP or \fBerrexit\fP option were set \(em
-see \fBset\fP command above).
-\fBEXIT\fP handlers are executed in the environment of the last executed
-command.
-Note that for non-interactive shells, the trap handler cannot be changed for
-signals that were ignored when the shell started.
-.sp
-With no arguments, \fBtrap\fP lists, as a series of \fBtrap\fP commands,
-the current state of the traps that have been set since the shell started.
-.sp
-.\" todo: add these features (trap DEBUG, trap ERR/EXIT in function)
-The original Korn shell's \fBDEBUG\fP trap and the handling of \fBERR\fP and
-\fBEXIT\fP traps in functions are not yet implemented.
-.\"}}}
-.\"{{{ true
-.IP \fBtrue\fP
-A command that exits with a zero value.
-.\"}}}
-.\"{{{ typeset [[+-Ulrtux] [-L[n]] [-R[n]] [-Z[n]] [-i[n]] | -f [-tux]] [name[=value] ...]
-.IP "\fBtypeset\fP [[\(+-Ulrtux] [\fB\-L\fP[\fIn\fP]] [\fB\-R\fP[\fIn\fP]] [\fB\-Z\fP[\fIn\fP]] [\fB\-i\fP[\fIn\fP]] | \fB\-f\fP [\fB\-tux\fP]] [\fIname\fP[\fB=\fP\fIvalue\fP] ...]"
-Display or set parameter attributes.
-With no \fIname\fP arguments, parameter attributes are displayed: if no options
-arg used, the current attributes of all parameters are printed as typeset
-commands; if an option is given (or \fB\-\fP with no option letter)
-all parameters and their values with the specified attributes are printed;
-if options are introduced with \fB+\fP, parameter values are not printed.
-.sp
-If \fIname\fP arguments are given, the attributes of the named parameters
-are set (\fB\-\fP) or cleared (\fB+\fP).
-Values for parameters may optionally be specified.
-If typeset is used inside a function, any newly created parameters are local
-to the function.
-.sp
-When \fB\-f\fP is used, typeset operates on the attributes of functions.
-As with parameters, if no \fIname\fPs are given, functions are listed
-with their values (\fIi.e.\fP, definitions) unless options are introduced with
-\fB+\fP, in which case only the function names are reported.
-.sp
-.TS
-expand;
-afB lw(4.5i).
-\-L\fIn\fP T{
-Left justify attribute: \fIn\fP specifies the field width.
-If \fIn\fP is not specified, the current width of a parameter (or the
-width of its first assigned value) is used.
-Leading white space (and zeros, if used with the \fB\-Z\fP option) is stripped.
-If necessary, values are either truncated or space padded to fit the
-field width.
-T}
-\-R\fIn\fP T{
-Right justify attribute: \fIn\fP specifies the field width.
-If \fIn\fP is not specified, the current width of a parameter (or the
-width of its first assigned value) is used.
-Trailing white space are stripped.
-If necessary, values are either stripped of leading characters
-or space padded to make them fit the field width.
-T}
-\-Z\fIn\fP T{
-Zero fill attribute: if not combined with \fB\-L\fP, this is the
-same as \fB\-R\fP, except zero padding is used instead of space padding.
-T}
-\-i\fIn\fP T{
-integer attribute:
-\fIn\fP specifies the base to use when displaying the integer
-(if not specified, the base given in the first assignment is used).
-Parameters with this attribute may be assigned values containing
-arithmetic expressions.
-T}
-\-U T{
-unsigned integer attribute: integers are printed as unsigned values
-(only useful when combined with the \fB\-i\fP option).
-This option is not in the original Korn shell.
-T}
-\-f T{
-Function mode: display or set functions and their attributes, instead of
-parameters.
-T}
-\-l T{
-Lower case attribute: all upper case characters in values are converted to
-lower case.
-(In the original Korn shell, this parameter meant `long integer' when used
-with the \fB\-i\fP option).
-T}
-\-r T{
-Readonly attribute: parameters with the this attribute may not be assigned to
-or unset.
-Once this attribute is set, it can not be turned off.
-T}
-\-t T{
-Tag attribute: has no meaning to the shell; provided for application use.
-.sp
-For functions, \fB\-t\fP is the trace attribute.
-When functions with the trace attribute are executed, the \fBxtrace\fP (\fB\-x\fP) shell option is temporarily turned on.
-T}
-\-u T{
-Upper case attribute: all lower case characters in values are converted to
-upper case.
-(In the original Korn shell, this parameter meant `unsigned integer' when used
-with the \fB\-i\fP option, which meant upper case letters would never be used
-for bases greater than 10. See the \fB\-U\fP option).
-.sp
-For functions, \fB\-u\fP is the undefined attribute. See Functions above
-for the implications of this.
-T}
-\-x T{
-Export attribute: parameters (or functions) are placed in the environment of
-any executed commands. Exported functions are not implemented yet.
-T}
-.TE
-.\"}}}
-.\"{{{ ulimit [-acdfHlmnpsStvw] [value]
-.IP "\fBulimit\fP [\fB\-acdfHlmnpsStvw\fP] [\fIvalue\fP]"
-Display or set process limits.
-If no options are used, the file size limit (\fB\-f\fP) is assumed.
-\fBvalue\fP, if specified, may be either be an arithmetic expression or the
-word \fBunlimited\fP.
-The limits affect the shell and any processes created by the shell after
-a limit is imposed.
-Note that some systems may not allow limits to be increased once they
-are set.
-Also note that the types of limits available are system dependent \- some
-systems have only the \fB\-f\fP limit.
-.RS
-.IP \fB\-a\fP
-Displays all limits; unless \fB\-H\fP is used, soft limits are displayed.
-.IP \fB\-H\fP
-Set the hard limit only (default is to set both hard and soft limits).
-.IP \fB\-S\fP
-Set the soft limit only (default is to set both hard and soft limits).
-.IP \fB\-c\fP
-Impose a size limit of \fIn\fP blocks on the size of core dumps.
-.IP \fB\-d\fP
-Impose a size limit of \fIn\fP kbytes on the size of the data area.
-.IP \fB\-f\fP
-Impose a size limit of \fIn\fP blocks on files written by the shell and
-its child processes (files of any size may be read).
-.IP \fB\-l\fP
-Impose a limit of \fIn\fP kbytes on the amount of locked (wired) physical
-memory.
-.IP \fB\-m\fP
-Impose a limit of \fIn\fP kbytes on the amount of physical memory used.
-.IP \fB\-n\fP
-Impose a limit of \fIn\fP file descriptors that can be open at once.
-.IP \fB\-p\fP
-Impose a limit of \fIn\fP processes that can be run by the user at any one
-time.
-.IP \fB\-s\fP
-Impose a size limit of \fIn\fP kbytes on the size of the stack area.
-.IP \fB\-t\fP
-Impose a time limit of \fIn\fP cpu seconds to be used by each process.
-.IP \fB\-v\fP
-Impose a limit of \fIn\fP kbytes on the amount of virtual memory used;
-on some systems this is the maximum allowable virtual address (in bytes,
-not kbytes).
-.IP \fB\-w\fP
-Impose a limit of \fIn\fP kbytes on the amount of swap space used.
-.PP
-As far as \fBulimit\fP is concerned, a block is 512 bytes.
-.RE
-.\"}}}
-.\"{{{ umask [-S] [mask]
-.IP "\fBumask\fP [\fB\-S\fP] [\fImask\fP]"
-.RS
-Display or set the file permission creation mask, or umask (see \fIumask\fP(2)).
-If the \fB\-S\fP option is used, the mask displayed or set is symbolic,
-otherwise it is an octal number.
-.sp
-Symbolic masks are like those used by \fIchmod\fP(1):
-.RS
-[\fBugoa\fP]{{\fB=+-\fP}{\fBrwx\fP}*}+[\fB,\fP...]
-.RE
-in which the first group of characters is the \fIwho\fP part, the second
-group is the \fIop\fP part, and the last group is the \fIperm\fP part.
-The \fIwho\fP part specifies which part of the umask is to be modified.
-The letters mean:
-.RS
-.IP \fBu\fP
-the user permissions
-.IP \fBg\fP
-the group permissions
-.IP \fBo\fP
-the other permissions (non-user, non-group)
-.IP \fBa\fP
-all permissions (user, group and other)
-.RE
-.sp
-The \fIop\fP part indicates how the \fIwho\fP permissions are to be modified:
-.RS
-.IP \fB=\fP
-set
-.IP \fB+\fP
-added to
-.IP \fB\-\fP
-removed from
-.RE
-.sp
-The \fIperm\fP part specifies which permissions are to be set, added or removed:
-.RS
-.IP \fBr\fP
-read permission
-.IP \fBw\fP
-write permission
-.IP \fBx\fP
-execute permission
-.RE
-.sp
-When symbolic masks are used, they describe what permissions may
-be made available (as opposed to octal masks in which a set bit means
-the corresponding bit is to be cleared).
-Example: `ug=rwx,o=' sets the mask so files will not be readable, writable
-or executable by `others', and is equivalent (on most systems) to the octal
-mask `07'.
-.RE
-.\"}}}
-.\"{{{ unalias [-adt] name ...
-.IP "\fBunalias\fP [\fB\-adt\fP] [\fIname1\fP ...]"
-The aliases for the given names are removed.
-If the \fB\-a\fP option is used, all aliases are removed.
-If the \fB\-t\fP or \fB\-d\fP options are used, the indicated operations
-are carried out on tracked or directory aliases, respectively.
-.\"}}}
-.\"{{{ unset [-fv] parameter ...
-.IP "\fBunset\fP [\fB\-fv\fP] \fIparameter\fP ..."
-Unset the named parameters (\fB\-v\fP, the default) or functions (\fB\-f\fP).
-The exit status is non-zero if any of the parameters were already unset,
-zero otherwise.
-.\"}}}
-.\"{{{ wait [job]
-.IP "\fBwait\fP [\fIjob\fP]"
-Wait for the specified job(s) to finish.
-The exit status of wait is that of the last specified job:
-if the last job is killed by a signal, the exit status is 128 + the
-number of the signal (see \fBkill \-l\fP \fIexit-status\fP above); if the last
-specified job can't be found (because it never existed, or had already
-finished), the exit status of wait is 127.
-See Job Control below for the format of \fIjob\fP.
-\fBWait\fP will return if a signal for which a trap has been set is received,
-or if a HUP, INT or QUIT signal is received.
-.sp
-If no jobs are specified, \fBwait\fP waits for all currently running jobs
-(if any) to finish and exits with a zero status.
-If job monitoring is enabled, the completion status of jobs is
-printed (this is not the case when jobs are explicitly specified).
-.\"}}}
-.\"{{{ whence [-pv] [name ...]
-.IP "\fBwhence\fP [\fB\-pv\fP] [name ...]"
-For each name, the type of command is listed (reserved word, built-in, alias,
-function, tracked alias or executable).
-If the \fB\-p\fP option is used, a path search done even if \fIname\fP
-is a reserved word, alias, \fIetc.\fP
-Without the \fB\-v\fP option, \fBwhence\fP is similar to \fBcommand \-v\fP
-except that \fBwhence\fP will find reserved words and won't print aliases
-as alias commands;
-with the \fB\-v\fP option, \fBwhence\fP is the same as \fBcommand \-V\fP.
-Note that for \fBwhence\fP, the \fB\-p\fP option does not affect the search
-path used, as it does for \fBcommand\fP.
-If the type of one or more of the names could not be determined, the
-exit status is non-zero.
-.\"}}}
-.\"}}}
-.\"{{{ job control (and its built-in commands)
-.SS "Job Control"
-Job control refers to the shell's ability to monitor and control \fBjobs\fP,
-which are processes or groups of processes created for commands or pipelines.
-At a minimum, the shell keeps track of the status of the background
-(\fIi.e.\fP, asynchronous) jobs that currently exist; this information can be
-displayed using the \fBjobs\fP command.
-If job control is fully enabled (using \fBset \-m\fP or
-\fBset \-o monitor\fP), as it is for interactive shells,
-the processes of a job are placed in their own process group,
-foreground jobs can be stopped by typing the suspend character from the
-terminal (normally ^Z),
-jobs can be restarted in either the foreground
-or background, using the \fBfg\fP and \fBbg\fP commands, respectively,
-and the state of the terminal is saved or restored when a foreground
-job is stopped or restarted, respectively.
-.sp
-Note that only commands that create processes (\fIe.g.\fP,
-asynchronous commands, subshell commands, and non-built-in,
-non-function commands) can be stopped; commands like \fBread\fP cannot be.
-.sp
-When a job is created, it is assigned a job-number.
-For interactive shells, this number is printed inside \fB[\fP..\fB]\fP,
-followed by the process-ids of the processes in the job when an asynchronous
-command is run.
-A job may be referred to in \fBbg\fP, \fBfg\fP, \fBjobs\fP, \fBkill\fP and
-\fBwait\fP commands either by the process id of the last process in the
-command pipeline (as stored in the \fB$!\fP parameter) or by prefixing the
-job-number with a percent sign (\fB%\fP).
-Other percent sequences can also be used to refer to jobs:
-.sp
-.TS
-expand;
-afB lw(4.5i).
-%+ T{
-The most recently stopped job, or, if there are no stopped jobs, the oldest
-running job.
-T}
-%%\fR, \fP% T{
-Same as \fB%+\fP.
-T}
-%\- T{
-The job that would be the \fB%+\fP job, if the later did not exist.
-T}
-%\fIn\fP T{
-The job with job-number \fIn\fP.
-T}
-%?\fIstring\fP T{
-The job containing the string \fIstring\fP (an error occurs if multiple jobs
-are matched).
-T}
-%\fIstring\fP T{
-The job starting with string \fIstring\fP (an error occurs if multiple jobs
-are matched).
-T}
-.TE
-.sp
-When a job changes state (\fIe.g.\fP, a background job finishes or foreground
-job is stopped), the shell prints the following status information:
-.RS
-\fB[\fP\fInumber\fP\fB]\fP \fIflag status command\fP
-.RE
-where
-.IP "\ \fInumber\fP"
-is the job-number of the job.
-.IP "\ \fIflag\fP"
-is \fB+\fP or \fB-\fP if the job is the \fB%+\fP or \fB%-\fP job,
-respectively, or space if it is neither.
-.IP "\ \fIstatus\fP"
-indicates the current state of the job and can be
-.RS
-.IP "\fBRunning\fP"
-the job has neither stopped or exited (note that running does not
-necessarily mean consuming CPU time \(em the process could be blocked waiting
-for some event).
-.IP "\fBDone\fP [\fB(\fP\fInumber\fP\fB)\fP]"
-the job exited. \fInumber\fP is the exit status of the job, which is
-omitted if the status is zero.
-.IP "\fBStopped\fP [\fB(\fP\fIsignal\fP\fB)\fP]"
-the job was stopped by the indicated \fIsignal\fP (if no signal is given,
-the job was stopped by SIGTSTP).
-.IP "\fIsignal-description\fP [\fB(core dumped)\fP]"
-the job was killed by a signal (\fIe.g.\fP, Memory\ fault,
-Hangup, \fIetc.\fP \(em use
-\fBkill \-l\fP for a list of signal descriptions).
-The \fB(core\ dumped)\fP message indicates the process created a core file.
-.RE
-.IP "\ \fIcommand\fP"
-is the command that created the process.
-If there are multiple processes in the job, then each process will
-have a line showing its \fIcommand\fP and possibly its \fIstatus\fP,
-if it is different from the status of the previous process.
-.PP
-When an attempt is made to exit the shell while there are jobs in
-the stopped state, the shell warns the user that there are stopped jobs
-and does not exit.
-If another attempt is immediately made to exit the shell, the stopped
-jobs are sent a \fBHUP\fP signal and the shell exits.
-Similarly, if the \fBnohup\fP option is not set and there are running
-jobs when an attempt is made to exit a login shell, the shell warns the
-user and does not exit.
-If another attempt is immediately made to exit the shell, the running
-jobs are sent a \fBHUP\fP signal and the shell exits.
-.\"}}}
-.\"{{{ Emacs Interactive Input Line Editing
-.\"}}}
-.\"{{{ Vi Interactive Input Line Editing
-.\"}}}
-.\"}}}
-.\"{{{ Files
-.SH FILES
-~/.profile
-.br
-/etc/profile
-.br
-/etc/suid_profile
-.\"}}}
-.\"{{{ Notes
-.SH NOTES
-Sh is implemented as a runtime option of pdksh, with only those ksh features
-whose syntax or semantics are incompatible with a traditional Bourne
-shell disabled. Since this leaves some ksh extensions exposed, caution
-should be used where backwards compatibility with traditional Bourne or
-POSIX compliant shells is an issue.
-.\"}}}
-.\"{{{ Bugs
-.SH BUGS
-Any bugs in pdksh should be reported to pdksh@cs.mun.ca. Please
-include the version of pdksh (echo $KSH_VERSION shows it), the machine,
-operating system and compiler you are using and a description of how to
-repeat the bug (a small shell script that demonstrates the bug is
-best). The following, if relevant (if you are not sure, include them),
-can also helpful: options you are using (both options.h options and set
-\-o options) and a copy of your config.h (the file generated by the
-configure script). New versions of pdksh can be obtained from
-ftp.cs.mun.ca:pub/pdksh/.
-.\"}}}
-.\"{{{ Authors
-.SH AUTHORS
-This shell is based on the public domain 7th edition Bourne shell clone by
-Charles Forsyth and parts of the BRL shell by Doug A.\& Gwyn, Doug Kingston,
-Ron Natalie, Arnold Robbins, Lou Salkind and others. The first release
-was created by Eric Gisin, and it was subsequently maintained by
-John R.\& MacMillan (chance!john@sq.sq.com), and
-Simon J.\& Gerraty (sjg@zen.void.oz.au). The current maintainer is
-Michael Rendell (michael@cs.mun.ca).
-The CONTRIBUTORS file in the source distribution contains a more complete
-list of people and their part in the shell's development.
-.\"}}}
-.\"{{{ See also
-.SH "SEE ALSO"
-awk(1),
-ksh(1),
-csh(1), ed(1), getconf(1), getopt(1), sed(1), stty(1), vi(1),
-dup(2), execve(2), getgid(2), getuid(2), open(2), pipe(2), wait(2),
-getopt(3), rand(3), signal(3), system(3),
-environ(5)
-.PP
-.IR "The KornShell Command and Programming Language" ,
-Morris Bolsky and David Korn, 1989, ISBN 0-13-516972-0.
-.PP
-.\" XXX ISBN missing
-.IR "UNIX Shell Programming" ,
-Stephen G.\& Kochan, Patrick H.\& Wood, Hayden.
-.PP
-.IR "IEEE Standard for information Technology \- Portable Operating System Interface (POSIX) \- Part 2: Shell and Utilities" ,
-IEEE Inc, 1993, ISBN 1-55937-255-9.
-.\"}}}
diff --git a/bin/pdksh/sh.h b/bin/pdksh/sh.h
deleted file mode 100644
index 588abd2c18e..00000000000
--- a/bin/pdksh/sh.h
+++ /dev/null
@@ -1,707 +0,0 @@
-/* $OpenBSD: sh.h,v 1.5 1997/01/02 09:34:10 downsj Exp $ */
-
-/*
- * Public Domain Bourne/Korn shell
- */
-
-/* $From: sh.h,v 1.2 1994/05/19 18:32:40 michael Exp michael $ */
-
-#include "config.h" /* system and option configuration info */
-
-#ifdef HAVE_PROTOTYPES
-# define ARGS(args) args /* prototype declaration */
-#else
-# define ARGS(args) () /* K&R declaration */
-#endif
-
-
-/* Start of common headers */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <setjmp.h>
-#ifdef HAVE_STDDEF_H
-# include <stddef.h>
-#endif
-
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#else
-/* just a useful subset of what stdlib.h would have */
-extern char * getenv ARGS((const char *));
-extern void * malloc ARGS((size_t));
-extern int free ARGS((void *));
-extern int exit ARGS((int));
-extern int rand ARGS((void));
-extern void srand ARGS((unsigned int));
-extern int atoi ARGS((const char *));
-#endif /* HAVE_STDLIB_H */
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#else
-/* just a useful subset of what unistd.h would have */
-extern int access ARGS((const char *, int));
-extern int open ARGS((const char *, int, ...));
-extern int creat ARGS((const char *, mode_t));
-extern int read ARGS((int, char *, unsigned));
-extern int write ARGS((int, const char *, unsigned));
-extern off_t lseek ARGS((int, off_t, int));
-extern int close ARGS((int));
-extern int pipe ARGS((int []));
-extern int dup2 ARGS((int, int));
-extern int unlink ARGS((const char *));
-extern int fork ARGS((void));
-extern int execve ARGS((const char *, char * const[], char * const[]));
-extern int chdir ARGS((const char *));
-extern int kill ARGS((pid_t, int));
-extern char *getcwd(); /* no ARGS here - differs on different machines */
-extern int geteuid ARGS((void));
-extern int readlink ARGS((const char *, char *, int));
-extern int getegid ARGS((void));
-extern int getpid ARGS((void));
-extern int getppid ARGS((void));
-extern unsigned int sleep ARGS((unsigned int));
-extern int isatty ARGS((int));
-# ifdef POSIX_PGRP
-extern int getpgrp ARGS((void));
-extern int setpgid ARGS((pid_t, pid_t));
-# endif /* POSIX_PGRP */
-# ifdef BSD_PGRP
-extern int getpgrp ARGS((pid_t));
-extern int setpgrp ARGS((pid_t, pid_t));
-# endif /* BSD_PGRP */
-# ifdef SYSV_PGRP
-extern int getpgrp ARGS((void));
-extern int setpgrp ARGS((void));
-# endif /* SYSV_PGRP */
-#endif /* HAVE_UNISTD_H */
-
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# include <strings.h>
-# define strchr index
-# define strrchr rindex
-#endif /* HAVE_STRING_H */
-#ifndef HAVE_STRSTR
-char *strstr ARGS((const char *s, const char *p));
-#endif /* HAVE_STRSTR */
-#ifndef HAVE_STRCASECMP
-int strcasecmp ARGS((const char *s1, const char *s2));
-int strncasecmp ARGS((const char *s1, const char *s2, int n));
-#endif /* HAVE_STRCASECMP */
-
-#ifdef HAVE_MEMORY_H
-# include <memory.h>
-#endif
-#ifndef HAVE_MEMSET
-# define memcpy(d, s, n) bcopy(s, d, n)
-# define memcmp(s1, s2, n) bcmp(s1, s2, n)
-void *memset ARGS((void *d, int c, size_t n));
-#endif /* HAVE_MEMSET */
-#ifndef HAVE_MEMMOVE
-# ifdef HAVE_BCOPY
-# define memmove(d, s, n) bcopy(s, d, n)
-# else
-void *memmove ARGS((void *d, const void *s, size_t n));
-# endif
-#endif /* HAVE_MEMMOVE */
-
-#ifdef HAVE_PROTOTYPES
-# include <stdarg.h>
-# define SH_VA_START(va, argn) va_start(va, argn)
-#else
-# include <varargs.h>
-# define SH_VA_START(va, argn) va_start(va)
-#endif /* HAVE_PROTOTYPES */
-
-#include <errno.h>
-extern int errno;
-
-#ifdef HAVE_FCNTL_H
-# include <fcntl.h>
-#else
-# include <sys/file.h>
-#endif /* HAVE_FCNTL_H */
-#ifndef O_ACCMODE
-# define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
-#endif /* !O_ACCMODE */
-
-#ifndef F_OK /* access() arguments */
-# define F_OK 0
-# define X_OK 1
-# define W_OK 2
-# define R_OK 4
-#endif /* !F_OK */
-
-#ifndef SEEK_SET
-# ifdef L_SET
-# define SEEK_SET L_SET
-# define SEEK_CUR L_INCR
-# define SEEK_END L_XTND
-# else /* L_SET */
-# define SEEK_SET 0
-# define SEEK_CUR 1
-# define SEEK_END 2
-# endif /* L_SET */
-#endif /* !SEEK_SET */
-
-/* Some machines (eg, FreeBSD 1.1.5) define CLK_TCK in limits.h
- * (ksh_limval.h assumes limits has been included, if available)
- */
-#ifdef HAVE_LIMITS_H
-# include <limits.h>
-#endif /* HAVE_LIMITS_H */
-
-#include <signal.h>
-#ifdef NSIG
-# define SIGNALS NSIG
-#else
-# ifdef _MINIX
-# define SIGNALS (_NSIG+1) /* _NSIG is # of signals used, excluding 0. */
-# else
-# ifdef _SIGMAX /* QNX */
-# define SIGNALS _SIGMAX
-# else /* _SIGMAX */
-# define SIGNALS 32
-# endif /* _SIGMAX */
-# endif /* _MINIX */
-#endif /* NSIG */
-#ifndef SIGCHLD
-# define SIGCHLD SIGCLD
-#endif
-/* struct sigaction.sa_flags is set to KSH_SA_FLAGS. Used to ensure
- * system calls are interrupted
- */
-#ifdef SA_INTERRUPT
-# define KSH_SA_FLAGS SA_INTERRUPT
-#else /* SA_INTERRUPT */
-# define KSH_SA_FLAGS 0
-#endif /* SA_INTERRUPT */
-
-typedef RETSIGTYPE (*handler_t) ARGS((int)); /* signal handler */
-
-#ifdef USE_FAKE_SIGACT
-# include "sigact.h" /* use sjg's fake sigaction() */
-#endif
-
-#ifdef HAVE_PATHS_H
-# include <paths.h>
-#endif /* HAVE_PATHS_H */
-#ifdef _PATH_DEFPATH
-# define DEFAULT__PATH _PATH_DEFPATH
-#else /* _PATH_DEFPATH */
-# define DEFAULT__PATH DEFAULT_PATH
-#endif /* _PATH_DEFPATH */
-
-#ifndef offsetof
-# define offsetof(type,id) ((size_t)&((type*)NULL)->id)
-#endif
-
-#ifndef HAVE_KILLPG
-# define killpg(p, s) kill(-(p), (s))
-#endif /* !HAVE_KILLPG */
-
-/* Special cases for execve(2) */
-#ifdef OS2
-extern int ksh_execve(char *cmd, char **args, char **env);
-#else /* OS2 */
-# if defined(OS_ISC) && defined(_POSIX_SOURCE)
-/* Kludge for ISC 3.2 (and other versions?) so programs will run correctly. */
-# define ksh_execve(p, av, ev) do { \
- __setostype(0); \
- execve(p, av, ev); \
- __setostype(1); \
- } while (0)
-# else /* OS_ISC && _POSIX */
-# define ksh_execve(p, av, ev) execve(p, av, ev)
-# endif /* OS_ISC && _POSIX */
-#endif /* OS2 */
-
-/* this is a hang-over from older versions of the os2 port */
-#define ksh_dupbase(fd, base) fcntl(fd, F_DUPFD, base)
-
-#ifdef HAVE_SIGSETJMP
-# define ksh_sigsetjmp(env,sm) sigsetjmp((env), (sm))
-# define ksh_siglongjmp(env,v) siglongjmp((env), (v))
-# define ksh_jmp_buf sigjmp_buf
-#else /* HAVE_SIGSETJMP */
-# ifdef HAVE__SETJMP
-# define ksh_sigsetjmp(env,sm) _setjmp(env)
-# define ksh_siglongjmp(env,v) _longjmp((env), (v))
-# else /* HAVE__SETJMP */
-# define ksh_sigsetjmp(env,sm) setjmp(env)
-# define ksh_siglongjmp(env,v) longjmp((env), (v))
-# endif /* HAVE__SETJMP */
-# define ksh_jmp_buf jmp_buf
-#endif /* HAVE_SIGSETJMP */
-
-/* Find a integer type that is at least 32 bits (or die) - SIZEOF_* defined
- * by autoconf (assumes an 8 bit byte, but I'm not concerned)
- */
-#if SIZEOF_INT >= 4
-# define INT32 int
-#else /* SIZEOF_INT */
-# if SIZEOF_LONG >= 4
-# define INT32 long
-# else /* SIZEOF_LONG */
- #error cannot find 32 bit type...
-# endif /* SIZEOF_LONG */
-#endif /* SIZEOF_INT */
-
-/* end of common headers */
-
-/* Stop gcc and lint from complaining about possibly uninitialized variables */
-#if defined(__GNUC__) || defined(lint)
-# define UNINITIALIZED(var) var = 0
-#else
-# define UNINITIALIZED(var) var
-#endif /* GNUC || lint */
-
-/* some useful #defines */
-#ifdef EXTERN
-# define I__(i) = i
-#else
-# define I__(i)
-# define EXTERN extern
-# define EXTERN_DEFINED
-#endif
-
-#ifndef EXECSHELL
-/* shell to exec scripts (see also $SHELL initialization in main.c) */
-# ifdef OS2
-# define EXECSHELL "c:\\os2\\cmd.exe"
-# define EXECSHELL_STR "OS2_SHELL"
-# else /* OS2 */
-# define EXECSHELL "/bin/sh"
-# define EXECSHELL_STR "EXECSHELL"
-# endif /* OS2 */
-#endif
-
-/* ISABSPATH() means path is fully and completely specified,
- * ISROOTEDPATH() means a .. as the first component is a no-op,
- * ISRELPATH() means $PWD can be tacked on to get an absolute path.
- *
- * OS Path ISABSPATH ISROOTEDPATH ISRELPATH
- * unix /foo yes yes no
- * unix foo no no yes
- * unix ../foo no no yes
- * os2 a:/foo yes yes no
- * os2 a:foo no no no
- * os2 /foo no yes no
- * os2 foo no no yes
- * os2 ../foo no no yes
- */
-#ifdef OS2
-# define PATHSEP ';'
-# define DIRSEP '/' /* even though \ is native */
-# define DIRSEPSTR "\\"
-# define ISDIRSEP(c) ((c) == '\\' || (c) == '/')
-# define ISABSPATH(s) (((s)[0] && (s)[1] == ':' && ISDIRSEP((s)[2])))
-# define ISROOTEDPATH(s) (ISDIRSEP((s)[0]) || ISABSPATH(s))
-# define ISRELPATH(s) (!(s)[0] || ((s)[1] != ':' && !ISDIRSEP((s)[0])))
-# define FILECHCONV(c) (isascii(c) && isupper(c) ? tolower(c) : c)
-# define FILECMP(s1, s2) stricmp(s1, s2)
-# define FILENCMP(s1, s2, n) strnicmp(s1, s2, n)
-extern char *ksh_strchr_dirsep(const char *path);
-extern char *ksh_strrchr_dirsep(const char *path);
-# define chdir _chdir2
-# define getcwd _getcwd2
-#else
-# define PATHSEP ':'
-# define DIRSEP '/'
-# define DIRSEPSTR "/"
-# define ISDIRSEP(c) ((c) == '/')
-# define ISABSPATH(s) ISDIRSEP((s)[0])
-# define ISROOTEDPATH(s) ISABSPATH(s)
-# define ISRELPATH(s) (!ISABSPATH(s))
-# define FILECHCONV(c) c
-# define FILECMP(s1, s2) strcmp(s1, s2)
-# define FILENCMP(s1, s2, n) strncmp(s1, s2, n)
-# define ksh_strchr_dirsep(p) strchr(p, DIRSEP)
-# define ksh_strrchr_dirsep(p) strrchr(p, DIRSEP)
-#endif
-
-typedef int bool_t;
-#define FALSE 0
-#define TRUE 1
-
-#define NELEM(a) (sizeof(a) / sizeof((a)[0]))
-#define sizeofN(type, n) (sizeof(type) * (n))
-#define BIT(i) (1<<(i)) /* define bit in flag */
-
-/* Table flag type - needs > 16 and < 32 bits */
-typedef INT32 Tflag;
-
-#define NUFILE 32 /* Number of user-accessible files */
-#define FDBASE 10 /* First file usable by Shell */
-
-/* you're not going to run setuid shell scripts, are you? */
-#define eaccess(path, mode) access(path, mode)
-
-/* Make MAGIC a char that might be printed to make bugs more obvious, but
- * not a char that is used often. Also, can't use the high bit as it causes
- * portability problems (calling strchr(x, 0x80|'x') is error prone).
- */
-#define MAGIC (7)/* prefix for *?[!{,} during expand */
-#define ISMAGIC(c) ((unsigned char)(c) == MAGIC)
-#define NOT '!' /* might use ^ (ie, [!...] vs [^..]) */
-
-#define LINE 1024 /* input line size */
-#define PATH 1024 /* pathname size (todo: PATH_MAX/pathconf()) */
-#define ARRAYMAX 1023 /* max array index */
-
-EXTERN const char *kshname; /* $0 */
-EXTERN pid_t kshpid; /* $$, shell pid */
-EXTERN pid_t procpid; /* pid of executing process */
-EXTERN int exstat; /* exit status */
-EXTERN int subst_exstat; /* exit status of last $(..)/`..` */
-EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */
-
-
-/*
- * Area-based allocation built on malloc/free
- */
-
-typedef struct Area {
- struct Block *freelist; /* free list */
-} Area;
-
-EXTERN Area aperm; /* permanent object space */
-#define APERM &aperm
-#define ATEMP &e->area
-
-#ifdef MEM_DEBUG
-# include "chmem.h" /* a debugging front end for malloc et. al. */
-#endif /* MEM_DEBUG */
-
-
-/*
- * parsing & execution environment
- */
-EXTERN struct env {
- short type; /* enviroment type - see below */
- short flags; /* EF_* */
- Area area; /* temporary allocation area */
- struct block *loc; /* local variables and functions */
- short *savefd; /* original redirected fd's */
- struct env *oenv; /* link to previous enviroment */
- ksh_jmp_buf jbuf; /* long jump back to env creator */
- struct temp *temps; /* temp files */
-} *e;
-
-/* struct env.type values */
-#define E_NONE 0 /* dummy enviroment */
-#define E_PARSE 1 /* parsing command # */
-#define E_FUNC 2 /* executing function # */
-#define E_INCL 3 /* including a file via . # */
-#define E_EXEC 4 /* executing command tree */
-#define E_LOOP 5 /* executing for/while # */
-#define E_ERRH 6 /* general error handler # */
-/* # indicates env has valid jbuf (see unwind()) */
-
-/* struct env.flag values */
-#define EF_FUNC_PARSE BIT(0) /* function being parsed */
-#define EF_BRKCONT_PASS BIT(1) /* set if E_LOOP must pass break/continue on */
-
-/* Do breaks/continues stop at env type e? */
-#define STOP_BRKCONT(t) ((t) == E_NONE || (t) == E_PARSE \
- || (t) == E_FUNC || (t) == E_INCL)
-/* Do returns stop at env type e? */
-#define STOP_RETURN(t) ((t) == E_FUNC || (t) == E_INCL)
-
-/* values for ksh_siglongjmp(e->jbuf, 0) */
-#define LRETURN 1 /* return statement */
-#define LEXIT 2 /* exit statement */
-#define LERROR 3 /* errorf() called */
-#define LLEAVE 4 /* untrappable exit/error */
-#define LINTR 5 /* ^C noticed */
-#define LBREAK 6 /* break statement */
-#define LCONTIN 7 /* continue statement */
-#define LSHELL 8 /* return to interactive shell() */
-#define LAEXPR 9 /* error in arithmetic expression */
-
-
-/* option processing */
-#define OF_CMDLINE 0x01 /* command line */
-#define OF_SET 0x02 /* set builtin */
-#define OF_SPECIAL 0x04 /* a special variable changing */
-#define OF_ANY (OF_CMDLINE | OF_SET | OF_SPECIAL)
-
-struct option {
- const char *name; /* long name of option */
- char c; /* character flag (if any) */
- short flags; /* OF_* */
-};
-extern const struct option options[];
-
-/*
- * flags (the order of these enums MUST match the order in misc.c(options[]))
- */
-enum sh_flag {
- FEXPORT = 0, /* -a: export all */
-#ifdef BRACE_EXPAND
- FBRACEEXPAND, /* enable {} globbing */
-#endif
- FBGNICE, /* bgnice */
- FCOMMAND, /* -c: (invocation) execute specified command */
-#ifdef EMACS
- FEMACS, /* emacs command editing */
-#endif
- FERREXIT, /* -e: quit on error */
-#ifdef EMACS
- FGMACS, /* gmacs command editing */
-#endif
- FIGNOREEOF, /* eof does not exit */
- FTALKING, /* -i: interactive */
- FKEYWORD, /* -k: name=value anywere */
- FLOGIN, /* -l: a login shell */
- FMARKDIRS, /* mark dirs with / in file name completion */
- FMONITOR, /* -m: job control monitoring */
- FNOCLOBBER, /* -C: don't overwrite existing files */
- FNOEXEC, /* -n: don't execute any commands */
- FNOGLOB, /* -f: don't do file globbing */
- FNOHUP, /* -H: don't kill running jobs when login shell exits */
- FNOLOG, /* don't save functions in history (ignored) */
-#ifdef JOBS
- FNOTIFY, /* -b: asynchronous job completion notification */
-#endif
- FNOUNSET, /* -u: using an unset var is an error */
- FPHYSICAL, /* -o physical: don't do logical cd's/pwd's */
- FPOSIX, /* -o posix: be posixly correct */
- FPRIVILEGED, /* -p: use suid_profile */
- FRESTRICTED, /* -r: restricted shell */
- FSH, /* -o sh: favor sh behavour */
- FSTDIN, /* -s: (invocation) parse stdin */
- FTRACKALL, /* -h: create tracked aliases for all commands */
- FVERBOSE, /* -v: echo input */
-#ifdef VI
- FVI, /* vi command editing */
- FVIRAW, /* always read in raw mode (ignored) */
- FVISHOW8, /* display chars with 8th bit set as is (versus M-) */
- FVITABCOMPLETE, /* enable tab as file name completion char */
- FVIESCCOMPLETE, /* enable ESC as file name completion in command mode */
-#endif
- FXTRACE, /* -x: execution trace */
- FNFLAGS /* (place holder: how many flags are there) */
-};
-
-#define Flag(f) (shell_flags[(int) (f)])
-
-EXTERN char shell_flags [FNFLAGS];
-
-EXTERN char null [] I__(""); /* null value for variable */
-EXTERN char space [] I__(" ");
-EXTERN char newline [] I__("\n");
-EXTERN char slash [] I__("/");
-
-/* temp/here files. the file is removed when the struct is freed */
-struct temp {
- struct temp *next;
- struct shf *shf;
- int pid; /* pid of process parsed here-doc */
- char *name;
-};
-
-/* here documents in functions are treated specially (the get removed when
- * shell exis) */
-EXTERN struct temp *func_heredocs;
-
-/*
- * stdio and our IO routines
- */
-
-#define shl_spare (&shf_iob[0]) /* for c_read()/c_print() */
-#define shl_stdout (&shf_iob[1])
-#define shl_out (&shf_iob[2])
-EXTERN int shl_stdout_ok;
-
-/*
- * trap handlers
- */
-typedef struct trap {
- int signal; /* signal number */
- const char *name; /* short name */
- const char *mess; /* descriptive name */
- char *trap; /* trap command */
- int volatile set; /* trap pending */
- int flags; /* TF_* */
- handler_t cursig; /* current handler (valid if TF_ORIG_* set) */
- handler_t shtrap; /* shell signal handler */
-} Trap;
-
-/* values for Trap.flags */
-#define TF_SHELL_USES BIT(0) /* shell uses signal, user can't change */
-#define TF_USER_SET BIT(1) /* user has (tried to) set trap */
-#define TF_ORIG_IGN BIT(2) /* original action was SIG_IGN */
-#define TF_ORIG_DFL BIT(3) /* original action was SIG_DFL */
-#define TF_EXEC_IGN BIT(4) /* restore SIG_IGN just before exec */
-#define TF_EXEC_DFL BIT(5) /* restore SIG_DFL just before exec */
-#define TF_DFL_INTR BIT(6) /* when received, default action is LINTR */
-#define TF_TTY_INTR BIT(7) /* tty generated signal (see j_waitj) */
-#define TF_CHANGED BIT(8) /* used by runtrap() to detect trap changes */
-#define TF_FATAL BIT(9) /* causes termination if not trapped */
-
-/* values for setsig()/setexecsig() flags argument */
-#define SS_RESTORE_MASK 0x3 /* how to restore a signal before an exec() */
-#define SS_RESTORE_CURR 0 /* leave current handler in place */
-#define SS_RESTORE_ORIG 1 /* restore original handler */
-#define SS_RESTORE_DFL 2 /* restore to SIG_DFL */
-#define SS_RESTORE_IGN 3 /* restore to SIG_IGN */
-#define SS_FORCE BIT(3) /* set signal even if original signal ignored */
-#define SS_USER BIT(4) /* user is doing the set (ie, trap command) */
-#define SS_SHTRAP BIT(5) /* trap for internal use (CHLD,ALRM,WINCH) */
-
-#define SIGEXIT_ 0 /* for trap EXIT */
-#define SIGERR_ SIGNALS /* for trap ERR */
-
-EXTERN int volatile trap; /* traps pending? */
-EXTERN int volatile intrsig; /* pending trap interrupts executing command */
-EXTERN int volatile fatal_trap;/* received a fatal signal */
-#ifndef FROM_TRAP_C
-/* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */
-extern Trap sigtraps[SIGNALS+1];
-#endif /* !FROM_TRAP_C */
-
-
-#ifdef KSH
-/*
- * TMOUT support
- */
-/* values for ksh_tmout_state */
-enum tmout_enum {
- TMOUT_EXECUTING = 0, /* executing commands */
- TMOUT_READING, /* waiting for input */
- TMOUT_LEAVING /* have timed out */
- };
-EXTERN unsigned int ksh_tmout;
-EXTERN enum tmout_enum ksh_tmout_state I__(TMOUT_EXECUTING);
-#endif /* KSH */
-
-
-/* For "You have stopped jobs" message */
-EXTERN int really_exit;
-
-
-/*
- * fast character classes
- */
-#define C_ALPHA BIT(0) /* a-z_A-Z */
-#define C_DIGIT BIT(1) /* 0-9 */
-#define C_LEX1 BIT(2) /* \0 \t\n|&;<>() */
-#define C_VAR1 BIT(3) /* *@#!$-? */
-#define C_IFSWS BIT(4) /* \t \n (IFS white space) */
-#define C_SUBOP1 BIT(5) /* "=-+?" */
-#define C_SUBOP2 BIT(6) /* "#%" */
-#define C_IFS BIT(7) /* $IFS */
-#define C_QUOTE BIT(8) /* \n\t"#$&'()*;<>?[\`| (needing quoting) */
-
-extern short ctypes [];
-
-#define ctype(c, t) !!(ctypes[(unsigned char)(c)]&(t))
-#define letter(c) ctype(c, C_ALPHA)
-#define digit(c) ctype(c, C_DIGIT)
-#define letnum(c) ctype(c, C_ALPHA|C_DIGIT)
-
-EXTERN int ifs0 I__(' '); /* for "$*" */
-
-
-/* Argument parsing for built-in commands and getopts command */
-
-/* Values for Getopt.flags */
-#define GF_ERROR BIT(0) /* call errorf() if there is an error */
-#define GF_PLUSOPT BIT(1) /* allow +c as an option */
-#define GF_NONAME BIT(2) /* don't print argv[0] in errors */
-
-/* Values for Getopt.info */
-#define GI_MINUS BIT(0) /* an option started with -... */
-#define GI_PLUS BIT(1) /* an option started with +... */
-#define GI_MINUSMINUS BIT(2) /* arguments were ended with -- */
-
-typedef struct {
- int optind;
- char *optarg;
- int flags; /* see GF_* */
- int info; /* see GI_* */
- unsigned int p; /* 0 or index into argv[optind - 1] */
- char buf[2]; /* for bad option OPTARG value */
-} Getopt;
-
-EXTERN Getopt builtin_opt; /* for shell builtin commands */
-
-
-#ifdef KSH
-/* This for co-processes */
-
-typedef INT32 Coproc_id; /* something that won't (realisticly) wrap */
-struct coproc {
- int read; /* pipe from co-process's stdout */
- int readw; /* other side of read (saved temporarily) */
- int write; /* pipe to co-process's stdin */
- Coproc_id id; /* id of current output pipe */
- int njobs; /* number of live jobs using output pipe */
- void *job; /* 0 or job of co-process using input pipe */
-};
-EXTERN struct coproc coproc;
-#endif /* KSH */
-
-/* Used in jobs.c and by coprocess stuff in exec.c */
-#ifdef JOB_SIGS
-EXTERN sigset_t sm_default, sm_sigchld;
-#endif /* JOB_SIGS */
-
-extern const char ksh_version[];
-
-/* name of called builtin function (used by error functions) */
-EXTERN char *builtin_argv0;
-EXTERN Tflag builtin_flag; /* flags of called builtin (SPEC_BI, etc.) */
-
-/* current working directory, and size of memory allocated for same */
-EXTERN char *current_wd;
-EXTERN int current_wd_size;
-
-#ifdef EDIT
-/* Minimium required space to work with on a line - if the prompt leaves less
- * space than this on a line, the prompt is truncated.
- */
-# define MIN_EDIT_SPACE 7
-/* Minimium allowed value for x_cols: 2 for prompt, 3 for " < " at end of line
- */
-# define MIN_COLS (2 + MIN_EDIT_SPACE + 3)
-EXTERN int x_cols I__(80); /* tty columns */
-#else
-# define x_cols 80 /* for pr_menu(exec.c) */
-#endif
-
-
-/* These to avoid bracket matching problems */
-#define OPAREN '('
-#define CPAREN ')'
-#define OBRACK '['
-#define CBRACK ']'
-#define OBRACE '{'
-#define CBRACE '}'
-
-/* Determine the location of the system (common) profile */
-#ifndef KSH_SYSTEM_PROFILE
-# ifdef __NeXT
-# define KSH_SYSTEM_PROFILE "/etc/profile.std"
-# else /* __NeXT */
-# define KSH_SYSTEM_PROFILE "/etc/profile"
-# endif /* __NeXT */
-#endif /* KSH_SYSTEM_PROFILE */
-
-#include "shf.h"
-#include "table.h"
-#include "tree.h"
-#include "expand.h"
-#include "lex.h"
-#include "proto.h"
-
-/* be sure not to interfere with anyone else's idea about EXTERN */
-#ifdef EXTERN_DEFINED
-# undef EXTERN_DEFINED
-# undef EXTERN
-#endif
-#undef I__
diff --git a/bin/pdksh/shf.c b/bin/pdksh/shf.c
deleted file mode 100644
index 78266aa9b26..00000000000
--- a/bin/pdksh/shf.c
+++ /dev/null
@@ -1,1271 +0,0 @@
-/* $OpenBSD: shf.c,v 1.3 1997/06/19 13:58:46 kstailey Exp $ */
-
-/*
- * Shell file I/O routines
- */
-
-#include "sh.h"
-#include "ksh_stat.h"
-#include "ksh_limval.h"
-
-
-/* flags to shf_emptybuf() */
-#define EB_READSW 0x01 /* about to switch to reading */
-#define EB_GROW 0x02 /* grow buffer if necessary (STRING+DYNAMIC) */
-
-/*
- * Replacement stdio routines. Stdio is too flakey on too many machines
- * to be useful when you have multiple processes using the same underlying
- * file descriptors.
- */
-
-static int shf_fillbuf ARGS((struct shf *shf));
-static int shf_emptybuf ARGS((struct shf *shf, int flags));
-
-/* Open a file. First three args are for open(), last arg is flags for
- * this package. Returns NULL if file could not be opened, or if a dup
- * fails.
- */
-struct shf *
-shf_open(name, oflags, mode, sflags)
- const char *name;
- int oflags;
- int mode;
- int sflags;
-{
- int fd;
-
- fd = open(name, oflags, mode);
- if (fd < 0)
- return NULL;
- if ((sflags & SHF_MAPHI) && fd < FDBASE) {
- int nfd;
-
- nfd = ksh_dupbase(fd, FDBASE);
- close(fd);
- if (nfd < 0)
- return NULL;
- fd = nfd;
- }
- sflags &= ~SHF_ACCMODE;
- sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD
- : ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR
- : SHF_RDWR);
-
- return shf_fdopen(fd, sflags, (struct shf *) 0);
-}
-
-/* Set up the shf structure for a file descriptor. Doesn't fail. */
-struct shf *
-shf_fdopen(fd, sflags, shf)
- int fd;
- int sflags;
- struct shf *shf;
-{
- int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
-
- /* use fcntl() to figure out correct read/write flags */
- if (sflags & SHF_GETFL) {
- int flags = fcntl(fd, F_GETFL, 0);
-
- if (flags < 0)
- /* will get an error on first read/write */
- sflags |= SHF_RDWR;
- else
- switch (flags & O_ACCMODE) {
- case O_RDONLY: sflags |= SHF_RD; break;
- case O_WRONLY: sflags |= SHF_WR; break;
- case O_RDWR: sflags |= SHF_RDWR; break;
- }
- }
-
- if (!(sflags & (SHF_RD | SHF_WR)))
- internal_errorf(1, "shf_fdopen: missing read/write");
-
- if (shf) {
- if (bsize) {
- shf->buf = (unsigned char *) alloc(bsize, ATEMP);
- sflags |= SHF_ALLOCB;
- } else
- shf->buf = (unsigned char *) 0;
- } else {
- shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP);
- shf->buf = (unsigned char *) &shf[1];
- sflags |= SHF_ALLOCS;
- }
- shf->areap = ATEMP;
- shf->fd = fd;
- shf->rp = shf->wp = shf->buf;
- shf->rnleft = 0;
- shf->rbsize = bsize;
- shf->wnleft = 0; /* force call to shf_emptybuf() */
- shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
- shf->flags = sflags;
- shf->errno_ = 0;
- shf->bsize = bsize;
- if (sflags & SHF_CLEXEC)
- fd_clexec(fd);
- return shf;
-}
-
-/* Set up an existing shf (and buffer) to use the given fd */
-struct shf *
-shf_reopen(fd, sflags, shf)
- int fd;
- int sflags;
- struct shf *shf;
-{
- int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
-
- /* use fcntl() to figure out correct read/write flags */
- if (sflags & SHF_GETFL) {
- int flags = fcntl(fd, F_GETFL, 0);
-
- if (flags < 0)
- /* will get an error on first read/write */
- sflags |= SHF_RDWR;
- else
- switch (flags & O_ACCMODE) {
- case O_RDONLY: sflags |= SHF_RD; break;
- case O_WRONLY: sflags |= SHF_WR; break;
- case O_RDWR: sflags |= SHF_RDWR; break;
- }
- }
-
- if (!(sflags & (SHF_RD | SHF_WR)))
- internal_errorf(1, "shf_reopen: missing read/write");
- if (!shf || !shf->buf || shf->bsize < bsize)
- internal_errorf(1, "shf_reopen: bad shf/buf/bsize");
-
- /* assumes shf->buf and shf->bsize already set up */
- shf->fd = fd;
- shf->rp = shf->wp = shf->buf;
- shf->rnleft = 0;
- shf->rbsize = bsize;
- shf->wnleft = 0; /* force call to shf_emptybuf() */
- shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize;
- shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags;
- shf->errno_ = 0;
- if (sflags & SHF_CLEXEC)
- fd_clexec(fd);
- return shf;
-}
-
-/* Open a string for reading or writing. If reading, bsize is the number
- * of bytes that can be read. If writing, bsize is the maximum number of
- * bytes that can be written. If shf is not null, it is filled in and
- * returned, if it is null, shf is allocated. If writing and buf is null
- * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is
- * used for the initial size). Doesn't fail.
- * When writing, a byte is reserved for a trailing null - see shf_sclose().
- */
-struct shf *
-shf_sopen(buf, bsize, sflags, shf)
- char *buf;
- int bsize;
- int sflags;
- struct shf *shf;
-{
- /* can't have a read+write string */
- if (!(sflags & (SHF_RD | SHF_WR))
- || (sflags & (SHF_RD | SHF_WR)) == (SHF_RD | SHF_WR))
- internal_errorf(1, "shf_sopen: flags 0x%x", sflags);
-
- if (!shf) {
- shf = (struct shf *) alloc(sizeof(struct shf), ATEMP);
- sflags |= SHF_ALLOCS;
- }
- shf->areap = ATEMP;
- if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) {
- if (bsize <= 0)
- bsize = 64;
- sflags |= SHF_ALLOCB;
- buf = alloc(bsize, shf->areap);
- }
- shf->fd = -1;
- shf->buf = shf->rp = shf->wp = (unsigned char *) buf;
- shf->rnleft = bsize;
- shf->rbsize = bsize;
- shf->wnleft = bsize - 1; /* space for a '\0' */
- shf->wbsize = bsize;
- shf->flags = sflags | SHF_STRING;
- shf->errno_ = 0;
- shf->bsize = bsize;
-
- return shf;
-}
-
-/* Flush and close file descriptor, free the shf structure */
-int
-shf_close(shf)
- struct shf *shf;
-{
- int ret = 0;
-
- if (shf->fd >= 0) {
- ret = shf_flush(shf);
- if (close(shf->fd) < 0)
- ret = EOF;
- }
- if (shf->flags & SHF_ALLOCS)
- afree(shf, shf->areap);
- else if (shf->flags & SHF_ALLOCB)
- afree(shf->buf, shf->areap);
-
- return ret;
-}
-
-/* Flush and close file descriptor, don't free file structure */
-int
-shf_fdclose(shf)
- struct shf *shf;
-{
- int ret = 0;
-
- if (shf->fd >= 0) {
- ret = shf_flush(shf);
- if (close(shf->fd) < 0)
- ret = EOF;
- shf->rnleft = 0;
- shf->rp = shf->buf;
- shf->wnleft = 0;
- shf->fd = -1;
- }
-
- return ret;
-}
-
-/* Close a string - if it was opened for writing, it is null terminated;
- * returns a pointer to the string and frees shf if it was allocated
- * (does not free string if it was allocated).
- */
-char *
-shf_sclose(shf)
- struct shf *shf;
-{
- unsigned char *s = shf->buf;
-
- /* null terminate */
- if (shf->flags & SHF_WR) {
- shf->wnleft++;
- shf_putc('\0', shf);
- }
- if (shf->flags & SHF_ALLOCS)
- afree(shf, shf->areap);
- return (char *) s;
-}
-
-/* Flush and free file structure, don't close file descriptor */
-int
-shf_finish(shf)
- struct shf *shf;
-{
- int ret = 0;
-
- if (shf->fd >= 0)
- ret = shf_flush(shf);
- if (shf->flags & SHF_ALLOCS)
- afree(shf, shf->areap);
- else if (shf->flags & SHF_ALLOCB)
- afree(shf->buf, shf->areap);
-
- return ret;
-}
-
-/* Un-read what has been read but not examined, or write what has been
- * buffered. Returns 0 for success, EOF for (write) error.
- */
-int
-shf_flush(shf)
- struct shf *shf;
-{
- if (shf->flags & SHF_STRING)
- return (shf->flags & SHF_WR) ? EOF : 0;
-
- if (shf->fd < 0)
- internal_errorf(1, "shf_flush: no fd");
-
- if (shf->flags & SHF_ERROR) {
- errno = shf->errno_;
- return EOF;
- }
-
- if (shf->flags & SHF_READING) {
- shf->flags &= ~(SHF_EOF | SHF_READING);
- if (shf->rnleft > 0) {
- lseek(shf->fd, (off_t) -shf->rnleft, 1);
- shf->rnleft = 0;
- shf->rp = shf->buf;
- }
- return 0;
- } else if (shf->flags & SHF_WRITING)
- return shf_emptybuf(shf, 0);
-
- return 0;
-}
-
-/* Write out any buffered data. If currently reading, flushes the read
- * buffer. Returns 0 for success, EOF for (write) error.
- */
-static int
-shf_emptybuf(shf, flags)
- struct shf *shf;
- int flags;
-{
- int ret = 0;
-
- if (!(shf->flags & SHF_STRING) && shf->fd < 0)
- internal_errorf(1, "shf_emptybuf: no fd");
-
- if (shf->flags & SHF_ERROR) {
- errno = shf->errno_;
- return EOF;
- }
-
- if (shf->flags & SHF_READING) {
- if (flags & EB_READSW) /* doesn't happen */
- return 0;
- ret = shf_flush(shf);
- shf->flags &= ~SHF_READING;
- }
- if (shf->flags & SHF_STRING) {
- unsigned char *nbuf;
-
- /* Note that we assume SHF_ALLOCS is not set if SHF_ALLOCB
- * is set... (changing the shf pointer could cause problems)
- */
- if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC)
- || !(shf->flags & SHF_ALLOCB))
- return EOF;
- /* allocate more space for buffer */
- nbuf = (unsigned char *) aresize(shf->buf, shf->wbsize * 2,
- shf->areap);
- shf->rp = nbuf + (shf->rp - shf->buf);
- shf->wp = nbuf + (shf->wp - shf->buf);
- shf->rbsize += shf->wbsize;
- shf->wbsize += shf->wbsize;
- shf->wnleft += shf->wbsize;
- shf->wbsize *= 2;
- shf->buf = nbuf;
- } else {
- if (shf->flags & SHF_WRITING) {
- int ntowrite = shf->wp - shf->buf;
- unsigned char *buf = shf->buf;
- int n;
-
- while (ntowrite > 0) {
- n = write(shf->fd, buf, ntowrite);
- if (n < 0) {
- if (errno == EINTR
- && !(shf->flags & SHF_INTERRUPT))
- continue;
- shf->flags |= SHF_ERROR;
- shf->errno_ = errno;
- shf->wnleft = 0;
- if (buf != shf->buf) {
- /* allow a second flush
- * to work */
- memmove(shf->buf, buf,
- ntowrite);
- shf->wp = shf->buf + ntowrite;
- }
- return EOF;
- }
- buf += n;
- ntowrite -= n;
- }
- if (flags & EB_READSW) {
- shf->wp = shf->buf;
- shf->wnleft = 0;
- shf->flags &= ~SHF_WRITING;
- return 0;
- }
- }
- shf->wp = shf->buf;
- shf->wnleft = shf->wbsize;
- }
- shf->flags |= SHF_WRITING;
-
- return ret;
-}
-
-/* Fill up a read buffer. Returns EOF for a read error, 0 otherwise. */
-static int
-shf_fillbuf(shf)
- struct shf *shf;
-{
- if (shf->flags & SHF_STRING)
- return 0;
-
- if (shf->fd < 0)
- internal_errorf(1, "shf_fillbuf: no fd");
-
- if (shf->flags & (SHF_EOF | SHF_ERROR)) {
- if (shf->flags & SHF_ERROR)
- errno = shf->errno_;
- return EOF;
- }
-
- if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)
- return EOF;
-
- shf->flags |= SHF_READING;
-
- shf->rp = shf->buf;
- while (1) {
- shf->rnleft = blocking_read(shf->fd, (char *) shf->buf,
- shf->rbsize);
- if (shf->rnleft < 0 && errno == EINTR
- && !(shf->flags & SHF_INTERRUPT))
- continue;
- break;
- }
- if (shf->rnleft <= 0) {
- if (shf->rnleft < 0) {
- shf->flags |= SHF_ERROR;
- shf->errno_ = errno;
- shf->rnleft = 0;
- shf->rp = shf->buf;
- return EOF;
- }
- shf->flags |= SHF_EOF;
- }
- return 0;
-}
-
-/* Seek to a new position in the file. If writing, flushes the buffer
- * first. If reading, optimizes small relative seeks that stay inside the
- * buffer. Returns 0 for success, EOF otherwise.
- */
-int
-shf_seek(shf, where, from)
- struct shf *shf;
- off_t where;
- int from;
-{
- if (shf->fd < 0) {
- errno = EINVAL;
- return EOF;
- }
-
- if (shf->flags & SHF_ERROR) {
- errno = shf->errno_;
- return EOF;
- }
-
- if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)
- return EOF;
-
- if (shf->flags & SHF_READING) {
- if (from == SEEK_CUR &&
- (where < 0 ?
- -where >= shf->rbsize - shf->rnleft :
- where < shf->rnleft)) {
- shf->rnleft -= where;
- shf->rp += where;
- return 0;
- }
- shf->rnleft = 0;
- shf->rp = shf->buf;
- }
-
- shf->flags &= ~(SHF_EOF | SHF_READING | SHF_WRITING);
-
- if (lseek(shf->fd, where, from) < 0) {
- shf->errno_ = errno;
- shf->flags |= SHF_ERROR;
- return EOF;
- }
-
- return 0;
-}
-
-
-/* Read a buffer from shf. Returns the number of bytes read into buf,
- * if no bytes were read, returns 0 if end of file was seen, EOF if
- * a read error occurred.
- */
-int
-shf_read(buf, bsize, shf)
- char *buf;
- int bsize;
- struct shf *shf;
-{
- int orig_bsize = bsize;
- int ncopy;
-
- if (!(shf->flags & SHF_RD))
- internal_errorf(1, "shf_read: flags %x", shf->flags);
-
- if (bsize <= 0)
- internal_errorf(1, "shf_read: bsize %d", bsize);
-
- while (bsize > 0) {
- if (shf->rnleft == 0
- && (shf_fillbuf(shf) == EOF || shf->rnleft == 0))
- break;
- ncopy = shf->rnleft;
- if (ncopy > bsize)
- ncopy = bsize;
- memcpy(buf, shf->rp, ncopy);
- buf += ncopy;
- bsize -= ncopy;
- shf->rp += ncopy;
- shf->rnleft -= ncopy;
- }
- /* Note: fread(3S) returns 0 for errors - this doesn't */
- return orig_bsize == bsize ? (shf_error(shf) ? EOF : 0)
- : orig_bsize - bsize;
-}
-
-/* Read up to a newline or EOF. The newline is put in buf; buf is always
- * null terminated. Returns NULL on read error or if nothing was read before
- * end of file, returns a pointer to the null byte in buf otherwise.
- */
-char *
-shf_getse(buf, bsize, shf)
- char *buf;
- int bsize;
- struct shf *shf;
-{
- unsigned char *end;
- int ncopy;
- char *orig_buf = buf;
-
- if (!(shf->flags & SHF_RD))
- internal_errorf(1, "shf_getse: flags %x", shf->flags);
-
- if (bsize <= 0)
- return (char *) 0;
-
- --bsize; /* save room for null */
- do {
- if (shf->rnleft == 0) {
- if (shf_fillbuf(shf) == EOF)
- return NULL;
- if (shf->rnleft == 0) {
- *buf = '\0';
- return buf == orig_buf ? NULL : buf;
- }
- }
- end = (unsigned char *) memchr((char *) shf->rp, '\n',
- shf->rnleft);
- ncopy = end ? end - shf->rp + 1 : shf->rnleft;
- if (ncopy > bsize)
- ncopy = bsize;
- memcpy(buf, (char *) shf->rp, ncopy);
- shf->rp += ncopy;
- shf->rnleft -= ncopy;
- buf += ncopy;
- bsize -= ncopy;
- } while (!end && bsize);
- *buf = '\0';
- return buf;
-}
-
-/* Returns the char read. Returns EOF for error and end of file. */
-int
-shf_getchar(shf)
- struct shf *shf;
-{
- if (!(shf->flags & SHF_RD))
- internal_errorf(1, "shf_getchar: flags %x", shf->flags);
-
- if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0))
- return EOF;
- --shf->rnleft;
- return *shf->rp++;
-}
-
-/* Put a character back in the input stream. Returns the character if
- * successful, EOF if there is no room.
- */
-int
-shf_ungetc(c, shf)
- int c;
- struct shf *shf;
-{
- if (!(shf->flags & SHF_RD))
- internal_errorf(1, "shf_ungetc: flags %x", shf->flags);
-
- if ((shf->flags & SHF_ERROR) || c == EOF
- || (shf->rp == shf->buf && shf->rnleft))
- return EOF;
-
- if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF)
- return EOF;
-
- if (shf->rp == shf->buf)
- shf->rp = shf->buf + shf->rbsize;
- if (shf->flags & SHF_STRING) {
- /* Can unget what was read, but not something different - we
- * don't want to modify a string.
- */
- if (shf->rp[-1] != c)
- return EOF;
- shf->flags &= ~SHF_EOF;
- shf->rp--;
- shf->rnleft++;
- return c;
- }
- shf->flags &= ~SHF_EOF;
- *--(shf->rp) = c;
- shf->rnleft++;
- return c;
-}
-
-/* Write a character. Returns the character if successful, EOF if
- * the char could not be written.
- */
-int
-shf_putchar(c, shf)
- int c;
- struct shf *shf;
-{
- if (!(shf->flags & SHF_WR))
- internal_errorf(1, "shf_putchar: flags %x", shf->flags);
-
- if (c == EOF)
- return EOF;
-
- if (shf->flags & SHF_UNBUF) {
- char cc = c;
- int n;
-
- if (shf->fd < 0)
- internal_errorf(1, "shf_putchar: no fd");
- if (shf->flags & SHF_ERROR) {
- errno = shf->errno_;
- return EOF;
- }
- while ((n = write(shf->fd, &cc, 1)) != 1)
- if (n < 0) {
- if (errno == EINTR
- && !(shf->flags & SHF_INTERRUPT))
- continue;
- shf->flags |= SHF_ERROR;
- shf->errno_ = errno;
- return EOF;
- }
- } else {
- /* Flush deals with strings and sticky errors */
- if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF)
- return EOF;
- shf->wnleft--;
- *shf->wp++ = c;
- }
-
- return c;
-}
-
-/* Write a string. Returns the length of the string if successful, EOF if
- * the string could not be written.
- */
-int
-shf_puts(s, shf)
- const char *s;
- struct shf *shf;
-{
- if (!s)
- return EOF;
-
- return shf_write(s, strlen(s), shf);
-}
-
-/* Write a buffer. Returns nbytes if successful, EOF if there is an error. */
-int
-shf_write(buf, nbytes, shf)
- const char *buf;
- int nbytes;
- struct shf *shf;
-{
- int orig_nbytes = nbytes;
- int n;
- int ncopy;
-
- if (!(shf->flags & SHF_WR))
- internal_errorf(1, "shf_write: flags %x", shf->flags);
-
- if (nbytes < 0)
- internal_errorf(1, "shf_write: nbytes %d", nbytes);
-
- if ((ncopy = shf->wnleft)) {
- if (ncopy > nbytes)
- ncopy = nbytes;
- memcpy(shf->wp, buf, ncopy);
- nbytes -= ncopy;
- buf += ncopy;
- shf->wp += ncopy;
- shf->wnleft -= ncopy;
- }
- if (nbytes > 0) {
- /* Flush deals with strings and sticky errors */
- if (shf_emptybuf(shf, EB_GROW) == EOF)
- return EOF;
- if (nbytes > shf->wbsize) {
- ncopy = nbytes;
- if (shf->wbsize)
- ncopy -= nbytes % shf->wbsize;
- nbytes -= ncopy;
- while (ncopy > 0) {
- n = write(shf->fd, buf, ncopy);
- if (n < 0) {
- if (errno == EINTR
- && !(shf->flags & SHF_INTERRUPT))
- continue;
- shf->flags |= SHF_ERROR;
- shf->errno_ = errno;
- shf->wnleft = 0;
- /* Note: fwrite(3S) returns 0 for
- * errors - this doesn't */
- return EOF;
- }
- buf += n;
- ncopy -= n;
- }
- }
- if (nbytes > 0) {
- memcpy(shf->wp, buf, nbytes);
- shf->wp += nbytes;
- shf->wnleft -= nbytes;
- }
- }
-
- return orig_nbytes;
-}
-
-int
-#ifdef HAVE_PROTOTYPES
-shf_fprintf(struct shf *shf, const char *fmt, ...)
-#else
-shf_fprintf(shf, fmt, va_alist)
- struct shf *shf;
- const char *fmt;
- va_dcl
-#endif
-{
- va_list args;
- int n;
-
- SH_VA_START(args, fmt);
- n = shf_vfprintf(shf, fmt, args);
- va_end(args);
-
- return n;
-}
-
-int
-#ifdef HAVE_PROTOTYPES
-shf_snprintf(char *buf, int bsize, const char *fmt, ...)
-#else
-shf_snprintf(buf, bsize, fmt, va_alist)
- char *buf;
- int bsize;
- const char *fmt;
- va_dcl
-#endif
-{
- struct shf shf;
- va_list args;
- int n;
-
- if (!buf || bsize <= 0)
- internal_errorf(1, "shf_snprintf: buf %lx, bsize %d",
- (long) buf, bsize);
-
- shf_sopen(buf, bsize, SHF_WR, &shf);
- SH_VA_START(args, fmt);
- n = shf_vfprintf(&shf, fmt, args);
- va_end(args);
- shf_sclose(&shf); /* null terminates */
- return n;
-}
-
-char *
-#ifdef HAVE_PROTOTYPES
-shf_smprintf(const char *fmt, ...)
-#else
-shf_smprintf(fmt, va_alist)
- char *fmt;
- va_dcl
-#endif
-{
- struct shf shf;
- va_list args;
-
- shf_sopen((char *) 0, 0, SHF_WR|SHF_DYNAMIC, &shf);
- SH_VA_START(args, fmt);
- shf_vfprintf(&shf, fmt, args);
- va_end(args);
- return shf_sclose(&shf); /* null terminates */
-}
-
-#undef FP /* if you want floating point stuff */
-
-#define BUF_SIZE 128
-#define FPBUF_SIZE (DMAXEXP+16)/* this must be >
- * MAX(DMAXEXP, log10(pow(2, DSIGNIF)))
- * + ceil(log10(DMAXEXP)) + 8 (I think).
- * Since this is hard to express as a
- * constant, just use a large buffer.
- */
-
-/*
- * What kinda of machine we on? Hopefully the C compiler will optimize
- * this out...
- *
- * For shorts, we want sign extend for %d but not for %[oxu] - on 16 bit
- * machines it don't matter. Assmumes C compiler has converted shorts to
- * ints before pushing them.
- */
-#define POP_INT(f, s, a) (((f) & FL_LONG) ? \
- va_arg((a), unsigned long) \
- : \
- (sizeof(int) < sizeof(long) ? \
- ((s) ? \
- (long) va_arg((a), int) \
- : \
- va_arg((a), unsigned)) \
- : \
- va_arg((a), unsigned)))
-
-#define ABIGNUM 32000 /* big numer that will fit in a short */
-#define LOG2_10 3.321928094887362347870319429 /* log base 2 of 10 */
-
-#define FL_HASH 0x001 /* `#' seen */
-#define FL_PLUS 0x002 /* `+' seen */
-#define FL_RIGHT 0x004 /* `-' seen */
-#define FL_BLANK 0x008 /* ` ' seen */
-#define FL_SHORT 0x010 /* `h' seen */
-#define FL_LONG 0x020 /* `l' seen */
-#define FL_ZERO 0x040 /* `0' seen */
-#define FL_DOT 0x080 /* '.' seen */
-#define FL_UPPER 0x100 /* format character was uppercase */
-#define FL_NUMBER 0x200 /* a number was formated %[douxefg] */
-
-
-#ifdef FP
-#include <math.h>
-
-static double
-my_ceil(d)
- double d;
-{
- double i;
-
- return d - modf(d, &i) + (d < 0 ? -1 : 1);
-}
-#endif /* FP */
-
-int
-shf_vfprintf(shf, fmt, args)
- struct shf *shf;
- const char *fmt;
- va_list args;
-{
- char c, *s;
- int UNINITIALIZED(tmp);
- int field, precision;
- int len;
- int flags;
- unsigned long lnum;
- /* %#o produces the longest output */
- char numbuf[(BITS(long) + 2) / 3 + 1];
- /* this stuff for dealing with the buffer */
- int nwritten = 0;
-#ifdef FP
- /* should be in <math.h>
- * extern double frexp();
- */
- extern char *ecvt();
-
- double fpnum;
- int expo, decpt;
- char style;
- char fpbuf[FPBUF_SIZE];
-#endif /* FP */
-
- if (!fmt)
- return 0;
-
- while ((c = *fmt++)) {
- if (c != '%') {
- shf_putc(c, shf);
- nwritten++;
- continue;
- }
- /*
- * This will accept flags/fields in any order - not
- * just the order specified in printf(3), but this is
- * the way _doprnt() seems to work (on bsd and sysV).
- * The only resriction is that the format character must
- * come last :-).
- */
- flags = field = precision = 0;
- for ( ; (c = *fmt++) ; ) {
- switch (c) {
- case '#':
- flags |= FL_HASH;
- continue;
-
- case '+':
- flags |= FL_PLUS;
- continue;
-
- case '-':
- flags |= FL_RIGHT;
- continue;
-
- case ' ':
- flags |= FL_BLANK;
- continue;
-
- case '0':
- if (!(flags & FL_DOT))
- flags |= FL_ZERO;
- continue;
-
- case '.':
- flags |= FL_DOT;
- precision = 0;
- continue;
-
- case '*':
- tmp = va_arg(args, int);
- if (flags & FL_DOT)
- precision = tmp;
- else if ((field = tmp) < 0) {
- field = -field;
- flags |= FL_RIGHT;
- }
- continue;
-
- case 'l':
- flags |= FL_LONG;
- continue;
-
- case 'h':
- flags |= FL_SHORT;
- continue;
- }
- if (digit(c)) {
- tmp = c - '0';
- while (c = *fmt++, digit(c))
- tmp = tmp * 10 + c - '0';
- --fmt;
- if (tmp < 0) /* overflow? */
- tmp = 0;
- if (flags & FL_DOT)
- precision = tmp;
- else
- field = tmp;
- continue;
- }
- break;
- }
-
- if (precision < 0)
- precision = 0;
-
- if (!c) /* nasty format */
- break;
-
- if (c >= 'A' && c <= 'Z') {
- flags |= FL_UPPER;
- c = c - 'A' + 'a';
- }
-
- switch (c) {
- case 'p': /* pointer */
- flags &= ~(FL_LONG | FL_SHORT);
- if (sizeof(char *) > sizeof(int))
- flags |= FL_LONG; /* hope it fits.. */
- /* aaahhh... */
- case 'd':
- case 'i':
- case 'o':
- case 'u':
- case 'x':
- flags |= FL_NUMBER;
- s = &numbuf[sizeof(numbuf)];
- lnum = POP_INT(flags, c == 'd', args);
- switch (c) {
- case 'd':
- case 'i':
- if (0 > (long) lnum)
- lnum = - (long) lnum, tmp = 1;
- else
- tmp = 0;
- /* aaahhhh..... */
-
- case 'u':
- do {
- *--s = lnum % 10 + '0';
- lnum /= 10;
- } while (lnum);
-
- if (c != 'u') {
- if (tmp)
- *--s = '-';
- else if (flags & FL_PLUS)
- *--s = '+';
- else if (flags & FL_BLANK)
- *--s = ' ';
- }
- break;
-
- case 'o':
- do {
- *--s = (lnum & 0x7) + '0';
- lnum >>= 3;
- } while (lnum);
-
- if ((flags & FL_HASH) && *s != '0')
- *--s = '0';
- break;
-
- case 'p':
- case 'x':
- {
- const char *digits = (flags & FL_UPPER) ?
- "0123456789ABCDEF"
- : "0123456789abcdef";
- do {
- *--s = digits[lnum & 0xf];
- lnum >>= 4;
- } while (lnum);
-
- if (flags & FL_HASH) {
- *--s = (flags & FL_UPPER) ? 'X' : 'x';
- *--s = '0';
- }
- }
- }
- len = &numbuf[sizeof(numbuf)] - s;
- if (flags & FL_DOT) {
- if (precision > len) {
- field = precision;
- flags |= FL_ZERO;
- } else
- precision = len; /* no loss */
- }
- break;
-
-#ifdef FP
- case 'e':
- case 'g':
- case 'f':
- {
- char *p;
-
- /*
- * This could proabably be done better,
- * but it seems to work. Note that gcvt()
- * is not used, as you cannot tell it to
- * not strip the zeros.
- */
- flags |= FL_NUMBER;
- if (!(flags & FL_DOT))
- precision = 6; /* default */
- /*
- * Assumes doubles are pushed on
- * the stack. If this is not so, then
- * FL_LONG/FL_SHORT should be checked.
- */
- fpnum = va_arg(args, double);
- s = fpbuf;
- style = c;
- /*
- * This is the same as
- * expo = ceil(log10(fpnum))
- * but doesn't need -lm. This is an
- * aproximation as expo is rounded up.
- */
- (void) frexp(fpnum, &expo);
- expo = my_ceil(expo / LOG2_10);
-
- if (expo < 0)
- expo = 0;
-
- p = ecvt(fpnum, precision + 1 + expo,
- &decpt, &tmp);
- if (c == 'g') {
- if (decpt < -4 || decpt > precision)
- style = 'e';
- else
- style = 'f';
- if (decpt > 0 && (precision -= decpt) < 0)
- precision = 0;
- }
- if (tmp)
- *--s = '-';
- else if (flags & FL_PLUS)
- *--s = '+';
- else if (flags & FL_BLANK)
- *--s = ' ';
-
- if (style == 'e')
- *s++ = *p++;
- else {
- if (decpt > 0) {
- /* Overflow check - should
- * never have this problem.
- */
- if (decpt >
- &fpbuf[sizeof(fpbuf)]
- - s - 8)
- decpt =
- &fpbuf[sizeof(fpbuf)]
- - s - 8;
- (void) memcpy(s, p, decpt);
- s += decpt;
- p += decpt;
- } else
- *s++ = '0';
- }
-
- /* print the fraction? */
- if (precision > 0) {
- *s++ = '.';
- /* Overflow check - should
- * never have this problem.
- */
- if (precision > &fpbuf[sizeof(fpbuf)]
- - s - 7)
- precision =
- &fpbuf[sizeof(fpbuf)]
- - s - 7;
- for (tmp = decpt; tmp++ < 0 &&
- precision > 0 ; precision--)
- *s++ = '0';
- tmp = strlen(p);
- if (precision > tmp)
- precision = tmp;
- /* Overflow check - should
- * never have this problem.
- */
- if (precision > &fpbuf[sizeof(fpbuf)]
- - s - 7)
- precision =
- &fpbuf[sizeof(fpbuf)]
- - s - 7;
- (void) memcpy(s, p, precision);
- s += precision;
- /*
- * `g' format strips trailing
- * zeros after the decimal.
- */
- if (c == 'g' && !(flags & FL_HASH)) {
- while (*--s == '0')
- ;
- if (*s != '.')
- s++;
- }
- } else if (flags & FL_HASH)
- *s++ = '.';
-
- if (style == 'e') {
- *s++ = (flags & FL_UPPER) ? 'E' : 'e';
- if (--decpt >= 0)
- *s++ = '+';
- else {
- *s++ = '-';
- decpt = -decpt;
- }
- p = &numbuf[sizeof(numbuf)];
- for (tmp = 0; tmp < 2 || decpt ; tmp++) {
- *--p = '0' + decpt % 10;
- decpt /= 10;
- }
- tmp = &numbuf[sizeof(numbuf)] - p;
- (void) memcpy(s, p, tmp);
- s += tmp;
- }
-
- len = s - fpbuf;
- s = fpbuf;
- precision = len;
- break;
- }
-#endif /* FP */
-
- case 's':
- if (!(s = va_arg(args, char *)))
- s = "(null %s)";
- len = strlen(s);
- break;
-
- case 'c':
- flags &= ~FL_DOT;
- numbuf[0] = va_arg(args, int);
- s = numbuf;
- len = 1;
- break;
-
- case '%':
- default:
- numbuf[0] = c;
- s = numbuf;
- len = 1;
- break;
- }
-
- /*
- * At this point s should point to a string that is
- * to be formatted, and len should be the length of the
- * string.
- */
- if (!(flags & FL_DOT) || len < precision)
- precision = len;
- if (field > precision) {
- field -= precision;
- if (!(flags & FL_RIGHT)) {
- field = -field;
- /* skip past sign or 0x when padding with 0 */
- if ((flags & FL_ZERO) && (flags & FL_NUMBER)) {
- if (*s == '+' || *s == '-' || *s ==' ')
- {
- shf_putc(*s, shf);
- s++;
- precision--;
- nwritten++;
- } else if (*s == '0') {
- shf_putc(*s, shf);
- s++;
- nwritten++;
- if (--precision > 0 &&
- (*s | 0x20) == 'x')
- {
- shf_putc(*s, shf);
- s++;
- precision--;
- nwritten++;
- }
- }
- c = '0';
- } else
- c = flags & FL_ZERO ? '0' : ' ';
- if (field < 0) {
- nwritten += -field;
- for ( ; field < 0 ; field++)
- shf_putc(c, shf);
- }
- } else
- c = ' ';
- } else
- field = 0;
-
- if (precision > 0) {
- nwritten += precision;
- for ( ; precision-- > 0 ; s++)
- shf_putc(*s, shf);
- }
- if (field > 0) {
- nwritten += field;
- for ( ; field > 0 ; --field)
- shf_putc(c, shf);
- }
- }
-
- return shf_error(shf) ? EOF : nwritten;
-}
diff --git a/bin/pdksh/shf.h b/bin/pdksh/shf.h
deleted file mode 100644
index 2069d3248b8..00000000000
--- a/bin/pdksh/shf.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* $OpenBSD: shf.h,v 1.1 1996/08/14 06:19:11 downsj Exp $ */
-
-/*
- * Shell file I/O routines
- */
-
-#define SHF_BSIZE 512
-
-#define shf_fileno(shf) ((shf)->fd)
-#define shf_setfileno(shf,nfd) ((shf)->fd = (nfd))
-#define shf_getc(shf) ((shf)->rnleft > 0 ? (shf)->rnleft--, *(shf)->rp++ : \
- shf_getchar(shf))
-#define shf_putc(c, shf) ((shf)->wnleft == 0 ? shf_putchar((c), (shf)) \
- : ((shf)->wnleft--, *(shf)->wp++ = (c)))
-#define shf_eof(shf) ((shf)->flags & SHF_EOF)
-#define shf_error(shf) ((shf)->flags & SHF_ERROR)
-#define shf_errno(shf) ((shf)->errno_)
-#define shf_clearerr(shf) ((shf)->flags &= ~(SHF_EOF | SHF_ERROR))
-
-/* Flags passed to shf_*open() */
-#define SHF_RD 0x0001
-#define SHF_WR 0x0002
-#define SHF_RDWR (SHF_RD|SHF_WR)
-#define SHF_ACCMODE 0x0003 /* mask */
-#define SHF_GETFL 0x0004 /* use fcntl() to figure RD/WR flags */
-#define SHF_UNBUF 0x0008 /* unbuffered I/O */
-#define SHF_CLEXEC 0x0010 /* set close on exec flag */
-#define SHF_MAPHI 0x0020 /* make fd > FDBASE (and close orig)
- * (shf_open() only) */
-#define SHF_DYNAMIC 0x0040 /* string: increase buffer as needed */
-#define SHF_INTERRUPT 0x0080 /* EINTR in read/write causes error */
-/* Flags used internally */
-#define SHF_STRING 0x0100 /* a string, not a file */
-#define SHF_ALLOCS 0x0200 /* shf and shf->buf were alloc()ed */
-#define SHF_ALLOCB 0x0400 /* shf->buf was alloc()ed */
-#define SHF_ERROR 0x0800 /* read()/write() error */
-#define SHF_EOF 0x1000 /* read eof (sticky) */
-#define SHF_READING 0x2000 /* currently reading: rnleft,rp valid */
-#define SHF_WRITING 0x4000 /* currently writing: wnleft,wp valid */
-
-
-struct shf {
- int flags; /* see SHF_* */
- unsigned char *rp; /* read: current position in buffer */
- int rbsize; /* size of buffer (1 if SHF_UNBUF) */
- int rnleft; /* read: how much data left in buffer */
- unsigned char *wp; /* write: current position in buffer */
- int wbsize; /* size of buffer (0 if SHF_UNBUF) */
- int wnleft; /* write: how much space left in buffer */
- unsigned char *buf; /* buffer */
- int fd; /* file descriptor */
- int errno_; /* saved value of errno after error */
- int bsize; /* actual size of buf */
- Area *areap; /* area shf/buf were allocated in */
-};
-
-extern struct shf shf_iob[];
-
-struct shf *shf_open ARGS((const char *name, int oflags, int mode,
- int sflags));
-struct shf *shf_fdopen ARGS((int fd, int sflags, struct shf *shf));
-struct shf *shf_reopen ARGS((int fd, int sflags, struct shf *shf));
-struct shf *shf_sopen ARGS((char *buf, int bsize, int sflags,
- struct shf *shf));
-int shf_close ARGS((struct shf *shf));
-int shf_fdclose ARGS((struct shf *shf));
-char *shf_sclose ARGS((struct shf *shf));
-int shf_finish ARGS((struct shf *shf));
-int shf_flush ARGS((struct shf *shf));
-int shf_seek ARGS((struct shf *shf, off_t where, int from));
-int shf_read ARGS((char *buf, int bsize, struct shf *shf));
-char *shf_getse ARGS((char *buf, int bsize, struct shf *shf));
-int shf_getchar ARGS((struct shf *shf));
-int shf_ungetc ARGS((int c, struct shf *shf));
-int shf_putchar ARGS((int c, struct shf *shf));
-int shf_puts ARGS((const char *s, struct shf *shf));
-int shf_write ARGS((const char *buf, int nbytes, struct shf *shf));
-int shf_fprintf ARGS((struct shf *shf, const char *fmt, ...));
-int shf_snprintf ARGS((char *buf, int bsize, const char *fmt, ...));
-char *shf_smprintf ARGS((const char *fmt, ...));
-int shf_vfprintf ARGS((struct shf *, const char *fmt, va_list args));
diff --git a/bin/pdksh/siglist.in b/bin/pdksh/siglist.in
deleted file mode 100644
index de6f1dd849f..00000000000
--- a/bin/pdksh/siglist.in
+++ /dev/null
@@ -1,56 +0,0 @@
-# $OpenBSD: siglist.in,v 1.1 1996/08/14 06:19:11 downsj Exp $
-#
-# List of signals used to initialize ksh's signal table (see trap.c
-# and siglist.sh).
-#
-# Note that if a system has multiple defines for the same signal
-# (eg, SIGABRT vs SIGIOT, SIGCHLD vs SIGCLD), only the first one
-# will be seen, so the order in this list is important.
-#
- HUP Hangup
- INT Interrupt
- QUIT Quit
- ILL Illegal instruction
- TRAP Trace trap
-# before IOT (ABRT is posix and ABRT is sometimes the same as IOT)
- ABRT Abort
- IOT IOT instruction
- EMT EMT trap
- FPE Floating point exception
- KILL Killed
-# before BUS (linux doesn't really have a BUS, but defines it to UNUSED)
- UNUSED Unused
- BUS Bus error
- SEGV Memory fault
- SYS Bad system call
- PIPE Broken pipe
- ALRM Alarm clock
- TERM Terminated
- STKFLT Stack fault
- IO I/O possible
- XCPU CPU time limit exceeded
- XFSZ File size limit exceeded
- VTALRM Virtual timer expired
- PROF Profiling timer expired
- WINCH Window size change
- LOST File lock lost
- USR1 User defined signal 1
- USR2 User defined signal 2
- PWR Power-fail/Restart
- POLL Pollable event occurred
- STOP Stopped (signal)
- TSTP Stopped
- CONT Continued
-# before CLD (CHLD is posix and CHLD is sometimes the same as CLD)
- CHLD Child exited
- CLD Child exited
- TTIN Stopped (tty input)
- TTOU Stopped (tty output)
- INFO Information request
- URG Urgent I/O condition
-# Solaris (svr4?) signals
- WAITING No runnable LWPs
- LWP Inter-LWP signal
- FREEZE Checkpoint freeze
- THAW Checkpoint thaw
- CANCEL Thread cancellation
diff --git a/bin/pdksh/siglist.sh b/bin/pdksh/siglist.sh
deleted file mode 100644
index 123b190140c..00000000000
--- a/bin/pdksh/siglist.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/sh
-# $OpenBSD: siglist.sh,v 1.4 1997/06/19 13:58:47 kstailey Exp $
-
-#
-# Script to generate a sorted, complete list of signals, suitable
-# for inclusion in trap.c as array initializer.
-#
-
-set -e
-
-in=tmpi$$.c
-out=tmpo$$.c
-ecode=1
-trapsigs='0 1 2 13 15'
-trap 'rm -f $in $out; trap 0; exit $ecode' $trapsigs
-
-CPP="${1-cc -E}"
-
-# The trap here to make up for a bug in bash (1.14.3(1)) that calls the trap
-(trap $trapsigs;
- echo '#include "sh.h"';
- echo ' { QwErTy SIGNALS , "DUMMY" , "hook for number of signals" },';
- sed -e '/^[ ]*#/d' -e 's/^[ ]*\([^ ][^ ]*\)[ ][ ]*\(.*[^ ]\)[ ]*$/#ifdef SIG\1\
- { QwErTy SIG\1 , "\1", "\2" },\
-#endif/') > $in
-$CPP $in > $out
-sed -n 's/{ QwErTy/{/p' < $out | awk '{print NR, $0}' | sort +2n +0n |
- sed 's/^[0-9]* //' |
- awk 'BEGIN { last=0; nsigs=0; }
- {
- if ($2 ~ /^[0-9][0-9]*$/ && $3 == ",") {
- n = $2;
- if (n > 0 && n != last) {
- while (++last < n) {
- printf "\t{ %d , (char *) 0, `Signal %d` } ,\n", last, last;
- }
- print;
- }
- }
- }' |
- tr '`' '"' | grep -v '"DUMMY"'
-ecode=0
diff --git a/bin/pdksh/syn.c b/bin/pdksh/syn.c
deleted file mode 100644
index 4b37baa819d..00000000000
--- a/bin/pdksh/syn.c
+++ /dev/null
@@ -1,948 +0,0 @@
-/* $OpenBSD: syn.c,v 1.8 1997/09/01 18:30:12 deraadt Exp $ */
-
-/*
- * shell parser (C version)
- */
-
-#include "sh.h"
-#include "c_test.h"
-
-struct multiline_state {
- int on; /* set in multiline commands (\n becomes ;) */
- int start_token; /* token multiline is for (eg, FOR, {, etc.) */
- int start_line; /* line multiline command started on */
-};
-
-static void yyparse ARGS((void));
-static struct op *pipeline ARGS((int cf));
-static struct op *andor ARGS((void));
-static struct op *c_list ARGS((void));
-static struct ioword *synio ARGS((int cf));
-static void musthave ARGS((int c, int cf));
-static struct op *nested ARGS((int type, int smark, int emark));
-static struct op *get_command ARGS((int cf));
-static struct op *dogroup ARGS((void));
-static struct op *thenpart ARGS((void));
-static struct op *elsepart ARGS((void));
-static struct op *caselist ARGS((void));
-static struct op *casepart ARGS((int endtok));
-static struct op *function_body ARGS((char *name, int ksh_func));
-static char ** wordlist ARGS((void));
-static struct op *block ARGS((int type, struct op *t1, struct op *t2,
- char **wp));
-static struct op *newtp ARGS((int type));
-static void syntaxerr ARGS((const char *what))
- GCC_FUNC_ATTR(noreturn);
-static void multiline_push ARGS((struct multiline_state *save, int tok));
-static void multiline_pop ARGS((struct multiline_state *saved));
-static int assign_command ARGS((char *s));
-static int inalias ARGS((struct source *s));
-#ifdef KSH
-static int dbtestp_isa ARGS((Test_env *te, Test_meta meta));
-static const char *dbtestp_getopnd ARGS((Test_env *te, Test_op op,
- int do_eval));
-static int dbtestp_eval ARGS((Test_env *te, Test_op op, const char *opnd1,
- const char *opnd2, int do_eval));
-static void dbtestp_error ARGS((Test_env *te, int offset, const char *msg));
-#endif /* KSH */
-
-static struct op *outtree; /* yyparse output */
-
-static struct multiline_state multiline; /* \n changed to ; */
-
-static int reject; /* token(cf) gets symbol again */
-static int symbol; /* yylex value */
-
-#define REJECT (reject = 1)
-#define ACCEPT (reject = 0)
-#define token(cf) \
- ((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf)))
-#define tpeek(cf) \
- ((reject) ? (symbol) : (REJECT, symbol = yylex(cf)))
-
-static void
-yyparse()
-{
- int c;
-
- ACCEPT;
- yynerrs = 0;
-
- outtree = c_list();
- c = tpeek(0);
- if (c == 0 && !outtree)
- outtree = newtp(TEOF);
- else if (c != '\n' && c != 0)
- syntaxerr((char *) 0);
-}
-
-static struct op *
-pipeline(cf)
- int cf;
-{
- register struct op *t, *p, *tl = NULL;
-
- t = get_command(cf);
- if (t != NULL) {
- while (token(0) == '|') {
- if ((p = get_command(CONTIN)) == NULL)
- syntaxerr((char *) 0);
- if (tl == NULL)
- t = tl = block(TPIPE, t, p, NOWORDS);
- else
- tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);
- }
- REJECT;
- }
- return (t);
-}
-
-static struct op *
-andor()
-{
- register struct op *t, *p;
- register int c;
-
- t = pipeline(0);
- if (t != NULL) {
- while ((c = token(0)) == LOGAND || c == LOGOR) {
- if ((p = pipeline(CONTIN)) == NULL)
- syntaxerr((char *) 0);
- t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
- }
- REJECT;
- }
- return (t);
-}
-
-static struct op *
-c_list()
-{
- register struct op *t, *p, *tl = NULL;
- register int c;
-
- t = andor();
- if (t != NULL) {
- /* Token has always been read/rejected at this point, so
- * we don't worray about what flags to pass token()
- */
- while ((c = token(0)) == ';' || c == '&' || c == COPROC ||
- (c == '\n' && (multiline.on || inalias(source))))
- {
- if (c == '&' || c == COPROC) {
- int type = c == '&' ? TASYNC : TCOPROC;
- if (tl)
- tl->right = block(type, tl->right,
- NOBLOCK, NOWORDS);
- else
- t = block(type, t, NOBLOCK, NOWORDS);
- }
- if ((p = andor()) == NULL)
- return (t);
- if (tl == NULL)
- t = tl = block(TLIST, t, p, NOWORDS);
- else
- tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
- }
- REJECT;
- }
- return (t);
-}
-
-static struct ioword *
-synio(cf)
- int cf;
-{
- register struct ioword *iop;
- int ishere;
-
- if (tpeek(cf) != REDIR)
- return NULL;
- ACCEPT;
- iop = yylval.iop;
- ishere = (iop->flag&IOTYPE) == IOHERE;
- musthave(LWORD, ishere ? HEREDELIM : 0);
- if (ishere) {
- iop->delim = yylval.cp;
- if (*ident != 0) /* unquoted */
- iop->flag |= IOEVAL;
- if (herep >= &heres[HERES])
- yyerror("too many <<'s\n");
- *herep++ = iop;
- } else
- iop->name = yylval.cp;
- return iop;
-}
-
-static void
-musthave(c, cf)
- int c, cf;
-{
- if ((token(cf)) != c)
- syntaxerr((char *) 0);
-}
-
-static struct op *
-nested(type, smark, emark)
- int type, smark, emark;
-{
- register struct op *t;
- struct multiline_state old_multiline;
-
- multiline_push(&old_multiline, smark);
- t = c_list();
- musthave(emark, KEYWORD|ALIAS);
- multiline_pop(&old_multiline);
- return (block(type, t, NOBLOCK, NOWORDS));
-}
-
-static struct op *
-get_command(cf)
- int cf;
-{
- register struct op *t;
- register int c, iopn = 0, syniocf;
- struct ioword *iop, **iops;
- XPtrV args, vars;
- struct multiline_state old_multiline;
-
- iops = (struct ioword **) alloc(sizeofN(struct ioword *, NUFILE+1),
- ATEMP);
- XPinit(args, 16);
- XPinit(vars, 16);
-
- /* Don't want to pass CONTIN if reading interactively as just hitting
- * return would print PS2 instead of PS1.
- */
- if (multiline.on || inalias(source))
- cf = CONTIN;
- syniocf = KEYWORD|ALIAS;
- switch (c = token(cf|KEYWORD|ALIAS|VARASN)) {
- default:
- REJECT;
- afree((void*) iops, ATEMP);
- XPfree(args);
- XPfree(vars);
- return NULL; /* empty line */
-
- case LWORD:
- case REDIR:
- REJECT;
- syniocf &= ~(KEYWORD|ALIAS);
- t = newtp(TCOM);
- while (1) {
- cf = (t->u.evalflags ? ARRAYVAR : 0)
- | (XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD);
- switch (tpeek(cf)) {
- case REDIR:
- if (iopn >= NUFILE)
- yyerror("too many redirections\n");
- iops[iopn++] = synio(cf);
- break;
-
- case LWORD:
- ACCEPT;
- /* the iopn == 0 and XPsize(vars) == 0 are
- * dubious but at&t ksh acts this way
- */
- if (iopn == 0 && XPsize(vars) == 0
- && XPsize(args) == 0
- && assign_command(ident))
- t->u.evalflags = DOVACHECK;
- if ((XPsize(args) == 0 || Flag(FKEYWORD))
- && is_wdvarassign(yylval.cp))
- XPput(vars, yylval.cp);
- else
- XPput(args, yylval.cp);
- break;
-
- case '(':
- /* Check for "> foo (echo hi)", which at&t ksh
- * allows (not POSIX, but not disallowed)
- */
- afree(t, ATEMP);
- if (XPsize(args) == 0 && XPsize(vars) == 0) {
- ACCEPT;
- goto Subshell;
- }
- /* Must be a function */
- if (iopn != 0 || XPsize(args) != 1
- || XPsize(vars) != 0)
- syntaxerr((char *) 0);
- ACCEPT;
- /*(*/
- musthave(')', 0);
- t = function_body(XPptrv(args)[0], FALSE);
- goto Leave;
-
- default:
- goto Leave;
- }
- }
- Leave:
- break;
-
- Subshell:
- case '(':
- t = nested(TPAREN, '(', ')');
- break;
-
- case '{': /*}*/
- t = nested(TBRACE, '{', '}');
- break;
-
-#ifdef KSH
- case MDPAREN:
- {
- static const char let_cmd[] = { CHAR, 'l', CHAR, 'e',
- CHAR, 't', EOS };
- syniocf &= ~(KEYWORD|ALIAS);
- t = newtp(TCOM);
- ACCEPT;
- XPput(args, wdcopy(let_cmd, ATEMP));
- musthave(LWORD,LETEXPR);
- XPput(args, yylval.cp);
- break;
- }
-#endif /* KSH */
-
-#ifdef KSH
- case DBRACKET: /* [[ .. ]] */
- syniocf &= ~(KEYWORD|ALIAS);
- t = newtp(TDBRACKET);
- ACCEPT;
- {
- Test_env te;
-
- te.flags = TEF_DBRACKET;
- te.pos.av = &args;
- te.isa = dbtestp_isa;
- te.getopnd = dbtestp_getopnd;
- te.eval = dbtestp_eval;
- te.error = dbtestp_error;
-
- test_parse(&te);
- }
- break;
-#endif /* KSH */
-
- case FOR:
- case SELECT:
- t = newtp((c == FOR) ? TFOR : TSELECT);
- musthave(LWORD, ARRAYVAR);
- if (!is_wdvarname(yylval.cp, TRUE))
- yyerror("%s: bad identifier\n",
- c == FOR ? "for" : "select");
- t->str = str_save(ident, ATEMP);
- multiline_push(&old_multiline, c);
- t->vars = wordlist();
- t->left = dogroup();
- multiline_pop(&old_multiline);
- break;
-
- case WHILE:
- case UNTIL:
- multiline_push(&old_multiline, c);
- t = newtp((c == WHILE) ? TWHILE : TUNTIL);
- t->left = c_list();
- t->right = dogroup();
- multiline_pop(&old_multiline);
- break;
-
- case CASE:
- t = newtp(TCASE);
- musthave(LWORD, 0);
- t->str = yylval.cp;
- multiline_push(&old_multiline, c);
- t->left = caselist();
- multiline_pop(&old_multiline);
- break;
-
- case IF:
- multiline_push(&old_multiline, c);
- t = newtp(TIF);
- t->left = c_list();
- t->right = thenpart();
- musthave(FI, KEYWORD|ALIAS);
- multiline_pop(&old_multiline);
- break;
-
- case BANG:
- syniocf &= ~(KEYWORD|ALIAS);
- t = pipeline(0);
- if (t == (struct op *) 0)
- syntaxerr((char *) 0);
- t = block(TBANG, NOBLOCK, t, NOWORDS);
- break;
-
- case TIME:
- syniocf &= ~(KEYWORD|ALIAS);
- t = pipeline(0);
- t = block(TTIME, t, NOBLOCK, NOWORDS);
- break;
-
- case FUNCTION:
- musthave(LWORD, 0);
- t = function_body(yylval.cp, TRUE);
- break;
- }
-
- while ((iop = synio(syniocf)) != NULL) {
- if (iopn >= NUFILE)
- yyerror("too many redirections\n");
- iops[iopn++] = iop;
- }
-
- if (iopn == 0) {
- afree((void*) iops, ATEMP);
- t->ioact = NULL;
- } else {
- iops[iopn++] = NULL;
- iops = (struct ioword **) aresize((void*) iops,
- sizeofN(struct ioword *, iopn), ATEMP);
- t->ioact = iops;
- }
-
- if (t->type == TCOM || t->type == TDBRACKET) {
- XPput(args, NULL);
- t->args = (char **) XPclose(args);
- XPput(vars, NULL);
- t->vars = (char **) XPclose(vars);
- } else {
- XPfree(args);
- XPfree(vars);
- }
-
- return t;
-}
-
-static struct op *
-dogroup()
-{
- register int c;
- register struct op *list;
-
- c = token(CONTIN|KEYWORD|ALIAS);
- /* A {...} can be used instead of do...done for for/select loops
- * but not for while/until loops - we don't need to check if it
- * is a while loop because it would have been parsed as part of
- * the conditional command list...
- */
- if (c == DO)
- c = DONE;
- else if (c == '{')
- c = '}';
- else
- syntaxerr((char *) 0);
- list = c_list();
- musthave(c, KEYWORD|ALIAS);
- return list;
-}
-
-static struct op *
-thenpart()
-{
- register struct op *t;
-
- musthave(THEN, KEYWORD|ALIAS);
- t = newtp(0);
- t->left = c_list();
- if (t->left == NULL)
- syntaxerr((char *) 0);
- t->right = elsepart();
- return (t);
-}
-
-static struct op *
-elsepart()
-{
- register struct op *t;
-
- switch (token(KEYWORD|ALIAS|VARASN)) {
- case ELSE:
- if ((t = c_list()) == NULL)
- syntaxerr((char *) 0);
- return (t);
-
- case ELIF:
- t = newtp(TELIF);
- t->left = c_list();
- t->right = thenpart();
- return (t);
-
- default:
- REJECT;
- }
- return NULL;
-}
-
-static struct op *
-caselist()
-{
- register struct op *t, *tl;
- int c;
-
- c = token(CONTIN|KEYWORD|ALIAS);
- /* A {...} can be used instead of in...esac for case statements */
- if (c == IN)
- c = ESAC;
- else if (c == '{')
- c = '}';
- else
- syntaxerr((char *) 0);
- t = tl = NULL;
- while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) { /* no ALIAS here */
- struct op *tc = casepart(c);
- if (tl == NULL)
- t = tl = tc, tl->right = NULL;
- else
- tl->right = tc, tl = tc;
- }
- musthave(c, KEYWORD|ALIAS);
- return (t);
-}
-
-static struct op *
-casepart(endtok)
- int endtok;
-{
- register struct op *t;
- register int c;
- XPtrV ptns;
-
- XPinit(ptns, 16);
- t = newtp(TPAT);
- c = token(CONTIN|KEYWORD); /* no ALIAS here */
- if (c != '(')
- REJECT;
- do {
- musthave(LWORD, 0);
- XPput(ptns, yylval.cp);
- } while ((c = token(0)) == '|');
- REJECT;
- XPput(ptns, NULL);
- t->vars = (char **) XPclose(ptns);
- musthave(')', 0);
-
- t->left = c_list();
- if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok)
- musthave(BREAK, CONTIN|KEYWORD|ALIAS);
- return (t);
-}
-
-static struct op *
-function_body(name, ksh_func)
- char *name;
- int ksh_func; /* function foo { ... } vs foo() { .. } */
-{
- XString xs;
- char *xp, *p;
- struct op *t;
- int old_func_parse;
-
- Xinit(xs, xp, 16, ATEMP);
- for (p = name; ; ) {
- if ((*p == EOS && Xlength(xs, xp) == 0)
- || (*p != EOS && *p != CHAR && *p != QCHAR
- && *p != OQUOTE && *p != CQUOTE))
- {
- p = snptreef((char *) 0, 32, "%S", name);
- yyerror("%s: invalid function name\n", p);
- }
- Xcheck(xs, xp);
- if (*p == EOS) {
- Xput(xs, xp, '\0');
- break;
- } else if (*p == CHAR || *p == QCHAR) {
- Xput(xs, xp, p[1]);
- p += 2;
- } else
- p++; /* OQUOTE/CQUOTE */
- }
- t = newtp(TFUNCT);
- t->str = Xclose(xs, xp);
- t->u.ksh_func = ksh_func;
-
- /* Note that POSIX allows only compound statements after foo(), sh and
- * at&t ksh allow any command, go with the later since it shouldn't
- * break anything. However, for function foo, at&t ksh only accepts
- * an open-brace.
- */
- if (ksh_func) {
- musthave('{', CONTIN|KEYWORD|ALIAS); /* } */
- REJECT;
- }
-
- old_func_parse = e->flags & EF_FUNC_PARSE;
- e->flags |= EF_FUNC_PARSE;
- if ((t->left = get_command(CONTIN)) == (struct op *) 0) {
- /* create empty command so foo(): will work */
- t->left = newtp(TCOM);
- t->args = (char **) alloc(sizeof(char *), ATEMP);
- t->args[0] = (char *) 0;
- t->vars = (char **) alloc(sizeof(char *), ATEMP);
- t->vars[0] = (char *) 0;
- }
- if (!old_func_parse)
- e->flags &= ~EF_FUNC_PARSE;
-
- return t;
-}
-
-static char **
-wordlist()
-{
- register int c;
- XPtrV args;
-
- XPinit(args, 16);
- if ((c = token(CONTIN|KEYWORD|ALIAS)) != IN) {
- if (c != ';') /* non-POSIX, but at&t ksh accepts a ; here */
- REJECT;
- return NULL;
- }
- while ((c = token(0)) == LWORD)
- XPput(args, yylval.cp);
- if (c != '\n' && c != ';')
- syntaxerr((char *) 0);
- if (XPsize(args) == 0) {
- XPfree(args);
- return NULL;
- } else {
- XPput(args, NULL);
- return (char **) XPclose(args);
- }
-}
-
-/*
- * supporting functions
- */
-
-static struct op *
-block(type, t1, t2, wp)
- int type;
- struct op *t1, *t2;
- char **wp;
-{
- register struct op *t;
-
- t = newtp(type);
- t->left = t1;
- t->right = t2;
- t->vars = wp;
- return (t);
-}
-
-const struct tokeninfo {
- const char *name;
- short val;
- short reserved;
-} tokentab[] = {
- /* Reserved words */
- { "if", IF, TRUE },
- { "then", THEN, TRUE },
- { "else", ELSE, TRUE },
- { "elif", ELIF, TRUE },
- { "fi", FI, TRUE },
- { "case", CASE, TRUE },
- { "esac", ESAC, TRUE },
- { "for", FOR, TRUE },
-#ifdef KSH
- { "select", SELECT, TRUE },
-#endif /* KSH */
- { "while", WHILE, TRUE },
- { "until", UNTIL, TRUE },
- { "do", DO, TRUE },
- { "done", DONE, TRUE },
- { "in", IN, TRUE },
- { "function", FUNCTION, TRUE },
- { "time", TIME, TRUE },
- { "{", '{', TRUE },
- { "}", '}', TRUE },
- { "!", BANG, TRUE },
-#ifdef KSH
- { "[[", DBRACKET, TRUE },
-#endif /* KSH */
- /* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */
- { "&&", LOGAND, FALSE },
- { "||", LOGOR, FALSE },
- { ";;", BREAK, FALSE },
-#ifdef KSH
- { "((", MDPAREN, FALSE },
- { "|&", COPROC, FALSE },
-#endif /* KSH */
- /* and some special cases... */
- { "newline", '\n', FALSE },
- { 0 }
-};
-
-void
-initkeywords()
-{
- register struct tokeninfo const *tt;
- register struct tbl *p;
-
- tinit(&keywords, APERM, 32); /* must be 2^n (currently 20 keywords) */
- for (tt = tokentab; tt->name; tt++) {
- if (tt->reserved) {
- p = tenter(&keywords, tt->name, hash(tt->name));
- p->flag |= DEFINED|ISSET;
- p->type = CKEYWD;
- p->val.i = tt->val;
- }
- }
-}
-
-static void
-syntaxerr(what)
- const char *what;
-{
- char redir[6]; /* 2<<- is the longest redirection, I think */
- const char *s;
- struct tokeninfo const *tt;
- int c;
-
- if (!what)
- what = "unexpected";
- REJECT;
- c = token(0);
- Again:
- switch (c) {
- case 0:
- if (multiline.on && multiline.start_token) {
- multiline.on = FALSE; /* avoid infinate loops */
- c = multiline.start_token;
- source->errline = multiline.start_line;
- what = "unmatched";
- goto Again;
- }
- /* don't quote the EOF */
- yyerror("syntax error: unexpected EOF\n");
- /*NOTREACHED*/
-
- case LWORD:
- s = snptreef((char *) 0, 32, "%S", yylval.cp);
- break;
-
- case REDIR:
- s = snptreef(redir, sizeof(redir), "%R", yylval.iop);
- break;
-
- default:
- for (tt = tokentab; tt->name; tt++)
- if (tt->val == c)
- break;
- if (tt->name)
- s = tt->name;
- else {
- if (c > 0 && c < 256) {
- redir[0] = c;
- redir[1] = '\0';
- } else
- shf_snprintf(redir, sizeof(redir),
- "?%d", c);
- s = redir;
- }
- }
- yyerror("syntax error: `%s' %s\n", s, what);
-}
-
-static void
-multiline_push(save, tok)
- struct multiline_state *save;
- int tok;
-{
- *save = multiline;
- multiline.on = TRUE;
- multiline.start_token = tok;
- multiline.start_line = source->line;
-}
-
-static void
-multiline_pop(saved)
- struct multiline_state *saved;
-{
- multiline = *saved;
-}
-
-static struct op *
-newtp(type)
- int type;
-{
- register struct op *t;
-
- t = (struct op *) alloc(sizeof(*t), ATEMP);
- t->type = type;
- t->u.evalflags = 0;
- t->args = t->vars = NULL;
- t->ioact = NULL;
- t->left = t->right = NULL;
- t->str = NULL;
- return (t);
-}
-
-struct op *
-compile(s)
- Source *s;
-{
- yynerrs = 0;
- multiline.on = s->type == SSTRING;
- multiline.start_token = 0;
- multiline.start_line = 0;
- herep = heres;
- source = s;
- yyparse();
- return outtree;
-}
-
-/* This kludge exists to take care of sh/at&t ksh oddity in which
- * the arguments of alias/export/readonly/typeset have no field
- * splitting, file globbing, or (normal) tilde expansion done.
- * at&t ksh seems to do something similar to this since
- * $ touch a=a; typeset a=[ab]; echo "$a"
- * a=[ab]
- * $ x=typeset; $x a=[ab]; echo "$a"
- * a=a
- * $
- */
-static int
-assign_command(s)
- char *s;
-{
- char c = *s;
-
- if (Flag(FPOSIX) || !*s)
- return 0;
- return (c == 'a' && strcmp(s, "alias") == 0)
- || (c == 'e' && strcmp(s, "export") == 0)
- || (c == 'r' && strcmp(s, "readonly") == 0)
- || (c == 't' && strcmp(s, "typeset") == 0);
-}
-
-/* Check if we are in the middle of reading an alias */
-static int
-inalias(s)
- struct source *s;
-{
- for (; s && s->type == SALIAS; s = s->next)
- if (!(s->flags & SF_ALIASEND))
- return 1;
- return 0;
-}
-
-
-#ifdef KSH
-/* Order important - indexed by Test_meta values
- * Note that ||, &&, ( and ) can't appear in as unquoted strings
- * in normal shell input, so these can be interpreted unambiguously
- * in the evaluation pass.
- */
-static const char dbtest_or[] = { CHAR, '|', CHAR, '|', EOS };
-static const char dbtest_and[] = { CHAR, '&', CHAR, '&', EOS };
-static const char dbtest_not[] = { CHAR, '!', EOS };
-static const char dbtest_oparen[] = { CHAR, '(', EOS };
-static const char dbtest_cparen[] = { CHAR, ')', EOS };
-const char *const dbtest_tokens[] = {
- dbtest_or, dbtest_and, dbtest_not,
- dbtest_oparen, dbtest_cparen
- };
-const char db_close[] = { CHAR, ']', CHAR, ']', EOS };
-const char db_lthan[] = { CHAR, '<', EOS };
-const char db_gthan[] = { CHAR, '>', EOS };
-
-/* Test if the current token is a whatever. Accepts the current token if
- * it is. Returns 0 if it is not, non-zero if it is (in the case of
- * TM_UNOP and TM_BINOP, the returned value is a Test_op).
- */
-static int
-dbtestp_isa(te, meta)
- Test_env *te;
- Test_meta meta;
-{
- int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN));
- int uqword = 0;
- char *save = (char *) 0;
- int ret = 0;
-
- /* unquoted word? */
- uqword = c == LWORD && *ident;
-
- if (meta == TM_OR)
- ret = c == LOGOR;
- else if (meta == TM_AND)
- ret = c == LOGAND;
- else if (meta == TM_NOT)
- ret = uqword && strcmp(yylval.cp, dbtest_tokens[(int) TM_NOT]) == 0;
- else if (meta == TM_OPAREN)
- ret = c == '(' /*)*/;
- else if (meta == TM_CPAREN)
- ret = c == /*(*/ ')';
- else if (meta == TM_UNOP || meta == TM_BINOP) {
- if (meta == TM_BINOP && c == REDIR
- && (yylval.iop->flag == IOREAD
- || yylval.iop->flag == IOWRITE))
- {
- ret = 1;
- save = wdcopy(yylval.iop->flag == IOREAD ?
- db_lthan : db_gthan, ATEMP);
- } else if (uqword && (ret = (int) test_isop(te, meta, ident)))
- save = yylval.cp;
- } else /* meta == TM_END */
- ret = uqword && strcmp(yylval.cp, db_close) == 0;
- if (ret) {
- ACCEPT;
- if (meta != TM_END) {
- if (!save)
- save = wdcopy(dbtest_tokens[(int) meta], ATEMP);
- XPput(*te->pos.av, save);
- }
- }
- return ret;
-}
-
-static const char *
-dbtestp_getopnd(te, op, do_eval)
- Test_env *te;
- Test_op op;
- int do_eval;
-{
- int c = tpeek(ARRAYVAR);
-
- if (c != LWORD)
- return (const char *) 0;
-
- ACCEPT;
- XPput(*te->pos.av, yylval.cp);
-
- return null;
-}
-
-static int
-dbtestp_eval(te, op, opnd1, opnd2, do_eval)
- Test_env *te;
- Test_op op;
- const char *opnd1;
- const char *opnd2;
- int do_eval;
-{
- return 1;
-}
-
-static void
-dbtestp_error(te, offset, msg)
- Test_env *te;
- int offset;
- const char *msg;
-{
- te->flags |= TEF_ERROR;
-
- if (offset < 0) {
- REJECT;
- /* Kludgy to say the least... */
- symbol = LWORD;
- yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av)
- + offset);
- }
- syntaxerr(msg);
-}
-#endif /* KSH */
diff --git a/bin/pdksh/table.c b/bin/pdksh/table.c
deleted file mode 100644
index a390c172c77..00000000000
--- a/bin/pdksh/table.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/* $OpenBSD: table.c,v 1.4 1997/06/19 13:58:47 kstailey Exp $ */
-
-/*
- * dynamic hashed associative table for commands and variables
- */
-
-#include "sh.h"
-
-#define INIT_TBLS 8 /* initial table size (power of 2) */
-
-static void texpand ARGS((struct table *tp, int nsize));
-static int tnamecmp ARGS((void *p1, void *p2));
-
-
-unsigned int
-hash(n)
- register const char * n;
-{
- register unsigned int h = 0;
-
- while (*n != '\0')
- h = 2*h + *n++;
- return h * 32821; /* scatter bits */
-}
-
-void
-tinit(tp, ap, tsize)
- register struct table *tp;
- register Area *ap;
- int tsize;
-{
- tp->areap = ap;
- tp->tbls = NULL;
- tp->size = tp->nfree = 0;
- if (tsize)
- texpand(tp, tsize);
-}
-
-static void
-texpand(tp, nsize)
- register struct table *tp;
- int nsize;
-{
- register int i;
- register struct tbl *tblp, **p;
- register struct tbl **ntblp, **otblp = tp->tbls;
- int osize = tp->size;
-
- ntblp = (struct tbl**) alloc(sizeofN(struct tbl *, nsize), tp->areap);
- for (i = 0; i < nsize; i++)
- ntblp[i] = NULL;
- tp->size = nsize;
- tp->nfree = 8*nsize/10; /* table can get 80% full */
- tp->tbls = ntblp;
- if (otblp == NULL)
- return;
- for (i = 0; i < osize; i++)
- if ((tblp = otblp[i]) != NULL)
- if ((tblp->flag&DEFINED)) {
- for (p = &ntblp[hash(tblp->name)
- & (tp->size-1)];
- *p != NULL; p--)
- if (p == ntblp) /* wrap */
- p += tp->size;
- *p = tblp;
- tp->nfree--;
- } else if (!(tblp->flag & FINUSE)) {
- afree((void*)tblp, tp->areap);
- }
- afree((void*)otblp, tp->areap);
-}
-
-struct tbl *
-tsearch(tp, n, h)
- register struct table *tp; /* table */
- register const char *n; /* name to enter */
- unsigned int h; /* hash(n) */
-{
- register struct tbl **pp, *p;
-
- if (tp->size == 0)
- return NULL;
-
- /* search for name in hashed table */
- for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp) != NULL; pp--) {
- if (*p->name == *n && strcmp(p->name, n) == 0
- && (p->flag&DEFINED))
- return p;
- if (pp == tp->tbls) /* wrap */
- pp += tp->size;
- }
-
- return NULL;
-}
-
-struct tbl *
-tenter(tp, n, h)
- register struct table *tp; /* table */
- register const char *n; /* name to enter */
- unsigned int h; /* hash(n) */
-{
- register struct tbl **pp, *p;
- register int len;
-
- if (tp->size == 0)
- texpand(tp, INIT_TBLS);
- Search:
- /* search for name in hashed table */
- for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp) != NULL; pp--) {
- if (*p->name == *n && strcmp(p->name, n) == 0)
- return p; /* found */
- if (pp == tp->tbls) /* wrap */
- pp += tp->size;
- }
-
- if (tp->nfree <= 0) { /* too full */
- texpand(tp, 2*tp->size);
- goto Search;
- }
-
- /* create new tbl entry */
- len = strlen(n) + 1;
- p = (struct tbl *) alloc(offsetof(struct tbl, name[0]) + len,
- tp->areap);
- p->flag = 0;
- p->type = 0;
- p->areap = tp->areap;
- p->u2.field = 0;
- p->u.array = (struct tbl *)0;
- memcpy(p->name, n, len);
-
- /* enter in tp->tbls */
- tp->nfree--;
- *pp = p;
- return p;
-}
-
-void
-tdelete(p)
- register struct tbl *p;
-{
- p->flag = 0;
-}
-
-void
-twalk(ts, tp)
- struct tstate *ts;
- struct table *tp;
-{
- ts->left = tp->size;
- ts->next = tp->tbls;
-}
-
-struct tbl *
-tnext(ts)
- struct tstate *ts;
-{
- while (--ts->left >= 0) {
- struct tbl *p = *ts->next++;
- if (p != NULL && (p->flag&DEFINED))
- return p;
- }
- return NULL;
-}
-
-static int
-tnamecmp(p1, p2)
- void *p1, *p2;
-{
- return strcmp(((struct tbl *)p1)->name, ((struct tbl *)p2)->name);
-}
-
-struct tbl **
-tsort(tp)
- register struct table *tp;
-{
- register int i;
- register struct tbl **p, **sp, **dp;
-
- p = (struct tbl **)alloc(sizeofN(struct tbl *, tp->size+1), ATEMP);
- sp = tp->tbls; /* source */
- dp = p; /* dest */
- for (i = 0; i < tp->size; i++)
- if ((*dp = *sp++) != NULL && (((*dp)->flag&DEFINED) ||
- ((*dp)->flag&ARRAY)))
- dp++;
- i = dp - p;
- qsortp((void**)p, (size_t)i, tnamecmp);
- p[i] = NULL;
- return p;
-}
-
-#ifdef PERF_DEBUG /* performance debugging */
-
-void tprintinfo ARGS((struct table *tp));
-
-void
-tprintinfo(tp)
- struct table *tp;
-{
- struct tbl *te;
- char *n;
- unsigned int h;
- int ncmp;
- int totncmp = 0, maxncmp = 0;
- int nentries = 0;
- struct tstate ts;
-
- shellf("table size %d, nfree %d\n", tp->size, tp->nfree);
- shellf(" Ncmp name\n");
- twalk(&ts, tp);
- while ((te = tnext(&ts))) {
- register struct tbl **pp, *p;
-
- h = hash(n = te->name);
- ncmp = 0;
-
- /* taken from tsearch() and added counter */
- for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp); pp--) {
- ncmp++;
- if (*p->name == *n && strcmp(p->name, n) == 0
- && (p->flag&DEFINED))
- break; /* return p; */
- if (pp == tp->tbls) /* wrap */
- pp += tp->size;
- }
- shellf(" %4d %s\n", ncmp, n);
- totncmp += ncmp;
- nentries++;
- if (ncmp > maxncmp)
- maxncmp = ncmp;
- }
- if (nentries)
- shellf(" %d entries, worst ncmp %d, avg ncmp %d.%02d\n",
- nentries, maxncmp,
- totncmp / nentries,
- (totncmp % nentries) * 100 / nentries);
-}
-#endif /* PERF_DEBUG */
diff --git a/bin/pdksh/table.h b/bin/pdksh/table.h
deleted file mode 100644
index 75215719c22..00000000000
--- a/bin/pdksh/table.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/* $OpenBSD: table.h,v 1.3 1996/11/21 07:59:35 downsj Exp $ */
-
-/* $From: table.h,v 1.3 1994/05/31 13:34:34 michael Exp $ */
-
-/*
- * generic hashed associative table for commands and variables.
- */
-
-struct table {
- Area *areap; /* area to allocate entries */
- short size, nfree; /* hash size (always 2^^n), free entries */
- struct tbl **tbls; /* hashed table items */
-};
-
-struct tbl { /* table item */
- Tflag flag; /* flags */
- int type; /* command type (see below), base (if INTEGER),
- * or offset from val.s of value (if EXPORT) */
- Area *areap; /* area to allocate from */
- union {
- char *s; /* string */
- long i; /* integer */
- int (*f) ARGS((char **)); /* int function */
- struct op *t; /* "function" tree */
- } val; /* value */
- int index; /* index for an array */
- union {
- int field; /* field with for -L/-R/-Z */
- int errno_; /* CEXEC/CTALIAS */
- } u2;
- union {
- struct tbl *array; /* array values */
- char *fpath; /* temporary path to undef function */
- } u;
- char name[4]; /* name -- variable length */
-};
-
-/* common flag bits */
-#define ALLOC BIT(0) /* val.s has been allocated */
-#define DEFINED BIT(1) /* is defined in block */
-#define ISSET BIT(2) /* has value, vp->val.[si] */
-#define EXPORT BIT(3) /* exported variable/function */
-#define TRACE BIT(4) /* var: user flagged, func: execution tracing */
-/* (start non-common flags at 8) */
-/* flag bits used for variables */
-#define SPECIAL BIT(8) /* PATH, IFS, SECONDS, etc */
-#define INTEGER BIT(9) /* val.i contains integer value */
-#define RDONLY BIT(10) /* read-only variable */
-#define LOCAL BIT(11) /* for local typeset() */
-#define ARRAY BIT(13) /* array */
-#define LJUST BIT(14) /* left justify */
-#define RJUST BIT(15) /* right justify */
-#define ZEROFIL BIT(16) /* 0 filled if RJUSTIFY, strip 0s if LJUSTIFY */
-#define LCASEV BIT(17) /* convert to lower case */
-#define UCASEV_AL BIT(18)/* convert to upper case / autoload function */
-#define INT_U BIT(19) /* unsigned integer */
-#define INT_L BIT(20) /* long integer (no-op) */
-#define IMPORT BIT(21) /* flag to typeset(): no arrays, must have = */
-#define LOCAL_COPY BIT(22) /* with LOCAL - copy attrs from existing var */
-#define EXPRINEVAL BIT(23) /* contents currently being evaluated */
-#define EXPRLVALUE BIT(24) /* useable as lvalue (temp flag) */
-/* flag bits used for taliases/builtins/aliases/keywords/functions */
-#define KEEPASN BIT(8) /* keep command assignments (eg, var=x cmd) */
-#define FINUSE BIT(9) /* function being executed */
-#define FDELETE BIT(10) /* function deleted while it was executing */
-#define FKSH BIT(11) /* function defined with function x (vs x()) */
-#define SPEC_BI BIT(12) /* a POSIX special builtin */
-#define REG_BI BIT(13) /* a POSIX regular builtin */
-/* Attributes that can be set by the user (used to decide if an unset param
- * should be repoted by set/typeset). Does not include ARRAY or LOCAL.
- */
-#define USERATTRIB (EXPORT|INTEGER|RDONLY|LJUST|RJUST|ZEROFIL\
- |LCASEV|UCASEV_AL|INT_U|INT_L)
-
-/* command types */
-#define CNONE 0 /* undefined */
-#define CSHELL 1 /* built-in */
-#define CFUNC 2 /* function */
-#define CEXEC 4 /* executable command */
-#define CALIAS 5 /* alias */
-#define CKEYWD 6 /* keyword */
-#define CTALIAS 7 /* tracked alias */
-
-/* Flags for findcom()/comexec() */
-#define FC_SPECBI BIT(0) /* special builtin */
-#define FC_FUNC BIT(1) /* function builtin */
-#define FC_REGBI BIT(2) /* regular builtin */
-#define FC_UNREGBI BIT(3) /* un-regular builtin (!special,!regular) */
-#define FC_BI (FC_SPECBI|FC_REGBI|FC_UNREGBI)
-#define FC_PATH BIT(4) /* do path search */
-#define FC_DEFPATH BIT(5) /* use default path in path search */
-
-
-#define AF_ARGV_ALLOC 0x1 /* argv[] array allocated */
-#define AF_ARGS_ALLOCED 0x2 /* argument strings allocated */
-#define AI_ARGV(a, i) ((i) == 0 ? (a).argv[0] : (a).argv[(i) - (a).skip])
-#define AI_ARGC(a) ((a).argc_ - (a).skip)
-
-/* Argument info. Used for $#, $* for shell, functions, includes, etc. */
-struct arg_info {
- int flags; /* AF_* */
- char **argv;
- int argc_;
- int skip; /* first arg is argv[0], second is argv[1 + skip] */
-};
-
-/*
- * activation record for function blocks
- */
-struct block {
- Area area; /* area to allocate things */
- /*struct arg_info argi;*/
- char **argv;
- int argc;
- struct table vars; /* local variables */
- struct table funs; /* local functions */
-#if 1
- char * error; /* error handler */
- char * exit; /* exit handler */
-#else
- Trap error, exit;
-#endif
- struct block *next; /* enclosing block */
-};
-
-/*
- * Used by twalk() and tnext() routines.
- */
-struct tstate {
- int left;
- struct tbl **next;
-};
-
-
-EXTERN struct table taliases; /* tracked aliases */
-EXTERN struct table builtins; /* built-in commands */
-EXTERN struct table aliases; /* aliases */
-EXTERN struct table keywords; /* keywords */
-EXTERN struct table homedirs; /* homedir() cache */
-
-struct builtin {
- const char *name;
- int (*func) ARGS((char **));
-};
-
-/* these really are externs! Look in table.c for them */
-extern const struct builtin shbuiltins [], kshbuiltins [];
-
-/* var spec values */
-#define V_NONE 0
-#define V_PATH 1
-#define V_IFS 2
-#define V_SECONDS 3
-#define V_OPTIND 4
-#define V_MAIL 5
-#define V_MAILPATH 6
-#define V_MAILCHECK 7
-#define V_RANDOM 8
-#define V_HISTSIZE 9
-#define V_HISTFILE 10
-#define V_VISUAL 11
-#define V_EDITOR 12
-#define V_COLUMNS 13
-#define V_POSIXLY_CORRECT 14
-#define V_TMOUT 15
-#define V_TMPDIR 16
-
-/* values for set_prompt() */
-#define PS1 0 /* command */
-#define PS2 1 /* command continuation */
-
-EXTERN const char *path; /* PATH value */
-EXTERN const char *def_path; /* path to use if PATH not set */
-EXTERN char *tmpdir; /* TMPDIR value */
-EXTERN const char *prompt;
-EXTERN int cur_prompt; /* PS1 or PS2 */
diff --git a/bin/pdksh/tests/alias.t b/bin/pdksh/tests/alias.t
deleted file mode 100644
index 0db6a2594cd..00000000000
--- a/bin/pdksh/tests/alias.t
+++ /dev/null
@@ -1,91 +0,0 @@
-name: alias-1
-description:
- Check that recursion is detected/avoided in aliases.
-stdin:
- alias fooBar=fooBar
- fooBar
- exit 0
-expected-stderr-pattern:
- /fooBar.*not found.*/
----
-
-name: alias-2
-description:
- Check that recursion is detected/avoided in aliases.
-stdin:
- alias fooBar=barFoo
- alias barFoo=fooBar
- fooBar
- barFoo
- exit 0
-expected-stderr-pattern:
- /fooBar.*not found.*\n.*barFoo.*not found/
----
-
-name: alias-3
-description:
- Check that recursion is detected/avoided in aliases.
-stdin:
- alias Echo='echo '
- alias fooBar=barFoo
- alias barFoo=fooBar
- Echo fooBar
- unalias barFoo
- Echo fooBar
-expected-stdout:
- fooBar
- barFoo
----
-
-name: alias-4
-description:
- Check that alias expansion isn't done on keywords (in keyword
- postitions).
-stdin:
- alias Echo='echo '
- alias while=While
- while false; do echo hi ; done
- Echo while
-expected-stdout:
- While
----
-
-name: alias-5
-description:
- Check that alias expansion done after alias with trailing space.
-stdin:
- alias Echo='echo '
- alias foo='bar stuff '
- alias bar='Bar1 Bar2 '
- alias stuff='Stuff'
- alias blah='Blah'
- Echo foo blah
-expected-stdout:
- Bar1 Bar2 Stuff Blah
----
-
-name: alias-6
-description:
- Check that alias expansion done after alias with trailing space.
-stdin:
- alias Echo='echo '
- alias foo='bar bar'
- alias bar='Bar '
- alias blah=Blah
- Echo foo blah
-expected-stdout:
- Bar Bar Blah
----
-
-name: alias-7
-description:
- Check that alias expansion done after alias with trailing space
- after a keyword.
-stdin:
- alias X='case '
- alias Y=Z
- X Y in 'Y') echo is y ;; Z) echo is z ; esac
-expected-stdout:
- is z
----
-
diff --git a/bin/pdksh/tests/arith.t b/bin/pdksh/tests/arith.t
deleted file mode 100644
index e18ea2e9d78..00000000000
--- a/bin/pdksh/tests/arith.t
+++ /dev/null
@@ -1,79 +0,0 @@
-name: arith-lazy-1
-description:
- Check that only one side of ternary operator is evaluated
-stdin:
- x=i+=2
- y=j+=2
- typeset -i i=1 j=1
- echo $((1 ? 20 : (x+=2)))
- echo $i,$x
- echo $((0 ? (y+=2) : 30))
- echo $j,$y
-expected-stdout:
- 20
- 1,i+=2
- 30
- 1,j+=2
----
-
-name: arith-lazy-2
-description:
- Check that assignments not done on non-evaluated side of ternary
- operator
-stdin:
- x=i+=2
- y=j+=2
- typeset -i i=1 j=1
- echo $((1 ? 20 : (x+=2)))
- echo $i,$x
- echo $((0 ? (y+=2) : 30))
- echo $i,$y
-expected-stdout:
- 20
- 1,i+=2
- 30
- 1,j+=2
----
-
-name: arith-ternary-prec-1
-description:
- Check precidance of ternary operator vs assignment
-stdin:
- typeset -i x=2
- y=$((1 ? 20 : x+=2))
-expected-exit: e != 0
-expected-stderr-pattern:
- /.*:.*1 \? 20 : x\+=2.*lvalue.*\n$/
----
-
-name: arith-ternary-prec-2
-description:
- Check precidance of ternary operator vs assignment
-stdin:
- typeset -i x=2
- echo $((0 ? x+=2 : 20))
-expected-stdout:
- 20
----
-
-name: arith-div-assoc-1
-description:
- Check associativity of division operator
-stdin:
- echo $((20 / 2 / 2))
-expected-stdout:
- 5
----
-
-name: arith-assop-assoc-1
-description:
- Check associativity of assignment-operator operator
-stdin:
- typeset -i i=1 j=2 k=3
- echo $((i += j += k))
- echo $i,$j,$k
-expected-stdout:
- 6
- 6,5,3
----
-
diff --git a/bin/pdksh/tests/bksl-nl.t b/bin/pdksh/tests/bksl-nl.t
deleted file mode 100644
index 3fb92ff53b5..00000000000
--- a/bin/pdksh/tests/bksl-nl.t
+++ /dev/null
@@ -1,339 +0,0 @@
-#
-# These tests deal with how \newline is handled in various situations. The
-# first group of tests are places where it shouldn't be collapsed, the next
-# group of tests are places where it should be collapsed.
-#
-name: bksl-nl-ign-1
-description:
- Check that \newline is not collasped after #
-stdin:
- echo hi #there \
- echo folks
-expected-stdout:
- hi
- folks
----
-
-name: bksl-nl-ign-2
-description:
- Check that \newline is not collasped inside single quotes
-stdin:
- echo 'hi \
- there'
- echo folks
-expected-stdout:
- hi \
- there
- folks
----
-
-name: bksl-nl-ign-3
-description:
- Check that \newline is not collasped inside single quotes
-stdin:
- cat << \EOF
- hi \
- there
- EOF
-expected-stdout:
- hi \
- there
----
-
-name: blsk-nl-ign-4
-description:
- Check interaction of aliases, single quotes and here-documents
- with backslash-newline
- (don't know what posix has to say about this)
-stdin:
- a=2
- alias x='echo hi
- cat << "EOF"
- foo\
- bar
- some'
- x
- more\
- stuff$a
- EOF
-expected-stdout:
- hi
- foo\
- bar
- some
- more\
- stuff$a
----
-
-name: blsk-nl-ign-5
-description:
- Check what happens with backslash at end of input
- (the old bourne shell trashes them; so do we)
-stdin: !
- echo `echo foo\\`bar
- echo hi\
-expected-stdout:
- foobar
- hi
----
-
-
-#
-# Places \newline should be collapsed
-#
-name: bksl-nl-1
-description:
- Check that \newline is collasped before, in the middle of, and
- after words
-stdin:
- \
- echo hi\
- There, \
- folks
-expected-stdout:
- hiThere, folks
----
-
-name: bksl-nl-2
-description:
- Check that \newline is collasped in $ sequences
- (ksh93 fails this)
-stdin:
- a=12
- ab=19
- echo $\
- a
- echo $a\
- b
- echo $\
- {a}
- echo ${a\
- b}
- echo ${ab\
- }
-expected-stdout:
- 12
- 19
- 12
- 19
- 19
----
-
-name: bksl-nl-3
-description:
- Check that \newline is collasped in $(..) and `...` sequences
- (ksh93 fails this)
-stdin:
- echo $\
- (echo foobar1)
- echo $(\
- echo foobar2)
- echo $(echo foo\
- bar3)
- echo $(echo foobar4\
- )
- echo `
- echo stuff1`
- echo `echo st\
- uff2`
-expected-stdout:
- foobar1
- foobar2
- foobar3
- foobar4
- stuff1
- stuff2
----
-
-name: bksl-nl-4
-description:
- Check that \newline is collasped in $((..)) sequences
- (ksh93 fails this)
-stdin:
- echo $\
- ((1+2))
- echo $(\
- (1+2+3))
- echo $((\
- 1+2+3+4))
- echo $((1+\
- 2+3+4+5))
- echo $((1+2+3+4+5+6)\
- )
-expected-stdout:
- 3
- 6
- 10
- 15
- 21
----
-
-name: bksl-nl-5
-description:
- Check that \newline is collasped in double quoted strings
-stdin:
- echo "\
- hi"
- echo "foo\
- bar"
- echo "folks\
- "
-expected-stdout:
- hi
- foobar
- folks
----
-
-name: bksl-nl-6
-description:
- Check that \newline is collasped in here document delimiters
- (ksh93 fails second part of this)
-stdin:
- a=12
- cat << EO\
- F
- a=$a
- foo\
- bar
- EOF
- cat << E_O_F
- foo
- E_O_\
- F
- echo done
-expected-stdout:
- a=12
- foobar
- foo
- done
----
-
-name: bksl-nl-7
-description:
- Check that \newline is collasped in double-quoted here-document
- delimiter.
-stdin:
- a=12
- cat << "EO\
- F"
- a=$a
- foo\
- bar
- EOF
- echo done
-expected-stdout:
- a=$a
- foo\
- bar
- done
----
-
-name: bksl-nl-8
-description:
- Check that \newline is collasped in various 2+ character tokens
- delimiter.
- (ksh93 fails this)
-stdin:
- echo hi &\
- & echo there
- echo foo |\
- | echo bar
- cat <\
- < EOF
- stuff
- EOF
- cat <\
- <\
- - EOF
- more stuff
- EOF
- cat <<\
- EOF
- abcdef
- EOF
- echo hi >\
- > /dev/null
- echo $?
- i=1
- case $i in
- (\
- x|\
- 1\
- ) echo hi;\
- ;
- (*) echo oops
- esac
-expected-stdout:
- hi
- there
- foo
- stuff
- more stuff
- abcdef
- 0
- hi
----
-
-name: blsk-nl-9
-description:
- Check that \ at the end of an alias is collapsed when followed
- by a newline
- (don't know what posix has to say about this)
-stdin:
- alias x='echo hi\'
- x
- echo there
-expected-stdout:
- hiecho there
----
-
-name: blsk-nl-10
-description:
- Check that \newline in a keyword is collapsed
-stdin:
- i\
- f true; then\
- echo pass; el\
- se echo fail; fi
-expected-stdout:
- pass
----
-
-#
-# Places \newline should be collapsed (ksh extensions)
-#
-
-name: blsk-nl-ksh-1
-description:
- Check that \newline is collapsed in extended globbing
- (ksh93 fails this)
-stdin:
- xxx=foo
- case $xxx in
- (f*\
- (\
- o\
- )\
- ) echo ok ;;
- *) echo bad
- esac
-expected-stdout:
- ok
----
-
-name: blsk-nl-ksh-2
-description:
- Check that \newline is collapsed in ((...)) expressions
- (ksh93 fails this)
-stdin:
- i=1
- (\
- (\
- i=i+2\
- )\
- )
- echo $i
-expected-stdout:
- 3
----
-
diff --git a/bin/pdksh/tests/brkcont.t b/bin/pdksh/tests/brkcont.t
deleted file mode 100644
index 1eb9c2581c9..00000000000
--- a/bin/pdksh/tests/brkcont.t
+++ /dev/null
@@ -1,195 +0,0 @@
-name: break-1
-description:
- See if break breaks out of loops
-stdin:
- for i in a b c; do echo $i; break; echo bad-$i; done
- echo end-1
- for i in a b c; do echo $i; break 1; echo bad-$i; done
- echo end-2
- for i in a b c; do
- for j in x y z; do
- echo $i:$j
- break
- echo bad-$i
- done
- echo end-$i
- done
- echo end-3
-expected-stdout:
- a
- end-1
- a
- end-2
- a:x
- end-a
- b:x
- end-b
- c:x
- end-c
- end-3
----
-
-name: break-2
-description:
- See if break breaks out of nested loops
-stdin:
- for i in a b c; do
- for j in x y z; do
- echo $i:$j
- break 2
- echo bad-$i
- done
- echo end-$i
- done
- echo end
-expected-stdout:
- a:x
- end
----
-
-
-name: break-3
-description:
- What if break used outside of any loops
- (ksh88,ksh93 don't print error messages here)
-stdin:
- break
-expected-stderr-pattern:
- /.*break.*/
----
-
-
-name: break-4
-description:
- What if break N used when only N-1 loops
- (ksh88,ksh93 don't print error messages here)
-stdin:
- for i in a b c; do echo $i; break 2; echo bad-$i; done
- echo end
-expected-stdout:
- a
- end
-expected-stderr-pattern:
- /.*break.*/
----
-
-
-name: break-5
-description:
- Error if break argument isn't a number
-stdin:
- for i in a b c; do echo $i; break abc; echo more-$i; done
- echo end
-expected-stdout:
- a
-expected-exit: e != 0
-expected-stderr-pattern:
- /.*break.*/
----
-
-
-name: continue-1
-description:
- See if continue continues loops
-stdin:
- for i in a b c; do echo $i; continue; echo bad-$i ; done
- echo end-1
- for i in a b c; do echo $i; continue 1; echo bad-$i; done
- echo end-2
- for i in a b c; do
- for j in x y z; do
- echo $i:$j
- continue
- echo bad-$i-$j
- done
- echo end-$i
- done
- echo end-3
-expected-stdout:
- a
- b
- c
- end-1
- a
- b
- c
- end-2
- a:x
- a:y
- a:z
- end-a
- b:x
- b:y
- b:z
- end-b
- c:x
- c:y
- c:z
- end-c
- end-3
----
-
-
-name: continue-2
-description:
- See if continue breaks out of nested loops
-stdin:
- for i in a b c; do
- for j in x y z; do
- echo $i:$j
- continue 2
- echo bad-$i-$j
- done
- echo end-$i
- done
- echo end
-expected-stdout:
- a:x
- b:x
- c:x
- end
----
-
-
-name: continue-3
-description:
- What if continue used outside of any loops
- (ksh88,ksh93 don't print error messages here)
-stdin:
- continue
-expected-stderr-pattern:
- /.*continue.*/
----
-
-
-name: continue-4
-description:
- What if continue N used when only N-1 loops
- (ksh88,ksh93 don't print error messages here)
-stdin:
- for i in a b c; do echo $i; continue 2; echo bad-$i; done
- echo end
-expected-stdout:
- a
- b
- c
- end
-expected-stderr-pattern:
- /.*continue.*/
----
-
-
-name: continue-5
-description:
- Error if continue argument isn't a number
-stdin:
- for i in a b c; do echo $i; continue abc; echo more-$i; done
- echo end
-expected-stdout:
- a
-expected-exit: e != 0
-expected-stderr-pattern:
- /.*continue.*/
----
-
-
diff --git a/bin/pdksh/tests/cdhist.t b/bin/pdksh/tests/cdhist.t
deleted file mode 100644
index 720f7d60bcc..00000000000
--- a/bin/pdksh/tests/cdhist.t
+++ /dev/null
@@ -1,160 +0,0 @@
-name: cd-history
-description:
- Test someone's CD history package (uses arrays)
-stdin:
- # go to known place before doing anything
- cd /
-
- alias cd=_cd
- function _cd
- {
- typeset -i cdlen i
- typeset t
-
- if [ $# -eq 0 ]
- then
- set -- $HOME
- fi
-
- if [ "$CDHISTFILE" -a -r "$CDHISTFILE" ] # if directory history exists
- then
- typeset CDHIST
- i=-1
- while read -r t # read directory history file
- do
- CDHIST[i=i+1]=$t
- done <$CDHISTFILE
- fi
-
- if [ "${CDHIST[0]}" != "$PWD" -a "$PWD" != "" ]
- then
- _cdins # insert $PWD into cd history
- fi
-
- cdlen=${#CDHIST[*]} # number of elements in history
-
- case "$@" in
- -) # cd to new dir
- if [ "$OLDPWD" = "" ] && ((cdlen>1))
- then
- 'print' ${CDHIST[1]}
- 'cd' ${CDHIST[1]}
- _pwd
- else
- 'cd' $@
- _pwd
- fi
- ;;
- -l) # print directory list
- typeset -R3 num
- ((i=cdlen))
- while (((i=i-1)>=0))
- do
- num=$i
- 'print' "$num ${CDHIST[i]}"
- done
- return
- ;;
- -[0-9]|-[0-9][0-9]) # cd to dir in list
- if (((i=${1#-})<cdlen))
- then
- 'print' ${CDHIST[i]}
- 'cd' ${CDHIST[i]}
- _pwd
- else
- 'cd' $@
- _pwd
- fi
- ;;
- -*) # cd to matched dir in list
- t=${1#-}
- i=1
- while ((i<cdlen))
- do
- case ${CDHIST[i]} in
- *$t*)
- 'print' ${CDHIST[i]}
- 'cd' ${CDHIST[i]}
- _pwd
- break
- ;;
- esac
- ((i=i+1))
- done
- if ((i>=cdlen))
- then
- 'cd' $@
- _pwd
- fi
- ;;
- *) # cd to new dir
- 'cd' $@
- _pwd
- ;;
- esac
-
- _cdins # insert $PWD into cd history
-
- if [ "$CDHISTFILE" ]
- then
- cdlen=${#CDHIST[*]} # number of elements in history
-
- i=0
- while ((i<cdlen))
- do
- 'print' -r ${CDHIST[i]} # update directory history
- ((i=i+1))
- done >$CDHISTFILE
- fi
- }
-
- function _cdins # insert $PWD into cd history
- { # meant to be called only by _cd
- typeset -i i
-
- ((i=0))
- while ((i<${#CDHIST[*]})) # see if dir is already in list
- do
- if [ "${CDHIST[$i]}" = "$PWD" ]
- then
- break
- fi
- ((i=i+1))
- done
-
- if ((i>22)) # limit max size of list
- then
- i=22
- fi
-
- while (((i=i-1)>=0)) # bump old dirs in list
- do
- CDHIST[i+1]=${CDHIST[i]}
- done
-
- CDHIST[0]=$PWD # insert new directory in list
- }
-
-
- function _pwd
- {
- if [ -n "$ECD" ]
- then
- pwd 1>&6
- fi
- }
- # Start of test
- cd /tmp
- cd /bin
- cd /etc
- cd -
- cd -2
- cd -l
-expected-stdout:
- /bin
- /tmp
- 3 /
- 2 /etc
- 1 /bin
- 0 /tmp
----
diff --git a/bin/pdksh/tests/eglob.t b/bin/pdksh/tests/eglob.t
deleted file mode 100644
index ea69f635fcf..00000000000
--- a/bin/pdksh/tests/eglob.t
+++ /dev/null
@@ -1,138 +0,0 @@
-name: eglob-bad-1
-description:
- Check that globbing isn't done when glob has syntax error
-perl-setup:
- &touch("abcx", "abcz", "bbc");
-stdin:
- echo !([*)*
- echo +(a|b[)*
-expected-stdout:
- !([*)*
- +(a|b[)*
----
-
-name: eglob-bad-2
-description:
- Check that globbing isn't done when glob has syntax error
- (at&t ksh fails this test)
-perl-setup:
- &touch("abcx", "abcz", "bbc");
-stdin:
- echo [a*(]*)z
-expected-stdout:
- [a*(]*)z
----
-
-name: eglob-infinite-plus
-description:
- Check that shell doesn't go into infinite loop expanding +(...)
- expressions.
-perl-setup:
- &touch("abc");
-time-limit: 3
-stdin:
- echo +()c
- echo +()x
- echo +(*)c
- echo +(*)x
-expected-stdout:
- +()c
- +()x
- abc
- +(*)x
----
-
-name: eglob-subst-1
-description:
- Check that eglobbing isn't done on substitution results
-perl-setup:
- &touch("abc");
-stdin:
- x='@(*)'
- echo $x
-expected-stdout:
- @(*)
----
-
-name: eglob-nomatch-1
-description:
- Check that the pattern doesn't match
-stdin:
- echo no-file+(a|b)stuff
- echo no-file+(a*(c)|b)stuff
-expected-stdout:
- no-file+(a|b)stuff
- no-file+(a*(c)|b)stuff
----
-
-name: eglob-match-1
-description:
- Check that the pattern matches correctly
-perl-setup:
- &touch("abd", "acd");
-stdin:
- echo a+(b|c)d
- echo a!(@(b|B))d
- echo a[b*(foo|bar)]d
-expected-stdout:
- abd acd
- acd
- abd
----
-
-name: eglob-case-1
-description:
- Simple negation tests
-stdin:
- case foo in !(foo|bar)) echo yes;; *) echo no;; esac
- case bar in !(foo|bar)) echo yes;; *) echo no;; esac
-expected-stdout:
- no
- no
----
-
-name: eglob-case-2
-description:
- Simple kleene tests
-stdin:
- case foo in *(a|b[)) echo yes;; *) echo no;; esac
- case foo in *(a|b[)|f*) echo yes;; *) echo no;; esac
- case '*(a|b[)' in *(a|b[)) echo yes;; *) echo no;; esac
-expected-stdout:
- no
- yes
- yes
----
-
-name: eglob-trim-1
-description:
- Eglobing in trim expressions...
- (at&t ksh fails this - docs say # matches shortest string, ## matches
- longest...)
-stdin:
- x=abcdef
- echo 1: ${x#a|abc}
- echo 2: ${x##a|abc}
- echo 3: ${x%def|f}
- echo 4: ${x%%f|def}
-expected-stdout:
- 1: bcdef
- 2: def
- 3: abcde
- 4: abc
----
-
-name: eglob-trim-2
-description:
- Check eglobing works in trims...
-stdin:
- x=abcdef
- echo ${x#*(a|b)cd}
- echo "${x#*(a|b)cd}"
- echo ${x#"*(a|b)cd"}
-expected-stdout:
- ef
- ef
- abcdef
----
-
diff --git a/bin/pdksh/tests/glob.t b/bin/pdksh/tests/glob.t
deleted file mode 100644
index c7d8e26808d..00000000000
--- a/bin/pdksh/tests/glob.t
+++ /dev/null
@@ -1,96 +0,0 @@
-name: glob-bad-1
-description:
- Check that globbing isn't done when glob has syntax error
-perl-setup:
- mkdir("[x", 0777) || die "couldn't make directory [x - $!\n";
- &touch("[x/foo");
-stdin:
- echo [*
- echo *[x
- echo [x/*
-expected-stdout:
- [*
- *[x
- [x/foo
----
-
-name: glob-bad-2
-description:
- Check that symbolic links aren't stat()'d
-perl-setup:
- mkdir("dir", 0777) || die "couldn't make directory dir - $!\n";
- &touch("dir/abc");
- symlink("non-existent-file", "dir/abc");
-stdin:
- echo d*/*
- echo d*/abc
-expected-stdout:
- dir/abc
- dir/abc
----
-
-name: glob-range-1
-description:
- Test range matching
-perl-setup:
- &touch(".bc", "abc", "bbc", "cbc", "-bc");
-stdin:
- echo [ab-]*
- echo [-ab]*
- echo [!-ab]*
- echo [!ab]*
- echo []ab]*
-expected-stdout:
- -bc abc bbc
- -bc abc bbc
- cbc
- -bc cbc
- abc bbc
----
-
-name: glob-range-2
-description:
- Test range matching
- (at&t ksh fails this; POSIX says invalid)
-perl-setup:
- &touch("abc");
-stdin:
- echo [a--]*
-expected-stdout:
- [a--]*
----
-
-name: glob-range-3
-description:
- Check that globbing matches the right things...
-perl-setup:
- &touch("a\302c");
-stdin:
- echo a[Á-Ú]*
-expected-stdout:
- aÂc
----
-
-name: glob-range-4
-description:
- Results unspecified according to POSIX
-perl-setup:
- &touch(".bc");
-stdin:
- echo [a.]*
-expected-stdout:
- [a.]*
----
-
-name: glob-range-5
-description:
- Results unspecified according to POSIX
- (at&t ksh treats this like [a-cc-e]*)
-perl-setup:
- &touch("abc", "bbc", "cbc", "dbc", "ebc", "-bc");
-stdin:
- echo [a-c-e]*
-expected-stdout:
- -bc abc bbc cbc ebc
----
-
diff --git a/bin/pdksh/tests/heredoc.t b/bin/pdksh/tests/heredoc.t
deleted file mode 100644
index 21feb925cea..00000000000
--- a/bin/pdksh/tests/heredoc.t
+++ /dev/null
@@ -1,144 +0,0 @@
-name: heredoc-1
-description:
- Check ordering/content of redundent here documents.
-stdin:
- cat << EOF1 << EOF2
- hi
- EOF1
- there
- EOF2
-expected-stdout:
- there
----
-
-name: heredoc-2
-description:
- Check quoted here-doc is protected.
-stdin:
- a=foo
- cat << 'EOF'
- hi\
- there$a
- stuff
- EO\
- F
- EOF
-expected-stdout:
- hi\
- there$a
- stuff
- EO\
- F
----
-
-name: heredoc-3
-description:
- Check that newline isn't needed after heredoc-delimiter marker.
-stdin: !
- cat << EOF
- hi
- there
- EOF
-expected-stdout:
- hi
- there
----
-
-name: heredoc-4
-description:
- Check that an error occurs if the heredoc-delimiter is missing.
-stdin: !
- cat << EOF
- hi
- there
-expected-exit: e > 0
-expected-stderr-pattern: /.*/
----
-
-name: heredoc-5
-description:
- Check that backslash quotes a $, ` and \ and kills a \newline
-stdin:
- a=BAD
- b=ok
- cat << EOF
- h\${a}i
- h\\${b}i
- th\`echo not-run\`ere
- th\\`echo is-run`ere
- fol\\ks
- more\\
- last \
- line
- EOF
-expected-stdout:
- h${a}i
- h\oki
- th`echo not-run`ere
- th\is-runere
- fol\ks
- more\
- last line
----
-
-name: heredoc-6
-description:
- Check that \newline in initial here-delim word doesn't imply
- a quoted here-doc.
-stdin:
- a=i
- cat << EO\
- F
- h$a
- there
- EOF
-expected-stdout:
- hi
- there
----
-
-name: heredoc-7
-description:
- Check that double quoted $ expressions in here delimiters are
- not expanded and match the delimiter.
- POSIX says only quote removal is applied to the delimiter.
-stdin:
- a=b
- cat << "E$a"
- hi
- h$a
- hb
- E$a
- echo done
-expected-stdout:
- hi
- h$a
- hb
- done
----
-
-name: heredoc-8
-description:
- Check that double quoted escaped $ expressions in here
- delimiters are not expanded and match the delimiter.
- POSIX says only quote removal is applied to the delimiter
- (\ counts as a quote).
-stdin:
- a=b
- cat << "E\$a"
- hi
- h$a
- h\$a
- hb
- h\b
- E$a
- echo done
-expected-stdout:
- hi
- h$a
- h\$a
- hb
- h\b
- done
----
-
diff --git a/bin/pdksh/tests/history.t b/bin/pdksh/tests/history.t
deleted file mode 100644
index 078aeb60969..00000000000
--- a/bin/pdksh/tests/history.t
+++ /dev/null
@@ -1,529 +0,0 @@
-# Not tested yet:
-# - commands in history file are not numbered negatively
-# (and a few hundred other things)
-
-name: history-basic
-description:
- See if we can test history at all
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo hi
- fc -l
-expected-stdout:
- hi
- 1 echo hi
-expected-stderr-pattern:
- /^X*$/
----
-
-name: history-e-minus-1
-description:
- Check if more recent command is executed
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo hi
- echo there
- fc -e -
-expected-stdout:
- hi
- there
- there
-expected-stderr-pattern:
- /^X*echo there\nX*$/
----
-
-name: history-e-minus-2
-description:
- Check that repeated command is printed before command
- is re-executed.
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- exec 2>&1
- echo hi
- echo there
- fc -e -
-expected-stdout-pattern:
- /X*hi\nX*there\nX*echo there\nthere\nX*/
-expected-stderr-pattern:
- /^X*$/
----
-
-name: history-e-minus-3
-description:
- fc -e - fails when there is no history
- (ksh93 has a bug that causes this to fail)
- (ksh88 loops on this)
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- fc -e -
- echo ok
-expected-stdout:
- ok
-expected-stderr-pattern:
- /^X*.*:.*history.*\nX*$/
----
-
-name: history-e-minus-4
-description:
- Check if "fc -e -" command output goes to stdout.
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo abc
- fc -e - | (read x; echo "A $x")
- echo ok
-expected-stdout:
- abc
- A abc
- ok
-expected-stderr-pattern:
- /^X*echo abc\nX*/
----
-
-name: history-e-minus-5
-description:
- fc is replaced in history by new command.
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo abc def
- echo ghi jkl
- fc -e - echo
- fc -l 2 4
-expected-stdout:
- abc def
- ghi jkl
- ghi jkl
- 2 echo ghi jkl
- 3 echo ghi jkl
- 4 fc -l 2 4
-expected-stderr-pattern:
- /^X*echo ghi jkl\nX*$/
----
-
-name: history-list-1
-description:
- List lists correct range
- (ksh88 fails 'cause it lists the fc command)
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo line 1
- echo line 2
- echo line 3
- fc -l -- -2
-expected-stdout:
- line 1
- line 2
- line 3
- 2 echo line 2
- 3 echo line 3
-expected-stderr-pattern:
- /^X*$/
----
-
-name: history-list-2
-description:
- Lists oldest history if given pre-historic number
- (ksh93 has a bug that causes this to fail)
- (ksh88 fails 'cause it lists the fc command)
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo line 1
- echo line 2
- echo line 3
- fc -l -- -40
-expected-stdout:
- line 1
- line 2
- line 3
- 1 echo line 1
- 2 echo line 2
- 3 echo line 3
-expected-stderr-pattern:
- /^X*$/
----
-
-name: history-list-3
-description:
- Can give number `options' to fc
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo line 1
- echo line 2
- echo line 3
- echo line 4
- fc -l -3 -2
-expected-stdout:
- line 1
- line 2
- line 3
- line 4
- 2 echo line 2
- 3 echo line 3
-expected-stderr-pattern:
- /^X*$/
----
-
-name: history-list-4
-description:
- -1 refers to previous command
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo line 1
- echo line 2
- echo line 3
- echo line 4
- fc -l -1 -1
-expected-stdout:
- line 1
- line 2
- line 3
- line 4
- 4 echo line 4
-expected-stderr-pattern:
- /^X*$/
----
-
-name: history-list-5
-description:
- List command stays in history
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo line 1
- echo line 2
- echo line 3
- echo line 4
- fc -l -1 -1
- fc -l -2 -1
-expected-stdout:
- line 1
- line 2
- line 3
- line 4
- 4 echo line 4
- 4 echo line 4
- 5 fc -l -1 -1
-expected-stderr-pattern:
- /^X*$/
----
-
-name: history-list-6
-description:
- HISTSIZE limits about of history kept.
- (ksh88 fails 'cause it lists the fc command)
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!HISTSIZE=3!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo line 1
- echo line 2
- echo line 3
- echo line 4
- echo line 5
- fc -l
-expected-stdout:
- line 1
- line 2
- line 3
- line 4
- line 5
- 4 echo line 4
- 5 echo line 5
-expected-stderr-pattern:
- /^X*$/
----
-
-name: history-list-7
-description:
- fc allows too old/new errors in range specification
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!HISTSIZE=3!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo line 1
- echo line 2
- echo line 3
- echo line 4
- echo line 5
- fc -l 1 30
-expected-stdout:
- line 1
- line 2
- line 3
- line 4
- line 5
- 4 echo line 4
- 5 echo line 5
- 6 fc -l 1 30
-expected-stderr-pattern:
- /^X*$/
----
-
-name: history-list-r-1
-description:
- test -r flag in history
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo line 1
- echo line 2
- echo line 3
- echo line 4
- echo line 5
- fc -l -r 2 4
-expected-stdout:
- line 1
- line 2
- line 3
- line 4
- line 5
- 4 echo line 4
- 3 echo line 3
- 2 echo line 2
-expected-stderr-pattern:
- /^X*$/
----
-
-name: history-list-r-2
-description:
- If first is newer than last, -r is implied.
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo line 1
- echo line 2
- echo line 3
- echo line 4
- echo line 5
- fc -l 4 2
-expected-stdout:
- line 1
- line 2
- line 3
- line 4
- line 5
- 4 echo line 4
- 3 echo line 3
- 2 echo line 2
-expected-stderr-pattern:
- /^X*$/
----
-
-name: history-list-r-3
-description:
- If first is newer than last, -r is cancelled.
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo line 1
- echo line 2
- echo line 3
- echo line 4
- echo line 5
- fc -l -r 4 2
-expected-stdout:
- line 1
- line 2
- line 3
- line 4
- line 5
- 2 echo line 2
- 3 echo line 3
- 4 echo line 4
-expected-stderr-pattern:
- /^X*$/
----
-
-name: history-subst-1
-description:
- Basic substitution
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo abc def
- echo ghi jkl
- fc -e - abc=AB 'echo a'
-expected-stdout:
- abc def
- ghi jkl
- AB def
-expected-stderr-pattern:
- /^X*echo AB def\nX*$/
----
-
-name: history-subst-2
-description:
- Does subst find previous command?
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo abc def
- echo ghi jkl
- fc -e - jkl=XYZQRT 'echo g'
-expected-stdout:
- abc def
- ghi jkl
- ghi XYZQRT
-expected-stderr-pattern:
- /^X*echo ghi XYZQRT\nX*$/
----
-
-name: history-subst-3
-description:
- Does subst find previous command when no arguments given
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo abc def
- echo ghi jkl
- fc -e - jkl=XYZQRT
-expected-stdout:
- abc def
- ghi jkl
- ghi XYZQRT
-expected-stderr-pattern:
- /^X*echo ghi XYZQRT\nX*$/
----
-
-name: history-subst-4
-description:
- Global substitutions work
- (ksh88 and ksh93 do not have -g option)
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo abc def asjj sadjhasdjh asdjhasd
- fc -e - -g a=FooBAR
-expected-stdout:
- abc def asjj sadjhasdjh asdjhasd
- FooBARbc def FooBARsjj sFooBARdjhFooBARsdjh FooBARsdjhFooBARsd
-expected-stderr-pattern:
- /^X*echo FooBARbc def FooBARsjj sFooBARdjhFooBARsdjh FooBARsdjhFooBARsd\nX*$/
----
-
-name: history-subst-5
-description:
- Make sure searches don't find current (fc) command
- (ksh88/ksh93 don't have the ? prefix thing so they fail this test)
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo abc def
- echo ghi jkl
- fc -e - abc=AB \?abc
-expected-stdout:
- abc def
- ghi jkl
- AB def
-expected-stderr-pattern:
- /^X*echo AB def\nX*$/
----
-
-name: history-ed-1
-description:
- Basic (ed) editing works (assumes you have generic ed editor
- that prints no prompts).
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo abc def
- fc echo
- s/abc/FOOBAR/
- w
- q
-expected-stdout:
- abc def
- 13
- 16
- FOOBAR def
-expected-stderr-pattern:
- /^X*echo FOOBAR def\nX*$/
----
-
-name: history-ed-2
-description:
- Correct command is edited when number given
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo line 1
- echo line 2 is here
- echo line 3
- echo line 4
- fc 2
- s/is here/is changed/
- w
- q
-expected-stdout:
- line 1
- line 2 is here
- line 3
- line 4
- 20
- 23
- line 2 is changed
-expected-stderr-pattern:
- /^X*echo line 2 is changed\nX*$/
----
-
-name: history-ed-3
-description:
- Newly created multi line commands show up as single command
- in history.
- (NOTE: will fail if using COMPLEX HISTORY compile time option)
- (ksh88 fails 'cause it lists the fc command)
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-perl-setup: system("echo PS1=X > Env");
-stdin:
- echo abc def
- fc echo
- s/abc/FOOBAR/
- $a
- echo a new line
- .
- w
- q
- fc -l
-expected-stdout:
- abc def
- 13
- 32
- FOOBAR def
- a new line
- 1 echo abc def
- 2 echo FOOBAR def
- echo a new line
-expected-stderr-pattern:
- /^X*echo FOOBAR def\necho a new line\nX*$/
----
diff --git a/bin/pdksh/tests/ifs.t b/bin/pdksh/tests/ifs.t
deleted file mode 100644
index a927aa301fc..00000000000
--- a/bin/pdksh/tests/ifs.t
+++ /dev/null
@@ -1,162 +0,0 @@
-name: IFS-space-1
-description:
- Simple test, default IFS
-stdin:
- showargs() { for i; do echo -n " <$i>"; done; echo; }
- set -- A B C
- showargs 1 $*
- showargs 2 "$*"
- showargs 3 $@
- showargs 4 "$@"
-expected-stdout:
- <1> <A> <B> <C>
- <2> <A B C>
- <3> <A> <B> <C>
- <4> <A> <B> <C>
----
-
-name: IFS-colon-1
-description:
- Simple test, IFS=:
-stdin:
- showargs() { for i; do echo -n " <$i>"; done; echo; }
- IFS=:
- set -- A B C
- showargs 1 $*
- showargs 2 "$*"
- showargs 3 $@
- showargs 4 "$@"
-expected-stdout:
- <1> <A> <B> <C>
- <2> <A:B:C>
- <3> <A> <B> <C>
- <4> <A> <B> <C>
----
-
-name: IFS-null-1
-description:
- Simple test, IFS=""
-stdin:
- showargs() { for i; do echo -n " <$i>"; done; echo; }
- IFS=""
- set -- A B C
- showargs 1 $*
- showargs 2 "$*"
- showargs 3 $@
- showargs 4 "$@"
-expected-stdout:
- <1> <A B C>
- <2> <ABC>
- <3> <A B C>
- <4> <A B C>
----
-
-name: IFS-space-colon-1
-description:
- Simple test, IFS=<white-space>:
-stdin:
- showargs() { for i; do echo -n " <$i>"; done; echo; }
- IFS="IFS:"
- set --
- showargs 1 $*
- showargs 2 "$*"
- showargs 3 $@
- showargs 4 "$@"
- showargs 5 : "$@"
-expected-stdout:
- <1>
- <2> <>
- <3>
- <4>
- <5> <:>
----
-
-name: IFS-space-colon-2
-description:
- Simple test, IFS=<white-space>:
- At&t ksh fails this, POSIX says the test is correct.
-stdin:
- showargs() { for i; do echo -n " <$i>"; done; echo; }
- IFS="IFS:"
- set --
- showargs :"$@"
-expected-stdout:
- <:>
----
-
-name: IFS-space-colon-3
-description:
- Simple test, IFS=<white-space>:
- pdksh fails both of these tests
-stdin:
- showargs() { for i; do echo -n " <$i>"; done; echo; }
- IFS="IFS:"
- x=
- set --
- showargs "$x$@"
- showargs "$@$x"
-expected-fail: yes
-expected-stdout:
- <>
- <>
----
-
-name: IFS-space-colon-4
-description:
- Simple test, IFS=<white-space>:
-stdin:
- showargs() { for i; do echo -n " <$i>"; done; echo; }
- IFS="IFS:"
- set --
- showargs "$@$@"
-expected-stdout:
-
----
-
-name: IFS-space-colon-5
-description:
- Simple test, IFS=<white-space>:
- Don't know what POSIX thinks of this. at&t ksh does not do this.
-stdin:
- showargs() { for i; do echo -n " <$i>"; done; echo; }
- IFS="IFS:"
- set --
- showargs "${@:-}"
-expected-stdout:
- <>
----
-
-name: IFS-subst-1
-description:
- Simple test, IFS=<white-space>:
-stdin:
- showargs() { for i; do echo -n " <$i>"; done; echo; }
- IFS="$IFS:"
- x=":b: :"
- echo -n '1:'; for i in $x ; do echo -n " [$i]" ; done ; echo
- echo -n '2:'; for i in :b:: ; do echo -n " [$i]" ; done ; echo
- showargs 3 $x
- showargs 4 :b::
- x="a:b:"
- echo -n '5:'; for i in $x ; do echo -n " [$i]" ; done ; echo
- showargs 6 $x
- x="a::c"
- echo -n '7:'; for i in $x ; do echo -n " [$i]" ; done ; echo
- showargs 8 $x
- echo -n '9:'; for i in ${FOO-`echo -n h:i`th:ere} ; do echo -n " [$i]" ; done ; echo
- showargs 10 ${FOO-`echo -n h:i`th:ere}
- showargs 11 "${FOO-`echo -n h:i`th:ere}"
-expected-stdout:
- 1: [] [b] [] []
- 2: [:b::]
- <3> <> <b> <> <>
- <4> <:b::>
- 5: [a] [b] []
- <6> <a> <b> <>
- 7: [a] [] [c]
- <8> <a> <> <c>
- 9: [h] [ith] [ere]
- <10> <h> <ith> <ere>
- <11> <h:ith:ere>
----
-
diff --git a/bin/pdksh/tests/integer.t b/bin/pdksh/tests/integer.t
deleted file mode 100644
index 7e39612b3ff..00000000000
--- a/bin/pdksh/tests/integer.t
+++ /dev/null
@@ -1,218 +0,0 @@
-name: integer-base-err-1
-description:
- Can't have 0 base (causes shell to exit)
-expected-exit: e != 0
-stdin:
- typeset -i i
- i=3
- i=0#4
- echo $i
-expected-stderr-pattern:
- /^.*:.*0#4.*\n$/
----
-
-name: integer-base-err-2
-description:
- Can't have multiple bases in a `constant' (causes shell to exit)
- (ksh88 fails this test)
-expected-exit: e != 0
-stdin:
- typeset -i i
- i=3
- i=2#110#11
- echo $i
-expected-stderr-pattern:
- /^.*:.*2#110#11.*\n$/
----
-
-name: integer-base-err-3
-description:
- Syntax errors in expressions and effects on bases
- (interactive so errors don't cause exits)
- (ksh88 fails this test - shell exits, even with -i)
-arguments: !-i!
-stdin:
- PS1= # minimize prompt hassles
- typeset -i4 a=10
- typeset -i a=2+
- echo $a
- typeset -i4 a=10
- typeset -i2 a=2+
- echo $a
-expected-stderr-pattern:
- /^([#\$] )?.*:.*2+.*\n.*:.*2+.*\n$/
-expected-stdout:
- 4#22
- 4#22
----
-
-name: integer-base-err-4
-description:
- Are invalid digits (according to base) errors?
- (ksh93 fails this test)
-expected-exit: e != 0
-stdin:
- typeset -i i;
- i=3#4
-expected-stderr-pattern:
- /^([#\$] )?.*:.*3#4.*\n$/
----
-
-
-name: integer-base-1
-description:
- Missing number after base is treated as 0.
-stdin:
- typeset -i i
- i=3
- i=2#
- echo $i
-expected-stdout:
- 0
----
-
-name: integer-base-2
-description:
- Check `stickyness' of base in various situations
-stdin:
- typeset -i i=8
- echo $i
- echo ---------- A
- typeset -i4 j=8
- echo $j
- echo ---------- B
- typeset -i k=8
- typeset -i4 k=8
- echo $k
- echo ---------- C
- typeset -i4 l
- l=3#10
- echo $l
- echo ---------- D
- typeset -i m
- m=3#10
- echo $m
- echo ---------- E
- n=2#11
- typeset -i n
- echo $n
- n=10
- echo $n
- echo ---------- F
- typeset -i8 o=12
- typeset -i4 o
- echo $o
- echo ---------- G
- typeset -i p
- let p=8#12
- echo $p
-expected-stdout:
- 8
- ---------- A
- 4#20
- ---------- B
- 4#20
- ---------- C
- 4#3
- ---------- D
- 3#10
- ---------- E
- 2#11
- 2#1010
- ---------- F
- 4#30
- ---------- G
- 8#12
----
-
-name: integer-base-3
-description:
- More base parsing (hmm doesn't test much..)
-stdin:
- typeset -i aa
- aa=1+12#10+2
- echo $aa
- typeset -i bb
- bb=1+$aa
- echo $bb
- typeset -i bb
- bb=$aa
- echo $bb
- typeset -i cc
- cc=$aa
- echo $cc
-expected-stdout:
- 15
- 16
- 15
- 15
----
-
-name: integer-base-4
-description:
- Check that things not declared as integers are not made integers,
- also, check if base is not reset by -i with no arguments.
- (ksh93 fails - prints 10#20 - go figure)
-stdin:
- xx=20
- let xx=10
- typeset -i | grep '^xx='
- typeset -i4 a=10
- typeset -i a=20
- echo $a
-expected-stdout:
- 4#110
----
-
-name: integer-base-5
-description:
- More base stuff
-stdin:
- typeset -i4 a=3#10
- echo $a
- echo --
- typeset -i j=3
- j=~3
- echo $j
- echo --
- typeset -i k=1
- x[k=k+1]=3
- echo $k
- echo --
- typeset -i l
- for l in 1 2+3 4; do echo $l; done
-expected-stdout:
- 4#3
- --
- -4
- --
- 2
- --
- 1
- 5
- 4
----
-
-name: integer-base-6
-description:
- Even more base stuff
- (ksh93 fails this test - prints 0)
-stdin:
- typeset -i7 i
- i=
- echo $i
-expected-stdout:
- 7#0
----
-
-name: integer-base-7
-description:
- Check that non-integer parameters don't get bases assigned
-stdin:
- echo $(( zz = 8#100 ))
- echo $zz
-expected-stdout:
- 64
- 64
----
-
diff --git a/bin/pdksh/tests/read.t b/bin/pdksh/tests/read.t
deleted file mode 100644
index aced86adc32..00000000000
--- a/bin/pdksh/tests/read.t
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-# To test:
-# POSIX:
-# - if no -r, \ is escape character
-# - \newline disappear
-# - \<IFS> -> don't break here
-# - \<anything-else> -> <anything-else>
-# - if -r, backslash is not special
-# - if stdin is tty and shell interactive
-# - prompt for continuation if \newline (prompt to stderr)
-# - a here-document isn't terminated after newline ????
-# - remaining vars set to empty string (not null)
-# - check field splitting
-# - left over fields and their seperators assigned to last var
-# - exit status is normally 0
-# - exit status is > 0 on eof
-# - exit status > 0 on error
-# - signals interrupt reads
-# extra:
-# - can't change read-only variables
-# - error if var name bogus
-# - set -o allexport effects read
-# ksh:
-# x check default variable: REPLY
-# - check -p, -s, -u options
-# - check var?prompt stuff
-# - "echo a b | read x y" sets x,y in parent shell (at&t)
-#
-name: read-IFS-1
-description:
- Simple test, default IFS
-stdin:
- echo "A B " > IN
- unset x y z
- read x y z < IN
- echo 1: "x[$x] y[$y] z[$z]"
- echo 1a: ${z-z not set}
- read x < IN
- echo 2: "x[$x]"
-expected-stdout:
- 1: x[A] y[B] z[]
- 1a:
- 2: x[A B]
----
-
-name: read-ksh-1
-description:
- If no var specified, REPLY is used
-stdin:
- echo "abc" > IN
- read < IN
- echo "[$REPLY]";
-expected-stdout:
- [abc]
----
-
diff --git a/bin/pdksh/tests/regress.t b/bin/pdksh/tests/regress.t
deleted file mode 100644
index 675ae53497a..00000000000
--- a/bin/pdksh/tests/regress.t
+++ /dev/null
@@ -1,770 +0,0 @@
-#
-# The first 39 of these tests are from the old Bugs script.
-#
-
-name: regression-1
-description:
- Lex array code had problems with this.
-stdin:
- echo foo[
- n=bar
- echo "hi[ $n ]=1"
-expected-stdout:
- foo[
- hi[ bar ]=1
----
-
-
-name: regression-2
-description:
- When PATH is set before running a command, the new path is
- not used in doing the path search
- $ echo echo hi > /tmp/q ; chmod a+rx /tmp/q
- $ PATH=/tmp q
- q: not found
- $
- in comexec() the two lines
- while (*vp != NULL)
- (void) typeset(*vp++, xxx, 0);
- need to be moved out of the switch to before findcom() is
- called - I don't know what this will break.
-stdin:
- : ${PWD:-`pwd 2> /dev/null`}
- : ${PWD:?"PWD not set - can't do test"}
- mkdir Y
- cat > Y/xxxscript << EOF
- #!/bin/sh
- # Need to restore path so echo can be found (some shells don't have
- # it as a built-in)
- PATH=\$OLDPATH
- echo hi
- exit 0
- EOF
- chmod a+rx Y/xxxscript
- export OLDPATH="$PATH"
- PATH=$PWD/Y xxxscript
- exit $?
-expected-stdout:
- hi
----
-
-
-#
-# 3. Sun OS 4.0.x (This seems to be a problem with sun's PENDIN not being done
-# properly)
-# sleep 5^J ls^J ls^J ls [only first ls runs]
-# vi ... ZZ (while waiting type) [some of the input gets eaten]
-# [not present in SunOS 4.1.x]
-#echo " [No automatic test for bug 3 - interactive]"
-
-
-#
-# 4. (fixed)
-#
-#echo " [Don't know what bug 4 was]"
-
-
-#
-# 5. Everywhere
-# File name completion (^X,*) does not mesh well with cd and
-# symbolic links. cd does path simplification wrt $PWD before
-# doing the actual chdir(), while file name completion does
-# not do the simplification. E.g., you are in directory A
-# which has a symbolic link to directory B, you create a file
-# called foobar and you then cd to the symlink to B, and type
-# $ echo ../foo^X
-# and the shell beeps at you. Would be more consistent to
-# do the completion after simplifing the `$PWD/..'.
-#echo " [No automatic test for bug 5 - interactive]"
-
-
-name: regression-6
-description:
- Parsing of $(..) expressions is non-optimal. It is
- impossible to have any parentheses inside the expression.
- I.e.,
- $ ksh -c 'echo $(echo \( )'
- no closing quote
- $ ksh -c 'echo $(echo "(" )'
- no closing quote
- $
- The solution is to hack the parsing clode in lex.c, the
- question is how to hack it: should any parentheses be
- escaped by a backslash, or should recursive parsing be done
- (so quotes could also be used to hide hem). The former is
- easier, the later better...
-stdin:
- echo $(echo \()
-expected-stdout:
- (
----
-
-
-#
-# 7. (fixed)
-#
-#echo " [Don't know what bug 7 was]"
-
-
-#
-# 8. Everywhere - NOT A BUG - this is what at&t ksh88 does
-# Strange typset -x behaviour in functions. The following function
-# does not set the environment variable BLAH outside the function:
-# function blah
-# {
-# typeset -x BLAH=foobar
-# }
-# This function does work:
-# function blah
-# { BLAH=foobar; export BLAH
-# }
-#echo ' [Bug 8 was bogus]'
-
-
-name: regression-9
-description:
- Continue in a for loop does not work right:
- for i in a b c ; do
- if [ $i = b ] ; then
- continue
- fi
- echo $i
- done
- Prints a forever...
-stdin:
- first=yes
- for i in a b c ; do
- if [ $i = b ] ; then
- if [ $first = no ] ; then
- echo 'continue in for loop broken'
- break # hope break isn't broken too :-)
- fi
- first=no
- continue
- fi
- done
- echo bye
-expected-stdout:
- bye
----
-
-
-name: regression-10
-description:
- The following:
- set -- `false`
- echo $?
- shoud not print 0. (according to /bin/sh, at&t ksh88, and the
- getopt(1) man page - not according to POSIX)
-stdin:
- set -- `false`
- echo $?
-expected-stdout:
- 1
----
-
-
-name: regression-11
-description:
- The following:
- x=/foo/bar/blah
- echo ${x##*/}
- should echo blah but on some machines echos /foo/bar/blah.
-stdin:
- x=/foo/bar/blah
- echo ${x##*/}
-expected-stdout:
- blah
----
-
-
-name: regression-12
-description:
- Both of the following echos produce the same output under sh/ksh.att:
- #!/bin/sh
- x="foo bar"
- echo "`echo \"$x\"`"
- echo "`echo "$x"`"
- pdksh produces different output for the former (foo instead of foo\tbar)
-stdin:
- x="foo bar"
- echo "`echo \"$x\"`"
- echo "`echo "$x"`"
-expected-stdout:
- foo bar
- foo bar
----
-
-
-name: regression-13
-description:
- The following command hangs forever:
- $ (: ; cat /etc/termcap) | sleep 2
- This is because the shell forks a shell to run the (..) command
- and this shell has the pipe open. When the sleep dies, the cat
- doesn't get a SIGPIPE 'cause a process (ie, the second shell)
- still has the pipe open.
-
- NOTE: this test provokes a bizarre bug in ksh93 (shell starts reading
- commands from /etc/termcap..)
-time-limit: 10
-stdin:
- echo A line of text that will be duplicated quite a number of times.> t1
- cat t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 t1 > t2
- cat t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 t2 > t1
- cat t1 t1 t1 t1 > t2
- (: ; cat t2) | sleep 1
----
-
-
-name: regression-14
-description:
- The command
- $ (foobar) 2> /dev/null
- generates no output under /bin/sh, but pdksh produces the error
- foobar: not found
- Also, the command
- $ foobar 2> /dev/null
- generates an error under /bin/sh and pdksh, but at&t ksh88 produces
- no error (redirected to /dev/null).
-stdin:
- (you/should/not/see/this/error/1) 2> /dev/null
- you/should/not/see/this/error/2 2> /dev/null
- true
----
-
-
-name: regression-15
-description:
- The command
- $ whence foobar
- generates a blank line under pdksh and sets the exit status to 0.
- at&t ksh88 generates no output and sets the exit status to 1. Also,
- the command
- $ whence foobar cat
- generates no output under at&t ksh88 (pdksh generates a blank line
- and /bin/cat).
-stdin:
- whence does/not/exist > /dev/null
- echo 1: $?
- echo 2: $(whence does/not/exist | wc -l)
- echo 3: $(whence does/not/exist cat | wc -l)
-expected-stdout:
- 1: 1
- 2: 0
- 3: 0
----
-
-
-name: regression-16
-description:
- ${var%%expr} seems to be broken in many places. On the mips
- the commands
- $ read line < /etc/passwd
- $ echo $line
- root:0:1:...
- $ echo ${line%%:*}
- root
- $ echo $line
- root
- $
- change the value of line. On sun4s & pas, the echo ${line%%:*} doesn't
- work. Haven't checked elsewhere...
-script:
- read x
- y=$x
- echo ${x%%:*}
- echo $x
-stdin:
- root:asdjhasdasjhs:0:1:Root:/:/bin/sh
-expected-stdout:
- root
- root:asdjhasdasjhs:0:1:Root:/:/bin/sh
----
-
-
-name: regression-17
-description:
- The command
- . /foo/bar
- should set the exit status to non-zero (sh and at&t ksh88 do).
- XXX doting a non existant file is a fatal error for a script
-stdin:
- . does/not/exist
-expected-exit: e != 0
-expected-stderr-pattern: /.?/
----
-
-
-#
-# 18. Everywhere
-# In vi mode ^X (and *) can dump core:
-# $ ab[cd^XMemory fault (core dumped)
-#echo " [No automatic test for bug 18 - interactive]"
-
-
-name: regression-19
-description:
- Both of the following echos should produce the same thing, but don't:
- $ x=foo/bar
- $ echo ${x%/*}
- foo
- $ echo "${x%/*}"
- foo/bar
-stdin:
- x=foo/bar
- echo "${x%/*}"
-expected-stdout:
- foo
----
-
-
-#
-# 20. (same as 18)
-#
-
-
-name: regression-21
-description:
- backslash does not work as expected in case labels:
- $ x='-x'
- $ case $x in
- -\?) echo hi
- esac
- hi
- $ x='-?'
- $ case $x in
- -\\?) echo hi
- esac
- hi
- $
-stdin:
- case -x in
- -\?) echo fail
- esac
----
-
-
-name: regression-22
-description:
- Quoting backquotes inside backquotes doesn't work:
- $ echo `echo hi \`echo there\` folks`
- asks for more info. sh and at&t ksh88 both echo
- hi there folks
-stdin:
- echo `echo hi \`echo there\` folks`
-expected-stdout:
- hi there folks
----
-
-
-name: regression-23
-description:
- )) is not treated `correctly':
- $ (echo hi ; (echo there ; echo folks))
- missing ((
- $
- instead of (as sh and ksh.att)
- $ (echo hi ; (echo there ; echo folks))
- hi
- there
- folks
- $
-stdin:
- ( : ; ( : ; echo hi))
-expected-stdout:
- hi
----
-
-
-#
-# 24. strangeness with file name completion involving symlinks to nowhere
-# $ mkdir foo foo/bar
-# $ ln -s /stuff/junk foo/bar/xx
-# $ echo foo/*/xx 
-# (beep)
-# $
-#echo " [No automatic test for bug 24 - interactive]"
-
-
-name: regression-25
-description:
- Check reading stdin in a while loop. The read should only read
- a single line, not a whole stdio buffer; the cat should get
- the rest.
-stdin:
- (echo a; echo b) | while read x ; do
- echo $x
- cat > /dev/null
- done
-expected-stdout:
- a
----
-
-
-name: regression-26
-description:
- Check reading stdin in a while loop. The read should read both
- lines, not just the first.
-script:
- a=
- while [ "$a" != xxx ] ; do
- last=$x
- read x
- /bin/cat /dev/null | sed 's/x/y/'
- a=x$a
- done
- echo $last
-stdin:
- a
- b
-expected-stdout:
- b
----
-
-
-name: regression-27
-description:
- The command
- . /does/not/exist
- should cause a script to exit.
-stdin:
- . does/not/exist
- echo hi
-expected-exit: e != 0
-expected-stderr-pattern: /does\/not\/exist/
----
-
-
-name: regression-28
-description:
- variable assignements not detected well
-stdin:
- a.x=1 echo hi
-expected-exit: e != 0
-expected-stderr-pattern: /a\.x=1/
----
-
-
-name: regression-29
-description:
- alias expansion different from at&t ksh88
-stdin:
- alias a='for ' b='i in'
- a b hi ; do echo $i ; done
-expected-stdout:
- hi
----
-
-
-name: regression-30
-description:
- strange characters allowed inside ${...}
-stdin:
- echo ${a{b}}
-expected-exit: e != 0
-expected-stderr-pattern: /.?/
----
-
-
-name: regression-31
-description:
- Does read handle partial lines correctly
-script:
- a= ret=
- while [ "$a" != xxx ] ; do
- read x y z
- ret=$?
- a=x$a
- done
- echo "[$x]"
- echo $ret
-stdin: !
- a A aA
- b B Bb
- c
-expected-stdout:
- [c]
- 1
----
-
-
-name: regression-32
-description:
- Does read set variables to null at eof?
-script:
- a=
- while [ "$a" != xxx ] ; do
- read x y z
- a=x$a
- done
- echo 1: ${x-x not set} ${y-y not set} ${z-z not set}
- echo 2: ${x:+x not null} ${y:+y not null} ${z:+z not null}
-stdin:
- a A Aa
- b B Bb
-expected-stdout:
- 1:
- 2:
----
-
-
-name: regression-33
-description:
- Does umask print a leading 0 when umask is 3 digits?
-stdin:
- umask 222
- umask
-expected-stdout:
- 0222
----
-
-
-#
-#
-# Does umask print a umask of 0 sanely?
-# There is lots of variety here (0, 00, 000, and 0000 have all been
-# seen in various shells...)
-#
-#echo ' [Bug 34 was bogus]'
-
-
-name: regression-35
-description:
- Tempory files used for here-docs in functions get trashed after
- the function is parsed (before it is executed)
-stdin:
- f1() {
- cat <<- EOF
- F1
- EOF
- f2() {
- cat <<- EOF
- F2
- EOF
- }
- }
- f1
- f2
- unset -f f1
- f2
-expected-stdout:
- F1
- F2
- F2
----
-
-
-name: regression-36
-description:
- Command substitution breaks reading in while loop
- (test from <sjg@void.zen.oz.au>)
-stdin:
- (echo abcdef; echo; echo 123) |
- while read line
- do
- # the following line breaks it
- c=`echo $line | wc -c`
- echo $c
- done
-expected-stdout:
- 7
- 1
- 4
----
-
-
-name: regression-37
-description:
- Machines with broken times() (reported by <sjg@void.zen.oz.au>)
- time does not report correct real time
-stdin:
- time sleep 1
-expected-stderr-pattern: !/^\s*0\.0[\s\d]+real|^\s*real[\s]+0+\.0/
----
-
-
-name: regression-38
-description:
- set -e doesn't ignore exit codes for if/while/until/&&/||/!.
-arguments: !-e!
-stdin:
- if false; then echo hi ; fi
- false || true
- false && true
- while false; do echo hi; done
- echo ok
-expected-stdout:
- ok
----
-
-
-name: regression-39
-description:
- set -e: errors in command substitutions aren't ignored
- Not clear if they should be or not...
-expected-fail: yes
-arguments: !-e!
-stdin:
- echo `false; echo hi`
-expected-stdout:
- hi
----
-
-name: regression-40
-description:
- This used to cause a core dump
-env-setup: !RANDOM=12!
-stdin:
- echo hi
-expected-stdout:
- hi
----
-
-name: regression-41
-description:
- foo should be set to bar (should not be empty)
-stdin:
- foo=`
- echo bar`
- echo "($foo)"
-expected-stdout:
- (bar)
----
-
-name: regression-42
-description:
- Can't use command line assignments to assign readonly parameters.
-stdin:
- foo=bar
- readonly foo
- foo=stuff env | grep '^foo'
-expected-exit: e != 0
-expected-stderr-pattern:
- /.*read *only.*/
----
-
-name: regression-43
-description:
- Can subshells be prefixed by redirections (historical shells allow
- this)
-stdin:
- < /dev/null (sed 's/^/X/')
----
-
-name: regression-44
-description:
- getopts sets OPTIND correctly for unparsed option
-stdin:
- set -- -a -a -x
- while getopts :a optc; do
- echo "OPTARG=$OPTARG, OPTIND=$OPTIND, optc=$optc."
- done
- echo done
-expected-stdout:
- OPTARG=, OPTIND=2, optc=a.
- OPTARG=, OPTIND=3, optc=a.
- OPTARG=x, OPTIND=3, optc=?.
- done
----
-
-name: regression-45
-description:
- Parameter assignments with [] recognized correctly
-stdin:
- FOO=*[12]
- BAR=abc[
- MORE=[abc]
- JUNK=a[bc
- echo "<$FOO>"
- echo "<$BAR>"
- echo "<$MORE>"
- echo "<$JUNK>"
-expected-stdout:
- <*[12]>
- <abc[>
- <[abc]>
- <a[bc>
----
-
-name: regression-46
-description:
- Check that alias expansion works in command substitutions and
- at the end of file.
-stdin:
- alias x='echo hi'
- FOO="`x` "
- echo "[$FOO]"
- x
-expected-stdout:
- [hi ]
- hi
----
-
-name: regression-47
-description:
- Check that aliases are fully read.
-stdin:
- alias x='echo hi;
- echo there'
- x
- echo done
-expected-stdout:
- hi
- there
- done
----
-
-name: regression-48
-description:
- Check that (here doc) temp files are not left behind after an exec.
-stdin:
- mkdir foo || exit 1
- TMPDIR=$PWD/foo $0 <<- 'EOF'
- x() {
- sed 's/^/X /' << E_O_F
- hi
- there
- folks
- E_O_F
- echo "done ($?)"
- }
- exec /bin/echo subtest-1 hi
- EOF
- echo subtest-1 foo/*
- TMPDIR=$PWD/foo $0 <<- 'EOF'
- sed 's/^/X /' << E_O_F; exec /bin/echo subtest-2 hi
- a
- few
- lines
- E_O_F
- EOF
- echo subtest-2 foo/*
-expected-stdout:
- subtest-1 hi
- subtest-1 foo/*
- X a
- X few
- X lines
- subtest-2 hi
- subtest-2 foo/*
----
-
-name: regression-49
-description:
- Check that unset params with attributes are reported by set, those
- sans attributes are not.
-stdin:
- unset FOO BAR
- echo X$FOO
- export BAR
- typeset -i BLAH
- set | grep FOO
- set | grep BAR
- set | grep BLAH
-expected-stdout:
- X
- BAR
- BLAH
----
-
diff --git a/bin/pdksh/tests/th b/bin/pdksh/tests/th
deleted file mode 100644
index ebe54718ece..00000000000
--- a/bin/pdksh/tests/th
+++ /dev/null
@@ -1,819 +0,0 @@
-#!/usr/bin/perl
-
-#
-# Test harness for pdksh tests.
-#
-# Example test:
-# name: a-test
-# description:
-# a test to show how tests are done
-# arguments: !-x!-f!
-# stdin:
-# echo -n *
-# false
-# expected-stdout: !
-# *
-# expected-stderr:
-# + echo -n *
-# + false
-# expected-exit: 1
-# ---
-# This runs the test-program (eg, pdksh) with the arguments -x and -f,
-# standard input is a file containing "echo hi*\nfalse\n". The program
-# is expected to produce "hi*" (no trailing newline) on standard output,
-# "+ echo hi*\n+false\n" on standard error, and an exit code of 1.
-#
-#
-# Format of test files:
-# - blank lines and lines starting with # are ignored
-# - a test file contains a series of tests
-# - a test is a series of tag:value pairs ended with a "---" line
-# (leading/trailing spaces are stripped from the first line of value)
-# - test tags are:
-# Tag Flag Description
-# ----- ---- -----------
-# name r The name of the test; should be unique
-# description m What test does
-# arguments M Arguments to pass to the program;
-# default is no arguments.
-# script m Value is written to a file which
-# is passed as an argument to the program
-# (after the arguments arguments)
-# stdin m Value is written to a file which is
-# used as standard-input for the program;
-# default is to use /dev/null.
-# perl-setup m Value is a perl script which is executed
-# just before the test is run. Try to
-# avoid using this...
-# perl-cleanup m Value is a perl script which is executed
-# just after the test is run. Try to
-# avoid using this...
-# env-setup M Value is a list of NAME=VALUE elements
-# which are put in the environment before
-# the test is run. If the =VALUE is
-# missing, NAME is removed from the
-# environment. Programs are run with
-# the following minimal environment:
-# USER, LOGNAME, HOME, PATH, SHELL
-# (values taken from the environment of
-# the test harness).
-# time-limit Time limit - the program is sent a
-# SIGKILL N seconds. Default is no
-# limit.
-# expected-fail `yes' if the test is expected to fail.
-# expected-exit expected exit code. Can be a number,
-# or a C expression using the variables
-# e, s and w (exit code, termination
-# signal, and status code).
-# expected-stdout m What the test should generate on stdout;
-# default is to expect no output.
-# expected-stdout-pattern m A perl pattern which matches the
-# expected output.
-# expected-stderr m What the test should generate on stderr;
-# default is to expect no output.
-# expected-stderr-pattern m A perl pattern which matches the
-# expected standard error.
-# Flag meanings:
-# r tag is required (eg, a test must have a name tag).
-# m value can be multiple lines. Lines must be prefixed with
-# a tab. If the value part of the initial tag:value line is
-# - empty: the initial blank line is stripped.
-# - a lone !: the last newline in the value is stripped;
-# M value can be multiple lines (prefixed by a tab) and consists
-# of multiple fields, delimited by a field seperator character.
-# The value must start and end with the f-s-c.
-#
-
-require 'signal.ph';
-require 'errno.ph';
-require 'getopts.pl';
-
-($prog = $0) =~ s#.*/##;
-
-$Usage = <<EOF ;
-Usage: $prog [-s test-set] [-p prog] [-v] test-name ...
- -p p Use p as the program to test
- -s s Read tests from file s; if s is a directory, it is recursively
- scaned for test files (which end in .t).
- -t t Use t as default time limit for tests (default is unlimited)
- -v Verbose mode: print reason test failed.
- test-name(s) specifies the name of the test(s) to run; if none are
- specified, all tests are run.
-EOF
-
-#
-# r - required
-# m - can be multi-line
-# M - multi-line, but without trailing newline
-#
-%test_fields = (
- 'name', 'r',
- 'description', 'm',
- 'arguments', 'M',
- 'script', 'm',
- 'stdin', 'm',
- 'perl-setup', 'm',
- 'perl-cleanup', 'm',
- 'env-setup', 'M',
- 'time-limit', '',
- 'expected-fail', '',
- 'expected-exit', '',
- 'expected-stdout', 'm',
- 'expected-stdout-pattern', 'm',
- 'expected-stderr', 'm',
- 'expected-stderr-pattern', 'm',
- );
-# Filled in by read_test()
-%internal_test_fields = (
- ':full-name', 1, # file:name
- ':long-name', 1, # dir/file:lineno:name
- );
-
-$temps = "/tmp/rts$$";
-$tempi = "/tmp/rti$$";
-$tempo = "/tmp/rto$$";
-$tempe = "/tmp/rte$$";
-$tempdir = "/tmp/rtd$$";
-
-$nfailed = 0;
-$nxfailed = 0;
-$npassed = 0;
-$nxpassed = 0;
-
-%known_tests = ();
-
-if (!&Getopts('p:s:t:v')) {
- print STDERR $Usage;
- exit 1;
-}
-
-die "$prog: no program specified (use -p)\n" if !defined $opt_p;
-die "$prog: no test set specified (use -s)\n" if !defined $opt_s;
-$test_prog = $opt_p;
-$verbose = defined $opt_v && $opt_v;
-$test_set = $opt_s;
-if (defined $opt_t) {
- die "$prog: bad -t argument (should be number > 0): $opt_t\n"
- if $opt_t !~ /^\d+$/ || $opt_t <= 0;
- $default_time_limit = $opt_t;
-}
-
-# Note which tests are to be run.
-%do_test = ();
-grep($do_test{$_} = 1, @ARGV);
-$all_tests = @ARGV == 0;
-
-# Set up a very minimal environment
-%new_env = ();
-foreach $env (('USER', 'LOGNAME', 'HOME', 'PATH', 'SHELL')) {
- $new_env{$env} = $ENV{$env} if defined $ENV{$env};
-}
-%old_env = %ENV;
-
-# The following doesn't work with perl5... Need to do it explicitly - yuck.
-#%ENV = %new_env;
-foreach $k (keys(%ENV)) {
- delete $ENV{$k};
-}
-$ENV{$k} = $v while ($k,$v) = each %new_env;
-
-die "$prog: couldn't make directory $tempdir - $!\n" if !mkdir($tempdir, 0777);
-
-chop($pwd = `pwd 2> /dev/null`);
-die "$prog: couldn't get current working directory\n" if $pwd eq '';
-die "$prog: couldn't cd to $pwd - $!\n" if !chdir($pwd);
-
-$test_prog = "$pwd/$test_prog" if substr($test_prog, 0, 1) ne '/';
-die "$prog: $test_prog is not executable - bye\n" if ! -x $test_prog;
-
-@trap_sigs = ('TERM', 'QUIT', 'INT', 'PIPE', 'HUP');
-@SIG{@trap_sigs} = ('cleanup_exit') x @trap_sigs;
-$child_kill_ok = 0;
-$SIG{'ALRM'} = 'catch_sigalrm';
-
-$| = 1;
-
-if (-d $test_set) {
- $file_prefix_skip = length($test_set) + 1;
- $ret = &process_test_dir($test_set);
-} else {
- $file_prefix_skip = 0;
- $ret = &process_test_file($test_set);
-}
-&cleanup_exit() if !defined $ret;
-
-$tot_failed = $nfailed + $nxfailed;
-$tot_passed = $npassed + $nxpassed;
-if ($tot_failed || $tot_passed) {
- print "Total failed: $tot_failed";
- print " ($nxfailed unexpected)" if $nxfailed;
- print " (as expected)" if $nfailed && !$nxfailed;
- print "\nTotal passed: $tot_passed";
- print " ($nxpassed unexpected)" if $nxpassed;
- print "\n";
-}
-
-&cleanup_exit('ok');
-
-sub
-cleanup_exit
-{
- local($sig, $exitcode) = ('', 1);
-
- if ($_[0] eq 'ok') {
- $exitcode = 0;
- } elsif ($_[0] ne '') {
- $sig = $_[0];
- }
-
- unlink($tempi, $tempo, $tempe, $temps);
- &scrub_dir($tempdir) if defined $tempdir;
- rmdir($tempdir) if defined $tempdir;
-
- if ($sig) {
- $SIG{$sig} = 'DEFAULT';
- kill $sig, $$;
- return;
- }
- exit $exitcode;
-}
-
-sub
-catch_sigalrm
-{
- $SIG{'ALRM'} = 'catch_sigalrm';
- kill(9, $child_pid) if $child_kill_ok;
- $child_killed = 1;
-}
-
-sub
-process_test_dir
-{
- local($dir) = @_;
- local($ret, $file);
- local(@todo) = ();
-
- if (!opendir(DIR, $dir)) {
- print STDERR "$prog: can't open directory $dir - $!\n";
- return undef;
- }
- while ($file = readdir(DIR)) {
- push(@todo, $file) if $file =~ /^[^.].*\.t$/;
- }
- closedir(DIR);
-
- foreach $file (@todo) {
- $file = "$dir/$file";
- if (-d $file) {
- $ret = &process_test_dir($file);
- } elsif (-f _) {
- $ret = &process_test_file($file);
- }
- last if !defined $ret;
- }
-
- return $ret;
-}
-
-sub
-process_test_file
-{
- local($file) = @_;
- local($ret);
-
- if (!open(IN, $file)) {
- die "$prog: can't open $file - $!\n";
- return undef;
- }
- while (1) {
- $ret = &read_test($file, IN, *test);
- last if !defined $ret || !$ret;
- next if !$all_tests && !$do_test{$test{'name'}};
- $ret = &run_test(*test);
- last if !defined $ret;
- }
- close(IN);
-
- return $ret;
-}
-
-sub
-run_test
-{
- local(*test) = @_;
- local($name) = $test{':full-name'};
-
- #print "Running test $name...\n" if $verbose;
-
- if (defined $test{'stdin'}) {
- return undef if !&write_file($tempi, $test{'stdin'});
- $ifile = $tempi;
- } else {
- $ifile = '/dev/null';
- }
-
- if (defined $test{'script'}) {
- return undef if !&write_file($temps, $test{'script'});
- }
-
- return undef if !&scrub_dir($tempdir);
-
- if (!chdir($tempdir)) {
- print STDERR "$prog: couldn't cd to $tempdir - $!\n";
- return undef;
- }
-
- if (defined $test{'perl-setup'}) {
- eval $test{'perl-setup'};
- if ($@ ne '') {
- print STDERR "$prog:$test{':long-name'}: error running perl-setup - $@\n";
- return undef;
- }
- }
-
- $pid = fork;
- if (!defined $pid) {
- print STDERR "$prog: can't fork - $!\n";
- return undef;
- }
- if (!$pid) {
- @SIG{@trap_sigs} = ('DEFAULT') x @trap_sigs;
- $SIG{'ALRM'} = 'DEFAULT';
- if (defined $test{'env-setup'}) {
- local($var, $val, $i);
-
- foreach $var (split(substr($test{'env-setup'}, 0, 1),
- $test{'env-setup'}))
- {
- $i = index($var, '=');
- next if $i == 0 || $var eq '';
- if ($i < 0) {
- delete $ENV{$var};
- } else {
- $ENV{substr($var, 0, $i)} = substr($var, $i + 1);
- }
- }
- }
- if (!open(STDIN, "< $ifile")) {
- print STDERR "$prog: couldn't open $ifile in child - $!\n";
- kill('TERM', $$);
- }
- if (!open(STDOUT, "> $tempo")) {
- print STDERR "$prog: couldn't open $tempo in child - $!\n";
- kill('TERM', $$);
- }
- if (!open(STDERR, "> $tempe")) {
- print STDOUT "$prog: couldn't open $tempe in child - $!\n";
- kill('TERM', $$);
- }
- @argv = ($test_prog);
- if (defined $test{'arguments'}) {
- push(@argv,
- split(substr($test{'arguments'}, 0, 1),
- substr($test{'arguments'}, 1)));
- }
- push(@argv, $temps) if defined $test{'script'};
- exec(@argv);
- print STDERR "$prog: couldn't execute $test_prog - $!\n";
- kill('TERM', $$);
- exit(95);
- }
- $child_pid = $pid;
- $child_killed = 0;
- $child_kill_ok = 1;
- alarm($test{'time-limit'}) if defined $test{'time-limit'};
- while (1) {
- $xpid = waitpid($pid, 0);
- $child_kill_ok = 0;
- if ($xpid < 0) {
- next if $! == &EINTR;
- print STDERR "$prog: error waiting for child - $!\n";
- return undef;
- }
- last;
- }
- $status = $?;
- alarm(0) if defined $test{'time-limit'};
-
- $failed = 0;
- $why = '';
-
- if ($child_killed) {
- $failed = 1;
- $why .= "\ttest timed out (limit of $test{'time-limit'} seconds)\n";
- }
-
- $ret = &eval_exit($test{'long-name'}, $status, $test{'expected-exit'});
- return undef if !defined $ret;
- if (!$ret) {
- local($expl);
-
- $failed = 1;
- if (($status & 0xff) == 0x7f) {
- $expl = "stopped";
- } elsif (($status & 0xff)) {
- $expl = "signal " . ($status & 0x7f);
- } else {
- $expl = "exit-code " . (($status >> 8) & 0xff);
- }
- $why .=
- "\tunexpected exit status $status ($expl), expected $test{'expected-exit'}\n";
- }
-
- $tmp = &check_output($test{'long-name'}, $tempo, 'stdout',
- $test{'expected-stdout'}, $test{'expected-stdout-pattern'});
- return undef if !defined $tmp;
- if ($tmp ne '') {
- $failed = 1;
- $why .= $tmp;
- }
-
- $tmp = &check_output($test{'long-name'}, $tempe, 'stderr',
- $test{'expected-stderr'}, $test{'expected-stderr-pattern'});
- return undef if !defined $tmp;
- if ($tmp ne '') {
- $failed = 1;
- $why .= $tmp;
- }
-
- if (defined $test{'perl-cleanup'}) {
- eval $test{'perl-cleanup'};
- if ($@ ne '') {
- print STDERR "$prog:$test{':long-name'}: error running perl-cleanup - $@\n";
- return undef;
- }
- }
-
- if (!chdir($pwd)) {
- print STDERR "$prog: couldn't cd to $pwd - $!\n";
- return undef;
- }
-
- if ($failed) {
- if (!$test{'expected-fail'}) {
- print "FAIL $name\n";
- $nxfailed++;
- } else {
- print "fail $name (as expected)\n";
- $nfailed++;
- }
- $why = "\tDescription"
- . &wrap_lines($test{'description'}, " (missing)\n")
- . $why;
- } elsif ($test{'expected-fail'}) {
- print "PASS $name (unexpectedly)\n";
- $nxpassed++;
- } else {
- print "pass $name\n";
- $npassed++;
- }
- print $why if $verbose;
- return 0;
-}
-
-sub
-scrub_dir
-{
- local($dir) = @_;
- local(@todo) = ();
- local($file);
-
- if (!opendir(DIR, $dir)) {
- print STDERR "$prog: couldn't open direcotry $dir - $!\n";
- return undef;
- }
- while ($file = readdir(DIR)) {
- push(@todo, $file) if $file ne '.' && $file ne '..';
- }
- closedir(DIR);
- foreach $file (@todo) {
- $file = "$dir/$file";
- if (-d $file) {
- return undef if !&scrub_dir($file);
- if (!rmdir($file)) {
- print STDERR "$prog: couldn't rmdir $file - $!\n";
- return undef;
- }
- } else {
- if (!unlink($file)) {
- print STDERR "$prog: couldn't unlink $file - $!\n";
- return undef;
- }
- }
- }
- return 1;
-}
-
-sub
-write_file
-{
- local($file, $str) = @_;
-
- if (!open(TEMP, "> $file")) {
- print STDERR "$prog: can't open $file - $!\n";
- return undef;
- }
- print TEMP $str;
- if (!close(TEMP)) {
- print STDERR "$prog: error writing $file - $!\n";
- return undef;
- }
- return 1;
-}
-
-sub
-check_output
-{
- local($name, $file, $what, $expect, $expect_pat) = @_;
- local($got) = '';
- local($why) = '';
- local($ret);
-
- if (!open(TEMP, "< $file")) {
- print STDERR "$prog:$name($what): couldn't open $file after running program - $!\n";
- return undef;
- }
- while (<TEMP>) {
- $got .= $_;
- }
- close(TEMP);
- if (defined $expect_pat) {
- $_ = $got;
- $ret = eval "$expect_pat";
- if ($@ ne '') {
- print STDERR "$prog:$name($what): error evaluating $what pattern: $expect_pat - $@\n";
- return undef;
- }
- if (!$ret) {
- $why = "\tunexpected $what - wanted pattern";
- $why .= &wrap_lines($expect_pat);
- $why .= "\tgot";
- $why .= &wrap_lines($got);
- }
- } else {
- $expect = '' if !defined $expect;
- if ($got ne $expect) {
- $why .= "\tunexpected $what - " . &first_diff($expect, $got) . "\n";
- $why .= "\twanted";
- $why .= &wrap_lines($expect);
- $why .= "\tgot";
- $why .= &wrap_lines($got);
- }
- }
- return $why;
-}
-
-sub
-wrap_lines
-{
- local($str, $empty) = @_;
- local($nonl) = substr($str, -1, 1) ne "\n";
-
- return (defined $empty ? $empty : " nothing\n") if $str eq '';
- substr($str, 0, 0) = ":\n";
- $str =~ s/\n/\n\t\t/g;
- if ($nonl) {
- $str .= "\n\t[incomplete last line]\n";
- } else {
- chop($str);
- chop($str);
- }
- return $str;
-}
-
-sub
-first_diff
-{
- local($exp, $got) = @_;
- local($lineno, $char) = (1, 1);
- local($i, $len);
- local($ce, $cg);
-
- $len = length($exp);
- if ($len != length($got)) {
- if ($len < length($got)) {
- if (substr($got, 0, $len) eq $exp) {
- return "got too much output";
- }
- } elsif (substr($exp, 0, $len) eq $got) {
- return "got too little output";
- }
- $len = length($got);
- }
- for ($i = 0; $i < $len; $i++) {
- $ce = substr($exp, $i, 1);
- $cg = substr($got, $i, 1);
- last if $ce ne $cg;
- $char++;
- if ($ce eq "\n") {
- $lineno++;
- $char = 1;
- }
- }
- return "first difference: line $lineno, char $char"
-}
-
-sub
-eval_exit
-{
- local($name, $status, $expect) = @_;
- local($expr);
- local($w, $e, $s) = ($status, ($status >> 8) & 0xff, $status & 0x7f);
-
- $e = -1000 if $status & 0xff;
- $s = -1000 if $s == 0x7f;
- if (!defined $expect) {
- $expr = '$w == 0';
- } elsif ($expect =~ /^(|-)\d+$/) {
- $expr = "\$e == $expect";
- } else {
- $expr = $expect;
- $expr =~ s/\b([wse])\b/\$$1/g;
- $expr =~ s/\b(SIG[A-Z0-9]+)\b/&$1/g;
- }
- $w = eval $expr;
- if ($@ ne '') {
- print STDERR "$prog:$test{':long-name'}: bad expected-exit expression: $expect ($@)\n";
- return undef;
- }
- return $w;
-}
-
-sub
-read_test
-{
- local($file, $in, *test) = @_;
- local($field, $val, $flags, $do_chop, $need_redo, $start_lineno);
-
- %test = ();
- while (<$in>) {
- next if /^\s*$/;
- next if /^ *#/;
- last if /^\s*---\s*$/;
- $start_lineno = $. if !defined $start_lineno;
- if (!/^([-\w]+):\s*(|\S|\S.*\S)\s*$/) {
- print STDERR "$prog:$file:$.: unrecognized line\n";
- return undef;
- }
- ($field, $val) = ($1, $2);
- if (defined $test{$field}) {
- print STDERR "$prog:$file:$.: multiple \"$field\" fields\n";
- return undef;
- }
- $flags = $test_fields{$field};
- if (!defined $flags) {
- print STDERR "$prog:$file:$.: unrecognized field \"$field\"\n";
- return undef;
- }
- $do_chop = $flags !~ /m/;
- $need_redo = 0;
- if ($val eq '' || $val eq '!') {
- if ($flags =~ /[Mm]/) {
- $do_chop = 1 if $val eq '!';
- $val = '';
- while (<$in>) {
- last if !/^\t/;
- $val .= $';
- }
- chop $val if $do_chop;
- $do_chop = 1;
- $need_redo = 1;
- } elsif ($val eq '') {
- print STDERR
- "$prog:$file:$.: no value given for field \"$field\"\n";
- return undef;
- }
- }
- $val .= "\n" if !$do_chop;
- $test{$field} = $val;
- redo if $need_redo;
- }
- if ($_ eq '') {
- if (%test) {
- print STDERR
- "$prog:$file:$start_lineno: end-of-file while reading test\n";
- return undef;
- }
- return 0;
- }
-
- while (($field, $val) = each %test_fields) {
- if ($val =~ /r/ && !defined $test{$field}) {
- print STDERR
- "$prog:$file:$start_lineno: required field \"$field\" missing\n";
- return undef;
- }
- }
-
- $test{':full-name'} = substr($file, $file_prefix_skip) . ":$test{'name'}";
- $test{':long-name'} = "$file:$start_lineno:$test{'name'}";
-
- # Syntax check on specific fields
- if (defined $test{'expected-fail'}) {
- if ($test{'expected-fail'} !~ /^(yes|no)$/) {
- print STDERR
- "$prog:$test{':long-name'}: bad value for expected-fail field\n";
- return undef;
- }
- $test{'expected-fail'} = $1 eq 'yes';
- } else {
- $test{'expected-fail'} = 0;
- }
- if (defined $test{'arguments'}) {
- local($firstc) = substr($test{'arguments'}, 0, 1);
-
- if (substr($test{'arguments'}, -1, 1) ne $firstc) {
- print STDERR "$prog:$test{':long-name'}: arguments field doesn't start and end with the same character\n";
- return undef;
- }
- }
- if (defined $test{'env-setup'}) {
- local($firstc) = substr($test{'env-setup'}, 0, 1);
-
- if (substr($test{'env-setup'}, -1, 1) ne $firstc) {
- print STDERR "$prog:$test{':long-name'}: env-setup field doesn't start and end with the same character\n";
- return undef;
- }
- }
- if (defined $test{'expected-exit'}) {
- local($val) = $test{'expected-exit'};
-
- if ($val =~ /^(|-)\d+$/) {
- if ($val < 0 || $val > 255) {
- print STDERR "$prog:$test{':long-name'}: expected-exit value $val not in 0..255\n";
- return undef;
- }
- } elsif ($val !~ /^([\s<>+-=*%\/&|!()]|\b[wse]\b|\bSIG[A-Z0-9]+\b)+$/) {
- print STDERR "$prog:$test{':long-name'}: bad expected-exit expression: $val\n";
- return undef;
- }
- } else {
- $test{'expected-exit'} = 0;
- }
- if (defined $test{'expected-stdout'}
- && defined $test{'expected-stdout-pattern'})
- {
- print STDERR "$prog:$test{':long-name'}: can't use both expected-stdout and expected-stdout-pattern\n";
- return undef;
- }
- if (defined $test{'expected-stderr'}
- && defined $test{'expected-stderr-pattern'})
- {
- print STDERR "$prog:$test{':long-name'}: can't use both expected-stderr and expected-stderr-pattern\n";
- return undef;
- }
- if (defined $test{'time-limit'}) {
- if ($test{'time-limit'} !~ /^\d+$/ || $test{'time-limit'} == 0) {
- print STDERR
- "$prog:$test{':long-name'}: bad value for time-limit field\n";
- return undef;
- }
- } elsif (defined $default_time_limit) {
- $test{'time-limit'} = $default_time_limit;
- }
-
- if (defined $known_tests{$test{'name'}}) {
- print STDERR "$prog:$test{':long-name'}: warning: duplicate test name ${test{'name'}}\n";
- }
- $known_tests{$test{'name'}} = 1;
-
- return 1;
-}
-
-sub
-touch
-{
- local(@files) = @_;
- local($file);
-
- foreach $file (@files) {
- if (!open(T, "> $file")) {
- die "Couldn't touch $file\n";
- }
- close(T);
- }
- return 1;
-}
-
-sub
-tty_msg
-{
- local($msg) = @_;
-
- open(TTY, "> /dev/tty") || return 0;
- print TTY $msg;
- close(TTY);
- return 1;
-}
-
-sub
-never_called_funcs
-{
- return 0;
- &tty_msg("hi\n");
- &touch("/tmp/foo");
- &never_called_funcs();
- &catch_sigalrm();
- $old_env{'foo'} = 'bar';
- $internal_test_fields{'foo'} = 'bar';
-}
diff --git a/bin/pdksh/tests/th.sh b/bin/pdksh/tests/th.sh
deleted file mode 100644
index 3ca78e8c955..00000000000
--- a/bin/pdksh/tests/th.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-
-#
-# Simple script to find perl and run it
-#
-
-# Avoid common problems with ENV (though perl shouldn't let it through)
-# (can you believe some shells don't have an unset???)
-unset ENV
-
-x=x
-[ -x /bin/sh ] 2> /dev/null || x=f
-
-IFS=:$IFS
-perl=
-for i in $PATH; do
- [ X"$i" = X ] && i=.
- for j in perl perl4 perl5 ; do
- [ -$x "$i/$j" ] && perl=$i/$j && break 2
- done
-done
-
-[ X"$perl" = X ] && {
- echo "$0: can't find perl - bye\n" 1>&2
- exit 1
- }
-
-exec $perl "$@"
diff --git a/bin/pdksh/tests/unclass1.t b/bin/pdksh/tests/unclass1.t
deleted file mode 100644
index 55d4e58976f..00000000000
--- a/bin/pdksh/tests/unclass1.t
+++ /dev/null
@@ -1,97 +0,0 @@
-name: xxx-quoted-newline-1
-description:
- Check that \<newline> works inside of ${}
-stdin:
- abc=2
- echo ${ab\
- c}
-expected-stdout:
- 2
----
-
-name: xxx-quoted-newline-2
-description:
- Check that \<newline> works at the start of a here document
-stdin:
- cat << EO\
- F
- hi
- EOF
-expected-stdout:
- hi
----
-
-name: xxx-quoted-newline-3
-description:
- Check that \<newline> works at the end of a here document
-stdin:
- cat << EOF
- hi
- EO\
- F
-expected-stdout:
- hi
----
-
-name: xxx-multi-assignment-cmd
-description:
- Check that assignments in a command affect subsequent assignments
- in the same command
-stdin:
- FOO=abc
- FOO=123 BAR=$FOO
- echo $BAR
-expected-stdout:
- 123
----
-
-name: xxx-exec-environment-1
-description:
- Check to see if exec sets it's environment correctly
-stdin:
- FOO=bar exec env
-expected-stdout-pattern:
- /(^|.*\n)FOO=bar\n/
----
-
-name: xxx-exec-environment-2
-description:
- Check to make sure exec doesn't change environment if a program
- isn't exec-ed
-stdin:
- env > bar1
- FOO=bar exec; env > bar2
- cmp -s bar1 bar2
----
-
-name: xxx-what-do-you-call-this-1
-stdin:
- echo "${foo:-"a"}*"
-expected-stdout:
- a*
----
-
-name: xxx-prefix-strip-1
-stdin:
- foo='a cdef'
- echo ${foo#a c}
-expected-stdout:
- def
----
-
-name: xxx-prefix-strip-2
-stdin:
- set a c
- x='a cdef'
- echo ${x#$*}
-expected-stdout:
- def
----
-
-name: xxx-variable-syntax-1
-stdin:
- echo ${:}
-expected-stderr-pattern:
- /bad substitution/
-expected-exit: 1
----
diff --git a/bin/pdksh/tests/unclass2.t b/bin/pdksh/tests/unclass2.t
deleted file mode 100644
index d9e14822e06..00000000000
--- a/bin/pdksh/tests/unclass2.t
+++ /dev/null
@@ -1,166 +0,0 @@
-name: xxx-subsitution-eval-order
-description:
- Check order of evaluation of expressions
-stdin:
- i=1 x= y=
- set -A A abc def GHI j G k
- echo ${A[x=(i+=1)]#${A[y=(i+=2)]}}
- echo $x $y
-expected-stdout:
- HI
- 2 4
----
-
-name: xxx-set-option-1
-description:
- Check option parsing in set
-stdin:
- set -A -vs A 1 3 2
- echo ${A[*]}
-expected-stderr:
- echo ${A[*]}
-expected-stdout:
- 1 2 3
----
-
-name: xxx-exec-1
-description:
- Check that exec exits for built-ins
-arguments: !-i!
-stdin:
- exec print hi
- echo still herre
-expected-stdout:
- hi
-expected-stderr-pattern: /.*/
----
-
-name: xxx-while-1
-description:
- Check the return value of while loops
- XXX need to do same for for/select/until loops
-stdin:
- i=x
- while [ $i != xxx ] ; do
- i=x$i
- if [ $i = xxx ] ; then
- false
- continue
- fi
- done
- echo loop1=$?
-
- i=x
- while [ $i != xxx ] ; do
- i=x$i
- if [ $i = xxx ] ; then
- false
- break
- fi
- done
- echo loop2=$?
-
- i=x
- while [ $i != xxx ] ; do
- i=x$i
- false
- done
- echo loop3=$?
-expected-stdout:
- loop1=0
- loop2=0
- loop3=1
----
-
-name: xxx-status-1
-description:
- Check that blank lines don't clear $?
-arguments: !-i!
-stdin:
- (exit 1)
- echo $?
- (exit 1)
-
- echo $?
- true
-expected-stdout:
- 1
- 1
-expected-stderr-pattern: /.*/
----
-
-name: xxx-status-2
-description:
- Check that $? is preserved in subshells, includes, traps.
-stdin:
- (exit 1)
-
- echo blank: $?
-
- (exit 2)
- (echo subshell: $?)
-
- echo 'echo include: $?' > foo
- (exit 3)
- . ./foo
-
- trap 'echo trap: $?' ERR
- (exit 4)
- echo exit: $?
-expected-stdout:
- blank: 1
- subshell: 2
- include: 3
- trap: 4
- exit: 4
----
-
-name: xxx-clean-chars-1
-description:
- Check MAGIC character is stuffed correctly
-stdin:
- echo `echo [£`
-expected-stdout:
- [£
----
-
-name: xxx-param-subst-qmark-1
-description:
- Check suppresion of error message with null string. According to
- POSIX, it shouldn't print the error as `word' isn't ommitted.
-stdin:
- unset foo
- x=
- echo x${foo?$x}
-expected-exit: 1
-expected-fail: yes
-expected-stderr-pattern: !/not set/
----
-
-name: xxx-param-_-1
-description:
- Check c flag is set.
-arguments: !-c!echo "[$-]"!
-expected-stdout-pattern: /^\[.*c.*\]$/
----
-
-name: env-prompt
-description:
- Check that prompt not printed when processing ENV
-env-setup: !ENV=./foo!
-perl-setup:
- system("cat > foo << EOF
- XXX=12
- PS1='X '
- false && echo hmmm
- EOF
- ");
-arguments: !-i!
-stdin:
- echo hi${XXX}there
-expected-stdout:
- hi12there
-expected-stderr: !
- X X
----
-
diff --git a/bin/pdksh/tests/version.t b/bin/pdksh/tests/version.t
deleted file mode 100644
index 23d834015fa..00000000000
--- a/bin/pdksh/tests/version.t
+++ /dev/null
@@ -1,8 +0,0 @@
-name: version-1
-description:
- Check version of shell.
-stdin:
- echo $KSH_VERSION
-expected-stdout:
- @(#)PD KSH v5.2.12 96/10/29
----
diff --git a/bin/pdksh/trap.c b/bin/pdksh/trap.c
deleted file mode 100644
index f1efe6451d9..00000000000
--- a/bin/pdksh/trap.c
+++ /dev/null
@@ -1,432 +0,0 @@
-/* $OpenBSD: trap.c,v 1.6 1997/09/01 18:30:13 deraadt Exp $ */
-
-/*
- * signal handling
- */
-
-/* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */
-#define FROM_TRAP_C
-#include "sh.h"
-
-/* Table is indexed by signal number
- *
- * The script siglist.sh generates siglist.out, which is a sorted, complete
- * list of signals
- */
-Trap sigtraps[SIGNALS+1] = {
- { SIGEXIT_, "EXIT", "Signal 0" },
-#include "siglist.out" /* generated by siglist.sh */
- { SIGERR_, "ERR", "Error handler" },
- };
-
-static struct sigaction Sigact_ign, Sigact_trap;
-
-void
-inittraps()
-{
-#ifdef HAVE_SYS_SIGLIST
-# ifndef SYS_SIGLIST_DECLARED
- extern char *sys_siglist[];
-# endif
- int i;
-
- /* Use system description, if available, for unknown signals... */
- for (i = 0; i < NSIG; i++)
- if (!sigtraps[i].name && sys_siglist[i][0])
- sigtraps[i].mess = sys_siglist[i];
-#endif /* HAVE_SYS_SIGLIST */
-
- sigemptyset(&Sigact_ign.sa_mask);
- Sigact_ign.sa_flags = KSH_SA_FLAGS;
- Sigact_ign.sa_handler = SIG_IGN;
- Sigact_trap = Sigact_ign;
- Sigact_trap.sa_handler = trapsig;
-
- sigtraps[SIGINT].flags |= TF_DFL_INTR | TF_TTY_INTR;
- sigtraps[SIGQUIT].flags |= TF_DFL_INTR | TF_TTY_INTR;
- sigtraps[SIGTERM].flags |= TF_DFL_INTR;/* not fatal for interactive */
- sigtraps[SIGHUP].flags |= TF_FATAL;
- sigtraps[SIGCHLD].flags |= TF_SHELL_USES;
-
- /* these are always caught so we can clean up any temproary files. */
- setsig(&sigtraps[SIGINT], trapsig, SS_RESTORE_ORIG);
- setsig(&sigtraps[SIGQUIT], trapsig, SS_RESTORE_ORIG);
- setsig(&sigtraps[SIGTERM], trapsig, SS_RESTORE_ORIG);
- setsig(&sigtraps[SIGHUP], trapsig, SS_RESTORE_ORIG);
-}
-
-#ifdef KSH
-static RETSIGTYPE alarm_catcher ARGS((int sig));
-
-void
-alarm_init()
-{
- sigtraps[SIGALRM].flags |= TF_SHELL_USES;
- setsig(&sigtraps[SIGALRM], alarm_catcher,
- SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
-}
-
-static RETSIGTYPE
-alarm_catcher(sig)
- int sig;
-{
- if (ksh_tmout_state == TMOUT_READING) {
- int left = alarm(0);
-
- if (left == 0) {
- ksh_tmout_state = TMOUT_LEAVING;
- intrsig = 1;
- } else
- alarm(left);
- }
- return RETSIGVAL;
-}
-#endif /* KSH */
-
-Trap *
-gettrap(name)
- const char *name;
-{
- int i;
- register Trap *p;
-
- if (digit(*name)) {
- int n;
-
- if (getn(name, &n) && 0 <= n && n < SIGNALS)
- return &sigtraps[n];
- return NULL;
- }
- for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
- if (p->name && strcasecmp(p->name, name) == 0)
- return p;
- return NULL;
-}
-
-/*
- * trap signal handler
- */
-RETSIGTYPE
-trapsig(i)
- int i;
-{
- Trap *p = &sigtraps[i];
- int save_errno = errno;
-
- trap = p->set = 1;
- if (p->flags & TF_DFL_INTR)
- intrsig = 1;
- if ((p->flags & TF_FATAL) && !p->trap) {
- fatal_trap = 1;
- intrsig = 1;
- }
- if (p->shtrap)
- (*p->shtrap)(i);
-#ifdef V7_SIGNALS
- if (sigtraps[i].cursig == trapsig) /* this for SIGCHLD,SIGALRM */
- sigaction(i, &Sigact_trap, (struct sigaction *) 0);
-#endif /* V7_SIGNALS */
- errno = save_errno;
- return RETSIGVAL;
-}
-
-/* called when we want to allow the user to ^C out of something - won't
- * work if user has trapped SIGINT.
- */
-void
-intrcheck()
-{
- if (intrsig)
- runtraps(TF_DFL_INTR|TF_FATAL);
-}
-
-/* called after EINTR to check if a signal with normally causes process
- * termination has been received.
- */
-int
-fatal_trap_check()
-{
- int i;
- Trap *p;
-
- /* todo: should check if signal is fatal, not the TF_DFL_INTR flag */
- for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
- if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL)))
- /* return value is used as an exit code */
- return 128 + p->signal;
- return 0;
-}
-
-/* Returns the signal number of any pending traps: ie, a signal which has
- * occured for which a trap has been set or for which the TF_DFL_INTR flag
- * is set.
- */
-int
-trap_pending()
-{
- int i;
- Trap *p;
-
- for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
- if (p->set && ((p->trap && p->trap[0])
- || ((p->flags & (TF_DFL_INTR|TF_FATAL))
- && !p->trap)))
- return p->signal;
- return 0;
-}
-
-/*
- * run any pending traps. If intr is set, only run traps that
- * can interrupt commands.
- */
-void
-runtraps(flag)
- int flag;
-{
- int i;
- register Trap *p;
-
-#ifdef KSH
- if (ksh_tmout_state == TMOUT_LEAVING) {
- ksh_tmout_state = TMOUT_EXECUTING;
- warningf(FALSE, "timed out waiting for input");
- unwind(LEXIT);
- } else
- /* XXX: this means the alarm will have no effect if a trap
- * is caught after the alarm() was started...not good.
- */
- ksh_tmout_state = TMOUT_EXECUTING;
-#endif /* KSH */
- if (!flag)
- trap = 0;
- if (flag & TF_DFL_INTR)
- intrsig = 0;
- if (flag & TF_FATAL)
- fatal_trap = 0;
- for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
- if (p->set && (!flag
- || ((p->flags & flag) && p->trap == (char *) 0)))
- runtrap(p);
-}
-
-void
-runtrap(p)
- Trap *p;
-{
- int i = p->signal;
- char *trapstr = p->trap;
- int oexstat;
- int UNINITIALIZED(old_changed);
-
- p->set = 0;
- if (trapstr == (char *) 0) { /* SIG_DFL */
- if (p->flags & TF_FATAL) {
- /* eg, SIGHUP */
- exstat = 128 + i;
- unwind(LLEAVE);
- }
- if (p->flags & TF_DFL_INTR) {
- /* eg, SIGINT, SIGQUIT, SIGTERM, etc. */
- exstat = 128 + i;
- unwind(LINTR);
- }
- return;
- }
- if (trapstr[0] == '\0') /* SIG_IGN */
- return;
- if (i == SIGEXIT_ || i == SIGERR_) { /* avoid recursion on these */
- old_changed = p->flags & TF_CHANGED;
- p->flags &= ~TF_CHANGED;
- p->trap = (char *) 0;
- }
- oexstat = exstat;
- command(trapstr);
- exstat = oexstat;
- if (i == SIGEXIT_ || i == SIGERR_) {
- if (p->flags & TF_CHANGED)
- /* don't clear TF_CHANGED */
- afree(trapstr, APERM);
- else
- p->trap = trapstr;
- p->flags |= old_changed;
- }
-}
-
-/* clear pending traps and reset user's trap handlers; used after fork(2) */
-void
-cleartraps()
-{
- int i;
- Trap *p;
-
- trap = 0;
- intrsig = 0;
- fatal_trap = 0;
- for (i = SIGNALS+1, p = sigtraps; --i >= 0; p++) {
- p->set = 0;
- if ((p->flags & TF_USER_SET) && (p->trap && p->trap[0]))
- settrap(p, (char *) 0);
- }
-}
-
-/* restore signals just before an exec(2) */
-void
-restoresigs()
-{
- int i;
- Trap *p;
-
- for (i = SIGNALS+1, p = sigtraps; --i >= 0; p++)
- if (p->flags & (TF_EXEC_IGN|TF_EXEC_DFL))
- setsig(p, (p->flags & TF_EXEC_IGN) ? SIG_IGN : SIG_DFL,
- SS_RESTORE_CURR|SS_FORCE);
-}
-
-void
-settrap(p, s)
- Trap *p;
- char *s;
-{
- handler_t f;
-
- if (p->trap)
- afree(p->trap, APERM);
- p->trap = str_save(s, APERM); /* handles s == 0 */
- p->flags |= TF_CHANGED;
- f = !s ? SIG_DFL : s[0] ? trapsig : SIG_IGN;
-
- p->flags |= TF_USER_SET;
- if ((p->flags & (TF_DFL_INTR|TF_FATAL)) && f == SIG_DFL)
- f = trapsig;
- else if (p->flags & TF_SHELL_USES) {
- if (!(p->flags & TF_ORIG_IGN) || Flag(FTALKING)) {
- /* do what user wants at exec time */
- p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL);
- if (f == SIG_IGN)
- p->flags |= TF_EXEC_IGN;
- else
- p->flags |= TF_EXEC_DFL;
- }
- /* assumes handler already set to what shell wants it
- * (normally trapsig, but could be j_sigchld() or SIG_IGN)
- */
- return;
- }
-
- /* todo: should we let user know signal is ignored? how? */
- setsig(p, f, SS_RESTORE_CURR|SS_USER);
-}
-
-/* Called by c_print() when writing to a co-process to ensure SIGPIPE won't
- * kill shell (unless user catches it and exits)
- */
-int
-block_pipe()
-{
- int restore_dfl = 0;
- Trap *p = &sigtraps[SIGPIPE];
-
- if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) {
- setsig(p, SIG_IGN, SS_RESTORE_CURR);
- if (p->flags & TF_ORIG_DFL)
- restore_dfl = 1;
- } else if (p->cursig == SIG_DFL) {
- setsig(p, SIG_IGN, SS_RESTORE_CURR);
- restore_dfl = 1; /* restore to SIG_DFL */
- }
- return restore_dfl;
-}
-
-/* Called by c_print() to undo whatever block_pipe() did */
-void
-restore_pipe(restore_dfl)
- int restore_dfl;
-{
- if (restore_dfl)
- setsig(&sigtraps[SIGPIPE], SIG_DFL, SS_RESTORE_CURR);
-}
-
-/* Set action for a signal. Action may not be set if original
- * action was SIG_IGN, depending on the value of flags and
- * FTALKING.
- */
-int
-setsig(p, f, flags)
- Trap *p;
- handler_t f;
- int flags;
-{
- struct sigaction sigact;
-
- if (p->signal == SIGEXIT_ || p->signal == SIGERR_)
- return 1;
-
- /* First time setting this signal? If so, get and note the current
- * setting.
- */
- if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) {
- sigaction(p->signal, &Sigact_ign, &sigact);
- p->flags |= sigact.sa_handler == SIG_IGN ?
- TF_ORIG_IGN : TF_ORIG_DFL;
- p->cursig = SIG_IGN;
- }
-
- /* Generally, an ignored signal stays ignored, except if
- * - the user of an interactive shell wants to change it
- * - the shell wants for force a change
- */
- if ((p->flags & TF_ORIG_IGN) && !(flags & SS_FORCE)
- && (!(flags & SS_USER) || !Flag(FTALKING)))
- return 0;
-
- setexecsig(p, flags & SS_RESTORE_MASK);
-
- /* This is here 'cause there should be a way of clearing shtraps, but
- * don't know if this is a sane way of doing it. At the moment,
- * all users of shtrap are lifetime users (SIGCHLD, SIGALRM, SIGWINCH).
- */
- if (!(flags & SS_USER))
- p->shtrap = (handler_t) 0;
- if (flags & SS_SHTRAP) {
- p->shtrap = f;
- f = trapsig;
- }
-
- if (p->cursig != f) {
- p->cursig = f;
- sigemptyset(&sigact.sa_mask);
- sigact.sa_flags = KSH_SA_FLAGS;
- sigact.sa_handler = f;
- sigaction(p->signal, &sigact, (struct sigaction *) 0);
- }
-
- return 1;
-}
-
-/* control what signal is set to before an exec() */
-void
-setexecsig(p, restore)
- Trap *p;
- int restore;
-{
- /* XXX debugging */
- if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL)))
- internal_errorf(1, "setexecsig: unset signal %d(%s)",
- p->signal, p->name);
-
- /* restore original value for exec'd kids */
- p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL);
- switch (restore & SS_RESTORE_MASK) {
- case SS_RESTORE_CURR: /* leave things as they currently are */
- break;
- case SS_RESTORE_ORIG:
- p->flags |= p->flags & TF_ORIG_IGN ? TF_EXEC_IGN : TF_EXEC_DFL;
- break;
- case SS_RESTORE_DFL:
- p->flags |= TF_EXEC_DFL;
- break;
- case SS_RESTORE_IGN:
- p->flags |= TF_EXEC_IGN;
- break;
- }
-}
diff --git a/bin/pdksh/tree.c b/bin/pdksh/tree.c
deleted file mode 100644
index 93e3f9d7de7..00000000000
--- a/bin/pdksh/tree.c
+++ /dev/null
@@ -1,656 +0,0 @@
-/* $OpenBSD: tree.c,v 1.5 1997/09/01 18:30:15 deraadt Exp $ */
-
-/*
- * command tree climbing
- */
-
-#include "sh.h"
-
-#define INDENT 4
-
-#define tputc(c, shf) shf_putchar(c, shf);
-static void ptree ARGS((struct op *t, int indent, struct shf *f));
-static void pioact ARGS((struct shf *f, int indent, struct ioword *iop));
-static void tputC ARGS((int c, struct shf *shf));
-static void tputS ARGS((char *wp, struct shf *shf));
-static void vfptreef ARGS((struct shf *shf, int indent, const char *fmt, va_list va));
-static struct ioword **iocopy ARGS((struct ioword **iow, Area *ap));
-static void iofree ARGS((struct ioword **iow, Area *ap));
-
-/*
- * print a command tree
- */
-
-static void
-ptree(t, indent, shf)
- register struct op *t;
- int indent;
- register struct shf *shf;
-{
- register char **w;
- struct ioword **ioact;
- struct op *t1;
-
- Chain:
- if (t == NULL)
- return;
- switch (t->type) {
- case TCOM:
- if (t->vars)
- for (w = t->vars; *w != NULL; )
- fptreef(shf, indent, "%S ", *w++);
- else
- fptreef(shf, indent, "#no-vars# ");
- if (t->args)
- for (w = t->args; *w != NULL; )
- fptreef(shf, indent, "%S ", *w++);
- else
- fptreef(shf, indent, "#no-args# ");
- break;
- case TEXEC:
- t = t->left;
- goto Chain;
- case TPAREN:
- fptreef(shf, indent + 2, "( %T) ", t->left);
- break;
- case TPIPE:
- fptreef(shf, indent, "%T| ", t->left);
- t = t->right;
- goto Chain;
- case TLIST:
- fptreef(shf, indent, "%T%;", t->left);
- t = t->right;
- goto Chain;
- case TOR:
- case TAND:
- fptreef(shf, indent, "%T%s %T",
- t->left, (t->type==TOR) ? "||" : "&&", t->right);
- break;
- case TBANG:
- fptreef(shf, indent, "! ");
- t = t->right;
- goto Chain;
- case TDBRACKET:
- {
- int i;
-
- fptreef(shf, indent, "[[");
- for (i = 0; t->args[i]; i++)
- fptreef(shf, indent, " %S", t->args[i]);
- fptreef(shf, indent, " ]] ");
- break;
- }
-#ifdef KSH
- case TSELECT:
- fptreef(shf, indent, "select %s ", t->str);
- /* fall through */
-#endif /* KSH */
- case TFOR:
- if (t->type == TFOR)
- fptreef(shf, indent, "for %s ", t->str);
- if (t->vars != NULL) {
- fptreef(shf, indent, "in ");
- for (w = t->vars; *w; )
- fptreef(shf, indent, "%S ", *w++);
- fptreef(shf, indent, "%;");
- }
- fptreef(shf, indent + INDENT, "do%N%T", t->left);
- fptreef(shf, indent, "%;done ");
- break;
- case TCASE:
- fptreef(shf, indent, "case %S in", t->str);
- for (t1 = t->left; t1 != NULL; t1 = t1->right) {
- fptreef(shf, indent, "%N(");
- for (w = t1->vars; *w != NULL; w++)
- fptreef(shf, indent, "%S%c", *w,
- (w[1] != NULL) ? '|' : ')');
- fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left);
- }
- fptreef(shf, indent, "%Nesac ");
- break;
- case TIF:
- case TELIF:
- /* 3 == strlen("if ") */
- fptreef(shf, indent + 3, "if %T", t->left);
- for (;;) {
- t = t->right;
- if (t->left != NULL) {
- fptreef(shf, indent, "%;");
- fptreef(shf, indent + INDENT, "then%N%T",
- t->left);
- }
- if (t->right == NULL || t->right->type != TELIF)
- break;
- t = t->right;
- fptreef(shf, indent, "%;");
- /* 5 == strlen("elif ") */
- fptreef(shf, indent + 5, "elif %T", t->left);
- }
- if (t->right != NULL) {
- fptreef(shf, indent, "%;");
- fptreef(shf, indent + INDENT, "else%;%T", t->right);
- }
- fptreef(shf, indent, "%;fi ");
- break;
- case TWHILE:
- case TUNTIL:
- /* 6 == strlen("while"/"until") */
- fptreef(shf, indent + 6, "%s %T",
- (t->type==TWHILE) ? "while" : "until",
- t->left);
- fptreef(shf, indent, "%;do");
- fptreef(shf, indent + INDENT, "%;%T", t->right);
- fptreef(shf, indent, "%;done ");
- break;
- case TBRACE:
- fptreef(shf, indent + INDENT, "{%;%T", t->left);
- fptreef(shf, indent, "%;} ");
- break;
- case TCOPROC:
- fptreef(shf, indent, "%T|& ", t->left);
- break;
- case TASYNC:
- fptreef(shf, indent, "%T& ", t->left);
- break;
- case TFUNCT:
- fptreef(shf, indent, "function %s %T", t->str, t->left);
- break;
- case TTIME:
- fptreef(shf, indent, "time %T", t->left);
- break;
- default:
- fptreef(shf, indent, "<botch>");
- break;
- }
- if ((ioact = t->ioact) != NULL) {
- int need_nl = 0;
-
- while (*ioact != NULL)
- pioact(shf, indent, *ioact++);
- /* Print here documents after everything else... */
- for (ioact = t->ioact; *ioact != NULL; ) {
- struct ioword *iop = *ioact++;
-
- /* name is 0 when tracing (set -x) */
- if ((iop->flag & IOTYPE) == IOHERE && iop->name) {
- struct shf *rshf;
- char buf[1024];
- int n;
-
- tputc('\n', shf);
- if ((rshf = shf_open(iop->name, O_RDONLY, 0, 0))) {
- while ((n = shf_read(buf, sizeof(buf), rshf))
- > 0)
- shf_write(buf, n, shf);
- shf_close(rshf);
- } else
- errorf("can't open %s - %s",
- iop->name, strerror(errno));
- fptreef(shf, indent, "%s", evalstr(iop->delim, 0));
- need_nl = 1;
- }
- }
- /* Last delimiter must be followed by a newline (this often
- * leads to an extra blank line, but its not worth worrying
- * about)
- */
- if (need_nl)
- tputc('\n', shf);
- }
-}
-
-static void
-pioact(shf, indent, iop)
- register struct shf *shf;
- int indent;
- register struct ioword *iop;
-{
- int flag = iop->flag;
- int type = flag & IOTYPE;
- int expected;
-
- expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0
- : (type == IOCAT || type == IOWRITE) ? 1
- : (type == IODUP && (iop->unit == !(flag & IORDUP))) ?
- iop->unit
- : iop->unit + 1;
- if (iop->unit != expected)
- tputc('0' + iop->unit, shf);
-
- switch (type) {
- case IOREAD:
- fptreef(shf, indent, "< ");
- break;
- case IOHERE:
- if (flag&IOSKIP)
- fptreef(shf, indent, "<<- ");
- else
- fptreef(shf, indent, "<< ");
- break;
- case IOCAT:
- fptreef(shf, indent, ">> ");
- break;
- case IOWRITE:
- if (flag&IOCLOB)
- fptreef(shf, indent, ">| ");
- else
- fptreef(shf, indent, "> ");
- break;
- case IORDWR:
- fptreef(shf, indent, "<> ");
- break;
- case IODUP:
- if (flag & IORDUP)
- fptreef(shf, indent, "<&");
- else
- fptreef(shf, indent, ">&");
- break;
- }
- /* name/delim are 0 when printing syntax errors */
- if (type == IOHERE) {
- if (iop->delim)
- fptreef(shf, indent, "%S ", iop->delim);
- } else if (iop->name)
- fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",
- iop->name);
-}
-
-
-/*
- * variants of fputc, fputs for ptreef and snptreef
- */
-
-static void
-tputC(c, shf)
- register int c;
- register struct shf *shf;
-{
- if ((c&0x60) == 0) { /* C0|C1 */
- tputc((c&0x80) ? '$' : '^', shf);
- tputc(((c&0x7F)|0x40), shf);
- } else if ((c&0x7F) == 0x7F) { /* DEL */
- tputc((c&0x80) ? '$' : '^', shf);
- tputc('?', shf);
- } else
- tputc(c, shf);
-}
-
-static void
-tputS(wp, shf)
- register char *wp;
- register struct shf *shf;
-{
- register int c, quoted=0;
-
- while (1)
- switch ((c = *wp++)) {
- case EOS:
- return;
- case CHAR:
- tputC(*wp++, shf);
- break;
- case QCHAR:
- c = *wp++;
- if (!quoted || (c == '"' || c == '`' || c == '$'))
- tputc('\\', shf);
- tputC(c, shf);
- break;
- case COMSUB:
- tputc('$', shf);
- tputc('(', shf);
- while (*wp != 0)
- tputC(*wp++, shf);
- tputc(')', shf);
- break;
- case EXPRSUB:
- tputc('$', shf);
- tputc('(', shf);
- tputc('(', shf);
- while (*wp != 0)
- tputC(*wp++, shf);
- tputc(')', shf);
- tputc(')', shf);
- break;
- case OQUOTE:
- quoted = 1;
- tputc('"', shf);
- break;
- case CQUOTE:
- quoted = 0;
- tputc('"', shf);
- break;
- case OSUBST:
- tputc('$', shf);
- tputc('{', shf);
- while ((c = *wp++) != 0)
- tputC(c, shf);
- break;
- case CSUBST:
- tputc('}', shf);
- break;
-#ifdef KSH
- case OPAT:
- tputc(*wp++, shf);
- tputc('(', shf);
- break;
- case SPAT:
- tputc('|', shf);
- break;
- case CPAT:
- tputc(')', shf);
- break;
-#endif /* KSH */
- }
-}
-
-/*
- * this is the _only_ way to reliably handle
- * variable args with an ANSI compiler
- */
-/* VARARGS */
-int
-#ifdef HAVE_PROTOTYPES
-fptreef(struct shf *shf, int indent, const char *fmt, ...)
-#else
-fptreef(shf, indent, fmt, va_alist)
- struct shf *shf;
- int indent;
- const char *fmt;
- va_dcl
-#endif
-{
- va_list va;
-
- SH_VA_START(va, fmt);
-
- vfptreef(shf, indent, fmt, va);
- va_end(va);
- return 0;
-}
-
-/* VARARGS */
-char *
-#ifdef HAVE_PROTOTYPES
-snptreef(char *s, int n, const char *fmt, ...)
-#else
-snptreef(s, n, fmt, va_alist)
- char *s;
- int n;
- const char *fmt;
- va_dcl
-#endif
-{
- va_list va;
- struct shf shf;
-
- shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);
-
- SH_VA_START(va, fmt);
- vfptreef(&shf, 0, fmt, va);
- va_end(va);
-
- return shf_sclose(&shf); /* null terminates */
-}
-
-static void
-vfptreef(shf, indent, fmt, va)
- register struct shf *shf;
- int indent;
- const char *fmt;
- register va_list va;
-{
- register int c;
-
- while ((c = *fmt++))
- if (c == '%') {
- register long n;
- register char *p;
- int neg;
-
- switch ((c = *fmt++)) {
- case 'c':
- tputc(va_arg(va, int), shf);
- break;
- case 's':
- p = va_arg(va, char *);
- while (*p)
- tputc(*p++, shf);
- break;
- case 'S': /* word */
- p = va_arg(va, char *);
- tputS(p, shf);
- break;
- case 'd': case 'u': /* decimal */
- n = (c == 'd') ? va_arg(va, int)
- : va_arg(va, unsigned int);
- neg = c=='d' && n<0;
- p = ulton((neg) ? -n : n, 10);
- if (neg)
- *--p = '-';
- while (*p)
- tputc(*p++, shf);
- break;
- case 'T': /* format tree */
- ptree(va_arg(va, struct op *), indent, shf);
- break;
- case ';': /* newline or ; */
- case 'N': /* newline or space */
- if (shf->flags & SHF_STRING) {
- if (c == ';')
- tputc(';', shf);
- tputc(' ', shf);
- } else {
- int i;
-
- tputc('\n', shf);
- for (i = indent; i >= 8; i -= 8)
- tputc('\t', shf);
- for (; i > 0; --i)
- tputc(' ', shf);
- }
- break;
- case 'R':
- pioact(shf, indent, va_arg(va, struct ioword *));
- break;
- default:
- tputc(c, shf);
- break;
- }
- } else
- tputc(c, shf);
-}
-
-/*
- * copy tree (for function definition)
- */
-
-struct op *
-tcopy(t, ap)
- register struct op *t;
- Area *ap;
-{
- register struct op *r;
- register char **tw, **rw;
-
- if (t == NULL)
- return NULL;
-
- r = (struct op *) alloc(sizeof(struct op), ap);
-
- r->type = t->type;
- r->u.evalflags = t->u.evalflags;
-
- r->str = t->type == TCASE ? wdcopy(t->str, ap) : str_save(t->str, ap);
-
- if (t->vars == NULL)
- r->vars = NULL;
- else {
- for (tw = t->vars; *tw++ != NULL; )
- ;
- rw = r->vars = (char **)
- alloc((int)(tw - t->vars) * sizeof(*tw), ap);
- for (tw = t->vars; *tw != NULL; )
- *rw++ = wdcopy(*tw++, ap);
- *rw = NULL;
- }
-
- if (t->args == NULL)
- r->args = NULL;
- else {
- for (tw = t->args; *tw++ != NULL; )
- ;
- rw = r->args = (char **)
- alloc((int)(tw - t->args) * sizeof(*tw), ap);
- for (tw = t->args; *tw != NULL; )
- *rw++ = wdcopy(*tw++, ap);
- *rw = NULL;
- }
-
- r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
-
- r->left = tcopy(t->left, ap);
- r->right = tcopy(t->right, ap);
-
- return r;
-}
-
-char *
-wdcopy(wp, ap)
- const char *wp;
- Area *ap;
-{
- size_t len = wdscan(wp, EOS) - wp;
- return memcpy(alloc(len, ap), wp, len);
-}
-
-/* return the position of prefix c in wp plus 1 */
-char *
-wdscan(wp, c)
- register const char *wp;
- register int c;
-{
- register int nest = 0;
-
- while (1)
- switch (*wp++) {
- case EOS:
- return (char *) wp;
- case CHAR:
- case QCHAR:
- wp++;
- break;
- case COMSUB:
- case EXPRSUB:
- while (*wp++ != 0)
- ;
- break;
- case OQUOTE:
- case CQUOTE:
- break;
- case OSUBST:
- nest++;
- while (*wp++ != '\0')
- ;
- break;
- case CSUBST:
- if (c == CSUBST && nest == 0)
- return (char *) wp;
- nest--;
- break;
-#ifdef KSH
- case OPAT:
- nest++;
- wp++;
- break;
- case SPAT:
- case CPAT:
- if (c == wp[-1] && nest == 0)
- return (char *) wp;
- if (wp[-1] == CPAT)
- nest--;
- break;
-#endif /* KSH */
- }
-}
-
-static struct ioword **
-iocopy(iow, ap)
- register struct ioword **iow;
- Area *ap;
-{
- register struct ioword **ior;
- register int i;
-
- for (ior = iow; *ior++ != NULL; )
- ;
- ior = (struct ioword **) alloc((int)(ior - iow) * sizeof(*ior), ap);
-
- for (i = 0; iow[i] != NULL; i++) {
- register struct ioword *p, *q;
-
- p = iow[i];
- q = (struct ioword *) alloc(sizeof(*p), ap);
- ior[i] = q;
- *q = *p;
- if (p->name != (char *) 0)
- q->name = wdcopy(p->name, ap);
- if (p->delim != (char *) 0)
- q->delim = wdcopy(p->delim, ap);
- }
- ior[i] = NULL;
-
- return ior;
-}
-
-/*
- * free tree (for function definition)
- */
-
-void
-tfree(t, ap)
- register struct op *t;
- Area *ap;
-{
- register char **w;
-
- if (t == NULL)
- return;
-
- if (t->str != NULL)
- afree((void*)t->str, ap);
-
- if (t->vars != NULL) {
- for (w = t->vars; *w != NULL; w++)
- afree((void*)*w, ap);
- afree((void*)t->vars, ap);
- }
-
- if (t->args != NULL) {
- for (w = t->args; *w != NULL; w++)
- afree((void*)*w, ap);
- afree((void*)t->args, ap);
- }
-
- if (t->ioact != NULL)
- iofree(t->ioact, ap);
-
- tfree(t->left, ap);
- tfree(t->right, ap);
-
- afree((void*)t, ap);
-}
-
-static void
-iofree(iow, ap)
- struct ioword **iow;
- Area *ap;
-{
- register struct ioword **iop;
- register struct ioword *p;
-
- for (iop = iow; (p = *iop++) != NULL; ) {
- if (p->name != NULL)
- afree((void*)p->name, ap);
- afree((void*)p, ap);
- }
-}
diff --git a/bin/pdksh/tree.h b/bin/pdksh/tree.h
deleted file mode 100644
index 863061dd91d..00000000000
--- a/bin/pdksh/tree.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/* $OpenBSD: tree.h,v 1.2 1996/08/19 20:09:02 downsj Exp $ */
-
-/*
- * command trees for compile/execute
- */
-
-/* $From: tree.h,v 1.3 1994/05/31 13:34:34 michael Exp $ */
-
-#define NOBLOCK ((struct op *)NULL)
-#define NOWORD ((char *)NULL)
-#define NOWORDS ((char **)NULL)
-
-/*
- * Description of a command or an operation on commands.
- */
-struct op {
- short type; /* operation type, see below */
- union { /* WARNING: newtp(), tcopy() use evalflags = 0 to clear union */
- short evalflags; /* TCOM: arg expansion eval() flags */
- short ksh_func; /* TFUNC: function x (vs x()) */
- } u;
- char **args; /* arguments to a command */
- char **vars; /* variable assignments */
- struct ioword **ioact; /* IO actions (eg, < > >>) */
- struct op *left, *right; /* descendents */
- char *str; /* word for case; identifier for for,
- * select, and functions;
- * path to execute for TEXEC
- */
-};
-
-/* Tree.type values */
-#define TEOF 0
-#define TCOM 1 /* command */
-#define TPAREN 2 /* (c-list) */
-#define TPIPE 3 /* a | b */
-#define TLIST 4 /* a ; b */
-#define TOR 5 /* || */
-#define TAND 6 /* && */
-#define TBANG 7 /* ! */
-#define TDBRACKET 8 /* [[ .. ]] */
-#define TFOR 9
-#define TSELECT 10
-#define TCASE 11
-#define TIF 12
-#define TWHILE 13
-#define TUNTIL 14
-#define TELIF 15
-#define TPAT 16 /* pattern in case */
-#define TBRACE 17 /* {c-list} */
-#define TASYNC 18 /* c & */
-#define TFUNCT 19 /* function name { command; } */
-#define TTIME 20 /* time pipeline */
-#define TEXEC 21 /* fork/exec eval'd TCOM */
-#define TCOPROC 22 /* coprocess |& */
-
-/*
- * prefix codes for words in command tree
- */
-#define EOS 0 /* end of string */
-#define CHAR 1 /* unquoted character */
-#define QCHAR 2 /* quoted character */
-#define COMSUB 3 /* $() substitution (0 terminated) */
-#define EXPRSUB 4 /* $(()) substitution (0 terminated) */
-#define OQUOTE 5 /* opening " or ' */
-#define CQUOTE 6 /* closing " or ' */
-#define OSUBST 7 /* opening ${ substitution */
-#define CSUBST 8 /* closing } of above */
-#define OPAT 9 /* open pattern: *(, @(, etc. */
-#define SPAT 10 /* seperate pattern: | */
-#define CPAT 11 /* close pattern: ) */
-
-/*
- * IO redirection
- */
-struct ioword {
- int unit; /* unit affected */
- int flag; /* action (below) */
- char *name; /* file name */
- char *delim; /* delimiter for <<,<<- */
-};
-
-/* ioword.flag - type of redirection */
-#define IOTYPE 0xF /* type: bits 0:3 */
-#define IOREAD 0x1 /* < */
-#define IOWRITE 0x2 /* > */
-#define IORDWR 0x3 /* <>: todo */
-#define IOHERE 0x4 /* << (here file) */
-#define IOCAT 0x5 /* >> */
-#define IODUP 0x6 /* <&/>& */
-#define IOEVAL BIT(4) /* expand in << */
-#define IOSKIP BIT(5) /* <<-, skip ^\t* */
-#define IOCLOB BIT(6) /* >|, override -o noclobber */
-#define IORDUP BIT(7) /* x<&y (as opposed to x>&y) */
-#define IONAMEXP BIT(8) /* name has been expanded */
-
-/* execute/exchild flags */
-#define XEXEC BIT(0) /* execute without forking */
-#define XFORK BIT(1) /* fork before executing */
-#define XBGND BIT(2) /* command & */
-#define XPIPEI BIT(3) /* input is pipe */
-#define XPIPEO BIT(4) /* output is pipe */
-#define XPIPE (XPIPEI|XPIPEO) /* member of pipe */
-#define XXCOM BIT(5) /* `...` command */
-#define XPCLOSE BIT(6) /* exchild: close close_fd in parent */
-#define XCCLOSE BIT(7) /* exchild: close close_fd in child */
-#define XERROK BIT(8) /* non-zero exit ok (for set -e) */
-#define XCOPROC BIT(9) /* starting a co-process */
-
-/*
- * flags to control expansion of words (assumed by t->evalflags to fit
- * in a short)
- */
-#define DOBLANK BIT(0) /* perform blank interpretation */
-#define DOGLOB BIT(1) /* expand [?* */
-#define DOPAT BIT(2) /* quote *?[ */
-#define DOTILDE BIT(3) /* normal ~ expansion (first char) */
-#define DONTRUNCOMMAND BIT(4) /* do not run $(command) things */
-#define DOASNTILDE BIT(5) /* assignment ~ expansion (after =, :) */
-#define DOBRACE_ BIT(6) /* used by expand(): do brace expansion */
-#define DOMAGIC_ BIT(7) /* used by expand(): string contains MAGIC */
-#define DOTEMP_ BIT(8) /* ditto : in word part of ${..[%#=?]..} */
-#define DOVACHECK BIT(9) /* var assign check (for typeset, set, etc) */
-#define DOMARKDIRS BIT(10) /* force markdirs behaviour */
-
-/*
- * The arguments of [[ .. ]] expressions are kept in t->args[] and flags
- * indicating how the arguments have been munged are kept in t->vars[].
- * The contents of t->vars[] are stuffed strings (so they can be treated
- * like all other t->vars[]) in which the second character is the one that
- * is examined. The DB_* defines are the values for these second characters.
- */
-#define DB_NORM 1 /* normal argument */
-#define DB_OR 2 /* || -> -o conversion */
-#define DB_AND 3 /* && -> -a conversion */
-#define DB_BE 4 /* an inserted -BE */
-#define DB_PAT 5 /* a pattern argument */
diff --git a/bin/pdksh/tty.c b/bin/pdksh/tty.c
deleted file mode 100644
index 00a94cd3ae6..00000000000
--- a/bin/pdksh/tty.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/* $OpenBSD: tty.c,v 1.2 1996/10/01 02:05:51 downsj Exp $ */
-
-#include "sh.h"
-#include "ksh_stat.h"
-#define EXTERN
-#include "tty.h"
-#undef EXTERN
-
-int
-get_tty(fd, ts)
- int fd;
- TTY_state *ts;
-{
- int ret;
-
-# ifdef HAVE_TERMIOS_H
- ret = tcgetattr(fd, ts);
-# else /* HAVE_TERIOS_H */
-# ifdef HAVE_TERMIO_H
- ret = ioctl(fd, TCGETA, ts);
-# else /* HAVE_TERMIO_H */
- ret = ioctl(fd, TIOCGETP, &ts->sgttyb);
-# ifdef TIOCGATC
- if (ioctl(fd, TIOCGATC, &ts->lchars) < 0)
- ret = -1;
-# else
- if (ioctl(fd, TIOCGETC, &ts->tchars) < 0)
- ret = -1;
-# ifdef TIOCGLTC
- if (ioctl(fd, TIOCGLTC, &ts->ltchars) < 0)
- ret = -1;
-# endif /* TIOCGLTC */
-# endif /* TIOCGATC */
-# endif /* HAVE_TERMIO_H */
-# endif /* HAVE_TERIOS_H */
- return ret;
-}
-
-int
-set_tty(fd, ts, flags)
- int fd;
- TTY_state *ts;
- int flags;
-{
- int ret = 0;
-
-# ifdef HAVE_TERMIOS_H
- ret = tcsetattr(fd, TCSADRAIN, ts);
-# else /* HAVE_TERIOS_H */
-# ifdef HAVE_TERMIO_H
-# ifndef TCSETAW /* e.g. Cray-2 */
- /* first wait for output to drain */
-# ifdef TCSBRK
- if (ioctl(tty_fd, TCSBRK, 1) < 0)
- ret = -1;
-# else /* the following kludge is minimally intrusive, but sometimes fails */
- if (flags & TF_WAIT)
- sleep((unsigned)1); /* fake it */
-# endif
-# endif /* !TCSETAW */
-# if defined(_BSD_SYSV) || !defined(TCSETAW)
-/* _BSD_SYSV must force TIOCSETN instead of TIOCSETP (preserve type-ahead) */
- if (ioctl(tty_fd, TCSETA, ts) < 0)
- ret = -1;
-# else
- if (ioctl(tty_fd, TCSETAW, ts) < 0)
- ret = -1;
-# endif
-# else /* HAVE_TERMIO_H */
-# if defined(__mips) && (defined(_SYSTYPE_BSD43) || defined(__SYSTYPE_BSD43))
- /* Under RISC/os 5.00, bsd43 environment, after a tty driver
- * generated interrupt (eg, INTR, TSTP), all output to tty is
- * lost until a SETP is done (there must be a better way of
- * doing this...).
- */
- if (flags & TF_MIPSKLUDGE)
- ret = ioctl(fd, TIOCSETP, &ts->sgttyb);
- else
-# endif /* _SYSTYPE_BSD43 */
- ret = ioctl(fd, TIOCSETN, &ts->sgttyb);
-# ifdef TIOCGATC
- if (ioctl(fd, TIOCSATC, &ts->lchars) < 0)
- ret = -1;
-# else
- if (ioctl(fd, TIOCSETC, &ts->tchars) < 0)
- ret = -1;
-# ifdef TIOCGLTC
- if (ioctl(fd, TIOCSLTC, &ts->ltchars) < 0)
- ret = -1;
-# endif /* TIOCGLTC */
-# endif /* TIOCGATC */
-# endif /* HAVE_TERMIO_H */
-# endif /* HAVE_TERIOS_H */
- return ret;
-}
-
-
-/* Initialize tty_fd. Used for saving/reseting tty modes upon
- * foreground job completion and for setting up tty process group.
- */
-void
-tty_init(init_ttystate)
- int init_ttystate;
-{
- int do_close = 1;
- int tfd;
-
- if (tty_fd >= 0) {
- close(tty_fd);
- tty_fd = -1;
- }
- tty_devtty = 1;
-
- /* SCO can't job control on /dev/tty, so don't try... */
-#if !defined(__SCO__)
- if ((tfd = open("/dev/tty", O_RDWR, 0)) < 0) {
-#ifdef __NeXT
- /* rlogin on NeXT boxes does not set up the controlling tty,
- * so force it to be done here...
- */
- {
- extern char *ttyname ARGS((int));
- char *s = ttyname(isatty(2) ? 2 : 0);
- int fd;
-
- if (s && (fd = open(s, O_RDWR, 0)) >= 0) {
- close(fd);
- tfd = open("/dev/tty", O_RDWR, 0);
- }
- }
-#endif /* __NeXT */
-
-/* X11R5 xterm on mips doesn't set controlling tty properly - temporary hack */
-# if !defined(__mips) || !(defined(_SYSTYPE_BSD43) || defined(__SYSTYPE_BSD43))
- if (tfd < 0) {
- tty_devtty = 0;
- warningf(FALSE,
- "No controlling tty (open /dev/tty: %s)",
- strerror(errno));
- }
-# endif /* __mips */
- }
-#else /* !__SCO__ */
- tfd = -1;
-#endif /* __SCO__ */
-
- if (tfd < 0) {
- do_close = 0;
- if (isatty(0))
- tfd = 0;
- else if (isatty(2))
- tfd = 2;
- else {
- warningf(FALSE, "Can't find tty file descriptor");
- return;
- }
- }
- if ((tty_fd = ksh_dupbase(tfd, FDBASE)) < 0) {
- warningf(FALSE, "j_ttyinit: dup of tty fd failed: %s",
- strerror(errno));
- } else if (fd_clexec(tty_fd) < 0) {
- warningf(FALSE, "j_ttyinit: can't set close-on-exec flag: %s",
- strerror(errno));
- close(tty_fd);
- tty_fd = -1;
- } else if (init_ttystate)
- get_tty(tty_fd, &tty_state);
- if (do_close)
- close(tfd);
-}
-
-void
-tty_close()
-{
- if (tty_fd >= 0) {
- close(tty_fd);
- tty_fd = -1;
- }
-}
diff --git a/bin/pdksh/tty.h b/bin/pdksh/tty.h
deleted file mode 100644
index a6cd2dae1e9..00000000000
--- a/bin/pdksh/tty.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/* $OpenBSD: tty.h,v 1.2 1996/11/21 07:59:36 downsj Exp $ */
-
-/*
- tty.h -- centralized definitions for a variety of terminal interfaces
-
- created by DPK, Oct. 1986
-
- Rearranged to work with autoconf, added TTY_state, get_tty/set_tty
- Michael Rendell, May '94
-
- last edit: 30-Jul-1987 D A Gwyn
-*/
-
-/* some useful #defines */
-#ifdef EXTERN
-# define I__(i) = i
-#else
-# define I__(i)
-# define EXTERN extern
-# define EXTERN_DEFINED
-#endif
-
-/* Don't know of a system on which including sys/ioctl.h with termios.h
- * causes problems. If there is one, these lines need to be deleted and
- * aclocal.m4 needs to have stuff un-commented.
- */
-#ifdef SYS_IOCTL_WITH_TERMIOS
-# define SYS_IOCTL_WITH_TERMIOS
-#endif /* SYS_IOCTL_WITH_TERMIOS */
-#ifdef SYS_IOCTL_WITH_TERMIO
-# define SYS_IOCTL_WITH_TERMIO
-#endif /* SYS_IOCTL_WITH_TERMIO */
-
-#ifdef HAVE_TERMIOS_H
-# include <termios.h>
-# ifdef SYS_IOCTL_WITH_TERMIOS
-# if !(defined(sun) && !defined(__svr4__)) /* too many warnings on sunos */
- /* Need to include sys/ioctl.h on some systems to get the TIOCGWINSZ
- * stuff (eg, digital unix).
- */
-# include <sys/ioctl.h>
-# endif /* !(sun && !__svr4__) */
-# endif /* SYS_IOCTL_WITH_TERMIOS */
-typedef struct termios TTY_state;
-#else
-# ifdef HAVE_TERMIO_H
-# include <termio.h>
-# ifdef SYS_IOCTL_WITH_TERMIO
-# include <sys/ioctl.h> /* see comment above in termios stuff */
-# endif /* SYS_IOCTL_WITH_TERMIO */
-# if _BSD_SYSV /* BRL UNIX System V emulation */
-# ifndef NTTYDISC
-# define TIOCGETD _IOR( 't', 0, int )
-# define TIOCSETD _IOW( 't', 1, int )
-# define NTTYDISC 2
-# endif
-# ifndef TIOCSTI
-# define TIOCSTI _IOW( 't', 114, char )
-# endif
-# ifndef TIOCSPGRP
-# define TIOCSPGRP _IOW( 't', 118, int )
-# endif
-# endif /* _BSD_SYSV */
-typedef struct termio TTY_state;
-# else /* HAVE_TERMIO_H */
-/* Assume BSD tty stuff. Uses TIOCGETP, TIOCSETN; uses TIOCGATC/TIOCSATC if
- * available, otherwise it uses TIOCGETC/TIOCSETC (also uses TIOCGLTC/TIOCSLTC
- * if available)
- */
-# ifdef _MINIX
-# include <sgtty.h>
-# define TIOCSETN TIOCSETP
-# else
-# include <sys/ioctl.h>
-# endif
-typedef struct {
- struct sgttyb sgttyb;
-# ifdef TIOCGATC
- struct lchars lchars;
-# else /* TIOCGATC */
- struct tchars tchars;
-# ifdef TIOCGLTC
- struct ltchars ltchars;
-# endif /* TIOCGLTC */
-# endif /* TIOCGATC */
-} TTY_state;
-# endif /* HAVE_TERMIO_H */
-#endif /* HAVE_TERMIOS_H */
-
-/* Flags for set_tty() */
-#define TF_NONE 0x00
-#define TF_WAIT 0x01 /* drain output, even it requires sleep() */
-#define TF_MIPSKLUDGE 0x02 /* kludge to unwedge RISC/os 5.0 tty driver */
-
-EXTERN int tty_fd I__(-1); /* dup'd tty file descriptor */
-EXTERN int tty_devtty; /* true if tty_fd is from /dev/tty */
-EXTERN TTY_state tty_state; /* saved tty state */
-
-extern int get_tty ARGS((int fd, TTY_state *ts));
-extern int set_tty ARGS((int fd, TTY_state *ts, int flags));
-extern void tty_init ARGS((int init_ttystate));
-extern void tty_close ARGS((void));
-
-/* be sure not to interfere with anyone else's idea about EXTERN */
-#ifdef EXTERN_DEFINED
-# undef EXTERN_DEFINED
-# undef EXTERN
-#endif
-#undef I__
diff --git a/bin/pdksh/var.c b/bin/pdksh/var.c
deleted file mode 100644
index 8350846a148..00000000000
--- a/bin/pdksh/var.c
+++ /dev/null
@@ -1,1137 +0,0 @@
-/* $OpenBSD: var.c,v 1.6 1997/09/01 18:30:16 deraadt Exp $ */
-
-#include "sh.h"
-#include "ksh_time.h"
-#include "ksh_limval.h"
-#include "ksh_stat.h"
-#include <ctype.h>
-
-/*
- * Variables
- *
- * WARNING: unreadable code, needs a rewrite
- *
- * if (flag&INTEGER), val.i contains integer value, and type contains base.
- * otherwise, (val.s + type) contains string value.
- * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
- */
-static struct tbl vtemp;
-static struct table specials;
-static char *formatstr ARGS((struct tbl *vp, const char *s));
-static void export ARGS((struct tbl *vp, const char *val));
-static int special ARGS((const char *name));
-static void getspec ARGS((struct tbl *vp));
-static void setspec ARGS((struct tbl *vp));
-static void unsetspec ARGS((struct tbl *vp));
-static struct tbl *arraysearch ARGS((struct tbl *, int));
-
-/*
- * create a new block for function calls and simple commands
- * assume caller has allocated and set up e->loc
- */
-void
-newblock()
-{
- register struct block *l;
- static char *const empty[] = {null};
-
- l = (struct block *) alloc(sizeof(struct block), ATEMP);
- ainit(&l->area);
- if (!e->loc) {
- l->argc = 0;
- l->argv = (char **) empty;
- } else {
- l->argc = e->loc->argc;
- l->argv = e->loc->argv;
- }
- l->exit = l->error = NULL;
- tinit(&l->vars, &l->area, 0);
- tinit(&l->funs, &l->area, 0);
- l->next = e->loc;
- e->loc = l;
-}
-
-/*
- * pop a block handling special variables
- */
-void
-popblock()
-{
- register struct block *l = e->loc;
- register struct tbl *vp, **vpp = l->vars.tbls, *vq;
- register int i;
-
- e->loc = l->next; /* pop block */
- for (i = l->vars.size; --i >= 0; )
- if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL))
- if ((vq = global(vp->name))->flag & ISSET)
- setspec(vq);
- else
- unsetspec(vq);
- afreeall(&l->area);
- afree(l, ATEMP);
-}
-
-/* called by main() to initialize variable data structures */
-void
-initvar()
-{
- static const struct {
- const char *name;
- int v;
- } names[] = {
- { "COLUMNS", V_COLUMNS },
- { "IFS", V_IFS },
- { "OPTIND", V_OPTIND },
- { "PATH", V_PATH },
- { "POSIXLY_CORRECT", V_POSIXLY_CORRECT },
- { "TMPDIR", V_TMPDIR },
-#ifdef HISTORY
- { "HISTFILE", V_HISTFILE },
- { "HISTSIZE", V_HISTSIZE },
-#endif /* HISTORY */
-#ifdef EDIT
- { "EDITOR", V_EDITOR },
- { "VISUAL", V_VISUAL },
-#endif /* EDIT */
-#ifdef KSH
- { "MAIL", V_MAIL },
- { "MAILCHECK", V_MAILCHECK },
- { "MAILPATH", V_MAILPATH },
- { "RANDOM", V_RANDOM },
- { "SECONDS", V_SECONDS },
- { "TMOUT", V_TMOUT },
-#endif /* KSH */
- { (char *) 0, 0 }
- };
- int i;
- struct tbl *tp;
-
- tinit(&specials, APERM, 32); /* must be 2^n (currently 16 speciasl) */
- for (i = 0; names[i].name; i++) {
- tp = tenter(&specials, names[i].name, hash(names[i].name));
- tp->flag = DEFINED|ISSET;
- tp->type = names[i].v;
- }
-}
-
-/* Used to calculate an array index for global()/local(). Sets *arrayp to
- * non-zero if this is an array, sets *valp to the array index, returns
- * the basename of the array.
- */
-const char *
-array_index_calc(n, arrayp, valp)
- const char *n;
- bool_t *arrayp;
- int *valp;
-{
- const char *p;
- int len;
-
- *arrayp = FALSE;
- p = skip_varname(n, FALSE);
- if (p != n && *p == '[' && (len = array_ref_len(p))) {
- char *sub, *tmp;
- long rval;
-
- /* Calculate the value of the subscript */
- *arrayp = TRUE;
- tmp = str_nsave(p+1, len-2, ATEMP);
- sub = substitute(tmp, 0);
- afree(tmp, ATEMP);
- n = str_nsave(n, p - n, ATEMP);
- evaluate(sub, &rval, FALSE);
- if (rval < 0 || rval > ARRAYMAX)
- errorf("%s: subscript out of range", n);
- *valp = rval;
- afree(sub, ATEMP);
- }
- return n;
-}
-
-/*
- * Search for variable, if not found create globally.
- */
-struct tbl *
-global(n)
- register const char *n;
-{
- register struct block *l = e->loc;
- register struct tbl *vp;
- register int c;
- unsigned h;
- bool_t array;
- int val;
-
- /* Check to see if this is an array */
- n = array_index_calc(n, &array, &val);
- h = hash(n);
- c = n[0];
- if (!letter(c)) {
- if (array)
- errorf("bad substitution");
- vp = &vtemp;
- vp->flag = (DEFINED|RDONLY);
- vp->type = 0;
- vp->areap = ATEMP;
- *vp->name = c;
- if (digit(c)) {
- for (c = 0; digit(*n); n++)
- c = c*10 + *n-'0';
- if (c <= l->argc)
- setstr(vp, l->argv[c]);
- return vp;
- }
- if (n[1] != '\0')
- return vp;
- vp->flag |= ISSET|INTEGER;
- switch (c) {
- case '$':
- vp->val.i = kshpid;
- break;
- case '!':
- /* If no job, expand to nothing */
- if ((vp->val.i = j_async()) == 0)
- vp->flag &= ~(ISSET|INTEGER);
- break;
- case '?':
- vp->val.i = exstat;
- break;
- case '#':
- vp->val.i = l->argc;
- break;
- case '-':
- vp->flag &= ~INTEGER;
- vp->val.s = getoptions();
- break;
- default:
- vp->flag &= ~(ISSET|INTEGER);
- }
- return vp;
- }
- for (l = e->loc; ; l = l->next) {
- vp = tsearch(&l->vars, n, h);
- if (vp != NULL)
- if (array)
- return arraysearch(vp, val);
- else
- return vp;
- if (l->next == NULL)
- break;
- }
- vp = tenter(&l->vars, n, h);
- if (array)
- vp = arraysearch(vp, val);
- vp->flag |= DEFINED;
- if (special(n))
- vp->flag |= SPECIAL;
- return vp;
-}
-
-/*
- * Search for local variable, if not found create locally.
- */
-struct tbl *
-local(n, copy)
- register const char *n;
- bool_t copy;
-{
- register struct block *l = e->loc;
- register struct tbl *vp;
- unsigned h;
- bool_t array;
- int val;
-
- /* Check to see if this is an array */
- n = array_index_calc(n, &array, &val);
- h = hash(n);
- if (!letter(*n)) {
- vp = &vtemp;
- vp->flag = DEFINED|RDONLY;
- vp->type = 0;
- vp->areap = ATEMP;
- return vp;
- }
- vp = tenter(&l->vars, n, h);
- if (copy && !(vp->flag & DEFINED)) {
- struct block *ll = l;
- struct tbl *vq = (struct tbl *) 0;
-
- while ((ll = ll->next) && !(vq = tsearch(&ll->vars, n, h)))
- ;
- if (vq) {
- vp->flag |= vq->flag & (EXPORT|INTEGER|RDONLY
- |LJUST|RJUST|ZEROFIL
- |LCASEV|UCASEV_AL|INT_U|INT_L);
- if (vq->flag & INTEGER)
- vp->type = vq->type;
- vp->u2.field = vq->u2.field;
- }
- }
- if (array)
- vp = arraysearch(vp, val);
- vp->flag |= DEFINED;
- if (special(n))
- vp->flag |= SPECIAL;
- return vp;
-}
-
-/* get variable string value */
-char *
-str_val(vp)
- register struct tbl *vp;
-{
- char *s;
-
- if ((vp->flag&SPECIAL))
- getspec(vp);
- if (!(vp->flag&ISSET))
- s = null; /* special to dollar() */
- else if (!(vp->flag&INTEGER)) /* string source */
- s = vp->val.s + vp->type;
- else { /* integer source */
- /* worst case number length is when base=2, so use BITS(long) */
- /* minus base # number null */
- static char strbuf[1 + 2 + 1 + BITS(long) + 1];
- const char *digits = (vp->flag & UCASEV_AL) ?
- "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- : "0123456789abcdefghijklmnopqrstuvwxyz";
- register unsigned long n;
- register int base;
-
- s = strbuf + sizeof(strbuf);
- if (vp->flag & INT_U)
- n = (unsigned long) vp->val.i;
- else
- n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
- base = (vp->type == 0) ? 10 : vp->type;
-
- *--s = '\0';
- do {
- *--s = digits[n % base];
- n /= base;
- } while (n != 0);
- if (base != 10) {
- *--s = '#';
- *--s = digits[base % 10];
- if (base >= 10)
- *--s = digits[base / 10];
- }
- if (!(vp->flag & INT_U) && vp->val.i < 0)
- *--s = '-';
- if (vp->flag & (RJUST|LJUST)) /* case already dealt with */
- s = formatstr(vp, s);
- }
- return s;
-}
-
-/* get variable integer value, with error checking */
-long
-intval(vp)
- register struct tbl *vp;
-{
- long num;
- int base;
-
- base = getint(vp, &num);
- if (base == -1)
- /* XXX check calls - is error here ok by POSIX? */
- errorf("%s: bad number", str_val(vp));
- return num;
-}
-
-/* set variable to string value */
-void
-setstr(vq, s)
- register struct tbl *vq;
- const char *s;
-{
- if (!(vq->flag&INTEGER)) { /* string dest */
- if ((vq->flag&ALLOC)) {
- /* debugging */
- if (s >= vq->val.s
- && s <= vq->val.s + strlen(vq->val.s))
- internal_errorf(TRUE,
- "setstr: %s=%s: assigning to self",
- vq->name, s);
- afree((void*)vq->val.s, vq->areap);
- }
- vq->flag &= ~(ISSET|ALLOC);
- vq->type = 0;
- if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST)))
- s = formatstr(vq, s);
- if ((vq->flag&EXPORT))
- export(vq, s);
- else {
- vq->val.s = str_save(s, vq->areap);
- if (vq->val.s) /* <sjg> don't lie */
- vq->flag |= ALLOC;
- }
- } else /* integer dest */
- /* XXX is this correct? */
- v_evaluate(vq, s, FALSE);
- vq->flag |= ISSET;
- if ((vq->flag&SPECIAL))
- setspec(vq);
-}
-
-/* set variable to integer */
-void
-setint(vq, n)
- register struct tbl *vq;
- long n;
-{
- if (!(vq->flag&INTEGER)) {
- register struct tbl *vp = &vtemp;
- vp->flag = (ISSET|INTEGER);
- vp->type = 0;
- vp->areap = ATEMP;
- vp->val.i = n;
- setstr(vq, str_val(vp));
- } else
- vq->val.i = n;
- vq->flag |= ISSET;
- if ((vq->flag&SPECIAL))
- setspec(vq);
-}
-
-int
-getint(vp, nump)
- struct tbl *vp;
- long *nump;
-{
- register char *s;
- register int c;
- int base, neg;
- int have_base = 0;
- long num;
-
- if (vp->flag&SPECIAL)
- getspec(vp);
- /* XXX is it possible for ISSET to be set and val.s to be 0? */
- if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL))
- return -1;
- if (vp->flag&INTEGER) {
- *nump = vp->val.i;
- return vp->type;
- }
- s = vp->val.s + vp->type;
- if (s == NULL) /* redundent given initial test */
- s = null;
- base = 10;
- num = 0;
- neg = 0;
- for (c = *s++; c ; c = *s++) {
- if (c == '-') {
- neg++;
- } else if (c == '#') {
- base = (int) num;
- if (have_base || base < 2 || base > 36)
- return -1;
- num = 0;
- have_base = 1;
- } else if (letnum(c)) {
- if (isdigit(c))
- c -= '0';
- else if (islower(c))
- c -= 'a' - 10; /* todo: assumes ascii */
- else if (isupper(c))
- c -= 'A' - 10; /* todo: assumes ascii */
- else
- c = -1; /* _: force error */
- if (c < 0 || c >= base)
- return -1;
- num = num * base + c;
- } else
- return -1;
- }
- if (neg)
- num = -num;
- *nump = num;
- return base;
-}
-
-/* convert variable vq to integer variable, setting its value from vp
- * (vq and vp may be the same)
- */
-struct tbl *
-setint_v(vq, vp)
- register struct tbl *vq, *vp;
-{
- int base;
- long num;
-
- if ((base = getint(vp, &num)) == -1)
- return NULL;
- if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) {
- vq->flag &= ~ALLOC;
- afree(vq->val.s, vq->areap);
- }
- vq->val.i = num;
- if (vq->type == 0) /* default base */
- vq->type = base;
- vq->flag |= ISSET|INTEGER;
- if (vq->flag&SPECIAL)
- setspec(vq);
- return vq;
-}
-
-static char *
-formatstr(vp, s)
- struct tbl *vp;
- const char *s;
-{
- int olen, nlen;
- char *p, *q;
-
- olen = strlen(s);
-
- if (vp->flag & (RJUST|LJUST)) {
- if (!vp->u2.field) /* default field width */
- vp->u2.field = olen;
- nlen = vp->u2.field;
- } else
- nlen = olen;
-
- p = (char *) alloc(nlen + 1, ATEMP);
- if (vp->flag & (RJUST|LJUST)) {
- int slen;
-
- if (vp->flag & RJUST) {
- const char *q = s + olen;
- /* strip trailing spaces (at&t ksh uses q[-1] == ' ') */
- while (q > s && isspace(q[-1]))
- --q;
- slen = q - s;
- if (slen > vp->u2.field) {
- s += slen - vp->u2.field;
- slen = vp->u2.field;
- }
- shf_snprintf(p, nlen + 1,
- ((vp->flag & ZEROFIL) && digit(*s)) ?
- "%0*s%.*s" : "%*s%.*s",
- vp->u2.field - slen, null, slen, s);
- } else {
- /* strip leading spaces/zeros */
- while (isspace(*s))
- s++;
- if (vp->flag & ZEROFIL)
- while (*s == '0')
- s++;
- shf_snprintf(p, nlen + 1, "%-*.*s",
- vp->u2.field, vp->u2.field, s);
- }
- } else
- memcpy(p, s, olen + 1);
-
- if (vp->flag & UCASEV_AL) {
- for (q = p; *q; q++)
- if (islower(*q))
- *q = toupper(*q);
- } else if (vp->flag & LCASEV) {
- for (q = p; *q; q++)
- if (isupper(*q))
- *q = tolower(*q);
- }
-
- return p;
-}
-
-/*
- * make vp->val.s be "name=value" for quick exporting.
- */
-static void
-export(vp, val)
- register struct tbl *vp;
- const char *val;
-{
- register char *xp;
- char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;
- int namelen = strlen(vp->name);
- int vallen = strlen(val) + 1;
-
- vp->flag |= ALLOC;
- xp = (char*)alloc(namelen + 1 + vallen, vp->areap);
- memcpy(vp->val.s = xp, vp->name, namelen);
- xp += namelen;
- *xp++ = '=';
- vp->type = xp - vp->val.s; /* offset to value */
- memcpy(xp, val, vallen);
- if (op != NULL)
- afree((void*)op, vp->areap);
-}
-
-/*
- * lookup variable (according to (set&LOCAL)),
- * set its attributes (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL,
- * LCASEV, UCASEV_AL), and optionally set its value if an assignment.
- */
-struct tbl *
-typeset(var, set, clr, field, base)
- register const char *var;
- Tflag clr, set;
- int field, base;
-{
- register struct tbl *vp;
- struct tbl *vpbase, *t;
- char *tvar;
- const char *val;
-
- /* check for valid variable name, search for value */
- val = skip_varname(var, FALSE);
- if (val == var)
- return NULL;
- if (*val == '[') {
- int len;
-
- len = array_ref_len(val);
- if (len == 0)
- return NULL;
- /* IMPORT is only used when the shell starts up and is
- * setting up its environment. Allow only simple array
- * references at this time since parameter/command substitution
- * is preformed on the [expression], which would be a major
- * security hole.
- */
- if (set & IMPORT) {
- int i;
- for (i = 1; i < len - 1; i++)
- if (!digit(val[i]))
- return NULL;
- }
- val += len;
- }
- if (*val == '=')
- tvar = str_nsave(var, val++ - var, ATEMP);
- else {
- /* Importing from original envirnment: must have an = */
- if (set & IMPORT)
- return NULL;
- tvar = (char *) var;
- val = NULL;
- }
-
- /* Prevent typeset from creating a local PATH/ENV/SHELL */
- if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0
- || strcmp(tvar, "ENV") == 0
- || strcmp(tvar, "SHELL") == 0))
- errorf("%s: restricted", tvar);
-
- vp = (set&LOCAL) ? local(tvar, (set & LOCAL_COPY) ? TRUE : FALSE)
- : global(tvar);
- set &= ~(LOCAL|LOCAL_COPY);
-
- vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp;
-
- /* only allow export flag to be set. at&t ksh allows any attribute to
- * be changed, which means it can be truncated or modified
- * (-L/-R/-Z/-i).
- */
- if ((vpbase->flag&RDONLY)
- && (val || clr || (set & ~EXPORT)))
- /* XXX check calls - is error here ok by POSIX? */
- errorf("%s: is read only", tvar);
- if (val)
- afree(tvar, ATEMP);
-
- /* most calls are with set/clr == 0 */
- if (set | clr) {
- /* XXX if x[0] isn't set, there will be problems: need to have
- * one copy of attributes for arrays...
- */
- for (t = vpbase; t; t = t->u.array) {
- int fake_assign;
- char UNINITIALIZED(*s);
- char UNINITIALIZED(*free_me);
-
- fake_assign = (t->flag & ISSET) && (!val || t != vp)
- && ((set & (UCASEV_AL|LCASEV|LJUST|RJUST|ZEROFIL))
- || ((t->flag & INTEGER) && (clr & INTEGER))
- || (!(t->flag & INTEGER) && (set & INTEGER)));
- if (fake_assign) {
- if (t->flag & INTEGER) {
- s = str_val(t);
- free_me = (char *) 0;
- } else {
- s = t->val.s + t->type;
- free_me = (t->flag & ALLOC) ? t->val.s
- : (char *) 0;
- }
- t->flag &= ~ALLOC;
- }
- if (!(t->flag & INTEGER) && (set & INTEGER)) {
- t->type = 0;
- t->flag &= ~ALLOC;
- }
- t->flag = (t->flag | set) & ~clr;
- /* Don't change base if assignment is to be done,
- * in case assignment fails.
- */
- if ((set & INTEGER) && base > 0 && (!val || t != vp))
- t->type = base;
- if (set & (LJUST|RJUST|ZEROFIL))
- t->u2.field = field;
- if (fake_assign) {
- setstr(t, s);
- if (free_me)
- afree((void *) free_me, t->areap);
- }
- }
- }
-
- if (val != NULL) {
- if (vp->flag&INTEGER) {
- /* do not zero base before assignment */
- setstr(vp, val);
- /* Done after assignment to override default */
- if (base > 0)
- vp->type = base;
- } else
- setstr(vp, val);
- }
-
- /* only x[0] is ever exported, so use vpbase */
- if ((vpbase->flag&EXPORT) && !(vpbase->flag&INTEGER)
- && vpbase->type == 0)
- export(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null);
-
- return vp;
-}
-
-/* Unset a variable. array_ref is set if there was an array reference in
- * the name lookup (eg, x[2]).
- */
-void
-unset(vp, array_ref)
- register struct tbl *vp;
- int array_ref;
-{
- if (vp->flag & ALLOC)
- afree((void*)vp->val.s, vp->areap);
- if ((vp->flag & ARRAY) && !array_ref) {
- struct tbl *a, *tmp;
-
- /* Free up entire array */
- for (a = vp->u.array; a; ) {
- tmp = a;
- a = a->u.array;
- if (tmp->flag & ALLOC)
- afree((void *) tmp->val.s, tmp->areap);
- afree(tmp, tmp->areap);
- }
- vp->u.array = (struct tbl *) 0;
- }
- /* If foo[0] is being unset, the remainder of the array is kept... */
- vp->flag &= SPECIAL | (array_ref ? ARRAY|DEFINED : 0);
- if (vp->flag & SPECIAL)
- unsetspec(vp); /* responsible for `unspecial'ing var */
-}
-
-/* return a pointer to the first char past a legal variable name (returns the
- * argument if there is no legal name, returns * a pointer to the terminating
- * null if whole string is legal).
- */
-char *
-skip_varname(s, aok)
- const char *s;
- int aok;
-{
- int alen;
-
- if (s && letter(*s)) {
- while (*++s && letnum(*s))
- ;
- if (aok && *s == '[' && (alen = array_ref_len(s)))
- s += alen;
- }
- return (char *) s;
-}
-
-/* Return a pointer to the first character past any legal variable name. */
-char *
-skip_wdvarname(s, aok)
- const char *s;
- int aok; /* skip array de-reference? */
-{
- if (s[0] == CHAR && letter(s[1])) {
- do
- s += 2;
- while (s[0] == CHAR && letnum(s[1]));
- if (aok && s[0] == CHAR && s[1] == '[') {
- /* skip possible array de-reference */
- const char *p = s;
- char c;
- int depth = 0;
-
- while (1) {
- if (p[0] != CHAR)
- break;
- c = p[1];
- p += 2;
- if (c == '[')
- depth++;
- else if (c == ']' && --depth == 0) {
- s = p;
- break;
- }
- }
- }
- }
- return (char *) s;
-}
-
-/* Check if coded string s is a variable name */
-int
-is_wdvarname(s, aok)
- const char *s;
- int aok;
-{
- char *p = skip_wdvarname(s, aok);
-
- return p != s && p[0] == EOS;
-}
-
-/* Check if coded string s is a variable assignment */
-int
-is_wdvarassign(s)
- const char *s;
-{
- char *p = skip_wdvarname(s, TRUE);
-
- return p != s && p[0] == CHAR && p[1] == '=';
-}
-
-/*
- * Make the exported environment from the exported names in the dictionary.
- */
-char **
-makenv()
-{
- struct block *l = e->loc;
- XPtrV env;
- register struct tbl *vp, **vpp;
- register int i;
-
- XPinit(env, 64);
- for (l = e->loc; l != NULL; l = l->next)
- for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )
- if ((vp = *vpp++) != NULL
- && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
- register struct block *l2;
- register struct tbl *vp2;
- unsigned h = hash(vp->name);
-
- /* unexport any redefined instances */
- for (l2 = l->next; l2 != NULL; l2 = l2->next) {
- vp2 = tsearch(&l2->vars, vp->name, h);
- if (vp2 != NULL)
- vp2->flag &= ~EXPORT;
- }
- if ((vp->flag&INTEGER)) {
- /* integer to string */
- char *val;
- val = str_val(vp);
- vp->flag &= ~INTEGER;
- setstr(vp, val);
- }
- XPput(env, vp->val.s);
- }
- XPput(env, NULL);
- return (char **) XPclose(env);
-}
-
-/*
- * handle special variables with side effects - PATH, SECONDS.
- */
-
-/* Test if name is a special parameter */
-static int
-special(name)
- register const char * name;
-{
- register struct tbl *tp;
-
- tp = tsearch(&specials, name, hash(name));
- return tp ? tp->type : V_NONE;
-}
-
-#ifdef KSH
-static time_t seconds; /* time SECONDS last set */
-#endif /* KSH */
-
-static void
-getspec(vp)
- register struct tbl *vp;
-{
- switch (special(vp->name)) {
-#ifdef KSH
- case V_SECONDS:
- vp->flag &= ~SPECIAL;
- setint(vp, (long) (time((time_t *)0) - seconds));
- vp->flag |= SPECIAL;
- break;
- case V_RANDOM:
- vp->flag &= ~SPECIAL;
- setint(vp, (long) (rand() & 0x7fff));
- vp->flag |= SPECIAL;
- break;
-#endif /* KSH */
-#ifdef HISTORY
- case V_HISTSIZE:
- vp->flag &= ~SPECIAL;
- setint(vp, (long) histsize);
- vp->flag |= SPECIAL;
- break;
-#endif /* HISTORY */
- }
-}
-
-static void
-setspec(vp)
- register struct tbl *vp;
-{
- char *s;
-
- switch (special(vp->name)) {
- case V_PATH:
- path = str_val(vp);
- flushcom(1); /* clear tracked aliases */
- break;
- case V_IFS:
- setctypes(s = str_val(vp), C_IFS);
- ifs0 = *s;
- break;
- case V_OPTIND:
- getopts_reset((int) intval(vp));
- break;
- case V_POSIXLY_CORRECT:
- change_flag(FPOSIX, OF_SPECIAL, 1);
- break;
- case V_TMPDIR:
- if (tmpdir) {
- afree(tmpdir, APERM);
- tmpdir = (char *) 0;
- }
- /* Use tmpdir iff it is an absolute path, is writable and
- * searchable and is a directory...
- */
- {
- struct stat statb;
- s = str_val(vp);
- if (ISABSPATH(s) && eaccess(s, W_OK|X_OK) == 0
- && stat(s, &statb) == 0 && S_ISDIR(statb.st_mode))
- tmpdir = str_save(s, APERM);
- }
- break;
-#ifdef HISTORY
- case V_HISTSIZE:
- vp->flag &= ~SPECIAL;
- sethistsize((int) intval(vp));
- vp->flag |= SPECIAL;
- break;
- case V_HISTFILE:
- sethistfile(str_val(vp));
- break;
-#endif /* HISTORY */
-#ifdef EDIT
- case V_VISUAL:
- set_editmode(str_val(vp));
- break;
- case V_EDITOR:
- if (!(global("VISUAL")->flag & ISSET))
- set_editmode(str_val(vp));
- break;
- case V_COLUMNS:
- if ((x_cols = intval(vp)) <= MIN_COLS)
- x_cols = MIN_COLS;
- break;
-#endif /* EDIT */
-#ifdef KSH
- case V_MAIL:
- mbset(str_val(vp));
- break;
- case V_MAILPATH:
- mpset(str_val(vp));
- break;
- case V_MAILCHECK:
- /* mail_check_set(intval(vp)); */
- break;
- case V_RANDOM:
- vp->flag &= ~SPECIAL;
- srand((unsigned int)intval(vp));
- vp->flag |= SPECIAL;
- break;
- case V_SECONDS:
- vp->flag &= ~SPECIAL;
- seconds = time((time_t*) 0) - intval(vp);
- vp->flag |= SPECIAL;
- break;
- case V_TMOUT:
- /* at&t ksh seems to do this (only listen if integer) */
- if (vp->flag & INTEGER)
- ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0;
- break;
-#endif /* KSH */
- }
-}
-
-static void
-unsetspec(vp)
- register struct tbl *vp;
-{
- switch (special(vp->name)) {
- case V_PATH:
- path = def_path;
- flushcom(1); /* clear tracked aliases */
- break;
- case V_IFS:
- setctypes(" \t\n", C_IFS);
- ifs0 = ' ';
- break;
- case V_TMPDIR:
- /* should not become unspecial */
- if (tmpdir) {
- afree(tmpdir, APERM);
- tmpdir = (char *) 0;
- }
- break;
-#ifdef KSH
- case V_MAIL:
- mbset((char *) 0);
- break;
- case V_MAILPATH:
- mpset((char *) 0);
- break;
- case V_TMOUT:
- /* at&t ksh doesn't do this. TMOUT becomes unspecial so
- * future assignments don't have effect. Could be
- * useful (eg, after "TMOUT=60; unset TMOUT", user
- * can't get rid of the timeout...). Should be handled
- * by generic unset code...
- */
- ksh_tmout = 0;
- break;
-#endif /* KSH */
- /* todo: generic action for specials (at&t says variables
- * lose their special meaning when unset but global() checks
- * the name of new vars to see if they are special)
- * lose meaning: _, ERRNO, LINENO, MAILCHECK,
- * OPTARG, OPTIND, RANDOM, SECONDS, TMOUT.
- * unknown: MAIL, MAILPATH, HISTSIZE, HISTFILE,
- * no effect: IFS, COLUMNS, PATH, TMPDIR,
- * VISUAL, EDITOR,
- * POSIXLY_CORRECT (use set +o posix instead)
- */
- }
-}
-
-/*
- * Search for (and possibly create) a table entry starting with
- * vp, indexed by val.
- */
-static struct tbl *
-arraysearch(vp, val)
- struct tbl *vp;
- int val;
-{
- struct tbl *prev, *curr, *new;
-
- vp->flag |= ARRAY|DEFINED;
-
- /* The table entry is always [0] */
- if (val == 0) {
- vp->index = 0;
- return vp;
- }
- prev = vp;
- curr = vp->u.array;
- while (curr && curr->index < val) {
- prev = curr;
- curr = curr->u.array;
- }
- if (curr && curr->index == val) {
- if (curr->flag&ISSET)
- return curr;
- else
- new = curr;
- } else
- new = (struct tbl *)alloc(sizeof(struct tbl)+strlen(vp->name)+1, vp->areap);
- strcpy(new->name, vp->name);
- new->flag = vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL);
- new->type = vp->type;
- new->areap = vp->areap;
- new->u2.field = vp->u2.field;
- new->index = val;
- if (curr != new) { /* not reusing old array entry */
- prev->u.array = new;
- new->u.array = curr;
- }
- return new;
-}
-
-/* Return the length of an array reference (eg, [1+2]) - cp is assumed
- * to point to the open bracket. Returns 0 if there is no matching closing
- * bracket.
- */
-int
-array_ref_len(cp)
- const char *cp;
-{
- const char *s = cp;
- int c;
- int depth = 0;
-
- while ((c = *s++) && (c != ']' || --depth))
- if (c == '[')
- depth++;
- if (!c)
- return 0;
- return s - cp;
-}
-
-/*
- * Make a copy of the base of an array name
- */
-char *
-arrayname(str)
- const char *str;
-{
- const char *p;
-
- if ((p = strchr(str, '[')) == 0)
- /* Shouldn't happen, but why worry? */
- return (char *) str;
-
- return str_nsave(str, p - str, ATEMP);
-}
-
-/* Set (or overwrite, if !reset) the array variable var to the values in vals.
- */
-void
-set_array(var, reset, vals)
- const char *var;
- int reset;
- char **vals;
-{
- struct tbl *vp, *vq;
- int i;
-
- /* to get local array, use "typeset foo; set -A foo" */
- vp = global(var);
-
- /* Note: at&t ksh allows set -A but not set +A of a read-only var */
- if ((vp->flag&RDONLY))
- errorf("%s: is read only", var);
- /* This code is quite non-optimal */
- if (reset > 0)
- /* trash existing values and attributes */
- unset(vp, 0);
- /* todo: would be nice for assignment to completely succeed or
- * completely fail. Only really effects integer arrays:
- * evaluation of some of vals[] may fail...
- */
- for (i = 0; vals[i]; i++) {
- vq = arraysearch(vp, i);
- setstr(vq, vals[i]);
- }
-}
diff --git a/bin/pdksh/version.c b/bin/pdksh/version.c
deleted file mode 100644
index 54394213105..00000000000
--- a/bin/pdksh/version.c
+++ /dev/null
@@ -1,10 +0,0 @@
-/* $OpenBSD: version.c,v 1.5 1996/11/21 07:59:37 downsj Exp $ */
-
-/*
- * value of $KSH_VERSION (or $SH_VERSION)
- */
-
-#include "sh.h"
-
-const char ksh_version [] =
- "@(#)PD KSH v5.2.12 96/10/29";
diff --git a/bin/pdksh/vi.c b/bin/pdksh/vi.c
deleted file mode 100644
index 81950b224a3..00000000000
--- a/bin/pdksh/vi.c
+++ /dev/null
@@ -1,2174 +0,0 @@
-/* $OpenBSD: vi.c,v 1.5 1997/06/19 13:58:49 kstailey Exp $ */
-
-/*
- * vi command editing
- * written by John Rochester (initially for nsh)
- * bludgeoned to fit pdksh by Larry Bouzane, Jeff Sparkes & Eric Gisin
- *
- */
-#include "config.h"
-#ifdef VI
-
-#include "sh.h"
-#include <ctype.h>
-#include "ksh_stat.h" /* completion */
-#include "edit.h"
-
-#define CMDLEN 1024
-#define Ctrl(c) (c&0x1f)
-#define is_wordch(c) (letnum(c))
-
-struct edstate {
- int winleft;
- char *cbuf;
- int cbufsize;
- int linelen;
- int cursor;
-};
-
-
-static int vi_hook ARGS((int ch));
-static void vi_reset ARGS((char *buf, size_t len));
-static int nextstate ARGS((int ch));
-static int vi_insert ARGS((int ch));
-static int vi_cmd ARGS((int argcnt, const char *cmd));
-static int domove ARGS((int argcnt, const char *cmd, int sub));
-static int redo_insert ARGS((int count));
-static void yank_range ARGS((int a, int b));
-static int bracktype ARGS((int ch));
-static void save_cbuf ARGS((void));
-static void restore_cbuf ARGS((void));
-static void edit_reset ARGS((char *buf, size_t len));
-static int putbuf ARGS((const char *buf, int len, int repl));
-static void del_range ARGS((int a, int b));
-static int findch ARGS((int ch, int cnt, int forw, int incl));
-static int forwword ARGS((int argcnt));
-static int backword ARGS((int argcnt));
-static int endword ARGS((int argcnt));
-static int Forwword ARGS((int argcnt));
-static int Backword ARGS((int argcnt));
-static int Endword ARGS((int argcnt));
-static int grabhist ARGS((int save, int n));
-static int grabsearch ARGS((int save, int start, int fwd, char *pat));
-static void redraw_line ARGS((int newline));
-static void refresh ARGS((int leftside));
-static int outofwin ARGS((void));
-static void rewindow ARGS((void));
-static int newcol ARGS((int ch, int col));
-static void display ARGS((char *wb1, char *wb2, int leftside));
-static void ed_mov_opt ARGS((int col, char *wb));
-static int expand_word ARGS((int command));
-static int complete_word ARGS((int command, int count));
-static int print_expansions ARGS((struct edstate *e, int command));
-static int char_len ARGS((int c));
-static void x_vi_zotc ARGS((int c));
-static void vi_pprompt ARGS((int full));
-static void vi_error ARGS((void));
-static void vi_macro_reset ARGS((void));
-
-#define C_ 0x1 /* a valid command that isn't a M_, E_, U_ */
-#define M_ 0x2 /* movement command (h, l, etc.) */
-#define E_ 0x4 /* extended command (c, d, y) */
-#define X_ 0x8 /* long command (@, f, F, t, T, etc.) */
-#define U_ 0x10 /* an UN-undoable command (that isn't a M_) */
-#define B_ 0x20 /* bad command (^@) */
-#define Z_ 0x40 /* repeat count defaults to 0 (not 1) */
-#define S_ 0x80 /* search (/, ?) */
-
-#define is_bad(c) (classify[(c)&0x7f]&B_)
-#define is_cmd(c) (classify[(c)&0x7f]&(M_|E_|C_|U_))
-#define is_move(c) (classify[(c)&0x7f]&M_)
-#define is_extend(c) (classify[(c)&0x7f]&E_)
-#define is_long(c) (classify[(c)&0x7f]&X_)
-#define is_undoable(c) (!(classify[(c)&0x7f]&U_))
-#define is_srch(c) (classify[(c)&0x7f]&S_)
-#define is_zerocount(c) (classify[(c)&0x7f]&Z_)
-
-const unsigned char classify[128] = {
- /* 0 1 2 3 4 5 6 7 */
- /* 0 ^@ ^A ^B ^C ^D ^E ^F ^G */
- B_, 0, 0, 0, 0, C_|U_, C_|Z_, 0,
- /* 01 ^H ^I ^J ^K ^L ^M ^N ^O */
- M_, C_|Z_, 0, 0, C_|U_, 0, C_, 0,
- /* 02 ^P ^Q ^R ^S ^T ^U ^V ^W */
- C_, 0, C_|U_, 0, 0, 0, C_, 0,
- /* 03 ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
- C_, 0, 0, C_|Z_, 0, 0, 0, 0,
- /* 04 <space> ! " # $ % & ' */
- M_, 0, 0, C_, M_, M_, 0, 0,
- /* 05 ( ) * + , - . / */
- 0, 0, C_, C_, M_, C_, 0, C_|S_,
- /* 06 0 1 2 3 4 5 6 7 */
- M_, 0, 0, 0, 0, 0, 0, 0,
- /* 07 8 9 : ; < = > ? */
- 0, 0, 0, M_, 0, C_, 0, C_|S_,
- /* 010 @ A B C D E F G */
- C_|X_, C_, M_, C_, C_, M_, M_|X_, C_|U_|Z_,
- /* 011 H I J K L M N O */
- 0, C_, 0, 0, 0, 0, C_|U_, 0,
- /* 012 P Q R S T U V W */
- C_, 0, C_, C_, M_|X_, C_, 0, M_,
- /* 013 X Y Z [ \ ] ^ _ */
- C_, C_|U_, 0, 0, C_|Z_, 0, M_, C_|Z_,
- /* 014 ` a b c d e f g */
- 0, C_, M_, E_, E_, M_, M_|X_, C_|Z_,
- /* 015 h i j k l m n o */
- M_, C_, C_|U_, C_|U_, M_, 0, C_|U_, 0,
- /* 016 p q r s t u v w */
- C_, 0, X_, C_, M_|X_, C_|U_, C_|U_|Z_,M_,
- /* 017 x y z { | } ~ ^? */
- C_, E_|U_, 0, 0, M_|Z_, 0, C_, 0
-};
-
-#define MAXVICMD 3
-#define SRCHLEN 40
-
-#define INSERT 1
-#define REPLACE 2
-
-#define VNORMAL 0 /* command, insert or replace mode */
-#define VARG1 1 /* digit prefix (first, eg, 5l) */
-#define VEXTCMD 2 /* cmd + movement (eg, cl) */
-#define VARG2 3 /* digit prefix (second, eg, 2c3l) */
-#define VXCH 4 /* f, F, t, T, @ */
-#define VFAIL 5 /* bad command */
-#define VCMD 6 /* single char command (eg, X) */
-#define VREDO 7 /* . */
-#define VLIT 8 /* ^V */
-#define VSEARCH 9 /* /, ? */
-#define VVERSION 10 /* <ESC> ^V */
-
-static char undocbuf[CMDLEN];
-
-static struct edstate *save_edstate ARGS((struct edstate *old));
-static void restore_edstate ARGS((struct edstate *old, struct edstate *new));
-static void free_edstate ARGS((struct edstate *old));
-
-static struct edstate ebuf;
-static struct edstate undobuf = { 0, undocbuf, CMDLEN, 0, 0 };
-
-static struct edstate *es; /* current editor state */
-static struct edstate *undo;
-
-static char ibuf[CMDLEN]; /* input buffer */
-static int first_insert; /* set when starting in insert mode */
-static int saved_inslen; /* saved inslen for first insert */
-static int inslen; /* length of input buffer */
-static int srchlen; /* length of current search pattern */
-static char ybuf[CMDLEN]; /* yank buffer */
-static int yanklen; /* length of yank buffer */
-static int fsavecmd = ' '; /* last find command */
-static int fsavech; /* character to find */
-static char lastcmd[MAXVICMD]; /* last non-move command */
-static int lastac; /* argcnt for lastcmd */
-static int lastsearch = ' '; /* last search command */
-static char srchpat[SRCHLEN]; /* last search pattern */
-static int insert; /* non-zero in insert mode */
-static int hnum; /* position in history */
-static int ohnum; /* history line copied (after mod) */
-static int hlast; /* 1 past last position in history */
-static int modified; /* buffer has been "modified" */
-static int state;
-
-/* Information for keeping track of macros that are being expanded.
- * The format of buf is the alias contents followed by a null byte followed
- * by the name (letter) of the alias. The end of the buffer is marked by
- * a double null. The name of the alias is stored so recursive macros can
- * be detected.
- */
-struct macro_state {
- unsigned char *p; /* current position in buf */
- unsigned char *buf; /* pointer to macro(s) being expanded */
- int len; /* how much data in buffer */
-};
-static struct macro_state macro;
-
-enum expand_mode { NONE, EXPAND, COMPLETE, PRINT };
-static enum expand_mode expanded = NONE;/* last input was expanded */
-
-int
-x_vi(buf, len)
- char *buf;
- size_t len;
-{
- int c;
-
- vi_reset(buf, len > CMDLEN ? CMDLEN : len);
- vi_pprompt(1);
- x_flush();
- while (1) {
- if (macro.p) {
- c = *macro.p++;
- /* end of current macro? */
- if (!c) {
- /* more macros left to finish? */
- if (*macro.p++)
- continue;
- /* must be the end of all the macros */
- vi_macro_reset();
- c = x_getc();
- }
- } else
- c = x_getc();
- if (c == -1)
- break;
- if (state != VLIT) {
- if (c == edchars.intr || c == edchars.quit) {
- /* pretend we got an interrupt */
- x_vi_zotc(c);
- x_flush();
- trapsig(c == edchars.intr ? SIGINT : SIGQUIT);
- x_mode(FALSE);
- unwind(LSHELL);
- } else if (c == edchars.eof && state != VVERSION) {
- if (es->linelen == 0) {
- x_vi_zotc(edchars.eof);
- c = -1;
- break;
- }
- continue;
- }
- }
- if (vi_hook(c))
- break;
- x_flush();
- }
-
- x_putc('\r'); x_putc('\n'); x_flush();
-
- if (c == -1)
- return -1;
-
- if (es->cbuf != buf)
- memmove(buf, es->cbuf, es->linelen);
-
- buf[es->linelen++] = '\n';
-
- return es->linelen;
-}
-
-static int
-vi_hook(ch)
- int ch;
-{
- static char curcmd[MAXVICMD];
- static char locpat[SRCHLEN];
- static int cmdlen;
- static int argc1, argc2;
-
- switch (state) {
-
- case VNORMAL:
- if (insert != 0) {
- if (ch == Ctrl('v')) {
- state = VLIT;
- ch = '^';
- }
- switch (vi_insert(ch)) {
- case -1:
-#ifdef OS2
- /* Arrow keys generate 0xe0X, where X is H.. */
- state = VCMD;
- argc1 = 1;
- switch (x_getc()) {
- case 'H':
- *curcmd='k';
- break;
- case 'K':
- *curcmd='h';
- break;
- case 'P':
- *curcmd='j';
- break;
- case 'M':
- *curcmd='l';
- break;
- default:
- vi_error();
- state = VNORMAL;
- }
- break;
-#else /* OS2 */
- vi_error();
- state = VNORMAL;
-#endif /* OS2 */
- break;
- case 0:
- if (state == VLIT) {
- es->cursor--;
- refresh(0);
- } else
- refresh(insert != 0);
- break;
- case 1:
- return 1;
- }
- } else {
- if (ch == '\r' || ch == '\n')
- return 1;
- cmdlen = 0;
- argc1 = 0;
- if (ch >= '1' && ch <= '9') {
- argc1 = ch - '0';
- state = VARG1;
- } else {
- curcmd[cmdlen++] = ch;
- state = nextstate(ch);
- if (state == VSEARCH) {
- save_cbuf();
- es->cursor = 0;
- es->linelen = 0;
- if (ch == '/') {
- if (putbuf("/", 1, 0) != 0) {
- return -1;
- }
- } else if (putbuf("?", 1, 0) != 0)
- return -1;
- refresh(0);
- }
- if (state == VVERSION) {
- save_cbuf();
- es->cursor = 0;
- es->linelen = 0;
- putbuf(ksh_version + 4,
- strlen(ksh_version + 4), 0);
- refresh(0);
- }
- }
- }
- break;
-
- case VLIT:
- if (is_bad(ch)) {
- del_range(es->cursor, es->cursor + 1);
- vi_error();
- } else
- es->cbuf[es->cursor++] = ch;
- refresh(1);
- state = VNORMAL;
- break;
-
- case VVERSION:
- restore_cbuf();
- state = VNORMAL;
- refresh(0);
- break;
-
- case VARG1:
- if (isdigit(ch))
- argc1 = argc1 * 10 + ch - '0';
- else {
- curcmd[cmdlen++] = ch;
- state = nextstate(ch);
- }
- break;
-
- case VEXTCMD:
- argc2 = 0;
- if (ch >= '1' && ch <= '9') {
- argc2 = ch - '0';
- state = VARG2;
- return 0;
- } else {
- curcmd[cmdlen++] = ch;
- if (ch == curcmd[0])
- state = VCMD;
- else if (is_move(ch))
- state = nextstate(ch);
- else
- state = VFAIL;
- }
- break;
-
- case VARG2:
- if (isdigit(ch))
- argc2 = argc2 * 10 + ch - '0';
- else {
- if (argc1 == 0)
- argc1 = argc2;
- else
- argc1 *= argc2;
- curcmd[cmdlen++] = ch;
- if (ch == curcmd[0])
- state = VCMD;
- else if (is_move(ch))
- state = nextstate(ch);
- else
- state = VFAIL;
- }
- break;
-
- case VXCH:
- if (ch == Ctrl('['))
- state = VNORMAL;
- else {
- curcmd[cmdlen++] = ch;
- state = VCMD;
- }
- break;
-
- case VSEARCH:
- if (ch == '\r' || ch == '\n' /*|| ch == Ctrl('[')*/ ) {
- restore_cbuf();
- /* Repeat last search? */
- if (srchlen == 0) {
- if (!srchpat[0]) {
- vi_error();
- state = VNORMAL;
- refresh(0);
- return 0;
- }
- } else {
- locpat[srchlen] = '\0';
- (void) strcpy(srchpat, locpat);
- }
- state = VCMD;
- } else if (ch == edchars.erase || ch == Ctrl('h')) {
- if (srchlen != 0) {
- srchlen--;
- es->linelen -= char_len((unsigned char) locpat[srchlen]);
- es->cursor = es->linelen;
- refresh(0);
- return 0;
- }
- restore_cbuf();
- state = VNORMAL;
- refresh(0);
- } else if (ch == edchars.kill) {
- srchlen = 0;
- es->linelen = 1;
- es->cursor = 1;
- refresh(0);
- return 0;
- } else if (ch == edchars.werase) {
- int i;
- int n = srchlen;
-
- while (n > 0 && isspace(locpat[n - 1]))
- n--;
- while (n > 0 && !isspace(locpat[n - 1]))
- n--;
- for (i = srchlen; --i >= n; )
- es->linelen -= char_len((unsigned char) locpat[i]);
- srchlen = n;
- es->cursor = es->linelen;
- refresh(0);
- return 0;
- } else {
- if (srchlen == SRCHLEN - 1)
- vi_error();
- else {
- locpat[srchlen++] = ch;
- if ((ch & 0x80) && Flag(FVISHOW8)) {
- es->cbuf[es->linelen++] = 'M';
- es->cbuf[es->linelen++] = '-';
- ch &= 0x7f;
- }
- if (ch < ' ' || ch == 0x7f) {
- es->cbuf[es->linelen++] = '^';
- es->cbuf[es->linelen++] = ch ^ '@';
- } else
- es->cbuf[es->linelen++] = ch;
- es->cursor = es->linelen;
- refresh(0);
- }
- return 0;
- }
- break;
- }
-
- switch (state) {
- case VCMD:
- state = VNORMAL;
- switch (vi_cmd(argc1, curcmd)) {
- case -1:
- vi_error();
- refresh(0);
- break;
- case 0:
- if (insert != 0)
- inslen = 0;
- refresh(insert != 0);
- break;
- case 1:
- refresh(0);
- return 1;
- case 2:
- /* back from a 'v' command - don't redraw the screen */
- return 1;
- }
- break;
-
- case VREDO:
- state = VNORMAL;
- if (argc1 != 0)
- lastac = argc1;
- switch (vi_cmd(lastac, lastcmd) != 0) {
- case -1:
- vi_error();
- refresh(0);
- break;
- case 0:
- if (insert != 0) {
- if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||
- lastcmd[0] == 'C') {
- if (redo_insert(1) != 0)
- vi_error();
- } else {
- if (redo_insert(lastac) != 0)
- vi_error();
- }
- }
- refresh(0);
- break;
- case 1:
- refresh(0);
- return 1;
- case 2:
- /* back from a 'v' command - don't redraw the screen */
- return 1;
- }
- break;
-
- case VFAIL:
- state = VNORMAL;
- vi_error();
- break;
- }
- return 0;
-}
-
-static void
-vi_reset(buf, len)
- char *buf;
- size_t len;
-{
- state = VNORMAL;
- ohnum = hnum = hlast = histnum(-1) + 1;
- insert = INSERT;
- saved_inslen = inslen;
- first_insert = 1;
- inslen = 0;
- modified = 1;
- vi_macro_reset();
- edit_reset(buf, len);
-}
-
-static int
-nextstate(ch)
- int ch;
-{
- if (is_extend(ch))
- return VEXTCMD;
- else if (is_srch(ch))
- return VSEARCH;
- else if (is_long(ch))
- return VXCH;
- else if (ch == '.')
- return VREDO;
- else if (ch == Ctrl('v'))
- return VVERSION;
- else if (is_cmd(ch))
- return VCMD;
- else
- return VFAIL;
-}
-
-static int
-vi_insert(ch)
- int ch;
-{
- int tcursor;
-
- if (ch == edchars.erase || ch == Ctrl('h')) {
- if (insert == REPLACE) {
- if (es->cursor == undo->cursor) {
- vi_error();
- return 0;
- }
- if (inslen > 0)
- inslen--;
- es->cursor--;
- if (es->cursor >= undo->linelen)
- es->linelen--;
- else
- es->cbuf[es->cursor] = undo->cbuf[es->cursor];
- } else {
- if (es->cursor == 0) {
- /* x_putc(BEL); no annoying bell here */
- return 0;
- }
- if (inslen > 0)
- inslen--;
- es->cursor--;
- es->linelen--;
- memmove(&es->cbuf[es->cursor], &es->cbuf[es->cursor+1],
- es->linelen - es->cursor + 1);
- }
- expanded = NONE;
- return 0;
- }
- if (ch == edchars.kill) {
- if (es->cursor != 0) {
- inslen = 0;
- memmove(es->cbuf, &es->cbuf[es->cursor],
- es->linelen - es->cursor);
- es->linelen -= es->cursor;
- es->cursor = 0;
- }
- expanded = NONE;
- return 0;
- }
- if (ch == edchars.werase) {
- if (es->cursor != 0) {
- tcursor = Backword(1);
- memmove(&es->cbuf[tcursor], &es->cbuf[es->cursor],
- es->linelen - es->cursor);
- es->linelen -= es->cursor - tcursor;
- if (inslen < es->cursor - tcursor)
- inslen = 0;
- else
- inslen -= es->cursor - tcursor;
- es->cursor = tcursor;
- }
- expanded = NONE;
- return 0;
- }
- /* If any chars are entered before escape, trash the saved insert
- * buffer (if user inserts & deletes char, ibuf gets trashed and
- * we don't want to use it)
- */
- if (first_insert && ch != Ctrl('['))
- saved_inslen = 0;
- switch (ch) {
-
-#ifdef OS2
- case 224: /* function key prefix */
-#endif /* OS2 */
- case '\0':
- return -1;
-
- case '\r':
- case '\n':
- return 1;
-
- case Ctrl('['):
- expanded = NONE;
- if (first_insert) {
- first_insert = 0;
- if (inslen == 0) {
- inslen = saved_inslen;
- return redo_insert(0);
- }
- lastcmd[0] = 'a';
- lastac = 1;
- }
- if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||
- lastcmd[0] == 'C')
- return redo_insert(0);
- else
- return redo_insert(lastac - 1);
-
- /* { Begin nonstandard vi commands */
- case Ctrl('x'):
- expand_word(0);
- break;
-
- case Ctrl('f'):
- complete_word(0, 0);
- break;
-
- case Ctrl('e'):
- print_expansions(es, 0);
- break;
-
- case Ctrl('i'):
- if (Flag(FVITABCOMPLETE)) {
- complete_word(0, 0);
- break;
- }
- /* FALLTHROUGH */
- /* End nonstandard vi commands } */
-
- default:
- if (es->linelen == es->cbufsize - 1)
- return -1;
- ibuf[inslen++] = ch;
- if (insert == INSERT) {
- memmove(&es->cbuf[es->cursor+1], &es->cbuf[es->cursor],
- es->linelen - es->cursor);
- es->linelen++;
- }
- es->cbuf[es->cursor++] = ch;
- if (insert == REPLACE && es->cursor > es->linelen)
- es->linelen++;
- expanded = NONE;
- }
- return 0;
-}
-
-static int
-vi_cmd(argcnt, cmd)
- int argcnt;
- const char *cmd;
-{
- int ncursor;
- int cur, c1, c2, c3 = 0;
- int any;
- struct edstate *t;
-
- if (argcnt == 0 && !is_zerocount(*cmd))
- argcnt = 1;
-
- if (is_move(*cmd)) {
- if ((cur = domove(argcnt, cmd, 0)) >= 0) {
- if (cur == es->linelen && cur != 0)
- cur--;
- es->cursor = cur;
- } else
- return -1;
- } else {
- /* Don't save state in middle of macro.. */
- if (is_undoable(*cmd) && !macro.p) {
- undo->winleft = es->winleft;
- memmove(undo->cbuf, es->cbuf, es->linelen);
- undo->linelen = es->linelen;
- undo->cursor = es->cursor;
- lastac = argcnt;
- memmove(lastcmd, cmd, MAXVICMD);
- }
- switch (*cmd) {
-
- case Ctrl('l'):
- case Ctrl('r'):
- redraw_line(1);
- break;
-
- case '@':
- {
- static char alias[] = "_\0";
- struct tbl *ap;
- int olen, nlen;
- char *p, *nbuf;
-
- /* lookup letter in alias list... */
- alias[1] = cmd[1];
- ap = tsearch(&aliases, alias, hash(alias));
- if (!cmd[1] || !ap || !(ap->flag & ISSET))
- return -1;
- /* check if this is a recursive call... */
- if ((p = (char *) macro.p))
- while ((p = strchr(p, '\0')) && p[1])
- if (*++p == cmd[1])
- return -1;
- /* insert alias into macro buffer */
- nlen = strlen(ap->val.s) + 1;
- olen = !macro.p ? 2
- : macro.len - (macro.p - macro.buf);
- nbuf = alloc(nlen + 1 + olen, APERM);
- memcpy(nbuf, ap->val.s, nlen);
- nbuf[nlen++] = cmd[1];
- if (macro.p) {
- memcpy(nbuf + nlen, macro.p, olen);
- afree(macro.buf, APERM);
- nlen += olen;
- } else {
- nbuf[nlen++] = '\0';
- nbuf[nlen++] = '\0';
- }
- macro.p = macro.buf = (unsigned char *) nbuf;
- macro.len = nlen;
- }
- break;
-
- case 'a':
- modified = 1; hnum = hlast;
- if (es->linelen != 0)
- es->cursor++;
- insert = INSERT;
- break;
-
- case 'A':
- modified = 1; hnum = hlast;
- del_range(0, 0);
- es->cursor = es->linelen;
- insert = INSERT;
- break;
-
- case 'S':
- es->cursor = domove(1, "^", 1);
- del_range(es->cursor, es->linelen);
- modified = 1; hnum = hlast;
- insert = INSERT;
- break;
-
- case 'Y':
- cmd = "y$";
- /* ahhhhhh... */
- case 'c':
- case 'd':
- case 'y':
- if (*cmd == cmd[1]) {
- c1 = *cmd == 'c' ? domove(1, "^", 1) : 0;
- c2 = es->linelen;
- } else if (!is_move(cmd[1]))
- return -1;
- else {
- if ((ncursor = domove(argcnt, &cmd[1], 1)) < 0)
- return -1;
- if (*cmd == 'c' &&
- (cmd[1]=='w' || cmd[1]=='W') &&
- !isspace(es->cbuf[es->cursor])) {
- while (isspace(es->cbuf[--ncursor]))
- ;
- ncursor++;
- }
- if (ncursor > es->cursor) {
- c1 = es->cursor;
- c2 = ncursor;
- } else {
- c1 = ncursor;
- c2 = es->cursor;
- if (cmd[1] == '%')
- c2++;
- }
- }
- if (*cmd != 'c' && c1 != c2)
- yank_range(c1, c2);
- if (*cmd != 'y') {
- del_range(c1, c2);
- es->cursor = c1;
- }
- if (*cmd == 'c') {
- modified = 1; hnum = hlast;
- insert = INSERT;
- }
- break;
-
- case 'p':
- modified = 1; hnum = hlast;
- if (es->linelen != 0)
- es->cursor++;
- while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
- ;
- if (es->cursor != 0)
- es->cursor--;
- if (argcnt != 0)
- return -1;
- break;
-
- case 'P':
- modified = 1; hnum = hlast;
- any = 0;
- while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
- any = 1;
- if (any && es->cursor != 0)
- es->cursor--;
- if (argcnt != 0)
- return -1;
- break;
-
- case 'C':
- modified = 1; hnum = hlast;
- del_range(es->cursor, es->linelen);
- insert = INSERT;
- break;
-
- case 'D':
- yank_range(es->cursor, es->linelen);
- del_range(es->cursor, es->linelen);
- if (es->cursor != 0)
- es->cursor--;
- break;
-
- case 'g':
- if (!argcnt)
- argcnt = hlast + 1;
- /* fall through */
- case 'G':
- if (!argcnt)
- argcnt = 1;
- else
- argcnt = hlast - (source->line - argcnt);
- if (grabhist(modified, argcnt - 1) < 0)
- return -1;
- else {
- modified = 0;
- hnum = argcnt - 1;
- }
- break;
-
- case 'i':
- modified = 1; hnum = hlast;
- insert = INSERT;
- break;
-
- case 'I':
- modified = 1; hnum = hlast;
- es->cursor = domove(1, "^", 1);
- insert = INSERT;
- break;
-
- case 'j':
- case '+':
- case Ctrl('n'):
- if (grabhist(modified, hnum + argcnt) < 0)
- return -1;
- else {
- modified = 0;
- hnum += argcnt;
- }
- break;
-
- case 'k':
- case '-':
- case Ctrl('p'):
- if (grabhist(modified, hnum - argcnt) < 0)
- return -1;
- else {
- modified = 0;
- hnum -= argcnt;
- }
- break;
-
- case 'r':
- if (es->linelen == 0)
- return -1;
- modified = 1; hnum = hlast;
- if (cmd[1] == 0)
- vi_error();
- else
- es->cbuf[es->cursor] = cmd[1];
- break;
-
- case 'R':
- modified = 1; hnum = hlast;
- insert = REPLACE;
- break;
-
- case 's':
- if (es->linelen == 0)
- return -1;
- modified = 1; hnum = hlast;
- if (es->cursor + argcnt > es->linelen)
- argcnt = es->linelen - es->cursor;
- del_range(es->cursor, es->cursor + argcnt);
- insert = INSERT;
- break;
-
- case 'v':
- if (es->linelen == 0)
- return -1;
- if (!argcnt) {
- if (modified) {
- es->cbuf[es->linelen] = '\0';
- source->line++;
- histsave(source->line, es->cbuf, 1);
- } else
- argcnt = source->line + 1
- - (hlast - hnum);
- }
- shf_snprintf(es->cbuf, es->cbufsize,
- argcnt ? "%s %d" : "%s",
- "fc -e ${VISUAL:-${EDITOR:-vi}} --",
- argcnt);
- es->linelen = strlen(es->cbuf);
- return 2;
-
- case 'x':
- if (es->linelen == 0)
- return -1;
- modified = 1; hnum = hlast;
- if (es->cursor + argcnt > es->linelen)
- argcnt = es->linelen - es->cursor;
- yank_range(es->cursor, es->cursor + argcnt);
- del_range(es->cursor, es->cursor + argcnt);
- break;
-
- case 'X':
- if (es->cursor > 0) {
- modified = 1; hnum = hlast;
- if (es->cursor < argcnt)
- argcnt = es->cursor;
- yank_range(es->cursor - argcnt, es->cursor);
- del_range(es->cursor - argcnt, es->cursor);
- es->cursor -= argcnt;
- } else
- return -1;
- break;
-
- case 'u':
- t = es;
- es = undo;
- undo = t;
- break;
-
- case 'U':
- if (!modified)
- return -1;
- if (grabhist(modified, ohnum) < 0)
- return -1;
- modified = 0;
- hnum = ohnum;
- break;
-
- case '?':
- if (hnum == hlast)
- hnum = -1;
- /* ahhh */
- case '/':
- c3 = 1;
- srchlen = 0;
- lastsearch = *cmd;
- /* fall through */
- case 'n':
- case 'N':
- if (lastsearch == ' ')
- return -1;
- if (lastsearch == '?')
- c1 = 1;
- else
- c1 = 0;
- if (*cmd == 'N')
- c1 = !c1;
- if ((c2 = grabsearch(modified, hnum,
- c1, srchpat)) < 0) {
- if (c3) {
- restore_cbuf();
- refresh(0);
- }
- return -1;
- } else {
- modified = 0;
- hnum = c2;
- ohnum = hnum;
- }
- break;
- case '_': {
- int inspace;
- char *p, *sp;
-
- if (histnum(-1) < 0)
- return -1;
- p = *histpos();
-#define issp(c) (isspace((c)) || (c) == '\n')
- if (argcnt) {
- while (*p && issp(*p))
- p++;
- while (*p && --argcnt) {
- while (*p && !issp(*p))
- p++;
- while (*p && issp(*p))
- p++;
- }
- if (!*p)
- return -1;
- sp = p;
- } else {
- sp = p;
- inspace = 0;
- while (*p) {
- if (issp(*p))
- inspace = 1;
- else if (inspace) {
- inspace = 0;
- sp = p;
- }
- p++;
- }
- p = sp;
- }
- modified = 1; hnum = hlast;
- if (es->cursor != es->linelen)
- es->cursor++;
- while (*p && !issp(*p)) {
- argcnt++;
- p++;
- }
- if (putbuf(space, 1, 0) != 0)
- argcnt = -1;
- else if (putbuf(sp, argcnt, 0) != 0)
- argcnt = -1;
- if (argcnt < 0) {
- if (es->cursor != 0)
- es->cursor--;
- return -1;
- }
- insert = INSERT;
- }
- break;
-
- case '~': {
- char *p;
- int i;
-
- if (es->linelen == 0)
- return -1;
- for (i = 0; i < argcnt; i++) {
- p = &es->cbuf[es->cursor];
- if (islower(*p)) {
- modified = 1; hnum = hlast;
- *p = toupper(*p);
- } else if (isupper(*p)) {
- modified = 1; hnum = hlast;
- *p = tolower(*p);
- }
- if (es->cursor < es->linelen - 1)
- es->cursor++;
- }
- break;
- }
-
- case '#':
- {
- int ret = x_do_comment(es->cbuf, es->cbufsize,
- &es->linelen);
- if (ret >= 0)
- es->cursor = 0;
- return ret;
- }
-
- case '=': /* at&t ksh */
- case Ctrl('e'): /* Nonstandard vi/ksh */
- print_expansions(es, 1);
- break;
-
-
- case Ctrl('i'): /* Nonstandard vi/ksh */
- if (!Flag(FVITABCOMPLETE))
- return -1;
- complete_word(1, argcnt);
- break;
-
- case Ctrl('['): /* some annoying at&t ksh's */
- if (!Flag(FVIESCCOMPLETE))
- return -1;
- case '\\': /* at&t ksh */
- case Ctrl('f'): /* Nonstandard vi/ksh */
- complete_word(1, argcnt);
- break;
-
-
- case '*': /* at&t ksh */
- case Ctrl('x'): /* Nonstandard vi/ksh */
- expand_word(1);
- break;
- }
- if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen)
- es->cursor--;
- }
- return 0;
-}
-
-static int
-domove(argcnt, cmd, sub)
- int argcnt;
- const char *cmd;
- int sub;
-{
- int bcount, UNINITIALIZED(i), t;
- int UNINITIALIZED(ncursor);
-
- switch (*cmd) {
-
- case 'b':
- if (!sub && es->cursor == 0)
- return -1;
- ncursor = backword(argcnt);
- break;
-
- case 'B':
- if (!sub && es->cursor == 0)
- return -1;
- ncursor = Backword(argcnt);
- break;
-
- case 'e':
- if (!sub && es->cursor + 1 >= es->linelen)
- return -1;
- ncursor = endword(argcnt);
- if (sub && ncursor < es->linelen)
- ncursor++;
- break;
-
- case 'E':
- if (!sub && es->cursor + 1 >= es->linelen)
- return -1;
- ncursor = Endword(argcnt);
- if (sub && ncursor < es->linelen)
- ncursor++;
- break;
-
- case 'f':
- case 'F':
- case 't':
- case 'T':
- fsavecmd = *cmd;
- fsavech = cmd[1];
- /* drop through */
-
- case ',':
- case ';':
- if (fsavecmd == ' ')
- return -1;
- i = fsavecmd == 'f' || fsavecmd == 'F';
- t = fsavecmd > 'a';
- if (*cmd == ',')
- t = !t;
- if ((ncursor = findch(fsavech, argcnt, t, i)) < 0)
- return -1;
- if (sub && t)
- ncursor++;
- break;
-
- case 'h':
- case Ctrl('h'):
- if (!sub && es->cursor == 0)
- return -1;
- ncursor = es->cursor - argcnt;
- if (ncursor < 0)
- ncursor = 0;
- break;
-
- case ' ':
- case 'l':
- if (!sub && es->cursor + 1 >= es->linelen)
- return -1;
- if (es->linelen != 0) {
- ncursor = es->cursor + argcnt;
- if (ncursor > es->linelen)
- ncursor = es->linelen;
- }
- break;
-
- case 'w':
- if (!sub && es->cursor + 1 >= es->linelen)
- return -1;
- ncursor = forwword(argcnt);
- break;
-
- case 'W':
- if (!sub && es->cursor + 1 >= es->linelen)
- return -1;
- ncursor = Forwword(argcnt);
- break;
-
- case '0':
- ncursor = 0;
- break;
-
- case '^':
- ncursor = 0;
- while (ncursor < es->linelen - 1 && isspace(es->cbuf[ncursor]))
- ncursor++;
- break;
-
- case '|':
- ncursor = argcnt;
- if (ncursor > es->linelen)
- ncursor = es->linelen;
- if (ncursor)
- ncursor--;
- break;
-
- case '$':
- if (es->linelen != 0)
- ncursor = es->linelen;
- else
- ncursor = 0;
- break;
-
- case '%':
- ncursor = es->cursor;
- while (ncursor < es->linelen &&
- (i = bracktype(es->cbuf[ncursor])) == 0)
- ncursor++;
- if (ncursor == es->linelen)
- return -1;
- bcount = 1;
- do {
- if (i > 0) {
- if (++ncursor >= es->linelen)
- return -1;
- } else {
- if (--ncursor < 0)
- return -1;
- }
- t = bracktype(es->cbuf[ncursor]);
- if (t == i)
- bcount++;
- else if (t == -i)
- bcount--;
- } while (bcount != 0);
- if (sub && i > 0)
- ncursor++;
- break;
-
- default:
- return -1;
- }
- return ncursor;
-}
-
-static int
-redo_insert(count)
- int count;
-{
- while (count-- > 0)
- if (putbuf(ibuf, inslen, insert==REPLACE) != 0)
- return -1;
- if (es->cursor > 0)
- es->cursor--;
- insert = 0;
- return 0;
-}
-
-static void
-yank_range(a, b)
- int a, b;
-{
- yanklen = b - a;
- if (yanklen != 0)
- memmove(ybuf, &es->cbuf[a], yanklen);
-}
-
-static int
-bracktype(ch)
- int ch;
-{
- switch (ch) {
-
- case '(':
- return 1;
-
- case '[':
- return 2;
-
- case '{':
- return 3;
-
- case ')':
- return -1;
-
- case ']':
- return -2;
-
- case '}':
- return -3;
-
- default:
- return 0;
- }
-}
-
-/*
- * Non user interface editor routines below here
- */
-
-static int cur_col; /* current column on line */
-static int pwidth; /* width of prompt */
-static int prompt_trunc; /* how much of prompt to truncate */
-static int prompt_skip; /* how much of prompt to skip */
-static int winwidth; /* width of window */
-static char *wbuf[2]; /* window buffers */
-static int wbuf_len; /* length of window buffers (x_cols-3)*/
-static int win; /* window buffer in use */
-static char morec; /* more character at right of window */
-static int lastref; /* argument to last refresh() */
-static char holdbuf[CMDLEN]; /* place to hold last edit buffer */
-static int holdlen; /* length of holdbuf */
-
-static void
-save_cbuf()
-{
- memmove(holdbuf, es->cbuf, es->linelen);
- holdlen = es->linelen;
- holdbuf[holdlen] = '\0';
-}
-
-static void
-restore_cbuf()
-{
- es->cursor = 0;
- es->linelen = holdlen;
- memmove(es->cbuf, holdbuf, holdlen);
-}
-
-/* return a new edstate */
-static struct edstate *
-save_edstate(old)
- struct edstate *old;
-{
- struct edstate *new;
-
- new = (struct edstate *)alloc(sizeof(struct edstate), APERM);
- new->cbuf = alloc(old->cbufsize, APERM);
- new->cbufsize = old->cbufsize;
- strcpy(new->cbuf, old->cbuf);
- new->linelen = old->linelen;
- new->cursor = old->cursor;
- new->winleft = old->winleft;
- return new;
-}
-
-static void
-restore_edstate(new, old)
- struct edstate *old, *new;
-{
- strncpy(new->cbuf, old->cbuf, old->linelen);
- new->linelen = old->linelen;
- new->cursor = old->cursor;
- new->winleft = old->winleft;
- free_edstate(old);
-}
-
-static void
-free_edstate(old)
- struct edstate *old;
-{
- afree(old->cbuf, APERM);
- afree((char *)old, APERM);
-}
-
-
-
-static void
-edit_reset(buf, len)
- char *buf;
- size_t len;
-{
- const char *p;
-
- es = &ebuf;
- es->cbuf = buf;
- es->cbufsize = len;
- undo = &undobuf;
- undo->cbufsize = len;
-
- es->linelen = undo->linelen = 0;
- es->cursor = undo->cursor = 0;
- es->winleft = undo->winleft = 0;
-
- cur_col = pwidth = promptlen(prompt, &p);
- prompt_skip = p - prompt;
- if (pwidth > x_cols - 3 - MIN_EDIT_SPACE) {
- cur_col = x_cols - 3 - MIN_EDIT_SPACE;
- prompt_trunc = pwidth - cur_col;
- pwidth -= prompt_trunc;
- } else
- prompt_trunc = 0;
- if (!wbuf_len || wbuf_len != x_cols - 3) {
- wbuf_len = x_cols - 3;
- wbuf[0] = aresize(wbuf[0], wbuf_len, APERM);
- wbuf[1] = aresize(wbuf[1], wbuf_len, APERM);
- }
- (void) memset(wbuf[0], ' ', wbuf_len);
- (void) memset(wbuf[1], ' ', wbuf_len);
- winwidth = x_cols - pwidth - 3;
- win = 0;
- morec = ' ';
- lastref = 1;
- holdlen = 0;
-}
-
-static int
-putbuf(buf, len, repl)
- const char *buf;
- int len;
- int repl;
-{
- if (len == 0)
- return 0;
- if (repl) {
- if (es->cursor + len >= es->cbufsize)
- return -1;
- if (es->cursor + len > es->linelen)
- es->linelen = es->cursor + len;
- } else {
- if (es->linelen + len >= es->cbufsize)
- return -1;
- memmove(&es->cbuf[es->cursor + len], &es->cbuf[es->cursor],
- es->linelen - es->cursor);
- es->linelen += len;
- }
- memmove(&es->cbuf[es->cursor], buf, len);
- es->cursor += len;
- return 0;
-}
-
-static void
-del_range(a, b)
- int a, b;
-{
- if (es->linelen != b)
- memmove(&es->cbuf[a], &es->cbuf[b], es->linelen - b);
- es->linelen -= b - a;
-}
-
-static int
-findch(ch, cnt, forw, incl)
- int ch;
- int cnt;
- int forw;
- int incl;
-{
- int ncursor;
-
- if (es->linelen == 0)
- return -1;
- ncursor = es->cursor;
- while (cnt--) {
- do {
- if (forw) {
- if (++ncursor == es->linelen)
- return -1;
- } else {
- if (--ncursor < 0)
- return -1;
- }
- } while (es->cbuf[ncursor] != ch);
- }
- if (!incl) {
- if (forw)
- ncursor--;
- else
- ncursor++;
- }
- return ncursor;
-}
-
-static int
-forwword(argcnt)
- int argcnt;
-{
- int ncursor;
-
- ncursor = es->cursor;
- while (ncursor < es->linelen && argcnt--) {
- if (is_wordch(es->cbuf[ncursor]))
- while (is_wordch(es->cbuf[ncursor]) &&
- ncursor < es->linelen)
- ncursor++;
- else if (!isspace(es->cbuf[ncursor]))
- while (!is_wordch(es->cbuf[ncursor]) &&
- !isspace(es->cbuf[ncursor]) &&
- ncursor < es->linelen)
- ncursor++;
- while (isspace(es->cbuf[ncursor]) && ncursor < es->linelen)
- ncursor++;
- }
- return ncursor;
-}
-
-static int
-backword(argcnt)
- int argcnt;
-{
- int ncursor;
-
- ncursor = es->cursor;
- while (ncursor > 0 && argcnt--) {
- while (--ncursor > 0 && isspace(es->cbuf[ncursor]))
- ;
- if (ncursor > 0) {
- if (is_wordch(es->cbuf[ncursor]))
- while (--ncursor >= 0 &&
- is_wordch(es->cbuf[ncursor]))
- ;
- else
- while (--ncursor >= 0 &&
- !is_wordch(es->cbuf[ncursor]) &&
- !isspace(es->cbuf[ncursor]))
- ;
- ncursor++;
- }
- }
- return ncursor;
-}
-
-static int
-endword(argcnt)
- int argcnt;
-{
- int ncursor;
-
- ncursor = es->cursor;
- while (ncursor < es->linelen && argcnt--) {
- while (++ncursor < es->linelen - 1 &&
- isspace(es->cbuf[ncursor]))
- ;
- if (ncursor < es->linelen - 1) {
- if (is_wordch(es->cbuf[ncursor]))
- while (++ncursor < es->linelen &&
- is_wordch(es->cbuf[ncursor]))
- ;
- else
- while (++ncursor < es->linelen &&
- !is_wordch(es->cbuf[ncursor]) &&
- !isspace(es->cbuf[ncursor]))
- ;
- ncursor--;
- }
- }
- return ncursor;
-}
-
-static int
-Forwword(argcnt)
- int argcnt;
-{
- int ncursor;
-
- ncursor = es->cursor;
- while (ncursor < es->linelen && argcnt--) {
- while (!isspace(es->cbuf[ncursor]) && ncursor < es->linelen)
- ncursor++;
- while (isspace(es->cbuf[ncursor]) && ncursor < es->linelen)
- ncursor++;
- }
- return ncursor;
-}
-
-static int
-Backword(argcnt)
- int argcnt;
-{
- int ncursor;
-
- ncursor = es->cursor;
- while (ncursor > 0 && argcnt--) {
- while (--ncursor >= 0 && isspace(es->cbuf[ncursor]))
- ;
- while (ncursor >= 0 && !isspace(es->cbuf[ncursor]))
- ncursor--;
- ncursor++;
- }
- return ncursor;
-}
-
-static int
-Endword(argcnt)
- int argcnt;
-{
- int ncursor;
-
- ncursor = es->cursor;
- while (ncursor < es->linelen - 1 && argcnt--) {
- while (++ncursor < es->linelen - 1 &&
- isspace(es->cbuf[ncursor]))
- ;
- if (ncursor < es->linelen - 1) {
- while (++ncursor < es->linelen &&
- !isspace(es->cbuf[ncursor]))
- ;
- ncursor--;
- }
- }
- return ncursor;
-}
-
-static int
-grabhist(save, n)
- int save;
- int n;
-{
- char *hptr;
-
- if (n < 0 || n > hlast)
- return -1;
- if (n == hlast) {
- restore_cbuf();
- ohnum = n;
- return 0;
- }
- (void) histnum(n);
- if ((hptr = *histpos()) == NULL) {
- internal_errorf(0, "grabhist: bad history array");
- return -1;
- }
- if (save)
- save_cbuf();
- if ((es->linelen = strlen(hptr)) >= es->cbufsize)
- es->linelen = es->cbufsize - 1;
- memmove(es->cbuf, hptr, es->linelen);
- es->cursor = 0;
- ohnum = n;
- return 0;
-}
-
-static int
-grabsearch(save, start, fwd, pat)
- int save, start, fwd;
- char *pat;
-{
- char *hptr;
- int hist;
- int anchored;
-
- if ((start == 0 && fwd == 0) || (start >= hlast-1 && fwd == 1))
- return -1;
- if (fwd)
- start++;
- else
- start--;
- anchored = *pat == '^' ? (++pat, 1) : 0;
- if ((hist = findhist(start, fwd, pat, anchored)) < 0) {
- /* if (start != 0 && fwd && match(holdbuf, pat) >= 0) { */
- /* XXX should FILECMP be strncmp? */
- if (start != 0 && fwd && FILECMP(holdbuf, pat) >= 0) {
- restore_cbuf();
- return 0;
- } else
- return -1;
- }
- if (save)
- save_cbuf();
- histnum(hist);
- hptr = *histpos();
- if ((es->linelen = strlen(hptr)) >= es->cbufsize)
- es->linelen = es->cbufsize - 1;
- memmove(es->cbuf, hptr, es->linelen);
- es->cursor = 0;
- return hist;
-}
-
-static void
-redraw_line(newline)
- int newline;
-{
- (void) memset(wbuf[win], ' ', wbuf_len);
- if (newline) {
- x_putc('\r');
- x_putc('\n');
- }
- vi_pprompt(0);
- cur_col = pwidth;
- morec = ' ';
-}
-
-static void
-refresh(leftside)
- int leftside;
-{
- if (leftside < 0)
- leftside = lastref;
- else
- lastref = leftside;
- if (outofwin())
- rewindow();
- display(wbuf[1 - win], wbuf[win], leftside);
- win = 1 - win;
-}
-
-static int
-outofwin()
-{
- int cur, col;
-
- if (es->cursor < es->winleft)
- return 1;
- col = 0;
- cur = es->winleft;
- while (cur < es->cursor)
- col = newcol((unsigned char) es->cbuf[cur++], col);
- if (col >= winwidth)
- return 1;
- return 0;
-}
-
-static void
-rewindow()
-{
- register int tcur, tcol;
- int holdcur1, holdcol1;
- int holdcur2, holdcol2;
-
- holdcur1 = holdcur2 = tcur = 0;
- holdcol1 = holdcol2 = tcol = 0;
- while (tcur < es->cursor) {
- if (tcol - holdcol2 > winwidth / 2) {
- holdcur1 = holdcur2;
- holdcol1 = holdcol2;
- holdcur2 = tcur;
- holdcol2 = tcol;
- }
- tcol = newcol((unsigned char) es->cbuf[tcur++], tcol);
- }
- while (tcol - holdcol1 > winwidth / 2)
- holdcol1 = newcol((unsigned char) es->cbuf[holdcur1++],
- holdcol1);
- es->winleft = holdcur1;
-}
-
-static int
-newcol(ch, col)
- int ch, col;
-{
- if (ch == '\t')
- return (col | 7) + 1;
- return col + char_len(ch);
-}
-
-static void
-display(wb1, wb2, leftside)
- char *wb1, *wb2;
- int leftside;
-{
- unsigned char ch;
- char *twb1, *twb2, mc;
- int cur, col, cnt;
- int UNINITIALIZED(ncol);
- int moreright;
-
- col = 0;
- cur = es->winleft;
- moreright = 0;
- twb1 = wb1;
- while (col < winwidth && cur < es->linelen) {
- if (cur == es->cursor && leftside)
- ncol = col + pwidth;
- if ((ch = es->cbuf[cur]) == '\t') {
- do {
- *twb1++ = ' ';
- } while (++col < winwidth && (col & 7) != 0);
- } else {
- if ((ch & 0x80) && Flag(FVISHOW8)) {
- *twb1++ = 'M';
- if (++col < winwidth) {
- *twb1++ = '-';
- col++;
- }
- ch &= 0x7f;
- }
- if (col < winwidth) {
- if (ch < ' ' || ch == 0x7f) {
- *twb1++ = '^';
- if (++col < winwidth) {
- *twb1++ = ch ^ '@';
- col++;
- }
- } else {
- *twb1++ = ch;
- col++;
- }
- }
- }
- if (cur == es->cursor && !leftside)
- ncol = col + pwidth - 1;
- cur++;
- }
- if (cur == es->cursor)
- ncol = col + pwidth;
- if (col < winwidth) {
- while (col < winwidth) {
- *twb1++ = ' ';
- col++;
- }
- } else
- moreright++;
- *twb1 = ' ';
-
- col = pwidth;
- cnt = winwidth;
- twb1 = wb1;
- twb2 = wb2;
- while (cnt--) {
- if (*twb1 != *twb2) {
- if (cur_col != col)
- ed_mov_opt(col, wb1);
- x_putc(*twb1);
- cur_col++;
- }
- twb1++;
- twb2++;
- col++;
- }
- if (es->winleft > 0 && moreright)
- /* POSIX says to use * for this but that is a globbing
- * character and may confuse people; + is more innocuous
- */
- mc = '+';
- else if (es->winleft > 0)
- mc = '<';
- else if (moreright)
- mc = '>';
- else
- mc = ' ';
- if (mc != morec) {
- ed_mov_opt(pwidth + winwidth + 1, wb1);
- x_putc(mc);
- cur_col++;
- morec = mc;
- }
- if (cur_col != ncol)
- ed_mov_opt(ncol, wb1);
-}
-
-static void
-ed_mov_opt(col, wb)
- int col;
- char *wb;
-{
- if (col < cur_col) {
- if (col + 1 < cur_col - col) {
- x_putc('\r');
- vi_pprompt(0);
- cur_col = pwidth;
- while (cur_col++ < col)
- x_putc(*wb++);
- } else {
- while (cur_col-- > col)
- x_putc('\b');
- }
- } else {
- wb = &wb[cur_col - pwidth];
- while (cur_col++ < col)
- x_putc(*wb++);
- }
- cur_col = col;
-}
-
-
-/* replace word with all expansions (ie, expand word*) */
-static int
-expand_word(command)
- int command;
-{
- static struct edstate *buf;
- int rval = 0;
- int nwords;
- int start, end;
- char **words;
- int i;
-
- /* Undo previous expansion */
- if (command == 0 && expanded == EXPAND && buf) {
- restore_edstate(es, buf);
- buf = 0;
- expanded = NONE;
- return 0;
- }
- if (buf) {
- free_edstate(buf);
- buf = 0;
- }
-
- nwords = x_cf_glob(XCF_COMMAND_FILE|XCF_FULLPATH,
- es->cbuf, es->linelen, es->cursor,
- &start, &end, &words, (int *) 0);
- if (nwords == 0) {
- vi_error();
- return -1;
- }
-
- buf = save_edstate(es);
- expanded = EXPAND;
- del_range(start, end);
- es->cursor = start;
- for (i = 0; i < nwords; ) {
- if (putbuf(words[i], (int) strlen(words[i]), 0) != 0) {
- rval = -1;
- break;
- }
- if (++i < nwords && putbuf(space, 1, 0) != 0) {
- rval = -1;
- break;
- }
- }
- i = buf->cursor - end;
- if (rval == 0 && i > 0)
- es->cursor += i;
- modified = 1; hnum = hlast;
- insert = INSERT;
- lastac = 0;
- refresh(0);
- return rval;
-}
-
-static int
-complete_word(command, count)
- int command;
- int count;
-{
- static struct edstate *buf;
- int rval = 0;
- int nwords;
- int start, end;
- char **words;
- char *match;
- int match_len;
- int is_unique;
- int is_command;
-
- /* Undo previous completion */
- if (command == 0 && expanded == COMPLETE && buf) {
- print_expansions(buf, 0);
- expanded = PRINT;
- return 0;
- }
- if (command == 0 && expanded == PRINT && buf) {
- restore_edstate(es, buf);
- buf = 0;
- expanded = NONE;
- return 0;
- }
- if (buf) {
- free_edstate(buf);
- buf = 0;
- }
-
- /* XCF_FULLPATH for count 'cause the menu printed by print_expansions()
- * was done this way.
- */
- nwords = x_cf_glob(XCF_COMMAND_FILE | (count ? XCF_FULLPATH : 0),
- es->cbuf, es->linelen, es->cursor,
- &start, &end, &words, &is_command);
- if (nwords == 0) {
- vi_error();
- return -1;
- }
- if (count) {
- int i;
-
- count--;
- if (count >= nwords) {
- vi_error();
- x_print_expansions(nwords, words, is_command);
- x_free_words(nwords, words);
- redraw_line(0);
- return -1;
- }
- /*
- * Expand the count'th word to its basename
- */
- if (is_command) {
- match = words[count]
- + x_basename(words[count], (char *) 0);
- /* If more than one possible match, use full path */
- for (i = 0; i < nwords; i++)
- if (i != count &&
- FILECMP(words[i]
- + x_basename(words[i], (char *) 0),
- match) == 0)
- {
- match = words[count];
- break;
- }
- } else
- match = words[count];
- match_len = strlen(match);
- is_unique = 1;
- /* expanded = PRINT; next call undo */
- } else {
- match = words[0];
- match_len = x_longest_prefix(nwords, words);
- expanded = COMPLETE; /* next call will list completions */
- is_unique = nwords == 1;
- }
-
- buf = save_edstate(es);
- del_range(start, end);
- es->cursor = start;
- if (putbuf(match, match_len, 0) != 0)
- rval = -1;
- else if (is_unique) {
- /* If exact match, don't undo. Allows directory completions
- * to be used (ie, complete the next portion of the path).
- */
- expanded = NONE;
-
- /* If not a directory, add a space to the end... */
- if (match_len > 0 && !ISDIRSEP(match[match_len - 1]))
- rval = putbuf(space, 1, 0);
- }
- x_free_words(nwords, words);
-
- modified = 1; hnum = hlast;
- insert = INSERT;
- lastac = 0; /* prevent this from being redone... */
- refresh(0);
-
- return rval;
-}
-
-static int
-print_expansions(e, command)
- struct edstate *e;
- int command;
-{
- int nwords;
- int start, end;
- char **words;
- int is_command;
-
- nwords = x_cf_glob(XCF_COMMAND_FILE|XCF_FULLPATH,
- e->cbuf, e->linelen, e->cursor,
- &start, &end, &words, &is_command);
- if (nwords == 0) {
- vi_error();
- return -1;
- }
- x_print_expansions(nwords, words, is_command);
- x_free_words(nwords, words);
- redraw_line(0);
- return 0;
-}
-
-/* How long is char when displayed (not counting tabs) */
-static int
-char_len(c)
- int c;
-{
- int len = 1;
-
- if ((c & 0x80) && Flag(FVISHOW8)) {
- len += 2;
- c &= 0x7f;
- }
- if (c < ' ' || c == 0x7f)
- len++;
- return len;
-}
-
-/* Similar to x_zotc(emacs.c), but no tab wierdness */
-static void
-x_vi_zotc(c)
- int c;
-{
- if (Flag(FVISHOW8) && (c & 0x80)) {
- x_puts("M-");
- c &= 0x7f;
- }
- if (c < ' ' || c == 0x7f) {
- x_putc('^');
- c ^= '@';
- }
- x_putc(c);
-}
-
-static void
-vi_pprompt(full)
- int full;
-{
- pprompt(prompt + (full ? 0 : prompt_skip), prompt_trunc);
-}
-
-static void
-vi_error()
-{
- /* Beem out of any macros as soon as an error occurs */
- vi_macro_reset();
- x_putc(BEL);
- x_flush();
-}
-
-static void
-vi_macro_reset()
-{
- if (macro.p) {
- afree(macro.buf, APERM);
- memset((char *) &macro, 0, sizeof(macro));
- }
-}
-
-#endif /* VI */