[Midnightbsd-cvs] CVS Commit: bin/ksh: Remove OpenBSD ksh

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sat Aug 18 01:43:55 EDT 2007


Log Message:
-----------
Remove OpenBSD ksh

Removed Files:
-------------
    src/bin/ksh:
        BUG-REPORTS
        CONTRIBUTORS
        ChangeLog
        ChangeLog.0
        IAFA-PACKAGE
        INSTALL
        LEGAL
        Makefile
        NEWS
        NOTES
        PROJECTS
        README
        alloc.c
        c_ksh.c
        c_sh.c
        c_test.c
        c_test.h
        c_ulimit.c
        config.h
        edit.c
        edit.h
        emacs-gen.sh
        emacs.c
        eval.c
        exec.c
        expand.h
        expr.c
        history.c
        io.c
        jobs.c
        ksh.1
        ksh_limval.h
        lex.c
        lex.h
        mail.c
        main.c
        misc.c
        mknod.c
        path.c
        proto.h
        sh.1
        sh.h
        shf.c
        shf.h
        syn.c
        table.c
        table.h
        trap.c
        tree.c
        tree.h
        tty.c
        tty.h
        var.c
        version.c
        vi.c
    src/bin/ksh/tests:
        README
        alias.t
        arith.t
        bksl-nl.t
        brkcont.t
        cdhist.t
        eglob.t
        glob.t
        heredoc.t
        history.t
        ifs.t
        integer.t
        lineno.t
        read.t
        regress.t
        syntax.t
        th
        unclass1.t
        unclass2.t
        version.t

-------------- next part --------------
--- bin/ksh/BUG-REPORTS
+++ /dev/null
@@ -1,1399 +0,0 @@
-$MidnightBSD: src/bin/ksh/BUG-REPORTS,v 1.2 2007/07/26 20:12:59 laffer1 Exp $
-$OpenBSD: BUG-REPORTS,v 1.16 2005/11/15 07:02:33 miod 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 separate 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]
-  [partly fixed in 5.2.14: backquote ok, but happens for the likes of ${.]
-
-* 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 at twinsun.com)): history (fc,
-  et al) don't work in shell scripts.
-  [see Mail.10:49]
-
-* 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.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]
-
-* pdksh 5.2.12, - (reported by Han Holl <jeholl at euronet.nl>): pdksh does not
-  parse the whole script before executing, so some syntax errors are not
-  detected (if the shell exits before reading the whole file).
-  [see Mail.XXX]
-
-* pdksh 5.2.12, (reported by Michael Staats): emacs: file completion does
-  not complete as much as possible when file is ~/something (will list
-  possible completions but won't fill in to the first difference).
-  Happens since code doesn't distinguish between globbing and ~ (needs
-  special case to strip & replace a leading ~ during the completion
-  process).
-
-* pdksh 5.2.13, (reported by Martin Dalecki): shell dumps core when set -x
-  is used on some scripts
-  [awaiting more info...]
-
-* pdksh 5.2.13, (reported by Arthor Pool): interactive shells can't be
-  interrupted when processing ${foo#bar} expressions.
-  [same goes for globbing - fixing this means checking for interrupts in
-  the `tight' loops - could slow things down quite a bit]
-
---------------------- 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): scripts 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 negative 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 at 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 at 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 at 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 at 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 at 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()).]
-
-x pdksh 5.2.12, - (reported with fix by Eric J. Chet via Thomas Gellekum):
-  . can cause core dump when cleaning up.
-  [see Mail.XXX]
-  [fixed in 5.2.13: call shf_close() before quitenv()]
-
-x pdksh 5.2.12, - (reported by Bruce Burns): test with a single -t option
-  always returns true (does a string test instead of isatty(1)).
-  [see Mail.XXX]
-  [fixed in 5.2.13: do the isatty(1) unless in posix mode]
-
-x pdksh 5.2.12, - (reported by David Tamkin): aliases ending in "; "
-  cause continuation prompt to be printed.
-  [see Mail.XXX]
-  [fixed in 5.2.13: syn.c(c_list) now handles blank lines, removed cf=CONTIN
-   in syn.c(get_command)]
-
-x pdksh 5.2.12, - (reported by Herbert Thielen via Larry Daffner): set
-  does not allow +o and -o options in the same command line.
-  [see Mail.XXX]
-  [fixed in 5.2.13: changed ksh_getopt to remove exclusion code.]
-
-x pdksh 5.2.12, - (reported by Han Holl <jeholl at euronet.nl>):
-  set -A foo -- bar doesn't skip the --.
-  [see Mail.XXX]
-  [fixed in 5.2.13: changed misc.c(parse_args) so A takes an option]
-
-x pdksh 5.2.12, - (reported by David Tamkin): -e (errexit) should be ignored
-  when processing profile and ENV.
-  [see Mail.XXX]
-  [fixed in 5.2.13: errexit saved/cleared/restored in main()]
-
-x pdksh 5.2.12, - (reported by Han Holl <jeholl at euronet.nl>):
-  [ -x foo ] succeeds for root if foo exists.
-  [see Mail.XXX]
-  [fixed in 5.2.13: changed c_test.c(test_access) to use stat in this case]
-
-x pdksh 5.2.4, - (reported by Gabor Zahemszky): echo ${foo[*]#/} generates
-  bad substsitution error, newer ksh's don't (older ones do);
-  error includes {...#@(/)}.
-  [fixed in 5.2.13: moved the @(..) hack from yylex() to expand()]
-
-x pdksh 5.2.8, - : extended pattern globing doesn't handle nested parens (),
-  e.g., [[ aby = +(a|b(x|y)) ]]
-
-x pdksh 5.2.12, - (reported by Marc Olzheim <marcolz at stack.nl>):
-  "echo a | (echo b | echo c)" causes a core dump.
-  [see Mail.XXX]
-  [fixed in 5.2.13: clear XPIPEI,XPIPEO at start of jobs.c(exchild)]
-
-x pdksh 5.2.12, - (reported by Curt Finch <curt at pnk.com>): in an interactive
-  shell, globbing isn't done on redirections if the command is part of
-  a pipeline.  e.g., in "cat < /tmp/*gz | grep foo", the /tmp/*gz is
-  not expanded.
-  [see Mail.XXX]
-  [fixed in 5.2.13: clear XPIPEI,XPIPEO at start of jobs.c(exchild)]
-
-x pdksh 5.2.12, - (reported with fix by Greg A. Woods <woods at most.weird.com>):
-  in emacs, ^[_ (aka ^[.) gets the word from the previous line relative to
-  where the current line came from in the history.  It should get it from
-  the last executed line ala at&t ksh.
-  [see Mail.XXX]
-  [fixed in 5.2.13: use absolute last command]
-
-x pdksh 5.2.12, - (reported by Gabor Zahemszky): MAILCHECK and MAIL
-  don't report `new mail' unless MAIL is re-assigned.
-  [see Mail.XXX]
-  [fixed in 5.2.13: mail code was using variables memory, which was later
-   trashed by exporting the MAIL variable.  Fixed by saving copy of value.]
-
-x pdksh 5.2.12, - (reported by Gabor Zahemszky): memory gets badly fragmented
-  when reversing a (large) file using a simple while read loop and variable
-  concatenation.
-  [see Mail.XXX]
-  [fixed in 5.2.13: alloc.c changed to allow malloc() to deal with large
-   blocks.]
-
-x pdksh 5.2.12, - (reported by Bernd Eggink <eggink at rrz.uni-hamburg.de>)
-  ksh style functions don't save/reset/restore OPTIND.
-  [see Mail.XXX]
-  [fixed in 5.2.13: save and restore user_opt for ksh-style functions.]
-
-x pdksh 5.2.12, - (reported by Marc Olzheim <marcolz at stack.nl>)
-  ${..%..} stuff don't work in SH mode.
-  [see Mail.XXX]
-  [fixed in 5.2.13: removed ifdef KSH from misc.c(do_gmatch)]
-
-x pdksh 5.2.12, - (reported with fix by George Robbins
-  <grr at shandakor.tharsis.com>)
-  in sh, "exec 3>&1" does not keep fd 3 open in executed commands.
-  [see Mail.XXX]
-  [fixed in 5.2.13: c_sh.c(c_exec): added ifdef KSH around fd_clexec() call]
-
-x pdksh 5.2.12, - (reported with fix by George White
-  <gwhite at bodnext.bio.dfo.ca>)
-  in remove_temps(main.c), space for name field is not allocated correctly.
-  [see Mail.XXX]
-  [fixed in 5.2.13: initialize t->name in new structure]
-
-x pdksh 5.2.12, - (reported with fix by Marc Olzheim <marcolz at stack.nl>):
-  when at (past) end of the line, word/command completion will skip back
-  [see Mail.XXX]
-  [fixed in 5.2.13: edit.c(x_locate_word): delete special handling of
-   end-of-buffer]
-
-x pdksh 5.2.12, - (reported by Mike Kelly <tfsmiles at ecst.csuchico.edu>):
-  doting a directory (or a empty path) is allowed.
-  [see Mail.XXX]
-  [fixed in 5.2.13: exec.c(search_access): don't do non-regular files for R_OK]
-
-x pdksh 5.2.13, - (reported by Mike Kelly <tfsmiles at ecst.csuchico.edu>):
-  typeset -f FUNC doesn't print follows command (and expression) substitutions.
-  [see Mail.XXX]
-  [fixed in 5.2.14: tree.c(tputS): add wp++]
-
-x pdksh 5.2.13, - (reported by Thomas Gellekum):
-  make check fails on freebsd with "chmod 644 abcx failed - Inappropriate ...".
-  [see Mail.XXX]
-  [fixed in 5.2.14: make test/th convert permissions to octal]
-
-x pdksh 5.2.13, - (reported with fix by David E. Wexelblat):
-  when re-allocating memory, too much may be copied from old memory.
-  [see Mail.XXX]
-  [fixed in 5.2.14: use min old old size and new size]
-
-x pdksh 5.2.13, - (reported with fix by David E. Wexelblat):
-  set -o printed some options sans names.
-  [see Mail.XXX]
-  [fixed in 5.2.14: use 0 instead of null in options[] table]
-
-x pdksh 5.2.13, - (reported by Gabor Zahemszky):
-  emacs mode: <esc>. in very fist command causes core dump.
-  [see Mail.XXX]
-  [fixed in 5.2.14: ring bell if no history in emacs.c(x_prev_histword)]
-
-x pdksh 5.2.13, - (reported by Keith S McCabe): pdksh dumps core
-  after a cd command.
-  [see Mail.XXX]
-  [fixed in 5.2.14: exec.c(flushcom) was setting bits in table entry, instead
-   of clearing a single bit]
-
-x pdksh 5.2.12, - (reported by Jaime A. Urquidi): typeset -i reports
-  on array elements that have no value (at&t ksh reports on array
-  base name - no index).
-  [see Mail.XXX]
-  [fixed in 5.2.14: hack to c_ksh.c(c_typeset) to generate the ksh88 style
-   output]
-
-x pdksh 5.2.13, - (reported with fix by Todd C. Miller):
-  ulimit -ctn unlimittttted kills shell (resource exceeded).
-  [see Mail.XXX]
-  [fixed in 5.2.14: hacked c_ulimit to generate error val is 0 and expr doesn't
-   start with a digit]
-
-x pdksh 5.2.13, - (reported with fix by Theo de Raadt):
-  ". /dev/null" says access denied.
-  [see Mail.XXX]
-  [fixed in 5.2.14: exec.c(search_access): allow non-regular file if reading]
-
-x pdksh 5.2.13, - (reported with fix by Eric Youngdale): flag field in aliases
-  incorrectly changed (all flags set instead of clearing ISSET) in
-  exec.c(flushcom).
-  [see Mail.XXX]
-  [fixed in 5.2.14: exec.c(flushcom): change = ~ISSET to &= ~ISSET]
-
-x pdksh 5.2.13, - (reported by Andre Delafontaine): ${#array[*]} prints
-  largest index instead of number of (set) elements in an array (ksh88 does
-  the former).
-  [see Mail.XXX]
-  [fixed in 5.2.14: eval.c(varsub): count number of elements]
-
-x pdksh 5.2.13, - (reported by Clifford Wolf): sys_siglist[] doesn't
-  always have NSIG non-null entries...
-  [see Mail.XXX]
-  [fixed in 5.2.14: trap.c(inittrap): check for null sys_siglist entries.]
-
-x pdksh 5.2.13, - (reported with fix by Todd C. Miller): waitfor in jobs.c
-  can cause core dump if j_lookup fails.
-  [fixed in 5.2.14: jobs.c(waitfor): return if j_lookup fails]
-
-x pdksh 5.2.13, - (reported by Martin Bond): if shell is started several
-  times in quick succession, echo $RANDOM produces the same results.
-  [fixed in 5.2.14: main.c(main): seed RANDOM using time, pid, ppid]
-
-x pdksh 5.2.13, - (reported by Martin Bond): repeating "echo `echo $RANDOM`"
-  will always produce the same number.
-  [fixed in 5.2.14: call var.c(change_random) from jobs.c(exchild)]
-
-x pdksh 5.2.13, hpux 10.x (reported by Mike Kelly): pwd will dump core if
-  current directory is not readable.
-  [fixed in 5.2.14: config test & code to work around hpux C library bug]
-
-x pdksh 5.2.13, linux (reported by Mike Jetzer): getwd warning from linker
-  [fixed in 5.2.14: configure.in/misc.c: check for getcwd, use it over getwd]
-
-x pdksh 5.2.13, (reported by Dmitri Kulginov): "trap exit 1" does not set a
-  trap for HUP (exit is mistaken as a signal name, not a command).
-  [fixed in 5.2.14: c_sh.c(c_trap): use case sensitive lookup for first arg]
-
-x pdksh 5.2.13, (reported by Mark Funkenhauser): eval "$(false)" does not
-  result in $? being set to 1 (is 0).
-  [fixed in 5.2.14: c_sh.c(c_eval): set exstat to subst_exstat before shell()]
-
-x pdksh 5.2.13, (reported with fix by Kevin Schoedel): word boundaries in
-  file completion are only spaces - at&t ksh uses ()<>&| and spaces.
-  [fixed in 5.2.14: edit.c(IS_WORDC): changed macro to be LEX1 + quotes]
-
-x pdksh 5.2.13.5, (reported with fix by Martin Lucina <mato at kotelna.sk>):
-  exit status parsing in exit command incorrect (sets status to random
-  value if no argument given).
-  [fixed in 5.2.14: c_sh.c(c_exitreturn): only set exstat if arg given]
-
-x pdksh 5.2.13.5, (reported with fix by Martin Lucina <mato at kotelna.sk>):
-  KSH_CHECK_H_TYPE in aclocal.m4 has too many [] around the patterns.
-  [fixed in 5.2.14: aclocal.m4(KSH_CHECK_H_TYPE): remove two pairs on []]
-
-x pdksh 5.2.13.5, (reported by Charles M. Hannum <root at ihack.net>): An exit
-  trap set in a subshell is not executed (unless explicit exit used).
-  [fixed in 5.2.14: exec.c(execute): changed exit(rv) to unwind(LEXIT).]
-
-x pdksh 5.2.12, - : MAILCHECK isn't preserved from the environment on startup.
-  [fixed in 5.2.14: changed main's initcoms[].]
-
-x pdksh 5.2.13, (reported by Marc Olzheim): time at the end of a pipeline
-  doesn't print anything.
-  [fixed in 5.2.14: exec.c(execute): clear XEXEC when calling timex().]
-
-x pdksh 5.2.13, (reported by David J. McMahon): here documents in subshells
-  don't work if the parent exits before the subshell.
-  [fixed in 5.2.14: heredocs now saved in memory, written to temp when needed.]
-
-x pdksh 5.2.13, (reported by Seiichi Namba): emacs: keys bound in .profile/$ENV
-  are overridden by stty settings (eg, binding ^U in .profile has no effect).
-  [fixed in 5.2.14: emacs.c: added x_bound array to track what user has set.]
-
-x pdksh 5.2.13: vi: failed redo (.) commands caused line to be returned to the
-  shell (eg, "echo hi/there^[Bdf/.").
-  [fixed in 5.2.14: vi.c(vi_hook): removed !=0 from VREDO switch expression]
-
-x pdksh 5.2.13, (reported by Arthor Pool): man page: (a) the time reserved
-  word is not described; (b) description of command line wrapping is in vi
-  section only (not in emacs); (c) limit on array indices not mentioned;
-  (d) ignoreeof ignored if eof read 13 times.
-  [fixed in 5.2.14: man page updated]
-
-x pdksh 5.2.13, (reported by Arthor Pool): set -u causes loss of stdout
-  when command substitution with undefined parameter reference is run
-  in an interactive shell.
-  [fixed in 5.2.14: jobs.c(fill_command): don't eval TCOM arguments]
-
-  XXX fd 1 lost (general fd pool handler?, error handler for comsub?)
-
-  AP messages:
-      time not descr
-      vi/emacs <+>
-      trap
-      typeset -f ... "$(jasdsjh)" ...
-      array
-      os2 interrupts + pattern 
-      ignoreeof
-      set -A --
-      set -u -> comsub errors & fill_command eval
-
-x pdksh 5.2.13, (reported by Dave Hillman): test -nt
-  and test -ot do not succeed if file2 (file2) does not exist.
-  [fixed in 5.2.14: c_test.c(test_eval): return true if appropriate stat fails]
-
--- bin/ksh/alloc.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/alloc.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: alloc.c,v 1.7 2004/02/19 18:51:17 deraadt Exp $	*/
-/*
- * Copyright (c) 2002 Marc Espie.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
- * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * area-based allocation built on malloc/free
- */
-
-#include "sh.h"
-
-struct link {
-	struct link *prev;
-	struct link *next;
-};
-
-Area *
-ainit(Area *ap)
-{
-	ap->freelist = NULL;
-	return ap;
-}
-
-void
-afreeall(Area *ap)
-{
-	struct link *l, *l2;
-
-	for (l = ap->freelist; l != NULL; l = l2) {
-		l2 = l->next;
-		free(l);
-	}
-	ap->freelist = NULL;
-}
-
-#define L2P(l)	( (void *)(((char *)(l)) + sizeof(struct link)) )
-#define P2L(p)	( (struct link *)(((char *)(p)) - sizeof(struct link)) )
-
-void *
-alloc(size_t size, Area *ap)
-{
-	struct link *l;
-
-	l = malloc(sizeof(struct link) + size);
-	if (l == NULL)
-		internal_errorf(1, "unable to allocate memory");
-	l->next = ap->freelist;
-	l->prev = NULL;
-	if (ap->freelist)
-		ap->freelist->prev = l;
-	ap->freelist = l;
-
-	return L2P(l);
-}
-
-void *
-aresize(void *ptr, size_t size, Area *ap)
-{
-	struct link *l, *l2, *lprev, *lnext;
-
-	if (ptr == NULL)
-		return alloc(size, ap);
-
-	l = P2L(ptr);
-	lprev = l->prev;
-	lnext = l->next;
-
-	l2 = realloc(l, sizeof(struct link) + size);
-	if (l2 == NULL)
-		internal_errorf(1, "unable to allocate memory");
-	if (lprev)
-		lprev->next = l2;
-	else
-		ap->freelist = l2;
-	if (lnext)
-		lnext->prev = l2;
-
-	return L2P(l2);
-}
-
-void
-afree(void *ptr, Area *ap)
-{
-	struct link *l;
-
-	if (!ptr)
-		return;
-
-	l = P2L(ptr);
-
-	if (l->prev)
-		l->prev->next = l->next;
-	else
-		ap->freelist = l->next;
-	if (l->next)
-		l->next->prev = l->prev;
-
-	free(l);
-}
--- bin/ksh/sh.h
+++ /dev/null
@@ -1,421 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/sh.h,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: sh.h,v 1.29 2005/12/11 18:53:51 deraadt 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 */
-
-/* Start of common headers */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <setjmp.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdarg.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-
-#include <signal.h>
-
-#include <paths.h>
-
-/* 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).
- * NOTE: INT32 may end up being more than 32 bits.
- */
-# define INT32	int
-
-/* end of common headers */
-
-/* some useful #defines */
-#ifdef EXTERN
-# define I__(i) = i
-#else
-# define I__(i)
-# define EXTERN extern
-# define EXTERN_DEFINED
-#endif
-
-#define EXECSHELL	_PATH_BSHELL
-#define EXECSHELL_STR	"EXECSHELL"
-
-#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 */
-
-/* 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	2048		/* input line size */
-#define	PATH	1024		/* pathname size (todo: PATH_MAX/pathconf()) */
-#define ARRAYMAX 2047		/* max array index */
-
-EXTERN	const char *kshname;	/* $0 */
-EXTERN	pid_t	kshpid;		/* $$, shell pid */
-EXTERN	pid_t	procpid;	/* pid of executing process */
-EXTERN	uid_t	ksheuid;	/* effective uid of shell */
-EXTERN	int	exstat;		/* exit status */
-EXTERN	int	subst_exstat;	/* exit status of last $(..)/`..` */
-EXTERN	const char *safe_prompt; /* safe prompt if PS1 substitution fails */
-EXTERN	char	username[];	/* username for \u prompt expansion */
-
-/*
- * Area-based allocation built on malloc/free
- */
-typedef struct Area {
-	struct link *freelist;	/* free list */
-} Area;
-
-EXTERN	Area	aperm;		/* permanent object space */
-#define	APERM	&aperm
-#define	ATEMP	&e->area
-
-#ifdef KSH_DEBUG
-# define kshdebug_init()	kshdebug_init_()
-# define kshdebug_printf(a)	kshdebug_printf_ a
-# define kshdebug_dump(a)	kshdebug_dump_ a
-#else /* KSH_DEBUG */
-# define kshdebug_init()
-# define kshdebug_printf(a)
-# define kshdebug_dump(a)
-#endif /* KSH_DEBUG */
-
-/*
- * parsing & execution environment
- */
-EXTERN	struct env {
-	short	type;			/* environment 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 environment */
-	sigjmp_buf jbuf;		/* long jump back to env creator */
-	struct temp *temps;		/* temp files */
-} *e;
-
-/* struct env.type values */
-#define	E_NONE	0		/* dummy environment */
-#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 */
-#define EF_FAKE_SIGDIE	BIT(2)	/* hack to get info from unwind to quitenv */
-
-/* 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 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_INTERNAL	0x08	/* set internally by shell */
-#define OF_ANY		(OF_CMDLINE | OF_SET | OF_SPECIAL | OF_INTERNAL)
-
-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 */
-	FCSHHISTORY,	/* csh-style history enabled */
-#ifdef EMACS
-	FEMACS,		/* emacs command editing */
-	FEMACSUSEMETA,	/* use 8th bit as meta */
-#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 anywhere */
-	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 behaviour */
-	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 */
-	FTALKING_I,	/* (internal): initial shell was interactive */
-	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");
-
-enum temp_type {
-	TT_HEREDOC_EXP,	/* expanded heredoc */
-	TT_HIST_EDIT	/* temp file used for history editing (fc -e) */
-};
-typedef enum temp_type Temp_type;
-/* temp/heredoc 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 */
-	Temp_type	type;
-	char		*name;
-};
-
-/*
- * 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 */
-	volatile sig_atomic_t set; /* trap pending */
-	int	flags;		/* TF_* */
-	sig_t cursig;		/* current handler (valid if TF_ORIG_* set) */
-	sig_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_		NSIG	/* for trap ERR */
-
-EXTERN	volatile sig_atomic_t trap;	/* traps pending? */
-EXTERN	volatile sig_atomic_t intrsig;	/* pending trap interrupts command */
-EXTERN	volatile sig_atomic_t fatal_trap;/* received a fatal signal */
-extern	Trap	sigtraps[NSIG+1];
-
-/*
- * 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);
-
-/* 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;
-	int		uoptind;/* what user sees in $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 */
-EXTERN Getopt user_opt;		/* parsing state for getopts builtin command */
-
-/* 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;
-
-/* Used in jobs.c and by coprocess stuff in exec.c */
-EXTERN sigset_t		sm_default, sm_sigchld;
-
-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
-/* Minimum 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
-/* Minimum 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 */
-#define KSH_SYSTEM_PROFILE "/etc/profile"
-
-/* Used by v_evaluate() and setstr() to control action when error occurs */
-#define KSH_UNWIND_ERROR	0	/* unwind the stack (longjmp) */
-#define KSH_RETURN_ERROR	1	/* return 1/0 for success/failure */
-
-#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__
--- bin/ksh/IAFA-PACKAGE
+++ /dev/null
@@ -1,18 +0,0 @@
-$OpenBSD: IAFA-PACKAGE,v 1.7 1999/07/14 13:37:23 millert Exp $
-
-Title:		pdksh
-Version:	5.2.14
-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 at zen.void.oz.au (Simon J. Gerraty),
-		michael at cs.mun.ca (Michael Rendell), (plus many others)
-Maintained-by:	michael at 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
-		and (using cygwin32 package) on win95/NT
-Copying-Policy:	Freely Redistributable (mostly public domain, some copyrighted)
-Keywords:	pdksh, ksh, Korn, shell, command line interpreter
--- bin/ksh/LEGAL
+++ /dev/null
@@ -1,12 +0,0 @@
-$OpenBSD: LEGAL,v 1.2 2003/07/17 20:59:43 deraadt 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
-		[REMOVED]
-	aclocal.m4
-		[REMOVED]
-
-That's it.  Short and simple.
--- bin/ksh/table.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/table.h,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: table.h,v 1.7 2005/12/11 20:31:21 otto 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)(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;
-	int	flags;		/* see BF_* */
-	struct	table vars;	/* local variables */
-	struct	table funs;	/* local functions */
-	Getopt	getopts_state;
-#if 1
-	char *	error;		/* error handler */
-	char *	exit;		/* exit handler */
-#else
-	Trap	error, exit;
-#endif
-	struct	block *next;	/* enclosing block */
-};
-
-/* Values for struct block.flags */
-#define BF_DOGETOPTS	BIT(0)	/* save/restore getopts state */
-
-/*
- * Used by ktwalk() and ktnext() 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)(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
-#define V_LINENO		17
-
-/* values for set_prompt() */
-#define PS1	0		/* command */
-#define PS2	1		/* command continuation */
-
-EXTERN char *path;		/* copy of either PATH or def_path */
-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 */
-EXTERN int current_lineno;	/* LINENO value */
--- bin/ksh/main.c
+++ /dev/null
@@ -1,749 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/main.c,v 1.4 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: main.c,v 1.41 2006/04/10 14:38:59 jaredy Exp $	*/
-
-/*
- * startup, main loop, environments and error handling
- */
-
-#define	EXTERN				/* define EXTERNs in sh.h */
-
-#include "sh.h"
-#include <sys/stat.h>
-#include <pwd.h>
-#include <sys/param.h>
-
-extern char **environ;
-
-/*
- * global data
- */
-
-static void	reclaim(void);
-static void	remove_temps(struct temp *tp);
-static int	is_restricted(char *name);
-static void	init_username(void);
-
-/*
- * shell initialization
- */
-
-static const char initifs[] = "IFS= \t\n";
-
-static const char initsubs[] = "${PS2=> } ${PS3=#? } ${PS4=+ }";
-
-static const char *initcoms [] = {
-	"typeset", "-r", "KSH_VERSION", NULL,
-	"typeset", "-x", "SHELL", "PATH", "HOME", NULL,
-	"typeset", "-i", "PPID", NULL,
-	"typeset", "-i", "OPTIND=1", NULL,
-	"eval", "typeset -i RANDOM MAILCHECK=\"${MAILCHECK-600}\" SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"", 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
-	  "autoload=typeset -fu",
-	  "functions=typeset -f",
-#ifdef HISTORY
-	  "history=fc -l",
-#endif /* HISTORY */
-	  "integer=typeset -i",
-	  "nohup=nohup ",
-	  "local=typeset",
-	  "r=fc -e -",
-	 /* Aliases that are builtin commands in at&t */
-	  "login=exec login",
-	  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,
-	NULL
-};
-
-char username[MAXLOGNAME];
-
-#define version_param  (initcoms[2])
-
-int
-main(int argc, char *argv[])
-{
-	int i;
-	int argi;
-	Source *s;
-	struct block *l;
-	int restricted, errexit;
-	char **wp;
-	struct env env;
-	pid_t ppid;
-
-	/* make sure argv[] is sane */
-	if (!*argv) {
-		static const char *empty_argv[] = {
-			"ksh", (char *) 0
-		};
-
-		argv = (char **) empty_argv;
-		argc = 1;
-	}
-	kshname = *argv;
-
-	ainit(&aperm);		/* initialize permanent Area */
-
-	/* set up base environment */
-	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();
-
-	coproc_init();
-
-	/* set up variable and command dictionaries */
-	ktinit(&taliases, APERM, 0);
-	ktinit(&aliases, APERM, 0);
-	ktinit(&homedirs, APERM, 0);
-
-	/* define shell keywords */
-	initkeywords();
-
-	/* define built-in commands */
-	ktinit(&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 = _PATH_DEFPATH;
-	{
-		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;
-		}
-	}
-
-	/* Set PATH to def_path (will set the path global variable).
-	 * (import of environment below will probably change this setting).
-	 */
-	{
-		struct tbl *vp = global("PATH");
-		/* setstr can't fail here */
-		setstr(vp, def_path, KSH_RETURN_ERROR);
-	}
-
-
-	/* Turn on nohup by default for now - will change to off
-	 * by default once people are aware of its existence
-	 * (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;
-		version_param = "SH_VERSION";
-	}
-
-	/* Set edit mode to emacs by default, may be overridden
-	 * by the environment or the user.  Also, we want tab completion
-	 * on in vi by default. */
-#if defined(EDIT) && defined(EMACS)
-	change_flag(FEMACS, OF_SPECIAL, 1);
-#endif /* EDIT && EMACS */
-#if defined(EDIT) && defined(VI)
-	Flag(FVITABCOMPLETE) = 1;
-#endif /* EDIT && VI */
-
-	/* import environment */
-	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 (pwd[0] != '/' ||
-		    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 can't fail here */
-			setstr(pwd_v, current_wd, KSH_RETURN_ERROR);
-	}
-	ppid = getppid();
-	setint(global("PPID"), (long) ppid);
-	/* setstr can't fail here */
-	setstr(global(version_param), ksh_version, KSH_RETURN_ERROR);
-
-	/* execute initialization statements */
-	for (wp = (char**) initcoms; *wp != NULL; wp++) {
-		shcomexec(wp);
-		for (; *wp != NULL; wp++)
-			;
-	}
-
-
-	ksheuid = geteuid();
-	init_username();
-	safe_prompt = ksheuid ? "$ " : "# ";
-	{
-		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) ||
-		    (!ksheuid && !strchr(str_val(vp), '#')))
-			/* setstr can't fail here */
-			setstr(vp, safe_prompt, KSH_RETURN_ERROR);
-	}
-
-	/* Set this before parsing arguments */
-	Flag(FPRIVILEGED) = getuid() != ksheuid || 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);
-		s->file = argv[argi++];
-		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) = Flag(FTALKING_I) = 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) &&
-		    Flag(FTALKING))
-			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;
-	errexit = Flag(FERREXIT);
-	Flag(FERREXIT) = 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)) {
-		include(KSH_SYSTEM_PROFILE, 0, (char **) 0, 1);
-		if (!Flag(FPRIVILEGED))
-			include(substitute("$HOME/.profile", 0), 0,
-			    (char **) 0, 1);
-	}
-
-	if (Flag(FPRIVILEGED))
-		include("/etc/suid_profile", 0, (char **) 0, 1);
-	else {
-		char *env_file;
-
-		/* 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);
-	}
-
-	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 (errexit)
-		Flag(FERREXIT) = 1;
-
-	if (Flag(FTALKING)) {
-		hist_init(s);
-		alarm_init();
-	} else
-		Flag(FTRACKALL) = 1;	/* set after ENV */
-
-	shell(s, true);	/* doesn't return */
-	return 0;
-}
-
-static void
-init_username(void)
-{
-	char *p;
-	struct tbl *vp = global("USER");
-
-	if (vp->flag & ISSET)
-		p = ksheuid == 0 ? "root" : str_val(vp);
-	else
-		p = getlogin();
-
-	strlcpy(username, p != NULL ? p : "?", sizeof username);
-}
-
-int
-include(const char *name, int argc, char **argv, int intr_ok)
-{
-	Source *volatile s = NULL;
-	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;
-	}
-	newenv(E_INCL);
-	i = sigsetjmp(e->jbuf, 0);
-	if (i) {
-		quitenv(s ? s->u.shf : NULL);
-		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;
-			/* FALLTHROUGH */
-		case LEXIT:
-		case LLEAVE:
-		case LSHELL:
-			unwind(i);
-			/* NOTREACHED */
-		default:
-			internal_errorf(1, "include: %d", i);
-			/* NOTREACHED */
-		}
-	}
-	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);
-	quitenv(s->u.shf);
-	if (old_argv) {
-		e->loc->argv = old_argv;
-		e->loc->argc = old_argc;
-	}
-	return i & 0xff;	/* & 0xff to ensure value not -1 */
-}
-
-int
-command(const char *comm)
-{
-	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(Source *volatile s, volatile int toplevel)
-{
-	struct op *t;
-	volatile int wastty = s->flags & SF_TTY;
-	volatile int attempts = 13;
-	volatile int interactive = Flag(FTALKING) && toplevel;
-	Source *volatile old_source = source;
-	int i;
-
-	newenv(E_PARSE);
-	if (interactive)
-		really_exit = 0;
-	i = sigsetjmp(e->jbuf, 0);
-	if (i) {
-		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)...
-				 */
-				/* toss any input we have so far */
-				s->start = s->str = null;
-				break;
-			}
-			/* FALLTHROUGH */
-		case LEXIT:
-		case LLEAVE:
-		case LRETURN:
-			source = old_source;
-			quitenv(NULL);
-			unwind(i);	/* keep on going */
-			/* NOTREACHED */
-		default:
-			source = old_source;
-			quitenv(NULL);
-			internal_errorf(1, "shell: %d", i);
-			/* NOTREACHED */
-		}
-	}
-
-	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();
-			mcheck();
-			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(NULL);
-	source = old_source;
-	return exstat;
-}
-
-/* return to closest error handler or shell(), exit if none found */
-void
-unwind(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:
-			siglongjmp(e->jbuf, i);
-			/* NOTREACHED */
-
-		case E_NONE:
-			if (i == LINTR)
-				e->flags |= EF_FAKE_SIGDIE;
-			/* FALLTHROUGH */
-
-		default:
-			quitenv(NULL);
-		}
-	}
-}
-
-void
-newenv(int type)
-{
-	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(struct shf *shf)
-{
-	struct env *ep = e;
-	int fd;
-
-	if (ep->oenv && 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);
-	}
-
-	/* Bottom of the stack.
-	 * Either main shell is exiting or cleanup_parents_env() was called.
-	 */
-	if (ep->oenv == NULL) {
-		if (ep->type == E_NONE) {	/* Main shell exiting? */
-			if (Flag(FTALKING))
-				hist_finish();
-			j_exit();
-			if (ep->flags & EF_FAKE_SIGDIE) {
-				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) &&
-				    getpgrp() == kshpid) {
-					setsig(&sigtraps[sig], SIG_DFL,
-					    SS_RESTORE_CURR|SS_FORCE);
-					kill(0, sig);
-				}
-			}
-		}
-		if (shf)
-			shf_close(shf);
-		reclaim();
-		exit(exstat);
-	}
-	if (shf)
-		shf_close(shf);
-	reclaim();
-
-	e = e->oenv;
-	afree(ep, ATEMP);
-}
-
-/* Called after a fork to cleanup stuff left over from parents environment */
-void
-cleanup_parents_env(void)
-{
-	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
-	 * anywhere.
-	 */
-
-	/* 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]);
-			afree(ep->savefd, &ep->area);
-			ep->savefd = (short *) 0;
-		}
-	}
-	e->oenv = (struct env *) 0;
-}
-
-/* Called just before an execve cleanup stuff temporary files */
-void
-cleanup_proc_env(void)
-{
-	struct env *ep;
-
-	for (ep = e; ep; ep = ep->oenv)
-		remove_temps(ep->temps);
-}
-
-/* remove temp files and free ATEMP Area */
-static void
-reclaim(void)
-{
-	remove_temps(e->temps);
-	e->temps = NULL;
-	afreeall(&e->area);
-}
-
-static void
-remove_temps(struct temp *tp)
-{
-
-	for (; tp != NULL; tp = tp->next)
-		if (tp->pid == procpid) {
-			unlink(tp->name);
-		}
-}
-
-/* Returns true if name refers to a restricted shell */
-static int
-is_restricted(char *name)
-{
-	char *p;
-
-	if ((p = strrchr(name, '/')))
-		name = p;
-	/* accepts rsh, rksh, rpdksh, pdrksh, etc. */
-	return (p = strchr(name, 'r')) && strstr(p, "sh");
-}
--- bin/ksh/tty.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/tty.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: tty.c,v 1.9 2006/03/14 22:08:01 deraadt Exp $	*/
-
-#include "sh.h"
-#include <sys/stat.h>
-#define EXTERN
-#include "tty.h"
-#undef EXTERN
-
-/* Initialize tty_fd.  Used for saving/reseting tty modes upon
- * foreground job completion and for setting up tty process group.
- */
-void
-tty_init(int init_ttystate)
-{
-	int	do_close = 1;
-	int	tfd;
-
-	if (tty_fd >= 0) {
-		close(tty_fd);
-		tty_fd = -1;
-	}
-	tty_devtty = 1;
-
-	if ((tfd = open("/dev/tty", O_RDWR, 0)) < 0) {
-		tty_devtty = 0;
-		warningf(false, "No controlling tty (open /dev/tty: %s)",
-		    strerror(errno));
-	}
-
-	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 = fcntl(tfd, F_DUPFD, FDBASE)) < 0) {
-		warningf(false, "j_ttyinit: dup of tty fd failed: %s",
-		    strerror(errno));
-	} else if (fcntl(tty_fd, F_SETFD, FD_CLOEXEC) < 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)
-		tcgetattr(tty_fd, &tty_state);
-	if (do_close)
-		close(tfd);
-}
-
-void
-tty_close(void)
-{
-	if (tty_fd >= 0) {
-		close(tty_fd);
-		tty_fd = -1;
-	}
-}
--- bin/ksh/proto.h
+++ /dev/null
@@ -1,267 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/proto.h,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: proto.h,v 1.30 2006/03/17 16:30:13 millert 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(Area *);
-void	afreeall(Area *);
-void *	alloc(size_t, Area *);
-void *	aresize(void *, size_t, Area *);
-void	afree(void *, Area *);
-/* c_ksh.c */
-int	c_hash(char **);
-int	c_cd(char **);
-int	c_pwd(char **);
-int	c_print(char **);
-int	c_whence(char **);
-int	c_command(char **);
-int	c_typeset(char **);
-int	c_alias(char **);
-int	c_unalias(char **);
-int	c_let(char **);
-int	c_jobs(char **);
-int	c_fgbg(char **);
-int	c_kill(char **);
-void	getopts_reset(int);
-int	c_getopts(char **);
-int	c_bind(char **);
-/* c_sh.c */
-int	c_label(char **);
-int	c_shift(char **);
-int	c_umask(char **);
-int	c_dot(char **);
-int	c_wait(char **);
-int	c_read(char **);
-int	c_eval(char **);
-int	c_trap(char **);
-int	c_brkcont(char **);
-int	c_exitreturn(char **);
-int	c_set(char **);
-int	c_unset(char **);
-int	c_ulimit(char **);
-int	c_times(char **);
-int	timex(struct op *, int);
-void	timex_hook(struct op *, char ** volatile *);
-int	c_exec(char **);
-int	c_builtin(char **);
-/* c_test.c */
-int	c_test(char **);
-/* edit.c: most prototypes in edit.h */
-void	x_init(void);
-int	x_read(char *, size_t);
-void	set_editmode(const char *);
-/* emacs.c: most prototypes in edit.h */
-int	x_bind(const char *, const char *, int, int);
-/* eval.c */
-char *	substitute(const char *, int);
-char **	eval(char **, int);
-char *	evalstr(char *cp, int);
-char *	evalonestr(char *cp, int);
-char	*debunk(char *, const char *, size_t);
-void	expand(char *, XPtrV *, int);
-int	glob_str(char *, XPtrV *, int);
-/* exec.c */
-int	execute(struct op * volatile, volatile int);
-int	shcomexec(char **);
-struct tbl * findfunc(const char *, unsigned int, int);
-int	define(const char *, struct op *);
-void	builtin(const char *, int (*)(char **));
-struct tbl *	findcom(const char *, int);
-void	flushcom(int);
-char *	search(const char *, const char *, int, int *);
-int	search_access(const char *, int, int *);
-int	pr_menu(char *const *);
-int	pr_list(char *const *);
-/* expr.c */
-int	evaluate(const char *, long *, int, bool);
-int	v_evaluate(struct tbl *, const char *, volatile int, bool);
-/* history.c */
-void	init_histvec(void);
-void	hist_init(Source *);
-void	hist_finish(void);
-void	histsave(int, const char *, int);
-#ifdef HISTORY
-int	c_fc(char **);
-void	sethistsize(int);
-void	sethistfile(const char *);
-char **	histpos(void);
-int	histnum(int);
-int	findhist(int, int, const char *, int);
-int	findhistrel(const char *);
-char  **hist_get_newest(int);
-
-#endif /* HISTORY */
-/* io.c */
-void	errorf(const char *, ...)
-	    __attribute__((__noreturn__, __format__ (printf, 1, 2)));
-void	warningf(int, const char *, ...)
-	    __attribute__((__format__ (printf, 2, 3)));
-void	bi_errorf(const char *, ...)
-	    __attribute__((__format__ (printf, 1, 2)));
-void	internal_errorf(int, const char *, ...)
-	    __attribute__((__format__ (printf, 2, 3)));
-void	error_prefix(int);
-void	shellf(const char *, ...)
-	    __attribute__((__format__ (printf, 1, 2)));
-void	shprintf(const char *, ...)
-	    __attribute__((__format__ (printf, 1, 2)));
-#ifdef KSH_DEBUG
-void	kshdebug_init_(void);
-void	kshdebug_printf_(const char *, ...)
-	    __attribute__((__format__ (printf, 1, 2)));
-void	kshdebug_dump_(const char *, const void *, int);
-#endif /* KSH_DEBUG */
-int	can_seek(int);
-void	initio(void);
-int	ksh_dup2(int, int, int);
-int	savefd(int);
-void	restfd(int, int);
-void	openpipe(int *);
-void	closepipe(int *);
-int	check_fd(char *, int, const char **);
-void	coproc_init(void);
-void	coproc_read_close(int);
-void	coproc_readw_close(int);
-void	coproc_write_close(int);
-int	coproc_getfd(int, const char **);
-void	coproc_cleanup(int);
-struct temp *maketemp(Area *, Temp_type, struct temp **);
-/* jobs.c */
-void	j_init(int);
-void	j_exit(void);
-void	j_change(void);
-int	exchild(struct op *, int, int);
-void	startlast(void);
-int	waitlast(void);
-int	waitfor(const char *, int *);
-int	j_kill(const char *, int);
-int	j_resume(const char *, int);
-int	j_jobs(const char *, int, int);
-int	j_njobs(void);
-void	j_notify(void);
-pid_t	j_async(void);
-int	j_stopped_running(void);
-/* lex.c */
-int	yylex(int);
-void	yyerror(const char *, ...)
-	    __attribute__((__noreturn__, __format__ (printf, 1, 2)));
-Source * pushs(int, Area *);
-void	set_prompt(int, Source *);
-void	pprompt(const char *, int);
-/* mail.c */
-void	mcheck(void);
-void	mcset(long);
-void	mbset(char *);
-void	mpset(char *);
-/* main.c */
-int	include(const char *, int, char **, int);
-int	command(const char *);
-int	shell(Source *volatile, int volatile);
-void	unwind(int) __attribute__((__noreturn__));
-void	newenv(int);
-void	quitenv(struct shf *);
-void	cleanup_parents_env(void);
-void	cleanup_proc_env(void);
-/* misc.c */
-void	setctypes(const char *, int);
-void	initctypes(void);
-char *	ulton(unsigned long, int);
-char *	str_save(const char *, Area *);
-char *	str_nsave(const char *, int, Area *);
-int	option(const char *);
-char *	getoptions(void);
-void	change_flag(enum sh_flag, int, int);
-int	parse_args(char **, int, int *);
-int	getn(const char *, int *);
-int	bi_getn(const char *, int *);
-int	gmatch(const char *, const char *, int);
-int	has_globbing(const char *, const char *);
-const unsigned char *pat_scan(const unsigned char *, const unsigned char *,
-    int);
-void	qsortp(void **, size_t, int (*)(void *, void *));
-int	xstrcmp(void *, void *);
-void	ksh_getopt_reset(Getopt *, int);
-int	ksh_getopt(char **, Getopt *, const char *);
-void	print_value_quoted(const char *);
-void	print_columns(struct shf *, int, char *(*)(void *, int, char *, int),
-    void *, int, int prefcol);
-int	strip_nuls(char *, int);
-int	blocking_read(int, char *, int);
-int	reset_nonblock(int);
-char	*ksh_get_wd(char *, int);
-/* mknod.c */
-int domknod(int, char **, mode_t);
-int domkfifo(int, char **, mode_t);
-/* path.c */
-int	make_path(const char *, const char *, char **, XString *, int *);
-void	simplify_path(char *);
-char	*get_phys_path(const char *);
-void	set_current_wd(char *);
-/* syn.c */
-void	initkeywords(void);
-struct op * compile(Source *);
-/* table.c */
-unsigned int	hash(const char *);
-void		ktinit(struct table *, Area *, int);
-struct tbl *	ktsearch(struct table *, const char *, unsigned int);
-struct tbl *	ktenter(struct table *, const char *, unsigned int);
-void		ktdelete(struct tbl *);
-void		ktwalk(struct tstate *, struct table *);
-struct tbl *	ktnext(struct tstate *);
-struct tbl **	ktsort(struct table *);
-/* trace.c */
-/* trap.c */
-void	inittraps(void);
-void	alarm_init(void);
-Trap *	gettrap(const char *, int);
-void	trapsig(int);
-void	intrcheck(void);
-int	fatal_trap_check(void);
-int	trap_pending(void);
-void	runtraps(int intr);
-void	runtrap(Trap *);
-void	cleartraps(void);
-void	restoresigs(void);
-void	settrap(Trap *, char *);
-int	block_pipe(void);
-void	restore_pipe(int);
-int	setsig(Trap *, sig_t, int);
-void	setexecsig(Trap *, int);
-/* tree.c */
-int	fptreef(struct shf *, int, const char *, ...);
-char *	snptreef(char *, int, const char *, ...);
-struct op *	tcopy(struct op *, Area *);
-char *	wdcopy(const char *, Area *);
-char *	wdscan(const char *, int);
-char *	wdstrip(const char *);
-void	tfree(struct op *, Area *);
-/* var.c */
-void	newblock(void);
-void	popblock(void);
-void	initvar(void);
-struct tbl *	global(const char *);
-struct tbl *	local(const char *, bool);
-char *	str_val(struct tbl *);
-long	intval(struct tbl *);
-int	setstr(struct tbl *, const char *, int);
-struct tbl *setint_v(struct tbl *, struct tbl *, bool);
-void	setint(struct tbl *, long);
-int	getint(struct tbl *, long *, bool);
-struct tbl *	typeset(const char *, Tflag, Tflag, int, int);
-void	unset(struct tbl *, int);
-char  * skip_varname(const char *, int);
-char	*skip_wdvarname(const char *, int);
-int	is_wdvarname(const char *, int);
-int	is_wdvarassign(const char *);
-char **	makenv(void);
-void	change_random(void);
-int	array_ref_len(const char *);
-char *	arrayname(const char *);
-void    set_array(const char *, int, char **);
-/* version.c */
-/* vi.c: see edit.h */
--- bin/ksh/history.c
+++ /dev/null
@@ -1,983 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/history.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: history.c,v 1.35 2006/05/29 18:22:24 otto Exp $	*/
-
-/*
- * command history
- *
- * only implements in-memory history.
- */
-
-/*
- *	This file contains
- *	a)	the original in-memory history  mechanism
- *	b)	a more complicated mechanism done by  pc at 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 <sys/stat.h>
-
-#ifdef HISTORY
-# 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(unsigned char *, int);
-static int hist_shrink(unsigned char *, int);
-static unsigned char *hist_skip_back(unsigned char *,int *,int);
-static void histload(Source *, unsigned char *, int);
-static void histinsert(Source *, int, unsigned char *);
-static void writehistfile(int, char *);
-static int sprinkle(int);
-
-static int	hist_execute(char *);
-static int	hist_replace(char **, const char *, const char *, int);
-static char   **hist_get(const char *, int, int);
-static char   **hist_get_oldest(void);
-static void	histbackup(void);
-
-static char   **current;	/* current position 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(char **wp)
-{
-	struct shf *shf;
-	struct temp *tf = NULL;
-	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;
-
-	if (!Flag(FTALKING_I)) {
-		bi_errorf("history functions not available");
-		return 1;
-	}
-
-	while ((optc = ksh_getopt(wp, &builtin_opt,
-	    "e:glnrs0,1,2,3,4,5,6,7,8,9,")) != -1)
-		switch (optc) {
-		case 'e':
-			p = builtin_opt.optarg;
-			if (strcmp(p, "-") == 0)
-				sflag++;
-			else {
-				size_t len = strlen(p) + 4;
-				editor = str_nsave(p, len, ATEMP);
-				strlcat(editor, " $_", len);
-			}
-			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, TT_HIST_EDIT, &e->temps);
-	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;
-	}
-
-	/* Ignore setstr errors here (arbitrary) */
-	setstr(local("_", false), tf->name, KSH_RETURN_ERROR);
-
-	/* 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(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;
-		}
-		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(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(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 */
-char **
-hist_get_newest(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(void)
-{
-	if (histptr <= history) {
-		bi_errorf("no history (yet)");
-		return (char **) 0;
-	}
-	return history;
-}
-
-/******************************/
-/* Back up over last histsave */
-/******************************/
-static void
-histbackup(void)
-{
-	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(void)
-{
-	return current;
-}
-
-int
-histnum(int n)
-{
-	int	last = histptr - history;
-
-	if (n < 0 || n >= last) {
-		current = histptr;
-		return last;
-	} else {
-		current = &history[n];
-		return n;
-	}
-}
-
-/*
- * This will become unnecessary if hist_get is modified to allow
- * searching from positions other than the end, and in either
- * direction.
- */
-int
-findhist(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;
-}
-
-int
-findhistrel(const char *str)
-{
-	int	maxhist = histptr - history;
-	int	start = maxhist - 1;
-	int	rec = atoi(str);
-
-	if (rec == 0)
-		return -1;
-	if (rec > 0) {
-		if (rec > maxhist)
-			return -1;
-		return rec - 1;
-	}
-	if (rec > maxhist)
-		return -1;
-	return start + rec + 1;
-}
-
-/*
- *	set history
- *	this means reallocating the dataspace
- */
-void
-sethistsize(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(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
-	 */
-	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;
-	}
-
-	hist_init(hist_source);
-}
-
-/*
- *	initialise the history vector
- */
-void
-init_histvec(void)
-{
-	if (history == (char **)NULL) {
-		histsize = HISTORYSIZE;
-		history = (char **)alloc(histsize*sizeof (char *), APERM);
-		histptr = history - 1;
-	}
-}
-
-
-/*
- *	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(int lno, const char *cmd, int dowrite)
-{
-	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(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);
-	if (histfd != fd)
-		close(fd);
-
-	(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_FILE|MAP_PRIVATE, histfd, 0);
-		/*
-		 * check on its validity
-		 */
-		if (base == MAP_FAILED || *base != HMAGIC1 || base[1] != HMAGIC2) {
-			if (base != MAP_FAILED)
-				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(unsigned char *base, int bytes)
-{
-	State state = shdr;
-	int 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(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 = open(nfile, O_CREAT | O_TRUNC | O_WRONLY, 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(unsigned char *base, int *bytes, int no)
-{
-	int lines = 0;
-	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(Source *s, unsigned char *base, int bytes)
-{
-	State state;
-	int	lno = 0;
-	unsigned char	*line = NULL;
-
-	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;
-					s->cmd_offset = lno;
-					histsave(lno, (char *)line, 0);
-				}
-				state = shdr;
-			}
-		}
-	}
-}
-
-/*
- *	Insert a line into the history at a specified number
- */
-static void
-histinsert(Source *s, int lno, unsigned char *line)
-{
-	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(int lno, char *cmd)
-{
-	int	sizenow;
-	unsigned char	*base;
-	unsigned char	*new;
-	int	bytes;
-	unsigned 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_FILE|MAP_PRIVATE, histfd, 0);
-			if (base == MAP_FAILED)
-				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)
-{
-	(void) flock(histfd, LOCK_UN);
-	(void) close(histfd);
-	histfd = 0;
-}
-
-/*
- *	add magic to the history file
- */
-static int
-sprinkle(int fd)
-{
-	static unsigned char mag[] = { HMAGIC1, HMAGIC2 };
-
-	return(write(fd, mag, 2) != 2);
-}
-
-#else /* HISTORY */
-
-/* No history to be compiled in: dummy routines to avoid lots more ifdefs */
-void
-init_histvec(void)
-{
-}
-void
-hist_init(Source *s)
-{
-}
-void
-hist_finish(void)
-{
-}
-void
-histsave(int lno, const char *cmd, int dowrite)
-{
-	errorf("history not enabled");
-}
-#endif /* HISTORY */
--- bin/ksh/tty.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/tty.h,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto 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
-
-#include <termios.h>
-
-EXTERN int		tty_fd I__(-1);	/* dup'd tty file descriptor */
-EXTERN int		tty_devtty;	/* true if tty_fd is from /dev/tty */
-EXTERN struct termios	tty_state;	/* saved tty state */
-
-extern void	tty_init(int);
-extern void	tty_close(void);
-
-/* be sure not to interfere with anyone else's idea about EXTERN */
-#ifdef EXTERN_DEFINED
-# undef EXTERN_DEFINED
-# undef EXTERN
-#endif
-#undef I__
--- bin/ksh/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
-#	$MidnightBSD: src/bin/ksh/Makefile,v 1.5 2006/08/20 23:01:33 adam Exp $
-#	$OpenBSD: Makefile,v 1.25 2005/10/06 06:39:35 otto Exp $
-
-PROG=	ksh
-INSTALLFLAGS= -S
-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 mknod.c \
-	misc.c path.c shf.c syn.c table.c trap.c tree.c tty.c var.c \
-	version.c vi.c
-
-DEFS=	-Wall -ansi -pedantic -std=c99
-CFLAGS+=${DEFS} -I. -I${.CURDIR}
-LDFLAGS+=-static
-WARNS?=	3
-NO_WERROR=yes
-MAN=	ksh.1 
-
-CLEANFILES+=	emacs.out
-
-LINKS=	${BINDIR}/ksh ${BINDIR}/rksh
-MLINKS=	ksh.1 rksh.1 ksh.1 ulimit.1
-
-.depend emacs.o: emacs.out
-
-emacs.out: emacs.c
-	/bin/sh ${.CURDIR}/emacs-gen.sh ${.CURDIR}/emacs.c > emacs.out
-
-check test:
-	/usr/bin/perl ${.CURDIR}/tests/th -s ${.CURDIR}/tests -p ./ksh -C \
-	    pdksh,sh,ksh,posix,posix-upu
-
-.include <bsd.prog.mk>
-
--- bin/ksh/trap.c
+++ /dev/null
@@ -1,421 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/trap.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: trap.c,v 1.22 2005/03/30 17:16:37 deraadt Exp $	*/
-
-/*
- * signal handling
- */
-
-#include "sh.h"
-
-Trap sigtraps[NSIG + 1];
-
-static struct sigaction Sigact_ign, Sigact_trap;
-
-void
-inittraps(void)
-{
-	int	i;
-
-	/* Populate sigtraps based on sys_signame and sys_siglist. */
-	for (i = 0; i <= NSIG; i++) {
-		sigtraps[i].signal = i;
-		if (i == SIGERR_) {
-			sigtraps[i].name = "ERR";
-			sigtraps[i].mess = "Error handler";
-		} else {
-			sigtraps[i].name = sys_signame[i];
-			sigtraps[i].mess = sys_siglist[i];
-		}
-	}
-	sigtraps[SIGEXIT_].name = "EXIT";	/* our name for signal 0 */
-
-	sigemptyset(&Sigact_ign.sa_mask);
-	Sigact_ign.sa_flags = 0; /* interruptible */
-	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 temporary 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);
-}
-
-static void alarm_catcher(int sig);
-
-void
-alarm_init(void)
-{
-	sigtraps[SIGALRM].flags |= TF_SHELL_USES;
-	setsig(&sigtraps[SIGALRM], alarm_catcher,
-		SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
-}
-
-/* ARGSUSED */
-static void
-alarm_catcher(int sig)
-{
-	int errno_ = errno;
-
-	if (ksh_tmout_state == TMOUT_READING) {
-		int left = alarm(0);
-
-		if (left == 0) {
-			ksh_tmout_state = TMOUT_LEAVING;
-			intrsig = 1;
-		} else
-			alarm(left);
-	}
-	errno = errno_;
-}
-
-Trap *
-gettrap(const char *name, int igncase)
-{
-	int i;
-	Trap *p;
-
-	if (digit(*name)) {
-		int n;
-
-		if (getn(name, &n) && 0 <= n && n < NSIG)
-			return &sigtraps[n];
-		return NULL;
-	}
-	for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
-		if (p->name) {
-			if (igncase) {
-				if (p->name && (!strcasecmp(p->name, name) ||
-				    (strlen(name) > 3 && !strncasecmp("SIG",
-				    p->name, 3) &&
-				    !strcasecmp(p->name, name + 3))))
-					return p;
-			} else {
-				if (p->name && (!strcmp(p->name, name) ||
-				    (strlen(name) > 3 && !strncmp("SIG",
-				    p->name, 3) && !strcmp(p->name, name + 3))))
-					return p;
-			}
-		}
-	return NULL;
-}
-
-/*
- * trap signal handler
- */
-void
-trapsig(int i)
-{
-	Trap *p = &sigtraps[i];
-	int 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);
-	errno = errno_;
-}
-
-/* called when we want to allow the user to ^C out of something - won't
- * work if user has trapped SIGINT.
- */
-void
-intrcheck(void)
-{
-	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(void)
-{
-	int i;
-	Trap *p;
-
-	/* todo: should check if signal is fatal, not the TF_DFL_INTR flag */
-	for (p = sigtraps, i = NSIG+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
- * occurred for which a trap has been set or for which the TF_DFL_INTR flag
- * is set.
- */
-int
-trap_pending(void)
-{
-	int i;
-	Trap *p;
-
-	for (p = sigtraps, i = NSIG+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(int flag)
-{
-	int i;
-	Trap *p;
-
-	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;
-	if (!flag)
-		trap = 0;
-	if (flag & TF_DFL_INTR)
-		intrsig = 0;
-	if (flag & TF_FATAL)
-		fatal_trap = 0;
-	for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
-		if (p->set && (!flag ||
-		    ((p->flags & flag) && p->trap == (char *) 0)))
-			runtrap(p);
-}
-
-void
-runtrap(Trap *p)
-{
-	int	i = p->signal;
-	char	*trapstr = p->trap;
-	int	oexstat;
-	int	old_changed = 0;
-
-	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;
-	/* Note: trapstr is fully parsed before anything is executed, thus
-	 * no problem with afree(p->trap) in settrap() while still in use.
-	 */
-	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(void)
-{
-	int i;
-	Trap *p;
-
-	trap = 0;
-	intrsig = 0;
-	fatal_trap = 0;
-	for (i = NSIG+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(void)
-{
-	int i;
-	Trap *p;
-
-	for (i = NSIG+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(Trap *p, char *s)
-{
-	sig_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(void)
-{
-	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(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(Trap *p, sig_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 = NULL;
-	if (flags & SS_SHTRAP) {
-		p->shtrap = f;
-		f = trapsig;
-	}
-
-	if (p->cursig != f) {
-		p->cursig = f;
-		sigemptyset(&sigact.sa_mask);
-		sigact.sa_flags = 0 /* interruptible */;
-		sigact.sa_handler = f;
-		sigaction(p->signal, &sigact, (struct sigaction *) 0);
-	}
-
-	return 1;
-}
-
-/* control what signal is set to before an exec() */
-void
-setexecsig(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;
-	}
-}
--- bin/ksh/emacs-gen.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/sh
-#	$OpenBSD: emacs-gen.sh,v 1.2 2004/12/18 20:55:52 millert 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 (int c);\n", fname;
-			nfunc++;
-		}
-	    }' || exit 1
-
-exit 0
--- bin/ksh/CONTRIBUTORS
+++ /dev/null
@@ -1,130 +0,0 @@
-$MidnightBSD: src/bin/ksh/CONTRIBUTORS,v 1.2 2007/07/26 20:13:00 laffer1 Exp $
-$OpenBSD: CONTRIBUTORS,v 1.10 2006/02/06 16:47:07 jmc 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 at 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 at sq.sq.com)
-      takes over as maintainer
-      dates?
-      Released versions: 3.3 (?)
-    * Simon J. Gerraty (sjg at zen.void.oz.au) takes over as maintainer
-      Nov '91..July '94 ?
-      Released versions: 4.0 .. 4.9
-    * Michael Rendell (michael at 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 at sq.sq.com), ?:
-      cleaned up configuration, many bug fixes (see misc/Changes.jrm).
-    * Simon Gerraty, (sjg at 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 at 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 at 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 at cs.mun.ca), '87: wrote vi command line editor; various
-      bug fixes/enhancements.
-    * Jeff Sparkes (jsparkes at bnr.ca), Mar '89..Mar '90: added arrays,
-      merged John Rochester's vi code into pdksh, misc bug fixes.
-    * Michael Haardt (u31b3hs at POOL.Informatik.RWTH-Aachen.DE), Sept '94:
-      organized man page, filled in many of its copious blank spots; added
-      KSH ifdefs.
-    * Dale DePriest (daled at cadence.com): ported to OS/2 (initially based on
-      port of pdksh4.9 to OS/2 by Kai Rommel (rommel at ars.muc.de)); maintains
-      OS/2 port; misc bug fixes.
-
-Other contributors:
-    * Piercarlo Grandi (pcg at aber.ac.uk), Dec '93: fixes for linux port
-    * Neil Smithline (Neil.Smithline at eng.sun.com), Aug '92: emacs-style
-      filename completion.
-    * Mike Jetzer [mlj] (jetzer at 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 at demon.co.uk), ?: promptlen() function.
-    * J.T. Conklin (jtc at cygnus.com): POSIXized test builtin; miscellaneous
-      fixes/enhancements.
-    * Sean Hogan (sean at neweast.ca): fixes for ICS 3.0 Unix, found and helped
-      fix numerous problems.
-    * Gordan Larson (hoh at approve.se): fix to compile sans VI, ksh.1 typo.
-    * Thomas Gellekum (thomas at ghpc8.ihf.rwth-aachen.de): fixes for Makefile
-      typos, fixed CLK_TCK for FreeBSD, man page fixes.
-    * Ed Ferguson (Ed.Ferguson at dseg.ti.com): fix to compile sans VI.
-    * Brian Campbell (brianc at qnx.com): fixes to compile under QNX and
-      to compile with dmake.
-    * (guy at netapp.com), Oct '94: patch to use gmacs flag.
-    * Andrew Moore (alm at netcom.com): reported many bugs, fixes.
-    * William Bader (wbader at CSEE.Lehigh.Edu): fix to compile on SCO Unix
-      (struct winsize).
-    * Mike Long (mike.long at analog.com): makefile fix - use $manext, not 1.
-    * Art Mills (aem at hpbs9162.bio.hp.com): bug fix for vi file completion in
-      command mode.
-    * Tory Bollinger (tboll at authstin.ibm.com): allow ~ in vi mode to take
-      a count.
-    * Frank Edwards (<crash at azhrei.EEC.COM>): added macros to vi (@char).
-    * Fritz Heinrichmeyer (<Fritz.Heinrichmeyer at FernUni-Hagen.de>): fixes
-      to allow compile under Linux 1.4.3.
-    * Gabor Zahemszky (<zgabor at CoDe.hu>): SVR3_PGRP vs SYSV_PGRP, many
-      bug reports and man page fixes.
-    * Dave Kinchlea (<kinch at julian.uwo.ca>): DEFAULT_ENV patches.
-    * Paul Borman (<prb at bsdi.com>): j_exit: send HUP, then CONT; HUP fg process.
-    * DaviD W. Sanderson (<dws at ssec.wisc.edu>): patches to allow { .. } instead
-      of in .. esac in case statements.
-    * ? (<ra at rhi.hi.is>): partial patches to handle SIGWINCH for command line
-      editing.
-    * Jason Tyler (<jason at nc.bhpese.oz.au>): fixes for bugs in fc.
-    * Stefan Dalibor (<Stefan.Dalibor at informatik.uni-erlangen.de>): fix for
-      COLUMNS never being set in x_init().
-    * Arnon Kanfi (<arnon at gilly.datatools.com>): fix for prompt.
-    * Marc Olzheim (<marcolz at stack.nl>): patches to ifdef KSH the mail check
-      code and aliases; enum patches for old K&R compilers; handle missing dup2.
-    * Lars Hecking (<lhecking at nmrc.ucc.ie>): fixes so shell compiles as sh
-      again.
-    * Bill Kish (<kish at browncow.com>): added prompt delimiter hack for
-      hidden characters (eg, escape codes).
-    * Andrew S. Townley (<atownley at informix.com>): fixes for NeXT machines:
-      get a controlling if one needed, use correct profile.
-    * Eric J. Chet (<ejc at bazzle.com>): fix for core dump in . (quitenv() called
-      too soon).
-    * Greg A. Woods <woods at most.weird.com>: fix to make ^[_ in emacs work
-      as in at&t ksh.
-    * George Robbins <grr at shandakor.tharsis.com>: fix for sh mode to
-      keep exec'd file descriptors open.
-    * George White <gwhite at bodnext.bio.dfo.ca>: fix here-doc problem under OS/2
-      (memory allocated incorrectly).
-    * David E. Wexelblat <dwex at DataFocus.com>: fix to avoid memory overrun
-      in aresize(); fix to not print un-named options.
-    * Clifford Wolf (<clifford at clifford.at>): fix memory overrun in aresize();
-      fixed sys_siglist[] problem.
-    * Theo de Raadt (<deraadt at cvs.openbsd.org>): allow ". /dev/null".
-    * Eric Youngdale (<ericy at datafocus.com>): flag field incorrectly changed
-      in exec.c(flushcom).
-    * Todd. C Miller (Todd C. Miller <Todd.Miller at courtesan.com>): fix
-      for coredump in jobs.
-    * Kevin Schoedel <schoedel at kw.igs.net>: fix for word location in file
-      completion.
-    * Martin Lucina <mato at kotelna.sk>: fix for argument parsing in exit command,
-      fix for KSH_CHECK_H_TYPE.
-    * Mark Funkenhauser <mark at interix.com>: added $LINENO support.
-    * Corinna Vinschen <Corinna at Vinschen.de> and Steven Hein <ssh at sgi.com>:
-      port to cyngin environment on win95/winnt.
-    * Martin Dalecki <dalecki at cs.net.pl>: changes for 8 bit emacs mode.
-    * Dave Hillman <daveh at gte.net>: patch for bug in test -nt.
--- bin/ksh/c_test.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/c_test.h,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $	*/
-
-/* Various types of operations.  Keeping things grouped nicely
- * (unary,binary) makes switch() statements more efficient.
- */
-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)(Test_env *, Test_meta);
-	const char *(*getopnd) (Test_env *, Test_op, int);
-	int	(*eval)(Test_env *, Test_op, const char *, const char *, int);
-	void	(*error)(Test_env *, int, const char *);
-};
-
-Test_op	test_isop(Test_env *, Test_meta, const char *);
-int     test_eval(Test_env *, Test_op, const char *, const char *, int);
-int	test_parse(Test_env *);
--- bin/ksh/path.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/path.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: path.c,v 1.12 2005/03/30 17:16:37 deraadt Exp $	*/
-
-#include "sh.h"
-#include <sys/stat.h>
-
-/*
- *	Contains a routine to search a : separated list of
- *	paths (a la CDPATH) and make appropriate file names.
- *	Also contains a routine to simplify .'s and ..'s out of
- *	a path name.
- *
- *	Larry Bouzane (larry at cs.mun.ca)
- */
-
-static char	*do_phys_path(XString *, char *, const char *);
-
-/*
- *	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 appended to result.
- */
-int
-make_path(const char *cwd, const char *file,
-    char **cdpathp,		/* & of : separated 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 (file[0] == '/') {
-		*phys_pathp = 0;
-		use_cdpath = 0;
-	} else {
-		if (file[0] == '.') {
-			char c = file[1];
-
-			if (c == '.')
-				c = file[2];
-			if (c == '/' || c == '\0')
-				use_cdpath = 0;
-		}
-
-		plist = *cdpathp;
-		if (!plist)
-			use_cdpath = 0;
-		else if (use_cdpath) {
-			char *pend;
-
-			for (pend = plist; *pend && *pend != ':'; pend++)
-				;
-			plen = pend - plist;
-			*cdpathp = *pend ? ++pend : (char *) 0;
-		}
-
-		if ((use_cdpath == 0 || !plen || plist[0] != '/') &&
-		    (cwd && *cwd)) {
-			len = strlen(cwd);
-			XcheckN(*xsp, xp, len);
-			memcpy(xp, cwd, len);
-			xp += len;
-			if (cwd[len - 1] != '/')
-				Xput(*xsp, xp, '/');
-		}
-		*phys_pathp = Xlength(*xsp, xp);
-		if (use_cdpath && plen) {
-			XcheckN(*xsp, xp, plen);
-			memcpy(xp, plist, plen);
-			xp += plen;
-			if (plist[plen - 1] != '/')
-				Xput(*xsp, xp, '/');
-			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(char *path)
-{
-	char	*cur;
-	char	*t;
-	int	isrooted;
-	char	*very_start = path;
-	char	*start;
-
-	if (!*path)
-		return;
-
-	if ((isrooted = path[0] == '/'))
-		very_start++;
-
-	/* Before			After
-	 *  /foo/			/foo
-	 *  /foo/../../bar		/bar
-	 *  /foo/./blah/..		/foo
-	 *  .				.
-	 *  ..				..
-	 *  ./foo			foo
-	 *  foo/../../../bar		../../bar
-	 */
-
-	for (cur = t = start = very_start; ; ) {
-		/* treat multiple '/'s as one '/' */
-		while (*t == '/')
-			t++;
-
-		if (*t == '\0') {
-			if (cur == path)
-				/* convert empty path to dot */
-				*cur++ = '.';
-			*cur = '\0';
-			break;
-		}
-
-		if (t[0] == '.') {
-			if (!t[1] || t[1] == '/') {
-				t += 1;
-				continue;
-			} else if (t[1] == '.' && (!t[2] || t[2] == '/')) {
-				if (!isrooted && cur == start) {
-					if (cur != very_start)
-						*cur++ = '/';
-					*cur++ = '.';
-					*cur++ = '.';
-					start = cur;
-				} else if (cur != start)
-					while (--cur > start && *cur != '/')
-						;
-				t += 2;
-				continue;
-			}
-		}
-
-		if (cur != very_start)
-			*cur++ = '/';
-
-		/* find/copy next component of pathname */
-		while (*t && *t != '/')
-			*cur++ = *t++;
-	}
-}
-
-
-void
-set_current_wd(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);
-}
-
-char *
-get_phys_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, '/');
-	Xput(xs, xp, '\0');
-
-	return Xclose(xs, xp);
-}
-
-static char *
-do_phys_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 (*p == '/')
-			p++;
-		if (!*p)
-			break;
-		len = (q = strchr(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 (*xp == '/')
-					break;
-			}
-			continue;
-		}
-
-		savepos = Xsavepos(*xsp, xp);
-		Xput(*xsp, xp, '/');
-		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 = lbuf[0] == '/' ? Xstring(*xsp, xp) :
-		    Xrestpos(*xsp, xp, savepos);
-		if (!(xp = do_phys_path(xsp, xp, lbuf)))
-			return (char *) 0;
-	}
-	return xp;
-}
-
-#ifdef	TEST
-
-int
-main(void)
-{
-	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 */
--- bin/ksh/mknod.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/mknod.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: mknod.c,v 1.1 2005/10/06 06:39:36 otto Exp $	*/
-/*	$NetBSD: mknod.c,v 1.8 1995/08/11 00:08:18 jtc Exp $	*/
-
-/*
- * Copyright (c) 1989, 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kevin Fall.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static const char copyright[] =
-"@(#) Copyright (c) 1989, 1993\n\
-	The Regents of the University of California.  All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)mknod.c	8.1 (Berkeley) 6/5/93";
-#else
-static const char rcsid[] = "$OpenBSD: mknod.c,v 1.1 2005/10/06 06:39:36 otto Exp $";
-#endif
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-#include "sh.h"
-
-int
-domknod(int argc, char **argv, mode_t mode)
-{
-	dev_t dev;
-	char *endp;
-	u_int major, minor;
-
-	if (argv[1][0] == 'c')
-		mode |= S_IFCHR;
-	else if (argv[1][0] == 'b')
-		mode |= S_IFBLK;
-	else {
-		bi_errorf("node must be type 'b' or 'c'.");
-		return 1;
-	}
-
-	major = (long)strtoul(argv[2], &endp, 0);
-	if (endp == argv[2] || *endp != '\0') {
-		bi_errorf("non-numeric major number.");
-		return 1;
-	}
-	minor = (long)strtoul(argv[3], &endp, 0);
-	if (endp == argv[3] || *endp != '\0') {
-		bi_errorf("non-numeric minor number.");
-		return 1;
-	}
-	dev = makedev(major, minor);
-	if (major(dev) != major || minor(dev) != minor) {
-		bi_errorf("major or minor number too large");
-		return 1;
-	}
-	if (mknod(argv[0], mode, dev) < 0) {
-		bi_errorf("%s: %s", argv[0], strerror(errno));
-		return 1;
-	}
-	return 0;
-}
-
-int
-domkfifo(int argc, char **argv, mode_t mode)
-{
-	int rv = 0;
-
-	if (mkfifo(argv[0], mode) < 0) {
-		bi_errorf("%s: %s", argv[0], strerror(errno));
-		rv = 1;
-	}
-	return(rv);
-}
-
--- bin/ksh/PROJECTS
+++ /dev/null
@@ -1,114 +0,0 @@
-$OpenBSD: PROJECTS,v 1.6 2004/12/18 20:55:52 millert 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
-
-      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 time 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 that 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, ident[], heres[], PATH, 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.
-
-	* decide wether to keep currently disabled FP stuff in shf.c; if
-	  not, eliminate ksh_limval.h (moving BITS to var.c).
--- bin/ksh/c_sh.c
+++ /dev/null
@@ -1,932 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/c_sh.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: c_sh.c,v 1.35 2006/04/10 14:38:59 jaredy Exp $	*/
-
-/*
- * built-in Bourne commands
- */
-
-#include "sh.h"
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-static void p_time(struct shf *, int, struct timeval *, int, char *, char *);
-
-/* :, false and true */
-int
-c_label(char **wp)
-{
-	return wp[0][0] == 'f' ? 1 : 0;
-}
-
-int
-c_shift(char **wp)
-{
-	struct block *l = e->loc;
-	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, KSH_UNWIND_ERROR, 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(char **wp)
-{
-	int i;
-	char *cp;
-	int symbolic = 0;
-	mode_t old_umask;
-	int optc;
-
-	while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != -1)
-		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 {
-		mode_t 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(char **wp)
-{
-	char *file, *cp;
-	char **argv;
-	int argc;
-	int i;
-	int err;
-
-	if (ksh_getopt(wp, &builtin_opt, null) == '?')
-		return 1;
-
-	if ((cp = wp[builtin_opt.optind]) == NULL)
-		return 0;
-	file = search(cp, path, R_OK, &err);
-	if (file == NULL) {
-		bi_errorf("%s: %s", cp, err ? strerror(err) : "not found");
-		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(char **wp)
-{
-	int rv = 0;
-	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(char **wp)
-{
-	int c = 0;
-	int expand = 1, history = 0;
-	int expanding;
-	int ecode = 0;
-	char *cp;
-	int fd = 0;
-	struct shf *shf;
-	int optc;
-	const char *emsg;
-	XString cs, xs;
-	struct tbl *vp;
-	char *xp = NULL;
-
-	while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != -1)
-		switch (optc) {
-		case 'p':
-			if ((fd = coproc_getfd(R_OK, &emsg)) < 0) {
-				bi_errorf("-p: %s", emsg);
-				return 1;
-			}
-			break;
-		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);
-		}
-	}
-
-	/* 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 compatible with at&t ksh... the fd is kept so another
-	 * coproc can be started with same output, 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);
-	 */
-
-	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')
-					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_I) && 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);
-		/* Must be done before setting export. */
-		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);
-		if (!setstr(vp, Xstring(cs, cp), KSH_RETURN_ERROR)) {
-		    shf_flush(shf);
-		    return 1;
-		}
-	}
-
-	shf_flush(shf);
-	if (history) {
-		Xput(xs, xp, '\0');
-		source->line++;
-		histsave(source->line, Xstring(xs, xp), 1);
-		Xfree(xs, xp);
-	}
-	/* 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);
-
-	return ecode ? ecode : c == EOF;
-}
-
-int
-c_eval(char **wp)
-{
-	struct source *s;
-
-	if (ksh_getopt(wp, &builtin_opt, null) == '?')
-		return 1;
-	s = pushs(SWORDS, ATEMP);
-	s->u.strv = wp + builtin_opt.optind;
-	if (!Flag(FPOSIX)) {
-		/*
-		 * Handle case where the command is empty due to failed
-		 * command substitution, eg, eval "$(false)".
-		 * In this case, shell() will not set/change exstat (because
-		 * compiled tree is empty), so will use this value.
-		 * subst_exstat is cleared in execute(), so should be 0 if
-		 * there were no substitutions.
-		 *
-		 * A strict reading of POSIX says we don't do this (though
-		 * it is traditionally done). [from 1003.2-1992]
-		 *    3.9.1: Simple Commands
-		 *	... If there is a command name, execution shall
-		 *	continue as described in 3.9.1.1.  If there
-		 *	is no command name, but the command contained a command
-		 *	substitution, the command shall complete with the exit
-		 *	status of the last command substitution
-		 *    3.9.1.1: Command Search and Execution
-		 *	...(1)...(a) If the command name matches the name of
-		 *	a special built-in utility, that special built-in
-		 *	utility shall be invoked.
-		 * 3.14.5: Eval
-		 *	... If there are no arguments, or only null arguments,
-		 *	eval shall return an exit status of zero.
-		 */
-		exstat = subst_exstat;
-	}
-
-	return shell(s, false);
-}
-
-int
-c_trap(char **wp)
-{
-	int i;
-	char *s;
-	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 = NSIG+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 = NSIG+1; --i >= 0; p++)
-				if (p->trap == NULL && p->name)
-					shprintf(" %s", p->name);
-			shprintf(newline);
-		}
-#endif
-		return 0;
-	}
-
-	/*
-	 * Use case sensitive lookup for first arg so the
-	 * command 'exit' isn't confused with the pseudo-signal
-	 * 'EXIT'.
-	 */
-	s = (gettrap(*wp, false) == NULL) ? *wp++ : NULL; /* get command */
-	if (s != NULL && s[0] == '-' && s[1] == '\0')
-		s = NULL;
-
-	/* set/clear traps */
-	while (*wp != NULL) {
-		p = gettrap(*wp++, true);
-		if (p == NULL) {
-			bi_errorf("bad signal %s", wp[-1]);
-			return 1;
-		}
-		settrap(p, s);
-	}
-	return 0;
-}
-
-int
-c_exitreturn(char **wp)
-{
-	int how = LEXIT;
-	int n;
-	char *arg;
-
-	if (ksh_getopt(wp, &builtin_opt, null) == '?')
-		return 1;
-	arg = wp[builtin_opt.optind];
-
-	if (arg) {
-		if (!getn(arg, &n)) {
-			exstat = 1;
-			warningf(true, "%s: bad number", arg);
-		} else
-			exstat = n;
-	}
-	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(NULL);	/* get rid of any i/o redirections */
-	unwind(how);
-	/* NOTREACHED */
-	return 0;
-}
-
-int
-c_brkcont(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(char **wp)
-{
-	int argi, setargs;
-	struct block *l = e->loc;
-	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(char **wp)
-{
-	char *id;
-	int optc, unset_var = 1;
-	int ret = 0;
-
-	while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != -1)
-		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;
-}
-
-static void
-p_time(struct shf *shf, int posix, struct timeval *tv, int width, char *prefix,
-    char *suffix)
-{
-	if (posix)
-		shf_fprintf(shf, "%s%*ld.%02ld%s", prefix ? prefix : "",
-		    width, tv->tv_sec, tv->tv_usec / 10000, suffix);
-	else
-		shf_fprintf(shf, "%s%*ldm%ld.%02lds%s", prefix ? prefix : "",
-		    width, tv->tv_sec / 60, tv->tv_sec % 60,
-		    tv->tv_usec / 10000, suffix);
-}
-
-int
-c_times(char **wp)
-{
-	struct rusage usage;
-
-	(void) getrusage(RUSAGE_SELF, &usage);
-	p_time(shl_stdout, 0, &usage.ru_utime, 0, NULL, " ");
-	p_time(shl_stdout, 0, &usage.ru_stime, 0, NULL, "\n");
-
-	(void) getrusage(RUSAGE_CHILDREN, &usage);
-	p_time(shl_stdout, 0, &usage.ru_utime, 0, NULL, " ");
-	p_time(shl_stdout, 0, &usage.ru_stime, 0, NULL, "\n");
-
-	return 0;
-}
-
-/*
- * time pipeline (really a statement, not a built-in command)
- */
-int
-timex(struct op *t, int f)
-{
-#define TF_NOARGS	BIT(0)
-#define TF_NOREAL	BIT(1)		/* don't report real time */
-#define TF_POSIX	BIT(2)		/* report in posix format */
-	int rv = 0;
-	struct rusage ru0, ru1, cru0, cru1;
-	struct timeval usrtime, systime, tv0, tv1;
-	int tf = 0;
-	extern struct timeval j_usrtime, j_systime; /* computed by j_wait */
-	char opts[1];
-
-	gettimeofday(&tv0, NULL);
-	getrusage(RUSAGE_SELF, &ru0);
-	getrusage(RUSAGE_CHILDREN, &cru0);
-	if (t->left) {
-		/*
-		 * Two ways of getting cpu usage of a command: just use t0
-		 * and t1 (which will get cpu usage from other jobs that
-		 * finish while we are executing t->left), or get the
-		 * cpu usage of t->left. at&t ksh does the former, while
-		 * pdksh tries to do the later (the j_usrtime hack doesn't
-		 * really work as it only counts the last job).
-		 */
-		timerclear(&j_usrtime);
-		timerclear(&j_systime);
-		if (t->left->type == TCOM)
-			t->left->str = opts;
-		opts[0] = 0;
-		rv = execute(t->left, f | XTIME);
-		tf |= opts[0];
-		gettimeofday(&tv1, NULL);
-		getrusage(RUSAGE_SELF, &ru1);
-		getrusage(RUSAGE_CHILDREN, &cru1);
-	} else
-		tf = TF_NOARGS;
-
-	if (tf & TF_NOARGS) { /* ksh93 - report shell times (shell+kids) */
-		tf |= TF_NOREAL;
-		timeradd(&ru0.ru_utime, &cru0.ru_utime, &usrtime);
-		timeradd(&ru0.ru_stime, &cru0.ru_stime, &systime);
-	} else {
-		timersub(&ru1.ru_utime, &ru0.ru_utime, &usrtime);
-		timeradd(&usrtime, &j_usrtime, &usrtime);
-		timersub(&ru1.ru_stime, &ru0.ru_stime, &systime);
-		timeradd(&systime, &j_systime, &systime);
-	}
-
-	if (!(tf & TF_NOREAL)) {
-		timersub(&tv1, &tv0, &tv1);
-		if (tf & TF_POSIX)
-			p_time(shl_out, 1, &tv1, 5, "real ", "\n");
-		else
-			p_time(shl_out, 0, &tv1, 5, NULL, " real ");
-	}
-	if (tf & TF_POSIX)
-		p_time(shl_out, 1, &usrtime, 5, "user ", "\n");
-	else
-		p_time(shl_out, 0, &usrtime, 5, NULL, " user ");
-	if (tf & TF_POSIX)
-		p_time(shl_out, 1, &systime, 5, "sys  ", "\n");
-	else
-		p_time(shl_out, 0, &systime, 5, NULL, " system\n");
-	shf_flush(shl_out);
-
-	return rv;
-}
-
-void
-timex_hook(struct op *t, char **volatile *app)
-{
-	char **wp = *app;
-	int optc;
-	int i, j;
-	Getopt opt;
-
-	ksh_getopt_reset(&opt, 0);
-	opt.optind = 0;	/* start at the start */
-	while ((optc = ksh_getopt(wp, &opt, ":p")) != -1)
-		switch (optc) {
-		case 'p':
-			t->str[0] |= TF_POSIX;
-			break;
-		case '?':
-			errorf("time: -%s unknown option", opt.optarg);
-		case ':':
-			errorf("time: -%s requires an argument",
-			    opt.optarg);
-		}
-	/* Copy command words down over options. */
-	if (opt.optind != 0) {
-		for (i = 0; i < opt.optind; i++)
-			afree(wp[i], ATEMP);
-		for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++)
-			;
-	}
-	if (!wp[0])
-		t->str[0] |= TF_NOARGS;
-	*app = wp;
-}
-
-/* exec with no args - args case is taken care of in comexec() */
-int
-c_exec(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]);
-			/*
-			 * For ksh keep anything > 2 private,
-			 * for sh, let them be (POSIX says what
-			 * happens is unspecified and the bourne shell
-			 * keeps them open).
-			 */
-			if (!Flag(FSH) && i > 2 && e->savefd[i])
-				fcntl(i, F_SETFD, FD_CLOEXEC);
-		}
-		e->savefd = NULL;
-	}
-	return 0;
-}
-
-static int
-c_mknod(char **wp)
-{
-	int argc, optc, ismkfifo = 0, ret;
-	char **argv;
-	void *set = NULL;
-	mode_t mode = 0, oldmode = 0;
-
-	while ((optc = ksh_getopt(wp, &builtin_opt, "m:")) != -1) {
-		switch (optc) {
-		case 'm':
-			set = setmode(builtin_opt.optarg);
-			if (set == NULL) {
-				bi_errorf("invalid file mode");
-				return 1;
-			}
-			mode = getmode(set, DEFFILEMODE);
-			free(set);
-			break;
-		default:
-			goto usage;
-		}
-	}
-	argv = &wp[builtin_opt.optind];
-	if (argv[0] == '\0')
-		goto usage;
-	for (argc = 0; argv[argc]; argc++)
-		;
-	if (argc == 2 && argv[1][0] == 'p') {
-		ismkfifo = 1;
-		argc--;
-	} else if (argc != 4)
-		goto usage;
-
-	if (set)
-		oldmode = umask(0);
-	else
-		mode = DEFFILEMODE;
-
-	if (ismkfifo)
-		ret = domkfifo(argc, argv, mode);
-	else
-		ret = domknod(argc, argv, mode);
-
-	if (set)
-		umask(oldmode);
-	return ret;
-usage:
-	bi_errorf("usage: mknod [-m mode] name [b | c] major minor");
-	bi_errorf("usage: mknod [-m mode] name p");
-	return 1;
-}
-
-/* dummy function, special case in comexec() */
-int
-c_builtin(char **wp)
-{
-	return 0;
-}
-
-extern	int c_test(char **wp);			/* in c_test.c */
-extern	int c_ulimit(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},
-	{"mknod", c_mknod},
-	{NULL, NULL}
-};
--- bin/ksh/misc.c
+++ /dev/null
@@ -1,1178 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/misc.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: misc.c,v 1.30 2006/03/12 00:26:58 deraadt Exp $	*/
-
-/*
- * Miscellaneous functions
- */
-
-#include "sh.h"
-#include <ctype.h>	/* ??? Removing this changes generated code! */
-#include <sys/param.h>	/* for MAXPATHLEN */
-
-short ctypes [UCHAR_MAX+1];	/* type bits for unsigned char */
-
-static int	do_gmatch(const unsigned char *, const unsigned char *,
-		    const unsigned char *, const unsigned char *);
-static const unsigned char *cclass(const unsigned char *, int);
-
-/*
- * Fast character classes
- */
-void
-setctypes(const char *s, int t)
-{
-	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(void)
-{
-	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(long unsigned int n, int base)
-{
-	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(const char *s, Area *ap)
-{
-	size_t len;
-	char *p;
-
-	if (!s)
-		return NULL;
-	len = strlen(s)+1;
-	p = alloc(len, ap);
-	strlcpy(p, s, len+1);
-	return (p);
-}
-
-/* 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(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_(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 },
-	{ (char *) 0,	'c',	    OF_CMDLINE },
-	{ "csh-history",  0,		OF_ANY }, /* non-standard */
-#ifdef EMACS
-	{ "emacs",	  0,		OF_ANY },
-	{ "emacs-usemeta",  0,		OF_ANY }, /* non-standard */
-#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 */
-	{ (char *) 0,	'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 },
-	/* Anonymous flags: used internally by shell only
-	 * (not visible to user)
-	 */
-	{ (char *) 0,	0,		OF_INTERNAL }, /* FTALKING_I */
-};
-
-/*
- * translate -o option into F* constant (also used for test -o option)
- */
-int
-option(const char *n)
-{
-	int i;
-
-	for (i = 0; i < NELEM(options); i++)
-		if (options[i].name && 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(void *arg, int i, char *buf, int buflen);
-static void printoptions(int verbose);
-
-/* format a single select menu item */
-static char *
-options_fmt_entry(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(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; i < NELEM(options); i++)
-			if (options[i].name) {
-				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, 1);
-	} else {
-		/* short version ala ksh93 */
-		shprintf("set");
-		for (i = 0; i < NELEM(options); i++)
-			if (Flag(i) && options[i].name)
-				shprintf(" -o %s", options[i].name);
-		shprintf(newline);
-	}
-}
-
-char *
-getoptions(void)
-{
-	int i;
-	char m[(int) FNFLAGS + 1];
-	char *cp = m;
-
-	for (i = 0; i < NELEM(options); 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(enum sh_flag f,
-    int what,		/* flag to change */
-    int newval)		/* what is changing the flag (command line vs set) */
-{
-	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) {
-		gid_t gid = getgid();
-
-		setresgid(gid, gid, gid);
-		setgroups(1, &gid);
-		setresuid(ksheuid, ksheuid, ksheuid);
-	} else if (f == FPOSIX && newval) {
-#ifdef BRACE_EXPAND
-		Flag(FBRACEEXPAND) = 0
-#endif /* BRACE_EXPAND */
-		;
-	}
-	/* Changing interactive flag? */
-	if (f == FTALKING) {
-		if ((what == OF_CMDLINE || what == OF_SET) && procpid == kshpid)
-			Flag(FTALKING_I) = newval;
-	}
-}
-
-/* parse command line & set command arguments.  returns the index of
- * non-option arguments, -1 if there is an error.
- */
-int
-parse_args(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 = (char *) 0;
-	Getopt go;
-	int i, optc, set, sortargs = 0, arrayset = 0;
-
-	/* First call?  Build option strings... */
-	if (cmd_opts[0] == '\0') {
-		char *p, *q;
-
-		/* see cmd_opts[] declaration */
-		strlcpy(cmd_opts, "o:", sizeof cmd_opts);
-		p = cmd_opts + strlen(cmd_opts);
-		/* see set_opts[] declaration */
-		strlcpy(set_opts, "A:o;s", sizeof set_opts);
-		q = set_opts + strlen(set_opts);
-		for (i = 0; i < NELEM(options); i++) {
-			if (options[i].c) {
-				if (options[i].flags & OF_CMDLINE)
-					*p++ = options[i].c;
-				if (options[i].flags & OF_SET)
-					*q++ = options[i].c;
-			}
-		}
-		*p = '\0';
-		*q = '\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 = strrchr(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)) != -1) {
-		set = (go.info & GI_PLUS) ? 0 : 1;
-		switch (optc) {
-		case 'A':
-			arrayset = set ? 1 : -1;
-			array = go.optarg;
-			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; i < NELEM(options); i++)
-				if (optc == options[i].c &&
-				    (what & options[i].flags)) {
-					change_flag((enum sh_flag) i, what,
-					    set);
-					break;
-				}
-			if (i == NELEM(options)) {
-				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 || *skip_varname(array, false))) {
-		bi_errorf("%s: is not an identifier", array);
-		return -1;
-	}
-	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(const char *as, int *ai)
-{
-	char *p;
-	long n;
-
-	n = strtol(as, &p, 10);
-
-	if (!*as || *p || INT_MIN >= n || n >= INT_MAX)
-		return 0;
-
-	*ai = (int)n;
-	return 1;
-}
-
-/* getn() that prints error */
-int
-bi_getn(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(const char *s, const char *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, len);
-		return !strcmp(t, s);
-	}
-	return do_gmatch((const unsigned char *) s, (const unsigned char *) se,
-	    (const unsigned char *) p, (const unsigned char *) pe);
-}
-
-/* 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 ]
- *	- imbalanced $(...) 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(const char *xp, const char *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(const unsigned char *s, const unsigned char *se,
-    const unsigned char *p, const unsigned char *pe)
-{
-	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 (!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))
-					return 1;
-			} while (s++ < se);
-			return 0;
-
-		  /*
-		   * [*+?@!](pattern|pattern|..)
-		   *
-		   * Not ifdef'd KSH as this is needed for ${..%..}, etc.
-		   */
-		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))
-				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) &&
-					    (do_gmatch(srest, se, prest, pe) ||
-					    (s != srest && do_gmatch(srest,
-					    se, p - 2, pe))))
-						return 1;
-				}
-				if (pnext == prest)
-					break;
-			}
-			return 0;
-
-		case 0x80|'?': /* matches zero or once */
-		case 0x80|'@': /* matches one of the patterns */
-		case 0x80|' ': /* simile for @ */
-			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))
-				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) &&
-					    do_gmatch(srest, se, prest, pe))
-						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)) {
-						matched = 1;
-						break;
-					}
-					if (pnext == prest)
-						break;
-				}
-				if (!matched &&
-				    do_gmatch(srest, se, prest, pe))
-					return 1;
-			}
-			return 0;
-
-		default:
-			if (sc != p[-1])
-				return 0;
-			break;
-		}
-	}
-	return s == se;
-}
-
-static const unsigned char *
-cclass(const unsigned char *p, int sub)
-{
-	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: *+?@! */
-				/* XXX the ( char isn't handled as part of [] */
-				if (c == ' ') /* simile for @: plain (..) */
-					c = '(' /*)*/;
-			}
-		}
-		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(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(void **base, void **lim, int (*f)(void *, void *));
-
-void
-qsortp(void **base,			/* base address */
-    size_t n,				/* elements */
-    int (*f) (void *, void *))		/* compare function */
-{
-	qsort1(base, base + n, f);
-}
-
-#define	swap2(a, b)	{\
-	void *t; t = *(a); *(a) = *(b); *(b) = t;\
-}
-#define	swap3(a, b, c)	{\
-	void *t; t = *(a); *(a) = *(c); *(c) = *(b); *(b) = t;\
-}
-
-static void
-qsort1(void **base, void **lim, int (*f) (void *, void *))
-{
-	void **i, **j;
-	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(void *p1, void *p2)
-{
-	return (strcmp((char *)p1, (char *)p2));
-}
-
-/* Initialize a Getopt structure */
-void
-ksh_getopt_reset(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.
- */
-int
-ksh_getopt(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 -1;
-		}
-		if (arg == (char *) 0 ||
-		    ((flag != '-' ) && /* neither a - nor a + (if + allowed) */
-		    (!(go->flags & GF_PLUSOPT) || flag != '+')) ||
-		    (c = arg[1]) == '\0') {
-			go->p = 0;
-			return -1;
-		}
-		go->optind++;
-		go->info &= ~(GI_MINUS|GI_PLUS);
-		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 attached 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 attached or unattached
-		 * 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(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(struct shf *shf, int n, char *(*func) (void *, int, char *, int),
-    void *arg, int max_width, int prefcol)
-{
-	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 (prefcol && 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(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;
-}
-
-/* Like read(2), but if read fails due to non-blocking flag, resets flag
- * and restarts read.
- */
-int
-blocking_read(int fd, char *buf, int nbytes)
-{
-	int ret;
-	int tried_reset = 0;
-
-	while ((ret = read(fd, buf, nbytes)) < 0) {
-		if (!tried_reset && errno == EAGAIN) {
-			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(int fd)
-{
-	int flags;
-
-	if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
-		return -1;
-	if (!(flags & O_NONBLOCK))
-		return 0;
-	flags &= ~O_NONBLOCK;
-	if (fcntl(fd, F_SETFL, flags) < 0)
-		return -1;
-	return 1;
-}
-
-
-/* Like getcwd(), except bsize is ignored if buf is 0 (MAXPATHLEN is used) */
-char *
-ksh_get_wd(char *buf, int bsize)
-{
-	char *b;
-	char *ret;
-
-	/* Note: we could just use plain getcwd(), but then we'd had to
-	 * inject possibly allocated space into the ATEMP area. */
-	/* 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;
-}
--- bin/ksh/jobs.c
+++ /dev/null
@@ -1,1593 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/jobs.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: jobs.c,v 1.35 2006/02/06 16:47:07 jmc Exp $	*/
-
-/*
- * Process and job control
- */
-
-/*
- * Reworked/Rewritten version of Eric Gisin's/Ron Natalie's code by
- * Larry Bouzane (larry at cs.mun.ca) and hacked again by
- * Michael Rendell (michael at 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 :)
- *
- */
-
-#include "sh.h"
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include "tty.h"
-
-/* 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;
-	int	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	/* flagged for removal (j_jobs()/j_noityf()) */
-#define JF_USETTYMODE	0x400	/* tty mode saved if process exits normally */
-#define JF_SAVEDTTYPGRP	0x800	/* j->saved_ttypgrp is valid */
-
-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 */
-	struct timeval systime;	/* system time used by job */
-	struct timeval usrtime;	/* user time used by job */
-	Proc	*proc_list;	/* process list */
-	Proc	*last_proc;	/* last process in list */
-	Coproc_id coproc_id;	/* 0 or id of coprocess output pipe */
-#ifdef JOBS
-	struct termios ttystate;/* saved tty state for stopped jobs */
-	pid_t	saved_ttypgrp;	/* saved tty process group for stopped jobs */
-#endif /* JOBS */
-};
-
-/* 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
-};
-
-struct timeval	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 */
-INT32			njobs;		/* # of jobs started */
-static int		child_max;	/* CHILD_MAX */
-
-
-/* held_sigchld is set if sigchld occurs before a job is completely started */
-static volatile sig_atomic_t held_sigchld;
-
-#ifdef JOBS
-static struct shf	*shl_j;
-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 /* JOBS */
-
-static void		j_set_async(Job *);
-static void		j_startjob(Job *);
-static int		j_waitj(Job *, int, const char *);
-static void		j_sigchld(int);
-static void		j_print(Job *, int, struct shf *);
-static Job		*j_lookup(const char *, int *);
-static Job		*new_job(void);
-static Proc		*new_proc(void);
-static void		check_job(Job *);
-static void		put_job(Job *, int);
-static void		remove_job(Job *, const char *);
-static int		kill_job(Job *, int);
-
-/* initialize job control */
-void
-j_init(int mflagset)
-{
-	child_max = CHILD_MAX; /* so syscon() isn't always being called */
-
-	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);
-
-#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);
-
-	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);
-		}
-	}
-
-	/* 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(void)
-{
-	/* 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;
-			if (j->pgrp == 0)
-				kill_job(j, SIGHUP);
-			else
-				killpg(j->pgrp, SIGHUP);
-#ifdef JOBS
-			if (j->state == PSTOPPED) {
-				if (j->pgrp == 0)
-					kill_job(j, SIGCONT);
-				else
-					killpg(j->pgrp, SIGCONT);
-			}
-#endif /* JOBS */
-		}
-	}
-	if (killed)
-		sleep(1);
-	j_notify();
-
-#ifdef JOBS
-	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);
-	}
-	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(void)
-{
-	int i;
-
-	if (Flag(FMONITOR)) {
-		/* Don't call tcgetattr() 'til we own the tty process group */
-		tty_init(false);
-
-		/* no controlling tty, no SIGT* */
-		ttypgrp_ok = tty_fd >= 0 && tty_devtty;
-
-		if (ttypgrp_ok && (our_pgrp = getpgrp()) < 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 (!ttypgrp_ok)
-			warningf(false, "warning: won't have full job control");
-		if (tty_fd >= 0)
-			tcgetattr(tty_fd, &tty_state);
-	} else {
-		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);
-			}
-		if (!Flag(FTALKING))
-			tty_close();
-	}
-}
-#endif /* JOBS */
-
-/* execute tree in child subprocess */
-int
-exchild(struct op *t, int flags,
-    int close_fd)	/* used if XPCLOSE or XCCLOSE */
-{
-	static Proc	*last_proc;	/* for pipelines */
-
-	int		i;
-	sigset_t	omask;
-	Proc		*p;
-	Job		*j;
-	int		rv = 0;
-	int		forksleep;
-	int		ischild;
-
-	if (flags & XEXEC)
-		/* Clear XFORK|XPCLOSE|XCCLOSE|XCOPROC|XPIPEO|XPIPEI|XXCOM|XBGND
-		 * (also done in another execute() below)
-		 */
-		return execute(t, flags & (XEXEC | XERROK));
-
-	/* no SIGCHLD's while messing with job and process lists */
-	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-
-	p = new_proc();
-	p->next = (Proc *) 0;
-	p->state = PRUNNING;
-	p->status = 0;
-	p->pid = 0;
-
-	/* link process into jobs list */
-	if (flags&XPIPEI) {	/* continuing with a pipe */
-		if (!last_job)
-			internal_errorf(1,
-			    "exchild: XPIPEI and no last_job - pid %d",
-			    (int) procpid);
-		j = last_job;
-		last_proc->next = p;
-		last_proc = p;
-	} else {
-		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));
-		timerclear(&j->usrtime);
-		timerclear(&j->systime);
-		j->state = PRUNNING;
-		j->pgrp = 0;
-		j->ppid = procpid;
-		j->age = ++njobs;
-		j->proc_list = p;
-		j->coproc_id = 0;
-		last_job = j;
-		last_proc = p;
-		put_job(j, PJ_PAST_STOPPED);
-	}
-
-	snptreef(p->command, sizeof(p->command), "%T", 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, SIGKILL);
-		remove_job(j, "fork failed");
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-		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;
-		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);
-		/* 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 /* JOBS */
-
-	/* used to close pipe input fd */
-	if (close_fd >= 0 && (((flags & XPCLOSE) && !ischild) ||
-	    ((flags & XCCLOSE) && ischild)))
-		close(close_fd);
-	if (ischild) {		/* child */
-		/* Do this before restoring signal */
-		if (flags & XCOPROC)
-			coproc_cleanup(false);
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-		cleanup_parents_env();
-#ifdef JOBS
-		/* 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 /* JOBS */
-		if (Flag(FBGNICE) && (flags & XBGND))
-			nice(4);
-		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 (!(flags & (XPIPEI | XCOPROC))) {
-				int fd = open("/dev/null", 0);
-				if (fd != 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 & XERROK) | XEXEC); /* no return */
-		internal_errorf(0, "exchild: execute() returned");
-		unwind(LLEAVE);
-		/* NOTREACHED */
-	}
-
-	/* shell (parent) stuff */
-	/* Ensure next child gets a (slightly) different $RANDOM sequence */
-	change_random();
-	if (!(flags & XPIPEO)) {	/* last process in a job */
-#ifdef JOBS
-		/* YYY: Is this needed? (see also YYY above)
-		   if (Flag(FMONITOR) && !(flags&(XXCOM|XBGND)))
-			tcsetpgrp(tty_fd, j->pgrp);
-		*/
-#endif /* JOBS */
-		j_startjob(j);
-		if (flags & XCOPROC) {
-			j->coproc_id = coproc.id;
-			coproc.njobs++; /* n jobs using co-process output */
-			coproc.job = (void *) j; /* j using co-process input */
-		}
-		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");
-	}
-
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-
-	return rv;
-}
-
-/* start the last job: only used for `command` jobs */
-void
-startlast(void)
-{
-	sigset_t omask;
-
-	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-
-	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);
-	}
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-}
-
-/* wait for last job: only used for `command` jobs */
-int
-waitlast(void)
-{
-	int	rv;
-	Job	*j;
-	sigset_t omask;
-
-	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-
-	j = last_job;
-	if (!j || !(j->flags & JF_STARTED)) {
-		if (!j)
-			warningf(true, "waitlast: no last job");
-		else
-			internal_errorf(0, "waitlast: not started");
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-		return 125; /* not so arbitrary, non-zero value */
-	}
-
-	rv = j_waitj(j, JW_NONE, "jw:waitlast");
-
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-
-	return rv;
-}
-
-/* wait for child, interruptable. */
-int
-waitfor(const char *cp, int *sigp)
-{
-	int	rv;
-	Job	*j;
-	int	ecode;
-	int	flags = JW_INTERRUPT|JW_ASYNCNOTIFY;
-	sigset_t omask;
-
-	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-
-	*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) {
-			sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-			return -1;
-		}
-	} else if ((j = j_lookup(cp, &ecode))) {
-		/* don't report normal job completion */
-		flags &= ~JW_ASYNCNOTIFY;
-		if (j->ppid != procpid) {
-			sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-			return -1;
-		}
-	} else {
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-		if (ecode != JL_NOSUCH)
-			bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
-		return -1;
-	}
-
-	/* at&t ksh will wait for stopped jobs - we don't */
-	rv = j_waitj(j, flags, "jw:waitfor");
-
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-
-	if (rv < 0) /* we were interrupted */
-		*sigp = 128 + -rv;
-
-	return rv;
-}
-
-/* kill (built-in) a job */
-int
-j_kill(const char *cp, int sig)
-{
-	Job	*j;
-	int	rv = 0;
-	int	ecode;
-	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) {	/* started when !Flag(FMONITOR) */
-		if (kill_job(j, 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;
-		}
-	}
-
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-
-	return rv;
-}
-
-#ifdef JOBS
-/* fg and bg built-ins: called only if Flag(FMONITOR) set */
-int
-j_resume(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;
-			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 JOBS
-		/* attach tty to job */
-		if (j->state == PRUNNING) {
-			if (ttypgrp_ok && (j->flags & JF_SAVEDTTY))
-				tcsetattr(tty_fd, TCSADRAIN, &j->ttystate);
-			/* See comment in j_waitj regarding saved_ttypgrp. */
-			if (ttypgrp_ok &&
-			    tcsetpgrp(tty_fd, (j->flags & JF_SAVEDTTYPGRP) ?
-			    j->saved_ttypgrp : j->pgrp) < 0) {
-				if (j->flags & JF_SAVEDTTY)
-					tcsetattr(tty_fd, TCSADRAIN, &tty_state);
-				sigprocmask(SIG_SETMASK, &omask,
-				    (sigset_t *) 0);
-				bi_errorf("1st tcsetpgrp(%d, %d) failed: %s",
-				    tty_fd,
-				    (int) ((j->flags & JF_SAVEDTTYPGRP) ?
-				    j->saved_ttypgrp : j->pgrp),
-				    strerror(errno));
-				return 1;
-			}
-		}
-# endif /* JOBS */
-		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 JOBS
-			if (ttypgrp_ok && (j->flags & JF_SAVEDTTY))
-				tcsetattr(tty_fd, TCSADRAIN, &tty_state);
-			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 /* JOBS */
-		}
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-		bi_errorf("cannot continue job %s: %s",
-		    cp, strerror(err));
-		return 1;
-	}
-	if (!bg) {
-# ifdef JOBS
-		if (ttypgrp_ok) {
-			j->flags &= ~(JF_SAVEDTTY | JF_SAVEDTTYPGRP);
-		}
-# endif /* JOBS */
-		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(void)
-{
-	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;
-}
-
-int
-j_njobs(void)
-{
-	Job *j;
-	int nj = 0;
-	sigset_t omask;
-
-	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-	for (j = job_list; j; j = j->next)
-		nj++;
-
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-	return nj;
-}
-
-
-/* list jobs for jobs built-in */
-int
-j_jobs(const char *cp, int slp,
-    int nflag)		/* 0: short, 1: long, 2: pgrp */
-{
-	Job	*j, *tmp;
-	int	how;
-	int	zflag = 0;
-	sigset_t omask;
-
-	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-
-	if (nflag < 0) { /* kludge: print zombies */
-		nflag = 0;
-		zflag = 1;
-	}
-	if (cp) {
-		int	ecode;
-
-		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;
-		}
-	} 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");
-	}
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-	return 0;
-}
-
-/* list jobs for top-level notification */
-void
-j_notify(void)
-{
-	Job	*j, *tmp;
-	sigset_t omask;
-
-	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-	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);
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-}
-
-/* Return pid of last process in last asynchronous job */
-pid_t
-j_async(void)
-{
-	sigset_t omask;
-
-	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-
-	if (async_job)
-		async_job->flags |= JF_KNOWN;
-
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-
-	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(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(Job *j)
-{
-	Proc	*p;
-
-	j->flags |= JF_STARTED;
-	for (p = j->proc_list; p->next; p = p->next)
-		;
-	j->last_proc = p;
-
-	if (held_sigchld) {
-		held_sigchld = 0;
-		/* Don't call j_sigchld() as it may remove job... */
-		kill(procpid, SIGCHLD);
-	}
-}
-
-/*
- * 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(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)) {
-		sigsuspend(&sm_default);
-		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) {
-		int	status;
-
-		j->flags &= ~JF_FG;
-#ifdef JOBS
-		if (Flag(FMONITOR) && ttypgrp_ok && j->pgrp) {
-			/*
-			 * Save the tty's current pgrp so it can be restored
-			 * when the job is foregrounded.  This is to
-			 * deal with things like the GNU su which does
-			 * a fork/exec instead of an exec (the fork means
-			 * the execed shell gets a different pid from its
-			 * pgrp, so naturally it sets its pgrp and gets hosed
-			 * when it gets foregrounded by the parent shell, which
-			 * has restored the tty's pgrp to that of the su
-			 * process).
-			 */
-			if (j->state == PSTOPPED &&
-			    (j->saved_ttypgrp = tcgetpgrp(tty_fd)) >= 0)
-				j->flags |= JF_SAVEDTTYPGRP;
-			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;
-				tcgetattr(tty_fd, &j->ttystate);
-			}
-		}
-#endif /* JOBS */
-		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)) {
-				tcgetattr(tty_fd, &tty_state);
-			} else {
-				tcsetattr(tty_fd, TCSADRAIN, &tty_state);
-				/* 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.
- */
-/* ARGSUSED */
-static void
-j_sigchld(int sig)
-{
-	int		errno_ = errno;
-	Job		*j;
-	Proc		*p = NULL;
-	int		pid;
-	int		status;
-	struct rusage	ru0, ru1;
-
-	/* 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;
-		}
-
-	getrusage(RUSAGE_CHILDREN, &ru0);
-	do {
-		pid = waitpid(-1, &status, (WNOHANG|WUNTRACED));
-
-		if (pid <= 0)	/* return if would block (0) ... */
-			break;	/* ... or no children or interrupted (-1) */
-
-		getrusage(RUSAGE_CHILDREN, &ru1);
-
-		/* 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);
-			 */
-			ru0 = ru1;
-			continue;
-		}
-
-		timeradd(&j->usrtime, &ru1.ru_utime, &j->usrtime);
-		timersub(&j->usrtime, &ru0.ru_utime, &j->usrtime);
-		timeradd(&j->systime, &ru1.ru_stime, &j->systime);
-		timersub(&j->systime, &ru0.ru_stime, &j->systime);
-		ru0 = ru1;
-		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 */
-	}
-	while (1);
-
-	errno = errno_;
-}
-
-/*
- * 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(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;
-	}
-
-	/* 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 least, 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);
-	}
-
-	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(Job *j, int how, struct shf *shf)
-{
-	Proc	*p;
-	int	state;
-	int	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:
-			strlcpy(buf, "Running", sizeof buf);
-			break;
-		case PSTOPPED:
-			strlcpy(buf, sigtraps[WSTOPSIG(p->status)].mess,
-			    sizeof buf);
-			break;
-		case PEXITED:
-			if (how == JP_SHORT)
-				buf[0] = '\0';
-			else if (WEXITSTATUS(p->status) == 0)
-				strlcpy(buf, "Done", sizeof buf);
-			else
-				shf_snprintf(buf, sizeof(buf), "Done (%d)",
-				    WEXITSTATUS(p->status));
-			break;
-		case PSIGNALLED:
-			if (WCOREDUMP(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
-				strlcpy(buf, sigtraps[WTERMSIG(p->status)].mess,
-				    sizeof buf);
-			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 && p->status == 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(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(void)
-{
-	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 struct
- *
- * If jobs are compiled in then this routine expects sigchld to be blocked.
- */
-static Proc *
-new_proc(void)
-{
-	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(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(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 int
-kill_job(Job *j, int sig)
-{
-	Proc	*p;
-	int	rval = 0;
-
-	for (p = j->proc_list; p != (Proc *) 0; p = p->next)
-		if (p->pid != 0)
-			if (kill(p->pid, sig) < 0)
-				rval = -1;
-	return rval;
-}
--- bin/ksh/ChangeLog.0
+++ /dev/null
@@ -1,3589 +0,0 @@
-$OpenBSD: ChangeLog.0,v 1.4 2003/02/28 09:45:09 jmc Exp $
-
-Thu Jun 15 11:02:06 NDT 1995 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* aclocal.m4(KSH_MEMMOVE): fixed test so copies overlap.
-
-Sun May 28 11:11:03 NDT 1995 John Rochester (jr at 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 at panda.cs.mun.ca)
-
-	* exec.c: put comments around token after #endif.
-
-Thu May 25 10:10:45 NDT 1995 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 redundant
-	  code eliminated.
-	  (based on fix from Michael Jetzer).
-
-Fri Apr 28 16:10:22 NDT 1995 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at garfield.cs.mun.ca)
-
-	* io.c(maketemp): create valid dos filenames.
-
-Mon Feb 27 11:04:32 NST 1995 Michael Rendell (michael at 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 at .
-	* 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* made pdksh-5.1.3 distribution
-
-	* *.c: removed RCSids.
-
-Wed Dec 21 11:55:01 NST 1994 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* tree.c(ptree): print TELIF part of if statements
-
-Fri Dec  9 15:21:36 NST 1994 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* trap.c(inittraps): OS2: don't trap SIGTERM (temporary 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* made pdksh-5.1.1 distribution
-
-Thu Dec  1 10:50:38 NST 1994 Michael Rendell (michael at 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 at 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 at 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 at 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 redundant np and optr variables.
-
-Mon Nov 28 14:55:49 NST 1994 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* exec.c(do_selectargs): removed use of pmenu variable (redundant)
-	  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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at qnx.com>)
-
-	* emacs.c(x_transpose): changed behavior if FGMACS flag set
-	  (fix from <guy at netapp.com>).
-
-Tue Oct 25 17:11:58 NDT 1994 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at arlene.cs.mun.ca)
-
-	* lex.c(readhere): check for and report write errors.
-
-Sun Oct 16 16:10:59 NDT 1994 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* made pdksh-5.0.7 distribution
-
-Tue Sep 20 09:56:54 NDT 1994 Michael Rendell (michael at 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 at 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 at 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 redundant "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 separately 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 at 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 at 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 at 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 at 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 at approve.se>).
-
-	* ksh.1(DESCRIPTION): added missing P in \fP
-	  (fix from Gordan Larson <hoh at approve.se>).
-
-Tue Sep 13 11:01:47 NDT 1994 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* made pdksh-5.0.6 distribution
-
-Mon Sep 12 11:39:07 NDT 1994 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at cygnus.com)
-	  for POSIXization of test builtin.
-
-Wed Aug 24 12:16:25 NDT 1994 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 separate).
-	* 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 at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* sh.h: fix lseek prototype (from sjg at zen.void.oz.au)
-
-	* configure.in,jobs.c: added HAVE_SYSCONF; don't use sysconf() unless
-	  HAVE_SYSCONF defined (for NetBSD-Feb12 from sjg at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at netcom.com).
-
-Fri Jul  8 09:37:51 NDT 1994 Michael Rendell (michael at 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 at 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 at zen.void.oz.au).
-
-Wed Jul  6 10:09:55 NDT 1994 Michael Rendell (michael at 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 at 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 at 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 separate 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 redundant).  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 at 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'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 at 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 at 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 at 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 redundant 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 redundant - always call afree()
--- bin/ksh/ChangeLog
+++ /dev/null
@@ -1,1600 +0,0 @@
-Tue Jul 13 14:32:57 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* made pdksh-5.2.14 distribution
-
-Wed Jun 30 17:42:54 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* c_test.c(test_eval): changed -nt/-ot tests so they succeed
-	  if file2 (file2) `does not exist' (ie, the stat fails).
-	  (based on fix from Dave Hillman).
-
-Tue May 25 17:23:39 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* jobs.c(fill_command): do not eval() TCOM arguments - can cause
-	  problems.
-
-Tue May 25 15:26:31 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* new-version.sh,ksh.Man: added version number to man page; update
-	  version as well as date when updating tests/version.t and ksh.Man.
-
-Mon May 24 20:57:21 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* c_sh.c(c_eval): only set exstat to substs_exstat if in non-posix mode.
-
-Mon May 24 15:44:10 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* tree.h(FTIME): new define.
-	* c_sh.c(timex): stuff to get info to/from timex_hook.
-	* c_sh.c(timex_hook): new function (handles option processing).
-	* exec.c(execute): call timex_hook() after TCOM eval().
-
-Tue May 18 12:23:27 NDT 1999 Michael Rendell (michael at deimos.cs.mun.ca)
-
-	* vi.c(vi_hook): case VREDO: removed != 0 from switch expression.
-
-Tue May 18 11:24:12 NDT 1999 Michael Rendell (michael at deimos.cs.mun.ca)
-
-	* emacs.c(CHARMASK,X_TABSZ): changed from 128 to 256.
-	* emacs.c(x_size,x_zotc,x_mapout): use iscntl() vs range test.
-	  (Based on changes from Martin Dalecki)
-
-Thu May 13 17:23:17 NDT 1999 Michael Rendell (michael at deimos.cs.mun.ca)
-
-	* emacs.c(x_bound,bind_if_not_bound): new variable/fucntion.
-	* emacs.c(x_bind): set bit in x_bound[].
-	* emacs.c(x_emacs_keys): call bind_if_not_bound.
-
-Thu May 13 14:23:12 NDT 1999 Michael Rendell (michael at deimos.cs.mun.ca)
-
-	* sh.h: ifdefs for __CYGWIN__ for path defines.
-	* path.c(simplify_path): ifdefs for __CYGWIN__; preserve leading
-	  double-slash on pathnames.
-	* c_ksh.c(c_cd): use cygwin_conv_to_full_posix_path().
-	* edit.c(x_mode): default eof char to ^D.
-
-	[fixes from Corinna Vinschen and Steven Hein, obtained from
-	 ftp://ftp.franken.de/pub/win32/develop/gnuwin32/cygwin/
-	    porters/Vinschen_Corinna/B20/]
-
-Wed May 12 12:30:09 NDT 1999 Michael Rendell (michael at deimos.cs.mun.ca)
-
-	* exit.c(x_mode): set fields of edchars to -1 if corrisponding char
-	  is unset.
-	* exit.c(x_init): initialize edchars to -2, not -1.
-	* emacs.c(x_emacs_keys): check if char is >= 0 before setting.
-
-Wed May 12 11:31:24 NDT 1999 Michael Rendell (michael at deimos.cs.mun.ca)
-
-	* shf.c(shf_write): don't buffer if buffer is empty and we're
-	  writting a large amount.
-	* shf.c(shf_open): changed to use shf_reopen instead of shf_fdopen
-	  so alloca failing won't lose the fd.
-
-Wed May 12 10:19:43 NDT 1999 Michael Rendell (michael at deimos.cs.mun.ca)
-
-	* sh.h: deleted TT_HEREDOC_RAW define.
-	* tree.h(struct ioword): added heredoc field.
-	* tree.c(iocopy,iofree): copy/free heredoc field; remove special case
-	  for IOHERE and name field.
-	* tree.c(ptree): changed to use heredoc content string (not open temp).
-	* lex.c(yylex): initialize heredoc field.
-	* lex.c(readhere): save to string instead of a temp file.
-	* exec.c(herein): changed first are from file name to heredoc content
-	  string; changed all calls.  Changed to always create a new temp file
-	  and write content to it.
-
-Tue May 11 11:38:22 NDT 1999 Michael Rendell (michael at deimos.cs.mun.ca)
-
-	* tree.c(iofree): free delim field; don't free name of IOHERE iowords.
-
-Tue May 11 10:57:53 NDT 1999 Michael Rendell (michael at deimos.cs.mun.ca)
-
-	* sh.h(func_heredocs): deleted.
-	* sh.h(EF_FAKE_SIGDIE): added.
-	* lex.c(readhere): put function heredocs at bottom of env stack.
-	* main.c(quitenv,cleanup_proc_env): deleted remove_temps(func_heredocs)
-	  calls.
-
-	* main.c(quitenv): moved exit of no oenv to en after reclaim.
-	* main.c(cleanup_parents_env): free ep->savefd and set to 0.
-	* main.c(unwind,quitenv): moved code for E_NONE from unwind()
-	  to quitenv().
-
-Mon May 10 17:04:03 NDT 1999 Michael Rendell (michael at deimos.cs.mun.ca)
-
-	* exec.c(herein): restore source to osource after yylex().
-
-Mon May 10 12:14:40 NDT 1999 Michael Rendell (michael at deimos.cs.mun.ca)
-
-	* tree.c(iocopy): don't copy IOHERE name (it belongs to a struct temp).
-	* tree.c(wdscan): added default case to print internal error.
-
-Mon May 10 10:39:34 NDT 1999 Michael Rendell (michael at deimos.cs.mun.ca)
-
-	* sh.h(Temp_type): new enum (TT_HEREDOC_RAW, TT_HEREDOC_EXP,
-	  TT_HIST_FILE).
-	* sh.h(struct temp): added type field.
-	* io.c(maketemp): added type and tlist arguments; changed
-	  all calls.
-
-Tue Apr 27 11:31:48 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* exec.c(execute): clear XEXEC in the call to timex() so time
-	  can be used at the end of a pipeline.
-
-Fri Apr 23 16:29:01 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* mail.c(mcheck): don't check if MAILCHECK is set, just check if
-	  mplist is null.
-	* mail.c(mcset): new function.
-	* var.c(setspec): case MAILCHECK: call mcset.
-	* var.c(unspecial): new function.
-	* var.c(unsetspec): call unspecial for LINENO, MAILCHECK, RANDOM,
-	  SECONDS, TMOUT.
-
-Fri Apr 23 15:34:39 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* main.c(initcoms): put MAILCHECK, SECONDS, TMOUT in an eval to
-	  preserve previous values.
-	* var.c(getspec): case V_SECONDS: don't do anything special if
-	  variable not set.
-
-Thu Apr 22 15:03:27 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* var.c(setstr): error if var is RDONLY.
-	* var.c(global): non-letter params: set RDONLY flag after setstr call.
-	* c_ksh.c(c_getopts), eval.c(expand), exec.c(execute):
-	  removed readonly check.
-
-	* sh.h(KSH_UNWIND_ERROR, KSH_RETURN_ERROR): new defines.
-	* var.c(setstr): added error_ok argument; changed all calls.
-	* c_ksh.c(c_getopts): clear READONLY and INTEGER flags for OPTARG;
-	  return non-zero if variable can't be set.
-	* var.c(typeset): if fake_assign fails, unset the variable's value
-	  and carry on for rest of array, then unwind.
-	* expr.c(expand,v_expand): changed all calls to use KSH_UNWIND_ERROR
-	  or KSH_RETURN_ERROR.
-
-Tue Apr 20 16:52:24 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* configure.in: added check dup2.
-	* sh.h: added dup2 prototype.
-	* aclocal.m4: replace AC_HEADER_DIRENT so it checks -lndir.
-
-	* missing.c(dup2): new function.
-	  Based on code from Marc Olzheim.
-
-Fri Apr 16 16:32:27 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* syn.c(lineno_offset): removed variable and all references.
-	* tree.c(tcopy): copy lineno field.
-	* var.c(user_lineno): new variable.
-	* var.c(setspec): added case for V_LINENO (sets user_lineno).
-	* var.c(getspec): V_LINENO: add in user_lineno.
-
-Fri Apr 16 15:26:26 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* tree.h(struct op): added lineno field.
-	* table.h(V_LINENO, current_lineno): new define/variable.
-	* exec.c(execute): set current_lineno for TCOM.
-	* syn.c(lineno_offset): new variable.
-	* syn.c(get_command): set t->lineno.
-	* syn.c(function_body): save/restore lineno_offset;
-	* syn.c(compile): initialize lineno_offset
-	* var.c(initvar,getspec): added V_LINENO entry.
-
-	Changes from Mark Funkenhauser.
-
-Fri Apr 16 12:18:08 NDT 1999 Michael Rendell (michael at lyman.cs.mun.ca)
-
-	* expr.c,misc.c(getoptions): added int casts to avoid errors from
-	  old K&R compilers.
-	Fixes from Marc Olzheim.
-
-Fri Jan 15 12:51:53 NST 1999 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* expr.c: pass es as first param to all functions; deleted
-	  es global variable.
-
-Tue Jan 12 12:28:41 NST 1999 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* emacs.c(x_defbindings[]): removed #else part of ifdef OS2.
-
-	* shf.c(shf_getse): added code to strip \r for OS2.
-	* lex.c(getsc_line): removed OS2 ifdefs
-
-	* os2/misc.c(ksh_execve),sh.h: added flags argument; changed all calls.
-	* exec.c(scriptexec): OS2: make copy of a0 before calling
-	  search_access(X_OK).
-	* sh.h: OS2: changed EXECSHELL, EXECSHELL_STR.
-	* jobs.c(exchild): set XINTACT.
-	* os2/config.h: added HAVE_TERMIOS_H.
-	* os2/configure.cmd: changed test for existence of sed & gcc.
-
-	Fixes from Ilya Zakharevich.
-
-	* tests/th: added -C option, added "category" field.
-	* tests/th(category_check): new function.
-	* tests/*.t: added "category: !os:os2" to a few tests.
-
-Tue Jan 12 11:17:52 NST 1999 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* exec.c(execute): changed exit(rv) to unwind(LEXIT) to
-	  allow exit traps to be done.
-
-Tue Jan  5 16:45:00 NST 1999 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* aclocal.m4(KSH_CHECK_H_TYPE): remove extra [] from egrep pattern.
-	* c_sh.c(c_exitreturn): fixed logic of exit status parsing
-	  (fixes from Martin Lucina).
-
-Tue Jan  5 16:31:37 NST 1999 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* edit.c(x_locate_word): changed IS_WORDC macro from !isspace
-	  to !lex1/'/"
-	  (based on fix from Kevin Schoedel).
-
-Wed Dec 16 15:02:48 NST 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* io.c(kshdebug_init_,kshdebug_printf_,kshdebug_dump_),
-	  sh.h(kshdebug_init,kshdebug_printf,kshdebug_dump):
-	  new macros/functions.
-
-Wed Dec 16 12:12:23 NST 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* c_sh.c(c_eval): set exstat to substs_exstat to propogate
-	  substition exit status if resulting command is empty
-	  (based on fix from Mark Funkenhauser).
-
-Tue Dec 15 15:50:34 NST 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* main.c(initcom[]): PPID no longer read only.
-
-Mon Dec 14 17:09:52 NST 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* trap.c(gettrap): added igncase argument; changed all calls.
-	* c_sh.c(c_trap): use case sensitive compare for first gettrap().
-	  (fix "trap exit 1").
-
-Thu Dec 10 12:24:53 NST 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* configure.in: added test for getcwd.
-	* aclocal.m4(KSH_OS_TYPE): added case for hpux; added test for
-	  bug in hpux getcwd (dumps core if . is not readable).
-	* config.h.in: added HAVE_HPUX_GETWD_BUG define.
-	* aclocal.m4,configure.in: remove AC_C_CROSS or change to AC_PROG_CC.
-	* misc.c(ksh_get_wd): added code to handle bug in hpux getwd;
-	  changed precedence of getcwd vs getwd (use getcwd if available:
-	  getwd causes warnings under linux).
-
-Tue Dec  8 17:17:47 NST 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* main.c(main): seed RANDOM using time, pid, ppid (was just time).
-
-Tue Nov 24 17:17:12 NST 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* c_ulimit.c(c_ulimit): improve setrlimit error message for EPERM
-	  (fix from Todd C. Miller).
-
-Thu Nov 19 18:09:59 NST 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* jobs.c(waitfor): if j_lookup fails, always return
-	  (fix from Todd C. Miller).
-
-Fri Oct 23 19:59:25 NDT 1998 Michael Rendell (michael at lenny.cs.mun.ca)
-
-	* jobs.c(JF_SAVEDTTYPGRP,j_resume,j_waitj): added save_ttypgrp
-	  stuff to deal with new gnu su which doesn't exec, but forks
-	  then execs.
-
-Thu Sep 24 16:23:48 NDT 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* trap.c(inittrap): Don't assume sys_siglist[] has NSIG non-null
-	  entries (fix from clifford at clifford.at).
-
-Thu Aug  6 14:46:45 NDT 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* eval.c(varsub): ${#array[*]} now prints N elements, not
-	  max index.
-
-Sun Jul 19 11:50:21 NDT 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* syn.c(function_body): fixed bug in handling of empty function
-	  body; if empty, pretend there is a : command.
-
-Mon Jun 29 10:13:02 NDT 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* exec.c(search_access): allow non-regular files to be .'ed
-	  (fix from Theo de Raadt).
-
-Thu Jun 25 17:01:36 NDT 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* c_ulimit.c(c_ulimit): added KSH_RLIM_INFINITY and defined
-	  if system doesn't define RLIM_INFINITY; use when setting limits.
-	  When setting, if expression evaluates to 0 and string was not
-	  a number, generate an error (based on fix from Todd C. Miller).
-
-Wed Mar 11 16:35:37 NST 1998 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* exec.c(flushcom): clear ISSET bit, don't set all the other bits
-	  (fix from Eric Youngdale).
-
-Tue Dec 16 11:07:21 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* shf.c(shf_vfprintf): %e/%f/%g conversion now prints negative
-	  numbers correctly (fix from Larry Bouzane).
-
-Thu Nov 20 15:16:15 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* emacs.c(x_prev_histword): check if histptr is 0.
-
-Sat Nov  8 11:46:32 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* misc.c(options[]): changed null entries to (char *) 0
-	  (based on fix from David E. Wexelblat).
-
-Fri Nov  7 14:45:24 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* alloc.c(aresize): avoid memory overrun when copying old memory
-	  to new memory.
-	  (fix from David E. Wexelblat).
-
-Tue Oct 28 11:26:22 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* tests/th: file-setup code: convert chmod argument to octal.
-
-Tue Oct 28 11:00:45 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* tree.c(tputS): incr wp after COMSUB and EXPRSUB while loop
-	  to get past null.
-
-Mon Oct 27 12:38:05 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* made pdksh-5.2.13 distribution
-
-Mon Oct 27 12:21:51 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* c_sh.c(c_dot): use search() error argument to report problem
-	  correctly.
-	* exec.c(search_access): don't set *errnop if it is already set.
-	* exec.c(search_access): extended non-regular file check from
-	  just X_OK to both X_OK and R_OK.
-
-Wed Oct 22 11:49:02 NDT 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* edit.c(x_locate_word): don't skip trailing space if at end
-	  of buffer (based on fix from Marc Olzheim).
-
-Fri Aug 15 22:06:53 NDT 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* eval.c(varsub,expand), lex.c(yylex): allow :%, :#, :%% and :##
-	  to be compatible with ksh88.
-
-Sat Aug  2 12:13:30 NDT 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* syn.c(get_command): case MDPAREN/DBRACKET: do not
-	  clear KEYWORD|ALIAS from syniocf.
-
-Tue Jul 29 16:24:38 NDT 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* c_sh.c(c_exec): added ifdef KSH around fd_clexec()
-	  (based on fix from George Robins).
-
-Tue Jun  3 12:52:05 NDT 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* misc.c(do_gmatch): removed ifdef KSH about @(..|..) code as it
-	  is needed in SH mode for ${..%..} stuff.
-
-Mon May 19 16:10:06 NDT 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* table.h(struct block): added getopt_state and flags fields;
-	  added BF_DOGETOPTS.
-	* sh.h,c_ksh.c: moved user_opt decl/defn from c_ksh.c to sh.h.
-	* var.c(getspec): added case for V_OPTIND.
-	* var.c(popblock): if BF_DOGETOPTS set, restore user_opt.
-	* exec.c(comexec): case CFUNC: save user_opt for ksh-style functions.
-	* c_ksh.c(getopts_reset,c_getopts): removed getopts_noreset variable
-	  and code.
-	* sh.h(Getopts): added uoptind field.
-
-Fri May 16 11:40:22 NDT 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* io.c(error_prefix): don't print kshname if it is the
-	  same as the source file name.
-
-Thu Mar 13 10:42:31 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* mail.c(mbset): save a copy of the path so it can't get trashed
-	  (eg, by exporting a variable).
-
-Wed Feb 26 11:24:06 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* emacs.c(x_prev_histword): get word from last command entered,
-	  not from last command relative to current location in history
-	  (fix from Greg A. Woods).
-
-Sun Feb 16 13:18:52 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* sh.h(FTALKING_I): new define
-	* misc.c(options[]): added anonymous options for internal use:
-	  changed all code using options to not assume null option name
-	  is the end of options (use NELEM()) instead.
-	  Added slot for FTALKING_I
-
-	* c_sh.c(c_read), exec.c(iosetup): test FTALKING_I instead of FTALKING.
-	* main.c(main): set FTALKING_I.
-
-Fri Jan 10 16:36:36 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* jobs.c(exchild): use orig_flags instead of flags when testing
-	  XPIPEI/XPIPEO; clear all flags except XEXEC and XERROK.
-
-Tue Jan  7 11:16:08 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* lex.h(yynerrs): deleted (not used); deleted all assignments of it.
-
-Fri Jan  3 13:40:29 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* lex.c(yylex): case STBRACE: interpret ( | ) as patterns;
-	  case SPATTERN: allow ( as an alias for @(.
-
-Thu Jan  2 15:44:07 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* main.c(main): set PATH to def_path in startup.
-
-Thu Jan  2 10:19:43 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* exec.c(comexec): ifdef KSH the setting of $_; only set $_ to
-	  last arg if interactive.
-
-Wed Jan  1 13:38:26 NST 1997 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* lex.c(yylex),eval.c(expand),tree.c(tputS,wdscan,wdstrip):
-	  changed OSUBST/CSUBST encoding to have { or x after xSUBST.
-
-	* lex.c(yylex): case ${: don't prepend @( and append ) to trim patterns.
-	* eval.c(expand): prepend MAGIC @ and append MAGIC ) to trim patterns.
-
-	* syn.c(function_body): call wdstrip().
-	* tree.c(wdstrip): new function.
-
-	* lex.c(yylex): moved handling of < and > into one location.
-
-Wed Dec 11 13:00:05 NST 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* sh.h(ksheuid): new variable.
-	* main.c(main): set/use ksheuid.
-	* misc.c(change_flag): set ksheuid.
-	* c_test.c(test_eval): use ksheuid
-	* c_test.c(test_eaccess): if doing X_OK and user is root, use
-	  stat to avoid false positives on files.
-
-Mon Dec  9 12:08:56 NST 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* main.c(main): save/clear/restore FERREXIT flag while processing
-	  profile and ENV.
-
-Wed Dec  4 12:25:23 NST 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* misc.c(parse_args): change -A option handling - make getopts
-	  gather the option (A: vs A).
-
-Thu Nov 21 15:42:57 NST 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* c_ksh.c(c_alias): accept + options; don't print alias definition
-	  if + option used; allow export flag to be cleared; added -p
-	  option.
-
-Thu Nov 21 14:35:47 NST 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* tree.c(ptree),c_ksh.c(c_typeset): print ksh functions as
-	  "function foo...", sh functions as "foo()...".
-
-	* c_ksh.c(c_typeset): accept -p flag (does nothing).
-
-Wed Nov 20 11:36:08 NST 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* c_ksh.c(c_typeset): simplified option exclusion code.
-
-	* misc.c(ksh_getopt): allow options in same command line to start
-	  with either + or - (if appropriate).  [code existed to similate
-	  ksh88 typeset behaviour which disallowed "typeset +x -i foo"]
-
-Wed Nov 13 12:02:59 NST 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* syn.c(c_list): added multi argument; changed all calls to pass
-	  TRUE, except one in yyparse(); changed logic to accept and
-	  ignore blank lines if multi flag is set.
-	* syn.c(get_command): removed multiline.on/cf=CONTIN test/assignment.
-	* syn.c(struct multiline_state,struct nesting_state,multiline,nesting,
-	  multiline_push,multiline_pop,nesting_push,nesting_pop): renamed
-	  *multiline* to *nesting*; removed struct multiline_state.on field
-	  (deleted all references).
-
-Mon Nov  4 16:29:50 NST 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* c_test.c(c_test): in special < 5 arg code: if single arg is
-	  -t and not in FPOSIX mode, don't decide its a string test.
-
-Wed Oct 30 11:34:39 NST 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* main.c(include): call quitenv() after shf_close()
-	  (fix from Eric J. Chet).
-
-Wed Oct 30 11:23:17 NST 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* exec.c(comexec): case CFUNC: set $0 to kshname if non-function
-	  function.
-
-$OpenBSD: ChangeLog,v 1.14 2003/03/10 03:48:16 david Exp $
-
-Tue Oct 29 11:34:58 NST 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* made pdksh-5.2.12 distribution
-
-Fri Oct 25 11:59:48 NDT 1996 Michael Rendell (michael at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* main.c(main): memset() env to 0.
-
-Mon Oct 21 12:53:44 NDT 1996 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* made pdksh-5.2.11 distribution
-
-Tue Oct  8 11:02:54 NDT 1996 Michael Rendell (michael at 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 at panda.cs.mun.ca)
-
-	* made pdksh-5.2.10 distribution
-
-Mon Oct  7 16:23:53 NDT 1996 Michael Rendell (michael at 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 at 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 at panda.cs.mun.ca)
-
-	* made pdksh-5.2.9 distribution
-
-Mon Sep 30 12:52:21 NDT 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* lex.c(pprompt): fixed usage of ntruncate.
-
-Thu Sep 19 17:43:33 NDT 1996 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* configure.in: fixed quoting of sed LDSTATIC expression.
-
-Mon Aug 19 14:26:08 NDT 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* made pdksh-5.2.8 distribution
-
-Mon Aug 19 11:38:16 NDT 1996 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* exec.c(findfunc): removed redundant DEFINED check after tsearch().
-
-Fri Aug  9 22:16:21 NDT 1996 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* c_test.c(b_ops[]): added "==" entry (ksh93ism).
-
-Mon Jun 10 14:00:21  1996 Michael Rendell (michael at 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 at 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 at panda.cs.mun.ca)
-
-	* made pdksh-5.2.6 distribution
-
-Sun Jun  2 11:46:56 NDT 1996 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* made pdksh-5.2.5 distribution
-
-Tue May  7 11:45:37 NDT 1996 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* siglist.in: added WAITING,LWP,FREEZE,THAW,CANCEL
-
-Thu Mar  7 23:26:37 NST 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* edit.c(x_init): set LINES if possible.
-
-Thu Mar  7 23:01:55 NST 1996 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* tree.c(ptree): add case for TSELECT.
-
-Wed Mar  6 12:40:34 NST 1996 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* vi.c(vi_cmd,classify[]): made ^I a command.
-
-Fri Feb  2 10:40:32 NST 1996 Michael Rendell (michael at 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 at panda.cs.mun.ca)
-
-	* c_test.h(Test_env): added end union.
-	* c_test.c(c_test): keep track of end position 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* sh.h(ksh_jmp_buf): new define.
-
-Thu Jan 18 15:03:19 NST 1996 Michael Rendell (michael at panda.cs.mun.ca)
-
-	* history.c(hist_replace): fixed substitution code (again).
-
-Wed Jan 17 20:10:02 NST 1996 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* emacs.c(iscfs): make ', " separators.
-	  (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 at 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 at garfield.cs.mun.ca)
-
-	* c_ksh.c(c_typeset): separate 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 at panda.cs.mun.ca)
-
-	* vi.c(globstr): deleted ifdef'd out code.
-
-Sun Dec 10 11:07:52 NST 1995 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at angel.cs.mun.ca)
-
-	* main.c(shell): do not zero exstat at start of routine.
-
-	* exec.c(execute): removed redundant "exstat = rv" before
-	  unwind(LERROR).
-
-Thu Nov  9 15:01:54 NST 1995 Michael Rendell (michael at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at panda.cs.mun.ca)
-
-	* main.c(initcoms[]): added EXTRA_INITCOMS.
-
-Fri Jun 16 12:33:10 NDT 1995 Michael Rendell (michael at 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 #.
-
--- bin/ksh/NEWS
+++ /dev/null
@@ -1,662 +0,0 @@
-Version 5.2.14
-
-* bug fixes
-    * test: -nt(-ot) now succeed if second (first) file doesn't exist and the
-      other does.
-    * time: now accepts the -p (posix) option.
-    * vi: failed redo (.) commands no longer return the line to the shell.
-    * emacs: bind commands in .profile/$ENV no longer overridden by tty
-      settings.
-    * heredocs: now saved in memory to avoid temp files disappear too soon.
-    * time: commands at the end of a pipeline can now be timed.
-    * on startup: MAILCHECK,TMOUT,SECONDS values from environment are honoured.
-    * trap: exit traps now executed in subshells (without explicit exit call).
-    * eval: if given empty command while in non-posix mode, exit status is
-      that of last command substitution (if any).
-    * trap: if first argument is "exit", it is taken as a command not a signal.
-    * pwd: config test & code to work around bug in hpux 10.x getcwd().
-    * RANDOM: seed based on both time and pid; different sequence in sub shells.
-    * typeset -f: now pretty-prints $(..) and $((..)) correctly.
-    * fixed bug in memory allocation which can lead to core dumps.
-    * set -o: no longer prints options that have no names.
-    * emacs: <esc>. in very fist command no longer dumps core.
-    * .: can now dot non-regular files (eg, /dev/null).
-    * parsing: bar(); no longer dumps core when function bar is run.
-    * variable substitution: ${#array[*]} now prints number of set elements
-      in the array (used to print largest index, not what ksh88 did).
-    * job control: resuming suspended gnu su no longer hoses su'd shell.
-    * job control: fixed possible core dump when waiting for jobs.
-
-* LINENO variable now supported.
-* port to cygwin environment on win95/winnt.
-
-
-Version 5.2.13
-
-* bug fixes
-    * functions: $0 in sh-style functions is now the same as the shell's $0.
-    * .: fixed possible core dump on clean up.
-    * test: a lone -t argument now does a isatty(1) test if not in posix mode.
-    * alias: PS2 no longer printed when expanding alias foo="cmd; ".
-    * set/typeset/getopts: can have options prefixed with both + and -.
-    * typeset -f: now reproduces functions correctly ("function F" vs "F()").
-    * alias: options can start with +.
-    * set -A: a -- marking end of options is now skipped.
-    * errexit option (-e) ignored when reading profile and $ENV files.
-    * test: '-x f' now fails for root if f is a file and has no x bits set.
-    * $_: set to last arg in interactive shells only.
-    * PATH: if $PATH not set on startup, it is set to the default path.
-    * extended globbing: allow (pat|pat) within @(...) and ${foo#...} patterns.
-    * emacs: ^[_ now behaves as it does in at&t ksh (word from _last_ command).
-    * MAIL/MAILCHECK: fixed bug that prevented the `new mail' messages.
-    * ${..%..} and ${..#..} now work if compiled as sh.
-    * sh: fd's greater than 2 are passed on to executed commands.
-    * syntax: accepts "if (( 1 )) then" (also [[ ]]): no ; required before then.
-    * substitution: accepts (and ignores) leading : in %, %%, #, ## substitions.
-    * .: doting directories no longer allowed.
-    * editing: completion after "cmd " now completes files (was command).
-
-
-$OpenBSD: NEWS,v 1.13 2003/10/22 07:40:38 jmc 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 trapped 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. Compatible with at&t ksh.
-
-* command line and set option parsing cleaned up, POSIXized.
-
-* POSIX IFS handling.
-
-* many many small bug fixes (see ChangeLog)
--- bin/ksh/lex.c
+++ /dev/null
@@ -1,1624 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/lex.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: lex.c,v 1.42 2006/07/10 17:12:41 beck Exp $	*/
-
-/*
- * lexical analysis and source input
- */
-
-#include "sh.h"
-#include <libgen.h>
-#include <ctype.h>
-#include <time.h>
-
-/* Structure to keep track of the lexing state and the various pieces of info
- * needed for each particular state.
- */
-typedef struct lex_state Lex_state;
-struct lex_state {
-	int ls_state;
-	union {
-		/* $(...) */
-		struct scsparen_info {
-			int nparen;	/* count open parenthesis */
-			int csstate;	/* XXX remove */
-#define ls_scsparen ls_info.u_scsparen
-		} u_scsparen;
-
-		/* $((...)) */
-		struct sasparen_info {
-			int nparen;	/* count open parenthesis */
-			int start;	/* marks start of $(( in output str */
-#define ls_sasparen ls_info.u_sasparen
-		} u_sasparen;
-
-		/* ((...)) */
-		struct sletparen_info {
-			int nparen;	/* count open parenthesis */
-#define ls_sletparen ls_info.u_sletparen
-		} u_sletparen;
-
-		/* `...` */
-		struct sbquote_info {
-			int indquotes;	/* true if in double quotes: "`...`" */
-#define ls_sbquote ls_info.u_sbquote
-		} u_sbquote;
-
-		Lex_state *base;	/* used to point to next state block */
-	} ls_info;
-};
-
-typedef struct State_info State_info;
-struct State_info {
-	Lex_state	*base;
-	Lex_state	*end;
-};
-
-
-static void	readhere(struct ioword *);
-static int	getsc__(void);
-static void	getsc_line(Source *);
-static int	getsc_bn(void);
-static char	*get_brace_var(XString *, char *);
-static int	arraysub(char **);
-static const char *ungetsc(int);
-static void	gethere(void);
-static Lex_state *push_state_(State_info *, Lex_state *);
-static Lex_state *pop_state_(State_info *, Lex_state *);
-static char	*special_prompt_expand(char *);
-static int	dopprompt(const char *, int, const char **, int);
-
-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__())
-
-#define STATE_BSIZE	32
-
-#define PUSH_STATE(s)	do { \
-			    if (++statep == state_info.end) \
-				statep = push_state_(&state_info, statep); \
-			    state = statep->ls_state = (s); \
-			} while (0)
-
-#define POP_STATE()	do { \
-			    if (--statep == state_info.base) \
-				statep = pop_state_(&state_info, statep); \
-			    state = statep->ls_state; \
-			} while (0)
-
-
-
-/*
- * 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(int cf)
-{
-	Lex_state states[STATE_BSIZE], *statep;
-	State_info state_info;
-	int c, state;
-	XString ws;		/* expandable output word */
-	char *wp;		/* output word pointer */
-	char *sp, *dp;
-	int c2;
-
-
-  Again:
-	states[0].ls_state = -1;
-	states[0].ls_info.base = (Lex_state *) 0;
-	statep = &states[1];
-	state_info.base = states;
-	state_info.end = &states[STATE_BSIZE];
-
-	Xinit(ws, wp, 64, ATEMP);
-
-	backslash_skip = 0;
-	ignore_backslash_newline = 0;
-
-	if (cf&ONEWORD)
-		state = SWORD;
-	else if (cf&LETEXPR) {
-		*wp++ = OQUOTE;	 /* enclose arguments in (double) quotes */
-		state = SLETPAREN;
-		statep->ls_sletparen.nparen = 0;
-	} else {		/* normal lexing */
-		state = (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;
-	}
-
-	/* Initial state: one of SBASE SHEREDELIM SWORD SASPAREN */
-	statep->ls_state = state;
-
-	/* collect non-special or quoted characters to form word */
-	while (!((c = getsc()) == 0 ||
-	    ((state == SBASE || state == SHEREDELIM) && ctype(c, C_LEX1)))) {
-		Xcheck(ws, wp);
-		switch (state) {
-		case SBASE:
-			if (Flag(FCSHHISTORY) && (source->flags & SF_TTY) &&
-			    c == '!') {
-				char **replace = NULL;
-
-				c2 = getsc();
-				if (c2 == '\0')
-					;
-				else if (c2 == ' ' || c2 == '\t')
-					ungetsc(c2);
-				else if (c2 == '!')
-					replace = hist_get_newest(0);
-				else if (isdigit(c2) || c2 == '-' ||
-				    isalpha(c2)) {
-					int get = !isalpha(c2);
-					char match[200], *str = match;
-
-					*str++ = c2;
-					do {
-						if ((c2 = getsc()) == '\0')
-							break;
-						if (c2 == '\t' || c2 == ' ' ||
-						    c2 == '\n') {
-							ungetsc(c2);
-							break;
-						}
-						*str++ = c2;
-					} while (str < &match[sizeof(match)-1]);
-					*str = '\0';
-
-					if (get) {
-						int h = findhistrel(match);
-						if (h >= 0)
-							replace = &history[h];
-					} else {
-						int h = findhist(-1, 0, match, true);
-						if (h >= 0)
-							replace = &history[h];
-					}
-				}
-
-				/*
-				 * XXX ksh history buffer saves un-expanded
-				 * commands. Until the history buffer code is
-				 * changed to contain expanded commands, we
-				 * ignore the bad commands (spinning sucks)
-				 */
-				if (replace && **replace == '!')
-					ungetsc(c2);
-				else if (replace) {
-					Source *s;
-
-					/* do not strdup replacement via alloc */
-					s = pushs(SREREAD, source->areap);
-					s->start = s->str = *replace;
-					s->next = source;
-					s->u.freeme = NULL;
-					source = s;
-					continue;
-				} else
-					ungetsc(c2);
-			}
-			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;
-			}
-			/* FALLTHROUGH */
-		  Sbase1:	/* includes *(...|...) pattern (*+?@!) */
-			if (c == '*' || c == '@' || c == '+' || c == '?' ||
-			    c == '!') {
-				c2 = getsc();
-				if (c2 == '(' /*)*/ ) {
-					*wp++ = OPAT;
-					*wp++ = c;
-					PUSH_STATE(SPATTERN);
-					break;
-				}
-				ungetsc(c2);
-			}
-			/* FALLTHROUGH */
-		  Sbase2:	/* doesn't include *(...|...) pattern (*+?@!) */
-			switch (c) {
-			case '\\':
-				c = getsc();
-				if (c) /* trailing \ is lost */
-					*wp++ = QCHAR, *wp++ = c;
-				break;
-			case '\'':
-				*wp++ = OQUOTE;
-				ignore_backslash_newline++;
-				PUSH_STATE(SSQUOTE);
-				break;
-			case '"':
-				*wp++ = OQUOTE;
-				PUSH_STATE(SDQUOTE);
-				break;
-			default:
-				goto Subst;
-			}
-			break;
-
-		  Subst:
-			switch (c) {
-			case '\\':
-				c = getsc();
-				switch (c) {
-				case '\\':
-				case '$': case '`':
-					*wp++ = QCHAR, *wp++ = c;
-					break;
-				case '"':
-					if ((cf & HEREDOC) == 0) {
-						*wp++ = QCHAR, *wp++ = c;
-						break;
-					}
-					/* FALLTROUGH */
-				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 == '(') /*)*/ {
-						PUSH_STATE(SASPAREN);
-						statep->ls_sasparen.nparen = 2;
-						statep->ls_sasparen.start =
-						    Xsavepos(ws, wp);
-						*wp++ = EXPRSUB;
-					} else {
-						ungetsc(c);
-						PUSH_STATE(SCSPAREN);
-						statep->ls_scsparen.nparen = 1;
-						statep->ls_scsparen.csstate = 0;
-						*wp++ = COMSUB;
-					}
-				} else if (c == '{') /*}*/ {
-					*wp++ = OSUBST;
-					*wp++ = '{'; /*}*/
-					wp = get_brace_var(&ws, wp);
-					c = getsc();
-					/* allow :# and :% (ksh88 compat) */
-					if (c == ':') {
-						*wp++ = CHAR, *wp++ = c;
-						c = getsc();
-					}
-					/* If this is a trim operation,
-					 * treat (,|,) specially in STBRACE.
-					 */
-					if (c == '#' || c == '%') {
-						ungetsc(c);
-						PUSH_STATE(STBRACE);
-					} else {
-						ungetsc(c);
-						PUSH_STATE(SBRACE);
-					}
-				} else if (ctype(c, C_ALPHA)) {
-					*wp++ = OSUBST;
-					*wp++ = 'X';
-					do {
-						Xcheck(ws, wp);
-						*wp++ = c;
-						c = getsc();
-					} while (ctype(c, C_ALPHA|C_DIGIT));
-					*wp++ = '\0';
-					*wp++ = CSUBST;
-					*wp++ = 'X';
-					ungetsc(c);
-				} else if (ctype(c, C_DIGIT|C_VAR1)) {
-					Xcheck(ws, wp);
-					*wp++ = OSUBST;
-					*wp++ = 'X';
-					*wp++ = c;
-					*wp++ = '\0';
-					*wp++ = CSUBST;
-					*wp++ = 'X';
-				} else {
-					*wp++ = CHAR, *wp++ = '$';
-					ungetsc(c);
-				}
-				break;
-			case '`':
-				PUSH_STATE(SBQUOTE);
-				*wp++ = COMSUB;
-				/* Need to know if we are inside double quotes
-				 * since sh/at&t-ksh translate the \" to " in
-				 * "`..\"..`".
-				 * This is not done in posix mode (section
-				 * 3.2.3, Double Quotes: "The backquote shall
-				 * retain its special meaning introducing the
-				 * other form of command substitution (see
-				 * 3.6.3). The portion of the quoted string
-				 * from the initial backquote and the
-				 * characters up to the next backquote that
-				 * is not preceded by a backslash (having
-				 * escape characters removed) defines that
-				 * command whose output replaces `...` when
-				 * the word is expanded."
-				 * Section 3.6.3, Command Substitution:
-				 * "Within the backquoted style of command
-				 * substitution, backslash shall retain its
-				 * literal meaning, except when followed by
-				 * $ ` \.").
-				 */
-				statep->ls_sbquote.indquotes = 0;
-				if (!Flag(FPOSIX)) {
-					Lex_state *s = statep;
-					Lex_state *base = state_info.base;
-					while (1) {
-						for (; s != base; s--) {
-							if (s->ls_state == SDQUOTE) {
-								statep->ls_sbquote.indquotes = 1;
-								break;
-							}
-						}
-						if (s != base)
-							break;
-						if (!(s = s->ls_info.base))
-							break;
-						base = s-- - STATE_BSIZE;
-					}
-				}
-				break;
-			default:
-				*wp++ = CHAR, *wp++ = c;
-			}
-			break;
-
-		case SSQUOTE:
-			if (c == '\'') {
-				POP_STATE();
-				*wp++ = CQUOTE;
-				ignore_backslash_newline--;
-			} else
-				*wp++ = QCHAR, *wp++ = c;
-			break;
-
-		case SDQUOTE:
-			if (c == '"') {
-				POP_STATE();
-				*wp++ = CQUOTE;
-			} else
-				goto Subst;
-			break;
-
-		case SCSPAREN: /* $( .. ) */
-			/* 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 (statep->ls_scsparen.csstate) {
-			case 0: /* normal */
-				switch (c) {
-				case '(':
-					statep->ls_scsparen.nparen++;
-					break;
-				case ')':
-					statep->ls_scsparen.nparen--;
-					break;
-				case '\\':
-					statep->ls_scsparen.csstate = 1;
-					break;
-				case '"':
-					statep->ls_scsparen.csstate = 2;
-					break;
-				case '\'':
-					statep->ls_scsparen.csstate = 4;
-					ignore_backslash_newline++;
-					break;
-				}
-				break;
-
-			case 1: /* backslash in normal mode */
-			case 3: /* backslash in double quotes */
-				--statep->ls_scsparen.csstate;
-				break;
-
-			case 2: /* double quotes */
-				if (c == '"')
-					statep->ls_scsparen.csstate = 0;
-				else if (c == '\\')
-					statep->ls_scsparen.csstate = 3;
-				break;
-
-			case 4: /* single quotes */
-				if (c == '\'') {
-					statep->ls_scsparen.csstate = 0;
-					ignore_backslash_newline--;
-				}
-				break;
-			}
-			if (statep->ls_scsparen.nparen == 0) {
-				POP_STATE();
-				*wp++ = 0; /* end of COMSUB */
-			} else
-				*wp++ = c;
-			break;
-
-		case SASPAREN: /* $(( .. )) */
-			/* todo: deal with $((...); (...)) properly */
-			/* XXX should nest using existing state machine
-			 * (embed "..", $(...), etc.) */
-			if (c == '(')
-				statep->ls_sasparen.nparen++;
-			else if (c == ')') {
-				statep->ls_sasparen.nparen--;
-				if (statep->ls_sasparen.nparen == 1) {
-					/*(*/
-					if ((c2 = getsc()) == ')') {
-						POP_STATE();
-						*wp++ = 0; /* end of EXPRSUB */
-						break;
-					} else {
-						char *s;
-
-						ungetsc(c2);
-						/* mismatched parenthesis -
-						 * assume we were really
-						 * parsing a $(..) expression
-						 */
-						s = Xrestpos(ws, wp,
-						    statep->ls_sasparen.start);
-						memmove(s + 1, s, wp - s);
-						*s++ = COMSUB;
-						*s = '('; /*)*/
-						wp++;
-						statep->ls_scsparen.nparen = 1;
-						statep->ls_scsparen.csstate = 0;
-						state = statep->ls_state =
-						    SCSPAREN;
-					}
-				}
-			}
-			*wp++ = c;
-			break;
-
-		case SBRACE:
-			/*{*/
-			if (c == '}') {
-				POP_STATE();
-				*wp++ = CSUBST;
-				*wp++ = /*{*/ '}';
-			} else
-				goto Sbase1;
-			break;
-
-		case STBRACE:
-			/* Same as SBRACE, except (,|,) treated specially */
-			/*{*/
-			if (c == '}') {
-				POP_STATE();
-				*wp++ = CSUBST;
-				*wp++ = /*{*/ '}';
-			} else if (c == '|') {
-				*wp++ = SPAT;
-			} else if (c == '(') {
-				*wp++ = OPAT;
-				*wp++ = ' ';	/* simile for @ */
-				PUSH_STATE(SPATTERN);
-			} else
-				goto Sbase1;
-			break;
-
-		case SBQUOTE:
-			if (c == '`') {
-				*wp++ = 0;
-				POP_STATE();
-			} else if (c == '\\') {
-				switch (c = getsc()) {
-				case '\\':
-				case '$': case '`':
-					*wp++ = c;
-					break;
-				case '"':
-					if (statep->ls_sbquote.indquotes) {
-						*wp++ = c;
-						break;
-					}
-					/* FALLTHROUGH */
-				default:
-					if (c) { /* trailing \ is lost */
-						*wp++ = '\\';
-						*wp++ = c;
-					}
-					break;
-				}
-			} else
-				*wp++ = c;
-			break;
-
-		case SWORD:	/* ONEWORD */
-			goto Subst;
-
-		case SLETPAREN:	/* LETEXPR: (( ... )) */
-			/*(*/
-			if (c == ')') {
-				if (statep->ls_sletparen.nparen > 0)
-				    --statep->ls_sletparen.nparen;
-				/*(*/
-				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
-				 */
-				++statep->ls_sletparen.nparen;
-			goto Sbase2;
-
-		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 == '\'') {
-				PUSH_STATE(SSQUOTE);
-				*wp++ = OQUOTE;
-				ignore_backslash_newline++;
-			} else if (c == '"') {
-				state = statep->ls_state = SHEREDQUOTE;
-				*wp++ = OQUOTE;
-			} else {
-				*wp++ = CHAR;
-				*wp++ = c;
-			}
-			break;
-
-		case SHEREDQUOTE:	/* " in <<,<<- delimiter */
-			if (c == '"') {
-				*wp++ = CQUOTE;
-				state = statep->ls_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;
-				POP_STATE();
-			} else if (c == '|') {
-				*wp++ = SPAT;
-			} else if (c == '(') {
-				*wp++ = OPAT;
-				*wp++ = ' ';	/* simile for @ */
-				PUSH_STATE(SPATTERN);
-			} else
-				goto Sbase1;
-			break;
-		}
-	}
-Done:
-	Xcheck(ws, wp);
-	if (statep != &states[1])
-		/* XXX figure out what is missing */
-		yyerror("no closing quote\n");
-
-	/* This done to avoid tests for SHEREDELIM wherever SBASE tested */
-	if (state == SHEREDELIM)
-		state = SBASE;
-
-	dp = Xstring(ws, wp);
-	if ((c == '<' || c == '>') && state == SBASE &&
-	    ((c2 = Xlength(ws, wp)) == 0 ||
-	    (c2 == 2 && dp[0] == CHAR && digit(dp[1])))) {
-		struct ioword *iop = (struct ioword *) alloc(sizeof(*iop), ATEMP);
-
-		if (c2 == 2)
-			iop->unit = dp[1] - '0';
-		else
-			iop->unit = c == '>'; /* 0 for <, 1 for > */
-
-		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;
-		iop->heredoc = (char *) 0;
-		Xfree(ws, wp);	/* free word */
-		yylval.iop = iop;
-		return REDIR;
-	}
-
-	if (wp == dp && 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;
-			else if (c == '|' && c2 == '&')
-				c = COPROC;
-			else
-				ungetsc(c2);
-			return c;
-
-		case '\n':
-			gethere();
-			if (cf & CONTIN)
-				goto Again;
-			return c;
-
-		case '(':  /*)*/
-			if (!Flag(FSH)) {
-				if ((c2 = getsc()) == '(') /*)*/
-					/* XXX need to handle ((...); (...)) */
-					c = MDPAREN;
-				else
-					ungetsc(c2);
-			}
-			return c;
-		  /*(*/
-		case ')':
-			return c;
-		}
-	}
-
-	*wp++ = EOS;		/* terminate word */
-	yylval.cp = Xclose(ws, wp);
-	if (state == SWORD || state == SLETPAREN)	/* 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' padded */
-	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 = ktsearch(&keywords, ident, h)) &&
-		    (!(cf & ESACONLY) || p->val.i == ESAC || p->val.i == '}')) {
-			afree(yylval.cp, ATEMP);
-			return p->val.i;
-		}
-		if ((cf & ALIAS) && (p = ktsearch(&aliases, ident, h)) &&
-		    (p->flag & ISSET)) {
-			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(void)
-{
-	struct ioword **p;
-
-	for (p = heres; p < herep; p++)
-		readhere(*p);
-	herep = heres;
-}
-
-/*
- * read "<<word" text into temp file
- */
-
-static void
-readhere(struct ioword *iop)
-{
-	int c;
-	char *volatile eof;
-	char *eofp;
-	int skiptabs;
-	XString xs;
-	char *xp;
-	int xpos;
-
-	eof = evalstr(iop->delim, 0);
-
-	if (!(iop->flag & IOEVAL))
-		ignore_backslash_newline++;
-
-	Xinit(xs, xp, 256, ATEMP);
-
-	for (;;) {
-		eofp = eof;
-		skiptabs = iop->flag & IOSKIP;
-		xpos = Xsavepos(xs, xp);
-		while ((c = getsc()) != 0) {
-			if (skiptabs) {
-				if (c == '\t')
-					continue;
-				skiptabs = 0;
-			}
-			if (c != *eofp)
-				break;
-			Xcheck(xs, xp);
-			Xput(xs, xp, c);
-			eofp++;
-		}
-		/* Allow EOF here so commands with out trailing newlines
-		 * will work (eg, ksh -c '...', $(...), etc).
-		 */
-		if (*eofp == '\0' && (c == 0 || c == '\n')) {
-			xp = Xrestpos(xs, xp, xpos);
-			break;
-		}
-		ungetsc(c);
-		while ((c = getsc()) != '\n') {
-			if (c == 0)
-				yyerror("here document `%s' unclosed\n", eof);
-			Xcheck(xs, xp);
-			Xput(xs, xp, c);
-		}
-		Xcheck(xs, xp);
-		Xput(xs, xp, c);
-	}
-	Xput(xs, xp, '\0');
-	iop->heredoc = Xclose(xs, xp);
-
-	if (!(iop->flag & IOEVAL))
-		ignore_backslash_newline--;
-}
-
-void
-yyerror(const char *fmt, ...)
-{
-	va_list va;
-
-	/* pop aliases and re-reads */
-	while (source->type == SALIAS || source->type == SREREAD)
-		source = source->next;
-	source->str = null;	/* zap pending input */
-
-	error_prefix(true);
-	va_start(va, fmt);
-	shf_vfprintf(shl_out, fmt, va);
-	va_end(va);
-	errorf(null);
-}
-
-/*
- * input for yylex with alias expansion
- */
-
-Source *
-pushs(int type, Area *areap)
-{
-	Source *s;
-
-	s = (Source *) alloc(sizeof(Source), areap);
-	s->type = type;
-	s->str = null;
-	s->start = NULL;
-	s->line = 0;
-	s->cmd_offset = 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__(void)
-{
-	Source *s = source;
-	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(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;
-
-	if (have_tty && ksh_tmout) {
-		ksh_tmout_state = TMOUT_READING;
-		alarm(ksh_tmout);
-	}
-#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);
-		} 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 */
-		}
-		/* 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;
-	if (have_tty && ksh_tmout) {
-		ksh_tmout_state = TMOUT_EXECUTING;
-		alarm(0);
-	}
-	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) {
-			s->line++;
-			histsave(s->line, s->str, 1);
-		}
-#endif /* HISTORY */
-	}
-	if (interactive)
-		set_prompt(PS2, (Source *) 0);
-}
-
-static char *
-special_prompt_expand(char *str)
-{
-	char *p = str;
-
-	while ((p = strstr(p, "\\$")) != NULL) {
-		*(p+1) = 'p';
-	}
-	return str;
-}
-
-void
-set_prompt(int to, Source *s)
-{
-	char *ps1;
-	Area *saved_atemp;
-
-	cur_prompt = to;
-
-	switch (to) {
-	case PS1: /* command */
-		ps1 = str_save(str_val(global("PS1")), ATEMP);
-		saved_atemp = ATEMP;	/* ps1 is freed by substitute() */
-		newenv(E_ERRH);
-		if (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 {
-			/* expand \$ before other substitutions are done */
-			char *tmp = special_prompt_expand(ps1);
-			prompt = str_save(substitute(tmp, 0), saved_atemp);
-		}
-		quitenv(NULL);
-		break;
-	case PS2: /* command continuation */
-		prompt = str_val(global("PS2"));
-		break;
-	}
-}
-
-static int
-dopprompt(const char *sp, int ntruncate, const char **spp, int doprint)
-{
-	char strbuf[1024], tmpbuf[1024], *p, *str, nbuf[32], delimiter = '\0';
-	int len, c, n, totlen = 0, indelimit = 0, counting = 1, delimitthis;
-	const char *cp = sp;
-	struct tm *tm;
-	time_t t;
-
-	if (*cp && cp[1] == '\r') {
-		delimiter = *cp;
-		cp += 2;
-	}
-
-	while (*cp != 0) {
-		delimitthis = 0;
-		if (indelimit && *cp != delimiter)
-			;
-		else if (*cp == '\n' || *cp == '\r') {
-			totlen = 0;
-			sp = cp + 1;
-		} else if (*cp == '\t') {
-			if (counting)
-				totlen = (totlen | 7) + 1;
-		} else if (*cp == delimiter) {
-			indelimit = !indelimit;
-			delimitthis = 1;
-		}
-
-		if (*cp == '\\') {
-			cp++;
-			if (!*cp)
-				break;
-			if (Flag(FSH))
-				snprintf(strbuf, sizeof strbuf, "\\%c", *cp);
-			else switch (*cp) {
-			case 'a':	/* '\' 'a' bell */
-				strbuf[0] = '\007';
-				strbuf[1] = '\0';
-				break;
-			case 'd':	/* '\' 'd' Dow Mon DD */
-				time(&t);
-				tm = localtime(&t);
-				strftime(strbuf, sizeof strbuf, "%a %b %d", tm);
-				break;
-			case 'D': /* '\' 'D' '{' strftime format '}' */
-				p = strchr(cp + 2, '}');
-				if (cp[1] != '{' || p == NULL) {
-					snprintf(strbuf, sizeof strbuf,
-					    "\\%c", *cp);
-					break;
-				}
-				strlcpy(tmpbuf, cp + 2, sizeof tmpbuf);
-				p = strchr(tmpbuf, '}');
-				if (p)
-					*p = '\0';
-				time(&t);
-				tm = localtime(&t);
-				strftime(strbuf, sizeof strbuf, tmpbuf, tm);
-				cp = strchr(cp + 2, '}');
-				break;
-			case 'e':	/* '\' 'e' escape */
-				strbuf[0] = '\033';
-				strbuf[1] = '\0';
-				break;
-			case 'h':	/* '\' 'h' shortened hostname */
-				gethostname(strbuf, sizeof strbuf);
-				p = strchr(strbuf, '.');
-				if (p)
-					*p = '\0';
-				break;
-			case 'H':	/* '\' 'H' full hostname */
-				gethostname(strbuf, sizeof strbuf);
-				break;
-			case 'j':	/* '\' 'j' number of jobs */
-				snprintf(strbuf, sizeof strbuf, "%d",
-				    j_njobs());
-				break;
-			case 'l':	/* '\' 'l' basename of tty */
-				p = ttyname(0);
-				if (p)
-					p = basename(p);
-				if (p)
-					strlcpy(strbuf, p, sizeof strbuf);
-				break;
-			case 'n':	/* '\' 'n' newline */
-				strbuf[0] = '\n';
-				strbuf[1] = '\0';
-				totlen = 0;	/* reset for prompt re-print */
-				sp = cp + 1;
-				break;
-			case 'p':	/* '\' '$' $ or # */
-				strbuf[0] = ksheuid ? '$' : '#';
-				strbuf[1] = '\0';
-				break;
-			case 'r':	/* '\' 'r' return */
-				strbuf[0] = '\r';
-				strbuf[1] = '\0';
-				totlen = 0;	/* reset for prompt re-print */
-				sp = cp + 1;
-				break;
-			case 's':	/* '\' 's' basename $0 */
-				strlcpy(strbuf, kshname, sizeof strbuf);
-				break;
-			case 't':	/* '\' 't' 24 hour HH:MM:SS */
-				time(&t);
-				tm = localtime(&t);
-				strftime(strbuf, sizeof strbuf, "%T", tm);
-				break;
-			case 'T':	/* '\' 'T' 12 hour HH:MM:SS */
-				time(&t);
-				tm = localtime(&t);
-				strftime(strbuf, sizeof strbuf, "%l:%M:%S", tm);
-				break;
-			case '@':	/* '\' '@' 12 hour am/pm format */
-				time(&t);
-				tm = localtime(&t);
-				strftime(strbuf, sizeof strbuf, "%r", tm);
-				break;
-			case 'A':	/* '\' 'A' 24 hour HH:MM */
-				time(&t);
-				tm = localtime(&t);
-				strftime(strbuf, sizeof strbuf, "%R", tm);
-				break;
-			case 'u':	/* '\' 'u' username */
-				strlcpy(strbuf, username, sizeof strbuf);
-				break;
-			case 'v':	/* '\' 'v' version (short) */
-				p = strchr(ksh_version, ' ');
-				if (p)
-					p = strchr(p + 1, ' ');
-				if (p) {
-					p++;
-					strlcpy(strbuf, p, sizeof strbuf);
-					p = strchr(strbuf, ' ');
-					if (p)
-						*p = '\0';
-				}
-				break;
-			case 'V':	/* '\' 'V' version (long) */
-				strlcpy(strbuf, ksh_version, sizeof strbuf);
-				break;
-			case 'w':	/* '\' 'w' cwd */
-				p = str_val(global("PWD"));
-				n = strlen(str_val(global("HOME")));
-				if (strcmp(p, "/") == 0) {
-					strlcpy(strbuf, p, sizeof strbuf);
-				} else if (strcmp(p, str_val(global("HOME"))) == 0) {
-					strbuf[0] = '~';
-					strbuf[1] = '\0';
-				} else if (strncmp(p, str_val(global("HOME")), n)
-				    == 0 && p[n] == '/') {
-					snprintf(strbuf, sizeof strbuf, "~/%s",
-					    str_val(global("PWD")) + n + 1);
-				} else
-					strlcpy(strbuf, p, sizeof strbuf);
-				break;
-			case 'W':	/* '\' 'W' basename(cwd) */
-				p = str_val(global("PWD"));
-				strlcpy(strbuf, basename(p), sizeof strbuf);
-				break;
-			case '!':	/* '\' '!' history line number */
-				snprintf(strbuf, sizeof strbuf, "%d",
-				    source->line + 1);
-				break;
-			case '#':	/* '\' '#' command line number */
-				snprintf(strbuf, sizeof strbuf, "%d",
-				    source->line - source->cmd_offset + 1);
-				break;
-			case '0':	/* '\' '#' '#' ' #' octal numeric handling */
-			case '1':
-			case '2':
-			case '3':
-			case '4':
-			case '5':
-			case '6':
-			case '7':
-				if ((cp[1] > '7' || cp[1] < '0') ||
-				    (cp[2] > '7' || cp[2] < '0')) {
-					snprintf(strbuf, sizeof strbuf,
-					    "\\%c", *cp);
-					break;
-				}
-				n = cp[0] * 8 * 8 + cp[1] * 8 + cp[2];
-				snprintf(strbuf, sizeof strbuf, "%c", n);
-				cp += 2;
-				break;
-			case '\\':	/* '\' '\' */
-				strbuf[0] = '\\';
-				strbuf[1] = '\0';
-				break;
-			case '[': /* '\' '[' .... stop counting */
-				strbuf[0] = '\0';
-				counting = 0;
-				break;
-			case ']': /* '\' ']' restart counting */
-				strbuf[0] = '\0';
-				counting = 1;
-				break;
-
-			default:
-				snprintf(strbuf, sizeof strbuf, "\\%c", *cp);
-				break;
-			}
-			cp++;
-
-			str = strbuf;
-			len = strlen(str);
-			if (ntruncate) {
-				if (ntruncate >= len) {
-					ntruncate -= len;
-					continue;
-				}
-				str += ntruncate;
-				len -= ntruncate;
-				ntruncate = 0;
-			}
-			if (doprint)
-				shf_write(str, len, shl_out);
-			if (counting && !indelimit && !delimitthis)
-				totlen += len;
-			continue;
-		} else if (*cp != '!')
-			c = *cp++;
-		else if (*++cp == '!')
-			c = *cp++;
-		else {
-			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;
-			}
-			if (doprint)
-				shf_write(p, len, shl_out);
-			if (counting && !indelimit && !delimitthis)
-				totlen += len;
-			continue;
-		}
-		if (counting && ntruncate)
-			--ntruncate;
-		else if (doprint) {
-			shf_putc(c, shl_out);
-		}
-		if (counting && !indelimit && !delimitthis)
-			totlen++;
-	}
-	if (doprint)
-		shf_flush(shl_out);
-	if (spp)
-		*spp = sp;
-	return (totlen);
-}
-
-void
-pprompt(const char *cp, int ntruncate)
-{
-	dopprompt(cp, ntruncate, NULL, 1);
-}
-
-int
-promptlen(const char *cp, const char **spp)
-{
-	return dopprompt(cp, 0, spp, 0);
-}
-
-/* Read the variable part of a ${...} expression (ie, up to but not including
- * the :[-+?=#%] or close-brace.
- */
-static char *
-get_brace_var(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;
-			}
-			/* FALLTHROUGH */
-		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(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(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(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;
-	}
-}
-
-static Lex_state *
-push_state_(State_info *si, Lex_state *old_end)
-{
-	Lex_state	*new = alloc(sizeof(Lex_state) * STATE_BSIZE, ATEMP);
-
-	new[0].ls_info.base = old_end;
-	si->base = &new[0];
-	si->end = &new[STATE_BSIZE];
-	return &new[1];
-}
-
-static Lex_state *
-pop_state_(State_info *si, Lex_state *old_end)
-{
-	Lex_state *old_base = si->base;
-
-	si->base = old_end->ls_info.base - STATE_BSIZE;
-	si->end = old_end->ls_info.base;
-
-	afree(old_base, ATEMP);
-
-	return si->base + STATE_BSIZE - 1;
-}
--- bin/ksh/expand.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/expand.h,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: expand.h,v 1.6 2005/03/30 17:16:37 deraadt Exp $	*/
-
-/*
- * Expanding strings
- */
-
-#define X_EXTRA		8	/* this many extra bytes in X string */
-
-#if 0				/* Usage */
-	XString xs;
-	char *xp;
-
-	Xinit(xs, xp, 128, ATEMP); /* allocate initial string */
-	while ((c = generate()) {
-		Xcheck(xs, xp);	/* expand string if necessary */
-		Xput(xs, xp, c); /* add character */
-	}
-	return Xclose(xs, xp);	/* resize string */
-/*
- * NOTE:
- *     The Xcheck and Xinit macros have a magic + X_EXTRA in the lengths.
- *     This is so that you can put up to X_EXTRA 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 + X_EXTRA, (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_(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 { \
-			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)
--- bin/ksh/vi.c
+++ /dev/null
@@ -1,2117 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/vi.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: vi.c,v 1.23 2006/04/10 14:38:59 jaredy 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 <sys/stat.h>		/* completion */
-#include "edit.h"
-
-#define CMDLEN		2048
-#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(int);
-static void	vi_reset(char *, size_t);
-static int	nextstate(int);
-static int	vi_insert(int);
-static int	vi_cmd(int, const char *);
-static int	domove(int, const char *, int);
-static int	redo_insert(int);
-static void	yank_range(int, int);
-static int	bracktype(int);
-static void	save_cbuf(void);
-static void	restore_cbuf(void);
-static void	edit_reset(char *, size_t);
-static int	putbuf(const char *, int, int);
-static void	del_range(int, int);
-static int	findch(int, int, int, int);
-static int	forwword(int);
-static int	backword(int);
-static int	endword(int);
-static int	Forwword(int);
-static int	Backword(int);
-static int	Endword(int);
-static int	grabhist(int, int);
-static int	grabsearch(int, int, int, char *);
-static void	redraw_line(int);
-static void	refresh(int);
-static int	outofwin(void);
-static void	rewindow(void);
-static int	newcol(int, int);
-static void	display(char *, char *, int);
-static void	ed_mov_opt(int, char *);
-static int	expand_word(int);
-static int	complete_word(int, int);
-static int	print_expansions(struct edstate *, int);
-static int	char_len(int);
-static void	x_vi_zotc(int);
-static void	vi_pprompt(int);
-static void	vi_error(void);
-static void	vi_macro_reset(void);
-static int	x_vi_putbuf(const char *, size_t);
-
-#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(struct edstate *old);
-static void		restore_edstate(struct edstate *old, struct edstate *new);
-static void		free_edstate(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(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 || len <= es->linelen)
-		return -1;
-
-	if (es->cbuf != buf)
-		memmove(buf, es->cbuf, es->linelen);
-
-	buf[es->linelen++] = '\n';
-
-	return es->linelen;
-}
-
-static int
-vi_hook(int ch)
-{
-	static char	curcmd[MAXVICMD], locpat[SRCHLEN];
-	static int	cmdlen, argc1, argc2;
-
-	switch (state) {
-
-	case VNORMAL:
-		if (insert != 0) {
-			if (ch == Ctrl('v')) {
-				state = VLIT;
-				ch = '^';
-			}
-			switch (vi_insert(ch)) {
-			case -1:
-				vi_error();
-				state = VNORMAL;
-				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) strlcpy(srchpat, locpat, sizeof srchpat);
-			}
-			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)) {
-					if (es->linelen + 2 > es->cbufsize)
-						vi_error();
-					es->cbuf[es->linelen++] = 'M';
-					es->cbuf[es->linelen++] = '-';
-					ch &= 0x7f;
-				}
-				if (ch < ' ' || ch == 0x7f) {
-					if (es->linelen + 2 > es->cbufsize)
-						vi_error();
-					es->cbuf[es->linelen++] = '^';
-					es->cbuf[es->linelen++] = ch ^ '@';
-				} else {
-					if (es->linelen >= es->cbufsize)
-						vi_error();
-					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)) {
-		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 - can't happen */
-			break;
-		}
-		break;
-
-	case VFAIL:
-		state = VNORMAL;
-		vi_error();
-		break;
-	}
-	return 0;
-}
-
-static void
-vi_reset(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(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(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) {
-	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(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 = ktsearch(&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;
-			/* FALLTHROUGH */
-		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 {
-				int	n;
-
-				if (es->cursor + argcnt > es->linelen)
-					return -1;
-				for (n = 0; n < argcnt; ++n)
-					es->cbuf[es->cursor + n] = cmd[1];
-				es->cursor += n - 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 && argcnt == 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;
-			/* FALLTHROUGH */
-		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(int argcnt, const char *cmd, int sub)
-{
-	int	bcount, i = 0, t;
-	int	ncursor = 0;
-
-	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(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(int a, int b)
-{
-	yanklen = b - a;
-	if (yanklen != 0)
-		memmove(ybuf, &es->cbuf[a], yanklen);
-}
-
-static int
-bracktype(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(void)
-{
-	memmove(holdbuf, es->cbuf, es->linelen);
-	holdlen = es->linelen;
-	holdbuf[holdlen] = '\0';
-}
-
-static void
-restore_cbuf(void)
-{
-	es->cursor = 0;
-	es->linelen = holdlen;
-	memmove(es->cbuf, holdbuf, holdlen);
-}
-
-/* return a new edstate */
-static struct edstate *
-save_edstate(struct edstate *old)
-{
-	struct edstate *new;
-
-	new = (struct edstate *)alloc(sizeof(struct edstate), APERM);
-	new->cbuf = alloc(old->cbufsize, APERM);
-	memcpy(new->cbuf, old->cbuf, old->linelen);
-	new->cbufsize = old->cbufsize;
-	new->linelen = old->linelen;
-	new->cursor = old->cursor;
-	new->winleft = old->winleft;
-	return new;
-}
-
-static void
-restore_edstate(struct edstate *new, struct edstate *old)
-{
-	memcpy(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(struct edstate *old)
-{
-	afree(old->cbuf, APERM);
-	afree((char *)old, APERM);
-}
-
-
-
-static void
-edit_reset(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;
-}
-
-/*
- * this is used for calling x_escape() in complete_word()
- */
-static int
-x_vi_putbuf(const char *s, size_t len)
-{
-	return putbuf(s, len, 0);
-}
-
-static int
-putbuf(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(int a, int b)
-{
-	if (es->linelen != b)
-		memmove(&es->cbuf[a], &es->cbuf[b], es->linelen - b);
-	es->linelen -= b - a;
-}
-
-static int
-findch(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(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(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(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(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(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(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(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(int save, int start, int 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 strcmp be strncmp? */
-		if (start != 0 && fwd && strcmp(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(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(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(void)
-{
-	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(void)
-{
-	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(int ch, int col)
-{
-	if (ch == '\t')
-		return (col | 7) + 1;
-	return col + char_len(ch);
-}
-
-static void
-display(char *wb1, char *wb2, int leftside)
-{
-	unsigned char ch;
-	char	*twb1, *twb2, mc;
-	int	cur, col, cnt;
-	int	ncol = 0;
-	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(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(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 (x_escape(words[i], strlen(words[i]), x_vi_putbuf) != 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(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 &&
-				    strcmp(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;
-
-	/* escape all shell-sensitive characters and put the result into
-	 * command buffer */
-	rval = x_escape(match, match_len, x_vi_putbuf);
-
-	if (rval == 0 && 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 && 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(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(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 weirdness */
-static void
-x_vi_zotc(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(int full)
-{
-	pprompt(prompt + (full ? 0 : prompt_skip), prompt_trunc);
-}
-
-static void
-vi_error(void)
-{
-	/* Beem out of any macros as soon as an error occurs */
-	vi_macro_reset();
-	x_putc(BEL);
-	x_flush();
-}
-
-static void
-vi_macro_reset(void)
-{
-	if (macro.p) {
-		afree(macro.buf, APERM);
-		memset((char *) &macro, 0, sizeof(macro));
-	}
-}
-
-#endif	/* VI */
--- bin/ksh/c_ulimit.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/c_ulimit.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: c_ulimit.c,v 1.15 2006/03/12 00:26:58 deraadt Exp $	*/
-
-/*
-	ulimit -- handle "ulimit" builtin
-
-	Reworked to use getrusage() and ulimit() at once (as needed on
-	some schizophrenic 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 <sys/resource.h>
-
-#define SOFT	0x1
-#define HARD	0x2
-
-int
-c_ulimit(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 */
-		{ "time(cpu-seconds)", RLIMIT, RLIMIT_CPU, RLIMIT_CPU, 1, 't' },
-		{ "file(blocks)", RLIMIT, RLIMIT_FSIZE, RLIMIT_FSIZE, 512, 'f' },
-		{ "coredump(blocks)", RLIMIT, RLIMIT_CORE, RLIMIT_CORE, 512, 'c' },
-		{ "data(kbytes)", RLIMIT, RLIMIT_DATA, RLIMIT_DATA, 1024, 'd' },
-		{ "stack(kbytes)", RLIMIT, RLIMIT_STACK, RLIMIT_STACK, 1024, 's' },
-		{ "lockedmem(kbytes)", RLIMIT, RLIMIT_MEMLOCK, RLIMIT_MEMLOCK,
-		    1024, 'l' },
-		{ "memory(kbytes)", RLIMIT, RLIMIT_RSS, RLIMIT_RSS, 1024, 'm' },
-		{ "nofiles(descriptors)", RLIMIT, RLIMIT_NOFILE, RLIMIT_NOFILE,
-		    1, 'n' },
-		{ "processes", RLIMIT, RLIMIT_NPROC, RLIMIT_NPROC, 1, 'p' },
-	#ifdef RLIMIT_VMEM
-		{ "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' },
-	#endif /* RLIMIT_VMEM */
-		{ (char *) 0 }
-	};
-	static char	options[3 + NELEM(limits)];
-	rlim_t		val = 0;
-	int		how = SOFT | HARD;
-	const struct limits	*l;
-	int		set, all = 0;
-	int		optc, what;
-	struct rlimit	limit;
-	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)) != -1)
-		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) {
-		if (all || wp[1]) {
-			bi_errorf("too many arguments");
-			return 1;
-		}
-		if (strcmp(wp[0], "unlimited") == 0)
-			val = RLIM_INFINITY;
-		else {
-			long rval;
-
-			if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR, false))
-				return 1;
-			/* Avoid problems caused by typos that
-			 * evaluate misses due to evaluating unset
-			 * parameters to 0...
-			 * If this causes problems, will have to
-			 * add parameter to evaluate() to control
-			 * if unset params are 0 or an error.
-			 */
-			if (!rval && !digit(wp[0][0])) {
-				bi_errorf("invalid limit: %s", wp[0]);
-				return 1;
-			}
-			val = rval * l->factor;
-		}
-	}
-	if (all) {
-		for (l = limits; l->name; l++) {
-			if (l->which == RLIMIT) {
-				getrlimit(l->gcmd, &limit);
-				if (how & SOFT)
-					val = limit.rlim_cur;
-				else if (how & HARD)
-					val = limit.rlim_max;
-			}
-			shprintf("%-20s ", l->name);
-			if (val == RLIM_INFINITY)
-				shprintf("unlimited\n");
-			else {
-				val /= l->factor;
-				shprintf("%ld\n", (long) val);
-			}
-		}
-		return 0;
-	}
-	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) {
-				if (errno == EPERM)
-					bi_errorf("exceeds allowable limit");
-				else
-					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;
-		}
-	}
-	if (!set) {
-		if (val == RLIM_INFINITY)
-			shprintf("unlimited\n");
-		else {
-			val /= l->factor;
-			shprintf("%ld\n", (long) val);
-		}
-	}
-	return 0;
-}
--- bin/ksh/exec.c
+++ /dev/null
@@ -1,1416 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/exec.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: exec.c,v 1.46 2006/04/10 14:38:59 jaredy Exp $	*/
-
-/*
- * execute command tree
- */
-
-#include "sh.h"
-#include "c_test.h"
-#include <ctype.h>
-#include <sys/stat.h>
-
-/* Does ps4 get parameter substitutions done? */
-# define PS4_SUBSTITUTE(s)	substitute((s), 0)
-
-static int	comexec(struct op *, struct tbl *volatile, char **,
-		    int volatile);
-static void	scriptexec(struct op *, char **);
-static int	call_builtin(struct tbl *, char **);
-static int	iosetup(struct ioword *, struct tbl *);
-static int	herein(const char *, int);
-static char	*do_selectargs(char **, bool);
-static int	dbteste_isa(Test_env *, Test_meta);
-static const char *dbteste_getopnd(Test_env *, Test_op, int);
-static int	dbteste_eval(Test_env *, Test_op, const char *, const char *,
-		    int);
-static void	dbteste_error(Test_env *, int, const char *);
-
-
-/*
- * execute command tree
- */
-int
-execute(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 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 & ~XTIME, -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 c_eval()) and by c_set().
-		 */
-		subst_exstat = 0;
-
-		current_lineno = t->lineno;	/* for $LINENO */
-
-		/* POSIX says expand command words first, then redirections,
-		 * and assignments last..
-		 */
-		ap = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE);
-		if (flags & XTIME)
-			/* Allow option parsing (bizarre, but POSIX) */
-			timex_hook(t, &ap);
-		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);
-	}
-	flags &= ~XTIME;
-
-	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);
-		e->savefd[1] = savefd(1);
-		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;
-
-	case TCOPROC:
-	    {
-		sigset_t	omask;
-
-		/* Block sigchild as we are using things changed in the
-		 * signal handler
-		 */
-		sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-		e->type = E_ERRH;
-		i = sigsetjmp(e->jbuf, 0);
-		if (i) {
-			sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-			quitenv(NULL);
-			unwind(i);
-			/* NOTREACHED */
-		}
-		/* 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);
-		e->savefd[1] = savefd(1);
-
-		openpipe(pv);
-		if (pv[0] != 0) {
-			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;
-		}
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-		e->type = E_EXEC; /* no more need for error handler */
-
-		/* 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;
-	    }
-
-	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;
-
-	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;
-	    }
-
-	case TFOR:
-	case TSELECT:
-	    {
-		volatile bool is_first = true;
-		ap = (t->vars != NULL) ? eval(t->vars, DOBLANK|DOGLOB|DOTILDE) :
-		    e->loc->argv + 1;
-		e->type = E_LOOP;
-		while (1) {
-			i = sigsetjmp(e->jbuf, 0);
-			if (!i)
-				break;
-			if ((e->flags&EF_BRKCONT_PASS) ||
-			    (i != LBREAK && i != LCONTIN)) {
-				quitenv(NULL);
-				unwind(i);
-			} else if (i == LBREAK) {
-				rv = 0;
-				goto Break;
-			}
-		}
-		rv = 0; /* in case of a continue */
-		if (t->type == TFOR) {
-			while (*ap != NULL) {
-				setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
-				rv = execute(t->left, flags & XERROK);
-			}
-		} else { /* TSELECT */
-			for (;;) {
-				if (!(cp = do_selectargs(ap, is_first))) {
-					rv = 1;
-					break;
-				}
-				is_first = false;
-				setstr(global(t->str), cp, KSH_UNWIND_ERROR);
-				rv = execute(t->left, flags & XERROK);
-			}
-		}
-	    }
-		break;
-
-	case TWHILE:
-	case TUNTIL:
-		e->type = E_LOOP;
-		while (1) {
-			i = sigsetjmp(e->jbuf, 0);
-			if (!i)
-				break;
-			if ((e->flags&EF_BRKCONT_PASS) ||
-			    (i != LBREAK && i != LCONTIN)) {
-				quitenv(NULL);
-				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:
-		/* Clear XEXEC so nested execute() call doesn't exit
-		 * (allows "ls -l | time grep foo").
-		 */
-		rv = timex(t, flags & ~XEXEC);
-		break;
-
-	case TEXEC:		/* an eval'd TCOM */
-		s = t->args[0];
-		ap = makenv();
-		restoresigs();
-		cleanup_proc_env();
-		execve(t->str, t->args, ap);
-		if (errno == ENOEXEC)
-			scriptexec(t, ap);
-		else
-			errorf("%s: %s", s, strerror(errno));
-	}
-    Break:
-	exstat = rv;
-
-	quitenv(NULL);		/* restores IO */
-	if ((flags&XEXEC))
-		unwind(LEXIT);	/* exit child */
-	if (rv != 0 && !(flags & XERROK)) {
-		if (Flag(FERREXIT))
-			unwind(LERROR);
-		trapsig(SIGERR_);
-	}
-	return rv;
-}
-
-/*
- * execute simple command
- */
-
-static int
-comexec(struct op *t, struct tbl *volatile tp, char **ap, volatile int flags)
-{
-	int i;
-	volatile int rv = 0;
-	char *cp;
-	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;
-	int bourne_function_call = 0;
-
-	/* 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 script) -
-	 * perhaps save last arg here and set it in shell()?.
-	 */
-	if (!Flag(FSH) && Flag(FTALKING) && *(lastp = ap)) {
-		while (*++lastp)
-			;
-		/* setstr() can't fail here */
-		setstr(typeset("_", LOCAL, 0, INTEGER, 0), *--lastp,
-		    KSH_RETURN_ERROR);
-	}
-
-	/* 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)) {
-			bourne_function_call = 1;
-			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 (bourne_function_call && !(type_flags & EXPORT))
-			typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0);
-	}
-
-	if ((cp = *ap) == NULL) {
-		rv = subst_exstat;
-		goto Leave;
-	} else if (!tp) {
-		if (Flag(FRESTRICTED) && strchr(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];
-		else
-			ap[0] = (char *) kshname;
-		e->loc->argv = ap;
-		for (i = 0; *ap++ != NULL; i++)
-			;
-		e->loc->argc = i - 1;
-		/* ksh-style functions handle getopts sanely,
-		 * bourne/posix functions are insane...
-		 */
-		if (tp->flag & FKSH) {
-			e->loc->flags |= BF_DOGETOPTS;
-			e->loc->getopts_state = user_opt;
-			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 = 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(NULL);
-			unwind(i);
-			/* NOTREACHED */
-		default:
-			quitenv(NULL);
-			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() can't fail here */
-			setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0),
-			    tp->val.s, KSH_RETURN_ERROR);
-		}
-
-		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(struct op *tp, 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;
-	*tp->args = shell;
-
-	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(char **wp)
-{
-	struct tbl *tp;
-
-	tp = ktsearch(&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(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 = ktsearch(&l->funs, name, h);
-		if (tp)
-			break;
-		if (!l->next && create) {
-			tp = ktenter(&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(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 */
-		ktdelete(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(const char *name, int (*func) (char **))
-{
-	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 = ktenter(&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(const char *name, int flags)
-{
-	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 (strchr(name, '/') != NULL) {
-		insert = 0;
-		/* prevent FPATH search below */
-		flags &= ~FC_FUNC;
-		goto Search;
-	}
-	tbi = (flags & FC_BI) ? ktsearch(&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 = ktsearch(&taliases, name, h);
-		if (tp && (tp->flag & ISSET) && access(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 = ktenter(&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(int all)	/* just relative or all */
-{
-	struct tbl *tp;
-	struct tstate ts;
-
-	for (ktwalk(&ts, &taliases); (tp = ktnext(&ts)) != NULL; )
-		if ((tp->flag&ISSET) && (all || 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(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 = access(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) ||
-	    !(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))) {
-	    /* This 'cause access() says root can execute everything */
-		ret = -1;
-		err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
-	}
-	if (err && errnop && !*errnop)
-		*errnop = err;
-	return ret;
-}
-
-/*
- * search for command with PATH
- */
-char *
-search(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;
-	if (strchr(name, '/')) {
-		if (search_access(name, mode, errnop) == 0)
-			return (char *) name;
-		return NULL;
-	}
-
-	namelen = strlen(name) + 1;
-	Xinit(xs, xp, 128, ATEMP);
-
-	sp = path;
-	while (sp != NULL) {
-		xp = Xstring(xs, xp);
-		if (!(p = strchr(sp, ':')))
-			p = sp + strlen(sp);
-		if (p != sp) {
-			XcheckN(xs, xp, p - sp);
-			memcpy(xp, sp, p - sp);
-			xp += p - sp;
-			*xp++ = '/';
-		}
-		sp = p;
-		XcheckN(xs, xp, namelen);
-		memcpy(xp, name, namelen);
-		if (search_access(Xstring(xs, xp), mode, errnop) == 0)
-			return Xclose(xs, xp + namelen);
-		if (*sp++ == '\0')
-			sp = NULL;
-	}
-	Xfree(xs, xp);
-	return NULL;
-}
-
-static int
-call_builtin(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(struct ioword *iop, struct tbl *tp)
-{
-	int u = -1;
-	char *cp = iop->name;
-	int iotype = iop->flag & IOTYPE;
-	int do_open = 1, do_close = 0, flags = 0;
-	struct ioword iotmp;
-	struct stat statb;
-
-	if (iotype != IOHERE)
-		cp = evalonestr(cp, DOTILDE|(Flag(FTALKING_I) ? 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;
-		/* The stat() is here to allow redirections to
-		 * things like /dev/null without error.
-		 */
-		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(iop->heredoc, 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;
-		}
-		if (u == iop->unit)
-			return 0;		/* "dup from" == "dup to" */
-		break;
-	    }
-	}
-
-	if (do_open) {
-		if (Flag(FRESTRICTED) && (flags & O_CREAT)) {
-			warningf(true, "%s: restricted", cp);
-			return -1;
-		}
-		u = open(cp, flags, 0666);
-	}
-	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) {
-		/* If these are the same, it means unit was previously closed */
-		if (u == iop->unit)
-			e->savefd[iop->unit] = -1;
-		else
-			/* c_exec() assumes e->savefd[fd] set for any
-			 * redirections.  Ask savefd() not to close iop->unit;
-			 * this 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);
-	}
-
-	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);
-		/* 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);
-		}
-	}
-	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(const char *content, int sub)
-{
-	volatile int fd = -1;
-	struct source *s, *volatile osource;
-	struct shf *volatile shf;
-	struct temp *h;
-	int i;
-
-	/* ksh -c 'cat << EOF' can cause this... */
-	if (content == (char *) 0) {
-		warningf(true, "here document missing");
-		return -2; /* special to iosetup(): don't print error */
-	}
-
-	/* Create temp file to hold content (done before newenv so temp
-	 * doesn't get removed too soon).
-	 */
-	h = maketemp(ATEMP, TT_HEREDOC_EXP, &e->temps);
-	if (!(shf = h->shf) || (fd = open(h->name, O_RDONLY, 0)) < 0) {
-		warningf(true, "can't %s temporary file %s: %s",
-		    !shf ? "create" : "open",
-		    h->name, strerror(errno));
-		if (shf)
-			shf_close(shf);
-		return -2 /* special to iosetup(): don't print error */;
-	}
-
-	osource = source;
-	newenv(E_ERRH);
-	i = sigsetjmp(e->jbuf, 0);
-	if (i) {
-		source = osource;
-		quitenv(shf);
-		close(fd);
-		return -2; /* special to iosetup(): don't print error */
-	}
-	if (sub) {
-		/* Do substitutions on the content of heredoc */
-		s = pushs(SSTRING, ATEMP);
-		s->start = s->str = content;
-		source = s;
-		if (yylex(ONEWORD|HEREDOC) != LWORD)
-			internal_errorf(1, "herein: yylex");
-		source = osource;
-		shf_puts(evalstr(yylval.cp, 0), shf);
-	} else
-		shf_puts(content, shf);
-
-	quitenv(NULL);
-
-	if (shf_close(shf) == EOF) {
-		close(fd);
-		warningf(true, "error writing %s: %s", h->name,
-		    strerror(errno));
-		return -2; /* special to iosetup(): don't print error */
-	}
-
-	return fd;
-}
-
-#ifdef EDIT
-/*
- *	ksh special - the select command processing section
- *	print the args in column form - assuming that we can
- */
-static char *
-do_selectargs(char **ap, bool 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;
-};
-
-static char *select_fmt_entry(void *arg, int i, char *buf, int buflen);
-
-/* format a single select menu item */
-static char *
-select_fmt_entry(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(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, 1);
-
-	return n;
-}
-
-/* XXX: horrible kludge to fit within the framework */
-
-static char *plain_fmt_entry(void *arg, int i, char *buf, int buflen);
-
-static char *
-plain_fmt_entry(void *arg, int i, char *buf, int buflen)
-{
-	shf_snprintf(buf, buflen, "%s", ((char *const *)arg)[i]);
-	return buf;
-}
-
-int
-pr_list(char *const *ap)
-{
-	char *const *pp;
-	int nwidth;
-	int i, n;
-
-	for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) {
-		i = strlen(*pp);
-		nwidth = (i > nwidth) ? i : nwidth;
-	}
-	print_columns(shl_out, n, plain_fmt_entry, (void *) ap, nwidth + 1, 0);
-
-	return n;
-}
-#endif /* EDIT */
-
-/*
- *	[[ ... ]] 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(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(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(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(Test_env *te, int offset, const char *msg)
-{
-	te->flags |= TEF_ERROR;
-	internal_errorf(0, "dbteste_error: %s (offset %d)", msg, offset);
-}
--- bin/ksh/config.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/config.h,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: config.h,v 1.13 2004/12/18 22:42:26 millert Exp $	*/
-
-/* config.h.  NOT generated automatically. */
-
-/*
- * This file, config.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
-
-/* Include emacs editing? */
-#define EMACS 1
-
-/* Include vi editing? */
-#define VI 1
-
-/* Include job control? */
-#define JOBS 1
-
-/* Include brace-expansion? */
-#define BRACE_EXPAND 1
-
-/* Include any history? */
-#define HISTORY 1
-
-/* Strict POSIX behaviour? */
-/* #undef POSIXLY_CORRECT */
-
-/* Specify default $ENV? */
-/* #undef DEFAULT_ENV */
-
-/* Include game-of-life? */
-/* #undef SILLY */
-
-/* The number of bytes in a int.  */
-#define SIZEOF_INT 4
-
-/*
- * 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 */
-
-#endif /* CONFIG_H */
--- bin/ksh/edit.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/edit.h,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: edit.h,v 1.8 2005/03/28 21:28:22 deraadt 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(void);
-void	x_flush(void);
-void	x_putc(int);
-void	x_puts(const char *);
-bool	x_mode(bool);
-int	promptlen(const char *, const char **);
-int	x_do_comment(char *, int, int *);
-void	x_print_expansions(int, char *const *, int);
-int	x_cf_glob(int, const char *, int, int, int *, int *, char ***, int *);
-int	x_longest_prefix(int , char *const *);
-int	x_basename(const char *, const char *);
-void	x_free_words(int, char **);
-int	x_escape(const char *, size_t, int (*)(const char *, size_t));
-/* emacs.c */
-int	x_emacs(char *, size_t);
-void	x_init_emacs(void);
-void	x_emacs_keys(X_chars *);
-/* vi.c */
-int	x_vi(char *, size_t);
-
-
-#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:
- */
--- bin/ksh/c_test.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/c_test.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: c_test.c,v 1.17 2005/03/30 17:16:37 deraadt 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 <sys/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 },
-	{"==",	TO_STEQL },
-	{"!=",	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(const char *, struct stat *);
-static int	test_eaccess(const char *, int);
-static int	test_oexpr(Test_env *, int);
-static int	test_aexpr(Test_env *, int);
-static int	test_nexpr(Test_env *, int);
-static int	test_primary(Test_env *, int);
-static int	ptest_isa(Test_env *, Test_meta);
-static const char *ptest_getopnd(Test_env *, Test_op, int);
-static int	ptest_eval(Test_env *, Test_op, const char *,
-		    const char *, int);
-static void	ptest_error(Test_env *, int, const char *);
-
-int
-c_test(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 omitted 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);
-				/* Historically, -t by itself test if fd 1
-				 * is a file descriptor, but POSIX says its
-				 * a string test...
-				 */
-				if (!Flag(FPOSIX) && strcmp(opnd1, "-t") == 0)
-				    break;
-				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(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(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 */
-		return test_stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode);
-	case TO_FILBDEV: /* -b */
-		return test_stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode);
-	case TO_FILFIFO: /* -p */
-		return test_stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode);
-	case TO_FILSYM: /* -h -L */
-		return lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode);
-	case TO_FILSOCK: /* -S */
-		return test_stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode);
-	case TO_FILCDF:/* -H HP context dependent files (directories) */
-		return 0;
-	case TO_FILSETU: /* -u */
-		return test_stat(opnd1, &b1) == 0 &&
-		    (b1.st_mode & S_ISUID) == S_ISUID;
-	case TO_FILSETG: /* -g */
-		return test_stat(opnd1, &b1) == 0 &&
-		    (b1.st_mode & S_ISGID) == S_ISGID;
-	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 {
-			/* generate error if in FPOSIX mode? */
-			res = isatty(opnd1 ? res : 0);
-		}
-		return res;
-	case TO_FILUID: /* -O */
-		return test_stat(opnd1, &b1) == 0 && b1.st_uid == ksheuid;
-	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, KSH_RETURN_ERROR, false) ||
-			    !evaluate(opnd2, &v2, KSH_RETURN_ERROR, false)) {
-				/* 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 */
-		{
-			int s2;
-			/* ksh88/ksh93 succeed if file2 can't be stated
-			 * (subtly different from `does not exist').
-			 */
-			return stat(opnd1, &b1) == 0 &&
-			    (((s2 = stat(opnd2, &b2)) == 0 &&
-			    b1.st_mtime > b2.st_mtime) || s2 < 0);
-		}
-	case TO_FILOT: /* -ot */
-		{
-			int s1;
-			/* ksh88/ksh93 succeed if file1 can't be stated
-			 * (subtly different from `does not exist').
-			 */
-			return stat(opnd2, &b2) == 0 &&
-			    (((s1 = stat(opnd1, &b1)) == 0 &&
-			    b1.st_mtime < b2.st_mtime) || s1 < 0);
-		}
-	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(const char *path, struct stat *statb)
-{
-	return stat(path, statb);
-}
-
-/* Routine to handle Korn's /dev/fd hack, and to deal with X_OK on
- * non-directories when running as root.
- */
-static int
-test_eaccess(const char *path, int mode)
-{
-	int res;
-
-	res = access(path, mode);
-	/*
-	 * On most (all?) unixes, access() says everything is executable for
-	 * root - avoid this on files by using stat().
-	 */
-	if (res == 0 && ksheuid == 0 && (mode & X_OK)) {
-		struct stat statb;
-
-		if (stat(path, &statb) < 0)
-			res = -1;
-		else if (S_ISDIR(statb.st_mode))
-			res = 0;
-		else
-			res = (statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) ?
-			    0 : -1;
-	}
-
-	return res;
-}
-
-int
-test_parse(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(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(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(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(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(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(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(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(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);
-}
--- bin/ksh/syn.c
+++ /dev/null
@@ -1,898 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/syn.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: syn.c,v 1.27 2006/04/10 14:38:59 jaredy Exp $	*/
-
-/*
- * shell parser (C version)
- */
-
-#include "sh.h"
-#include "c_test.h"
-
-struct nesting_state {
-	int	start_token;	/* token than began nesting (eg, FOR) */
-	int	start_line;	/* line nesting began on */
-};
-
-static void	yyparse(void);
-static struct op *pipeline(int);
-static struct op *andor(void);
-static struct op *c_list(int);
-static struct ioword *synio(int);
-static void	musthave(int, int);
-static struct op *nested(int, int, int);
-static struct op *get_command(int);
-static struct op *dogroup(void);
-static struct op *thenpart(void);
-static struct op *elsepart(void);
-static struct op *caselist(void);
-static struct op *casepart(int);
-static struct op *function_body(char *, int);
-static char **	wordlist(void);
-static struct op *block(int, struct op *, struct op *, char **);
-static struct op *newtp(int);
-static void	syntaxerr(const char *) __attribute__((__noreturn__));
-static void	nesting_push(struct nesting_state *, int);
-static void	nesting_pop(struct nesting_state *);
-static int	assign_command(char *);
-static int	inalias(struct source *);
-static int	dbtestp_isa(Test_env *, Test_meta);
-static const char *dbtestp_getopnd(Test_env *, Test_op, int);
-static int	dbtestp_eval(Test_env *, Test_op, const char *, const char *,
-		    int);
-static void	dbtestp_error(Test_env *, int, const char *);
-
-static	struct	op	*outtree; /* yyparse output */
-
-static struct nesting_state nesting;	/* \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(void)
-{
-	int c;
-
-	ACCEPT;
-
-	outtree = c_list(source->type == SSTRING);
-	c = tpeek(0);
-	if (c == 0 && !outtree)
-		outtree = newtp(TEOF);
-	else if (c != '\n' && c != 0)
-		syntaxerr((char *) 0);
-}
-
-static struct op *
-pipeline(int cf)
-{
-	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(void)
-{
-	struct op *t, *p;
-	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(int multi)
-{
-	struct op *t = NULL, *p, *tl = NULL;
-	int c;
-	int have_sep;
-
-	while (1) {
-		p = andor();
-		/* Token has always been read/rejected at this point, so
-		 * we don't worry about what flags to pass token()
-		 */
-		c = token(0);
-		have_sep = 1;
-		if (c == '\n' && (multi || inalias(source))) {
-			if (!p) /* ignore blank lines */
-				continue;
-		} else if (!p)
-			break;
-		else if (c == '&' || c == COPROC)
-			p = block(c == '&' ? TASYNC : TCOPROC,
-				  p, NOBLOCK, NOWORDS);
-		else if (c != ';')
-			have_sep = 0;
-		if (!t)
-			t = p;
-		else if (!tl)
-			t = tl = block(TLIST, t, p, NOWORDS);
-		else
-			tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
-		if (!have_sep)
-			break;
-	}
-	REJECT;
-	return t;
-}
-
-static struct ioword *
-synio(int cf)
-{
-	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(int c, int cf)
-{
-	if ((token(cf)) != c)
-		syntaxerr((char *) 0);
-}
-
-static struct op *
-nested(int type, int smark, int emark)
-{
-	struct op *t;
-	struct nesting_state old_nesting;
-
-	nesting_push(&old_nesting, smark);
-	t = c_list(true);
-	musthave(emark, KEYWORD|ALIAS);
-	nesting_pop(&old_nesting);
-	return (block(type, t, NOBLOCK, NOWORDS));
-}
-
-static struct op *
-get_command(int cf)
-{
-	struct op *t;
-	int c, iopn = 0, syniocf;
-	struct ioword *iop, **iops;
-	XPtrV args, vars;
-	struct nesting_state old_nesting;
-
-	iops = (struct ioword **) alloc(sizeofN(struct ioword *, NUFILE+1),
-	    ATEMP);
-	XPinit(args, 16);
-	XPinit(vars, 16);
-
-	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);
-		t->lineno = source->line;
-		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;
-
-	case MDPAREN:
-	  {
-		static const char let_cmd[] = {
-			CHAR, 'l', CHAR, 'e',
-			CHAR, 't', EOS
-		};
-		/* Leave KEYWORD in syniocf (allow if (( 1 )) then ...) */
-		t = newtp(TCOM);
-		t->lineno = source->line;
-		ACCEPT;
-		XPput(args, wdcopy(let_cmd, ATEMP));
-		musthave(LWORD,LETEXPR);
-		XPput(args, yylval.cp);
-		break;
-	  }
-
-	case DBRACKET: /* [[ .. ]] */
-		/* Leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */
-		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;
-
-	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);
-		nesting_push(&old_nesting, c);
-		t->vars = wordlist();
-		t->left = dogroup();
-		nesting_pop(&old_nesting);
-		break;
-
-	case WHILE:
-	case UNTIL:
-		nesting_push(&old_nesting, c);
-		t = newtp((c == WHILE) ? TWHILE : TUNTIL);
-		t->left = c_list(true);
-		t->right = dogroup();
-		nesting_pop(&old_nesting);
-		break;
-
-	case CASE:
-		t = newtp(TCASE);
-		musthave(LWORD, 0);
-		t->str = yylval.cp;
-		nesting_push(&old_nesting, c);
-		t->left = caselist();
-		nesting_pop(&old_nesting);
-		break;
-
-	case IF:
-		nesting_push(&old_nesting, c);
-		t = newtp(TIF);
-		t->left = c_list(true);
-		t->right = thenpart();
-		musthave(FI, KEYWORD|ALIAS);
-		nesting_pop(&old_nesting);
-		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(void)
-{
-	int c;
-	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(true);
-	musthave(c, KEYWORD|ALIAS);
-	return list;
-}
-
-static struct op *
-thenpart(void)
-{
-	struct op *t;
-
-	musthave(THEN, KEYWORD|ALIAS);
-	t = newtp(0);
-	t->left = c_list(true);
-	if (t->left == NULL)
-		syntaxerr((char *) 0);
-	t->right = elsepart();
-	return (t);
-}
-
-static struct op *
-elsepart(void)
-{
-	struct op *t;
-
-	switch (token(KEYWORD|ALIAS|VARASN)) {
-	case ELSE:
-		if ((t = c_list(true)) == NULL)
-			syntaxerr((char *) 0);
-		return (t);
-
-	case ELIF:
-		t = newtp(TELIF);
-		t->left = c_list(true);
-		t->right = thenpart();
-		return (t);
-
-	default:
-		REJECT;
-	}
-	return NULL;
-}
-
-static struct op *
-caselist(void)
-{
-	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(int endtok)
-{
-	struct op *t;
-	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(true);
-	/* Note: Posix requires the ;; */
-	if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok)
-		musthave(BREAK, CONTIN|KEYWORD|ALIAS);
-	return (t);
-}
-
-static struct op *
-function_body(char *name,
-    int ksh_func)		/* function foo { ... } vs foo() { .. } */
-{
-	char *sname, *p;
-	struct op *t;
-	int old_func_parse;
-
-	sname = wdstrip(name);
-	/* Check for valid characters in name.  posix and ksh93 say only
-	 * allow [a-zA-Z_0-9] but this allows more as old pdksh's have
-	 * allowed more (the following were never allowed:
-	 *	nul space nl tab $ ' " \ ` ( ) & | ; = < >
-	 *  C_QUOTE covers all but = and adds # [ ? *)
-	 */
-	for (p = sname; *p; p++)
-		if (ctype(*p, C_QUOTE) || *p == '=')
-			yyerror("%s: invalid function name\n", sname);
-
-	t = newtp(TFUNCT);
-	t->str = sname;
-	t->u.ksh_func = ksh_func;
-	t->lineno = source->line;
-
-	/* 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) {
-		/*
-		 * Probably something like foo() followed by eof or ;.
-		 * This is accepted by sh and ksh88.
-		 * To make "typeset -f foo" work reliably (so its output can
-		 * be used as input), we pretend there is a colon here.
-		 */
-		t->left = newtp(TCOM);
-		t->left->args = (char **) alloc(sizeof(char *) * 2, ATEMP);
-		t->left->args[0] = alloc(sizeof(char) * 3, ATEMP);
-		t->left->args[0][0] = CHAR;
-		t->left->args[0][1] = ':';
-		t->left->args[0][2] = EOS;
-		t->left->args[1] = (char *) 0;
-		t->left->vars = (char **) alloc(sizeof(char *), ATEMP);
-		t->left->vars[0] = (char *) 0;
-		t->left->lineno = 1;
-	}
-	if (!old_func_parse)
-		e->flags &= ~EF_FUNC_PARSE;
-
-	return t;
-}
-
-static char **
-wordlist(void)
-{
-	int c;
-	XPtrV args;
-
-	XPinit(args, 16);
-	/* Posix does not do alias expansion here... */
-	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(int type, struct op *t1, struct op *t2, char **wp)
-{
-	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 },
-	{ "select",	SELECT,	true },
-	{ "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 },
-	{ "[[",		DBRACKET, true },
-	/* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */
-	{ "&&",		LOGAND,	false },
-	{ "||",		LOGOR,	false },
-	{ ";;",		BREAK,	false },
-	{ "((",		MDPAREN, false },
-	{ "|&",		COPROC,	false },
-	/* and some special cases... */
-	{ "newline",	'\n',	false },
-	{ 0 }
-};
-
-void
-initkeywords(void)
-{
-	struct tokeninfo const *tt;
-	struct tbl *p;
-
-	ktinit(&keywords, APERM, 32); /* must be 2^n (currently 20 keywords) */
-	for (tt = tokentab; tt->name; tt++) {
-		if (tt->reserved) {
-			p = ktenter(&keywords, tt->name, hash(tt->name));
-			p->flag |= DEFINED|ISSET;
-			p->type = CKEYWD;
-			p->val.i = tt->val;
-		}
-	}
-}
-
-static void
-syntaxerr(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 (nesting.start_token) {
-			c = nesting.start_token;
-			source->errline = nesting.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
-nesting_push(struct nesting_state *save, int tok)
-{
-	*save = nesting;
-	nesting.start_token = tok;
-	nesting.start_line = source->line;
-}
-
-static void
-nesting_pop(struct nesting_state *saved)
-{
-	nesting = *saved;
-}
-
-static struct op *
-newtp(int type)
-{
-	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(Source *s)
-{
-	nesting.start_token = 0;
-	nesting.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(char *s)
-{
-	if (Flag(FPOSIX) || !*s)
-		return 0;
-	return (strcmp(s, "alias") == 0) ||
-	    (strcmp(s, "export") == 0) ||
-	    (strcmp(s, "readonly") == 0) ||
-	    (strcmp(s, "typeset") == 0);
-}
-
-/* Check if we are in the middle of reading an alias */
-static int
-inalias(struct source *s)
-{
-	for (; s && s->type == SALIAS; s = s->next)
-		if (!(s->flags & SF_ALIASEND))
-			return 1;
-	return 0;
-}
-
-
-/* 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(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(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(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
-    int do_eval)
-{
-	return 1;
-}
-
-static void
-dbtestp_error(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);
-}
--- bin/ksh/table.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/table.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: table.c,v 1.12 2005/12/11 20:31:21 otto 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(struct table *, int);
-static int	tnamecmp(void *, void *);
-
-
-unsigned int
-hash(const char *n)
-{
-	unsigned int h = 0;
-
-	while (*n != '\0')
-		h = 2*h + *n++;
-	return h * 32821;	/* scatter bits */
-}
-
-void
-ktinit(struct table *tp, Area *ap, int tsize)
-{
-	tp->areap = ap;
-	tp->tbls = NULL;
-	tp->size = tp->nfree = 0;
-	if (tsize)
-		texpand(tp, tsize);
-}
-
-static void
-texpand(struct table *tp, int nsize)
-{
-	int i;
-	struct tbl *tblp, **p;
-	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);
-}
-
-/* table */
-/* name to enter */
-/* hash(n) */
-struct tbl *
-ktsearch(struct table *tp, const char *n, unsigned int h)
-{
-	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;
-}
-
-/* table */
-/* name to enter */
-/* hash(n) */
-struct tbl *
-ktenter(struct table *tp, const char *n, unsigned int h)
-{
-	struct tbl **pp, *p;
-	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
-ktdelete(struct tbl *p)
-{
-	p->flag = 0;
-}
-
-void
-ktwalk(struct tstate *ts, struct table *tp)
-{
-	ts->left = tp->size;
-	ts->next = tp->tbls;
-}
-
-struct tbl *
-ktnext(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(void *p1, void *p2)
-{
-	return strcmp(((struct tbl *)p1)->name, ((struct tbl *)p2)->name);
-}
-
-struct tbl **
-ktsort(struct table *tp)
-{
-	int i;
-	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(struct table *tp);
-
-void
-tprintinfo(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");
-	ktwalk(&ts, tp);
-	while ((te = ktnext(&ts))) {
-		struct tbl **pp, *p;
-
-		h = hash(n = te->name);
-		ncmp = 0;
-
-		/* taken from ktsearch() 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 */
--- bin/ksh/c_ksh.c
+++ /dev/null
@@ -1,1397 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/c_ksh.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: c_ksh.c,v 1.29 2006/03/12 00:26:58 deraadt Exp $	*/
-
-/*
- * built-in Korn commands: c_*
- */
-
-#include "sh.h"
-#include <sys/stat.h>
-#include <ctype.h>
-
-
-int
-c_cd(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")) != -1)
-		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;
-		}
-		/* substitute 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);
-		if (physical)
-			rval = chdir(try = Xstring(xs, xp) + phys_path);
-		else {
-			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 (note: unsetting OLDPWD does not disable this
-	 * setting in at&t ksh)
-	 */
-	if (current_wd[0])
-		/* Ignore failure (happens if readonly or integer) */
-		setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR);
-
-	if (Xstring(xs, xp)[0] != '/') {
-		pwd = (char *) 0;
-	} else
-	if (!physical || !(pwd = get_phys_path(Xstring(xs, xp))))
-		pwd = Xstring(xs, xp);
-
-	/* Set PWD */
-	if (pwd) {
-		char *ptmp = pwd;
-		set_current_wd(ptmp);
-		/* Ignore failure (happens if readonly or integer) */
-		setstr(pwd_s, ptmp, KSH_RETURN_ERROR);
-	} else {
-		set_current_wd(null);
-		pwd = Xstring(xs, xp);
-		/* XXX unset $PWD? */
-	}
-	if (printpath || cdnode)
-		shprintf("%s\n", pwd);
-
-	return 0;
-}
-
-int
-c_pwd(char **wp)
-{
-	int optc;
-	int physical = Flag(FPHYSICAL);
-	char *p;
-
-	while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1)
-		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;
-	}
-	p = current_wd[0] ? (physical ? get_phys_path(current_wd) : current_wd) :
-	    (char *) 0;
-	if (p && access(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(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 */
-	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;
-		const char *options = "Rnprsu,";
-		while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
-			switch (optc) {
-			case 'R': /* fake BSD echo command */
-				flags |= PO_PMINUSMINUS;
-				flags &= ~PO_EXPAND;
-				options = "ne";
-				break;
-			case 'e':
-				flags |= PO_EXPAND;
-				break;
-			case 'n':
-				flags &= ~PO_NL;
-				break;
-			case 'p':
-				if ((fd = coproc_getfd(W_OK, &emsg)) < 0) {
-					bi_errorf("-p: %s", emsg);
-					return 1;
-				}
-				break;
-			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) {
-		int c;
-		s = *wp;
-		while ((c = *s++) != '\0') {
-			Xcheck(xs, xp);
-			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).  Truly 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 opipe = 0;
-
-		/* 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();
-		}
-		for (s = Xstring(xs, xp); len > 0; ) {
-			n = write(fd, s, len);
-			if (n < 0) {
-				if (flags & PO_COPROC)
-					restore_pipe(opipe);
-				if (errno == EINTR) {
-					/* allow user to ^C out */
-					intrcheck();
-					if (flags & PO_COPROC)
-						opipe = block_pipe();
-					continue;
-				}
-				/* This doesn't really make sense - could
-				 * break scripts (print -p generates
-				 * error message).
-				*if (errno == EPIPE)
-				*	coproc_write_close(fd);
-				 */
-				return 1;
-			}
-			s += n;
-			len -= n;
-		}
-		if (flags & PO_COPROC)
-			restore_pipe(opipe);
-	}
-
-	return 0;
-}
-
-int
-c_whence(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)) != -1)
-		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 = ktsearch(&keywords, id, hash(id));
-		if (!tp && !pflag) {
-			tp = ktsearch(&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(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(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#lprtux";	/* 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 separate 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)) != -1) {
-		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.
-			 * typeset -p is the same as typeset (in pdksh);
-			 * here for compatibility with ksh93.
-			 */
-			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.
-		 * At this point, flags in fset are cleared in fclr and vise
-		 * versa.  This property should be preserved.
-		 */
-		if (fset & LCASEV)	/* LCASEV has priority over UCASEV_AL */
-			fset &= ~UCASEV_AL;
-		if (fset & LJUST)	/* LJUST has priority over RJUST */
-			fset &= ~RJUST;
-		if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) { /* -Z implies -ZR */
-			fset |= RJUST;
-			fclr &= ~RJUST;
-		}
-		/* 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);
-	}
-
-	/* 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,
-					    f->flag & FKSH ?
-					    "function %s %T\n" :
-					    "%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 = ktsort(&l->funs); (vp = *p++); ) {
-				if (flag && (vp->flag & flag) == 0)
-					continue;
-				if (thing == '-')
-					fptreef(shl_stdout, 0, vp->flag & FKSH ?
-					    "function %s %T\n" : "%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 = ktsort(&l->vars); (vp = *p++); ) {
-				struct tbl *tvp;
-				int any_set = 0;
-				/*
-				 * See if the parameter is set (for arrays, if any
-				 * element is set).
-				 */
-				for (tvp = vp; tvp; tvp = tvp->u.array)
-					if (tvp->flag & ISSET) {
-						any_set = 1;
-						break;
-					}
-
-				/*
-				 * Check attributes - note that all array elements
-				 * have (should have?) the same attributes, so checking
-				 * the first is sufficient.
-				 *
-				 * 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 (!any_set && !(vp->flag & USERATTRIB))
-					continue;
-				if (flag && (vp->flag & flag) == 0)
-					continue;
-				for (; vp; vp = vp->u.array) {
-					/* Ignore array elements that aren't
-					 * set unless there are no set elements,
-					 * in which case the first is reported on */
-					if ((vp->flag&ARRAY) && any_set &&
-					    !(vp->flag & ISSET))
-						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 ");
-						shprintf("%s\n", vp->name);
-						    if (vp->flag&ARRAY)
-						break;
-					} else {
-						if (pflag)
-							shprintf("%s ",
-							    (flag & EXPORT) ?
-							    "export" : "readonly");
-						if ((vp->flag&ARRAY) && any_set)
-							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);
-					}
-					/* Only report first `element' of an array with
-					* no set elements.
-					*/
-					if (!any_set)
-						break;
-				}
-			}
-		}
-	}
-	return 0;
-}
-
-int
-c_alias(char **wp)
-{
-	struct table *t = &aliases;
-	int rv = 0, rflag = 0, tflag, Uflag = 0, pflag = 0;
-	int prefix = 0;
-	Tflag xflag = 0;
-	int optc;
-
-	builtin_opt.flags |= GF_PLUSOPT;
-	while ((optc = ksh_getopt(wp, &builtin_opt, "dprtUx")) != -1) {
-		prefix = builtin_opt.info & GI_PLUS ? '+' : '-';
-		switch (optc) {
-		case 'd':
-			t = &homedirs;
-			break;
-		case 'p':
-			pflag = 1;
-			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;
-
-	if (!(builtin_opt.info & GI_MINUSMINUS) && *wp &&
-	    (wp[0][0] == '-' || wp[0][0] == '+') && wp[0][1] == '\0') {
-		prefix = wp[0][0];
-		wp++;
-	}
-
-	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 = ktsort(t); (ap = *p++) != NULL; )
-			if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) {
-				if (pflag)
-					shf_puts("alias ", shl_stdout);
-				shf_puts(ap->name, shl_stdout);
-				if (prefix != '+') {
-					shf_putc('=', shl_stdout);
-					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 = ktsearch(t, alias, h);
-			if (ap != NULL && (ap->flag&ISSET)) {
-				if (pflag)
-					shf_puts("alias ", shl_stdout);
-				shf_puts(ap->name, shl_stdout);
-				if (prefix != '+') {
-					shf_putc('=', shl_stdout);
-					print_value_quoted(ap->val.s);
-				}
-				shprintf(newline);
-			} else {
-				shprintf("%s alias not found\n", alias);
-				rv = 1;
-			}
-			continue;
-		}
-		ap = ktenter(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;
-		if (prefix == '+')
-			ap->flag &= ~xflag;
-		else
-			ap->flag |= xflag;
-		if (val)
-			afree(alias, ATEMP);
-	}
-
-	return rv;
-}
-
-int
-c_unalias(char **wp)
-{
-	struct table *t = &aliases;
-	struct tbl *ap;
-	int rv = 0, all = 0;
-	int optc;
-
-	while ((optc = ksh_getopt(wp, &builtin_opt, "adt")) != -1)
-		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 = ktsearch(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 (ktwalk(&ts, t); (ap = ktnext(&ts)); ) {
-			if (ap->flag&ALLOC) {
-				ap->flag &= ~(ALLOC|ISSET);
-				afree((void*)ap->val.s, APERM);
-			}
-			ap->flag &= ~(DEFINED|ISSET|EXPORT);
-		}
-	}
-
-	return rv;
-}
-
-int
-c_let(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, KSH_RETURN_ERROR, true)) {
-				rv = 2;	/* distinguish error from zero result */
-				break;
-			} else
-				rv = val == 0;
-	return rv;
-}
-
-int
-c_jobs(char **wp)
-{
-	int optc;
-	int flag = 0;
-	int nflag = 0;
-	int rv = 0;
-
-	while ((optc = ksh_getopt(wp, &builtin_opt, "lpnz")) != -1)
-		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(char **wp)
-{
-	int bg = strcmp(*wp, "bg") == 0;
-	int rv = 0;
-
-	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(void *arg, int i, char *buf, int buflen);
-
-/* format a single kill item */
-static char *
-kill_fmt_entry(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(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, true))) {
-			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:")) != -1)
-			switch (optc) {
-			case 'l':
-				lflag = 1;
-				break;
-			case 's':
-				if (!(t = gettrap(builtin_opt.optarg, true))) {
-					bi_errorf("bad signal `%s'",
-					    builtin_opt.optarg);
-					return 1;
-				}
-				break;
-			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 + NSIG)
-					n -= 128;
-				if (n > 0 && n < NSIG && sigtraps[n].name)
-					shprintf("%s\n", sigtraps[n].name);
-				else
-					shprintf("%d\n", n);
-			}
-		} else if (Flag(FPOSIX)) {
-			p = null;
-			for (i = 1; i < NSIG; 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 = NSIG, ki.num_width = 1; i >= 10; i /= 10)
-				ki.num_width++;
-			ki.name_width = mess_width = 0;
-			for (i = 0; i < NSIG; 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, NSIG - 1,
-			    kill_fmt_entry, (void *) &ki,
-			    ki.num_width + ki.name_width + mess_width + 3, 1);
-		}
-		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;
-}
-
-void
-getopts_reset(int val)
-{
-	if (val >= 1) {
-		ksh_getopt_reset(&user_opt,
-		    GF_NONAME | (Flag(FPOSIX) ? 0 : GF_PLUSOPT));
-		user_opt.optind = user_opt.uoptind = val;
-	}
-}
-
-int
-c_getopts(char **wp)
-{
-	int	argc;
-	const char *options;
-	const char *var;
-	int	optc;
-	int	ret;
-	char	buf[3];
-	struct tbl *vq, *voptarg;
-
-	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 != '?') {
-		user_opt.uoptind = user_opt.optind;
-	}
-
-	voptarg = global("OPTARG");
-	voptarg->flag &= ~RDONLY;	/* at&t ksh clears ro and int */
-	/* Paranoia: ensure no bizarre results. */
-	if (voptarg->flag & INTEGER)
-	    typeset("OPTARG", 0, INTEGER, 0, 0);
-	if (user_opt.optarg == (char *) 0)
-		unset(voptarg, 0);
-	else
-		/* This can't fail (have cleared readonly/integer) */
-		setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR);
-
-	ret = 0;
-
-	vq = global(var);
-	/* Error message already printed (integer, readonly) */
-	if (!setstr(vq, buf, KSH_RETURN_ERROR))
-	    ret = 1;
-	if (Flag(FEXPORT))
-		typeset(var, EXPORT, 0, 0, 0);
-
-	return optc < 0 ? 1 : ret;
-}
-
-#ifdef EMACS
-int
-c_bind(char **wp)
-{
-	int optc, rv = 0, macro = 0, list = 0;
-	char *cp;
-
-	while ((optc = ksh_getopt(wp, &builtin_opt, "lm")) != -1)
-		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},
-	{"let", c_let},
-	{"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}
-};
--- bin/ksh/mail.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/mail.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: mail.c,v 1.15 2005/03/30 17:16:37 deraadt Exp $	*/
-
-/*
- * Mailbox checking code by Robert J. Gibson, adapted for PD ksh by
- * John R. MacMillan
- */
-
-#include "config.h"
-
-#include "sh.h"
-#include <sys/stat.h>
-#include <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 time_t	mailcheck_interval;
-
-static void     munset(mbox_t *); /* free mlist and mval */
-static mbox_t * mballoc(char *, char *); /* allocate a new mbox */
-static void     mprintit(mbox_t *);
-
-void
-mcheck(void)
-{
-	mbox_t		*mbp;
-	time_t		 now;
-	struct tbl	*vp;
-	struct stat	 stbuf;
-
-	now = time((time_t *) 0);
-	if (mlastchkd == 0)
-		mlastchkd = now;
-	if (now - mlastchkd >= mailcheck_interval) {
-		mlastchkd = now;
-
-		if (mplist)
-			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
-mcset(long int interval)
-{
-	mailcheck_interval = interval;
-}
-
-void
-mbset(char *p)
-{
-	struct stat	stbuf;
-
-	if (mbox.mb_msg)
-		afree((void *)mbox.mb_msg, APERM);
-	if (mbox.mb_path)
-		afree((void *)mbox.mb_path, APERM);
-	/* Save a copy to protect from export (which munges the string) */
-	mbox.mb_path = str_save(p, APERM);
-	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(char *mptoparse)
-{
-	mbox_t	*mbp;
-	char	*mpath, *mmsg, *mval;
-	char *p;
-
-	munset( mplist );
-	mplist = NULL;
-	mval = str_save(mptoparse, APERM);
-	while (mval) {
-		mpath = mval;
-		if ((mval = strchr(mval, ':')) != 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(mbox_t *mlist)
-{
-	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(char *p, char *m)
-{
-	struct stat	stbuf;
-	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(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
-		/* Ignore setstr errors here (arbitrary) */
-		setstr((vp = local("_", false)), mbp->mb_path, KSH_RETURN_ERROR);
-
-	shellf("%s\n", substitute(mbp->mb_msg ? mbp->mb_msg : MBMESSAGE, 0));
-
-	unset(vp, 0);
-}
--- bin/ksh/NOTES
+++ /dev/null
@@ -1,545 +0,0 @@
-$OpenBSD: NOTES,v 1.9 2003/10/26 15:07:25 jmc Exp $
-
-General features of at&t ksh88 that are not (yet) in pdksh:
-    - exported aliases and functions (not in ksh93).
-    - set -t.
-    - signals/traps not cleared during functions.
-    - trap DEBUG, local ERR and EXIT traps in functions.
-    - ERRNO parameter.
-    - 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 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 constructs.  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 separate process in pdksh).
-    Misc:
-
-Known problems not caused by ksh:
-    - after stoping a job, emacs/vi is not re-entered.  Hitting return
-      prints the prompt and everything is fine again.  Problem (often
-      involving a pager like less) is related to order of process
-      scheduling (shell runs before `stop'ed (sub) processes have had a chance
-      to clean up the screen/terminal).
-
-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.
-    - LINENO:
-	- in ksh88 variable is always 1 (can't be changed) in interac mode;
-	  in pdksh it changes.
-	- Value of LINENO after it has been set by the script in one file
-	  is bizarre when used in another file.
-
-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 occurring
-      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 separate 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.
-    - pdksh accepts empty command lists for while and for statements, while
-      at&t ksh (and sh) don't.  Eg., pdksh likes
-	while false ; do done
-      but ksh88 doesn't like it.
-    - pdksh bumps RANDOM in parent after a fork, at&t ksh bumps it in both
-      parent and child:
-	RANDOM=1
-	echo child: `echo $RANDOM`
-	echo parent: $RANDOM
-      will produce "child: 16838 parent: 5758" in pdksh, while at&t ksh
-      will produce "child: 5758 parent: 5758".
-
-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
-	$ 
-    - (SunOS M-12/28/93d): 
-	$ cat -n << X $(
-	> echo foo
-	> )
-	> X
-	> echo bar
-	)
-	./ksh93: X: cannot open [No such file or directory]
-	Memory fault (core dumped)
-
-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.
--- bin/ksh/emacs.c
+++ /dev/null
@@ -1,2067 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/emacs.c,v 1.3 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: emacs.c,v 1.40 2006/07/10 17:12:41 beck 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 <sys/stat.h>
-#include <ctype.h>
-#include <locale.h>
-#include "edit.h"
-
-static	Area	aedit;
-#define	AEDIT	&aedit		/* area for kill ring and macro defns */
-
-#define	CTRL(x)		((x) == '?' ? 0x7F : (x) & 0x1F)	/* ASCII */
-#define	UNCTRL(x)	((x) == 0x7F ? '?' : (x) | 0x40)	/* ASCII */
-#define	META(x)		((x) & 0x7f)
-#define	ISMETA(x)	(Flag(FEMACSUSEMETA) && ((x) & 0x80))
-
-
-/* values returned by keyboard functions */
-#define	KSTD	0
-#define	KEOL	1		/* ^M, ^J */
-#define	KINTR	2		/* ^G, ^C */
-
-struct	x_ftab {
-	int		(*xf_func)(int c);
-	const char	*xf_name;
-	short		xf_flags;
-};
-
-struct x_defbindings {
-	u_char		xdb_func;	/* XFUNC_* */
-	unsigned 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 */
-
-# define CHARMASK	0xFF		/* 8-bit character mask */
-# define X_NTABS	3		/* normal, meta1, meta2 */
-#define X_TABSZ		(CHARMASK+1)	/* size of keydef tables etc */
-
-/* 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	u_char	x_last_command;
-static	u_char	(*x_tab)[X_TABSZ];	/* key definition */
-static	char    *(*x_atab)[X_TABSZ];	/* macro definitions */
-static	unsigned char	x_bound[(X_TABSZ * X_NTABS + 7) / 8];
-#define	KILLSIZE	20
-static	char    *killstack[KILLSIZE];
-static	int	killsp, killtp;
-static	int	x_curprefix;
-static	char    *macroptr;
-static	int	prompt_skip;
-static	int	prompt_redraw;
-
-static int      x_ins(char *);
-static void     x_delete(int, int);
-static int	x_bword(void);
-static int	x_fword(void);
-static void     x_goto(char *);
-static void     x_bs(int);
-static int      x_size_str(char *);
-static int      x_size(int);
-static void     x_zots(char *);
-static void     x_zotc(int);
-static void     x_load_hist(char **);
-static int      x_search(char *, int, int);
-static int      x_match(char *, char *);
-static void	x_redraw(int);
-static void     x_push(int);
-static char *   x_mapin(const char *);
-static char *   x_mapout(int);
-static void     x_print(int, int);
-static void	x_adjust(void);
-static void	x_e_ungetc(int);
-static int	x_e_getc(void);
-static void	x_e_putc(int);
-static void	x_e_puts(const char *);
-static int	x_comment(int);
-static int	x_fold_case(int);
-static char	*x_lastcp(void);
-static void	do_complete(int, Comp_type);
-static int	x_emacs_putbuf(const char *, size_t);
-
-
-/* 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_clear_screen,	"clear-screen",			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_capitalize,	"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
-	{ 0, 0, 0 },
-/* @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_clear_screen,		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(TIOCSTI)
-	{ XFUNC_stuff,			0, CTRL('T') },
-#else
-	{ XFUNC_transpose,		0, CTRL('T') },
-#endif
-	{ XFUNC_complete,		1, CTRL('[') },
-	{ XFUNC_comp_list,		0, CTRL('I') },
-	{ 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_literal,		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_capitalize,	1,	'C'  },
-	{ XFUNC_fold_capitalize,	1,	'c'  },
-	/* 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_meta2,			1,	'O'  },
-	{ XFUNC_prev_com,		2,	'A'  },
-	{ XFUNC_next_com,		2,	'B'  },
-	{ XFUNC_mv_forw,		2,	'C'  },
-	{ XFUNC_mv_back,		2,	'D'  },
-};
-
-int
-x_emacs(char *buf, size_t len)
-{
-	int	c;
-	const char *p;
-	int	i;
-	u_char 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;
-	prompt_redraw = 1;
-	if (x_col > xx_cols)
-		x_col = x_col - (x_col / xx_cols) * xx_cols;
-	x_displen = xx_cols - 2 - x_col;
-	x_adj_done = 0;
-
-	pprompt(prompt, 0);
-	if (x_displen < 1) {
-		x_col = 0;
-		x_displen = xx_cols - 2;
-		x_e_putc('\n');
-		prompt_redraw = 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;
-
-		if (ISMETA(c)) {
-			c = META(c);
-			x_curprefix = 1;
-		}
-
-		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(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(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(const char *cp, int len);
-
-static int
-x_do_ins(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(char *s)
-{
-	char	*cp = xcp;
-	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;
-}
-
-/*
- * this is used for x_escape() in do_complete()
- */
-static int
-x_emacs_putbuf(const char *s, size_t len)
-{
-	int rval;
-
-	if ((rval = x_do_ins(s, len)) != 0)
-		return (rval);
-	return (rval);
-}
-
-static int
-x_del_back(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(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(int nc, int 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 (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(int c)
-{
-	x_delete(x_bword(), true);
-	return KSTD;
-}
-
-static int
-x_mv_bword(int c)
-{
-	(void)x_bword();
-	return KSTD;
-}
-
-static int
-x_mv_fword(int c)
-{
-	x_goto(xcp + x_fword());
-	return KSTD;
-}
-
-static int
-x_del_fword(int c)
-{
-	x_delete(x_fword(), true);
-	return KSTD;
-}
-
-static int
-x_bword(void)
-{
-	int	nc = 0;
-	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(void)
-{
-	int	nc = 0;
-	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(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(int c)
-{
-	int i;
-
-	i = x_size(c);
-	while (i--)
-		x_e_putc('\b');
-}
-
-static int
-x_size_str(char *cp)
-{
-	int size = 0;
-	while (*cp)
-		size += x_size(*cp++);
-	return size;
-}
-
-static int
-x_size(int c)
-{
-	if (c=='\t')
-		return 4;	/* Kludge, tabs are always four spaces. */
-	if (iscntrl(c))		/* control char */
-		return 2;
-	return 1;
-}
-
-static void
-x_zots(char *str)
-{
-	int	adj = x_adj_done;
-
-	x_lastcp();
-	while (*str && str < xlp && adj == x_adj_done)
-		x_zotc(*str++);
-}
-
-static void
-x_zotc(int c)
-{
-	if (c == '\t') {
-		/*  Kludge, tabs are always four spaces.  */
-		x_e_puts("    ");
-	} else if (iscntrl(c)) {
-		x_e_putc('^');
-		x_e_putc(UNCTRL(c));
-	} else
-		x_e_putc(c);
-}
-
-static int
-x_mv_back(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(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(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(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(int c)
-{
-	x_e_putc('\r');
-	x_e_putc('\n');
-	x_flush();
-	*xep++ = '\n';
-	return KEOL;
-}
-
-static int
-x_end_of_text(int c)
-{
-	x_zotc(edchars.eof);
-	x_putc('\r');
-	x_putc('\n');
-	x_flush();
-	return KEOL;
-}
-
-static int x_beg_hist(int c) { x_load_hist(history); return KSTD;}
-
-static int x_end_hist(int c) { x_load_hist(histptr); return KSTD;}
-
-static int x_prev_com(int c) { x_load_hist(x_histp - x_arg); return KSTD;}
-
-static int x_next_com(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(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(char **hp)
-{
-	int	oldsize;
-
-	if (hp < history || hp > histptr) {
-		x_e_putc(BEL);
-		return;
-	}
-	x_histp = hp;
-	oldsize = x_size_str(xbuf);
-	strlcpy(xbuf, *hp, xend - xbuf);
-	xbp = xbuf;
-	xep = xcp = xbuf + strlen(xbuf);
-	xlp_valid = false;
-	if (xep <= x_lastcp())
-		x_redraw(oldsize);
-	x_goto(xep);
-}
-
-static int
-x_nl_next_com(int c)
-{
-	x_nextcmd = source->line - (histptr - x_histp) + 1;
-	return (x_newline(c));
-}
-
-static int
-x_eot_del(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(int c)
-{
-	int offset = -1;	/* offset of match in xbuf, else -1 */
-	char pat [256+1];	/* pattern buffer */
-	char *p = pat;
-	u_char 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(char *pat, int sameline, int offset)
-{
-	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(char *str, char *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(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(int c)
-{
-	x_goto(xep);
-	return KSTD;
-}
-
-static int
-x_mv_begin(int c)
-{
-	x_goto(xbuf);
-	return KSTD;
-}
-
-static int
-x_draw_line(int c)
-{
-	x_redraw(-1);
-	return KSTD;
-
-}
-
-static int
-x_clear_screen(int c)
-{
-	printf("\e[H\e[2J");
-	fflush(stdout);
-	x_redraw(0);
-	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(int limit)
-{
-	int	i, j, truncate = 0;
-	char	*cp;
-
-	x_adj_ok = 0;
-	if (limit == -1)
-		x_e_putc('\n');
-	else
-		x_e_putc('\r');
-	x_flush();
-	if (xbp == xbuf) {
-		x_col = promptlen(prompt, (const char **) 0);
-		if (x_col > xx_cols)
-			truncate = (x_col / xx_cols) * xx_cols;
-		if (prompt_redraw)
-			pprompt(prompt + prompt_skip, truncate);
-	}
-	if (x_col > xx_cols)
-		x_col = x_col - (x_col / xx_cols) * xx_cols;
-	x_displen = xx_cols - 2 - x_col;
-	if (x_displen < 1) {
-		x_col = 0;
-		x_displen = xx_cols - 2;
-	}
-	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(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 position:
-	 *     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 mode.
-	 * 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(int c)
-{
-	x_curprefix = -1;
-	return KSTD;
-}
-
-static int
-x_meta1(int c)
-{
-	x_curprefix = 1;
-	return KSTD;
-}
-
-static int
-x_meta2(int c)
-{
-	x_curprefix = 2;
-	return KSTD;
-}
-
-static int
-x_kill(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(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(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(int c)
-{
-	int	len;
-	if ((x_last_command != XFUNC_yank && x_last_command != XFUNC_meta_yank) ||
-	    killstack[killtp] == 0) {
-		killtp = killsp;
-		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(int c)
-{
-	/* x_zotc(c); */
-	xlp = xep = xcp = xbp = xbuf;
-	xlp_valid = true;
-	*xcp = 0;
-	return KINTR;
-}
-
-static int
-x_error(int c)
-{
-	x_e_putc(BEL);
-	return KSTD;
-}
-
-static int
-x_stuffreset(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(int c)
-{
-#ifdef TIOCSTI
-	char	ch = c;
-	bool	savmode = x_mode(false);
-
-	(void)ioctl(TTY, TIOCSTI, &ch);
-	(void)x_mode(savmode);
-	x_redraw(-1);
-#endif
-	return KSTD;
-}
-
-static char *
-x_mapin(const char *cp)
-{
-	char *new, *op;
-
-	op = new = str_save(cp, ATEMP);
-	while (*cp) {
-		/* XXX -- should handle \^ escape? */
-		if (*cp == '^') {
-			cp++;
-			if (*cp >= '?')	/* includes '?'; ASCII */
-				*op++ = CTRL(*cp);
-			else {
-				*op++ = '^';
-				cp--;
-			}
-		} else
-			*op++ = *cp;
-		cp++;
-	}
-	*op = '\0';
-
-	return new;
-}
-
-static char *
-x_mapout(int c)
-{
-	static char buf[8];
-	char *p = buf;
-
-	if (iscntrl(c)) {
-		*p++ = '^';
-		*p++ = UNCTRL(c);
-	} else
-		*p++ = c;
-	*p = 0;
-	return buf;
-}
-
-static void
-x_print(int prefix, int key)
-{
-	if (prefix == 1)
-		shprintf("%s", x_mapout(x_prefix1));
-	if (prefix == 2)
-		shprintf("%s", x_mapout(x_prefix2));
-	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( const char *a1, const char *a2,
-	int macro,		/* bind -m */
-	int list)		/* bind -l */
-{
-	u_char 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;
-		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;
-
-	/* Track what the user has bound so x_emacs_keys() won't toast things */
-	if (f == XFUNC_insert)
-		x_bound[(prefix * X_TABSZ + key) / 8] &=
-		    ~(1 << ((prefix * X_TABSZ + key) % 8));
-	else
-		x_bound[(prefix * X_TABSZ + key) / 8] |=
-		    (1 << ((prefix * X_TABSZ + key) % 8));
-
-	return 0;
-}
-
-void
-x_init_emacs(void)
-{
-	int i, j;
-	char *locale;
-
-	ainit(AEDIT);
-	x_nextcmd = -1;
-
-	x_tab = (u_char (*)[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[(unsigned char)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;
-
-	/* Determine if we can translate meta key or use 8-bit AscII
-	 * XXX - It would be nice if there was a locale attribute to
-	 * determine if the locale is 7-bit or not.
-	 */
-	locale = setlocale(LC_CTYPE, NULL);
-	if (locale == NULL || !strcmp(locale, "C") || !strcmp(locale, "POSIX"))
-		Flag(FEMACSUSEMETA) = 1;
-}
-
-static void bind_if_not_bound(int p, int k, int func);
-
-static void
-bind_if_not_bound(int p, int k, int func)
-{
-	/* Has user already bound this key?  If so, don't override it */
-	if (x_bound[((p) * X_TABSZ + (k)) / 8] &
-	    (1 << (((p) * X_TABSZ + (k)) % 8)))
-		return;
-
-	x_tab[p][k] = func;
-}
-
-void
-x_emacs_keys(X_chars *ec)
-{
-	if (ec->erase >= 0) {
-		bind_if_not_bound(0, ec->erase, XFUNC_del_back);
-		bind_if_not_bound(1, ec->erase, XFUNC_del_bword);
-	}
-	if (ec->kill >= 0)
-		bind_if_not_bound(0, ec->kill, XFUNC_del_line);
-	if (ec->werase >= 0)
-		bind_if_not_bound(0, ec->werase, XFUNC_del_bword);
-	if (ec->intr >= 0)
-		bind_if_not_bound(0, ec->intr, XFUNC_abort);
-	if (ec->quit >= 0)
-		bind_if_not_bound(0, ec->quit, XFUNC_noop);
-}
-
-static int
-x_set_mark(int c)
-{
-	xmp = xcp;
-	return KSTD;
-}
-
-static int
-x_kill_region(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(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(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(int c)
-{
-	return KSTD;
-}
-
-#ifdef SILLY
-static int
-x_game_of_life(int c)
-{
-	char	newbuf [256+1];
-	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(int c)
-{
-	do_complete(XCF_COMMAND, CT_COMPLETE);
-	return KSTD;
-}
-static int
-x_list_comm(int c)
-{
-	do_complete(XCF_COMMAND, CT_LIST);
-	return KSTD;
-}
-static int
-x_complete(int c)
-{
-	do_complete(XCF_COMMAND_FILE, CT_COMPLETE);
-	return KSTD;
-}
-static int
-x_enumerate(int c)
-{
-	do_complete(XCF_COMMAND_FILE, CT_LIST);
-	return KSTD;
-}
-static int
-x_comp_file(int c)
-{
-	do_complete(XCF_FILE, CT_COMPLETE);
-	return KSTD;
-}
-static int
-x_list_file(int c)
-{
-	do_complete(XCF_FILE, CT_LIST);
-	return KSTD;
-}
-static int
-x_comp_list(int c)
-{
-	do_complete(XCF_COMMAND_FILE, CT_COMPLIST);
-	return KSTD;
-}
-static int
-x_expand(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;) {
-		if (x_escape(words[i], strlen(words[i]), x_emacs_putbuf) < 0 ||
-		    (++i < nwords && x_ins(space) < 0)) {
-			x_e_putc(BEL);
-			return KSTD;
-		}
-	}
-	x_adjust();
-
-	return KSTD;
-}
-
-/* type == 0 for list, 1 for complete and 2 for complete-list */
-static void
-do_complete(int flags,	/* XCF_{COMMAND,FILE,COMMAND_FILE} */
-    Comp_type type)
-{
-	char **words;
-	int nwords;
-	int start, end, nlen, olen;
-	int is_command;
-	int completed = 0;
-
-	nwords = x_cf_glob(flags, xbuf, xep - xbuf, xcp - xbuf,
-	    &start, &end, &words, &is_command);
-	/* no match */
-	if (nwords == 0) {
-		x_e_putc(BEL);
-		return;
-	}
-
-	if (type == CT_LIST) {
-		x_print_expansions(nwords, words, is_command);
-		x_redraw(0);
-		x_free_words(nwords, words);
-		return;
-	}
-
-	olen = end - start;
-	nlen = x_longest_prefix(nwords, words);
-	/* complete */
-	if (nwords == 1 || nlen > olen) {
-		x_goto(xbuf + start);
-		x_delete(olen, false);
-		x_escape(words[0], nlen, x_emacs_putbuf);
-		x_adjust();
-		completed = 1;
-	}
-	/* add space if single non-dir match */
-	if (nwords == 1 && words[0][nlen - 1] != '/') {
-		x_ins(space);
-		completed = 1;
-	}
-
-	if (type == CT_COMPLIST && !completed) {
-		x_print_expansions(nwords, words, is_command);
-		completed = 1;
-	}
-
-	if (completed)
-		x_redraw(0);
-
-	x_free_words(nwords, words);
-}
-
-/* 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(void)
-{
-	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(int c)
-{
-	unget_char = c;
-}
-
-static int
-x_e_getc(void)
-{
-	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(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(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(const char *s)
-{
-	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(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(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(int c)
-{
-	char *rcp;
-	char *cp;
-
-	cp = *histptr;
-	if (!cp)
-		x_e_putc(BEL);
-	else 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(int c)
-{
-	return x_fold_case('U');
-}
-
-/* Lowercase N(1) words */
-static int
-x_fold_lower(int c)
-{
-	return x_fold_case('L');
-}
-
-/* Lowercase N(1) words */
-static int
-x_fold_capitalize(int c)
-{
-	return x_fold_case('C');
-}
-
-/* NAME:
- *      x_fold_case - convert word to UPPER/lower/Capital 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(int c)
-{
-	char *cp = xcp;
-
-	if (cp == xep) {
-		x_e_putc(BEL);
-		return KSTD;
-	}
-	while (x_arg--) {
-		/*
-		 * first 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, capitalize */
-				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, capitalize */
-				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(void)
-{
-	char *rcp;
-	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 */
--- bin/ksh/eval.c
+++ /dev/null
@@ -1,1324 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/eval.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: eval.c,v 1.30 2006/04/10 14:38:59 jaredy Exp $	*/
-
-/*
- * Expansion - quoting, separation, substitution, globbing
- */
-
-#include "sh.h"
-#include <pwd.h>
-#include <dirent.h>
-#include <sys/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) */
-#define XSUBMID		6	/* middle of expanding ${} */
-
-/* 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(Expand *, char *, char *, int *, int *);
-static	int	comsub(Expand *, char *);
-static	char   *trimsub(char *, char *, int);
-static	void	glob(char *, XPtrV *, int);
-static	void	globit(XString *, char **, char *, XPtrV *, int);
-static char	*maybe_expand_tilde(char *, XString *, char **, int);
-static	char   *tilde(char *);
-static	char   *homedir(char *);
-#ifdef BRACE_EXPAND
-static void	alt_expand(XPtrV *, char *, char *, char *, int);
-#endif
-
-/* compile and expand word */
-char *
-substitute(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(char **ap, int f)
-{
-	XPtrV w;
-
-	if (*ap == NULL)
-		return ap;
-	XPinit(w, 32);
-	XPput(w, NULL);		/* space for shell name */
-	while (*ap != NULL)
-		expand(*ap++, &w, f);
-	XPput(w, NULL);
-	return (char **) XPclose(w) + 1;
-}
-
-/*
- * expand string
- */
-char *
-evalstr(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(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(char *cp,	/* input word */
-    XPtrV *wp,		/* output words */
-    int f)		/* DO* flags */
-{
-	int c = 0;
-	int type;		/* expansion type */
-	int quote = 0;		/* quoted */
-	XString ds;		/* destination string */
-	char *dp, *sp;		/* dest., source */
-	int fdo, word;		/* second pass flags; have word */
-	int doblank;		/* field splitting of parameter/command subst */
-	Expand x;		/* expansion variables */
-	SubType st_head, *st;
-	int newlines = 0; /* For trailing newlines in COMSUB */
-	int saw_eq, tilde_ok;
-	int make_magic;
-	size_t len;
-
-	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),
-					    KSH_UNWIND_ERROR, true);
-					sp = strchr(sp, 0) + 1;
-					for (p = str_val(&v); *p; ) {
-						Xcheck(ds, dp);
-						*dp++ = *p++;
-					}
-				}
-				continue;
-			case OSUBST: /* ${{#}var{:}[=+-?#%]word} */
-			  /* format is:
-			   *   OSUBST [{x] plain-variable-part \0
-			   *     compiled-word-part CSUBST [}x]
-			   * This is where all syntax checking gets done...
-			   */
-			    {
-				char *varname = ++sp; /* skip the { or x (}) */
-				int stype;
-				int slen;
-
-				sp = strchr(sp, '\0') + 1; /* skip variable */
-				type = varsub(&x, varname, sp, &stype, &slen);
-				if (type < 0) {
-					char endc;
-					char *str, *end;
-
-					sp = varname - 2; /* restore sp */
-					end = (char *) wdscan(sp, CSUBST);
-					/* ({) the } or x is already skipped */
-					endc = *end;
-					*end = EOS;
-					str = snptreef(NULL, 64, "%S", sp);
-					*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 += slen;
-					switch (stype & 0x7f) {
-					case '#':
-					case '%':
-						/* ! DOBLANK,DOBRACE_,DOTILDE */
-						f = DOPAT | (f&DONTRUNCOMMAND) |
-						    DOTEMP_;
-						quote = 0;
-						/* Prepend open pattern (so |
-						 * in a trim will work as
-						 * expected)
-						 */
-						*dp++ = MAGIC;
-						*dp++ = '@' + 0x80;
-						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 (!(x.var->flag & INTEGER))
-							f |= DOASNTILDE|DOTILDE;
-						f |= DOTEMP_;
-						/* These will be done after the
-						 * value has been assigned.
-						 */
-						f &= ~(DOBLANK|DOGLOB|DOBRACE_);
-						tilde_ok = 1;
-						break;
-					case '?':
-						f &= ~DOBLANK;
-						f |= DOTEMP_;
-						/* FALLTHROUGH */
-					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 */
-				sp++; /* ({) skip the } or x */
-				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 '%':
-					/* Append end-pattern */
-					*dp++ = MAGIC; *dp++ = ')'; *dp = '\0';
-					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 '=':
-					/* 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.
-					 */
-					/* Note: not exported by FEXPORT
-					 * in at&t ksh.
-					 */
-					/* XXX POSIX says readonly is only
-					 * fatal for special builtins (setstr
-					 * does readonly check).
-					 */
-					len = strlen(dp) + 1;
-					setstr(st->var,
-					    debunk((char *) alloc(len, ATEMP),
-					    dp, len), KSH_UNWIND_ERROR);
-					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, strlen(s) + 1), 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 separator (|) */
-				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:
-		case XSUBMID:
-			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, strlen(p) + 1));
-				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 {
-			if (type == XSUB) {
-				if (word == IFS_NWS &&
-				    Xlength(ds, dp) == 0) {
-					char *p;
-
-					if ((p = strdup("")) == NULL)
-						internal_errorf(1, "unable "
-						    "to allocate memory");
-					XPput(*wp, p);
-				}
-				type = XSUBMID;
-			}
-
-			/* 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 ':': /* : */
-					/* 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(Expand *xp, char *sp, char *word,
-    int *stypep,	/* becomes qualifier type */
-    int *slenp)		/* " " len (=, :=, etc.) valid iff *stypep != 0 */
-{
-	int c;
-	int state;	/* next state: XBASE, XARG, XSUB, XNULLSUB */
-	int stype;	/* substitution type */
-	int slen;
-	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]==']') {
-			int n = 0;
-			int max = 0;
-
-			vp = global(arrayname(sp));
-			if (vp->flag & (ISSET|ARRAY))
-				zero_ok = 1;
-			for (; vp; vp = vp->u.array)
-				if (vp->flag & ISSET) {
-					max = vp->index + 1;
-					n++;
-				}
-			c = n; /* ksh88/ksh93 go for number, not max index */
-		} 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[slen = 0] == CHAR ? word[1] : 0;
-	if (c == ':') {
-		slen += 2;
-		stype = 0x80;
-		c = word[slen + 0] == CHAR ? word[slen + 1] : 0;
-	}
-	if (ctype(c, C_SUBOP1)) {
-		slen += 2;
-		stype |= c;
-	} else if (ctype(c, C_SUBOP2)) { /* Note: ksh88 allows :%, :%%, etc */
-		slen += 2;
-		stype = c;
-		if (word[slen + 0] == CHAR && c == word[slen + 1]) {
-			stype |= 0x80;
-			slen += 2;
-		}
-	} else if (stype)	/* : is not ok */
-		return -1;
-	if (!stype && *word != CSUBST)
-		return -1;
-	*stypep = stype;
-	*slenp = slen;
-
-	c = sp[0];
-	if (c == '*' || c == '@') {
-		switch (stype & 0x7f) {
-		case '=':	/* can't assign to a vector */
-		case '%':	/* can't trim a vector (yet) */
-		case '#':
-			return -1;
-		}
-		if (e->loc->argc == 0) {
-			xp->str = null;
-			xp->var = global(sp);
-			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 (yet) */
-			case '#':
-			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(Expand *xp, char *cp)
-{
-	Source *s, *sold;
-	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) {
-		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);
-		if (pv[1] != 1) {
-			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(char *str, char *pat, int how)
-{
-	char *end = strchr(str, 0);
-	char *p, c;
-
-	switch (how&0xff) {	/* UCHAR_MAX maybe? */
-	case '#':		/* shortest at beginning */
-		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 beginning */
-		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(char *cp, XPtrV *wp, int markdirs)
-{
-	int oldsize = XPsize(*wp);
-
-	if (glob_str(cp, wp, markdirs) == 0)
-		XPput(*wp, debunk(cp, cp, strlen(cp) + 1));
-	else
-		qsortp(XPptrv(*wp) + oldsize, (size_t)(XPsize(*wp) - oldsize),
-			xstrcmp);
-}
-
-#define GF_NONE		0
-#define GF_EXCHECK	BIT(0)		/* do existence 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(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(XString *xs,	/* dest string */
-    char **xpp,		/* ptr to dest end */
-    char *sp,		/* source path */
-    XPtrV *wp,		/* output list */
-    int check)		/* GF_* flags */
-{
-	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) &&
-			    xp[-1] == '/' && !S_ISDIR(lstatb.st_mode) &&
-			    (!S_ISLNK(lstatb.st_mode) ||
-			    stat_check() < 0 || !S_ISDIR(statb.st_mode)))
-				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) && xp[-1] != '/' &&
-			    (S_ISDIR(lstatb.st_mode) ||
-			    (S_ISLNK(lstatb.st_mode) && stat_check() > 0 &&
-			    S_ISDIR(statb.st_mode)))) {
-				*xp++ = '/';
-				*xp = '\0';
-			}
-		}
-		XPput(*wp, str_nsave(Xstring(*xs, xp), Xlength(*xs, xp), ATEMP));
-		return;
-	}
-
-	if (xp > Xstring(*xs, xp))
-		*xp++ = '/';
-	while (*sp == '/') {
-		Xcheck(*xs, xp);
-		*xp++ = *sp++;
-	}
-	np = strchr(sp, '/');
-	if (np != NULL) {
-		se = np;
-		odirsep = *np;	/* don't assume '/', 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, Xnleft(*xs, xp));
-		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 = 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 = strlen(d->d_name) + 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(XString *xs, char **xpp, char *p);
-static int
-copy_non_glob(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(char *dp, const char *sp, size_t dlen)
-{
-	char *d, *s;
-
-	if ((s = strchr(sp, MAGIC))) {
-		if (s - sp >= dlen)
-			return dp;
-		memcpy(dp, sp, s - sp);
-		for (d = dp + (s - sp); *s && (d - dp < dlen); s++)
-			if (!ISMAGIC(*s) || !(*++s & 0x80) ||
-			    !strchr("*+?@! ", *s & 0x7f))
-				*d++ = *s;
-			else {
-				/* extended pattern operators: *+?@! */
-				if ((*s & 0x7f) != ' ')
-					*d++ = *s & 0x7f;
-				if (d - dp < dlen)
-					*d++ = '(';
-			}
-		*d = '\0';
-	} else if (dp != sp)
-		strlcpy(dp, sp, dlen);
-	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(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 && p[1] != '/' && (!isassign || p[1] != ':'))
-	{
-		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(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(char *name)
-{
-	struct tbl *ap;
-
-	ap = ktenter(&homedirs, name, hash(name));
-	if (!(ap->flag & ISSET)) {
-		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;
-	}
-	return ap->val.s;
-}
-
-#ifdef BRACE_EXPAND
-static void
-alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
-{
-	int count = 0;
-	char *brace_start, *brace_end, *comma = NULL;
-	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, end - 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 */
--- bin/ksh/io.c
+++ /dev/null
@@ -1,438 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/io.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: io.c,v 1.22 2006/03/17 16:30:13 millert Exp $	*/
-
-/*
- * shell buffered IO and formatted output
- */
-
-#include <ctype.h>
-#include "sh.h"
-#include <sys/stat.h>
-
-static int initio_done;
-
-/*
- * formatted output functions
- */
-
-
-/* A shell error occurred (eg, syntax error, etc.) */
-void
-errorf(const char *fmt, ...)
-{
-	va_list va;
-
-	shl_stdout_ok = 0;	/* debugging: note that stdout not valid */
-	exstat = 1;
-	if (*fmt) {
-		error_prefix(true);
-		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
-warningf(int fileline, const char *fmt, ...)
-{
-	va_list va;
-
-	error_prefix(fileline);
-	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
-bi_errorf(const char *fmt, ...)
-{
-	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);
-		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
-internal_errorf(int jump, const char *fmt, ...)
-{
-	va_list va;
-
-	error_prefix(true);
-	shf_fprintf(shl_out, "internal error: ");
-	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(int fileline)
-{
-	/* Avoid foo: foo[2]: ... */
-	if (!fileline || !source || !source->file ||
-	    strcmp(source->file, kshname) != 0)
-		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
-shellf(const char *fmt, ...)
-{
-	va_list va;
-
-	if (!initio_done) /* shl_out may not be set up yet... */
-		return;
-	va_start(va, fmt);
-	shf_vfprintf(shl_out, fmt, va);
-	va_end(va);
-	shf_flush(shl_out);
-}
-
-/* printf to shl_stdout (stdout) */
-void
-shprintf(const char *fmt, ...)
-{
-	va_list va;
-
-	if (!shl_stdout_ok)
-		internal_errorf(1, "shl_stdout not valid");
-	va_start(va, fmt);
-	shf_vfprintf(shl_stdout, fmt, va);
-	va_end(va);
-}
-
-#ifdef KSH_DEBUG
-static struct shf *kshdebug_shf;
-
-void
-kshdebug_init_(void)
-{
-	if (kshdebug_shf)
-		shf_close(kshdebug_shf);
-	kshdebug_shf = shf_open("/tmp/ksh-debug.log",
-	    O_WRONLY|O_APPEND|O_CREAT, 0600, SHF_WR|SHF_MAPHI);
-	if (kshdebug_shf) {
-		shf_fprintf(kshdebug_shf, "\nNew shell[pid %d]\n", getpid());
-		shf_flush(kshdebug_shf);
-	}
-}
-
-/* print to debugging log */
-void
-kshdebug_printf_(const char *fmt, ...)
-{
-	va_list va;
-
-	if (!kshdebug_shf)
-		return;
-	va_start(va, fmt);
-	shf_fprintf(kshdebug_shf, "[%d] ", getpid());
-	shf_vfprintf(kshdebug_shf, fmt, va);
-	va_end(va);
-	shf_flush(kshdebug_shf);
-}
-
-void
-kshdebug_dump_(const char *str, const void *mem, int nbytes)
-{
-	int i, j;
-	int nprow = 16;
-
-	if (!kshdebug_shf)
-		return;
-	shf_fprintf(kshdebug_shf, "[%d] %s:\n", getpid(), str);
-	for (i = 0; i < nbytes; i += nprow) {
-		char c = '\t';
-
-		for (j = 0; j < nprow && i + j < nbytes; j++) {
-			shf_fprintf(kshdebug_shf, "%c%02x", c,
-			    ((const unsigned char *) mem)[i + j]);
-			c = ' ';
-		}
-		shf_fprintf(kshdebug_shf, "\n");
-	}
-	shf_flush(kshdebug_shf);
-}
-#endif /* KSH_DEBUG */
-
-/* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */
-int
-can_seek(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(void)
-{
-	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 */
-	initio_done = 1;
-	kshdebug_init();
-}
-
-/* A dup2() with error checking */
-int
-ksh_dup2(int ofd, int nfd, int errok)
-{
-	int ret = dup2(ofd, nfd);
-
-	if (ret < 0 && errno != EBADF && !errok)
-		errorf("too many files open in shell");
-
-	return ret;
-}
-
-/*
- * move fd from user space (0<=fd<10) to shell space (fd>=10),
- * set close-on-exec flag.
- */
-int
-savefd(int fd)
-{
-	int nfd;
-
-	if (fd < FDBASE) {
-		nfd = fcntl(fd, F_DUPFD, FDBASE);
-		if (nfd < 0) {
-			if (errno == EBADF)
-				return -1;
-			else
-				errorf("too many files open in shell");
-		}
-	} else
-		nfd = fd;
-	fcntl(nfd, F_SETFD, FD_CLOEXEC);
-	return nfd;
-}
-
-void
-restfd(int fd, int ofd)
-{
-	if (fd == 2)
-		shf_flush(&shf_iob[fd]);
-	if (ofd < 0)		/* original fd closed */
-		close(fd);
-	else if (fd != ofd) {
-		ksh_dup2(ofd, fd, true); /* XXX: what to do if this fails? */
-		close(ofd);
-	}
-}
-
-void
-openpipe(int *pv)
-{
-	int lpv[2];
-
-	if (pipe(lpv) < 0)
-		errorf("can't create pipe - try again");
-	pv[0] = savefd(lpv[0]);
-	if (pv[0] != lpv[0])
-		close(lpv[0]);
-	pv[1] = savefd(lpv[1]);
-	if (pv[1] != lpv[1])
-		close(lpv[1]);
-}
-
-void
-closepipe(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(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;
-		/* 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;
-		}
-		return fd;
-	} else if (name[0] == 'p' && !name[1])
-		return coproc_getfd(mode, emsgp);
-	if (emsgp)
-		*emsgp = "illegal file descriptor name";
-	return -1;
-}
-
-/* Called once from main */
-void
-coproc_init(void)
-{
-	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(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(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(int fd)
-{
-	if (coproc.write >= 0 && fd == coproc.write) {
-		close(coproc.write);
-		coproc.write = -1;
-	}
-}
-
-/* Called to check for existence 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(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(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;
-	}
-}
-
-
-/*
- * temporary files
- */
-
-struct temp *
-maketemp(Area *ap, Temp_type type, struct temp **tlist)
-{
-	struct temp *tp;
-	int len;
-	int fd;
-	char *path;
-	const char *dir;
-
-	dir = tmpdir ? tmpdir : "/tmp";
-	/* The 20 + 20 is a paranoid worst case for pid/inc */
-	len = strlen(dir) + 3 + 20 + 20 + 1;
-	tp = (struct temp *) alloc(sizeof(struct temp) + len, ap);
-	tp->name = path = (char *) &tp[1];
-	tp->shf = (struct shf *) 0;
-	tp->type = type;
-	shf_snprintf(path, len, "%s/shXXXXXXXX", dir);
-	fd = mkstemp(path);
-	if (fd >= 0)
-		tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
-	tp->pid = procpid;
-
-	tp->next = *tlist;
-	*tlist = tp;
-	return tp;
-}
--- bin/ksh/expr.c
+++ /dev/null
@@ -1,587 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/expr.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: expr.c,v 1.19 2006/04/10 14:38:59 jaredy 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) >= (int)O_EQ && ((int)op) <= (int)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;	/* precedence: 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 ?:,&&,||) */
-	bool	    arith;		/* true if evaluating an $(())
-					 * expression
-					 */
-	struct tbl *val;		/* value from token() */
-	struct tbl *evaling;		/* variable that is being recursively
-					 * expanded (EXPRINEVAL flag set)
-					 */
-};
-
-enum error_type {
-	ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE,
-	ET_LVALUE, ET_RDONLY, ET_STR
-};
-
-static void	   evalerr(Expr_state *, enum error_type, const char *)
-		    __attribute__((__noreturn__));
-static struct tbl *evalexpr(Expr_state *, enum prec);
-static void	   token(Expr_state *);
-static struct tbl *do_ppmm(Expr_state *, enum token, struct tbl *, bool);
-static void	   assign_check(Expr_state *, enum token, struct tbl *);
-static struct tbl *tempvar(void);
-static struct tbl *intvar(Expr_state *, struct tbl *);
-
-/*
- * parse and evaluate expression
- */
-int
-evaluate(const char *expr, long int *rval, int error_ok, bool arith)
-{
-	struct tbl v;
-	int ret;
-
-	v.flag = DEFINED|INTEGER;
-	v.type = 0;
-	ret = v_evaluate(&v, expr, error_ok, arith);
-	*rval = v.val.i;
-	return ret;
-}
-
-/*
- * parse and evaluate expression, storing result in vp.
- */
-int
-v_evaluate(struct tbl *vp, const char *expr, volatile int error_ok,
-    bool arith)
-{
-	struct tbl *v;
-	Expr_state curstate;
-	Expr_state * const es = &curstate;
-	int i;
-
-	/* save state to allow recursive calls */
-	curstate.expression = curstate.tokp = expr;
-	curstate.noassign = 0;
-	curstate.arith = arith;
-	curstate.evaling = (struct tbl *) 0;
-
-	newenv(E_ERRH);
-	i = sigsetjmp(e->jbuf, 0);
-	if (i) {
-		/* Clear EXPRINEVAL in of any variables we were playing with */
-		if (curstate.evaling)
-			curstate.evaling->flag &= ~EXPRINEVAL;
-		quitenv(NULL);
-		if (i == LAEXPR) {
-			if (error_ok == KSH_RETURN_ERROR)
-				return 0;
-			errorf(null);
-		}
-		unwind(i);
-		/* NOTREACHED */
-	}
-
-	token(es);
-#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(es, evalexpr(es, MAX_PREC));
-
-	if (es->tok != END)
-		evalerr(es, ET_UNEXPECTED, (char *) 0);
-
-	if (vp->flag & INTEGER)
-		setint_v(vp, v, es->arith);
-	else
-		/* can fail if readonly */
-		setstr(vp, str_val(v), error_ok);
-
-	quitenv(NULL);
-
-	return 1;
-}
-
-static void
-evalerr(Expr_state *es, enum error_type type, const char *str)
-{
-	char tbuf[2];
-	const char *s;
-
-	es->arith = false;
-	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(Expr_state *es, enum prec prec)
-{
-	struct tbl *vl, *vr = NULL, *vasn;
-	enum token op;
-	long res = 0;
-
-	if (prec == P_PRIMARY) {
-		op = es->tok;
-		if (op == O_BNOT || op == O_LNOT || op == O_MINUS ||
-		    op == O_PLUS) {
-			token(es);
-			vl = intvar(es, evalexpr(es, 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(es);
-			vl = evalexpr(es, MAX_PREC);
-			if (es->tok != CLOSE_PAREN)
-				evalerr(es, ET_STR, "missing )");
-			token(es);
-		} else if (op == O_PLUSPLUS || op == O_MINUSMINUS) {
-			token(es);
-			vl = do_ppmm(es, op, es->val, true);
-			token(es);
-		} else if (op == VAR || op == LIT) {
-			vl = es->val;
-			token(es);
-		} else {
-			evalerr(es, ET_UNEXPECTED, (char *) 0);
-			/* NOTREACHED */
-		}
-		if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) {
-			vl = do_ppmm(es, es->tok, vl, false);
-			token(es);
-		}
-		return vl;
-	}
-	vl = evalexpr(es, ((int) prec) - 1);
-	for (op = es->tok; IS_BINOP(op) && opinfo[(int) op].prec == prec;
-	    op = es->tok) {
-		token(es);
-		vasn = vl;
-		if (op != O_ASN) /* vl may not have a value yet */
-			vl = intvar(es, vl);
-		if (IS_ASSIGNOP(op)) {
-			assign_check(es, op, vasn);
-			vr = intvar(es, evalexpr(es, P_ASSIGN));
-		} else if (op != O_TERN && op != O_LAND && op != O_LOR)
-			vr = intvar(es, evalexpr(es, ((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(es, 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(es, evalexpr(es, ((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(es, evalexpr(es, ((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(es, MAX_PREC);
-				if (!e)
-					es->noassign--;
-				if (es->tok != CTERN)
-					evalerr(es, ET_STR, "missing :");
-				token(es);
-				if (e)
-					es->noassign++;
-				vr = evalexpr(es, 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, es->arith);
-			else
-				setint(vasn, res);
-			vl = vr;
-		} else if (op != O_TERN)
-			vl->val.i = res;
-	}
-	return vl;
-}
-
-static void
-token(Expr_state *es)
-{
-	const char *cp;
-	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(es, ET_STR, "missing ]");
-			cp += len;
-		} else if (c == '(' /*)*/ ) {
-			/* todo: add math functions (all take single argument):
-			 * abs acos asin atan cos cosh exp int log sin sinh sqrt
-			 * tan tanh
-			 */
-			;
-		}
-		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, es->arith) == NULL)
-			evalerr(es, 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(Expr_state *es, enum token op, struct tbl *vasn, bool is_prefix)
-{
-	struct tbl *vl;
-	int oval;
-
-	assign_check(es, op, vasn);
-
-	vl = intvar(es, vasn);
-	oval = op == O_PLUSPLUS ? vl->val.i++ : vl->val.i--;
-	if (vasn->flag & INTEGER)
-		setint_v(vasn, vl, es->arith);
-	else
-		setint(vasn, vl->val.i);
-	if (!is_prefix)		/* undo the inc/dec */
-		vl->val.i = oval;
-
-	return vl;
-}
-
-static void
-assign_check(Expr_state *es, enum token op, struct tbl *vasn)
-{
-	if (vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE))
-		evalerr(es, ET_LVALUE, opinfo[(int) op].name);
-	else if (vasn->flag & RDONLY)
-		evalerr(es, ET_RDONLY, opinfo[(int) op].name);
-}
-
-static struct tbl *
-tempvar(void)
-{
-	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(Expr_state *es, struct tbl *vp)
-{
-	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, es->arith) == NULL) {
-		if (vp->flag & EXPRINEVAL)
-			evalerr(es, ET_RECURSIVE, vp->name);
-		es->evaling = vp;
-		vp->flag |= EXPRINEVAL;
-		v_evaluate(vq, str_val(vp), KSH_UNWIND_ERROR, es->arith);
-		vp->flag &= ~EXPRINEVAL;
-		es->evaling = (struct tbl *) 0;
-	}
-	return vq;
-}
--- bin/ksh/edit.c
+++ /dev/null
@@ -1,865 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/edit.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: edit.c,v 1.31 2005/12/11 20:31:21 otto Exp $	*/
-
-/*
- * Command line editing - common code
- *
- */
-
-#include "config.h"
-#ifdef EDIT
-
-#include "sh.h"
-#include "tty.h"
-#define EXTERN
-#include "edit.h"
-#undef EXTERN
-#include <sys/ioctl.h>
-#include <ctype.h>
-#include <libgen.h>
-#include <sys/stat.h>
-
-
-static void x_sigwinch(int);
-static volatile sig_atomic_t got_sigwinch;
-static void check_sigwinch(void);
-
-static int	x_file_glob(int, const char *, int, char ***);
-static int	x_command_glob(int, const char *, int, char ***);
-static int	x_locate_word(const char *, int, int, int *, int *);
-
-
-/* Called from main */
-void
-x_init(void)
-{
-	/* set to -2 to force initial binding */
-	edchars.erase = edchars.kill = edchars.intr = edchars.quit =
-	    edchars.eof = -2;
-	/* default value for deficient systems */
-	edchars.werase = 027;	/* ^W */
-
-	if (setsig(&sigtraps[SIGWINCH], x_sigwinch, SS_RESTORE_ORIG|SS_SHTRAP))
-		sigtraps[SIGWINCH].flags |= TF_SHELL_USES;
-	got_sigwinch = 1; /* force initial check */
-	check_sigwinch();
-
-#ifdef EMACS
-	x_init_emacs();
-#endif /* EMACS */
-}
-
-/* ARGSUSED */
-static void
-x_sigwinch(int sig)
-{
-	got_sigwinch = 1;
-}
-
-static void
-check_sigwinch(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);
-		}
-	}
-}
-
-/*
- * read an edited command line
- */
-int
-x_read(char *buf, size_t len)
-{
-	int	i;
-
-	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);
-	check_sigwinch();
-	return i;
-}
-
-/* tty I/O */
-
-int
-x_getc(void)
-{
-	char c;
-	int n;
-
-	while ((n = blocking_read(STDIN_FILENO, &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;
-}
-
-void
-x_flush(void)
-{
-	shf_flush(shl_out);
-}
-
-void
-x_putc(int c)
-{
-	shf_putc(c, shl_out);
-}
-
-void
-x_puts(const char *s)
-{
-	while (*s != 0)
-		shf_putc(*s++, shl_out);
-}
-
-bool
-x_mode(bool onoff)
-{
-	static bool	x_cur_mode;
-	bool		prev;
-
-	if (x_cur_mode == onoff)
-		return x_cur_mode;
-	prev = x_cur_mode;
-	x_cur_mode = onoff;
-
-	if (onoff) {
-		struct termios	cb;
-		X_chars		oldchars;
-
-		oldchars = edchars;
-		cb = tty_state;
-
-		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];
-		edchars.werase = cb.c_cc[VWERASE];
-		cb.c_iflag &= ~(INLCR|ICRNL);
-		cb.c_lflag &= ~(ISIG|ICANON|ECHO);
-		/* osf/1 processes lnext when ~icanon */
-		cb.c_cc[VLNEXT] = _POSIX_VDISABLE;
-		/* sunos 4.1.x & osf/1 processes discard(flush) when ~icanon */
-		cb.c_cc[VDISCARD] = _POSIX_VDISABLE;
-		cb.c_cc[VTIME] = 0;
-		cb.c_cc[VMIN] = 1;
-
-		tcsetattr(tty_fd, TCSADRAIN, &cb);
-
-		/* Convert unset values to internal `unset' value */
-		if (edchars.erase == _POSIX_VDISABLE)
-			edchars.erase = -1;
-		if (edchars.kill == _POSIX_VDISABLE)
-			edchars.kill = -1;
-		if (edchars.intr == _POSIX_VDISABLE)
-			edchars.intr = -1;
-		if (edchars.quit == _POSIX_VDISABLE)
-			edchars.quit = -1;
-		if (edchars.eof == _POSIX_VDISABLE)
-			edchars.eof = -1;
-		if (edchars.werase == _POSIX_VDISABLE)
-			edchars.werase = -1;
-		if (memcmp(&edchars, &oldchars, sizeof(edchars)) != 0) {
-#ifdef EMACS
-			x_emacs_keys(&edchars);
-#endif
-		}
-	} else {
-		tcsetattr(tty_fd, TCSADRAIN, &tty_state);
-	}
-
-	return prev;
-}
-
-void
-set_editmode(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 = strrchr(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(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(const char *str, int slen);
-static void	glob_table(const char *pat, XPtrV *wp, struct table *tp);
-static void	glob_path(int flags, const char *pat, XPtrV *wp,
-				const char *path);
-
-#if 0 /* not used... */
-int	x_complete_word(const char *str, int slen, int is_command,
-	    int *multiple, char **ret);
-int
-x_complete_word(const char *str, int slen, int is_command, int *multiple,
-    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(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 omit 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 && 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_list(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(int flags, const char *str, int slen, char ***wordsp)
-{
-	char *toglob;
-	char **words;
-	int nwords, i, idx, escaping;
-	XPtrV w;
-	struct source *s, *sold;
-
-	if (slen < 0)
-		return 0;
-
-	toglob = add_glob(str, slen);
-
-	/* remove all escaping backward slashes */
-	escaping = 0;
-	for (i = 0, idx = 0; toglob[i]; i++) {
-		if (toglob[i] == '\\' && !escaping) {
-			escaping = 1;
-			continue;
-		}
-
-		toglob[idx] = toglob[i];
-		idx++;
-		if (escaping) escaping = 0;
-	}
-	toglob[idx] = '\0';
-
-	/*
-	 * 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;
-};
-
-static int path_order_cmp(const void *aa, const void *bb);
-
-/* Compare routine used in x_command_glob() */
-static int
-path_order_cmp(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 = strcmp(a->word + a->base, b->word + b->base);
-	return t ? t : a->path_order - b->path_order;
-}
-
-static int
-x_command_glob(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 ||
-			    strncmp(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)	!( ctype(c, C_LEX1) || (c) == '\'' || (c) == '"' || \
-			    (c) == '`' || (c) == '=' || (c) == ':' )
-
-static int
-x_locate_word(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;
-	}
-	/* The case where pos == buflen happens to take care of itself... */
-
-	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 > 1 && buf[start-2] == '\\'); start--)
-		;
-	/* Go forwards to end of word */
-	for (end = start; end < buflen && IS_WORDC(buf[end]); end++) {
-		if (buf[end] == '\\' && (end+1) < buflen)
-			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 (buf[p] == '/')
-					break;
-			iscmd = p == end;
-		}
-		*is_commandp = iscmd;
-	}
-
-	*startp = start;
-
-	return end - start;
-}
-
-int
-x_cf_glob(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(const char *str, int slen)
-{
-	char *toglob;
-	char *s;
-	bool 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 (*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(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 (p[j] != words[0][j]) {
-				prefix_len = j;
-				break;
-			}
-	return prefix_len;
-}
-
-void
-x_free_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(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 && *p == '/'; p--)
-		;
-	for (; p > s && *p != '/'; p--)
-		;
-	if (*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(const char *pat, XPtrV *wp, struct table *tp)
-{
-	struct tstate ts;
-	struct tbl *te;
-
-	for (ktwalk(&ts, tp); (te = ktnext(&ts)); ) {
-		if (gmatch(te->name, pat, false))
-			XPput(*wp, str_save(te->name, ATEMP));
-	}
-}
-
-static void
-glob_path(int flags, const char *pat, XPtrV *wp, const char *path)
-{
-	const char *sp, *p;
-	char *xp;
-	int staterr;
-	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, ':')))
-			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++ = '/';
-			pathlen++;
-		}
-		sp = p;
-		XcheckN(xs, xp, patlen);
-		memcpy(xp, pat, patlen);
-
-		oldsize = XPsize(*wp);
-		glob_str(Xstring(xs, xp), wp, 1); /* mark dirs */
-		newsize = XPsize(*wp);
-
-		/* Check that each match is executable... */
-		words = (char **) XPptrv(*wp);
-		for (i = j = oldsize; i < newsize; i++) {
-			staterr = 0;
-			if ((search_access(words[i], X_OK, &staterr) >= 0) ||
-			    (staterr == EISDIR)) {
-				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);
-}
-
-/*
- * if argument string contains any special characters, they will
- * be escaped and the result will be put into edit buffer by
- * keybinding-specific function
- */
-int
-x_escape(const char *s, size_t len, int (*putbuf_func) (const char *, size_t))
-{
-	size_t add, wlen;
-	const char *ifs = str_val(local("IFS", 0));
-	int rval=0;
-
-	for (add = 0, wlen = len; wlen - add > 0; add++) {
-		if (strchr("\\$(){}*&;#|<>\"'`", s[add]) || strchr(ifs, s[add])) {
-			if (putbuf_func(s, add) != 0) {
-				rval = -1;
-				break;
-			}
-
-			putbuf_func("\\", 1);
-			putbuf_func(&s[add], 1);
-
-			add++;
-			wlen -= add;
-			s += add;
-			add = -1; /* after the increment it will go to 0 */
-		}
-	}
-	if (wlen > 0 && rval == 0)
-		rval = putbuf_func(s, wlen);
-
-	return (rval);
-}
-#endif /* EDIT */
--- bin/ksh/ksh_limval.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/ksh_limval.h,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: ksh_limval.h,v 1.2 2004/12/18 20:55:52 millert Exp $	*/
-
-/* Wrapper around the values.h/limits.h includes/ifdefs */
-
-/* limits.h is included in sh.h */
-
-#ifndef DMAXEXP
-# define DMAXEXP	128	/* should be big enough */
-#endif
-
-#ifndef BITS
-# define BITS(t)	(CHAR_BIT * sizeof(t))
-#endif
--- bin/ksh/tree.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/tree.h,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: tree.h,v 1.10 2005/03/28 21:28:22 deraadt 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;
-					 * time hook for TCOM.
-					 */
-	int	lineno;			/* TCOM/TFUNC: LINENO for this */
-};
-
-/* 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 ${ subst (followed by { or X) */
-#define	CSUBST	8		/* closing } of above (followed by } or X) */
-#define OPAT	9		/* open pattern: *(, @(, etc. */
-#define SPAT	10		/* separate pattern: | */
-#define CPAT	11		/* close pattern: ) */
-
-/*
- * IO redirection
- */
-struct ioword {
-	int	unit;	/* unit affected */
-	int	flag;	/* action (below) */
-	char	*name;	/* file name (unused if heredoc) */
-	char	*delim;	/* delimiter for <<,<<- */
-	char	*heredoc;/* content of heredoc */
-};
-
-/* 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 */
-#define XTIME	BIT(10)		/* timing TCOM command */
-
-/*
- * 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 */
--- bin/ksh/shf.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/shf.h,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: shf.h,v 1.6 2005/12/11 18:53:51 deraadt Exp $	*/
-
-#ifndef SHF_H
-# define SHF_H
-
-/*
- * 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(const char *, int, int, int);
-struct shf *shf_fdopen(int, int, struct shf *);
-struct shf *shf_reopen(int, int, struct shf *);
-struct shf *shf_sopen(char *, int, int, struct shf *);
-int	    shf_close(struct shf *);
-int	    shf_fdclose(struct shf *);
-char	   *shf_sclose(struct shf *);
-int	    shf_flush(struct shf *);
-int	    shf_read(char *, int, struct shf *);
-char	   *shf_getse(char *, int, struct shf *);
-int	    shf_getchar(struct shf *s);
-int	    shf_ungetc(int, struct shf *);
-int	    shf_putchar(int, struct shf *);
-int	    shf_puts(const char *, struct shf *);
-int	    shf_write(const char *, int, struct shf *);
-int	    shf_fprintf(struct shf *, const char *, ...);
-int	    shf_snprintf(char *, int, const char *, ...);
-char	    *shf_smprintf(const char *, ...);
-int	    shf_vfprintf(struct shf *, const char *, va_list);
-
-#endif /* SHF_H */
--- bin/ksh/ksh.1
+++ /dev/null
@@ -1,5609 +0,0 @@
-.\"	$OpenBSD: ksh.1,v 1.117 2006/08/03 11:22:05 jmc Exp $
-.\"
-.\"	Public Domain
-.\"
-.Dd August 19, 1996
-.Dt KSH 1
-.Os
-.Sh NAME
-.Nm ksh
-.Nd public domain Korn shell
-.Sh SYNOPSIS
-.Nm ksh
-.Bk -words
-.Op Fl +abCefhiklmnpruvXx
-.Op Fl +o Ar option
-.Oo Fl c Ar string \*(Ba Fl s \*(Ba
-.Ar \ file\ \&
-.Op Ar argument ... Oc
-.Ek
-.Sh DESCRIPTION
-.Nm
-is a command interpreter intended for both interactive and shell
-script use.
-Its command language is a superset of the
-.Xr sh 1
-shell language.
-.Pp
-The options are as follows:
-.Bl -tag -width Ds
-.It Fl c Ar string
-.Nm
-will execute the command(s) contained in
-.Ar string .
-.It Fl i
-Interactive shell.
-A shell is
-.Dq interactive
-if this
-option is used or if both standard input and standard error are attached
-to a
-.Xr tty 4 .
-An interactive shell has job control enabled, ignores the
-.Dv SIGINT ,
-.Dv SIGQUIT ,
-and
-.Dv SIGTERM
-signals, and prints prompts before reading input (see the
-.Ev PS1
-and
-.Ev PS2
-parameters).
-For non-interactive shells, the
-.Ic trackall
-option is on by default (see the
-.Ic set
-command below).
-.It Fl l
-Login shell.
-If the basename the shell is called with (i.e. argv[0])
-starts with
-.Ql -
-or if this option is used,
-the shell is assumed to be a login shell and the shell reads and executes
-the contents of
-.Pa /etc/profile
-and
-.Pa $HOME/.profile
-if they exist and are readable.
-.It Fl p
-Privileged shell.
-A shell is
-.Dq privileged
-if this option is used
-or if the real user ID or group ID does not match the
-effective user ID or group ID (see
-.Xr getuid 2
-and
-.Xr getgid 2 ) .
-A privileged shell does not process
-.Pa $HOME/.profile
-nor the
-.Ev ENV
-parameter (see below).
-Instead, the file
-.Pa /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).
-.It Fl r
-Restricted shell.
-A shell is
-.Dq restricted
-if this
-option is used;
-if the basename the shell was invoked with was
-.Dq rksh ;
-or if the
-.Ev SHELL
-parameter is set to
-.Dq rksh .
-The following restrictions come into effect after the shell processes any
-profile and
-.Ev ENV
-files:
-.Pp
-.Bl -bullet -compact
-.It
-The
-.Ic cd
-command is disabled.
-.It
-The
-.Ev SHELL ,
-.Ev ENV ,
-and
-.Ev PATH
-parameters cannot be changed.
-.It
-Command names can't be specified with absolute or relative paths.
-.It
-The
-.Fl p
-option of the built-in command
-.Ic command
-can't be used.
-.It
-Redirections that create files can't be used (i.e.\&
-.Ql \*(Gt ,
-.Ql \*(Gt\*(Ba ,
-.Ql \*(Gt\*(Gt ,
-.Ql \*(Lt\*(Gt ) .
-.El
-.It Fl s
-The shell reads commands from standard input; all non-option arguments
-are positional parameters.
-.El
-.Pp
-In addition to the above, the options described in the
-.Ic set
-built-in command can also be used on the command line:
-both
-.Op Fl +abCefhkmnuvXx
-and
-.Op Fl +o Ar option
-can be used for single letter or long options, respectively.
-.Pp
-If neither the
-.Fl c
-nor the
-.Fl s
-option is 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 the standard input.
-The name of the shell (i.e. the contents of $0)
-is determined as follows: if the
-.Fl c
-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 basename the shell was called with (i.e. argv[0]) is used.
-.Pp
-If the
-.Ev ENV
-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
-.Pq Sq ~
-substitution and the resulting file
-(if any) is read and executed.
-In order to have an interactive (as opposed to login) shell
-process a startup file,
-.Ev ENV
-may be set and exported (see below) in
-.Pa $HOME/.profile
-\- future interactive shell invocations will process any file pointed to by
-.Ev $ENV :
-.Pp
-.Dl export ENV=$HOME/.kshrc
-.Pp
-.Pa $HOME/.kshrc
-is then free to specify instructions for interactive shells.
-For example, the global configuration file may be sourced:
-.Bd -literal -offset indent
-if [ -o interactive ]; then
-\&. /etc/ksh.kshrc
-fi
-.Ed
-.Pp
-The above strategy may be employed to keep
-setup procedures for login shells in
-.Pa $HOME/.profile
-and setup procedures for interactive shells in
-.Pa $HOME/.kshrc .
-Of course, since login shells are also interactive,
-any commands placed in
-.Pa $HOME/.kshrc
-will be executed by login shells too.
-.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.
-.Ss Command syntax
-The shell begins parsing its input by breaking it into
-.Em words .
-Words, which are sequences of characters, are delimited by unquoted whitespace
-characters (space, tab, and newline) or meta-characters
-.Po
-.Ql \*(Lt ,
-.Ql \*(Gt ,
-.Ql \*(Ba ,
-.Ql \&; ,
-.Ql ( ,
-.Ql \&) ,
-and
-.Ql &
-.Pc .
-Aside from delimiting words, spaces and tabs are ignored, while newlines
-usually delimit commands.
-The meta-characters are used in building the following
-.Em tokens :
-.Ql \*(Lt ,
-.Ql \*(Lt& ,
-.Ql \*(Lt\*(Lt ,
-.Ql \*(Gt ,
-.Ql \*(Gt& ,
-.Ql \*(Gt\*(Gt ,
-etc. are used to specify redirections (see
-.Sx Input/output redirection
-below);
-.Ql \*(Ba
-is used to create pipelines;
-.Ql \*(Ba&
-is used to create co-processes (see
-.Sx Co-processes
-below);
-.Ql \&;
-is used to separate commands;
-.Ql &
-is used to create asynchronous pipelines;
-.Ql &&
-and
-.Ql ||
-are used to specify conditional execution;
-.Ql ;;
-is used in
-.Ic case
-statements;
-.Ql (( .. ))
-is used in arithmetic expressions;
-and lastly,
-.Ql \&( .. )\&
-is used to create subshells.
-.Pp
-Whitespace and meta-characters can be quoted individually using a backslash
-.Pq Sq \e ,
-or in groups using double
-.Pq Sq \&"
-or single
-.Pq Sq '
-quotes.
-Note that the following characters are also treated specially by the
-shell and must be quoted if they are to represent themselves:
-.Ql \e ,
-.Ql \&" ,
-.Ql ' ,
-.Ql # ,
-.Ql $ ,
-.Ql ` ,
-.Ql ~ ,
-.Ql { ,
-.Ql } ,
-.Ql * ,
-.Ql \&? ,
-and
-.Ql [ .
-The first three of these are the above mentioned quoting characters (see
-.Sx Quoting
-below);
-.Ql # ,
-if used at the beginning of a word, introduces a comment \(em everything after
-the
-.Ql #
-up to the nearest newline is ignored;
-.Ql $
-is used to introduce parameter, command, and arithmetic substitutions (see
-.Sx Substitution
-below);
-.Ql `
-introduces an old-style command substitution (see
-.Sx Substitution
-below);
-.Ql ~
-begins a directory expansion (see
-.Sx Tilde expansion
-below);
-.Ql {
-and
-.Ql }
-delimit
-.Xr csh 1 Ns -style
-alterations (see
-.Sx Brace expansion
-below);
-and finally,
-.Ql * ,
-.Ql \&? ,
-and
-.Ql [
-are used in file name generation (see
-.Sx File name patterns
-below).
-.Pp
-As words and tokens are parsed, the shell builds commands, of which there
-are two basic types:
-.Em simple-commands ,
-typically programs that are executed, and
-.Em compound-commands ,
-such as
-.Ic for
-and
-.Ic if
-statements, grouping constructs, and function definitions.
-.Pp
-A simple-command consists of some combination of parameter assignments
-(see
-.Sx Parameters
-below),
-input/output redirections (see
-.Sx 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 external command
-(i.e. a separate executable file that is located using the
-.Ev PATH
-parameter; see
-.Sx Command execution
-below).
-Note that all command constructs have an exit status: for external commands,
-this is related to the status returned by
-.Xr wait 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,
-etc.) 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 0 if there were no command substitutions.
-.Pp
-Commands can be chained together using the
-.Ql |
-token to form pipelines, in which the standard output of each command but the
-last is piped (see
-.Xr pipe 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
-.Ql \&!
-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;
-if the original status was not 0, the complemented status will be 0.
-.Pp
-.Em Lists
-of commands can be created by separating pipelines by any of the following
-tokens:
-.Ql && ,
-.Ql || ,
-.Ql & ,
-.Ql |& ,
-and
-.Ql \&; .
-The first two are for conditional execution:
-.Dq Ar cmd1 No && Ar cmd2
-executes
-.Ar cmd2
-only if the exit status of
-.Ar cmd1
-is zero;
-.Ql ||
-is the opposite \(em
-.Ar cmd2
-is executed only if the exit status of
-.Ar cmd1
-is non-zero.
-.Ql &&
-and
-.Ql ||
-have equal precedence which is higher than that of
-.Ql & ,
-.Ql |& ,
-and
-.Ql \&; ,
-which also have equal precedence.
-Note that the
-.Ql &&
-and
-.Ql ||
-operators are
-.Qq left-associative .
-For example, both of these commands will print only
-.Qq bar :
-.Bd -literal -offset indent
-$ false && echo foo || echo bar
-$ true || echo foo && echo bar
-.Ed
-.Pp
-The
-.Ql &
-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; see
-.Sx Job control
-below).
-When an asynchronous command is started when job control is disabled
-(i.e. in most scripts), the command is started with signals
-.Dv SIGINT
-and
-.Dv SIGQUIT
-ignored and with input redirected from
-.Pa /dev/null
-(however, redirections specified in the asynchronous command have precedence).
-The
-.Ql |&
-operator starts a co-process which is a special kind of asynchronous process
-(see
-.Sx Co-processes
-below).
-Note that a command must follow the
-.Ql &&
-and
-.Ql ||
-operators, while it need not follow
-.Ql & ,
-.Ql |& ,
-or
-.Ql \&; .
-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.
-.Pp
-Compound commands are created using the following reserved words.
-These words
-are only recognized if they are unquoted and if they are used as the first
-word of a command (i.e. they can't be preceded by parameter assignments or
-redirections):
-.Bd -literal -offset indent
-case     else     function     then      !
-do       esac     if           time      [[
-done     fi       in           until     {
-elif     for      select       while     }
-.Ed
-.Pp
-.Sy Note :
-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
-.Ic exec
-statement should be used instead to redirect file descriptors before the
-control structure.
-.Pp
-In the following compound command descriptions, command lists (denoted as
-.Em list )
-that are followed by reserved words must end with a semicolon, a newline, or
-a (syntactically correct) reserved word.
-For example, the following are all valid:
-.Bd -literal -offset indent
-$ { echo foo; echo bar; }
-$ { echo foo; echo bar\*(Ltnewline\*(Gt }
-$ { { echo foo; echo bar; } }
-.Ed
-.Pp
-This is not valid:
-.Pp
-.Dl $ { echo foo; echo bar }
-.Bl -tag -width Ds
-.It Pq Ar list
-Execute
-.Ar list
-in a subshell.
-There is no implicit way to pass environment changes from a
-subshell back to its parent.
-.It { Ar list ; No }
-Compound construct;
-.Ar list
-is executed, but not in a subshell.
-Note that
-.Ql {
-and
-.Ql }
-are reserved words, not meta-characters.
-.It Xo case Ar word No in
-.Oo Op (
-.Ar \ pattern
-.Op \*(Ba Ar pattern
-.No ... No )
-.Ar list No ;;\ \& Oc ... esac
-.Xc
-The
-.Ic case
-statement attempts to match
-.Ar word
-against a specified
-.Ar pattern ;
-the
-.Ar list
-associated with the first successfully matched pattern is executed.
-Patterns used in
-.Ic case
-statements are the same as those used for file name patterns except that the
-restrictions regarding
-.Ql \&.
-and
-.Ql /
-are dropped.
-Note that any unquoted space before and after a pattern is
-stripped; any space within 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
-.Ic in
-and
-.Ic esac
-e.g.\&
-.Ic case $foo { *) echo bar; } .
-The exit status of a
-.Ic case
-statement is that of the executed
-.Ar list ;
-if no
-.Ar list
-is executed, the exit status is zero.
-.It Xo for Ar name
-.Oo in Ar word No ... Oc ;
-.No do Ar list ; No done
-.Xc
-For each
-.Ar word
-in the specified word list, the parameter
-.Ar name
-is set to the word and
-.Ar list
-is executed.
-If
-.Ic in
-is not used to specify a word list, the positional parameters
-($1, $2, etc.)\&
-are used instead.
-For historical reasons, open and close braces may be used instead of
-.Ic do
-and
-.Ic done
-e.g.\&
-.Ic for i; { echo $i; } .
-The exit status of a
-.Ic for
-statement is the last exit status of
-.Ar list ;
-if
-.Ar list
-is never executed, the exit status is zero.
-.It Xo if Ar list ;
-.No then Ar list ;
-.Oo elif Ar list ;
-.No then Ar list ; Oc
-.No ...
-.Oo else Ar list ; Oc
-.No fi
-.Xc
-If the exit status of the first
-.Ar list
-is zero, the second
-.Ar list
-is executed; otherwise, the
-.Ar list
-following the
-.Ic elif ,
-if any, is executed with similar consequences.
-If all the lists following the
-.Ic if
-and
-.Ic elif Ns s
-fail (i.e. exit with non-zero status), the
-.Ar list
-following the
-.Ic else
-is executed.
-The exit status of an
-.Ic if
-statement is that of non-conditional
-.Ar list
-that is executed; if no non-conditional
-.Ar list
-is executed, the exit status is zero.
-.It Xo select Ar name
-.Oo in Ar word No ... Oc ;
-.No do Ar list ; No done
-.Xc
-The
-.Ic select
-statement provides an automatic method of presenting the user with a menu and
-selecting from it.
-An enumerated list of the specified
-.Ar word Ns (s)
-is printed on standard error, followed by a prompt
-.Po
-.Ev PS3: normally
-.Sq #?\ \&
-.Pc .
-A number corresponding to one of the enumerated words is then read from
-standard input,
-.Ar name
-is set to the selected word (or unset if the selection is not valid),
-.Ev REPLY
-is set to what was read (leading/trailing space is stripped), and
-.Ar list
-is executed.
-If a blank line (i.e. zero or more
-.Ev IFS
-characters) is entered, the menu is reprinted without executing
-.Ar list .
-.Pp
-When
-.Ar list
-completes, the enumerated list is printed if
-.Ev REPLY
-is
-.Dv NULL ,
-the prompt is printed, and so on.
-This process continues until an end-of-file
-is read, an interrupt is received, or a
-.Ic break
-statement is executed inside the loop.
-If
-.Dq in word ...
-is omitted, the positional parameters are used
-(i.e. $1, $2, etc.).
-For historical reasons, open and close braces may be used instead of
-.Ic do
-and
-.Ic done
-e.g.\&
-.Ic select i; { echo $i; } .
-The exit status of a
-.Ic select
-statement is zero if a
-.Ic break
-statement is used to exit the loop, non-zero otherwise.
-.It Xo until Ar list ;
-.No do Ar list ;
-.No done
-.Xc
-This works like
-.Ic while ,
-except that the body is executed only while the exit status of the first
-.Ar list
-is non-zero.
-.It Xo while Ar list ;
-.No do Ar list ;
-.No done
-.Xc
-A
-.Ic while
-is a pre-checked loop.
-Its body is executed as often as the exit status of the first
-.Ar list
-is zero.
-The exit status of a
-.Ic while
-statement is the last exit status of the
-.Ar list
-in the body of the loop; if the body is not executed, the exit status is zero.
-.It Xo function Ar name
-.No { Ar list ; No }
-.Xc
-Defines the function
-.Ar name
-(see
-.Sx Functions
-below).
-Note that redirections specified after a function definition are
-performed whenever the function is executed, not when the function definition
-is executed.
-.It Ar name Ns () Ar command
-Mostly the same as
-.Ic function
-(see
-.Sx Functions
-below).
-.It Xo Ic time Op Fl p
-.Op Ar pipeline
-.Xc
-The
-.Ic time
-reserved word is described in the
-.Sx Command execution
-section.
-.It (( Ar expression No ))
-The arithmetic expression
-.Ar expression
-is evaluated; equivalent to
-.Dq let expression
-(see
-.Sx Arithmetic expressions
-and the
-.Ic let
-command, below).
-.It Bq Bq Ar \ \&expression\ \&
-Similar to the
-.Ic test
-and
-.Ic \&[ ... \&]
-commands (described later), with the following exceptions:
-.Bl -bullet -offset indent
-.It
-Field splitting and file name generation are not performed on arguments.
-.It
-The
-.Fl a
-.Pq AND
-and
-.Fl o
-.Pq OR
-operators are replaced with
-.Ql &&
-and
-.Ql || ,
-respectively.
-.It
-Operators (e.g.\&
-.Sq Fl f ,
-.Sq = ,
-.Sq \&! )
-must be unquoted.
-.It
-The second operand of the
-.Sq !=
-and
-.Sq =
-expressions are patterns (e.g. the comparison
-.Ic [[ foobar = f*r ]]
-succeeds).
-.It
-There are two additional binary operators,
-.Ql \*(Lt
-and
-.Ql \*(Gt ,
-which return true if their first string operand is less than, or greater than,
-their second string operand, respectively.
-.It
-The single argument form of
-.Ic test ,
-which tests if the argument has a non-zero length, is not valid; explicit
-operators must always be used e.g. instead of
-.No \&[ Ar str No \&]
-use
-.No \&[[ -n Ar str No \&]] .
-.It
-Parameter, command, and arithmetic substitutions are performed as expressions
-are evaluated and lazy expression evaluation is used for the
-.Ql &&
-and
-.Ql ||
-operators.
-This means that in the following statement,
-.Ic $(\*(Lt foo)
-is evaluated if and only if the file
-.Pa foo
-exists and is readable:
-.Bd -literal -offset indent
-$ [[ -r foo && $(\*(Lt foo) = b*r ]]
-.Ed
-.El
-.El
-.Ss Quoting
-Quoting is used to prevent the shell from treating characters or words
-specially.
-There are three methods of quoting.
-First,
-.Ql \e
-quotes the following character, unless it is at the end of a line, in which
-case both the
-.Ql \e
-and the newline are stripped.
-Second, a single quote
-.Pq Sq '
-quotes everything up to the next single quote (this may span lines).
-Third, a double quote
-.Pq Sq \&"
-quotes all characters, except
-.Ql $ ,
-.Ql `
-and
-.Ql \e ,
-up to the next unquoted double quote.
-.Ql $
-and
-.Ql `
-inside double quotes have their usual meaning (i.e. parameter, command, or
-arithmetic substitution) except no field splitting is carried out on the
-results of double-quoted substitutions.
-If a
-.Ql \e
-inside a double-quoted string is followed by
-.Ql \e ,
-.Ql $ ,
-.Ql ` ,
-or
-.Ql \&" ,
-it is replaced by the second character; if it is followed by a newline, both
-the
-.Ql \e
-and the newline are stripped; otherwise, both the
-.Ql \e
-and the character following are unchanged.
-.Pp
-.Sy Note :
-See
-.Sx POSIX mode
-below for a special rule regarding
-differences in quoting when the shell is in POSIX mode.
-.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 (i.e. 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:
-.Bd -literal -offset indent
-autoload='typeset -fu'
-functions='typeset -f'
-hash='alias -t'
-history='fc -l'
-integer='typeset -i'
-local='typeset'
-login='exec login'
-nohup='nohup '
-r='fc -e -'
-stop='kill -STOP'
-suspend='kill -STOP $$'
-type='whence -v'
-.Ed
-.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
-.Ic alias -t .
-Note that changing the
-.Ev PATH
-parameter clears the saved paths for all tracked aliases.
-If the
-.Ic trackall
-option is set (i.e.\&
-.Ic set -o Ic trackall
-or
-.Ic set -h ) ,
-the shell tracks all commands.
-This option is set automatically for non-interactive shells.
-For interactive shells, only the following commands are
-automatically tracked:
-.Xr cat 1 ,
-.Xr cc 1 ,
-.Xr chmod 1 ,
-.Xr cp 1 ,
-.Xr date 1 ,
-.Xr ed 1 ,
-.Xr emacs 1 ,
-.Xr grep 1 ,
-.Xr ls 1 ,
-.Xr mail 1 ,
-.Xr make 1 ,
-.Xr mv 1 ,
-.Xr pr 1 ,
-.Xr rm 1 ,
-.Xr sed 1 ,
-.Xr sh 1 ,
-.Xr vi 1 ,
-and
-.Xr who 1 .
-.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
-.Pf $ Ns Ar name
-or
-.Pf ${ Ns Ar ... Ns } ;
-command substitutions take the form
-.Pf $( Ns Ar command Ns \&)
-or
-.Pf ` Ns Ar command Ns ` ;
-and arithmetic substitutions take the form
-.Pf $(( Ns Ar expression Ns )) .
-.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
-.Ev IFS
-parameter.
-The
-.Ev IFS
-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
-.Ev IFS
-characters are called
-.Dq IFS whitespace .
-Sequences of one or more
-.Ev IFS
-whitespace characters, in combination with zero or one
-.Pf non- Ev IFS
-whitespace
-characters, delimit a field.
-As a special case, leading and trailing
-.Ev IFS
-whitespace is stripped (i.e. no leading or trailing empty field is created by
-it); leading
-.Pf non- Ev IFS
-whitespace does create an empty field.
-.Pp
-Example: If
-.Ev IFS
-is set to
-.Dq \*(Ltspace\*(Gt: ,
-and VAR is set to
-.Dq \*(Ltspace\*(GtA\*(Ltspace\*(Gt:\*(Ltspace\*(Gt\*(Ltspace\*(GtB::D ,
-the substitution for $VAR results in four fields:
-.Sq A ,
-.Sq B ,
-.Sq
-(an empty field),
-and
-.Sq D .
-Note that if the
-.Ev IFS
-parameter is set to the
-.Dv 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 the immediate result of
-the substitution.
-Using the previous example, the substitution for $VAR:E
-results in the fields:
-.Sq A ,
-.Sq B ,
-.Sq ,
-and
-.Sq D:E ,
-not
-.Sq A ,
-.Sq B ,
-.Sq ,
-.Sq D ,
-and
-.Sq 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
-.Dv IFS
-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
-.Pf $( Ns Ar command Ns \&)
-substitutions, normal quoting rules are used when
-.Ar command
-is parsed; however, for the
-.Pf ` Ns Ar command Ns `
-form, a
-.Ql \e
-followed by any of
-.Ql $ ,
-.Ql ` ,
-or
-.Ql \e
-is stripped (a
-.Ql \e
-followed by any other character is unchanged).
-As a special case in command substitutions, a command of the form
-.Pf \*(Lt Ar file
-is interpreted to mean substitute the contents of
-.Ar file .
-Note that
-.Ic $(\*(Lt foo)
-has the same effect as
-.Ic $(cat foo) ,
-but it is carried out more efficiently because no process is started.
-.Pp
-.Sy Note :
-.Pf $( Ns Ar command Ns \&)
-expressions are currently parsed by finding the matching parenthesis,
-regardless of quoting.
-This should be fixed soon.
-.Pp
-Arithmetic substitutions are replaced by the value of the specified expression.
-For example, the command
-.Ic echo $((2+3*4))
-prints 14.
-See
-.Sx Arithmetic expressions
-for a description of an expression.
-.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
-.Po
-.Ql _
-counts as a letter
-.Pc .
-The latter form can be treated as arrays by appending an array index of the
-form
-.Op Ar expr
-where
-.Ar expr
-is an arithmetic expression.
-Array indices are currently limited to the range 0 through 2047, inclusive.
-Parameter substitutions take the form
-.Pf $ Ns Ar name ,
-.Pf ${ Ns Ar name Ns } ,
-or
-.Sm off
-.Pf ${ Ar name Oo Ar expr Oc }
-.Sm on
-where
-.Ar name
-is a parameter name.
-If substitution is performed on a parameter
-(or an array parameter element)
-that is not set, a null string is substituted unless the
-.Ic nounset
-option
-.Po
-.Ic set Fl o Ic nounset
-or
-.Ic set Fl u
-.Pc
-is set, in which case an error occurs.
-.Pp
-Parameters can be assigned values in a number of ways.
-First, the shell implicitly sets some parameters like
-.Ql # ,
-.Ql PWD ,
-and
-.Ql $ ;
-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,
-.Ic FOO=bar
-sets the parameter
-.Dq FOO
-to
-.Dq 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 the implications of this).
-Note that both the parameter name and the
-.Ql =
-must be unquoted for the shell to recognize a parameter assignment.
-The fourth way of setting a parameter is with the
-.Ic export ,
-.Ic readonly ,
-and
-.Ic typeset
-commands; see their descriptions in the
-.Sx Command execution
-section.
-Fifth,
-.Ic for
-and
-.Ic select
-loops set parameters as well as the
-.Ic getopts ,
-.Ic read ,
-and
-.Ic set -A
-commands.
-Lastly, parameters can be assigned values using assignment operators
-inside arithmetic expressions (see
-.Sx Arithmetic expressions
-below) or using the
-.Sm off
-.Pf ${ Ar name No = Ar value No }
-.Sm on
-form of the parameter substitution (see below).
-.Pp
-Parameters with the export attribute (set using the
-.Ic export
-or
-.Ic typeset Fl x
-commands, or by parameter assignments followed by simple commands) are put in
-the environment (see
-.Xr environ 7 )
-of commands run by the shell as
-.Ar name Ns = Ns Ar value
-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.
-.Pp
-Modifiers can be applied to the
-.Pf ${ Ns Ar name Ns }
-form of parameter substitution:
-.Bl -tag -width Ds
-.Sm off
-.It ${ Ar name No :- Ar word No }
-.Sm on
-If
-.Ar name
-is set and not
-.Dv NULL ,
-it is substituted; otherwise,
-.Ar word
-is substituted.
-.Sm off
-.It ${ Ar name No :+ Ar word No }
-.Sm on
-If
-.Ar name
-is set and not
-.Dv NULL ,
-.Ar word
-is substituted; otherwise, nothing is substituted.
-.Sm off
-.It ${ Ar name No := Ar word No }
-.Sm on
-If
-.Ar name
-is set and not
-.Dv NULL ,
-it is substituted; otherwise, it is assigned
-.Ar word
-and the resulting value of
-.Ar name
-is substituted.
-.Sm off
-.It ${ Ar name No :? Ar word No }
-.Sm on
-If
-.Ar name
-is set and not
-.Dv NULL ,
-it is substituted; otherwise,
-.Ar word
-is printed on standard error (preceded by
-.Ar name : )
-and an error occurs (normally causing termination of a shell script, function,
-or script sourced using the
-.Sq \&.
-built-in).
-If
-.Ar word
-is omitted, the string
-.Dq parameter null or not set
-is used instead.
-.El
-.Pp
-In the above modifiers, the
-.Ql \&:
-can be omitted, in which case the conditions only depend on
-.Ar name
-being set (as opposed to set and not
-.Dv NULL ) .
-If
-.Ar word
-is needed, parameter, command, arithmetic, and tilde substitution are performed
-on it; if
-.Ar word
-is not needed, it is not evaluated.
-.Pp
-The following forms of parameter substitution can also be used:
-.Pp
-.Bl -tag -width Ds -compact
-.It Pf ${# Ns Ar name Ns \&}
-The number of positional parameters if
-.Ar name
-is
-.Ql * ,
-.Ql @ ,
-or not specified; otherwise the length of the string value of parameter
-.Ar name .
-.Pp
-.It Pf ${# Ns Ar name Ns [*]}
-.It Pf ${# Ns Ar name Ns [@]}
-The number of elements in the array
-.Ar name .
-.Pp
-.Sm off
-.It Xo
-.Pf ${ Ar name
-.Pf # Ar pattern No }
-.Xc
-.It Xo
-.Pf ${ Ar name
-.Pf ## Ar pattern No }
-.Xc
-.Sm on
-If
-.Ar pattern
-matches the beginning of the value of parameter
-.Ar name ,
-the matched text is deleted from the result of substitution.
-A single
-.Ql #
-results in the shortest match, and two
-of them result in the longest match.
-.Pp
-.Sm off
-.It Xo
-.Pf ${ Ar name
-.Pf % Ar pattern No }
-.Xc
-.It Xo
-.Pf ${ Ar name
-.Pf %% Ar pattern No }
-.Xc
-.Sm on
-Like ${..#..} substitution, but it deletes from the end of the value.
-.El
-.Pp
-The following special parameters are implicitly set by the shell and cannot be
-set directly using assignments:
-.Bl -tag -width "1 ... 9"
-.It Ev \&!
-Process ID of the last background process started.
-If no background processes have been started, the parameter is not set.
-.It Ev \&#
-The number of positional parameters ($1, $2, etc.).
-.It Ev \&$
-The PID of the shell, or the PID of the original shell if it is a subshell.
-Do
-.Em NOT
-use this mechanism for generating temporary file names; see
-.Xr mktemp 1
-instead.
-.It Ev -
-The concatenation of the current single letter options (see the
-.Ic set
-command below for a list of options).
-.It Ev \&?
-The exit status of the last non-asynchronous command executed.
-If the last command was killed by a signal,
-.Ic $?\&
-is set to 128 plus the signal number.
-.It Ev 0
-The name of the shell, determined as follows:
-the first argument to
-.Nm
-if it was invoked with the
-.Fl c
-option and arguments were given; otherwise the
-.Ar file
-argument, if it was supplied;
-or else the basename the shell was invoked with (i.e.\&
-.Li argv[0] ) .
-.Ev $0
-is also set to the name of the current script or
-the name of the current function, if it was defined with the
-.Ic function
-keyword (i.e. a Korn shell style function).
-.It Ev 1 No ... Ev 9
-The first nine positional parameters that were supplied to the shell, function,
-or script sourced using the
-.Sq \&.
-built-in.
-Further positional parameters may be accessed using
-.Pf ${ Ar number Ns } .
-.It Ev *
-All positional parameters (except parameter 0) i.e. $1, $2, $3, ...
-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
-.Ev IFS
-parameter (or the empty string if
-.Ev IFS
-is
-.Dv NULL ) .
-.It Ev @
-Same as
-.Ic $* ,
-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.
-.Ic $@
-can be used to access arguments, verbatim, without losing
-.Dv NULL
-arguments or splitting arguments with spaces.
-.El
-.Pp
-The following parameters are set and/or used by the shell:
-.Bl -tag -width "EXECSHELL"
-.It Ev _ No (underscore)
-When an external command is executed by the shell, this parameter is set in the
-environment of the new process to the path of the executed command.
-In interactive use, this parameter is also set in the parent shell to the last
-word of the previous command.
-When
-.Ev MAILPATH
-messages are evaluated, this parameter contains the name of the file that
-changed (see the
-.Ev MAILPATH
-parameter, below).
-.It Ev CDPATH
-Search path for the
-.Ic cd
-built-in command.
-It works the same way as
-.Ev PATH
-for those directories not beginning with
-.Ql /
-in
-.Ic cd
-commands.
-Note that if
-.Ev CDPATH
-is set and does not contain
-.Sq \&.
-or contains an empty path, the current directory is not searched.
-Also, the
-.Ic cd
-built-in command will display the resulting directory when a match is found
-in any search path other than the empty path.
-.It Ev COLUMNS
-Set to the number of columns on the terminal or window.
-Currently set to the
-.Dq cols
-value as reported by
-.Xr stty 1
-if that value is non-zero.
-This parameter is used by the interactive line editing modes, and by the
-.Ic select ,
-.Ic set -o ,
-and
-.Ic kill -l
-commands to format information columns.
-.It Ev EDITOR
-If the
-.Ev VISUAL
-parameter is not set, this parameter controls the command-line editing mode for
-interactive shells.
-See the
-.Ev VISUAL
-parameter below for how this works.
-.Pp
-Note:
-traditionally,
-.Ev EDITOR
-was used to specify the name of an (old-style) line editor, such as
-.Xr ed 1 ,
-and
-.Ev VISUAL
-was used to specify a (new-style) screen editor, such as
-.Xr vi 1 .
-Hence if
-.Ev VISUAL
-is set, it overrides
-.Ev EDITOR .
-.It Ev ENV
-If this parameter is found to be set after any profile files are executed, the
-expanded value is used as a shell startup file.
-It typically contains function and alias definitions.
-.It Ev ERRNO
-Integer value of the shell's
-.Va errno
-variable.
-It indicates the reason the last system call failed.
-Not yet implemented.
-.It Ev EXECSHELL
-If set, this parameter is assumed to contain the shell that is to be used to
-execute commands that
-.Xr execve 2
-fails to execute and which do not start with a
-.Dq #! Ns Ar shell
-sequence.
-.It Ev FCEDIT
-The editor used by the
-.Ic fc
-command (see below).
-.It Ev FPATH
-Like
-.Ev PATH ,
-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
-.Ev PATH .
-See
-.Sx Functions
-below for more information.
-.It Ev HISTFILE
-The name of the file used to store command 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
-.Ev HISTFILE
-parameters all point to the same file.
-.Pp
-.Sy Note :
-If
-.Ev HISTFILE
-isn't set, no history file is used.
-This is different from the original Korn shell, which uses
-.Pa $HOME/.sh_history ;
-in the future,
-.Nm pdksh
-may also use a default history file.
-.It Ev HISTSIZE
-The number of commands normally stored for history.
-The default is 500.
-.It Ev HOME
-The default directory for the
-.Ic cd
-command and the value substituted for an unqualified
-.Ic ~
-(see
-.Sx Tilde expansion
-below).
-.It Ev IFS
-Internal field separator, used during substitution and by the
-.Ic read
-command, to split values into distinct arguments; normally set to space, tab,
-and newline.
-See
-.Sx Substitution
-above for details.
-.Pp
-.Sy Note :
-This parameter is not imported from the environment when the shell is
-started.
-.It Ev KSH_VERSION
-The version of the shell and the date the version was created (read-only).
-.It Ev LINENO
-The line number of the function or shell script that is currently being
-executed.
-.It Ev LINES
-Set to the number of lines on the terminal or window.
-.It Ev MAIL
-If set, the user will be informed of the arrival of mail in the named file.
-This parameter is ignored if the
-.Ev MAILPATH
-parameter is set.
-.It Ev MAILCHECK
-How often, in seconds, the shell will check for mail in the file(s) specified
-by
-.Ev MAIL
-or
-.Ev MAILPATH .
-If set to 0, the shell checks before each prompt.
-The default is 600 (10 minutes).
-.It Ev MAILPATH
-A list of files to be checked for mail.
-The list is colon separated, and each file may be followed by a
-.Ql \&?
-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
-.Ic $_
-contains the name of the file.
-The default message is
-.Dq you have mail in $_ .
-.It Ev OLDPWD
-The previous working directory.
-Unset if
-.Ic cd
-has not successfully changed directories since the shell started, or if the
-shell doesn't know where it is.
-.It Ev OPTARG
-When using
-.Ic getopts ,
-it contains the argument for a parsed option, if it requires one.
-.It Ev OPTIND
-The index of the next argument to be processed when using
-.Ic getopts .
-Assigning 1 to this parameter causes
-.Ic getopts
-to process arguments from the beginning the next time it is invoked.
-.It Ev PATH
-A colon separated list of directories that are searched when looking for
-commands and files sourced using the
-.Sq \&.
-command (see below).
-An empty string resulting from a leading or trailing
-colon, or two adjacent colons, is treated as a
-.Sq \&.
-(the current directory).
-.It Ev POSIXLY_CORRECT
-If set, this parameter causes the
-.Ic posix
-option to be enabled.
-See
-.Sx POSIX mode
-below.
-.It Ev PPID
-The process ID of the shell's parent (read-only).
-.It Ev PS1
-The primary prompt for interactive shells.
-Parameter, command, and arithmetic
-substitutions are performed,
-and the prompt string can be customised using
-backslash-escaped special characters.
-.Pp
-Note that since the command-line editors try to figure out how long the prompt
-is (so they know how far it is to the 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 using the
-.Li \e[ Ns Ar ... Ns Li \e]
-substitution (see below) or 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.
-By the way, don't blame me for
-this hack; it's in the original
-.Nm .
-.Pp
-The default prompt is
-.Sq $\ \&
-for non-root users,
-.Sq #\ \&
-for root.
-If
-.Nm
-is invoked by root and
-.Ev PS1
-does not contain a
-.Sq #
-character, the default value will be used even if
-.Ev PS1
-already exists in the environment.
-.Pp
-The following backslash-escaped special characters can be used
-to customise the prompt:
-.Pp
-.Bl -tag -width "\eD{format}XX" -compact
-.It Li \ea
-Insert an ASCII bell character.
-.It Li \ed
-The current date, in the format
-.Dq Day Month Date
-for example
-.Dq Wed Nov 03 .
-.It Li \eD{ Ns Ar format Ns Li }
-The current date, with
-.Ar format
-converted by
-.Xr strftime 3 .
-The braces must be specified.
-.It Li \ee
-Insert an ASCII escape character.
-.It Li \eh
-The hostname, minus domain name.
-.It Li \eH
-The full hostname, including domain name.
-.It Li \ej
-Current number of jobs running
-(see
-.Sx Job control
-below).
-.It Li \el
-The controlling terminal.
-.It Li \en
-Insert a newline character.
-.It Li \er
-Insert a carriage return character.
-.It Li \es
-The name of the shell.
-.It Li \et
-The current time, in 24-hour HH:MM:SS format.
-.It Li \eT
-The current time, in 12-hour HH:MM:SS format.
-.It Li \e@
-The current time, in 12-hour HH:MM:SS AM/PM format.
-.It Li \eA
-The current time, in 24-hour HH:MM format.
-.It Li \eu
-The current user's username.
-.It Li \ev
-The current version of
-.Nm .
-.It Li \eV
-Like
-.Sq \ev ,
-but more verbose.
-.It Li \ew
-The current working directory.
-.Dv $HOME
-is abbreviated as
-.Sq ~ .
-.It Li \eW
-The basename of
-the current working directory.
-.It Li \e!
-The current history number.
-An unescaped
-.Ql !\&
-will produce the current history number too,
-as per the POSIX specification.
-A literal
-.Ql \&!
-can be put in the prompt by placing
-.Ql !!
-in
-.Ev PS1 .
-.It Li \e#
-The current command number.
-This could be different to the current history number,
-if
-.Ev HISTFILE
-contains a history list from a previous session.
-.It Li \e$
-The default prompt i.e.\&
-.Sq # \&
-if the effective UID is 0,
-otherwise
-.Sq $ \& .
-Since the shell interprets
-.Sq $
-as a special character within double quotes,
-it is safer in this case to escape the backslash
-than to try quoting it.
-.It Li \e Ns Ar nnn
-The octal character
-.Ar nnn .
-.It Li \e\e
-Insert a single backslash character.
-.It Li \e[
-Normally the shell keeps track of the number of characters in the prompt.
-Use of this sequence turns off that count.
-.It Li \e]
-Use of this sequence turns the count back on.
-.El
-.Pp
-Note that the backslash itself may be interpreted by the shell.
-Hence, to set
-.Ev PS1
-either escape the backslash itself,
-or use double quotes.
-The latter is more practical:
-.Bd -literal -offset indent
-PS1="\eu "
-.Ed
-.Pp
-This is a more complex example,
-which does not rely on the above backslash-escaped sequences.
-It embeds the current working directory,
-in reverse video,
-in the prompt string:
-.Bd -literal -offset indent
-x=$(print \e\e001)
-PS1="$x$(print \e\er)$x$(tput so)$x\e$PWD$x$(tput se)$x\*(Gt "
-.Ed
-.It Ev PS2
-Secondary prompt string, by default
-.Sq \*(Gt\ \& ,
-used when more input is needed to complete a command.
-.It Ev PS3
-Prompt used by the
-.Ic select
-statement when reading a menu selection.
-The default is
-.Sq #?\ \& .
-.It Ev PS4
-Used to prefix commands that are printed during execution tracing (see the
-.Ic set Fl x
-command below).
-Parameter, command, and arithmetic substitutions are performed
-before it is printed.
-The default is
-.Sq +\ \& .
-.It Ev PWD
-The current working directory.
-May be unset or
-.Dv NULL
-if the shell doesn't know where it is.
-.It Ev RANDOM
-A random number generator.
-Every time
-.Ev RANDOM
-is referenced, it is assigned the next random number in the range
-0\-32767.
-By default,
-.Xr arc4random 3
-is used to produce values.
-If the variable
-.Ev RANDOM
-is assigned a value, the value is used as the seed to
-.Xr srand 3
-and subsequent references of
-.Ev RANDOM
-will use
-.Xr rand 3
-to produce values, resulting in a predictable sequence.
-.It Ev REPLY
-Default parameter for the
-.Ic read
-command if no names are given.
-Also used in
-.Ic select
-loops to store the value that is read from standard input.
-.It Ev SECONDS
-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.
-.It Ev TMOUT
-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
-.Pq Ev PS1 .
-If the time is exceeded, the shell exits.
-.It Ev TMPDIR
-The directory temporary shell 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
-.Pa /tmp .
-.It Ev VISUAL
-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
-.Dq vi ,
-.Dq emacs ,
-or
-.Dq gmacs ,
-the
-.Xr vi ,
-.Xr emacs ,
-or
-.Xr gmacs
-(Gosling emacs) editing mode is enabled, respectively.
-See also the
-.Ev EDITOR
-parameter, above.
-.El
-.Ss Tilde expansion
-Tilde expansion, which is done in parallel with parameter substitution, is done
-on words starting with an unquoted
-.Ql ~ .
-The characters following the tilde, up to the first
-.Ql / ,
-if any, are assumed to be a login name.
-If the login name is empty,
-.Ql + ,
-or
-.Ql - ,
-the value of the
-.Ev HOME ,
-.Ev PWD ,
-or
-.Ev OLDPWD
-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
-(such as those preceding a simple-command or those occurring
-in the arguments of
-.Ic alias ,
-.Ic export ,
-.Ic readonly ,
-and
-.Ic typeset ) ,
-tilde expansion is done after any assignment
-(i.e. after the equals sign)
-or after an unquoted colon
-.Pq Sq \&: ;
-login names are also delimited by colons.
-.Pp
-The home directory of previously expanded login names are cached and re-used.
-The
-.Ic alias -d
-command may be used to list, change, and add to this cache (e.g.\&
-.Ic alias -d fac=/usr/local/facilities; cd ~fac/bin ) .
-.Ss Brace expansion (alteration)
-Brace expressions take the following form:
-.Bd -unfilled -offset indent
-.Sm off
-.Xo
-.Ar prefix No { Ar str1 No ,...,
-.Ar strN No } Ar suffix
-.Xc
-.Sm on
-.Ed
-.Pp
-The expressions are expanded to
-.Ar N
-words, each of which is the concatenation of
-.Ar prefix ,
-.Ar str Ns i ,
-and
-.Ar suffix
-(e.g.\&
-.Dq a{c,b{X,Y},d}e
-expands to four words:
-.Dq ace ,
-.Dq abXe ,
-.Dq abYe ,
-and
-.Dq 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
-.Pq Sq \&,
-for expansion to occur (e.g.\&
-.Ic {}
-and
-.Ic {foo}
-are not expanded).
-Brace expansion is carried out after parameter substitution
-and before file name generation.
-.Ss File name patterns
-A file name pattern is a word containing one or more unquoted
-.Ql \&? ,
-.Ql * ,
-.Ql + ,
-.Ql @ ,
-or
-.Ql \&!
-characters or
-.Dq [..]
-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:
-.Bl -tag -width Ds
-.It \&?
-Matches any single character.
-.It \&*
-Matches any sequence of characters.
-.It [..]
-Matches any of the characters inside the brackets.
-Ranges of characters can be
-specified by separating two characters by a
-.Ql -
-(e.g.\&
-.Dq [a0-9]
-matches the letter
-.Sq a
-or any digit).
-In order to represent itself, a
-.Ql -
-must either be quoted or the first or last character in the character list.
-Similarly, a
-.Ql \&]
-must be quoted or the first character in the list if it is to represent itself
-instead of the end of the list.
-Also, a
-.Ql \&!
-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.
-.It [!..]
-Like [..],
-except it matches any character not inside the brackets.
-.Sm off
-.It *( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
-.Sm on
-Matches any string of characters that matches zero or more occurrences of the
-specified patterns.
-Example: The pattern
-.Ic *(foo|bar)
-matches the strings
-.Dq ,
-.Dq foo ,
-.Dq bar ,
-.Dq foobarfoo ,
-etc.
-.Sm off
-.It +( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
-.Sm on
-Matches any string of characters that matches one or more occurrences of the
-specified patterns.
-Example: The pattern
-.Ic +(foo|bar)
-matches the strings
-.Dq foo ,
-.Dq bar ,
-.Dq foobar ,
-etc.
-.Sm off
-.It ?( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
-.Sm on
-Matches the empty string or a string that matches one of the specified
-patterns.
-Example: The pattern
-.Ic ?(foo|bar)
-only matches the strings
-.Dq ,
-.Dq foo ,
-and
-.Dq bar .
-.Sm off
-.It @( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
-.Sm on
-Matches a string that matches one of the specified patterns.
-Example: The pattern
-.Ic @(foo|bar)
-only matches the strings
-.Dq foo
-and
-.Dq bar .
-.Sm off
-.It !( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
-.Sm on
-Matches any string that does not match one of the specified patterns.
-Examples: The pattern
-.Ic !(foo|bar)
-matches all strings except
-.Dq foo
-and
-.Dq bar ;
-the pattern
-.Ic !(*)
-matches no strings; the pattern
-.Ic !(?)*\&
-matches all strings (think about it).
-.El
-.Pp
-Note that
-.Nm pdksh
-currently never matches
-.Sq \&.
-and
-.Sq .. ,
-but the original
-.Xr ksh ,
-Bourne
-.Xr 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
-.Pq Sq \&.
-at the start of a file name or a slash
-.Pq Sq / ,
-even if they are explicitly used in a [..] sequence; also, the names
-.Sq \&.
-and
-.Sq ..
-are never matched, even by the pattern
-.Sq .* .
-.Pp
-If the
-.Ic markdirs
-option is set, any directories that result from file name generation are marked
-with a trailing
-.Ql / .
-.Pp
-The POSIX character classes (i.e.\&
-.Pf [: Ns Ar class-name Ns :]
-inside a [..] expression) are not yet implemented.
-.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
-.Pa /dev/null ,
-and commands for which any of the following redirections have been specified:
-.Bl -tag -width Ds
-.It \*(Gt Ar file
-Standard output is redirected to
-.Ar file .
-If
-.Ar file
-does not exist, it is created; if it does exist, is a regular file, and the
-.Ic noclobber
-option is set, an error occurs; otherwise, the file is truncated.
-Note that this means the command
-.Ic cmd \*(Lt foo \*(Gt foo
-will open
-.Ar foo
-for reading and then truncate it when it opens it for writing, before
-.Ar cmd
-gets a chance to actually read
-.Ar foo .
-.It \*(Gt\*(Ba Ar file
-Same as
-.Ic \*(Gt ,
-except the file is truncated, even if the
-.Ic noclobber
-option is set.
-.It \*(Gt\*(Gt Ar file
-Same as
-.Ic \*(Gt ,
-except if
-.Ar file
-exists it 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
-.Xr open 2 ) .
-.It \*(Lt Ar file
-Standard input is redirected from
-.Ar file ,
-which is opened for reading.
-.It \*(Lt\*(Gt Ar file
-Same as
-.Ic \*(Lt ,
-except the file is opened for reading and writing.
-.It \*(Lt\*(Lt Ar marker
-After reading the command line containing this kind of redirection (called a
-.Dq here document ) ,
-the shell copies lines from the command source into a temporary file until a
-line matching
-.Ar marker
-is read.
-When the command is executed, standard input is redirected from the
-temporary file.
-If
-.Ar marker
-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
-.Pq Sq \e
-escapes for
-.Ql $ ,
-.Ql ` ,
-.Ql \e ,
-and
-.Ql \enewline .
-If multiple here documents are used on the same command line, they are saved in
-order.
-.It \*(Lt\*(Lt- Ar marker
-Same as
-.Ic \*(Lt\*(Lt ,
-except leading tabs are stripped from lines in the here document.
-.It \*(Lt& Ar fd
-Standard input is duplicated from file descriptor
-.Ar fd .
-.Ar fd
-can be a single digit, indicating the number of an existing file descriptor;
-the letter
-.Ql p ,
-indicating the file descriptor associated with the output of the current
-co-process; or the character
-.Ql - ,
-indicating standard input is to be closed.
-.It \*(Gt& Ar fd
-Same as
-.Ic \*(Lt& ,
-except the operation is done on standard output.
-.El
-.Pp
-In any of the above redirections, the file descriptor that is redirected
-(i.e. 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 (if the shell is interactive)
-file name generation are all performed on the
-.Ar file ,
-.Ar marker ,
-and
-.Ar fd
-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 expanded 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
-.Po
-.Ic if
-statements, etc.
-.Pc ,
-any redirections must appear at the end.
-Redirections are processed after
-pipelines are created and in the order they are given, so the following
-will print an error with a line number prepended to it:
-.Pp
-.D1 $ cat /foo/bar 2\*(Gt&1 \*(Gt /dev/null \*(Ba cat -n
-.Ss Arithmetic expressions
-Integer arithmetic expressions can be used with the
-.Ic let
-command, inside $((..)) expressions, inside array references (e.g.\&
-.Ar name Ns Bq Ar expr ) ,
-as numeric arguments to the
-.Ic test
-command, and as the value of an assignment to an integer parameter.
-.Pp
-Expressions 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):
-.Pp
-Unary operators:
-.Bd -literal -offset indent
-+ - ! ~ ++ --
-.Ed
-.Pp
-Binary operators:
-.Bd -literal -offset indent
-,
-= *= /= %= += -= \*(Lt\*(Lt= \*(Gt\*(Gt= &= ^= \*(Ba=
-\*(Ba\*(Ba
-&&
-\*(Ba
-^
-&
-== !=
-\*(Lt \*(Lt= \*(Gt= \*(Gt
-\*(Lt\*(Lt \*(Gt\*(Gt
-+ -
-* / %
-.Ed
-.Pp
-Ternary operators:
-.Bd -literal -offset indent
-?: (precedence is immediately higher than assignment)
-.Ed
-.Pp
-Grouping operators:
-.Bd -literal -offset indent
-( )
-.Ed
-.Pp
-Integer constants may be specified with arbitrary bases using the notation
-.Ar base Ns # Ns Ar number ,
-where
-.Ar base
-is a decimal integer specifying the base, and
-.Ar number
-is a number in the specified base.
-Additionally,
-integers may be prefixed with
-.Sq 0X
-or
-.Sq 0x
-(specifying base 16)
-or
-.Sq 0
-(base 8)
-in all forms of arithmetic expressions,
-except as numeric arguments to the
-.Ic test
-command.
-.Pp
-The operators are evaluated as follows:
-.Bl -tag -width Ds -offset indent
-.It unary +
-Result is the argument (included for completeness).
-.It unary -
-Negation.
-.It \&!
-Logical NOT;
-the result is 1 if argument is zero, 0 if not.
-.It ~
-Arithmetic (bit-wise) NOT.
-.It ++
-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.
-.It --
-Similar to
-.Ic ++ ,
-except the parameter is decremented by 1.
-.It \&,
-Separates two arithmetic expressions; the left-hand side is evaluated first,
-then the right.
-The result is the value of the expression on the right-hand side.
-.It =
-Assignment; the variable on the left is set to the value on the right.
-.It Xo
-.No *= /= += -= \*(Lt\*(Lt=
-.No \*(Gt\*(Gt= &= ^= \*(Ba=
-.Xc
-Assignment operators.
-.Sm off
-.Aq Xo Ar var
-.Aq Ar op
-.No = Aq Ar expr
-.Xc
-.Sm on
-is the same as
-.Sm off
-.Aq Xo Ar var
-.No = Aq Ar var
-.Aq Ar op
-.Aq Ar expr ,
-.Xc
-.Sm on
-with any operator precedence in
-.Aq Ar expr
-preserved.
-For example,
-.Dq var1 *= 5 + 3
-is the same as specifying
-.Dq var1 = var1 * (5 + 3) .
-.It \*(Ba\*(Ba
-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.
-.It &&
-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.
-.It \*(Ba
-Arithmetic (bit-wise) OR.
-.It ^
-Arithmetic (bit-wise) XOR
-(exclusive-OR).
-.It &
-Arithmetic (bit-wise) AND.
-.It ==
-Equal; the result is 1 if both arguments are equal, 0 if not.
-.It !=
-Not equal; the result is 0 if both arguments are equal, 1 if not.
-.It \*(Lt
-Less than; the result is 1 if the left argument is less than the right, 0 if
-not.
-.It \*(Lt= \*(Gt= \*(Gt
-Less than or equal, greater than or equal, greater than.
-See
-.Ic \*(Lt .
-.It \*(Lt\*(Lt \*(Gt\*(Gt
-Shift left (right); the result is the left argument with its bits shifted left
-(right) by the amount given in the right argument.
-.It + - * /
-Addition, subtraction, multiplication, and division.
-.It %
-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.
-.It Xo
-.Sm off
-.Aq Ar arg1 ?
-.Aq Ar arg2 :
-.Aq Ar arg3
-.Sm on
-.Xc
-If
-.Aq Ar arg1
-is non-zero, the result is
-.Aq Ar arg2 ;
-otherwise the result is
-.Aq Ar arg3 .
-.El
-.Ss Co-processes
-A co-process, which is a pipeline created with the
-.Sq \*(Ba&
-operator, is an asynchronous process that the shell can both write to (using
-.Ic print -p )
-and read from (using
-.Ic read -p ) .
-The input and output of the co-process can also be manipulated using
-.Ic \*(Gt&p
-and
-.Ic \*(Lt&p
-redirections, respectively.
-Once a co-process has been started, another can't
-be started until the co-process exits, or until the co-process's input has been
-redirected using an
-.Ic exec Ar n Ns Ic \*(Gt&p
-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
-.Ic exec Ar n Ns Ic \*(Lt&p
-redirection.
-.Pp
-Some notes concerning co-processes:
-.Bl -bullet
-.It
-The only way to close the co-process's 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 e.g.\&
-.Ic exec 3\*(Gt&p; exec 3\*(Gt&- .
-.It
-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's 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-process output when the most recently started co-process
-(instead of when all sharing co-processes) exits.
-.It
-.Ic print -p
-will ignore
-.Dv SIGPIPE
-signals during writes if the signal is not being trapped or ignored; the same
-is true if the co-process input has been duplicated to another file descriptor
-and
-.Ic print -u Ns Ar n
-is used.
-.El
-.Ss Functions
-Functions are defined using either Korn shell
-.Ic function Ar function-name
-syntax or the Bourne/POSIX shell
-.Ar function-name Ns ()
-syntax (see below for the difference between the two forms).
-Functions are like
-.Li .-scripts
-(i.e. scripts sourced using the
-.Sq \&.
-built-in)
-in that they are executed in the current environment.
-However, unlike
-.Li .-scripts ,
-shell arguments (i.e. positional parameters $1, $2, etc.)\&
-are never visible inside them.
-When the shell is determining the location of a command, functions
-are searched after special built-in commands, before regular and
-non-regular built-ins, and before the
-.Ev PATH
-is searched.
-.Pp
-An existing function may be deleted using
-.Ic unset Fl f Ar function-name .
-A list of functions can be obtained using
-.Ic typeset +f
-and the function definitions can be listed using
-.Ic typeset -f .
-The
-.Ic autoload
-command (which is an alias for
-.Ic typeset -fu )
-may be used to create undefined functions: when an undefined function is
-executed, the shell searches the path specified in the
-.Ev FPATH
-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 (i.e. the shell searches the regular built-in command table and
-.Ev PATH ) .
-Note that if a command is not found using
-.Ev PATH ,
-an attempt is made to autoload a function using
-.Ev FPATH
-(this is an undocumented feature of the original Korn shell).
-.Pp
-Functions can have two attributes,
-.Dq trace
-and
-.Dq export ,
-which can be set with
-.Ic typeset -ft
-and
-.Ic typeset -fx ,
-respectively.
-When a traced function is executed, the shell's
-.Ic xtrace
-option is turned on for the function's duration; otherwise, the
-.Ic xtrace
-option is turned off.
-The
-.Dq 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
-.Ic typeset
-command can be used inside a function to create a local parameter.
-Note that special parameters (e.g.\&
-.Ic \&$$ , $! )
-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
-.Ic return
-command; this may also be used to explicitly specify the exit status.
-.Pp
-Functions defined with the
-.Ic function
-reserved word are treated differently in the following ways from functions
-defined with the
-.Ic ()
-notation:
-.Bl -bullet
-.It
-The $0 parameter is set to the name of the function
-(Bourne-style functions leave $0 untouched).
-.It
-Parameter assignments preceding function calls are not kept in the shell
-environment (executing Bourne-style functions will keep assignments).
-.It
-.Ev OPTIND
-is saved/reset and restored on entry and exit from the function so
-.Ic getopts
-can be used properly both inside and outside the function (Bourne-style
-functions leave
-.Ev OPTIND
-untouched, so using
-.Ic getopts
-inside a function interferes with using
-.Ic getopts
-outside the function).
-.El
-.Pp
-In the future, the following differences will also be added:
-.Bl -bullet
-.It
-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.
-.It
-The EXIT trap, if set in a function, will be executed after the function
-returns.
-.El
-.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
-.Ic posix
-option
-.Pq Ic set -o posix .
-If it is on, the POSIX behaviour is followed; otherwise, it is not.
-The
-.Ic posix
-option is set automatically when the shell starts up if the environment
-contains the
-.Ev POSIXLY_CORRECT
-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
-.Ic posix
-option:
-.Bl -bullet
-.It
-Occurrences of
-.Ic \e\&"
-inside double quoted
-.Ic `..`
-command substitutions.
-In POSIX mode, the
-.Ic \e\&"
-is interpreted when the command is interpreted;
-in non-POSIX mode,
-the backslash is stripped before the command substitution is interpreted.
-For example,
-.Ic echo \&"`echo \e\&"hi\e\&"`\&"
-produces
-.Dq \&"hi\&"
-in POSIX mode,
-.Dq hi
-in non-POSIX mode.
-To avoid problems, use the
-.Ic $(...)\&
-form of command substitution.
-.It
-.Ic kill -l
-output.
-In POSIX mode, only signal names are listed (in a single line);
-in non-POSIX mode,
-signal numbers, names, and descriptions are printed (in columns).
-In the future, a new option
-.Pq Fl v No perhaps
-will be added to distinguish the two behaviours.
-.It
-.Ic fg
-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.
-.It
-.Ic eval
-exit status.
-If
-.Ic eval
-gets to see an empty command (i.e.\&
-.Ic eval `false` ) ,
-its exit status in POSIX mode will be 0.
-In non-POSIX mode,
-it will be the exit status of the last command substitution that was
-done in the processing of the arguments to
-.Ic eval
-(or 0 if there were no command substitutions).
-.It
-.Ic getopts .
-In POSIX mode, options must start with a
-.Ql - ;
-in non-POSIX mode, options can start with either
-.Ql -
-or
-.Ql + .
-.It
-Brace expansion (also known as alternation).
-In POSIX mode, brace expansion is disabled;
-in non-POSIX mode, brace expansion is enabled.
-Note that
-.Ic set -o posix
-(or setting the
-.Ev POSIXLY_CORRECT
-parameter) automatically turns the
-.Ic braceexpand
-option off; however, it can be explicitly turned on later.
-.It
-.Ic set - .
-In POSIX mode, this does not clear the
-.Ic verbose
-or
-.Ic xtrace
-options; in non-POSIX mode, it does.
-.It
-.Ic set
-exit status.
-In POSIX mode, the exit status of
-.Ic 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
-.Ic set
-command.
-For example,
-.Ic set -- `false`; echo $?\&
-prints 0 in POSIX mode, 1 in non-POSIX mode.
-This construct is used in most shell scripts that use the old
-.Xr getopt 1
-command.
-.It
-Argument expansion of the
-.Ic alias ,
-.Ic export ,
-.Ic readonly ,
-and
-.Ic typeset
-commands.
-In POSIX mode, normal argument expansion is done; in non-POSIX mode,
-field splitting, file globbing, brace expansion, and (normal) tilde expansion
-are turned off, while assignment tilde expansion is turned on.
-.It
-Signal specification.
-In POSIX mode, signals can be specified as digits, only
-if signal numbers match POSIX values
-(i.e. HUP=1, INT=2, QUIT=3, ABRT=6, KILL=9, ALRM=14, and TERM=15);
-in non-POSIX mode, signals can always be digits.
-.It
-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
-.Ic for
-loop uses parameter
-.Sq i
-in POSIX mode and
-.Sq j
-in non-POSIX mode:
-.Bd -literal -offset indent
-alias a='for ' i='j'
-a i in 1 2; do echo i=$i j=$j; done
-.Ed
-.Pp
-.It
-.Ic test .
-In POSIX mode, the expression
-.Sq Fl t
-(preceded by some number of
-.Sq \&!
-arguments) is always true as it is a non-zero length string;
-in non-POSIX mode, it tests if file descriptor 1 is a
-.Xr tty 4
-(i.e. the
-.Ar fd
-argument to the
-.Fl t
-test may be left out and defaults to 1).
-.El
-.Ss Strict Bourne shell mode
-When the
-.Ic sh
-option is enabled (see the
-.Ic set
-command),
-.Nm
-will behave like
-.Xr sh 1
-in the following ways:
-.Bl -bullet
-.It
-The parameter
-.Ic $_
-is not set to:
-.Pp
-.Bl -dash -compact
-.It
-the expanded alias' full program path after entering commands
-that are tracked aliases
-.It
-the last argument on the command line after entering external
-commands
-.It
-the file that changed when
-.Ev MAILPATH
-is set to monitor a mailbox
-.El
-.It
-File descriptors are left untouched when executing
-.Ic exec
-with no arguments.
-.It
-Backslash-escaped special characters are not substituted in
-.Ev PS1 .
-.It
-Sequences of
-.Sq ((...))
-are not interpreted as arithmetic expressions.
-.El
-.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
-.Ev PATH
-parameter.
-The checks are made in the above order.
-Special built-in commands differ from other commands in that the
-.Ev PATH
-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
-.Ic posix
-option is turned off (see the
-.Ic set
-command below), some special commands are very special in that no field
-splitting, file globbing, brace expansion, nor tilde expansion is performed
-on arguments that look like assignments.
-Regular built-in commands are different only in that the
-.Ev PATH
-parameter is not used to find them.
-.Pp
-The original
-.Nm ksh
-and POSIX differ somewhat in which commands are considered
-special or regular:
-.Pp
-POSIX special commands
-.Pp
-.Ic \&. , \&: , break , continue ,
-.Ic eval , exec , exit , export ,
-.Ic readonly , return , set , shift ,
-.Ic trap , unset
-.Pp
-Additional
-.Nm
-special commands
-.Pp
-.Ic builtin , times , typeset
-.Pp
-Very special commands
-.Pq non-POSIX
-.Pp
-.Ic alias , readonly , set , typeset
-.Pp
-POSIX regular commands
-.Pp
-.Ic alias , bg , cd , command ,
-.Ic false , fc , fg , getopts ,
-.Ic jobs , kill , read , true ,
-.Ic umask , unalias , wait
-.Pp
-Additional
-.Nm
-regular commands
-.Pp
-.Ic \&[ , echo , let , mknod ,
-.Ic print , pwd , test , ulimit ,
-.Ic whence
-.Pp
-In the future, the additional
-.Nm
-special and regular commands may be treated
-differently from the POSIX special and regular commands.
-.Pp
-Once the type of 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:
-.Pp
-.Bl -tag -width Ds -compact
-.It Ic \&. Ar file Op Ar arg ...
-Execute the commands in
-.Ar file
-in the current environment.
-The file is searched for in the directories of
-.Ev PATH .
-If arguments are given, the positional parameters may be used to access them
-while
-.Ar file
-is being executed.
-If no arguments are given, the positional parameters are
-those of the environment the command is used in.
-.Pp
-.It Ic \&: Op Ar ...
-The null command.
-Exit status is set to zero.
-.Pp
-.It Xo Ic alias
-.Oo Fl d \*(Ba t Oo Fl r Oc \*(Ba
-.Cm +-x Oc
-.Op Fl p
-.Op Cm +
-.Oo Ar name
-.Op Ns = Ns Ar value
-.Ar ... Oc
-.Xc
-Without arguments,
-.Ic alias
-lists all aliases.
-For any name without a value, the existing alias is listed.
-Any name with a value defines an alias (see
-.Sx Aliases
-above).
-.Pp
-When listing aliases, one of two formats is used.
-Normally, aliases are listed as
-.Ar name Ns = Ns Ar value ,
-where
-.Ar value
-is quoted.
-If options were preceded with
-.Ql + ,
-or a lone
-.Ql +
-is given on the command line, only
-.Ar name
-is printed.
-.Pp
-The
-.Fl d
-option causes directory aliases, which are used in tilde expansion, to be
-listed or set (see
-.Sx Tilde expansion
-above).
-.Pp
-If the
-.Fl p
-option is used, each alias is prefixed with the string
-.Dq alias\ \& .
-.Pp
-The
-.Fl t
-option indicates that tracked aliases are to be listed/set (values specified on
-the command line are ignored for tracked aliases).
-The
-.Fl r
-option indicates that all tracked aliases are to be reset.
-.Pp
-The
-.Fl x
-option sets
-.Pq Ic +x No clears
-the export attribute of an alias, or, if no names are given, lists the aliases
-with the export attribute (exporting an alias has no effect).
-.Pp
-.It Ic bg Op Ar job ...
-Resume the specified stopped job(s) in the background.
-If no jobs are specified,
-.Ic %+
-is assumed.
-See
-.Sx Job control
-below for more information.
-.Pp
-.It Ic bind Op Fl l
-The current bindings are listed.
-If the
-.Fl l
-flag is given,
-.Ic bind
-instead lists the names of the functions to which keys may be bound.
-See
-.Sx Emacs editing mode
-for more information.
-.Pp
-.It Xo Ic bind Op Fl m
-.Ar string Ns = Ns Op Ar substitute
-.Ar ...
-.Xc
-.It Xo Ic bind
-.Ar string Ns = Ns Op Ar editing-command
-.Ar ...
-.Xc
-The specified editing command is bound to the given
-.Ar string ,
-which should consist of a control character
-optionally preceded by one of the two prefix characters.
-Future input of the
-.Ar string
-will cause the editing command to be immediately invoked.
-If the
-.Fl m
-flag is given, the specified input
-.Ar string
-will afterwards be immediately replaced by the given
-.Ar substitute
-string, which may contain editing commands.
-.Pp
-Control characters may be written using caret notation
-i.e. ^X represents Control-X.
-Note that although only two prefix characters (usually ESC and ^X)
-are supported, some multi-character sequences can be supported.
-.Pp
-The following default bindings show how the arrow keys
-on an ANSI terminal or xterm are bound
-(of course some escape sequences won't work out quite this nicely):
-.Bd -literal -offset indent
-bind '^[['=prefix-2
-bind '^XA'=up-history
-bind '^XB'=down-history
-bind '^XC'=forward-char
-bind '^XD'=backward-char
-.Ed
-.Pp
-.It Ic break Op Ar level
-Exit the
-.Ar level Ns th
-inner-most
-.Ic for ,
-.Ic select ,
-.Ic until ,
-or
-.Ic while
-loop.
-.Ar level
-defaults to 1.
-.Pp
-.It Ic builtin Ar command Op Ar arg ...
-Execute the built-in command
-.Ar command .
-.Pp
-.It Xo
-.Ic cd
-.Op Fl LP
-.Op Ar dir
-.Xc
-Set the working directory to
-.Ar dir .
-If the parameter
-.Ev CDPATH
-is set, it lists the search path for the directory containing
-.Ar dir .
-A
-.Dv NULL
-path means the current directory.
-If
-.Ar dir
-is found in any component of the
-.Ev CDPATH
-search path other than the
-.Dv NULL
-path, the name of the new working directory will be written to standard output.
-If
-.Ar dir
-is missing, the home directory
-.Ev HOME
-is used.
-If
-.Ar dir
-is
-.Ql - ,
-the previous working directory is used (see the
-.Ev OLDPWD
-parameter).
-.Pp
-If the
-.Fl L
-option (logical path) is used or if the
-.Ic physical
-option isn't set (see the
-.Ic set
-command below), references to
-.Sq ..
-in
-.Ar dir
-are relative to the path used to get to the directory.
-If the
-.Fl P
-option (physical path) is used or if the
-.Ic physical
-option is set,
-.Sq ..
-is relative to the filesystem directory tree.
-The
-.Ev PWD
-and
-.Ev OLDPWD
-parameters are updated to reflect the current and old working directory,
-respectively.
-.Pp
-.It Xo
-.Ic cd
-.Op Fl LP
-.Ar old new
-.Xc
-The string
-.Ar new
-is substituted for
-.Ar old
-in the current directory, and the shell attempts to change to the new
-directory.
-.Pp
-.It Xo
-.Ic command
-.Op Fl pVv
-.Ar cmd
-.Op Ar arg ...
-.Xc
-If neither the
-.Fl v
-nor
-.Fl V
-option is given,
-.Ar cmd
-is executed exactly as if
-.Ic command
-had not been specified, with two exceptions:
-firstly,
-.Ar cmd
-cannot be a shell function;
-and secondly, special built-in commands lose their specialness
-(i.e. redirection and utility errors do not cause the shell to
-exit, and command assignments are not permanent).
-.Pp
-If the
-.Fl p
-option is given, a default search path is used instead of the current value of
-.Ev PATH
-(the actual value of the default path is system dependent: on
-POSIX-ish systems, it is the value returned by
-.Ic getconf CS_PATH ) .
-.Pp
-If the
-.Fl v
-option is given, instead of executing
-.Ar cmd ,
-information about what would be executed is given (and the same is done for
-.Ar arg ... ) .
-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
-.Ev PATH
-parameter, the full path of the command is printed.
-If no command is found
-(i.e. the path search fails), nothing is printed and
-.Ic command
-exits with a non-zero status.
-The
-.Fl V
-option is like the
-.Fl v
-option, except it is more verbose.
-.Pp
-.It Ic continue Op Ar level
-Jumps to the beginning of the
-.Ar level Ns th
-inner-most
-.Ic for ,
-.Ic select ,
-.Ic until ,
-or
-.Ic while
-loop.
-.Ar level
-defaults to 1.
-.Pp
-.It Xo
-.Ic echo
-.Op Fl Een
-.Op Ar arg ...
-.Xc
-Prints its arguments (separated by spaces) followed by a newline, to the
-standard output.
-The newline is suppressed if any of the arguments contain the
-backslash sequence
-.Ql \ec .
-See the
-.Ic print
-command below for a list of other backslash sequences that are recognized.
-.Pp
-The options are provided for compatibility with
-.Bx
-shell scripts.
-The
-.Fl n
-option suppresses the trailing newline,
-.Fl e
-enables backslash interpretation (a no-op, since this is normally done), and
-.Fl E
-suppresses backslash interpretation.
-.Pp
-.It Ic eval Ar command ...
-The arguments are concatenated (with spaces between them) to form a single
-string which the shell then parses and executes in the current environment.
-.Pp
-.It Xo
-.Ic exec
-.Op Ar command Op Ar arg ...
-.Xc
-The command is executed without forking, replacing the shell process.
-.Pp
-If no command is given except for I/O redirection, the I/O redirection is
-permanent and the shell is
-not replaced.
-Any file descriptors greater than 2 which are opened or
-.Xr dup 2 Ns 'd
-in this way are not made available to other executed commands (i.e. commands
-that are not built-in to the shell).
-Note that the Bourne shell differs here;
-it does pass these file descriptors on.
-.Pp
-.It Ic exit Op Ar status
-The shell exits with the specified exit status.
-If
-.Ar status
-is not specified, the exit status is the current value of the
-.Ic $?\&
-parameter.
-.Pp
-.It Xo
-.Ic export
-.Op Fl p
-.Op Ar parameter Ns Op = Ns Ar value
-.Xc
-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 are also assigned.
-.Pp
-If no parameters are specified, the names of all parameters with the export
-attribute are printed one per line, unless the
-.Fl p
-option is used, in which case
-.Ic export
-commands defining all exported parameters, including their values, are printed.
-.Pp
-.It Ic false
-A command that exits with a non-zero status.
-.Pp
-.It Xo
-.Ic fc
-.Oo Fl e Ar editor \*(Ba
-.Fl l Op Fl n Oc
-.Op Fl r
-.Op Ar first Op Ar last
-.Xc
-.Ar first
-and
-.Ar last
-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
-.Fl l
-option lists the command on standard output, and
-.Fl n
-inhibits the default command numbers.
-The
-.Fl r
-option reverses the order of the list.
-Without
-.Fl l ,
-the selected commands are edited by the editor specified with the
-.Fl e
-option, or if no
-.Fl e
-is specified, the editor specified by the
-.Ev FCEDIT
-parameter (if this parameter is not set,
-.Pa /bin/ed
-is used), and then executed by the shell.
-.Pp
-.It Xo
-.Ic fc
-.Cm -e - \*(Ba Fl s
-.Op Fl g
-.Op Ar old Ns = Ns Ar new
-.Op Ar prefix
-.Xc
-Re-execute the selected command (the previous command by default) after
-performing the optional substitution of
-.Ar old
-with
-.Ar new .
-If
-.Fl g
-is specified, all occurrences of
-.Ar old
-are replaced with
-.Ar new .
-The meaning of
-.Cm -e -
-and
-.Fl s
-is identical: re-execute the selected command without invoking an editor.
-This command is usually accessed with the predefined
-.Ic alias r='fc -e -' .
-.Pp
-.It Ic fg Op Ar job ...
-Resume the specified job(s) in the foreground.
-If no jobs are specified,
-.Ic %+
-is assumed.
-See
-.Sx Job control
-below for more information.
-.Pp
-.It Xo
-.Ic getopts
-.Ar optstring name
-.Op Ar arg ...
-.Xc
-Used by shell procedures to parse the specified arguments (or positional
-parameters, if no arguments are given) and to check for legal options.
-.Ar optstring
-contains the option letters that
-.Ic getopts
-is to recognize.
-If a letter is followed by a colon, the option is expected to
-have an argument.
-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.
-.Pp
-Each time
-.Ic getopts
-is invoked, it places the next option in the shell parameter
-.Ar name
-and the index of the argument to be processed by the next call to
-.Ic getopts
-in the shell parameter
-.Ev OPTIND .
-If the option was introduced with a
-.Ql + ,
-the option placed in
-.Ar name
-is prefixed with a
-.Ql + .
-When an option requires an argument,
-.Ic getopts
-places it in the shell parameter
-.Ev OPTARG .
-.Pp
-When an illegal option or a missing option argument is encountered, a question
-mark or a colon is placed in
-.Ar name
-(indicating an illegal option or missing argument, respectively) and
-.Ev OPTARG
-is set to the option character that caused the problem.
-Furthermore, if
-.Ar optstring
-does not begin with a colon, a question mark is placed in
-.Ar name ,
-.Ev OPTARG
-is unset, and an error message is printed to standard error.
-.Pp
-When the end of the options is encountered,
-.Ic getopts
-exits with a non-zero exit status.
-Options end at the first (non-option
-argument) argument that does not start with a
-.Ql - ,
-or when a
-.Ql --
-argument is encountered.
-.Pp
-Option parsing can be reset by setting
-.Ev OPTIND
-to 1 (this is done automatically whenever the shell or a shell procedure is
-invoked).
-.Pp
-Warning: Changing the value of the shell parameter
-.Ev OPTIND
-to a value other than 1, or parsing different sets of arguments without
-resetting
-.Ev OPTIND ,
-may lead to unexpected results.
-.Pp
-.It Xo
-.Ic hash
-.Op Fl r
-.Op Ar name ...
-.Xc
-Without arguments, any hashed executable command pathnames are listed.
-The
-.Fl r
-option causes all hashed commands to be removed from the hash table.
-Each
-.Ar name
-is searched as if it were a command name and added to the hash table if it is
-an executable command.
-.Pp
-.It Xo
-.Ic jobs
-.Op Fl lnp
-.Op Ar job ...
-.Xc
-Display information about the specified job(s); if no jobs are specified, all
-jobs are displayed.
-The
-.Fl n
-option causes information to be displayed only for jobs that have changed
-state since the last notification.
-If the
-.Fl l
-option is used, the process ID of each process in a job is also listed.
-The
-.Fl p
-option causes only the process group of each job to be printed.
-See
-.Sx Job control
-below for the format of
-.Ar job
-and the displayed job.
-.Pp
-.It Xo
-.Ic kill
-.Oo Fl s Ar signame \*(Ba
-.No - Ns Ar signum \*(Ba
-.No - Ns Ar signame Oc
-.No { Ar job \*(Ba pid \*(Ba pgrp No }
-.Ar ...
-.Xc
-Send the specified signal to the specified jobs, process IDs, or process
-groups.
-If no signal is specified, the
-.Dv TERM
-signal is sent.
-If a job is specified, the signal is sent to the job's process group.
-See
-.Sx Job control
-below for the format of
-.Ar job .
-.Pp
-.It Xo
-.Ic kill
-.Fl l
-.Op Ar exit-status ...
-.Xc
-Print the signal name corresponding to
-.Ar exit-status .
-If no arguments are specified, a list of all the signals, their numbers, and
-a short description of them are printed.
-.Pp
-.It Ic let Op Ar expression ...
-Each expression is evaluated (see
-.Sx 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,
-.No (( Ar expr No ))
-is syntactic sugar for
-.No let \&" Ns Ar expr Ns \&" .
-.Pp
-.It Xo
-.Ic mknod
-.Op Fl m Ar mode
-.Ar name
-.Op Cm c | Cm b
-.Ar major minor
-.Xc
-.It Xo
-.Ic mknod
-.Op Fl m Ar mode
-.Ar name
-.Cm p
-.Xc
-Create a device special file.
-The file type may be
-.Cm b
-(block type device),
-.Cm c
-(character type device),
-or
-.Cm p
-(named pipe).
-The file created may be modified according to its
-.Ar mode
-(via the
-.Fl m
-option),
-.Ar major
-(major device number),
-and
-.Ar minor
-(minor device number).
-.Pp
-See
-.Xr mknod 8
-for further information.
-.Pp
-.It Xo
-.Ic print
-.Oo Fl nprsu Ns Oo Ar n Oc \*(Ba
-.Fl R Op Fl en Oc
-.Op Ar argument ...
-.Xc
-.Ic print
-prints its arguments on the standard output, separated by spaces and
-terminated with a newline.
-The
-.Fl n
-option suppresses the newline.
-By default, certain C escapes are translated.
-These include
-.Ql \eb ,
-.Ql \ef ,
-.Ql \en ,
-.Ql \er ,
-.Ql \et ,
-.Ql \ev ,
-and
-.Ql \e0###
-.Po
-.Ql #
-is an octal digit, of which there may be 0 to 3
-.Pc .
-.Ql \ec
-is equivalent to using the
-.Fl n
-option.
-.Ql \e
-expansion may be inhibited with the
-.Fl r
-option.
-The
-.Fl s
-option prints to the history file instead of standard output; the
-.Fl u
-option prints to file descriptor
-.Ar n
-.Po
-.Ar n
-defaults to 1 if omitted
-.Pc ;
-and the
-.Fl p
-option prints to the co-process (see
-.Sx Co-processes
-above).
-.Pp
-The
-.Fl R
-option is used to emulate, to some degree, the
-.Bx
-.Xr echo 1
-command, which does not process
-.Ql \e
-sequences unless the
-.Fl e
-option is given.
-As above, the
-.Fl n
-option suppresses the trailing newline.
-.Pp
-.It Ic pwd Op Fl LP
-Print the present working directory.
-If the
-.Fl L
-option is used or if the
-.Ic physical
-option isn't set (see the
-.Ic set
-command below), the logical path is printed (i.e. the path used to
-.Ic cd
-to the current directory).
-If the
-.Fl P
-option (physical path) is used or if the
-.Ic physical
-option is set, the path determined from the filesystem (by following
-.Sq ..
-directories to the root directory) is printed.
-.Pp
-.It Xo
-.Ic read
-.Op Fl prsu Ns Op Ar n
-.Op Ar parameter ...
-.Xc
-Reads a line of input from the standard input, separates the line into fields
-using the
-.Ev IFS
-parameter (see
-.Sx Substitution
-above), and assigns each field to the specified parameters.
-If there are more parameters than fields, the extra parameters are set to
-.Dv 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
-.Ev REPLY
-parameter is used.
-If the input line ends in a backslash and the
-.Fl r
-option was not used, the backslash and the newline are stripped and more input
-is read.
-If no input is read,
-.Ic read
-exits with a non-zero status.
-.Pp
-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
-.Xr tty 4
-(e.g.\&
-.Ic read nfoo?'number of foos: ' ) .
-.Pp
-The
-.Fl u Ns Ar n
-and
-.Fl p
-options cause input to be read from file descriptor
-.Ar n
-.Pf ( Ar n
-defaults to 0 if omitted)
-or the current co-process (see
-.Sx Co-processes
-above for comments on this), respectively.
-If the
-.Fl s
-option is used, input is saved to the history file.
-.Pp
-.It Xo
-.Ic readonly
-.Op Fl p
-.Oo Ar parameter
-.Op Ns = Ns Ar value
-.Ar ... Oc
-.Xc
-Sets the read-only attribute of the named parameters.
-If values are given,
-parameters are set to them before setting the attribute.
-Once a parameter is
-made read-only, it cannot be unset and its value cannot be changed.
-.Pp
-If no parameters are specified, the names of all parameters with the read-only
-attribute are printed one per line, unless the
-.Fl p
-option is used, in which case
-.Ic readonly
-commands defining all read-only parameters, including their values, are
-printed.
-.Pp
-.It Ic return Op Ar status
-Returns from a function or
-.Ic .\&
-script, with exit status
-.Ar status .
-If no
-.Ar status
-is given, the exit status of the last executed command is used.
-If used outside of a function or
-.Ic .\&
-script, it has the same effect as
-.Ic exit .
-Note that
-.Nm pdksh
-treats both profile and
-.Ev ENV
-files as
-.Ic .\&
-scripts, while the original Korn shell only treats profiles as
-.Ic .\&
-scripts.
-.Pp
-.It Xo
-.Ic set Op Ic +-abCefhkmnpsuvXx
-.Op Ic +-o Ar option
-.Op Ic +-A Ar name
-.Op Fl -
-.Op Ar arg ...
-.Xc
-The
-.Ic set
-command can be used to set
-.Pq Ic -
-or clear
-.Pq Ic +
-shell options, set the positional parameters, or set an array parameter.
-Options can be changed using the
-.Cm +-o Ar option
-syntax, where
-.Ar option
-is the long name of an option, or using the
-.Cm +- Ns Ar letter
-syntax, where
-.Ar letter
-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:
-.Bl -tag -width 15n
-.It Fl A Ar name
-Sets the elements of the array parameter
-.Ar name
-to
-.Ar arg ...
-If
-.Fl A
-is used, the array is reset (i.e. emptied) first; if
-.Ic +A
-is used, the first N elements are set (where N is the number of arguments);
-the rest are left untouched.
-.It Fl a \*(Ba Ic allexport
-All new parameters are created with the export attribute.
-.It Fl b \*(Ba Ic notify
-Print job notification messages asynchronously, instead of just before the
-prompt.
-Only used if job control is enabled
-.Pq Fl m .
-.It Fl C \*(Ba Ic noclobber
-Prevent \*(Gt redirection from overwriting existing files.
-Instead, \*(Gt\*(Ba must be used to force an overwrite.
-.It Fl e \*(Ba Ic errexit
-Exit (after executing the
-.Dv ERR
-trap) as soon as an error occurs or a command fails (i.e. exits with a
-non-zero status).
-This does not apply to commands whose exit status is
-explicitly tested by a shell construct such as
-.Ic if ,
-.Ic until ,
-.Ic while ,
-.Ic && ,
-or
-.Ic ||
-statements.
-.It Fl f \*(Ba Ic noglob
-Do not expand file name patterns.
-.It Fl h \*(Ba Ic trackall
-Create tracked aliases for all executed commands (see
-.Sx Aliases
-above).
-Enabled by default for non-interactive shells.
-.It Fl k \*(Ba Ic keyword
-Parameter assignments are recognized anywhere in a command.
-.It Fl m \*(Ba Ic monitor
-Enable job control (default for interactive shells).
-.It Fl n \*(Ba Ic noexec
-Do not execute any commands.
-Useful for checking the syntax of scripts
-(ignored if interactive).
-.It Fl p \*(Ba Ic privileged
-The shell is a privileged shell.
-It is set automatically if, when the shell starts,
-the real UID or GID does not match
-the effective UID (EUID) or GID (EGID), respectively.
-See above for a description of what this means.
-.It Fl s \*(Ba Ic stdin
-If used when the shell is invoked, commands are read from standard input.
-Set automatically if the shell is invoked with no arguments.
-.Pp
-When
-.Fl s
-is used with the
-.Ic set
-command it causes the specified arguments to be sorted before assigning them to
-the positional parameters (or to array
-.Ar name ,
-if
-.Fl A
-is used).
-.It Fl u \*(Ba Ic nounset
-Referencing of an unset parameter is treated as an error, unless one of the
-.Ql - ,
-.Ql + ,
-or
-.Ql =
-modifiers is used.
-.It Fl v \*(Ba Ic verbose
-Write shell input to standard error as it is read.
-.It Fl X \*(Ba Ic markdirs
-Mark directories with a trailing
-.Ql /
-during file name generation.
-.It Fl x \*(Ba Ic xtrace
-Print commands and parameter assignments when they are executed, preceded by
-the value of
-.Ev PS4 .
-.It Ic bgnice
-Background jobs are run with lower priority.
-.It Ic braceexpand
-Enable brace expansion (a.k.a. alternation).
-.It Ic csh-history
-Enables a subset of
-.Xr csh 1 Ns -style
-history editing using the
-.Ql !\&
-character.
-.It Ic emacs
-Enable BRL emacs-like command-line editing (interactive shells only); see
-.Sx Emacs editing mode .
-.It Ic emacs-usemeta
-In emacs command-line editing, use the 8th bit as meta (^[) prefix.
-This is the default.
-.It Ic gmacs
-Enable gmacs-like command-line editing (interactive shells only).
-Currently identical to emacs editing except that transpose (^T) acts slightly
-differently.
-.It Ic ignoreeof
-The shell will not (easily) exit when end-of-file is read;
-.Ic exit
-must be used.
-To avoid infinite loops, the shell will exit if
-.Dv EOF
-is read 13 times in a row.
-.It Ic interactive
-The shell is an interactive shell.
-This option can only be used when the shell is invoked.
-See above for a description of what this means.
-.It Ic login
-The shell is a login shell.
-This option can only be used when the shell is invoked.
-See above for a description of what this means.
-.It Ic nohup
-Do not kill running jobs with a
-.Dv SIGHUP
-signal when a login shell exits.
-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
-.Dv SIGHUP
-signal).
-.It Ic nolog
-No effect.
-In the original Korn shell, this prevents function definitions from
-being stored in the history file.
-.It Ic physical
-Causes the
-.Ic cd
-and
-.Ic pwd
-commands to use
-.Dq physical
-(i.e. the filesystem's)
-.Sq ..
-directories instead of
-.Dq logical
-directories (i.e. the shell handles
-.Sq .. ,
-which allows the user to be oblivious of symbolic links to directories).
-Clear by default.
-Note that setting this option does not affect the current value of the
-.Ev PWD
-parameter; only the
-.Ic cd
-command changes
-.Ev PWD .
-See the
-.Ic cd
-and
-.Ic pwd
-commands above for more details.
-.It Ic posix
-Enable POSIX mode.
-See
-.Sx POSIX mode
-above.
-.It Ic restricted
-The shell is a restricted shell.
-This option can only be used when the shell is invoked.
-See above for a description of what this means.
-.It Ic sh
-Enable strict Bourne shell mode (see
-.Sx Strict Bourne shell mode
-above).
-.It Ic vi
-Enable
-.Xr vi 1 Ns -like
-command-line editing (interactive shells only).
-.It Ic vi-esccomplete
-In vi command-line editing, do command and file name completion when escape
-(^[) is entered in command mode.
-.It Ic vi-show8
-Prefix characters with the eighth bit set with
-.Sq M- .
-If this option is not set, characters in the range 128\-160 are printed as is,
-which may cause problems.
-.It Ic vi-tabcomplete
-In vi command-line editing, do command and file name completion when tab (^I)
-is entered in insert mode.
-This is the default.
-.It Ic viraw
-No effect.
-In the original Korn shell, unless
-.Ic viraw
-was set, the vi command-line mode would let the
-.Xr tty 4
-driver do the work until ESC (^[) was entered.
-.Nm pdksh
-is always in viraw mode.
-.El
-.Pp
-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
-.Sq $- .
-.Ic set Fl o
-with no option name will list all the options and whether each is on or off;
-.Ic set +o
-will print the long names of all options that are currently on.
-.Pp
-Remaining arguments, if any, are positional parameters and are assigned, in
-order, to the positional parameters (i.e. $1, $2, etc.).
-If options end with
-.Ql --
-and there are no remaining arguments, all positional parameters are cleared.
-If no options or arguments are given, the values of all names are printed.
-For unknown historical reasons, a lone
-.Ql -
-option is treated specially \- it clears both the
-.Fl x
-and
-.Fl v
-options.
-.Pp
-.It Ic shift Op Ar number
-The positional parameters
-.Ar number Ns +1 ,
-.Ar number Ns +2 ,
-etc. are renamed to
-.Sq 1 ,
-.Sq 2 ,
-etc.
-.Ar number
-defaults to 1.
-.Pp
-.It Ic test Ar expression
-.It Ic \&[ Ar expression Ic \&]
-.Ic test
-evaluates the
-.Ar expression
-and returns zero status if true, 1 if false, or greater than 1 if there
-was an error.
-It is normally used as the condition command of
-.Ic if
-and
-.Ic while
-statements.
-Symbolic links are followed for all
-.Ar file
-expressions except
-.Fl h
-and
-.Fl L .
-.Pp
-The following basic expressions are available:
-.Bl -tag -width 17n
-.It Fl a Ar file
-.Ar file
-exists.
-.It Fl b Ar file
-.Ar file
-is a block special device.
-.It Fl c Ar file
-.Ar file
-is a character special device.
-.It Fl d Ar file
-.Ar file
-is a directory.
-.It Fl e Ar file
-.Ar file
-exists.
-.It Fl f Ar file
-.Ar file
-is a regular file.
-.It Fl G Ar file
-.Ar file Ns 's
-group is the shell's effective group ID.
-.It Fl g Ar file
-.Ar file Ns 's
-mode has the setgid bit set.
-.It Fl h Ar file
-.Ar file
-is a symbolic link.
-.It Fl k Ar file
-.Ar file Ns 's
-mode has the
-.Xr sticky 8
-bit set.
-.It Fl L Ar file
-.Ar file
-is a symbolic link.
-.It Fl O Ar file
-.Ar file Ns 's
-owner is the shell's effective user ID.
-.It Fl o Ar option
-Shell
-.Ar option
-is set (see the
-.Ic set
-command above for a list of options).
-As a non-standard extension, if the option starts with a
-.Ql \&! ,
-the test is negated; the test always fails if
-.Ar option
-doesn't exist (so [ -o foo -o -o !foo ] returns true if and only if option
-.Ar foo
-exists).
-.It Fl p Ar file
-.Ar file
-is a named pipe.
-.It Fl r Ar file
-.Ar file
-exists and is readable.
-.It Fl S Ar file
-.Ar file
-is a
-.Xr unix 4 Ns -domain
-socket.
-.It Fl s Ar file
-.Ar file
-is not empty.
-.It Fl t Op Ar fd
-File descriptor
-.Ar fd
-is a
-.Xr tty 4
-device.
-If the
-.Ic posix
-option is not set,
-.Ar fd
-may be left out, in which case it is taken to be 1 (the behaviour differs due
-to the special POSIX rules described above).
-.It Fl u Ar file
-.Ar file Ns 's
-mode has the setuid bit set.
-.It Fl w Ar file
-.Ar file
-exists and is writable.
-.It Fl x Ar file
-.Ar file
-exists and is executable.
-.It Ar file1 Fl nt Ar file2
-.Ar file1
-is newer than
-.Ar file2
-or
-.Ar file1
-exists and
-.Ar file2
-does not.
-.It Ar file1 Fl ot Ar file2
-.Ar file1
-is older than
-.Ar file2
-or
-.Ar file2
-exists and
-.Ar file1
-does not.
-.It Ar file1 Fl ef Ar file2
-.Ar file1
-is the same file as
-.Ar file2 .
-.It Ar string
-.Ar string
-has non-zero length.
-.It Fl n Ar string
-.Ar string
-is not empty.
-.It Fl z Ar string
-.Ar string
-is empty.
-.It Ar string No = Ar string
-Strings are equal.
-.It Ar string No == Ar string
-Strings are equal.
-.It Ar string No != Ar string
-Strings are not equal.
-.It Ar number Fl eq Ar number
-Numbers compare equal.
-.It Ar number Fl ne Ar number
-Numbers compare not equal.
-.It Ar number Fl ge Ar number
-Numbers compare greater than or equal.
-.It Ar number Fl gt Ar number
-Numbers compare greater than.
-.It Ar number Fl le Ar number
-Numbers compare less than or equal.
-.It Ar number Fl \&lt Ar number
-Numbers compare less than.
-.El
-.Pp
-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):
-.Bd -literal -offset indent
-expr -o expr		Logical OR.
-expr -a expr		Logical AND.
-! expr			Logical NOT.
-( expr )		Grouping.
-.Ed
-.Pp
-On operating systems not supporting
-.Pa /dev/fd/ Ns Ar n
-devices (where
-.Ar n
-is a file descriptor number), the
-.Ic test
-command will attempt to fake it for all tests that operate on files (except the
-.Fl e
-test).
-For example,
-[ -w /dev/fd/2 ] tests if file descriptor 2 is writable.
-.Pp
-Note that some special rules are applied (courtesy of POSIX)
-if the number of
-arguments to
-.Ic test
-or
-.Ic \&[ ... \&]
-is less than five: if leading
-.Ql \&!
-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
-.Ql \&!
-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 the first argument is a unary operator, including an unstripped
-.Ql \&! ) .
-.Pp
-.Sy Note :
-A common mistake is to use
-.Dq if \&[ $foo = bar \&]
-which fails if parameter
-.Dq foo
-is
-.Dv NULL
-or unset, if it has embedded spaces (i.e.\&
-.Ev IFS
-characters), or if it is a unary operator like
-.Sq \&!
-or
-.Sq Fl n .
-Use tests like
-.Dq if \&[ \&"X$foo\&" = Xbar \&]
-instead.
-.Pp
-.It Xo
-.Ic time
-.Op Fl p
-.Op Ar pipeline
-.Xc
-If a
-.Ar pipeline
-is given, the times used to execute the pipeline are reported.
-If no pipeline
-is given, then the user and system time used by the shell itself, and all the
-commands it has run since it was started, are reported.
-The times reported are the real time (elapsed time from start to finish),
-the user CPU time (time spent running in user mode), and the system CPU time
-(time spent running in kernel mode).
-Times are reported to standard error; the format of the output is:
-.Pp
-.Dl "0m0.00s real     0m0.00s user     0m0.00s system"
-.Pp
-If the
-.Fl p
-option is given the output is slightly longer:
-.Bd -literal -offset indent
-real     0.00
-user     0.00
-sys      0.00
-.Ed
-.Pp
-It is an error to specify the
-.Fl p
-option unless
-.Ar pipeline
-is a simple command.
-.Pp
-Simple redirections of standard error do not affect the output of the
-.Ic time
-command:
-.Pp
-.Dl $ time sleep 1 2\*(Gt afile
-.Dl $ { time sleep 1; } 2\*(Gt afile
-.Pp
-Times for the first command do not go to
-.Dq afile ,
-but those of the second command do.
-.Pp
-.It Ic times
-Print the accumulated user and system times used both by the shell
-and by processes that the shell started which have exited.
-The format of the output is:
-.Bd -literal -offset indent
-0m0.00s 0m0.00s
-0m0.00s 0m0.00s
-.Ed
-.Pp
-.It Ic trap Op Ar handler signal ...
-Sets a trap handler that is to be executed when any of the specified signals are
-received.
-.Ar handler
-is either a
-.Dv NULL
-string, indicating the signals are to be ignored, a minus sign
-.Pq Sq - ,
-indicating that the default action is to be taken for the signals (see
-.Xr signal 3 ) ,
-or a string containing shell commands to be evaluated and executed at the first
-opportunity (i.e. when the current command completes, or before printing the
-next
-.Ev PS1
-prompt) after receipt of one of the signals.
-.Ar signal
-is the name of a signal (e.g.\&
-.Dv PIPE
-or
-.Dv ALRM )
-or the number of the signal (see the
-.Ic kill -l
-command above).
-.Pp
-There are two special signals:
-.Dv EXIT
-(also known as 0), which is executed when the shell is about to exit, and
-.Dv ERR ,
-which is executed after an error occurs (an error is something that would cause
-the shell to exit if the
-.Fl e
-or
-.Ic errexit
-option were set \- see the
-.Ic set
-command above).
-.Dv EXIT
-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.
-.Pp
-With no arguments,
-.Ic trap
-lists, as a series of
-.Ic trap
-commands, the current state of the traps that have been set since the shell
-started.
-Note that the output of
-.Ic trap
-cannot be usefully piped to another process (an artifact of the fact that
-traps are cleared when subprocesses are created).
-.Pp
-The original Korn shell's
-.Dv DEBUG
-trap and the handling of
-.Dv ERR
-and
-.Dv EXIT
-traps in functions are not yet implemented.
-.Pp
-.It Ic true
-A command that exits with a zero value.
-.Pp
-.It Xo
-.Ic typeset
-.Oo Op Ic +-lprtUux
-.Op Fl L Ns Op Ar n
-.Op Fl R Ns Op Ar n
-.Op Fl Z Ns Op Ar n
-.Op Fl i Ns Op Ar n
-.No \*(Ba Fl f Op Fl tux Oc
-.Oo Ar name
-.Op Ns = Ns Ar value
-.Ar ... Oc
-.Xc
-Display or set parameter attributes.
-With no
-.Ar name
-arguments, parameter attributes are displayed; if no options are used, the
-current attributes of all parameters are printed as
-.Ic typeset
-commands; if an option is given (or
-.Ql -
-with no option letter), all parameters and their values with the specified
-attributes are printed; if options are introduced with
-.Ql + ,
-parameter values are not printed.
-.Pp
-If
-.Ar name
-arguments are given, the attributes of the named parameters are set
-.Pq Ic -
-or cleared
-.Pq Ic + .
-Values for parameters may optionally be specified.
-If
-.Ic typeset
-is used inside a function, any newly created parameters are local to the
-function.
-.Pp
-When
-.Fl f
-is used,
-.Ic typeset
-operates on the attributes of functions.
-As with parameters, if no
-.Ar name
-arguments are given,
-functions are listed with their values (i.e. definitions) unless
-options are introduced with
-.Ql + ,
-in which case only the function names are reported.
-.Bl -tag -width Ds
-.It Fl f
-Function mode.
-Display or set functions and their attributes, instead of parameters.
-.It Fl i Ns Op Ar n
-Integer attribute.
-.Ar n
-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.
-.It Fl L Ns Op Ar n
-Left justify attribute.
-.Ar n
-specifies the field width.
-If
-.Ar n
-is not specified, the current width of a parameter (or the width of its first
-assigned value) is used.
-Leading whitespace (and zeros, if used with the
-.Fl Z
-option) is stripped.
-If necessary, values are either truncated or space padded
-to fit the field width.
-.It Fl l
-Lower case attribute.
-All upper case characters in values are converted to lower case.
-(In the original Korn shell, this parameter meant
-.Dq long integer
-when used with the
-.Fl i
-option.)
-.It Fl p
-Print complete
-.Ic typeset
-commands that can be used to re-create the attributes (but not the values) of
-parameters.
-This is the default action (option exists for ksh93 compatibility).
-.It Fl R Ns Op Ar n
-Right justify attribute.
-.Ar n
-specifies the field width.
-If
-.Ar n
-is not specified, the current width of a parameter (or the width of its first
-assigned value) is used.
-Trailing whitespace is stripped.
-If necessary, values are either stripped of leading characters or space
-padded to make them fit the field width.
-.It Fl r
-Read-only attribute.
-Parameters with this attribute may not be assigned to or unset.
-Once this attribute is set, it cannot be turned off.
-.It Fl t
-Tag attribute.
-Has no meaning to the shell; provided for application use.
-.Pp
-For functions,
-.Fl t
-is the trace attribute.
-When functions with the trace attribute are executed, the
-.Ic xtrace
-.Pq Fl x
-shell option is temporarily turned on.
-.It Fl U
-Unsigned integer attribute.
-Integers are printed as unsigned values (only
-useful when combined with the
-.Fl i
-option).
-This option is not in the original Korn shell.
-.It Fl u
-Upper case attribute.
-All lower case characters in values are converted to upper case.
-(In the original Korn shell, this parameter meant
-.Dq unsigned integer
-when used with the
-.Fl i
-option, which meant upper case letters would never be used for bases greater
-than 10.
-See the
-.Fl U
-option.)
-.Pp
-For functions,
-.Fl u
-is the undefined attribute.
-See
-.Sx Functions
-above for the implications of this.
-.It Fl x
-Export attribute.
-Parameters (or functions) are placed in the environment of
-any executed commands.
-Exported functions are not yet implemented.
-.It Fl Z Ns Op Ar n
-Zero fill attribute.
-If not combined with
-.Fl L ,
-this is the same as
-.Fl R ,
-except zero padding is used instead of space padding.
-.El
-.Pp
-.It Xo
-.Ic ulimit
-.Op Fl acdfHlmnpSst
-.Op Ar value
-.Xc
-Display or set process limits.
-If no options are used, the file size limit
-.Pq Fl f
-is assumed.
-.Ar value ,
-if specified, may be either an arithmetic expression or the word
-.Dq unlimited .
-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
-.Fl f
-limit.
-.Bl -tag -width 5n
-.It Fl a
-Display all limits; unless
-.Fl H
-is used, soft limits are displayed.
-.It Fl c Ar n
-Impose a size limit of
-.Ar n
-blocks on the size of core dumps.
-.It Fl d Ar n
-Impose a size limit of
-.Ar n
-kilobytes on the size of the data area.
-.It Fl f Ar n
-Impose a size limit of
-.Ar n
-blocks on files written by the shell and its child processes (files of any
-size may be read).
-.It Fl H
-Set the hard limit only (the default is to set both hard and soft limits).
-.It Fl l Ar n
-Impose a limit of
-.Ar n
-kilobytes on the amount of locked (wired) physical memory.
-.It Fl m Ar n
-Impose a limit of
-.Ar n
-kilobytes on the amount of physical memory used.
-.It Fl n Ar n
-Impose a limit of
-.Ar n
-file descriptors that can be open at once.
-.It Fl p Ar n
-Impose a limit of
-.Ar n
-processes that can be run by the user at any one time.
-.It Fl S
-Set the soft limit only (the default is to set both hard and soft limits).
-.It Fl s Ar n
-Impose a size limit of
-.Ar n
-kilobytes on the size of the stack area.
-.It Fl t Ar n
-Impose a time limit of
-.Ar n
-CPU seconds spent in user mode to be used by each process.
-.\".It Fl v Ar n
-.\"Impose a limit of
-.\"Ar n
-.\"kilobytes on the amount of virtual memory used.
-.El
-.Pp
-As far as
-.Ic ulimit
-is concerned, a block is 512 bytes.
-.Pp
-.It Xo
-.Ic umask
-.Op Fl S
-.Op Ar mask
-.Xc
-Display or set the file permission creation mask, or umask (see
-.Xr umask 2 ) .
-If the
-.Fl S
-option is used, the mask displayed or set is symbolic; otherwise, it is an
-octal number.
-.Pp
-Symbolic masks are like those used by
-.Xr chmod 1 .
-When 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).
-For example,
-.Dq ug=rwx,o=
-sets the mask so files will not be readable, writable, or executable by
-.Dq others ,
-and is equivalent (on most systems) to the octal mask
-.Dq 007 .
-.Pp
-.It Xo
-.Ic unalias
-.Op Fl adt
-.Op Ar name ...
-.Xc
-The aliases for the given names are removed.
-If the
-.Fl a
-option is used, all aliases are removed.
-If the
-.Fl t
-or
-.Fl d
-options are used, the indicated operations are carried out on tracked or
-directory aliases, respectively.
-.Pp
-.It Xo
-.Ic unset
-.Op Fl fv
-.Ar parameter ...
-.Xc
-Unset the named parameters
-.Po
-.Fl v ,
-the default
-.Pc
-or functions
-.Pq Fl f .
-The exit status is non-zero if any of the parameters were already unset, zero
-otherwise.
-.Pp
-.It Ic wait Op Ar job ...
-Wait for the specified job(s) to finish.
-The exit status of
-.Ic 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
-.Ic kill -l Ar exit-status
-above); if the last specified job can't be found (because it never existed, or
-had already finished), the exit status of
-.Ic wait
-is 127.
-See
-.Sx Job control
-below for the format of
-.Ar job .
-.Ic wait
-will return if a signal for which a trap has been set is received, or if a
-.Dv SIGHUP ,
-.Dv SIGINT ,
-or
-.Dv SIGQUIT
-signal is received.
-.Pp
-If no jobs are specified,
-.Ic wait
-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).
-.Pp
-.It Xo
-.Ic whence
-.Op Fl pv
-.Op Ar name ...
-.Xc
-For each
-.Ar name ,
-the type of command is listed (reserved word, built-in, alias,
-function, tracked alias, or executable).
-If the
-.Fl p
-option is used, a path search is performed even if
-.Ar name
-is a reserved word, alias, etc.
-Without the
-.Fl v
-option,
-.Ic whence
-is similar to
-.Ic command Fl v
-except that
-.Ic whence
-will find reserved words and won't print aliases as alias commands.
-With the
-.Fl v
-option,
-.Ic whence
-is the same as
-.Ic command Fl V .
-Note that for
-.Ic whence ,
-the
-.Fl p
-option does not affect the search path used, as it does for
-.Ic command .
-If the type of one or more of the names could not be determined, the exit
-status is non-zero.
-.El
-.Ss Job control
-Job control refers to the shell's ability to monitor and control jobs, 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 (i.e.\&
-asynchronous) jobs that currently exist; this information can be displayed
-using the
-.Ic jobs
-commands.
-If job control is fully enabled (using
-.Ic set -m
-or
-.Ic set -o monitor ) ,
-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
-.Ic fg
-and
-.Ic bg
-commands, and the state of the terminal is saved or restored when a foreground
-job is stopped or restarted, respectively.
-.Pp
-Note that only commands that create processes (e.g. asynchronous commands,
-subshell commands, and non-built-in, non-function commands) can be stopped;
-commands like
-.Ic read
-cannot be.
-.Pp
-When a job is created, it is assigned a job number.
-For interactive shells, this number is printed inside
-.Dq [..] ,
-followed by the process IDs of the processes in the job when an asynchronous
-command is run.
-A job may be referred to in the
-.Ic bg ,
-.Ic fg ,
-.Ic jobs ,
-.Ic kill ,
-and
-.Ic wait
-commands either by the process ID of the last process in the command pipeline
-(as stored in the
-.Ic $!\&
-parameter) or by prefixing the job number with a percent
-sign
-.Pq Sq % .
-Other percent sequences can also be used to refer to jobs:
-.Bl -tag -width "%+ | %% | %XX"
-.It %+ \*(Ba %% \*(Ba %
-The most recently stopped job, or, if there are no stopped jobs, the oldest
-running job.
-.It %-
-The job that would be the
-.Ic %+
-job if the latter did not exist.
-.It % Ns Ar n
-The job with job number
-.Ar n .
-.It %? Ns Ar string
-The job with its command containing the string
-.Ar string
-(an error occurs if multiple jobs are matched).
-.It % Ns Ar string
-The job with its command starting with the string
-.Ar string
-(an error occurs if multiple jobs are matched).
-.El
-.Pp
-When a job changes state (e.g. a background job finishes or foreground job is
-stopped), the shell prints the following status information:
-.Pp
-.D1 [ Ns Ar number ] Ar flag status command
-.Pp
-where...
-.Bl -tag -width "command"
-.It Ar number
-is the job number of the job;
-.It Ar flag
-is the
-.Ql +
-or
-.Ql -
-character if the job is the
-.Ic %+
-or
-.Ic %-
-job, respectively, or space if it is neither;
-.It Ar status
-indicates the current state of the job and can be:
-.Bl -tag -width "RunningXX"
-.It Done Op Ar number
-The job exited.
-.Ar number
-is the exit status of the job, which is omitted if the status is zero.
-.It Running
-The job has neither stopped nor exited (note that running does not necessarily
-mean consuming CPU time \-
-the process could be blocked waiting for some event).
-.It Stopped Op Ar signal
-The job was stopped by the indicated
-.Ar signal
-(if no signal is given, the job was stopped by
-.Dv SIGTSTP ) .
-.It Ar signal-description Op Dq core dumped
-The job was killed by a signal (e.g. memory fault, hangup); use
-.Ic kill -l
-for a list of signal descriptions.
-The
-.Dq core dumped
-message indicates the process created a core file.
-.El
-.It Ar command
-is the command that created the process.
-If there are multiple processes in
-the job, each process will have a line showing its
-.Ar command
-and possibly its
-.Ar status ,
-if it is different from the status of the previous process.
-.El
-.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
-.Dv SIGHUP
-signal and the shell exits.
-Similarly, if the
-.Ic nohup
-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
-.Dv SIGHUP
-signal and the shell exits.
-.Ss Interactive input line editing
-The shell supports three modes of reading command lines from a
-.Xr tty 4
-in an interactive session, controlled by the
-.Ic emacs ,
-.Ic gmacs ,
-and
-.Ic vi
-options (at most one of these can be set at once).
-The default is
-.Ic emacs .
-Editing modes can be set explicitly using the
-.Ic set
-built-in, or implicitly via the
-.Ev EDITOR
-and
-.Ev VISUAL
-environment variables.
-If none of these options are enabled,
-the shell simply reads lines using the normal
-.Xr tty 4
-driver.
-If the
-.Ic emacs
-or
-.Ic gmacs
-option is set, the shell allows emacs-like editing of the command; similarly,
-if the
-.Ic vi
-option is set, the shell allows vi-like editing of the command.
-These modes are described in detail in the following sections.
-.Pp
-In these editing modes, if a line is longer than the screen width (see the
-.Ev COLUMNS
-parameter),
-a
-.Ql \*(Gt ,
-.Ql + ,
-or
-.Ql \*(Lt
-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.
-.Ss Emacs editing mode
-When the
-.Ic emacs
-option is set, interactive input line editing is enabled.
-Warning: This mode is
-slightly different from the emacs mode in the original Korn shell.
-In this mode, various editing commands
-(typically bound to one or more control characters) cause immediate actions
-without waiting for a newline.
-Several editing commands are bound to particular
-control characters when the shell is invoked; these bindings can be changed
-using the
-.Ic bind
-command.
-.Pp
-The following is a list of available editing commands.
-Each description starts with the name of the command,
-suffixed with a colon;
-an
-.Op Ar n
-(if the command can be prefixed with a count); and any keys the command is
-bound to by default, written using caret notation
-e.g. the ASCII ESC character is written as ^[.
-^[A-Z] sequences are not case sensitive.
-A count prefix for a command is entered using the sequence
-.Pf ^[ Ns Ar n ,
-where
-.Ar n
-is a sequence of 1 or more digits.
-Unless otherwise specified, if a count is
-omitted, it defaults to 1.
-.Pp
-Note that editing command names are used only with the
-.Ic bind
-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 user's
-.Xr tty 4
-characters (e.g.\&
-.Dv ERASE )
-are bound to
-reasonable substitutes and override the default bindings.
-.Bl -tag -width Ds
-.It abort: ^C, ^G
-Useful as a response to a request for a
-.Ic search-history
-pattern in order to abort the search.
-.It auto-insert: Op Ar n
-Simply causes the character to appear as literal input.
-Most ordinary characters are bound to this.
-.It Xo backward-char:
-.Op Ar n
-.No ^B , ^XD
-.Xc
-Moves the cursor backward
-.Ar n
-characters.
-.It Xo backward-word:
-.Op Ar n
-.No ^[b
-.Xc
-Moves the cursor backward to the beginning of the word; words consist of
-alphanumerics, underscore
-.Pq Sq _ ,
-and dollar sign
-.Pq Sq $
-characters.
-.It beginning-of-history: ^[\*(Lt
-Moves to the beginning of the history.
-.It beginning-of-line: ^A
-Moves the cursor to the beginning of the edited input line.
-.It Xo capitalize-word:
-.Op Ar n
-.No ^[C , ^[c
-.Xc
-Uppercase the first character in the next
-.Ar n
-words, leaving the cursor past the end of the last word.
-.It clear-screen: ^L
-Clears the screen.
-.It 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.
-.It complete: ^[^[
-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
-.Ql /
-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 beep to be
-sounded).
-.It complete-command: ^X^[
-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
-.Ic complete
-command above.
-.It complete-file: ^[^X
-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
-.Ic complete
-command described above.
-.It complete-list: ^I, ^[=
-Complete as much as is possible of the current word,
-and list the possible completions for it.
-If only one completion is possible,
-match as in the
-.Ic complete
-command above.
-.It Xo delete-char-backward:
-.Op Ar n
-.No ERASE , ^? , ^H
-.Xc
-Deletes
-.Ar n
-characters before the cursor.
-.It delete-char-forward: Op Ar n
-Deletes
-.Ar n
-characters after the cursor.
-.It Xo delete-word-backward:
-.Op Ar n
-.No ERASE , ^[^? , ^[^H , ^[h
-.Xc
-Deletes
-.Ar n
-words before the cursor.
-.It Xo delete-word-forward:
-.Op Ar n
-.No ^[d
-.Xc
-Deletes characters after the cursor up to the end of
-.Ar n
-words.
-.It Xo down-history:
-.Op Ar n
-.No ^N , ^XB
-.Xc
-Scrolls the history buffer forward
-.Ar n
-lines (later).
-Each input line originally starts just after the last entry
-in the history buffer, so
-.Ic down-history
-is not useful until either
-.Ic search-history
-or
-.Ic up-history
-has been performed.
-.It Xo downcase-word:
-.Op Ar n
-.No ^[L , ^[l
-.Xc
-Lowercases the next
-.Ar n
-words.
-.It end-of-history: ^[\*(Gt
-Moves to the end of the history.
-.It end-of-line: ^E
-Moves the cursor to the end of the input line.
-.It eot: ^_
-Acts as an end-of-file; this is useful because edit-mode input disables
-normal terminal input canonicalization.
-.It Xo eot-or-delete:
-.Op Ar n
-.No ^D
-.Xc
-Acts as
-.Ic eot
-if alone on a line; otherwise acts as
-.Ic delete-char-forward .
-.It error:
-Error (ring the bell).
-.It exchange-point-and-mark: ^X^X
-Places the cursor where the mark is and sets the mark to where the cursor was.
-.It expand-file: ^[*
-Appends a
-.Ql *
-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.
-.It Xo forward-char:
-.Op Ar n
-.No ^F , ^XC
-.Xc
-Moves the cursor forward
-.Ar n
-characters.
-.It Xo forward-word:
-.Op Ar n
-.No ^[f
-.Xc
-Moves the cursor forward to the end of the
-.Ar n Ns th
-word.
-.It Xo goto-history:
-.Op Ar n
-.No ^[g
-.Xc
-Goes to history number
-.Ar n .
-.It kill-line: KILL
-Deletes the entire input line.
-.It kill-region: ^W
-Deletes the input between the cursor and the mark.
-.It Xo kill-to-eol:
-.Op Ar n
-.No ^K
-.Xc
-Deletes the input from the cursor to the end of the line if
-.Ar n
-is not specified; otherwise deletes characters between the cursor and column
-.Ar n .
-.It list: ^[?
-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
-.Ql /
-appended to them.
-.It list-command: ^X?
-Prints a sorted, columnated list of command names (if any) that can complete
-the partial word containing the cursor.
-.It list-file: ^X^Y
-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
-.Ic list
-above.
-.It newline: ^J , ^M
-Causes the current input line to be processed by the shell.
-The current cursor position may be anywhere on the line.
-.It newline-and-next: ^O
-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
-.Ic up-history
-or
-.Ic search-history .
-.It no-op: QUIT
-This does nothing.
-.It prefix-1: ^[
-Introduces a 2-character command sequence.
-.It prefix-2: ^X , ^[[ , ^[O
-Introduces a 2-character command sequence.
-.It Xo prev-hist-word:
-.Op Ar n
-.No ^[. , ^[_
-.Xc
-The last
-.Pq Ar n Ns th
-word of the previous command is inserted at the cursor.
-.It quote: ^^
-The following character is taken literally rather than as an editing command.
-.It redraw: ^L
-Reprints the prompt string and the current input line.
-.It Xo search-character-backward:
-.Op Ar n
-.No ^[^]
-.Xc
-Search backward in the current line for the
-.Ar n Ns th
-occurrence of the next character typed.
-.It Xo search-character-forward:
-.Op Ar n
-.No ^]
-.Xc
-Search forward in the current line for the
-.Ar n Ns th
-occurrence of the next character typed.
-.It search-history: ^R
-Enter incremental search mode.
-The internal history list is searched
-backwards for commands matching the input.
-An initial
-.Ql ^
-in the search string anchors the search.
-The abort key will leave search mode.
-Other commands will be executed after leaving search mode.
-Successive
-.Ic search-history
-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.
-.It set-mark-command: ^[ Ns Aq space
-Set the mark at the cursor position.
-.It stuff:
-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 ^T mini-systat feature, for example.
-.It stuff-reset:
-Acts like
-.Ic stuff ,
-then aborts input the same as an interrupt.
-.It transpose-chars: ^T
-If at the end of line, or if the
-.Ic gmacs
-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.
-.It Xo up-history:
-.Op Ar n
-.No ^P , ^XA
-.Xc
-Scrolls the history buffer backward
-.Ar n
-lines (earlier).
-.It Xo upcase-word:
-.Op Ar n
-.No ^[U , ^[u
-.Xc
-Uppercase the next
-.Ar n
-words.
-.It quote: ^V
-Synonym for ^^.
-.It yank: ^Y
-Inserts the most recently killed text string at the current cursor position.
-.It yank-pop: ^[y
-Immediately after a
-.Ic yank ,
-replaces the inserted text string with the next previously killed text string.
-.El
-.Ss Vi editing mode
-The vi command-line editor in
-.Nm
-has basically the same commands as the
-.Xr vi 1
-editor with the following exceptions:
-.Bl -bullet
-.It
-You start out in insert mode.
-.It
-There are file name and command completion commands:
-=, \e, *, ^X, ^E, ^F, and, optionally,
-.Aq tab
-and
-.Aq esc .
-.It
-The
-.Ic _
-command is different (in
-.Nm
-it is the last argument command; in
-.Xr vi 1
-it goes to the start of the current line).
-.It
-The
-.Ic /
-and
-.Ic G
-commands move in the opposite direction to the
-.Ic j
-command.
-.It
-Commands which don't make sense in a single line editor are not available
-(e.g. screen movement commands and
-.Xr ex 1 Ns -style
-colon
-.Pq Ic \&:
-commands).
-.El
-.Pp
-Note that the ^X stands for control-X; also
-.Aq esc ,
-.Aq space ,
-and
-.Aq tab
-are used for escape, space, and tab, respectively (no kidding).
-.Pp
-Like
-.Xr vi 1 ,
-there are two modes:
-.Dq insert
-mode and
-.Dq 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
-.Xr tty 4
-settings
-(see
-.Xr stty 1 )
-and have their usual meaning (normal values are in parentheses): kill (^U),
-erase (^?), werase (^W), eof (^D), intr (^C), and quit (^\e).
-In addition to
-the above, the following characters are also treated specially in insert mode:
-.Bl -tag -width 10n
-.It ^E
-Command and file name enumeration (see below).
-.It ^F
-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.
-.It ^H
-Erases previous character.
-.It ^J \*(Ba ^M
-End of line.
-The current line is read, parsed, and executed by the shell.
-.It ^V
-Literal next.
-The next character typed is not treated specially (can be used
-to insert the characters being described here).
-.It ^X
-Command and file name expansion (see below).
-.It Aq esc
-Puts the editor in command mode (see below).
-.It Aq tab
-Optional file name and command completion (see
-.Ic ^F
-above), enabled with
-.Ic set -o vi-tabcomplete .
-.El
-.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, an
-.Op Ar n
-indicates the command may be prefixed by a number (e.g.\&
-.Ic 10l
-moves right 10 characters); if no number prefix is used,
-.Ar n
-is assumed to be 1 unless otherwise specified.
-The term
-.Dq current position
-refers to the position between the cursor and the character preceding the
-cursor.
-A
-.Dq word
-is a sequence of letters, digits, and underscore characters or a sequence of
-non-letter, non-digit, non-underscore, and non-whitespace characters (e.g.\&
-.Dq ab2*&^
-contains two words) and a
-.Dq big-word
-is a sequence of non-whitespace characters.
-.Pp
-Special
-.Nm
-vi commands:
-.Pp
-The following commands are not in, or are different from, the normal vi file
-editor:
-.Bl -tag -width 10n
-.It Xo
-.Oo Ar n Oc Ns _
-.Xc
-Insert a space followed by the
-.Ar n Ns th
-big-word from the last command in the history at the current position and enter
-insert mode; if
-.Ar n
-is not specified, the last word is inserted.
-.It #
-Insert the comment character
-.Pq Sq #
-at the start of the current line and return the line to the shell (equivalent
-to
-.Ic I#^J ) .
-.It Xo
-.Oo Ar n Oc Ns g
-.Xc
-Like
-.Ic G ,
-except if
-.Ar n
-is not specified, it goes to the most recent remembered line.
-.It Xo
-.Oo Ar n Oc Ns v
-.Xc
-Edit line
-.Ar n
-using the
-.Xr vi 1
-editor; if
-.Ar n
-is not specified, the current line is edited.
-The actual command executed is
-.Ic fc -e ${VISUAL:-${EDITOR:-vi}} Ar n .
-.It * and ^X
-Command or file name expansion is applied to the current big-word (with an
-appended
-.Ql *
-if the word contains no file globbing 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:
-.Ql \&; ,
-.Ql | ,
-.Ql & ,
-.Ql ( ,
-or
-.Ql \&)
-and does not contain a slash
-.Pq Sq /
-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
-.Ev PATH
-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.
-.It Xo
-.Oo Ar n Oc Ns \e ,
-.Oo Ar n Oc Ns ^F ,
-.Oo Ar n Oc Ns Aq tab ,
-.No and
-.Oo Ar n Oc Ns Aq esc
-.Xc
-Command/file name completion.
-Replace the current big-word with the
-longest unique match obtained after performing command and file name expansion.
-.Aq tab
-is only recognized if the
-.Ic vi-tabcomplete
-option is set, while
-.Aq esc
-is only recognized if the
-.Ic vi-esccomplete
-option is set (see
-.Ic set -o ) .
-If
-.Ar n
-is specified, the
-.Ar n Ns th
-possible completion is selected (as reported by the command/file name
-enumeration command).
-.It = and ^E
-Command/file name enumeration.
-List all the commands or files that match the current big-word.
-.It @ Ns Ar c
-Macro expansion.
-Execute the commands found in the alias
-.Ar c .
-.El
-.Pp
-Intra-line movement commands:
-.Bl -tag -width Ds
-.It Xo
-.Oo Ar n Oc Ns h and
-.Oo Ar n Oc Ns ^H
-.Xc
-Move left
-.Ar n
-characters.
-.It Xo
-.Oo Ar n Oc Ns l and
-.Oo Ar n Oc Ns Aq space
-.Xc
-Move right
-.Ar n
-characters.
-.It 0
-Move to column 0.
-.It ^
-Move to the first non-whitespace character.
-.It Xo
-.Oo Ar n Oc Ns \*(Ba
-.Xc
-Move to column
-.Ar n .
-.It $
-Move to the last character.
-.It Xo
-.Oo Ar n Oc Ns b
-.Xc
-Move back
-.Ar n
-words.
-.It Xo
-.Oo Ar n Oc Ns B
-.Xc
-Move back
-.Ar n
-big-words.
-.It Xo
-.Oo Ar n Oc Ns e
-.Xc
-Move forward to the end of the word,
-.Ar n
-times.
-.It Xo
-.Oo Ar n Oc Ns E
-.Xc
-Move forward to the end of the big-word,
-.Ar n
-times.
-.It Xo
-.Oo Ar n Oc Ns w
-.Xc
-Move forward
-.Ar n
-words.
-.It Xo
-.Oo Ar n Oc Ns W
-.Xc
-Move forward
-.Ar n
-big-words.
-.It %
-Find match.
-The editor looks forward for the nearest parenthesis, bracket, or
-brace and then moves the cursor to the matching parenthesis, bracket, or brace.
-.It Xo
-.Oo Ar n Oc Ns f Ns Ar c
-.Xc
-Move forward to the
-.Ar n Ns th
-occurrence of the character
-.Ar c .
-.It Xo
-.Oo Ar n Oc Ns F Ns Ar c
-.Xc
-Move backward to the
-.Ar n Ns th
-occurrence of the character
-.Ar c .
-.It Xo
-.Oo Ar n Oc Ns t Ns Ar c
-.Xc
-Move forward to just before the
-.Ar n Ns th
-occurrence of the character
-.Ar c .
-.It Xo
-.Oo Ar n Oc Ns T Ns Ar c
-.Xc
-Move backward to just before the
-.Ar n Ns th
-occurrence of the character
-.Ar c .
-.It Xo
-.Oo Ar n Oc Ns \&;
-.Xc
-Repeats the last
-.Ic f , F , t ,
-or
-.Ic T
-command.
-.It Xo
-.Oo Ar n Oc Ns \&,
-.Xc
-Repeats the last
-.Ic f , F , t ,
-or
-.Ic T
-command, but moves in the opposite direction.
-.El
-.Pp
-Inter-line movement commands:
-.Bl -tag -width Ds
-.It Xo
-.Oo Ar n Oc Ns j ,
-.Oo Ar n Oc Ns + ,
-.No and
-.Oo Ar n Oc Ns ^N
-.Xc
-Move to the
-.Ar n Ns th
-next line in the history.
-.It Xo
-.Oo Ar n Oc Ns k ,
-.Oo Ar n Oc Ns - ,
-.No and
-.Oo Ar n Oc Ns ^P
-.Xc
-Move to the
-.Ar n Ns th
-previous line in the history.
-.It Xo
-.Oo Ar n Oc Ns G
-.Xc
-Move to line
-.Ar n
-in the history; if
-.Ar n
-is not specified, the number of the first remembered line is used.
-.It Xo
-.Oo Ar n Oc Ns g
-.Xc
-Like
-.Ic G ,
-except if
-.Ar n
-is not specified, it goes to the most recent remembered line.
-.It Xo
-.Oo Ar n Oc Ns / Ns Ar string
-.Xc
-Search backward through the history for the
-.Ar n Ns th
-line containing
-.Ar string ;
-if
-.Ar string
-starts with
-.Ql ^ ,
-the remainder of the string must appear at the start of the history line for
-it to match.
-.It Xo
-.Oo Ar n Oc Ns \&? Ns Ar string
-.Xc
-Same as
-.Ic / ,
-except it searches forward through the history.
-.It Xo
-.Oo Ar n Oc Ns n
-.Xc
-Search for the
-.Ar n Ns th
-occurrence of the last search string; the directory of the search is the same
-as the last search.
-.It Xo
-.Oo Ar n Oc Ns N
-.Xc
-Search for the
-.Ar n Ns th
-occurrence of the last search string; the directory of the search is the
-opposite of the last search.
-.El
-.Pp
-Edit commands
-.Bl -tag -width Ds
-.It Xo
-.Oo Ar n Oc Ns a
-.Xc
-Append text
-.Ar n
-times; goes into insert mode just after the current position.
-The append is
-only replicated if command mode is re-entered i.e.\&
-.Aq esc
-is used.
-.It Xo
-.Oo Ar n Oc Ns A
-.Xc
-Same as
-.Ic a ,
-except it appends at the end of the line.
-.It Xo
-.Oo Ar n Oc Ns i
-.Xc
-Insert text
-.Ar n
-times; goes into insert mode at the current position.
-The insertion is only
-replicated if command mode is re-entered i.e.\&
-.Aq esc
-is used.
-.It Xo
-.Oo Ar n Oc Ns I
-.Xc
-Same as
-.Ic i ,
-except the insertion is done just before the first non-blank character.
-.It Xo
-.Oo Ar n Oc Ns s
-.Xc
-Substitute the next
-.Ar n
-characters (i.e. delete the characters and go into insert mode).
-.It S
-Substitute whole line.
-All characters from the first non-blank character to the
-end of the line are deleted and insert mode is entered.
-.It Xo
-.Oo Ar n Oc Ns c Ns Ar move-cmd
-.Xc
-Change from the current position to the position resulting from
-.Ar n move-cmd Ns s
-(i.e. delete the indicated region and go into insert mode); if
-.Ar move-cmd
-is
-.Ic c ,
-the line starting from the first non-blank character is changed.
-.It C
-Change from the current position to the end of the line (i.e. delete to the
-end of the line and go into insert mode).
-.It Xo
-.Oo Ar n Oc Ns x
-.Xc
-Delete the next
-.Ar n
-characters.
-.It Xo
-.Oo Ar n Oc Ns X
-.Xc
-Delete the previous
-.Ar n
-characters.
-.It D
-Delete to the end of the line.
-.It Xo
-.Oo Ar n Oc Ns d Ns Ar move-cmd
-.Xc
-Delete from the current position to the position resulting from
-.Ar n move-cmd Ns s ;
-.Ar move-cmd
-is a movement command (see above) or
-.Ic d ,
-in which case the current line is deleted.
-.It Xo
-.Oo Ar n Oc Ns r Ns Ar c
-.Xc
-Replace the next
-.Ar n
-characters with the character
-.Ar c .
-.It Xo
-.Oo Ar n Oc Ns R
-.Xc
-Replace.
-Enter insert mode but overwrite existing characters instead of
-inserting before existing characters.
-The replacement is repeated
-.Ar n
-times.
-.It Xo
-.Oo Ar n Oc Ns ~
-.Xc
-Change the case of the next
-.Ar n
-characters.
-.It Xo
-.Oo Ar n Oc Ns y Ns Ar move-cmd
-.Xc
-Yank from the current position to the position resulting from
-.Ar n move-cmd Ns s
-into the yank buffer; if
-.Ar move-cmd
-is
-.Ic y ,
-the whole line is yanked.
-.It Y
-Yank from the current position to the end of the line.
-.It Xo
-.Oo Ar n Oc Ns p
-.Xc
-Paste the contents of the yank buffer just after the current position,
-.Ar n
-times.
-.It Xo
-.Oo Ar n Oc Ns P
-.Xc
-Same as
-.Ic p ,
-except the buffer is pasted at the current position.
-.El
-.Pp
-Miscellaneous vi commands
-.Bl -tag -width Ds
-.It ^J and ^M
-The current line is read, parsed, and executed by the shell.
-.It ^L and ^R
-Redraw the current line.
-.It Xo
-.Oo Ar n Oc Ns \&.
-.Xc
-Redo the last edit command
-.Ar n
-times.
-.It u
-Undo the last edit command.
-.It U
-Undo all changes that have been made to the current line.
-.It Ar intr No and Ar quit
-The interrupt and quit terminal characters cause the current line to be
-deleted and a new prompt to be printed.
-.El
-.Sh FILES
-.Bl -tag -width "/etc/suid_profileXX" -compact
-.It Pa ~/.profile
-User's login profile.
-.It Pa /etc/ksh.kshrc
-Global configuration file.
-Not sourced by default.
-.It Pa /etc/profile
-System login profile.
-.It Pa /etc/shells
-Shell database.
-.It Pa /etc/suid_profile
-Privileged shell profile.
-.El
-.Sh SEE ALSO
-.Xr csh 1 ,
-.Xr ed 1 ,
-.Xr mg 1 ,
-.Xr sh 1 ,
-.Xr stty 1 ,
-.Xr vi 1 ,
-.Xr shells 5 ,
-.Xr environ 7 ,
-.Xr script 7
-.Rs
-.%A Morris Bolsky
-.%A David Korn
-.%T "The KornShell Command and Programming Language"
-.%D 1983
-.%O "ISBN 0-13-516972-0"
-.Re
-.Rs
-.%A Stephen G. Kochan
-.%A Patrick H. Wood
-.%T "UNIX Shell Programming"
-.%O "Hayden"
-.Re
-.Rs
-.%A "IEEE Inc."
-.%T "IEEE Standard for Information Technology \- Portable Operating " \
-    "System Interface (POSIX) \- Part 2: Shell and Utilities"
-.%D 1993
-.%O "ISBN 1-55937-266-9"
-.Re
-.Sh VERSION
-This page documents version @(#)PD KSH v5.2.14 99/07/13.2 of the public
-domain Korn shell.
-.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 of
-.Nm pdksh
-was created by Eric Gisin, and it was subsequently maintained by John R.\&
-MacMillan (change!john at sq.sq.com), Simon J. Gerraty (sjg at zen.void.oz.au),
-and Michael Rendell (michael at cs.mun.ca).
-The
-.Pa CONTRIBUTORS
-file in the source distribution contains a more complete list of people and
-their part in the shell's development.
-.\" .Sh BUGS
-.\" Any bugs in
-.\" .Nm pdksh
-.\" should be reported to pdksh at cs.mun.ca.
-.\" Please include the version of
-.\" .Nm pdksh
-.\" .Po
-.\" .Ic echo $KSH_VERSION
-.\" shows it
-.\" .Pc ,
-.\" 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 be
-.\" helpful: options you are using (both
-.\" .Pa options.h
-.\" and
-.\" .Ic set Fl o Ic options )
-.\" and a copy of your
-.\" .Pa config.h
-.\" (the file generated by the
-.\" .Pa configure
-.\" script).
-.\" New versions of
-.\" .Nm pdksh
-.\" can be obtained from ftp://ftp.cs.mun.ca/pub/pdksh.
-.\" .Pp
-.\" BTW, the most frequently reported bug is:
-.\" .Bd -literal -offset indent
-.\" $ echo hi | read a; echo $a   # Does not print hi
-.\" .Ed
-.\" .Pp
-.\" I'm aware of this and there is no need to report it.
--- bin/ksh/sh.1
+++ /dev/null
@@ -1,3807 +0,0 @@
-.\" $MidnightBSD: src/bin/ksh/sh.1,v 1.2 2007/07/26 20:13:00 laffer1 Exp $
-.\"	$OpenBSD: sh.1,v 1.73 2006/07/26 10:13:25 jmc Exp $
-.\"
-.\"	Public Domain
-.\"
-.Dd August 19, 1996
-.Dt SH 1
-.Os
-.Sh NAME
-.Nm sh
-.Nd public domain Bourne shell
-.Sh SYNOPSIS
-.Nm sh
-.Bk -words
-.Op Fl +abCefhiklmnpruvXx
-.Op Fl +o Ar option
-.Oo Fl c Ar string \*(Ba Fl s \*(Ba
-.Ar \ file\ \&
-.Op Ar argument ... Oc
-.Ek
-.Sh DESCRIPTION
-.Nm
-is a reimplementation of the Bourne shell, a command interpreter for both
-interactive and script use.
-.Pp
-The options are as follows:
-.Bl -tag -width Ds
-.It Fl c Ar string
-.Nm
-will execute the command(s) contained in
-.Ar string .
-.It Fl i
-Interactive shell.
-A shell is
-.Dq interactive
-if this
-option is used or if both standard input and standard error are attached
-to a
-.Xr tty 4 .
-An interactive shell has job control enabled, ignores the
-.Dv SIGINT ,
-.Dv SIGQUIT ,
-and
-.Dv SIGTERM
-signals, and prints prompts before reading input (see the
-.Ev PS1
-and
-.Ev PS2
-parameters).
-For non-interactive shells, the
-.Ic trackall
-option is on by default (see the
-.Ic set
-command below).
-.It Fl l
-Login shell.
-If the basename the shell is called with (i.e. argv[0])
-starts with
-.Ql -
-or if this option is used,
-the shell is assumed to be a login shell and the shell reads and executes
-the contents of
-.Pa /etc/profile
-and
-.Pa $HOME/.profile
-if they exist and are readable.
-.It Fl p
-Privileged shell.
-A shell is
-.Dq privileged
-if this option is used
-or if the real user ID or group ID does not match the
-effective user ID or group ID (see
-.Xr getuid 2
-and
-.Xr getgid 2 ) .
-A privileged shell does not process
-.Pa $HOME/.profile
-nor the
-.Ev ENV
-parameter (see below).
-Instead, the file
-.Pa /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).
-.It Fl r
-Restricted shell.
-A shell is
-.Dq restricted
-if this
-option is used;
-if the basename the shell was invoked with was
-.Dq rsh ;
-or if the
-.Ev SHELL
-parameter is set to
-.Dq rsh .
-The following restrictions come into effect after the shell processes any
-profile and
-.Ev ENV
-files:
-.Pp
-.Bl -bullet -compact
-.It
-The
-.Ic cd
-command is disabled.
-.It
-The
-.Ev SHELL ,
-.Ev ENV ,
-and
-.Ev PATH
-parameters cannot be changed.
-.It
-Command names can't be specified with absolute or relative paths.
-.It
-The
-.Fl p
-option of the built-in command
-.Ic command
-can't be used.
-.It
-Redirections that create files can't be used (i.e.\&
-.Ql \*(Gt ,
-.Ql \*(Gt\*(Ba ,
-.Ql \*(Gt\*(Gt ,
-.Ql \*(Lt\*(Gt ) .
-.El
-.It Fl s
-The shell reads commands from standard input; all non-option arguments
-are positional parameters.
-.El
-.Pp
-In addition to the above, the options described in the
-.Ic set
-built-in command can also be used on the command line:
-both
-.Op Fl +abCefhkmnuvXx
-and
-.Op Fl +o Ar option
-can be used for single letter or long options, respectively.
-.Pp
-If neither the
-.Fl c
-nor the
-.Fl s
-option is 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 the standard input.
-The name of the shell (i.e. the contents of $0)
-is determined as follows: if the
-.Fl c
-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 basename the shell was called with (i.e. argv[0]) is used.
-.Pp
-If the
-.Ev ENV
-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
-.Pq Sq ~
-substitution and the resulting file
-(if any) is read and executed.
-.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.
-.Ss Command syntax
-The shell begins parsing its input by breaking it into
-.Em words .
-Words, which are sequences of characters, are delimited by unquoted whitespace
-characters (space, tab, and newline) or meta-characters
-.Po
-.Ql \*(Lt ,
-.Ql \*(Gt ,
-.Ql \*(Ba ,
-.Ql \&; ,
-.Ql ( ,
-.Ql \&) ,
-and
-.Ql &
-.Pc .
-Aside from delimiting words, spaces and tabs are ignored, while newlines
-usually delimit commands.
-The meta-characters are used in building the following
-.Em tokens :
-.Ql \*(Lt ,
-.Ql \*(Lt& ,
-.Ql \*(Lt\*(Lt ,
-.Ql \*(Gt ,
-.Ql \*(Gt& ,
-.Ql \*(Gt\*(Gt ,
-etc. are used to specify redirections (see
-.Sx Input/output redirection
-below);
-.Ql \*(Ba
-is used to create pipelines;
-.Ql \&;
-is used to separate commands;
-.Ql &
-is used to create asynchronous pipelines;
-.Ql &&
-and
-.Ql ||
-are used to specify conditional execution;
-.Ql ;;
-is used in
-.Ic case
-statements;
-and lastly,
-.Ql \&( .. )\&
-is used to create subshells.
-.Pp
-Whitespace and meta-characters can be quoted individually using a backslash
-.Pq Sq \e ,
-or in groups using double
-.Pq Sq \&"
-or single
-.Pq Sq '
-quotes.
-Note that the following characters are also treated specially by the
-shell and must be quoted if they are to represent themselves:
-.Ql \e ,
-.Ql \&" ,
-.Ql ' ,
-.Ql # ,
-.Ql $ ,
-.Ql ` ,
-.Ql ~ ,
-.Ql { ,
-.Ql } ,
-.Ql * ,
-.Ql \&? ,
-and
-.Ql [ .
-The first three of these are the above mentioned quoting characters (see
-.Sx Quoting
-below);
-.Ql # ,
-if used at the beginning of a word, introduces a comment \(em everything after
-the
-.Ql #
-up to the nearest newline is ignored;
-.Ql $
-is used to introduce parameter, command, and arithmetic substitutions (see
-.Sx Substitution
-below);
-.Ql `
-introduces an old-style command substitution (see
-.Sx Substitution
-below);
-.Ql ~
-begins a directory expansion (see
-.Sx Tilde expansion
-below);
-and finally,
-.Ql * ,
-.Ql \&? ,
-and
-.Ql [
-are used in file name generation (see
-.Sx File name patterns
-below).
-.Pp
-As words and tokens are parsed, the shell builds commands, of which there
-are two basic types:
-.Em simple-commands ,
-typically programs that are executed, and
-.Em compound-commands ,
-such as
-.Ic for
-and
-.Ic if
-statements, grouping constructs, and function definitions.
-.Pp
-A simple-command consists of some combination of parameter assignments
-(see
-.Sx Parameters
-below),
-input/output redirections (see
-.Sx 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 external command
-(i.e. a separate executable file that is located using the
-.Ev PATH
-parameter; see
-.Sx Command execution
-below).
-Note that all command constructs have an exit status: for external commands,
-this is related to the status returned by
-.Xr wait 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,
-etc.) 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 0 if there were no command substitutions.
-.Pp
-Commands can be chained together using the
-.Ql |
-token to form pipelines, in which the standard output of each command but the
-last is piped (see
-.Xr pipe 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
-.Ql \&!
-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;
-if the original status was not 0, the complemented status will be 0.
-.Pp
-.Em Lists
-of commands can be created by separating pipelines by any of the following
-tokens:
-.Ql && ,
-.Ql || ,
-.Ql & ,
-.Ql |& ,
-and
-.Ql \&; .
-The first two are for conditional execution:
-.Dq Ar cmd1 No && Ar cmd2
-executes
-.Ar cmd2
-only if the exit status of
-.Ar cmd1
-is zero;
-.Ql ||
-is the opposite \(em
-.Ar cmd2
-is executed only if the exit status of
-.Ar cmd1
-is non-zero.
-.Ql &&
-and
-.Ql ||
-have equal precedence which is higher than that of
-.Ql & ,
-.Ql |& ,
-and
-.Ql \&; ,
-which also have equal precedence.
-Note that the
-.Ql &&
-and
-.Ql ||
-operators are
-.Qq left-associative .
-For example, both of these commands will print only
-.Qq bar :
-.Bd -literal -offset indent
-$ false && echo foo || echo bar
-$ true || echo foo && echo bar
-.Ed
-.Pp
-The
-.Ql &
-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; see
-.Sx Job control
-below).
-When an asynchronous command is started when job control is disabled
-(i.e. in most scripts), the command is started with signals
-.Dv SIGINT
-and
-.Dv SIGQUIT
-ignored and with input redirected from
-.Pa /dev/null
-(however, redirections specified in the asynchronous command have precedence).
-Note that a command must follow the
-.Ql &&
-and
-.Ql ||
-operators, while it need not follow
-.Ql & ,
-.Ql |& ,
-or
-.Ql \&; .
-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.
-.Pp
-Compound commands are created using the following reserved words.
-These words
-are only recognized if they are unquoted and if they are used as the first
-word of a command (i.e. they can't be preceded by parameter assignments or
-redirections):
-.Bd -literal -offset indent
-case     else     function     then      !
-do       esac     if           time      [[
-done     fi       in           until     {
-elif     for      select       while     }
-.Ed
-.Pp
-.Sy Note :
-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
-.Ic exec
-statement should be used instead to redirect file descriptors before the
-control structure.
-.Pp
-In the following compound command descriptions, command lists (denoted as
-.Em list )
-that are followed by reserved words must end with a semicolon, a newline, or
-a (syntactically correct) reserved word.
-For example, the following are all valid:
-.Bd -literal -offset indent
-$ { echo foo; echo bar; }
-$ { echo foo; echo bar\*(Ltnewline\*(Gt }
-$ { { echo foo; echo bar; } }
-.Ed
-.Pp
-This is not valid:
-.Pp
-.Dl $ { echo foo; echo bar }
-.Bl -tag -width Ds
-.It Pq Ar list
-Execute
-.Ar list
-in a subshell.
-There is no implicit way to pass environment changes from a
-subshell back to its parent.
-.It { Ar list ; No }
-Compound construct;
-.Ar list
-is executed, but not in a subshell.
-Note that
-.Ql {
-and
-.Ql }
-are reserved words, not meta-characters.
-.It Xo case Ar word No in
-.Oo Op (
-.Ar \ pattern
-.Op \*(Ba Ar pattern
-.No ... No )
-.Ar list No ;;\ \& Oc ... esac
-.Xc
-The
-.Ic case
-statement attempts to match
-.Ar word
-against a specified
-.Ar pattern ;
-the
-.Ar list
-associated with the first successfully matched pattern is executed.
-Patterns used in
-.Ic case
-statements are the same as those used for file name patterns except that the
-restrictions regarding
-.Ql \&.
-and
-.Ql /
-are dropped.
-Note that any unquoted space before and after a pattern is
-stripped; any space within 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
-.Ic in
-and
-.Ic esac
-e.g.\&
-.Ic case $foo { *) echo bar; } .
-The exit status of a
-.Ic case
-statement is that of the executed
-.Ar list ;
-if no
-.Ar list
-is executed, the exit status is zero.
-.It Xo for Ar name
-.Oo in Ar word No ... Oc ;
-.No do Ar list ; No done
-.Xc
-For each
-.Ar word
-in the specified word list, the parameter
-.Ar name
-is set to the word and
-.Ar list
-is executed.
-If
-.Ic in
-is not used to specify a word list, the positional parameters
-($1, $2, etc.)\&
-are used instead.
-For historical reasons, open and close braces may be used instead of
-.Ic do
-and
-.Ic done
-e.g.\&
-.Ic for i; { echo $i; } .
-The exit status of a
-.Ic for
-statement is the last exit status of
-.Ar list ;
-if
-.Ar list
-is never executed, the exit status is zero.
-.It Xo if Ar list ;
-.No then Ar list ;
-.Oo elif Ar list ;
-.No then Ar list ; Oc
-.No ...
-.Oo else Ar list ; Oc
-.No fi
-.Xc
-If the exit status of the first
-.Ar list
-is zero, the second
-.Ar list
-is executed; otherwise, the
-.Ar list
-following the
-.Ic elif ,
-if any, is executed with similar consequences.
-If all the lists following the
-.Ic if
-and
-.Ic elif Ns s
-fail (i.e. exit with non-zero status), the
-.Ar list
-following the
-.Ic else
-is executed.
-The exit status of an
-.Ic if
-statement is that of non-conditional
-.Ar list
-that is executed; if no non-conditional
-.Ar list
-is executed, the exit status is zero.
-.It Xo until Ar list ;
-.No do Ar list ;
-.No done
-.Xc
-This works like
-.Ic while ,
-except that the body is executed only while the exit status of the first
-.Ar list
-is non-zero.
-.It Xo while Ar list ;
-.No do Ar list ;
-.No done
-.Xc
-A
-.Ic while
-is a pre-checked loop.
-Its body is executed as often as the exit status of the first
-.Ar list
-is zero.
-The exit status of a
-.Ic while
-statement is the last exit status of the
-.Ar list
-in the body of the loop; if the body is not executed, the exit status is zero.
-.It Xo function Ar name
-.No { Ar list ; No }
-.Xc
-Defines the function
-.Ar name
-(see
-.Sx Functions
-below).
-Note that redirections specified after a function definition are
-performed whenever the function is executed, not when the function definition
-is executed.
-.It Ar name Ns () Ar command
-Mostly the same as
-.Ic function
-(see
-.Sx Functions
-below).
-.El
-.Ss Quoting
-Quoting is used to prevent the shell from treating characters or words
-specially.
-There are three methods of quoting.
-First,
-.Ql \e
-quotes the following character, unless it is at the end of a line, in which
-case both the
-.Ql \e
-and the newline are stripped.
-Second, a single quote
-.Pq Sq '
-quotes everything up to the next single quote (this may span lines).
-Third, a double quote
-.Pq Sq \&"
-quotes all characters, except
-.Ql $ ,
-.Ql `
-and
-.Ql \e ,
-up to the next unquoted double quote.
-.Ql $
-and
-.Ql `
-inside double quotes have their usual meaning (i.e. parameter, command, or
-arithmetic substitution) except no field splitting is carried out on the
-results of double-quoted substitutions.
-If a
-.Ql \e
-inside a double-quoted string is followed by
-.Ql \e ,
-.Ql $ ,
-.Ql ` ,
-or
-.Ql \&" ,
-it is replaced by the second character; if it is followed by a newline, both
-the
-.Ql \e
-and the newline are stripped; otherwise, both the
-.Ql \e
-and the character following are unchanged.
-.Pp
-.Sy Note :
-See
-.Sx POSIX mode
-below for a special rule regarding
-differences in quoting when the shell is in POSIX mode.
-.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 (i.e. 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:
-.Bd -literal -offset indent
-hash='alias -t'
-type='whence -v'
-.Ed
-.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
-.Ic alias -t .
-Note that changing the
-.Ev PATH
-parameter clears the saved paths for all tracked aliases.
-If the
-.Ic trackall
-option is set (i.e.\&
-.Ic set -o Ic trackall
-or
-.Ic set -h ) ,
-the shell tracks all commands.
-This option is set automatically for non-interactive shells.
-For interactive shells, only the following commands are
-automatically tracked:
-.Xr cat 1 ,
-.Xr cc 1 ,
-.Xr chmod 1 ,
-.Xr cp 1 ,
-.Xr date 1 ,
-.Xr ed 1 ,
-.Xr emacs 1 ,
-.Xr grep 1 ,
-.Xr ls 1 ,
-.Xr mail 1 ,
-.Xr make 1 ,
-.Xr mv 1 ,
-.Xr pr 1 ,
-.Xr rm 1 ,
-.Xr sed 1 ,
-.Xr vi 1 ,
-and
-.Xr who 1 .
-.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
-.Pf $ Ns Ar name
-or
-.Pf ${ Ns Ar ... Ns } ;
-command substitutions take the form
-.Pf $( Ns Ar command Ns \&)
-or
-.Pf ` Ns Ar command Ns ` ;
-and arithmetic substitutions take the form
-.Pf $(( Ns Ar expression Ns )) .
-.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
-.Ev IFS
-parameter.
-The
-.Ev IFS
-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
-.Ev IFS
-characters are called
-.Dq IFS whitespace .
-Sequences of one or more
-.Ev IFS
-whitespace characters, in combination with zero or one
-.Pf non- Ev IFS
-whitespace
-characters, delimit a field.
-As a special case, leading and trailing
-.Ev IFS
-whitespace is stripped (i.e. no leading or trailing empty field is created by
-it); leading
-.Pf non- Ev IFS
-whitespace does create an empty field.
-.Pp
-Example: If
-.Ev IFS
-is set to
-.Dq \*(Ltspace\*(Gt: ,
-and VAR is set to
-.Dq \*(Ltspace\*(GtA\*(Ltspace\*(Gt:\*(Ltspace\*(Gt\*(Ltspace\*(GtB::D ,
-the substitution for $VAR results in four fields:
-.Sq A ,
-.Sq B ,
-.Sq
-(an empty field),
-and
-.Sq D .
-Note that if the
-.Ev IFS
-parameter is set to the
-.Dv 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 the immediate result of
-the substitution.
-Using the previous example, the substitution for $VAR:E
-results in the fields:
-.Sq A ,
-.Sq B ,
-.Sq ,
-and
-.Sq D:E ,
-not
-.Sq A ,
-.Sq B ,
-.Sq ,
-.Sq D ,
-and
-.Sq 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
-.Dv IFS
-as a general whitespace delimiter.
-.Pp
-The results of substitution are, unless otherwise specified, also subject to
-file name expansion (see the relevant section below).
-.Pp
-A command substitution is replaced by the output generated by the specified
-command, which is run in a subshell.
-For
-.Pf $( Ns Ar command Ns \&)
-substitutions, normal quoting rules are used when
-.Ar command
-is parsed; however, for the
-.Pf ` Ns Ar command Ns `
-form, a
-.Ql \e
-followed by any of
-.Ql $ ,
-.Ql ` ,
-or
-.Ql \e
-is stripped (a
-.Ql \e
-followed by any other character is unchanged).
-As a special case in command substitutions, a command of the form
-.Pf \*(Lt Ar file
-is interpreted to mean substitute the contents of
-.Ar file .
-Note that
-.Ic $(\*(Lt foo)
-has the same effect as
-.Ic $(cat foo) ,
-but it is carried out more efficiently because no process is started.
-.Pp
-.Sy Note :
-.Pf $( Ns Ar command Ns \&)
-expressions are currently parsed by finding the matching parenthesis,
-regardless of quoting.
-This should be fixed soon.
-.Pp
-Arithmetic substitutions are replaced by the value of the specified expression.
-For example, the command
-.Ic echo $((2+3*4))
-prints 14.
-See
-.Sx Arithmetic expressions
-for a description of an expression.
-.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
-.Po
-.Ql _
-counts as a letter
-.Pc .
-Parameter substitutions take the form
-.Pf $ Ns Ar name ,
-.Pf ${ Ns Ar name Ns } ,
-or
-.Sm off
-.Pf ${ Ar name Oo Ar expr Oc }
-.Sm on
-where
-.Ar name
-is a parameter name.
-If substitution is performed on a parameter
-that is not set, a null string is substituted unless the
-.Ic nounset
-option
-.Po
-.Ic set Fl o Ic nounset
-or
-.Ic set Fl u
-.Pc
-is set, in which case an error occurs.
-.Pp
-Parameters can be assigned values in a number of ways.
-First, the shell implicitly sets some parameters like
-.Ql # ,
-.Ql PWD ,
-and
-.Ql $ ;
-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,
-.Ic FOO=bar
-sets the parameter
-.Dq FOO
-to
-.Dq 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 the implications of this).
-Note that both the parameter name and the
-.Ql =
-must be unquoted for the shell to recognize a parameter assignment.
-The fourth way of setting a parameter is with the
-.Ic export ,
-.Ic readonly ,
-and
-.Ic typeset
-commands; see their descriptions in the
-.Sx Command execution
-section.
-Fifth,
-.Ic for
-loops set parameters as well as the
-.Ic getopts ,
-.Ic read ,
-and
-.Ic set -A
-commands.
-Lastly, parameters can be assigned values using assignment operators
-inside arithmetic expressions (see
-.Sx Arithmetic expressions
-below) or using the
-.Sm off
-.Pf ${ Ar name No = Ar value No }
-.Sm on
-form of the parameter substitution (see below).
-.Pp
-Parameters with the export attribute (set using the
-.Ic export
-or
-.Ic typeset Fl x
-commands, or by parameter assignments followed by simple commands) are put in
-the environment (see
-.Xr environ 7 )
-of commands run by the shell as
-.Ar name Ns = Ns Ar value
-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.
-.Pp
-Modifiers can be applied to the
-.Pf ${ Ns Ar name Ns }
-form of parameter substitution:
-.Bl -tag -width Ds
-.Sm off
-.It ${ Ar name No :- Ar word No }
-.Sm on
-If
-.Ar name
-is set and not
-.Dv NULL ,
-it is substituted; otherwise,
-.Ar word
-is substituted.
-.Sm off
-.It ${ Ar name No :+ Ar word No }
-.Sm on
-If
-.Ar name
-is set and not
-.Dv NULL ,
-.Ar word
-is substituted; otherwise, nothing is substituted.
-.Sm off
-.It ${ Ar name No := Ar word No }
-.Sm on
-If
-.Ar name
-is set and not
-.Dv NULL ,
-it is substituted; otherwise, it is assigned
-.Ar word
-and the resulting value of
-.Ar name
-is substituted.
-.Sm off
-.It ${ Ar name No :? Ar word No }
-.Sm on
-If
-.Ar name
-is set and not
-.Dv NULL ,
-it is substituted; otherwise,
-.Ar word
-is printed on standard error (preceded by
-.Ar name : )
-and an error occurs (normally causing termination of a shell script, function,
-or script sourced using the
-.Sq \&.
-built-in).
-If
-.Ar word
-is omitted, the string
-.Dq parameter null or not set
-is used instead.
-.El
-.Pp
-In the above modifiers, the
-.Ql \&:
-can be omitted, in which case the conditions only depend on
-.Ar name
-being set (as opposed to set and not
-.Dv NULL ) .
-If
-.Ar word
-is needed, parameter, command, arithmetic, and tilde substitution are performed
-on it; if
-.Ar word
-is not needed, it is not evaluated.
-.Pp
-The following forms of parameter substitution can also be used:
-.Pp
-.Bl -tag -width Ds -compact
-.It Pf ${# Ns Ar name Ns \&}
-The number of positional parameters if
-.Ar name
-is
-.Ql * ,
-.Ql @ ,
-or not specified; otherwise the length of the string value of parameter
-.Ar name .
-.Pp
-.It Pf ${# Ns Ar name Ns [*]}
-.It Pf ${# Ns Ar name Ns [@]}
-The number of elements in the array
-.Ar name .
-.Pp
-.Sm off
-.It Xo
-.Pf ${ Ar name
-.Pf # Ar pattern No }
-.Xc
-.It Xo
-.Pf ${ Ar name
-.Pf ## Ar pattern No }
-.Xc
-.Sm on
-If
-.Ar pattern
-matches the beginning of the value of parameter
-.Ar name ,
-the matched text is deleted from the result of substitution.
-A single
-.Ql #
-results in the shortest match, and two
-of them result in the longest match.
-.Pp
-.Sm off
-.It Xo
-.Pf ${ Ar name
-.Pf % Ar pattern No }
-.Xc
-.It Xo
-.Pf ${ Ar name
-.Pf %% Ar pattern No }
-.Xc
-.Sm on
-Like ${..#..} substitution, but it deletes from the end of the value.
-.El
-.Pp
-The following special parameters are implicitly set by the shell and cannot be
-set directly using assignments:
-.Bl -tag -width "1 ... 9"
-.It Ev \&!
-Process ID of the last background process started.
-If no background processes have been started, the parameter is not set.
-.It Ev \&#
-The number of positional parameters ($1, $2, etc.).
-.It Ev \&$
-The PID of the shell, or the PID of the original shell if it is a subshell.
-Do
-.Em NOT
-use this mechanism for generating temporary file names; see
-.Xr mktemp 1
-instead.
-.It Ev -
-The concatenation of the current single letter options (see the
-.Ic set
-command below for a list of options).
-.It Ev \&?
-The exit status of the last non-asynchronous command executed.
-If the last command was killed by a signal,
-.Ic $?\&
-is set to 128 plus the signal number.
-.It Ev 0
-The name of the shell, determined as follows:
-the first argument to
-.Nm
-if it was invoked with the
-.Fl c
-option and arguments were given; otherwise the
-.Ar file
-argument, if it was supplied;
-or else the basename the shell was invoked with (i.e.\&
-.Li argv[0] ) .
-.Ev $0
-is also set to the name of the current script or
-the name of the current function, if it was defined with the
-.Ic function
-keyword (i.e. a Korn shell style function).
-.It Ev 1 No ... Ev 9
-The first nine positional parameters that were supplied to the shell, function,
-or script sourced using the
-.Sq \&.
-built-in.
-Further positional parameters may be accessed using
-.Pf ${ Ar number Ns } .
-.It Ev *
-All positional parameters (except parameter 0) i.e. $1, $2, $3, ...
-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
-.Ev IFS
-parameter (or the empty string if
-.Ev IFS
-is
-.Dv NULL ) .
-.It Ev @
-Same as
-.Ic $* ,
-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.
-.Ic $@
-can be used to access arguments, verbatim, without losing
-.Dv NULL
-arguments or splitting arguments with spaces.
-.El
-.Pp
-The following parameters are set and/or used by the shell:
-.Bl -tag -width "EXECSHELL"
-.It Ev CDPATH
-Search path for the
-.Ic cd
-built-in command.
-It works the same way as
-.Ev PATH
-for those directories not beginning with
-.Ql /
-in
-.Ic cd
-commands.
-Note that if
-.Ev CDPATH
-is set and does not contain
-.Sq \&.
-or contains an empty path, the current directory is not searched.
-Also, the
-.Ic cd
-built-in command will display the resulting directory when a match is found
-in any search path other than the empty path.
-.It Ev COLUMNS
-Set to the number of columns on the terminal or window.
-Currently set to the
-.Dq cols
-value as reported by
-.Xr stty 1
-if that value is non-zero.
-This parameter is used by the
-.Ic set -o
-and
-.Ic kill -l
-commands to format information columns.
-.It Ev ENV
-If this parameter is found to be set after any profile files are executed, the
-expanded value is used as a shell startup file.
-It typically contains function and alias definitions.
-.It Ev ERRNO
-Integer value of the shell's
-.Va errno
-variable.
-It indicates the reason the last system call failed.
-Not yet implemented.
-.It Ev EXECSHELL
-If set, this parameter is assumed to contain the shell that is to be used to
-execute commands that
-.Xr execve 2
-fails to execute and which do not start with a
-.Dq #! Ns Ar shell
-sequence.
-.It Ev FCEDIT
-The editor used by the
-.Ic fc
-command (see below).
-.It Ev FPATH
-Like
-.Ev PATH ,
-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
-.Ev PATH .
-See
-.Sx Functions
-below for more information.
-.It Ev HOME
-The default directory for the
-.Ic cd
-command and the value substituted for an unqualified
-.Ic ~
-(see
-.Sx Tilde expansion
-below).
-.It Ev IFS
-Internal field separator, used during substitution and by the
-.Ic read
-command, to split values into distinct arguments; normally set to space, tab,
-and newline.
-See
-.Sx Substitution
-above for details.
-.Pp
-.Sy Note :
-This parameter is not imported from the environment when the shell is
-started.
-.It Ev SH_VERSION
-The version of shell and the date the version was created (read-only).
-.It Ev LINENO
-The line number of the function or shell script that is currently being
-executed.
-.It Ev LINES
-Set to the number of lines on the terminal or window.
-.It Ev OLDPWD
-The previous working directory.
-Unset if
-.Ic cd
-has not successfully changed directories since the shell started, or if the
-shell doesn't know where it is.
-.It Ev OPTARG
-When using
-.Ic getopts ,
-it contains the argument for a parsed option, if it requires one.
-.It Ev OPTIND
-The index of the next argument to be processed when using
-.Ic getopts .
-Assigning 1 to this parameter causes
-.Ic getopts
-to process arguments from the beginning the next time it is invoked.
-.It Ev PATH
-A colon separated list of directories that are searched when looking for
-commands and files sourced using the
-.Sq \&.
-command (see below).
-An empty string resulting from a leading or trailing
-colon, or two adjacent colons, is treated as a
-.Sq \&.
-(the current directory).
-.It Ev POSIXLY_CORRECT
-If set, this parameter causes the
-.Ic posix
-option to be enabled.
-See
-.Sx POSIX mode
-below.
-.It Ev PPID
-The process ID of the shell's parent (read-only).
-.It Ev PS1
-The primary prompt for interactive shells.
-Parameter, command, and arithmetic
-substitutions are performed.
-.Ql \&!
-is replaced with the current command number (see the
-.Ic fc
-command below).
-A literal
-.Ql \&!
-can be put in the prompt by placing
-.Ql !!
-in
-.Ev PS1 .
-The default is
-.Sq $\ \&
-for non-root users,
-.Sq #\ \&
-for root.
-.It Ev PS2
-Secondary prompt string, by default
-.Sq \*(Gt\ \& ,
-used when more input is needed to complete a command.
-.It Ev PS4
-Used to prefix commands that are printed during execution tracing (see the
-.Ic set Fl x
-command below).
-Parameter, command, and arithmetic substitutions are performed
-before it is printed.
-The default is
-.Sq +\ \& .
-.It Ev PWD
-The current working directory.
-May be unset or
-.Dv NULL
-if the shell doesn't know where it is.
-.It Ev REPLY
-Default parameter for the
-.Ic read
-command if no names are given.
-.It Ev TMPDIR
-The directory temporary shell 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
-.Pa /tmp .
-.El
-.Ss Tilde expansion
-Tilde expansion, which is done in parallel with parameter substitution, is done
-on words starting with an unquoted
-.Ql ~ .
-The characters following the tilde, up to the first
-.Ql / ,
-if any, are assumed to be a login name.
-If the login name is empty,
-.Ql + ,
-or
-.Ql - ,
-the value of the
-.Ev HOME ,
-.Ev PWD ,
-or
-.Ev OLDPWD
-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
-(such as those preceding a simple-command or those occurring
-in the arguments of
-.Ic alias ,
-.Ic export ,
-.Ic readonly ,
-and
-.Ic typeset ) ,
-tilde expansion is done after any assignment
-(i.e. after the equals sign)
-or after an unquoted colon
-.Pq Sq \&: ;
-login names are also delimited by colons.
-.Pp
-The home directory of previously expanded login names are cached and re-used.
-The
-.Ic alias -d
-command may be used to list, change, and add to this cache (e.g.\&
-.Ic alias -d fac=/usr/local/facilities; cd ~fac/bin ) .
-.Ss File name patterns
-A file name pattern is a word containing one or more unquoted
-.Ql \&? ,
-.Ql * ,
-.Ql + ,
-.Ql @ ,
-or
-.Ql \&!
-characters or
-.Dq [..]
-sequences.
-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:
-.Bl -tag -width Ds
-.It \&?
-Matches any single character.
-.It \&*
-Matches any sequence of characters.
-.It [..]
-Matches any of the characters inside the brackets.
-Ranges of characters can be
-specified by separating two characters by a
-.Ql -
-(e.g.\&
-.Dq [a0-9]
-matches the letter
-.Sq a
-or any digit).
-In order to represent itself, a
-.Ql -
-must either be quoted or the first or last character in the character list.
-Similarly, a
-.Ql \&]
-must be quoted or the first character in the list if it is to represent itself
-instead of the end of the list.
-Also, a
-.Ql \&!
-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.
-.It [!..]
-Like [..],
-except it matches any character not inside the brackets.
-.Sm off
-.It *( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
-.Sm on
-Matches any string of characters that matches zero or more occurrences of the
-specified patterns.
-Example: The pattern
-.Ic *(foo|bar)
-matches the strings
-.Dq ,
-.Dq foo ,
-.Dq bar ,
-.Dq foobarfoo ,
-etc.
-.Sm off
-.It +( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
-.Sm on
-Matches any string of characters that matches one or more occurrences of the
-specified patterns.
-Example: The pattern
-.Ic +(foo|bar)
-matches the strings
-.Dq foo ,
-.Dq bar ,
-.Dq foobar ,
-etc.
-.Sm off
-.It ?( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
-.Sm on
-Matches the empty string or a string that matches one of the specified
-patterns.
-Example: The pattern
-.Ic ?(foo|bar)
-only matches the strings
-.Dq ,
-.Dq foo ,
-and
-.Dq bar .
-.Sm off
-.It @( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
-.Sm on
-Matches a string that matches one of the specified patterns.
-Example: The pattern
-.Ic @(foo|bar)
-only matches the strings
-.Dq foo
-and
-.Dq bar .
-.Sm off
-.It !( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
-.Sm on
-Matches any string that does not match one of the specified patterns.
-Examples: The pattern
-.Ic !(foo|bar)
-matches all strings except
-.Dq foo
-and
-.Dq bar ;
-the pattern
-.Ic !(*)
-matches no strings; the pattern
-.Ic !(?)*\&
-matches all strings (think about it).
-.El
-.Pp
-Note that
-.Nm pdksh
-currently never matches
-.Sq \&.
-and
-.Sq .. ,
-but the original
-.Xr ksh ,
-Bourne
-.Xr 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
-.Pq Sq \&.
-at the start of a file name or a slash
-.Pq Sq / ,
-even if they are explicitly used in a [..] sequence; also, the names
-.Sq \&.
-and
-.Sq ..
-are never matched, even by the pattern
-.Sq .* .
-.Pp
-If the
-.Ic markdirs
-option is set, any directories that result from file name generation are marked
-with a trailing
-.Ql / .
-.Pp
-The POSIX character classes (i.e.\&
-.Pf [: Ns Ar class-name Ns :]
-inside a [..] expression) are not yet implemented.
-.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
-.Pa /dev/null ,
-and commands for which any of the following redirections have been specified:
-.Bl -tag -width Ds
-.It \*(Gt Ar file
-Standard output is redirected to
-.Ar file .
-If
-.Ar file
-does not exist, it is created; if it does exist, is a regular file, and the
-.Ic noclobber
-option is set, an error occurs; otherwise, the file is truncated.
-Note that this means the command
-.Ic cmd \*(Lt foo \*(Gt foo
-will open
-.Ar foo
-for reading and then truncate it when it opens it for writing, before
-.Ar cmd
-gets a chance to actually read
-.Ar foo .
-.It \*(Gt\*(Ba Ar file
-Same as
-.Ic \*(Gt ,
-except the file is truncated, even if the
-.Ic noclobber
-option is set.
-.It \*(Gt\*(Gt Ar file
-Same as
-.Ic \*(Gt ,
-except if
-.Ar file
-exists it 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
-.Xr open 2 ) .
-.It \*(Lt Ar file
-Standard input is redirected from
-.Ar file ,
-which is opened for reading.
-.It \*(Lt\*(Gt Ar file
-Same as
-.Ic \*(Lt ,
-except the file is opened for reading and writing.
-.It \*(Lt\*(Lt Ar marker
-After reading the command line containing this kind of redirection (called a
-.Dq here document ) ,
-the shell copies lines from the command source into a temporary file until a
-line matching
-.Ar marker
-is read.
-When the command is executed, standard input is redirected from the
-temporary file.
-If
-.Ar marker
-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
-.Pq Sq \e
-escapes for
-.Ql $ ,
-.Ql ` ,
-.Ql \e ,
-and
-.Ql \enewline .
-If multiple here documents are used on the same command line, they are saved in
-order.
-.It \*(Lt\*(Lt- Ar marker
-Same as
-.Ic \*(Lt\*(Lt ,
-except leading tabs are stripped from lines in the here document.
-.It \*(Lt& Ar fd
-Standard input is duplicated from file descriptor
-.Ar fd .
-.Ar fd
-can be a single digit, indicating the number of an existing file descriptor;
-the letter
-.Ql p ,
-indicating the file descriptor associated with the output of the current
-co-process; or the character
-.Ql - ,
-indicating standard input is to be closed.
-.It \*(Gt& Ar fd
-Same as
-.Ic \*(Lt& ,
-except the operation is done on standard output.
-.El
-.Pp
-In any of the above redirections, the file descriptor that is redirected
-(i.e. 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 (if the shell is interactive)
-file name generation are all performed on the
-.Ar file ,
-.Ar marker ,
-and
-.Ar fd
-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 expanded 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
-.Po
-.Ic if
-statements, etc.
-.Pc ,
-any redirections must appear at the end.
-Redirections are processed after
-pipelines are created and in the order they are given, so the following
-will print an error with a line number prepended to it:
-.Pp
-.D1 $ cat /foo/bar 2\*(Gt&1 \*(Gt /dev/null \*(Ba cat -n
-.Ss Arithmetic expressions
-Integer arithmetic expressions can be used with the
-.Ic let
-command, inside $((..)) expressions, inside array references (e.g.\&
-.Ar name Ns Bq Ar expr ) ,
-as numeric arguments to the
-.Ic test
-command, and as the value of an assignment to an integer parameter.
-.Pp
-Expressions 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):
-.Pp
-Unary operators:
-.Bd -literal -offset indent
-+ - ! ~ ++ --
-.Ed
-.Pp
-Binary operators:
-.Bd -literal -offset indent
-,
-= *= /= %= += -= \*(Lt\*(Lt= \*(Gt\*(Gt= &= ^= \*(Ba=
-\*(Ba\*(Ba
-&&
-\*(Ba
-^
-&
-== !=
-\*(Lt \*(Lt= \*(Gt= \*(Gt
-\*(Lt\*(Lt \*(Gt\*(Gt
-+ -
-* / %
-.Ed
-.Pp
-Ternary operators:
-.Bd -literal -offset indent
-?: (precedence is immediately higher than assignment)
-.Ed
-.Pp
-Grouping operators:
-.Bd -literal -offset indent
-( )
-.Ed
-.Pp
-Integer constants may be specified with arbitrary bases using the notation
-.Ar base Ns # Ns Ar number ,
-where
-.Ar base
-is a decimal integer specifying the base, and
-.Ar number
-is a number in the specified base.
-Additionally,
-integers may be prefixed with
-.Sq 0X
-or
-.Sq 0x
-(specifying base 16)
-or
-.Sq 0
-(base 8)
-in all forms of arithmetic expressions,
-except as numeric arguments to the
-.Ic test
-command.
-.Pp
-The operators are evaluated as follows:
-.Bl -tag -width Ds -offset indent
-.It unary +
-Result is the argument (included for completeness).
-.It unary -
-Negation.
-.It \&!
-Logical NOT;
-the result is 1 if argument is zero, 0 if not.
-.It ~
-Arithmetic (bit-wise) NOT.
-.It ++
-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.
-.It --
-Similar to
-.Ic ++ ,
-except the parameter is decremented by 1.
-.It \&,
-Separates two arithmetic expressions; the left-hand side is evaluated first,
-then the right.
-The result is the value of the expression on the right-hand side.
-.It =
-Assignment; the variable on the left is set to the value on the right.
-.It Xo
-.No *= /= += -= \*(Lt\*(Lt=
-.No \*(Gt\*(Gt= &= ^= \*(Ba=
-.Xc
-Assignment operators.
-.Sm off
-.Aq Xo Ar var
-.Aq Ar op
-.No = Aq Ar expr
-.Xc
-.Sm on
-is the same as
-.Sm off
-.Aq Xo Ar var
-.No = Aq Ar var
-.Aq Ar op
-.Aq Ar expr ,
-.Xc
-.Sm on
-with any operator precedence in
-.Aq Ar expr
-preserved.
-For example,
-.Dq var1 *= 5 + 3
-is the same as specifying
-.Dq var1 = var1 * (5 + 3) .
-.It \*(Ba\*(Ba
-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.
-.It &&
-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.
-.It \*(Ba
-Arithmetic (bit-wise) OR.
-.It ^
-Arithmetic (bit-wise) XOR
-(exclusive-OR).
-.It &
-Arithmetic (bit-wise) AND.
-.It ==
-Equal; the result is 1 if both arguments are equal, 0 if not.
-.It !=
-Not equal; the result is 0 if both arguments are equal, 1 if not.
-.It \*(Lt
-Less than; the result is 1 if the left argument is less than the right, 0 if
-not.
-.It \*(Lt= \*(Gt= \*(Gt
-Less than or equal, greater than or equal, greater than.
-See
-.Ic \*(Lt .
-.It \*(Lt\*(Lt \*(Gt\*(Gt
-Shift left (right); the result is the left argument with its bits shifted left
-(right) by the amount given in the right argument.
-.It + - * /
-Addition, subtraction, multiplication, and division.
-.It %
-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.
-.It Xo
-.Sm off
-.Aq Ar arg1 ?
-.Aq Ar arg2 :
-.Aq Ar arg3
-.Sm on
-.Xc
-If
-.Aq Ar arg1
-is non-zero, the result is
-.Aq Ar arg2 ;
-otherwise the result is
-.Aq Ar arg3 .
-.El
-.Ss Functions
-Functions are defined using either Korn shell
-.Ic function Ar function-name
-syntax or the Bourne/POSIX shell
-.Ar function-name Ns ()
-syntax (see below for the difference between the two forms).
-Functions are like
-.Li .-scripts
-(i.e. scripts sourced using the
-.Sq \&.
-built-in)
-in that they are executed in the current environment.
-However, unlike
-.Li .-scripts ,
-shell arguments (i.e. positional parameters $1, $2, etc.)\&
-are never visible inside them.
-When the shell is determining the location of a command, functions
-are searched after special built-in commands, before regular and
-non-regular built-ins, and before the
-.Ev PATH
-is searched.
-.Pp
-An existing function may be deleted using
-.Ic unset Fl f Ar function-name .
-A list of functions can be obtained using
-.Ic typeset +f
-and the function definitions can be listed using
-.Ic typeset -f .
-The
-.Ic autoload
-command (which is an alias for
-.Ic typeset -fu )
-may be used to create undefined functions: when an undefined function is
-executed, the shell searches the path specified in the
-.Ev FPATH
-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 (i.e. the shell searches the regular built-in command table and
-.Ev PATH ) .
-Note that if a command is not found using
-.Ev PATH ,
-an attempt is made to autoload a function using
-.Ev FPATH
-(this is an undocumented feature of the original Korn shell).
-.Pp
-Functions can have two attributes,
-.Dq trace
-and
-.Dq export ,
-which can be set with
-.Ic typeset -ft
-and
-.Ic typeset -fx ,
-respectively.
-When a traced function is executed, the shell's
-.Ic xtrace
-option is turned on for the function's duration; otherwise, the
-.Ic xtrace
-option is turned off.
-The
-.Dq 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
-.Ic typeset
-command can be used inside a function to create a local parameter.
-Note that special parameters (e.g.\&
-.Ic \&$$ , $! )
-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
-.Ic return
-command; this may also be used to explicitly specify the exit status.
-.Pp
-Functions defined with the
-.Ic function
-reserved word are treated differently in the following ways from functions
-defined with the
-.Ic ()
-notation:
-.Bl -bullet
-.It
-The $0 parameter is set to the name of the function
-(Bourne-style functions leave $0 untouched).
-.It
-Parameter assignments preceding function calls are not kept in the shell
-environment (executing Bourne-style functions will keep assignments).
-.It
-.Ev OPTIND
-is saved/reset and restored on entry and exit from the function so
-.Ic getopts
-can be used properly both inside and outside the function (Bourne-style
-functions leave
-.Ev OPTIND
-untouched, so using
-.Ic getopts
-inside a function interferes with using
-.Ic getopts
-outside the function).
-.El
-.Pp
-In the future, the following differences will also be added:
-.Bl -bullet
-.It
-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.
-.It
-The EXIT trap, if set in a function, will be executed after the function
-returns.
-.El
-.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
-.Ic posix
-option
-.Pq Ic set -o posix .
-If it is on, the POSIX behaviour is followed; otherwise, it is not.
-The
-.Ic posix
-option is set automatically when the shell starts up if the environment
-contains the
-.Ev POSIXLY_CORRECT
-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
-.Ic posix
-option:
-.Bl -bullet
-.It
-Reading of
-.Ev $ENV :
-if not in
-.Ic posix
-mode, the
-.Ev ENV
-parameter is not expanded and included when the shell starts.
-.It
-Occurrences of
-.Ic \e\&"
-inside double quoted
-.Ic `..`
-command substitutions.
-In POSIX mode, the
-.Ic \e\&"
-is interpreted when the command is interpreted;
-in non-POSIX mode,
-the backslash is stripped before the command substitution is interpreted.
-For example,
-.Ic echo \&"`echo \e\&"hi\e\&"`\&"
-produces
-.Dq \&"hi\&"
-in POSIX mode,
-.Dq hi
-in non-POSIX mode.
-To avoid problems, use the
-.Ic $(...)\&
-form of command substitution.
-.It
-.Ic kill -l
-output.
-In POSIX mode, only signal names are listed (in a single line);
-in non-POSIX mode,
-signal numbers, names, and descriptions are printed (in columns).
-In the future, a new option
-.Pq Fl v No perhaps
-will be added to distinguish the two behaviours.
-.It
-.Ic fg
-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.
-.It
-.Ic getopts .
-In POSIX mode, options must start with a
-.Ql - ;
-in non-POSIX mode, options can start with either
-.Ql -
-or
-.Ql + .
-.It
-.Ic set - .
-In POSIX mode, this does not clear the
-.Ic verbose
-or
-.Ic xtrace
-options; in non-POSIX mode, it does.
-.It
-.Ic set
-exit status.
-In POSIX mode, the exit status of
-.Ic 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
-.Ic set
-command.
-For example,
-.Ic set -- `false`; echo $?\&
-prints 0 in POSIX mode, 1 in non-POSIX mode.
-This construct is used in most shell scripts that use the old
-.Xr getopt 1
-command.
-.It
-Argument expansion of the
-.Ic alias ,
-.Ic export ,
-.Ic readonly ,
-and
-.Ic typeset
-commands.
-In POSIX mode, normal argument expansion is done; in non-POSIX mode,
-field splitting, file globbing, and (normal) tilde expansion
-are turned off, while assignment tilde expansion is turned on.
-.It
-Signal specification.
-In POSIX mode, signals can be specified as digits, only
-if signal numbers match POSIX values
-(i.e. HUP=1, INT=2, QUIT=3, ABRT=6, KILL=9, ALRM=14, and TERM=15);
-in non-POSIX mode, signals can always be digits.
-.It
-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
-.Ic for
-loop uses parameter
-.Sq i
-in POSIX mode and
-.Sq j
-in non-POSIX mode:
-.Bd -literal -offset indent
-alias a='for ' i='j'
-a i in 1 2; do echo i=$i j=$j; done
-.Ed
-.Pp
-.It
-.Ic test .
-In POSIX mode, the expression
-.Sq Fl t
-(preceded by some number of
-.Sq \&!
-arguments) is always true as it is a non-zero length string;
-in non-POSIX mode, it tests if file descriptor 1 is a
-.Xr tty 4
-(i.e. the
-.Ar fd
-argument to the
-.Fl t
-test may be left out and defaults to 1).
-.El
-.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
-.Ev PATH
-parameter.
-The checks are made in the above order.
-Special built-in commands differ from other commands in that the
-.Ev PATH
-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
-.Ic posix
-option is turned off (see the
-.Ic set
-command below), some special commands are very special in that no field
-splitting, file globbing, nor tilde expansion is performed
-on arguments that look like assignments.
-Regular built-in commands are different only in that the
-.Ev PATH
-parameter is not used to find them.
-.Pp
-The original
-.Nm ksh
-and POSIX differ somewhat in which commands are considered
-special or regular:
-.Pp
-POSIX special commands
-.Pp
-.Ic \&. , \&: , break , continue ,
-.Ic eval , exec , exit , export ,
-.Ic readonly , return , set , shift ,
-.Ic trap , unset
-.Pp
-Additional
-.Nm
-special commands
-.Pp
-.Ic builtin , times , typeset
-.Pp
-Very special commands
-.Pq non-POSIX
-.Pp
-.Ic alias , readonly , set , typeset
-.Pp
-POSIX regular commands
-.Pp
-.Ic alias , bg , cd , command ,
-.Ic false , fc , fg , getopts ,
-.Ic jobs , kill , read , true ,
-.Ic umask , unalias , wait
-.Pp
-Additional
-.Nm
-regular commands
-.Pp
-.Ic \&[ , echo , let , print ,
-.Ic pwd , test , ulimit , whence
-.Pp
-In the future, the additional
-.Nm
-special and regular commands may be treated
-differently from the POSIX special and regular commands.
-.Pp
-Once the type of 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:
-.Pp
-.Bl -tag -width Ds -compact
-.It Ic \&. Ar file Op Ar arg ...
-Execute the commands in
-.Ar file
-in the current environment.
-The file is searched for in the directories of
-.Ev PATH .
-If arguments are given, the positional parameters may be used to access them
-while
-.Ar file
-is being executed.
-If no arguments are given, the positional parameters are
-those of the environment the command is used in.
-.Pp
-.It Ic \&: Op Ar ...
-The null command.
-Exit status is set to zero.
-.Pp
-.It Xo Ic alias
-.Oo Fl d \*(Ba t Oo Fl r Oc \*(Ba
-.Cm +-x Oc
-.Op Fl p
-.Op Cm +
-.Oo Ar name
-.Op Ns = Ns Ar value
-.Ar ... Oc
-.Xc
-Without arguments,
-.Ic alias
-lists all aliases.
-For any name without a value, the existing alias is listed.
-Any name with a value defines an alias (see
-.Sx Aliases
-above).
-.Pp
-When listing aliases, one of two formats is used.
-Normally, aliases are listed as
-.Ar name Ns = Ns Ar value ,
-where
-.Ar value
-is quoted.
-If options were preceded with
-.Ql + ,
-or a lone
-.Ql +
-is given on the command line, only
-.Ar name
-is printed.
-.Pp
-The
-.Fl d
-option causes directory aliases, which are used in tilde expansion, to be
-listed or set (see
-.Sx Tilde expansion
-above).
-.Pp
-If the
-.Fl p
-option is used, each alias is prefixed with the string
-.Dq alias\ \& .
-.Pp
-The
-.Fl t
-option indicates that tracked aliases are to be listed/set (values specified on
-the command line are ignored for tracked aliases).
-The
-.Fl r
-option indicates that all tracked aliases are to be reset.
-.Pp
-The
-.Fl x
-option sets
-.Pq Ic +x No clears
-the export attribute of an alias, or, if no names are given, lists the aliases
-with the export attribute (exporting an alias has no effect).
-.Pp
-.It Ic bg Op Ar job ...
-Resume the specified stopped job(s) in the background.
-If no jobs are specified,
-.Ic %+
-is assumed.
-See
-.Sx Job control
-below for more information.
-.Pp
-.It Ic break Op Ar level
-Exit the
-.Ar level Ns th
-inner-most
-.Ic for ,
-.Ic until ,
-or
-.Ic while
-loop.
-.Ar level
-defaults to 1.
-.Pp
-.It Ic builtin Ar command Op Ar arg ...
-Execute the built-in command
-.Ar command .
-.Pp
-.It Xo
-.Ic cd
-.Op Fl LP
-.Op Ar dir
-.Xc
-Set the working directory to
-.Ar dir .
-If the parameter
-.Ev CDPATH
-is set, it lists the search path for the directory containing
-.Ar dir .
-A
-.Dv NULL
-path means the current directory.
-If
-.Ar dir
-is found in any component of the
-.Ev CDPATH
-search path other than the
-.Dv NULL
-path, the name of the new working directory will be written to standard output.
-If
-.Ar dir
-is missing, the home directory
-.Ev HOME
-is used.
-If
-.Ar dir
-is
-.Ql - ,
-the previous working directory is used (see the
-.Ev OLDPWD
-parameter).
-.Pp
-If the
-.Fl L
-option (logical path) is used or if the
-.Ic physical
-option isn't set (see the
-.Ic set
-command below), references to
-.Sq ..
-in
-.Ar dir
-are relative to the path used to get to the directory.
-If the
-.Fl P
-option (physical path) is used or if the
-.Ic physical
-option is set,
-.Sq ..
-is relative to the filesystem directory tree.
-The
-.Ev PWD
-and
-.Ev OLDPWD
-parameters are updated to reflect the current and old working directory,
-respectively.
-.Pp
-.It Xo
-.Ic cd
-.Op Fl LP
-.Ar old new
-.Xc
-The string
-.Ar new
-is substituted for
-.Ar old
-in the current directory, and the shell attempts to change to the new
-directory.
-.Pp
-.It Xo
-.Ic command
-.Op Fl p
-.Ar cmd
-.Op Ar arg ...
-.Xc
-.Ar cmd
-is executed exactly as if
-.Ic command
-had not been specified, with two exceptions:
-firstly,
-.Ar cmd
-cannot be a shell function;
-and secondly, special built-in commands lose their specialness
-(i.e. redirection and utility errors do not cause the shell to
-exit, and command assignments are not permanent).
-.Pp
-If the
-.Fl p
-option is given, a default search path is used instead of the current value of
-.Ev PATH
-(the actual value of the default path is system dependent: on
-POSIX-ish systems, it is the value returned by
-.Ic getconf CS_PATH ) .
-.Pp
-.It Ic continue Op Ar level
-Jumps to the beginning of the
-.Ar level Ns th
-inner-most
-.Ic for ,
-.Ic until ,
-or
-.Ic while
-loop.
-.Ar level
-defaults to 1.
-.Pp
-.It Xo
-.Ic echo
-.Op Fl Een
-.Op Ar arg ...
-.Xc
-Prints its arguments (separated by spaces) followed by a newline, to the
-standard output.
-The newline is suppressed if any of the arguments contain the
-backslash sequence
-.Ql \ec .
-See the
-.Ic print
-command below for a list of other backslash sequences that are recognized.
-.Pp
-The options are provided for compatibility with
-.Bx
-shell scripts.
-The
-.Fl n
-option suppresses the trailing newline,
-.Fl e
-enables backslash interpretation (a no-op, since this is normally done), and
-.Fl E
-suppresses backslash interpretation.
-.Pp
-.It Ic eval Ar command ...
-The arguments are concatenated (with spaces between them) to form a single
-string which the shell then parses and executes in the current environment.
-.Pp
-.It Xo
-.Ic exec
-.Op Ar command Op Ar arg ...
-.Xc
-The command is executed without forking, replacing the shell process.
-.Pp
-If no command is given except for I/O redirection, the I/O redirection is
-permanent and the shell is
-not replaced.
-Any file descriptors which are opened or
-.Xr dup 2 Ns 'd
-in this way are made available to other executed commands (note that the Korn
-shell differs here: it does not pass on file descriptors greater than 2).
-.Pp
-.It Ic exit Op Ar status
-The shell exits with the specified exit status.
-If
-.Ar status
-is not specified, the exit status is the current value of the
-.Ic $?\&
-parameter.
-.Pp
-.It Xo
-.Ic export
-.Op Fl p
-.Op Ar parameter Ns Op = Ns Ar value
-.Xc
-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 are also assigned.
-.Pp
-If no parameters are specified, the names of all parameters with the export
-attribute are printed one per line, unless the
-.Fl p
-option is used, in which case
-.Ic export
-commands defining all exported parameters, including their values, are printed.
-.Pp
-.It Ic false
-A command that exits with a non-zero status.
-.Pp
-.It Xo
-.Ic fc
-.Cm -e - \*(Ba Fl s
-.Op Fl g
-.Op Ar old Ns = Ns Ar new
-.Op Ar prefix
-.Xc
-Re-execute the selected command (the previous command by default) after
-performing the optional substitution of
-.Ar old
-with
-.Ar new .
-If
-.Fl g
-is specified, all occurrences of
-.Ar old
-are replaced with
-.Ar new .
-The meaning of
-.Cm -e -
-and
-.Fl s
-is identical: re-execute the selected command without invoking an editor.
-This command is usually accessed with the predefined
-.Ic alias r='fc -e -' .
-.Pp
-.It Ic fg Op Ar job ...
-Resume the specified job(s) in the foreground.
-If no jobs are specified,
-.Ic %+
-is assumed.
-See
-.Sx Job control
-below for more information.
-.Pp
-.It Xo
-.Ic getopts
-.Ar optstring name
-.Op Ar arg ...
-.Xc
-Used by shell procedures to parse the specified arguments (or positional
-parameters, if no arguments are given) and to check for legal options.
-.Ar optstring
-contains the option letters that
-.Ic getopts
-is to recognize.
-If a letter is followed by a colon, the option is expected to
-have an argument.
-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.
-.Pp
-Each time
-.Ic getopts
-is invoked, it places the next option in the shell parameter
-.Ar name
-and the index of the argument to be processed by the next call to
-.Ic getopts
-in the shell parameter
-.Ev OPTIND .
-If the option was introduced with a
-.Ql + ,
-the option placed in
-.Ar name
-is prefixed with a
-.Ql + .
-When an option requires an argument,
-.Ic getopts
-places it in the shell parameter
-.Ev OPTARG .
-.Pp
-When an illegal option or a missing option argument is encountered, a question
-mark or a colon is placed in
-.Ar name
-(indicating an illegal option or missing argument, respectively) and
-.Ev OPTARG
-is set to the option character that caused the problem.
-Furthermore, if
-.Ar optstring
-does not begin with a colon, a question mark is placed in
-.Ar name ,
-.Ev OPTARG
-is unset, and an error message is printed to standard error.
-.Pp
-When the end of the options is encountered,
-.Ic getopts
-exits with a non-zero exit status.
-Options end at the first (non-option
-argument) argument that does not start with a
-.Ql - ,
-or when a
-.Ql --
-argument is encountered.
-.Pp
-Option parsing can be reset by setting
-.Ev OPTIND
-to 1 (this is done automatically whenever the shell or a shell procedure is
-invoked).
-.Pp
-Warning: Changing the value of the shell parameter
-.Ev OPTIND
-to a value other than 1, or parsing different sets of arguments without
-resetting
-.Ev OPTIND ,
-may lead to unexpected results.
-.Pp
-.It Xo
-.Ic hash
-.Op Fl r
-.Op Ar name ...
-.Xc
-Without arguments, any hashed executable command pathnames are listed.
-The
-.Fl r
-option causes all hashed commands to be removed from the hash table.
-Each
-.Ar name
-is searched as if it were a command name and added to the hash table if it is
-an executable command.
-.Pp
-.It Xo
-.Ic jobs
-.Op Fl lnp
-.Op Ar job ...
-.Xc
-Display information about the specified job(s); if no jobs are specified, all
-jobs are displayed.
-The
-.Fl n
-option causes information to be displayed only for jobs that have changed
-state since the last notification.
-If the
-.Fl l
-option is used, the process ID of each process in a job is also listed.
-The
-.Fl p
-option causes only the process group of each job to be printed.
-See
-.Sx Job control
-below for the format of
-.Ar job
-and the displayed job.
-.Pp
-.It Xo
-.Ic kill
-.Oo Fl s Ar signame \*(Ba
-.No - Ns Ar signum \*(Ba
-.No - Ns Ar signame Oc
-.No { Ar job \*(Ba pid \*(Ba pgrp No }
-.Ar ...
-.Xc
-Send the specified signal to the specified jobs, process IDs, or process
-groups.
-If no signal is specified, the
-.Dv TERM
-signal is sent.
-If a job is specified, the signal is sent to the job's process group.
-See
-.Sx Job control
-below for the format of
-.Ar job .
-.Pp
-.It Xo
-.Ic kill
-.Fl l
-.Op Ar exit-status ...
-.Xc
-Print the signal name corresponding to
-.Ar exit-status .
-If no arguments are specified, a list of all the signals, their numbers, and
-a short description of them are printed.
-.Pp
-.It Xo
-.Ic print
-.Oo Fl nrsu Ns Oo Ar n Oc \*(Ba
-.Fl R Op Fl en Oc
-.Op Ar argument ...
-.Xc
-.Ic print
-prints its arguments on the standard output, separated by spaces and
-terminated with a newline.
-The
-.Fl n
-option suppresses the newline.
-By default, certain C escapes are translated.
-These include
-.Ql \eb ,
-.Ql \ef ,
-.Ql \en ,
-.Ql \er ,
-.Ql \et ,
-.Ql \ev ,
-and
-.Ql \e0###
-.Po
-.Ql #
-is an octal digit, of which there may be 0 to 3
-.Pc .
-.Ql \ec
-is equivalent to using the
-.Fl n
-option.
-.Ql \e
-expansion may be inhibited with the
-.Fl r
-option.
-The
-.Fl s
-option prints to the history file instead of standard output; and the
-.Fl u
-option prints to file descriptor
-.Ar n
-.Po
-.Ar n
-defaults to 1 if omitted
-.Pc .
-.Pp
-The
-.Fl R
-option is used to emulate, to some degree, the
-.Bx
-.Xr echo 1
-command, which does not process
-.Ql \e
-sequences unless the
-.Fl e
-option is given.
-As above, the
-.Fl n
-option suppresses the trailing newline.
-.Pp
-.It Ic pwd Op Fl LP
-Print the present working directory.
-If the
-.Fl L
-option is used or if the
-.Ic physical
-option isn't set (see the
-.Ic set
-command below), the logical path is printed (i.e. the path used to
-.Ic cd
-to the current directory).
-If the
-.Fl P
-option (physical path) is used or if the
-.Ic physical
-option is set, the path determined from the filesystem (by following
-.Sq ..
-directories to the root directory) is printed.
-.Pp
-.It Xo
-.Ic read
-.Op Fl rsu Ns Op Ar n
-.Op Ar parameter ...
-.Xc
-Reads a line of input from the standard input, separates the line into fields
-using the
-.Ev IFS
-parameter (see
-.Sx Substitution
-above), and assigns each field to the specified parameters.
-If there are more parameters than fields, the extra parameters are set to
-.Dv 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
-.Ev REPLY
-parameter is used.
-If the input line ends in a backslash and the
-.Fl r
-option was not used, the backslash and the newline are stripped and more input
-is read.
-If no input is read,
-.Ic read
-exits with a non-zero status.
-.Pp
-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
-.Xr tty 4
-(e.g.\&
-.Ic read nfoo?'number of foos: ' ) .
-.Pp
-The
-.Fl u Ns Ar n
-option causes input to be read from file descriptor
-.Ar n
-.Pf ( Ar n
-defaults to 0 if omitted).
-If the
-.Fl s
-option is used, input is saved to the history file.
-.Pp
-.It Xo
-.Ic readonly
-.Op Fl p
-.Oo Ar parameter
-.Op Ns = Ns Ar value
-.Ar ... Oc
-.Xc
-Sets the read-only attribute of the named parameters.
-If values are given,
-parameters are set to them before setting the attribute.
-Once a parameter is
-made read-only, it cannot be unset and its value cannot be changed.
-.Pp
-If no parameters are specified, the names of all parameters with the read-only
-attribute are printed one per line, unless the
-.Fl p
-option is used, in which case
-.Ic readonly
-commands defining all read-only parameters, including their values, are
-printed.
-.Pp
-.It Ic return Op Ar status
-Returns from a function or
-.Ic .\&
-script, with exit status
-.Ar status .
-If no
-.Ar status
-is given, the exit status of the last executed command is used.
-If used outside of a function or
-.Ic .\&
-script, it has the same effect as
-.Ic exit .
-Note that
-.Nm pdksh
-treats both profile and
-.Ev ENV
-files as
-.Ic .\&
-scripts, while the original Korn shell only treats profiles as
-.Ic .\&
-scripts.
-.Pp
-.It Xo
-.Ic set Op Ic +-abCefhkmnpsuvXx
-.Op Ic +-o Ar option
-.Op Ic +-A Ar name
-.Op Fl -
-.Op Ar arg ...
-.Xc
-The
-.Ic set
-command can be used to set
-.Pq Ic -
-or clear
-.Pq Ic +
-shell options, set the positional parameters, or set an array parameter.
-Options can be changed using the
-.Cm +-o Ar option
-syntax, where
-.Ar option
-is the long name of an option, or using the
-.Cm +- Ns Ar letter
-syntax, where
-.Ar letter
-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:
-.Bl -tag -width 15n
-.It Fl A Ar name
-Sets the elements of the array parameter
-.Ar name
-to
-.Ar arg ...
-If
-.Fl A
-is used, the array is reset (i.e. emptied) first; if
-.Ic +A
-is used, the first N elements are set (where N is the number of arguments);
-the rest are left untouched.
-.It Fl a \*(Ba Ic allexport
-All new parameters are created with the export attribute.
-.It Fl b \*(Ba Ic notify
-Print job notification messages asynchronously, instead of just before the
-prompt.
-Only used if job control is enabled
-.Pq Fl m .
-.It Fl C \*(Ba Ic noclobber
-Prevent \*(Gt redirection from overwriting existing files.
-Instead, \*(Gt\*(Ba must be used to force an overwrite.
-.It Fl e \*(Ba Ic errexit
-Exit (after executing the
-.Dv ERR
-trap) as soon as an error occurs or a command fails (i.e. exits with a
-non-zero status).
-This does not apply to commands whose exit status is
-explicitly tested by a shell construct such as
-.Ic if ,
-.Ic until ,
-.Ic while ,
-.Ic && ,
-or
-.Ic ||
-statements.
-.It Fl f \*(Ba Ic noglob
-Do not expand file name patterns.
-.It Fl h \*(Ba Ic trackall
-Create tracked aliases for all executed commands (see
-.Sx Aliases
-above).
-Enabled by default for non-interactive shells.
-.It Fl k \*(Ba Ic keyword
-Parameter assignments are recognized anywhere in a command.
-.It Fl m \*(Ba Ic monitor
-Enable job control (default for interactive shells).
-.It Fl n \*(Ba Ic noexec
-Do not execute any commands.
-Useful for checking the syntax of scripts
-(ignored if interactive).
-.It Fl p \*(Ba Ic privileged
-The shell is a privileged shell.
-It is set automatically if, when the shell starts,
-the real UID or GID does not match
-the effective UID (EUID) or GID (EGID), respectively.
-See above for a description of what this means.
-.It Fl s \*(Ba Ic stdin
-If used when the shell is invoked, commands are read from standard input.
-Set automatically if the shell is invoked with no arguments.
-.Pp
-When
-.Fl s
-is used with the
-.Ic set
-command it causes the specified arguments to be sorted before assigning them to
-the positional parameters (or to array
-.Ar name ,
-if
-.Fl A
-is used).
-.It Fl u \*(Ba Ic nounset
-Referencing of an unset parameter is treated as an error, unless one of the
-.Ql - ,
-.Ql + ,
-or
-.Ql =
-modifiers is used.
-.It Fl v \*(Ba Ic verbose
-Write shell input to standard error as it is read.
-.It Fl X \*(Ba Ic markdirs
-Mark directories with a trailing
-.Ql /
-during file name generation.
-.It Fl x \*(Ba Ic xtrace
-Print commands and parameter assignments when they are executed, preceded by
-the value of
-.Ev PS4 .
-.It Ic bgnice
-Background jobs are run with lower priority.
-.It Ic ignoreeof
-The shell will not exit when end-of-file is read;
-.Ic exit
-must be used.
-.It Ic interactive
-The shell is an interactive shell.
-This option can only be used when the shell is invoked.
-See above for a description of what this means.
-.It Ic login
-The shell is a login shell.
-This option can only be used when the shell is invoked.
-See above for a description of what this means.
-.It Ic nohup
-Do not kill running jobs with a
-.Dv SIGHUP
-signal when a login shell exits.
-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
-.Dv SIGHUP
-signal).
-.It Ic nolog
-No effect.
-In the original Korn shell, this prevents function definitions from
-being stored in the history file.
-.It Ic physical
-Causes the
-.Ic cd
-and
-.Ic pwd
-commands to use
-.Dq physical
-(i.e. the filesystem's)
-.Sq ..
-directories instead of
-.Dq logical
-directories (i.e. the shell handles
-.Sq .. ,
-which allows the user to be oblivious of symbolic links to directories).
-Clear by default.
-Note that setting this option does not affect the current value of the
-.Ev PWD
-parameter; only the
-.Ic cd
-command changes
-.Ev PWD .
-See the
-.Ic cd
-and
-.Ic pwd
-commands above for more details.
-.It Ic posix
-Enable POSIX mode.
-See
-.Sx POSIX mode
-above.
-.It Ic restricted
-The shell is a restricted shell.
-This option can only be used when the shell is invoked.
-See above for a description of what this means.
-.It Ic vi
-Enable
-.Xr vi 1 Ns -like
-command-line editing (interactive shells only).
-.It Ic vi-esccomplete
-In vi command-line editing, do command and file name completion when escape
-(^[) is entered in command mode.
-.It Ic vi-show8
-Prefix characters with the eighth bit set with
-.Sq M- .
-If this option is not set, characters in the range 128\-160 are printed as is,
-which may cause problems.
-.It Ic vi-tabcomplete
-In vi command-line editing, do command and file name completion when tab (^I)
-is entered in insert mode.
-.It Ic viraw
-No effect.
-In the original Korn shell, unless
-.Ic viraw
-was set, the vi command-line mode would let the
-.Xr tty 4
-driver do the work until ESC (^[) was entered.
-.Nm pdksh
-is always in viraw mode.
-.El
-.Pp
-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
-.Sq $- .
-.Ic set Fl o
-with no option name will list all the options and whether each is on or off;
-.Ic set +o
-will print the long names of all options that are currently on.
-.Pp
-Remaining arguments, if any, are positional parameters and are assigned, in
-order, to the positional parameters (i.e. $1, $2, etc.).
-If options end with
-.Ql --
-and there are no remaining arguments, all positional parameters are cleared.
-If no options or arguments are given, the values of all names are printed.
-For unknown historical reasons, a lone
-.Ql -
-option is treated specially \- it clears both the
-.Fl x
-and
-.Fl v
-options.
-.Pp
-.It Ic shift Op Ar number
-The positional parameters
-.Ar number Ns +1 ,
-.Ar number Ns +2 ,
-etc. are renamed to
-.Sq 1 ,
-.Sq 2 ,
-etc.
-.Ar number
-defaults to 1.
-.Pp
-.It Ic test Ar expression
-.It Ic \&[ Ar expression Ic \&]
-.Ic test
-evaluates the
-.Ar expression
-and returns zero status if true, 1 if false, or greater than 1 if there
-was an error.
-It is normally used as the condition command of
-.Ic if
-and
-.Ic while
-statements.
-Symbolic links are followed for all
-.Ar file
-expressions except
-.Fl h
-and
-.Fl L .
-.Pp
-The following basic expressions are available:
-.Bl -tag -width 17n
-.It Fl a Ar file
-.Ar file
-exists.
-.It Fl b Ar file
-.Ar file
-is a block special device.
-.It Fl c Ar file
-.Ar file
-is a character special device.
-.It Fl d Ar file
-.Ar file
-is a directory.
-.It Fl e Ar file
-.Ar file
-exists.
-.It Fl f Ar file
-.Ar file
-is a regular file.
-.It Fl G Ar file
-.Ar file Ns 's
-group is the shell's effective group ID.
-.It Fl g Ar file
-.Ar file Ns 's
-mode has the setgid bit set.
-.It Fl h Ar file
-.Ar file
-is a symbolic link.
-.It Fl k Ar file
-.Ar file Ns 's
-mode has the
-.Xr sticky 8
-bit set.
-.It Fl L Ar file
-.Ar file
-is a symbolic link.
-.It Fl O Ar file
-.Ar file Ns 's
-owner is the shell's effective user ID.
-.It Fl o Ar option
-Shell
-.Ar option
-is set (see the
-.Ic set
-command above for a list of options).
-As a non-standard extension, if the option starts with a
-.Ql \&! ,
-the test is negated; the test always fails if
-.Ar option
-doesn't exist (so [ -o foo -o -o !foo ] returns true if and only if option
-.Ar foo
-exists).
-.It Fl p Ar file
-.Ar file
-is a named pipe.
-.It Fl r Ar file
-.Ar file
-exists and is readable.
-.It Fl S Ar file
-.Ar file
-is a
-.Xr unix 4 Ns -domain
-socket.
-.It Fl s Ar file
-.Ar file
-is not empty.
-.It Fl t Op Ar fd
-File descriptor
-.Ar fd
-is a
-.Xr tty 4
-device.
-If the
-.Ic posix
-option is not set,
-.Ar fd
-may be left out, in which case it is taken to be 1 (the behaviour differs due
-to the special POSIX rules described above).
-.It Fl u Ar file
-.Ar file Ns 's
-mode has the setuid bit set.
-.It Fl w Ar file
-.Ar file
-exists and is writable.
-.It Fl x Ar file
-.Ar file
-exists and is executable.
-.It Ar file1 Fl nt Ar file2
-.Ar file1
-is newer than
-.Ar file2 .
-.It Ar file1 Fl ot Ar file2
-.Ar file1
-is older than
-.Ar file2 .
-.It Ar file1 Fl ef Ar file2
-.Ar file1
-is the same file as
-.Ar file2 .
-.It Ar string
-.Ar string
-has non-zero length.
-.It Fl n Ar string
-.Ar string
-is not empty.
-.It Fl z Ar string
-.Ar string
-is empty.
-.It Ar string No = Ar string
-Strings are equal.
-.It Ar string No != Ar string
-Strings are not equal.
-.It Ar number Fl eq Ar number
-Numbers compare equal.
-.It Ar number Fl ne Ar number
-Numbers compare not equal.
-.It Ar number Fl ge Ar number
-Numbers compare greater than or equal.
-.It Ar number Fl gt Ar number
-Numbers compare greater than.
-.It Ar number Fl le Ar number
-Numbers compare less than or equal.
-.It Ar number Fl \&lt Ar number
-Numbers compare less than.
-.El
-.Pp
-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):
-.Bd -literal -offset indent
-expr -o expr		Logical OR.
-expr -a expr		Logical AND.
-! expr			Logical NOT.
-( expr )		Grouping.
-.Ed
-.Pp
-On operating systems not supporting
-.Pa /dev/fd/ Ns Ar n
-devices (where
-.Ar n
-is a file descriptor number), the
-.Ic test
-command will attempt to fake it for all tests that operate on files (except the
-.Fl e
-test).
-For example,
-[ -w /dev/fd/2 ] tests if file descriptor 2 is writable.
-.Pp
-Note that some special rules are applied (courtesy of POSIX)
-if the number of
-arguments to
-.Ic test
-or
-.Ic \&[ ... \&]
-is less than five: if leading
-.Ql \&!
-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
-.Ql \&!
-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 the first argument is a unary operator, including an unstripped
-.Ql \&! ) .
-.Pp
-.Sy Note :
-A common mistake is to use
-.Dq if \&[ $foo = bar \&] ,
-which fails if parameter
-.Dq foo
-is
-.Dv NULL
-or unset, if it has embedded spaces (i.e.\&
-.Ev IFS
-characters), or if it is a unary operator like
-.Sq \&!
-or
-.Sq Fl n .
-Use tests like
-.Dq if \&[ \&"X$foo\&" = Xbar \&]
-instead.
-.Pp
-.It Ic times
-Print the accumulated user and system times used both by the shell
-and by processes that the shell started which have exited.
-The format of the output is:
-.Bd -literal -offset indent
-0m0.00s 0m0.00s
-0m0.00s 0m0.00s
-.Ed
-.Pp
-.It Ic trap Op Ar handler signal ...
-Sets a trap handler that is to be executed when any of the specified signals are
-received.
-.Ar handler
-is either a
-.Dv NULL
-string, indicating the signals are to be ignored, a minus sign
-.Pq Sq - ,
-indicating that the default action is to be taken for the signals (see
-.Xr signal 3 ) ,
-or a string containing shell commands to be evaluated and executed at the first
-opportunity (i.e. when the current command completes, or before printing the
-next
-.Ev PS1
-prompt) after receipt of one of the signals.
-.Ar signal
-is the name of a signal (e.g.\&
-.Dv PIPE
-or
-.Dv ALRM )
-or the number of the signal (see the
-.Ic kill -l
-command above).
-.Pp
-There are two special signals:
-.Dv EXIT
-(also known as 0), which is executed when the shell is about to exit, and
-.Dv ERR ,
-which is executed after an error occurs (an error is something that would cause
-the shell to exit if the
-.Fl e
-or
-.Ic errexit
-option were set \- see the
-.Ic set
-command above).
-.Dv EXIT
-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.
-.Pp
-With no arguments,
-.Ic trap
-lists, as a series of
-.Ic trap
-commands, the current state of the traps that have been set since the shell
-started.
-Note that the output of
-.Ic trap
-cannot be usefully piped to another process (an artifact of the fact that
-traps are cleared when subprocesses are created).
-.Pp
-The original Korn shell's
-.Dv DEBUG
-trap and the handling of
-.Dv ERR
-and
-.Dv EXIT
-traps in functions are not yet implemented.
-.Pp
-.It Ic true
-A command that exits with a zero value.
-.Pp
-.It Xo
-.Ic typeset
-.Oo Op Ic +-lprtUux
-.Op Fl L Ns Op Ar n
-.Op Fl R Ns Op Ar n
-.Op Fl Z Ns Op Ar n
-.Op Fl i Ns Op Ar n
-.No \*(Ba Fl f Op Fl tux Oc
-.Oo Ar name
-.Op Ns = Ns Ar value
-.Ar ... Oc
-.Xc
-Display or set parameter attributes.
-With no
-.Ar name
-arguments, parameter attributes are displayed; if no options are used, the
-current attributes of all parameters are printed as
-.Ic typeset
-commands; if an option is given (or
-.Ql -
-with no option letter), all parameters and their values with the specified
-attributes are printed; if options are introduced with
-.Ql + ,
-parameter values are not printed.
-.Pp
-If
-.Ar name
-arguments are given, the attributes of the named parameters are set
-.Pq Ic -
-or cleared
-.Pq Ic + .
-Values for parameters may optionally be specified.
-If
-.Ic typeset
-is used inside a function, any newly created parameters are local to the
-function.
-.Pp
-When
-.Fl f
-is used,
-.Ic typeset
-operates on the attributes of functions.
-As with parameters, if no
-.Ar name
-arguments are given,
-functions are listed with their values (i.e. definitions) unless
-options are introduced with
-.Ql + ,
-in which case only the function names are reported.
-.Bl -tag -width Ds
-.It Fl f
-Function mode.
-Display or set functions and their attributes, instead of parameters.
-.It Fl i Ns Op Ar n
-Integer attribute.
-.Ar n
-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.
-.It Fl L Ns Op Ar n
-Left justify attribute.
-.Ar n
-specifies the field width.
-If
-.Ar n
-is not specified, the current width of a parameter (or the width of its first
-assigned value) is used.
-Leading whitespace (and zeros, if used with the
-.Fl Z
-option) is stripped.
-If necessary, values are either truncated or space padded
-to fit the field width.
-.It Fl l
-Lower case attribute.
-All upper case characters in values are converted to lower case.
-(In the original Korn shell, this parameter meant
-.Dq long integer
-when used with the
-.Fl i
-option.)
-.It Fl p
-Print complete
-.Ic typeset
-commands that can be used to re-create the attributes (but not the values) of
-parameters.
-This is the default action (option exists for ksh93 compatibility).
-.It Fl R Ns Op Ar n
-Right justify attribute.
-.Ar n
-specifies the field width.
-If
-.Ar n
-is not specified, the current width of a parameter (or the width of its first
-assigned value) is used.
-Trailing whitespace is stripped.
-If necessary, values are either stripped of leading characters or space
-padded to make them fit the field width.
-.It Fl r
-Read-only attribute.
-Parameters with this attribute may not be assigned to or unset.
-Once this attribute is set, it cannot be turned off.
-.It Fl t
-Tag attribute.
-Has no meaning to the shell; provided for application use.
-.Pp
-For functions,
-.Fl t
-is the trace attribute.
-When functions with the trace attribute are executed, the
-.Ic xtrace
-.Pq Fl x
-shell option is temporarily turned on.
-.It Fl U
-Unsigned integer attribute.
-Integers are printed as unsigned values (only
-useful when combined with the
-.Fl i
-option).
-This option is not in the original Korn shell.
-.It Fl u
-Upper case attribute.
-All lower case characters in values are converted to upper case.
-(In the original Korn shell, this parameter meant
-.Dq unsigned integer
-when used with the
-.Fl i
-option, which meant upper case letters would never be used for bases greater
-than 10.
-See the
-.Fl U
-option.)
-.Pp
-For functions,
-.Fl u
-is the undefined attribute.
-See
-.Sx Functions
-above for the implications of this.
-.It Fl x
-Export attribute.
-Parameters (or functions) are placed in the environment of
-any executed commands.
-Exported functions are not yet implemented.
-.It Fl Z Ns Op Ar n
-Zero fill attribute.
-If not combined with
-.Fl L ,
-this is the same as
-.Fl R ,
-except zero padding is used instead of space padding.
-.El
-.Pp
-.It Xo
-.Ic ulimit
-.Op Fl acdfHlmnpSst
-.Op Ar value
-.Xc
-Display or set process limits.
-If no options are used, the file size limit
-.Pq Fl f
-is assumed.
-.Ar value ,
-if specified, may be either an arithmetic expression or the word
-.Dq unlimited .
-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
-.Fl f
-limit.
-.Bl -tag -width 5n
-.It Fl a
-Display all limits; unless
-.Fl H
-is used, soft limits are displayed.
-.It Fl c Ar n
-Impose a size limit of
-.Ar n
-blocks on the size of core dumps.
-.It Fl d Ar n
-Impose a size limit of
-.Ar n
-kilobytes on the size of the data area.
-.It Fl f Ar n
-Impose a size limit of
-.Ar n
-blocks on files written by the shell and its child processes (files of any
-size may be read).
-.It Fl H
-Set the hard limit only (the default is to set both hard and soft limits).
-.It Fl l Ar n
-Impose a limit of
-.Ar n
-kilobytes on the amount of locked (wired) physical memory.
-.It Fl m Ar n
-Impose a limit of
-.Ar n
-kilobytes on the amount of physical memory used.
-.It Fl n Ar n
-Impose a limit of
-.Ar n
-file descriptors that can be open at once.
-.It Fl p Ar n
-Impose a limit of
-.Ar n
-processes that can be run by the user at any one time.
-.It Fl S
-Set the soft limit only (the default is to set both hard and soft limits).
-.It Fl s Ar n
-Impose a size limit of
-.Ar n
-kilobytes on the size of the stack area.
-.It Fl t Ar n
-Impose a time limit of
-.Ar n
-CPU seconds spent in user mode to be used by each process.
-.\".It Fl v Ar n
-.\"Impose a limit of
-.\".Ar n
-.\"kilobytes on the amount of virtual memory used.
-.El
-.Pp
-As far as
-.Ic ulimit
-is concerned, a block is 512 bytes.
-.Pp
-.It Xo
-.Ic umask
-.Op Fl S
-.Op Ar mask
-.Xc
-Display or set the file permission creation mask, or umask (see
-.Xr umask 2 ) .
-If the
-.Fl S
-option is used, the mask displayed or set is symbolic; otherwise, it is an
-octal number.
-.Pp
-Symbolic masks are like those used by
-.Xr chmod 1 .
-When 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).
-For example,
-.Dq ug=rwx,o=
-sets the mask so files will not be readable, writable, or executable by
-.Dq others ,
-and is equivalent (on most systems) to the octal mask
-.Dq 007 .
-.Pp
-.It Xo
-.Ic unalias
-.Op Fl adt
-.Op Ar name ...
-.Xc
-The aliases for the given names are removed.
-If the
-.Fl a
-option is used, all aliases are removed.
-If the
-.Fl t
-or
-.Fl d
-options are used, the indicated operations are carried out on tracked or
-directory aliases, respectively.
-.Pp
-.It Xo
-.Ic unset
-.Op Fl fv
-.Ar parameter ...
-.Xc
-Unset the named parameters
-.Po
-.Fl v ,
-the default
-.Pc
-or functions
-.Pq Fl f .
-The exit status is non-zero if any of the parameters were already unset, zero
-otherwise.
-.Pp
-.It Ic wait Op Ar job ...
-Wait for the specified job(s) to finish.
-The exit status of
-.Ic 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
-.Ic kill -l Ar exit-status
-above); if the last specified job can't be found (because it never existed, or
-had already finished), the exit status of
-.Ic wait
-is 127.
-See
-.Sx Job control
-below for the format of
-.Ar job .
-.Ic wait
-will return if a signal for which a trap has been set is received, or if a
-.Dv SIGHUP ,
-.Dv SIGINT ,
-or
-.Dv SIGQUIT
-signal is received.
-.Pp
-If no jobs are specified,
-.Ic wait
-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).
-.Pp
-.It Xo
-.Ic whence
-.Op Fl pv
-.Op Ar name ...
-.Xc
-For each
-.Ar name ,
-the type of command is listed (reserved word, built-in, alias,
-function, tracked alias, or executable).
-If the
-.Fl p
-option is used, a path search is performed even if
-.Ar name
-is a reserved word, alias, etc.
-Without the
-.Fl v
-option,
-.Ic whence
-is similar to
-.Ic command Fl v
-except that
-.Ic whence
-will find reserved words and won't print aliases as alias commands.
-With the
-.Fl v
-option,
-.Ic whence
-is the same as
-.Ic command Fl V .
-Note that for
-.Ic whence ,
-the
-.Fl p
-option does not affect the search path used, as it does for
-.Ic command .
-If the type of one or more of the names could not be determined, the exit
-status is non-zero.
-.El
-.Ss Job control
-Job control refers to the shell's ability to monitor and control jobs, 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 (i.e.\&
-asynchronous) jobs that currently exist; this information can be displayed
-using the
-.Ic jobs
-commands.
-If job control is fully enabled (using
-.Ic set -m
-or
-.Ic set -o monitor ) ,
-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
-.Ic fg
-and
-.Ic bg
-commands, and the state of the terminal is saved or restored when a foreground
-job is stopped or restarted, respectively.
-.Pp
-Note that only commands that create processes (e.g. asynchronous commands,
-subshell commands, and non-built-in, non-function commands) can be stopped;
-commands like
-.Ic read
-cannot be.
-.Pp
-When a job is created, it is assigned a job number.
-For interactive shells, this number is printed inside
-.Dq [..] ,
-followed by the process IDs of the processes in the job when an asynchronous
-command is run.
-A job may be referred to in the
-.Ic bg ,
-.Ic fg ,
-.Ic jobs ,
-.Ic kill ,
-and
-.Ic wait
-commands either by the process ID of the last process in the command pipeline
-(as stored in the
-.Ic $!\&
-parameter) or by prefixing the job number with a percent
-sign
-.Pq Sq % .
-Other percent sequences can also be used to refer to jobs:
-.Bl -tag -width "%+ | %% | %XX"
-.It %+ \*(Ba %% \*(Ba %
-The most recently stopped job, or, if there are no stopped jobs, the oldest
-running job.
-.It %-
-The job that would be the
-.Ic %+
-job if the latter did not exist.
-.It % Ns Ar n
-The job with job number
-.Ar n .
-.It %? Ns Ar string
-The job with its command containing the string
-.Ar string
-(an error occurs if multiple jobs are matched).
-.It % Ns Ar string
-The job with its command starting with the string
-.Ar string
-(an error occurs if multiple jobs are matched).
-.El
-.Pp
-When a job changes state (e.g. a background job finishes or foreground job is
-stopped), the shell prints the following status information:
-.Pp
-.D1 [ Ns Ar number ] Ar flag status command
-.Pp
-where...
-.Bl -tag -width "command"
-.It Ar number
-is the job number of the job;
-.It Ar flag
-is the
-.Ql +
-or
-.Ql -
-character if the job is the
-.Ic %+
-or
-.Ic %-
-job, respectively, or space if it is neither;
-.It Ar status
-indicates the current state of the job and can be:
-.Bl -tag -width "RunningXX"
-.It Done Op Ar number
-The job exited.
-.Ar number
-is the exit status of the job, which is omitted if the status is zero.
-.It Running
-The job has neither stopped nor exited (note that running does not necessarily
-mean consuming CPU time \-
-the process could be blocked waiting for some event).
-.It Stopped Op Ar signal
-The job was stopped by the indicated
-.Ar signal
-(if no signal is given, the job was stopped by
-.Dv SIGTSTP ) .
-.It Ar signal-description Op Dq core dumped
-The job was killed by a signal (e.g. memory fault, hangup); use
-.Ic kill -l
-for a list of signal descriptions.
-The
-.Dq core dumped
-message indicates the process created a core file.
-.El
-.It Ar command
-is the command that created the process.
-If there are multiple processes in
-the job, each process will have a line showing its
-.Ar command
-and possibly its
-.Ar status ,
-if it is different from the status of the previous process.
-.El
-.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
-.Dv SIGHUP
-signal and the shell exits.
-Similarly, if the
-.Ic nohup
-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
-.Dv SIGHUP
-signal and the shell exits.
-.Sh FILES
-.Bl -tag -width "/etc/suid_profileXX" -compact
-.It Pa ~/.profile
-User's login profile.
-.It Pa /etc/profile
-System login profile.
-.It Pa /etc/suid_profile
-Privileged shell profile.
-.It Pa /etc/shells
-Shell database.
-.El
-.Sh SEE ALSO
-.Xr csh 1 ,
-.Xr ed 1 ,
-.Xr ksh 1 ,
-.Xr mg 1 ,
-.Xr stty 1 ,
-.Xr vi 1 ,
-.Xr shells 5 ,
-.Xr environ 7 ,
-.Xr script 7
-.Rs
-.%A Morris Bolsky
-.%A David Korn
-.%T "The KornShell Command and Programming Language"
-.%D 1983
-.%O "ISBN 0-13-516972-0"
-.Re
-.Rs
-.%A Stephen G. Kochan
-.%A Patrick H. Wood
-.%T "UNIX Shell Programming"
-.%O "Hayden"
-.Re
-.Rs
-.%A "IEEE Inc."
-.%T "IEEE Standard for Information Technology \- Portable Operating " \
-    "System Interface (POSIX) \- Part 2: Shell and Utilities"
-.%D 1993
-.%O "ISBN 1-55937-266-9"
-.Re
-.Sh NOTES
-.Nm
-is implemented as a run-time option of
-.Nm pdksh ,
-with only those
-.Nm
-features whose syntax or semantics are incompatible with a traditional Bourne
-shell disabled.
-Since this leaves some
-.Nm
-extensions exposed, caution should be used where backwards compatibility with
-traditional Bourne or POSIX compliant shells is an issue.
-.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 of
-.Nm pdksh
-was created by Eric Gisin, and it was subsequently maintained by John R.\&
-MacMillan (change!john at sq.sq.com), Simon J. Gerraty (sjg at zen.void.oz.au),
-and Michael Rendell (michael at cs.mun.ca).
-The
-.Pa CONTRIBUTORS
-file in the source distribution contains a more complete list of people and
-their part in the shell's development.
-.\" .Sh BUGS
-.\" Any bugs in
-.\" .Nm pdksh
-.\" should be reported to pdksh at cs.mun.ca.
-.\" Please include the version of
-.\" .Nm pdksh
-.\" .Po
-.\" .Ic echo $KSH_VERSION
-.\" shows it
-.\" .Pc ,
-.\" 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 be
-.\" helpful: options you are using (both
-.\" .Pa options.h
-.\" and
-.\" .Ic set Fl o Ic options )
-.\" and a copy of your
-.\" .Pa config.h
-.\" (the file generated by the
-.\" .Pa configure
-.\" script).
-.\" New versions of
-.\" .Nm pdksh
-.\" can be obtained from ftp://ftp.cs.mun.ca/pub/pdksh.
-.\" .Pp
-.\" BTW, the most frequently reported bug is:
-.\" .Bd -literal -offset indent
-.\" $ echo hi | read a; echo $a   # Does not print hi
-.\" .Ed
-.\" .Pp
-.\" I'm aware of this and there is no need to report it.
--- bin/ksh/version.c
+++ /dev/null
@@ -1,11 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/version.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: version.c,v 1.12 1999/07/14 13:37:24 millert Exp $	*/
-
-/*
- * value of $KSH_VERSION (or $SH_VERSION)
- */
-
-#include "sh.h"
-
-const char ksh_version [] =
-	"@(#)PD KSH v5.2.14 99/07/13.2";
--- bin/ksh/shf.c
+++ /dev/null
@@ -1,1156 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/shf.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: shf.c,v 1.15 2006/04/02 00:48:33 deraadt Exp $	*/
-
-/*
- *  Shell file I/O routines
- */
-
-#include "sh.h"
-#include <sys/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(struct shf *);
-static int	shf_emptybuf(struct shf *, int);
-
-/* 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(const char *name, int oflags, int mode, int sflags)
-{
-	struct shf *shf;
-	int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
-	int fd;
-
-	/* Done before open so if alloca fails, fd won't be lost. */
-	shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP);
-	shf->areap = ATEMP;
-	shf->buf = (unsigned char *) &shf[1];
-	shf->bsize = bsize;
-	shf->flags = SHF_ALLOCS;
-	/* Rest filled in by reopen. */
-
-	fd = open(name, oflags, mode);
-	if (fd < 0) {
-		afree(shf, shf->areap);
-		return NULL;
-	}
-	if ((sflags & SHF_MAPHI) && fd < FDBASE) {
-		int nfd;
-
-		nfd = fcntl(fd, F_DUPFD, FDBASE);
-		close(fd);
-		if (nfd < 0) {
-			afree(shf, shf->areap);
-			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_reopen(fd, sflags, shf);
-}
-
-/* Set up the shf structure for a file descriptor.  Doesn't fail. */
-struct shf *
-shf_fdopen(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)
-		fcntl(fd, F_SETFD, FD_CLOEXEC);
-	return shf;
-}
-
-/* Set up an existing shf (and buffer) to use the given fd */
-struct shf *
-shf_reopen(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)
-		fcntl(fd, F_SETFD, FD_CLOEXEC);
-	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(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(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(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(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;
-}
-
-/* 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(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, SEEK_CUR);
-			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(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->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(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;
-}
-
-/* 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(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(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(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(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(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(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(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);
-
-	/* Don't buffer if buffer is empty and we're writting a large amount. */
-	if ((ncopy = shf->wnleft) &&
-	    (shf->wp != shf->buf || nbytes < 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
-shf_fprintf(struct shf *shf, const char *fmt, ...)
-{
-	va_list args;
-	int n;
-
-	va_start(args, fmt);
-	n = shf_vfprintf(shf, fmt, args);
-	va_end(args);
-
-	return n;
-}
-
-int
-shf_snprintf(char *buf, int bsize, const char *fmt, ...)
-{
-	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);
-	va_start(args, fmt);
-	n = shf_vfprintf(&shf, fmt, args);
-	va_end(args);
-	shf_sclose(&shf); /* null terminates */
-	return n;
-}
-
-char *
-shf_smprintf(const char *fmt, ...)
-{
-	struct shf shf;
-	va_list args;
-
-	shf_sopen((char *) 0, 0, SHF_WR|SHF_DYNAMIC, &shf);
-	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.  Assumes 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(double d)
-{
-	double		i;
-
-	return d - modf(d, &i) + (d < 0 ? -1 : 1);
-}
-#endif /* FP */
-
-int
-shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
-{
-	char		c, *s;
-	int		tmp = 0;
-	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 restriction 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 probably 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
-			 *  approximation 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;
-}
--- bin/ksh/var.c
+++ /dev/null
@@ -1,1205 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/var.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: var.c,v 1.30 2006/05/21 18:40:39 otto Exp $	*/
-
-#include "sh.h"
-#include <time.h>
-#include "ksh_limval.h"
-#include <sys/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(struct tbl *, const char *);
-static void	export(struct tbl *, const char *);
-static int	special(const char *);
-static void	unspecial(const char *);
-static void	getspec(struct tbl *);
-static void	setspec(struct tbl *);
-static void	unsetspec(struct tbl *);
-static struct tbl *arraysearch(struct tbl *, int);
-
-/*
- * create a new block for function calls and simple commands
- * assume caller has allocated and set up e->loc
- */
-void
-newblock(void)
-{
-	struct block *l;
-	static char *const empty[] = {null};
-
-	l = (struct block *) alloc(sizeof(struct block), ATEMP);
-	l->flags = 0;
-	ainit(&l->area); /* todo: could use e->area (l->area => l->areap) */
-	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;
-	ktinit(&l->vars, &l->area, 0);
-	ktinit(&l->funs, &l->area, 0);
-	l->next = e->loc;
-	e->loc = l;
-}
-
-/*
- * pop a block handling special variables
- */
-void
-popblock(void)
-{
-	struct block *l = e->loc;
-	struct tbl *vp, **vpp = l->vars.tbls, *vq;
-	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);
-		}
-	if (l->flags & BF_DOGETOPTS)
-		user_opt = l->getopts_state;
-	afreeall(&l->area);
-	afree(l, ATEMP);
-}
-
-/* called by main() to initialize variable data structures */
-void
-initvar(void)
-{
-	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 */
-		{ "MAIL",		V_MAIL },
-		{ "MAILCHECK",		V_MAILCHECK },
-		{ "MAILPATH",		V_MAILPATH },
-		{ "RANDOM",		V_RANDOM },
-		{ "SECONDS",		V_SECONDS },
-		{ "TMOUT",		V_TMOUT },
-		{ "LINENO",		V_LINENO },
-		{ (char *) 0,	0 }
-	};
-	int i;
-	struct tbl *tp;
-
-	ktinit(&specials, APERM, 32); /* must be 2^n (currently 17 specials) */
-	for (i = 0; names[i].name; i++) {
-		tp = ktenter(&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.
- */
-static const char *
-array_index_calc(const char *n, bool *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, KSH_UNWIND_ERROR, true);
-		if (rval < 0 || rval > ARRAYMAX)
-			errorf("%s: subscript %ld out of range", n, rval);
-		*valp = rval;
-		afree(sub, ATEMP);
-	}
-	return n;
-}
-
-/*
- * Search for variable, if not found create globally.
- */
-struct tbl *
-global(const char *n)
-{
-	struct block *l = e->loc;
-	struct tbl *vp;
-	int c;
-	unsigned h;
-	bool	 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;
-		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 can't fail here */
-				setstr(vp, l->argv[c], KSH_RETURN_ERROR);
-			vp->flag |= RDONLY;
-			return vp;
-		}
-		vp->flag |= RDONLY;
-		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 = ktsearch(&l->vars, n, h);
-		if (vp != NULL) {
-			if (array)
-				return arraysearch(vp, val);
-			else
-				return vp;
-		}
-		if (l->next == NULL)
-			break;
-	}
-	vp = ktenter(&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(const char *n, bool copy)
-{
-	struct block *l = e->loc;
-	struct tbl *vp;
-	unsigned h;
-	bool	 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 = ktenter(&l->vars, n, h);
-	if (copy && !(vp->flag & DEFINED)) {
-		struct block *ll = l;
-		struct tbl *vq = (struct tbl *) 0;
-
-		while ((ll = ll->next) && !(vq = ktsearch(&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(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 */
-		char strbuf[1 + 2 + 1 + BITS(long) + 1];
-		const char *digits = (vp->flag & UCASEV_AL) ?
-		    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" :
-		    "0123456789abcdefghijklmnopqrstuvwxyz";
-		unsigned long n;
-		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);
-		else
-			s = str_save(s, ATEMP);
-	}
-	return s;
-}
-
-/* get variable integer value, with error checking */
-long
-intval(struct tbl *vp)
-{
-	long num;
-	int base;
-
-	base = getint(vp, &num, false);
-	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 */
-int
-setstr(struct tbl *vq, const char *s, int error_ok)
-{
-	int no_ro_check = error_ok & 0x4;
-	error_ok &= ~0x4;
-	if ((vq->flag & RDONLY) && !no_ro_check) {
-		warningf(true, "%s: is read only", vq->name);
-		if (!error_ok)
-			errorf(null);
-		return 0;
-	}
-	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);
-			vq->flag |= ALLOC;
-		}
-	} else {		/* integer dest */
-		if (!v_evaluate(vq, s, error_ok, true))
-			return 0;
-	}
-	vq->flag |= ISSET;
-	if ((vq->flag&SPECIAL))
-		setspec(vq);
-	return 1;
-}
-
-/* set variable to integer */
-void
-setint(struct tbl *vq, long int n)
-{
-	if (!(vq->flag&INTEGER)) {
-		struct tbl *vp = &vtemp;
-		vp->flag = (ISSET|INTEGER);
-		vp->type = 0;
-		vp->areap = ATEMP;
-		vp->val.i = n;
-		/* setstr can't fail here */
-		setstr(vq, str_val(vp), KSH_RETURN_ERROR);
-	} else
-		vq->val.i = n;
-	vq->flag |= ISSET;
-	if ((vq->flag&SPECIAL))
-		setspec(vq);
-}
-
-int
-getint(struct tbl *vp, long int *nump, bool arith)
-{
-	char *s;
-	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)	/* redundant given initial test */
-		s = null;
-	base = 10;
-	num = 0;
-	neg = 0;
-	if (arith && *s == '0' && *(s+1)) {
-		s++;
-		if (*s == 'x' || *s == 'X') {
-			s++;
-			base = 16;
-		} else if (vp->flag & ZEROFIL) {
-			while (*s == '0')
-				s++;
-		} else
-			base = 8;
-		have_base++;
-	}
-	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(struct tbl *vq, struct tbl *vp, bool arith)
-{
-	int base;
-	long num;
-
-	if ((base = getint(vp, &num, arith)) == -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(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(struct tbl *vp, const char *val)
-{
-	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(const char *var, Tflag set, Tflag clr, int field, int base)
-{
-	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 environment: 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) {
-		int ok = 1;
-		/* 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 *s = NULL;
-			char *free_me = NULL;
-
-			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) {
-				if (!setstr(t, s, KSH_RETURN_ERROR)) {
-					/* Somewhat arbitrary action here:
-					 * zap contents of variable, but keep
-					 * the flag settings.
-					 */
-					ok = 0;
-					if (t->flag & INTEGER)
-						t->flag &= ~ISSET;
-					else {
-						if (t->flag & ALLOC)
-							afree((void*) t->val.s,
-							    t->areap);
-						t->flag &= ~(ISSET|ALLOC);
-						t->type = 0;
-					}
-				}
-				if (free_me)
-					afree((void *) free_me, t->areap);
-			}
-		}
-		if (!ok)
-		    errorf(null);
-	}
-
-	if (val != NULL) {
-		if (vp->flag&INTEGER) {
-			/* do not zero base before assignment */
-			setstr(vp, val, KSH_UNWIND_ERROR | 0x4);
-			/* Done after assignment to override default */
-			if (base > 0)
-				vp->type = base;
-		} else
-			/* setstr can't fail (readonly check already done) */
-			setstr(vp, val, KSH_RETURN_ERROR | 0x4);
-	}
-
-	/* 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(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(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(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(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(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(void)
-{
-	struct block *l = e->loc;
-	XPtrV env;
-	struct tbl *vp, **vpp;
-	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)) {
-				struct block *l2;
-				struct tbl *vp2;
-				unsigned h = hash(vp->name);
-
-				/* unexport any redefined instances */
-				for (l2 = l->next; l2 != NULL; l2 = l2->next) {
-					vp2 = ktsearch(&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|RDONLY);
-					/* setstr can't fail here */
-					setstr(vp, val, KSH_RETURN_ERROR);
-				}
-				XPput(env, vp->val.s);
-			}
-	XPput(env, NULL);
-	return (char **) XPclose(env);
-}
-
-/*
- * Someone has set the srand() value, therefore from now on
- * we return values from rand() instead of arc4random()
- */
-int use_rand = 0;
-
-/*
- * Called after a fork in parent to bump the random number generator.
- * Done to ensure children will not get the same random number sequence
- * if the parent doesn't use $RANDOM.
- */
-void
-change_random(void)
-{
-	if (use_rand)
-		rand();
-}
-
-/*
- * handle special variables with side effects - PATH, SECONDS.
- */
-
-/* Test if name is a special parameter */
-static int
-special(const char *name)
-{
-	struct tbl *tp;
-
-	tp = ktsearch(&specials, name, hash(name));
-	return tp && (tp->flag & ISSET) ? tp->type : V_NONE;
-}
-
-/* Make a variable non-special */
-static void
-unspecial(const char *name)
-{
-	struct tbl *tp;
-
-	tp = ktsearch(&specials, name, hash(name));
-	if (tp)
-		ktdelete(tp);
-}
-
-static	time_t	seconds;		/* time SECONDS last set */
-static	int	user_lineno;		/* what user set $LINENO to */
-
-static void
-getspec(struct tbl *vp)
-{
-	switch (special(vp->name)) {
-	case V_SECONDS:
-		vp->flag &= ~SPECIAL;
-		/* On start up the value of SECONDS is used before seconds
-		 * has been set - don't do anything in this case
-		 * (see initcoms[] in main.c).
-		 */
-		if (vp->flag & ISSET)
-			setint(vp, (long) (time((time_t *)0) - seconds));
-		vp->flag |= SPECIAL;
-		break;
-	case V_RANDOM:
-		vp->flag &= ~SPECIAL;
-		if (use_rand)
-			setint(vp, (long) (rand() & 0x7fff));
-		else
-			setint(vp, (long) (arc4random() & 0x7fff));
-		vp->flag |= SPECIAL;
-		break;
-#ifdef HISTORY
-	case V_HISTSIZE:
-		vp->flag &= ~SPECIAL;
-		setint(vp, (long) histsize);
-		vp->flag |= SPECIAL;
-		break;
-#endif /* HISTORY */
-	case V_OPTIND:
-		vp->flag &= ~SPECIAL;
-		setint(vp, (long) user_opt.uoptind);
-		vp->flag |= SPECIAL;
-		break;
-	case V_LINENO:
-		vp->flag &= ~SPECIAL;
-		setint(vp, (long) current_lineno + user_lineno);
-		vp->flag |= SPECIAL;
-		break;
-	}
-}
-
-static void
-setspec(struct tbl *vp)
-{
-	char *s;
-
-	switch (special(vp->name)) {
-	case V_PATH:
-		if (path)
-			afree(path, APERM);
-		path = str_save(str_val(vp), APERM);
-		flushcom(1);	/* clear tracked aliases */
-		break;
-	case V_IFS:
-		setctypes(s = str_val(vp), C_IFS);
-		ifs0 = *s;
-		break;
-	case V_OPTIND:
-		vp->flag &= ~SPECIAL;
-		getopts_reset((int) intval(vp));
-		vp->flag |= SPECIAL;
-		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 (s[0] == '/' && access(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 */
-	case V_MAIL:
-		mbset(str_val(vp));
-		break;
-	case V_MAILPATH:
-		mpset(str_val(vp));
-		break;
-	case V_MAILCHECK:
-		vp->flag &= ~SPECIAL;
-		mcset(intval(vp));
-		vp->flag |= SPECIAL;
-		break;
-	case V_RANDOM:
-		vp->flag &= ~SPECIAL;
-		srand((unsigned int)intval(vp));
-		use_rand = 1;
-		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;
-	case V_LINENO:
-		vp->flag &= ~SPECIAL;
-		/* The -1 is because line numbering starts at 1. */
-		user_lineno = (unsigned int) intval(vp) - current_lineno - 1;
-		vp->flag |= SPECIAL;
-		break;
-	}
-}
-
-static void
-unsetspec(struct tbl *vp)
-{
-	switch (special(vp->name)) {
-	case V_PATH:
-		if (path)
-			afree(path, APERM);
-		path = str_save(def_path, APERM);
-		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;
-	case V_MAIL:
-		mbset((char *) 0);
-		break;
-	case V_MAILPATH:
-		mpset((char *) 0);
-		break;
-	case V_LINENO:
-	case V_MAILCHECK:	/* at&t ksh leaves previous value in place */
-	case V_RANDOM:
-	case V_SECONDS:
-	case V_TMOUT:		/* at&t ksh leaves previous value in place */
-		unspecial(vp->name);
-		break;
-
-	  /* at&t ksh man page says OPTIND, OPTARG and _ lose special meaning,
-	   * but OPTARG does not (still set by getopts) and _ is also still
-	   * set in various places.
-	   * Don't know what at&t does for:
-	   *		MAIL, MAILPATH, HISTSIZE, HISTFILE,
-	   * Unsetting these in at&t ksh does not loose the `specialness':
-	   *    no effect: IFS, COLUMNS, PATH, TMPDIR,
-	   *		VISUAL, EDITOR,
-	   * pdkshisms: no effect:
-	   *		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(struct tbl *vp, int val)
-{
-	struct tbl *prev, *curr, *new;
-	size_t namelen = strlen(vp->name) + 1;
-
-	vp->flag |= ARRAY|DEFINED;
-	vp->index = 0;
-	/* The table entry is always [0] */
-	if (val == 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) + namelen,
-		    vp->areap);
-	strlcpy(new->name, vp->name, namelen);
-	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(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(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(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);
-		/* would be nice to deal with errors here... (see above) */
-		setstr(vq, vals[i], KSH_RETURN_ERROR);
-	}
-}
--- bin/ksh/lex.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/lex.h,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: lex.h,v 1.11 2006/05/29 18:22:24 otto 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 */
-	const char *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	cmd_offset;	/* line number - command number */
-	int	errline;	/* line the error occurred 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[] separator */
-#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() */
-#define	SLETPAREN 2		/* inside (( )), implicit quoting */
-#define	SSQUOTE	3		/* inside '' */
-#define	SDQUOTE	4		/* inside "" */
-#define	SBRACE	5		/* inside ${} */
-#define	SCSPAREN 6		/* inside $() */
-#define	SBQUOTE	7		/* inside `` */
-#define	SASPAREN 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
-#define MDPAREN	277		/* (( )) */
-#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 HEREDOC BIT(10)		/* parsing heredoc */
-
-#define	HERES	10		/* max << in line */
-
-EXTERN	Source *source;		/* yyparse/yylex source */
-EXTERN	YYSTYPE	yylval;		/* result from yylex */
-EXTERN	struct ioword *heres [HERES], **herep;
-EXTERN	char	ident [IDENT+1];
-
-#ifdef HISTORY
-# define HISTORYSIZE	500	/* size of saved history */
-
-EXTERN	char  **history;	/* saved commands */
-EXTERN	char  **histptr;	/* last history item */
-EXTERN	int	histsize;	/* history size */
-#endif /* HISTORY */
--- bin/ksh/INSTALL
+++ /dev/null
@@ -1,152 +0,0 @@
-$MidnightBSD: src/bin/ksh/INSTALL,v 1.2 2007/07/26 20:13:00 laffer1 Exp $
-$OpenBSD: INSTALL,v 1.1.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'.
--- bin/ksh/tree.c
+++ /dev/null
@@ -1,710 +0,0 @@
-/* $MidnightBSD: src/bin/ksh/tree.c,v 1.2 2007/07/26 20:13:00 laffer1 Exp $ */
-/*	$OpenBSD: tree.c,v 1.18 2006/04/10 14:38:59 jaredy Exp $	*/
-
-/*
- * command tree climbing
- */
-
-#include "sh.h"
-
-#define INDENT	4
-
-#define tputc(c, shf)	shf_putchar(c, shf);
-static void	ptree(struct op *, int, struct shf *);
-static void	pioact(struct shf *, int, struct ioword *);
-static void	tputC(int, struct shf *);
-static void	tputS(char *, struct shf *);
-static void	vfptreef(struct shf *, int, const char *, va_list);
-static struct ioword **iocopy(struct ioword **, Area *);
-static void     iofree(struct ioword **, Area *);
-
-/*
- * print a command tree
- */
-
-static void
-ptree(struct op *t, int indent, struct shf *shf)
-{
-	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:
-#if 0 /* ?not useful - can't be called? */
-		/* Print original vars */
-		if (t->left->vars)
-			for (w = t->left->vars; *w != NULL; )
-				fptreef(shf, indent, "%S ", *w++);
-		else
-			fptreef(shf, indent, "#no-vars# ");
-		/* Print expanded vars */
-		if (t->args)
-			for (w = t->args; *w != NULL; )
-				fptreef(shf, indent, "%s ", *w++);
-		else
-			fptreef(shf, indent, "#no-args# ");
-		/* Print original io */
-		t = t->left;
-#else
-		t = t->left;
-		goto Chain;
-#endif
-	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;
-	  }
-	case TSELECT:
-		fptreef(shf, indent, "select %s ", t->str);
-		/* FALLTHROUGH */
-	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,
-		    t->u.ksh_func ? "function %s %T" : "%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++;
-
-			/* heredoc is 0 when tracing (set -x) */
-			if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc) {
-				tputc('\n', shf);
-				shf_puts(iop->heredoc, shf);
-				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(struct shf *shf, int indent, 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(int c, 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(char *wp, struct shf *shf)
-{
-	int c, quoted=0;
-
-	/* problems:
-	 *	`...` -> $(...)
-	 *	'foo' -> "foo"
-	 * could change encoding to:
-	 *	OQUOTE ["'] ... CQUOTE ["']
-	 *	COMSUB [(`] ...\0	(handle $ ` \ and maybe " in `...` case)
-	 */
-	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);
-			wp++;
-			break;
-		case EXPRSUB:
-			tputc('$', shf);
-			tputc('(', shf);
-			tputc('(', shf);
-			while (*wp != 0)
-				tputC(*wp++, shf);
-			tputc(')', shf);
-			tputc(')', shf);
-			wp++;
-			break;
-		case OQUOTE:
-			quoted = 1;
-			tputc('"', shf);
-			break;
-		case CQUOTE:
-			quoted = 0;
-			tputc('"', shf);
-			break;
-		case OSUBST:
-			tputc('$', shf);
-			if (*wp++ == '{')
-				tputc('{', shf);
-			while ((c = *wp++) != 0)
-				tputC(c, shf);
-			break;
-		case CSUBST:
-			if (*wp++ == '}')
-				tputc('}', shf);
-			break;
-		case OPAT:
-			tputc(*wp++, shf);
-			tputc('(', shf);
-			break;
-		case SPAT:
-			tputc('|', shf);
-			break;
-		case CPAT:
-			tputc(')', shf);
-			break;
-		}
-}
-
-/*
- * this is the _only_ way to reliably handle
- * variable args with an ANSI compiler
- */
-/* VARARGS */
-int
-fptreef(struct shf *shf, int indent, const char *fmt, ...)
-{
-  va_list	va;
-
-  va_start(va, fmt);
-
-  vfptreef(shf, indent, fmt, va);
-  va_end(va);
-  return 0;
-}
-
-/* VARARGS */
-char *
-snptreef(char *s, int n, const char *fmt, ...)
-{
-  va_list va;
-  struct shf shf;
-
-  shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);
-
-  va_start(va, fmt);
-  vfptreef(&shf, 0, fmt, va);
-  va_end(va);
-
-  return shf_sclose(&shf); /* null terminates */
-}
-
-static void
-vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
-{
-	int c;
-
-	while ((c = *fmt++)) {
-		if (c == '%') {
-			long n;
-			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(struct op *t, Area *ap)
-{
-	struct op *r;
-	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((tw - t->vars + 1) * 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((tw - t->args + 1) * 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);
-	r->lineno = t->lineno;
-
-	return r;
-}
-
-char *
-wdcopy(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(const char *wp, int c)
-{
-	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:
-			wp++;
-			if (c == CSUBST && nest == 0)
-				return (char *) wp;
-			nest--;
-			break;
-		case OPAT:
-			nest++;
-			wp++;
-			break;
-		case SPAT:
-		case CPAT:
-			if (c == wp[-1] && nest == 0)
-				return (char *) wp;
-			if (wp[-1] == CPAT)
-				nest--;
-			break;
-		default:
-			internal_errorf(0,
-			    "wdscan: unknown char 0x%x (carrying on)",
-			    wp[-1]);
-		}
-}
-
-/* return a copy of wp without any of the mark up characters and
- * with quote characters (" ' \) stripped.
- * (string is allocated from ATEMP)
- */
-char *
-wdstrip(const char *wp)
-{
-	struct shf shf;
-	int c;
-
-	shf_sopen((char *) 0, 32, SHF_WR | SHF_DYNAMIC, &shf);
-
-	/* problems:
-	 *	`...` -> $(...)
-	 *	x${foo:-"hi"} -> x${foo:-hi}
-	 *	x${foo:-'hi'} -> x${foo:-hi}
-	 */
-	while (1)
-		switch ((c = *wp++)) {
-		case EOS:
-			return shf_sclose(&shf); /* null terminates */
-		case CHAR:
-		case QCHAR:
-			shf_putchar(*wp++, &shf);
-			break;
-		case COMSUB:
-			shf_putchar('$', &shf);
-			shf_putchar('(', &shf);
-			while (*wp != 0)
-				shf_putchar(*wp++, &shf);
-			shf_putchar(')', &shf);
-			break;
-		case EXPRSUB:
-			shf_putchar('$', &shf);
-			shf_putchar('(', &shf);
-			shf_putchar('(', &shf);
-			while (*wp != 0)
-				shf_putchar(*wp++, &shf);
-			shf_putchar(')', &shf);
-			shf_putchar(')', &shf);
-			break;
-		case OQUOTE:
-			break;
-		case CQUOTE:
-			break;
-		case OSUBST:
-			shf_putchar('$', &shf);
-			if (*wp++ == '{')
-			    shf_putchar('{', &shf);
-			while ((c = *wp++) != 0)
-				shf_putchar(c, &shf);
-			break;
-		case CSUBST:
-			if (*wp++ == '}')
-				shf_putchar('}', &shf);
-			break;
-		case OPAT:
-			shf_putchar(*wp++, &shf);
-			shf_putchar('(', &shf);
-			break;
-		case SPAT:
-			shf_putchar('|', &shf);
-			break;
-		case CPAT:
-			shf_putchar(')', &shf);
-			break;
-		}
-}
-
-static	struct ioword **
-iocopy(struct ioword **iow, Area *ap)
-{
-	struct ioword **ior;
-	int i;
-
-	for (ior = iow; *ior++ != NULL; )
-		;
-	ior = (struct ioword **) alloc((ior - iow + 1) * sizeof(*ior), ap);
-
-	for (i = 0; iow[i] != NULL; i++) {
-		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);
-		if (p->heredoc != (char *) 0)
-			q->heredoc = str_save(p->heredoc, ap);
-	}
-	ior[i] = NULL;
-
-	return ior;
-}
-
-/*
- * free tree (for function definition)
- */
-
-void
-tfree(struct op *t, Area *ap)
-{
-	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(struct ioword **iow, Area *ap)
-{
-	struct ioword **iop;
-	struct ioword *p;
-
-	for (iop = iow; (p = *iop++) != NULL; ) {
-		if (p->name != NULL)
-			afree((void*)p->name, ap);
-		if (p->delim != NULL)
-			afree((void*)p->delim, ap);
-		if (p->heredoc != NULL)
-			afree((void*)p->heredoc, ap);
-		afree((void*)p, ap);
-	}
-}
--- bin/ksh/README
+++ /dev/null
@@ -1,198 +0,0 @@
-$MidnightBSD: src/bin/ksh/README,v 1.2 2007/07/26 20:13:00 laffer1 Exp $
-$OpenBSD: README,v 1.10 2003/03/10 03:48:16 david Exp $
-
-Last updated Jul '99 for pdksh-5.2.14.
-	(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 mostly finished 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 at cs.mun.ca),
-who took over from Simon J. Gerraty (sjg at 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 at 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.x, 3.x
-    -/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
-    Commodore/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).  The file pdksh-unstable-XXX.tar.gz has the very latest version which
-may not compile (it is generated automatically when changes are detected
-in the main source repository) - it is for those who want to follow
-changes as they are made.
-
-You can send bug reports, fixes, and enhancements to pdksh at 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.
-
-BTW, THE MOST FREQUENTLY REPORTED BUG IS
-	echo hi | read a; echo $a	# Does not print hi
-I'm aware of this and there is no need to report it.
-
-Michael Rendell, michael at cs.mun.ca
--- bin/ksh/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.*/
----
-
-
--- bin/ksh/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
----
-
--- bin/ksh/tests/ifs.t
+++ /dev/null
@@ -1,167 +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}"
-	x=" A :  B::D"
-	echo -n '12:'; for i in $x ; do echo -n " [$i]" ; done ; echo
-	showargs 13 $x
-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>
-	12: [A] [B] [] [D]
-	 <13> <A> <B> <> <D>
----
-
--- bin/ksh/tests/bksl-nl.t
+++ /dev/null
@@ -1,341 +0,0 @@
-#	$OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
-
-#
-#  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
----
-
--- bin/ksh/tests/lineno.t
+++ /dev/null
@@ -1,111 +0,0 @@
-name: lineno-stdin
-description:
-	See if $LINENO is updated and can be modified.
-stdin:
-	echo A $LINENO
-	echo B $LINENO
-	LINENO=20
-	echo C $LINENO
-expected-stdout:
-	A 1
-	B 2
-	C 20
----
-
-name: lineno-inc
-description:
-	See if $LINENO is set for .'d files.
-file-setup: file 644 "dotfile"
-	echo dot A $LINENO
-	echo dot B $LINENO
-	LINENO=20
-	echo dot C $LINENO
-stdin:
-	echo A $LINENO
-	echo B $LINENO
-	. ./dotfile
-expected-stdout:
-	A 1
-	B 2
-	dot A 1
-	dot B 2
-	dot C 20
----
-
-
-name: lineno-func
-description:
-	See if $LINENO is set for commands in a function.
-stdin:
-	echo A $LINENO
-	echo B $LINENO
-	bar() {
-	    echo func A $LINENO
-	    echo func B $LINENO
-	}
-	bar
-	echo C $LINENO
-expected-stdout:
-	A 1
-	B 2
-	func A 4
-	func B 5
-	C 8
----
-
-name: lineno-unset
-description:
-	See if unsetting LINENO makes it non-magic.
-file-setup: file 644 "dotfile"
-	echo dot A $LINENO
-	echo dot B $LINENO
-stdin:
-	unset LINENO
-	echo A $LINENO
-	echo B $LINENO
-	bar() {
-	    echo func A $LINENO
-	    echo func B $LINENO
-	}
-	bar
-	. ./dotfile
-	echo C $LINENO
-expected-stdout:
-	A
-	B
-	func A
-	func B
-	dot A
-	dot B
-	C
----
-
-name: lineno-unset-use
-description:
-	See if unsetting LINENO makes it non-magic even
-	when it is re-used.
-file-setup: file 644 "dotfile"
-	echo dot A $LINENO
-	echo dot B $LINENO
-stdin:
-	unset LINENO
-	LINENO=3
-	echo A $LINENO
-	echo B $LINENO
-	bar() {
-	    echo func A $LINENO
-	    echo func B $LINENO
-	}
-	bar
-	. ./dotfile
-	echo C $LINENO
-expected-stdout:
-	A 3
-	B 3
-	func A 3
-	func B 3
-	dot A 3
-	dot B 3
-	C 3
----
-
--- bin/ksh/tests/version.t
+++ /dev/null
@@ -1,9 +0,0 @@
-name: version-1
-description:
-	Check version of shell.
-category: pdksh
-stdin:
-	echo $KSH_VERSION
-expected-stdout:
-	@(#)PD KSH v5.2.14 99/07/13.2
----
--- bin/ksh/tests/th
+++ /dev/null
@@ -1,1211 +0,0 @@
-#!/usr/bin/perl
-#	$OpenBSD: th,v 1.13 2006/05/18 21:27:23 miod Exp $
-
-
-#
-# 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).
-#	file-setup		    mps Used to create files, directories
-#					and symlinks.  First word is either
-#					file, dir or symlink; second word is
-#					permissions; this is followed by a
-#					quoted word that is the name of the
-#					file; the end-quote should be followed
-#					by a newline, then the file data
-#					(if any).  The first word may be
-#					preceded by a ! to strip the trailing
-#					newline in a symlink.
-#	file-result		    mps Used to verify a file, symlink or
-#					directory is created correctly.
-#					The first word is either
-#					file, dir or symlink; second word is
-#					expected permissions; third word
-#					is user-id; fourth is group-id; 
-#					fifth is "exact" or "pattern"
-#					indicating whether the file contents
-#					which follow is to be matched exactly
-#					or if it is a regular expression.
-#					The fifth argument is the quoted name
-#					of the file that should be created.
-#					The end-quote should be followed
-#					by a newline, then the file data
-#					(if any).  The first word may be
-#					preceded by a ! to strip the trailing
-#					newline in the file contents.
-#					The permissions, user and group fields
-#					may be * meaning accept any value.
-#	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.
-#	category		    m	Specify a comma separated list of
-#					`categories' of program that the test
-#					is to be run for.  A category can be
-#					negated by prefixing the name with a !.
-#					The idea is that some tests in a
-#					test suite may apply to a particular
-#					program version and shouldn't be run
-#					on other versions.  The category(s) of
-#					the program being tested can be
-#					specified on the command line.
-#					One category os:XXX is predefined
-#					(XXX is the operating system name,
-#					eg, linux, dec_osf).
-# 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 separator character.
-#		The value must start and end with the f-s-c.
-#	p	tag takes parameters (used with m).
-#	s	tag can be used several times.
-#
-
-use POSIX qw(EINTR);
-use Getopt::Std;
-
-$os = defined $^O ? $^O : 'unknown';
-
-($prog = $0) =~ s#.*/##;
-
-$Usage = <<EOF ;
-Usage: $prog [-s test-set] [-C category] [-p prog] [-v] [-e e=v] test-name ...
-	-p p	Use p as the program to test
-	-C c	Specify the comma separated list of categories the program
-		belongs to (see category field).
-	-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)
-	-P	program (-p) string has multiple words, and the program is in
-		the path (kludge option)
-	-v	Verbose mode: print reason test failed.
-	-e e=v	Set the environment variable e to v for all tests
-		(if no =v is given, the current value is used)
-    test-name(s) specifies the name of the test(s) to run; if none are
-    specified, all tests are run.
-EOF
-
-#
-# See comment above for flag meanings
-#
-%test_fields = (
-	    'name',			'r',
-	    'description',		'm',
-	    'arguments',		'M',
-	    'script',			'm',
-	    'stdin',			'm',
-	    'perl-setup',		'm',
-	    'perl-cleanup',		'm',
-	    'env-setup',		'M',
-	    'file-setup',		'mps',
-	    'file-result',		'mps',
-	    'time-limit',		'',
-	    'expected-fail',		'',
-	    'expected-exit',		'',
-	    'expected-stdout',		'm',
-	    'expected-stdout-pattern',	'm',
-	    'expected-stderr',		'm',
-	    'expected-stderr-pattern',	'm',
-	    'category',			'm',
-	);
-# Filled in by read_test()
-%internal_test_fields = (
-	    ':full-name', 1,		# file:name
-	    ':long-name', 1,		# dir/file:lineno:name
-	);
-
-# Categories of the program under test.  Provide the current
-# os by default.
-%categories = (
-#	(defined $^O ? "os:$^O" : "os:unknown"), '1'
-	"os:$os", '1'
-	);
-
-$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('C:p:Ps:t:ve:')) {
-    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;
-}
-$program_kludge = defined $opt_P ? $opt_P : 0;
-
-if (defined $opt_C) {
-    foreach $c (split(',', $opt_C)) {
-	$c =~ s/\s+//;
-	die "$prog: categories can't be negated on the command line\n"
-	    if ($c =~ /^!/);
-	$categories{$c} = 1;
-    }
-}
-
-# 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};
-}
-if (defined $opt_e) {
-    # XXX need a way to allow many -e arguments...
-    if ($opt_e =~ /^([a-zA-Z_]\w*)(|=(.*))$/) {
-	$new_env{$1} = $2 eq '' ? $ENV{$1} : $3;
-    } else {
-	die "$0: bad -e argument: $opt_e\n";
-    }
-}
-%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);
-
-if (!$program_kludge) {
-    $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 && $os ne 'os2');
-}
-
- at trap_sigs = ('TERM', 'QUIT', 'INT', 'PIPE', 'HUP');
- at 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 (defined ($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)) {
-	print STDERR "$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'}};
-	next if !&category_check(*test);
-	$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{'file-setup'}) {
-	local($i);
-	local($type, $perm, $rest, $c, $len, $name);
-
-	for ($i = 0; $i < $test{'file-setup'}; $i++) {
-	    $val = $test{"file-setup:$i"};
-	    #
-	    # format is: type perm "name"
-	    #
-	    ($type, $perm, $rest) =
-		split(' ', $val, 3);
-	    $c = substr($rest, 0, 1);
-	    $len = index($rest, $c, 1) - 1;
-	    $name = substr($rest, 1, $len);
-	    $rest = substr($rest, 2 + $len);
-	    $perm = oct($perm) if $perm =~ /^\d+$/;
-	    if ($type eq 'file') {
-		return undef if !&write_file($name, $rest);
-		if (!chmod($perm, $name)) {
-		    print STDERR
-		  "$prog:$test{':long-name'}: can't chmod $perm $name - $!\n";
-		    return undef;
-		}
-	    } elsif ($type eq 'dir') {
-		if (!mkdir($name, $perm)) {
-		    print STDERR
-		  "$prog:$test{':long-name'}: can't mkdir $perm $name - $!\n";
-		    return undef;
-		}
-	    } elsif ($type eq 'symlink') {
-		local($oumask) = umask($perm);
-		local($ret) = symlink($rest, $name);
-		umask($oumask);
-		if (!$ret) {
-		    print STDERR
-	    "$prog:$test{':long-name'}: couldn't create symlink $name - $!\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', $$);
-	}
-	if ($program_kludge) {
-	    @argv = split(' ', $test_prog);
-	} else {
-	    @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;
-    }
-
-    $tmp = &check_file_result(*test);
-    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
-category_check
-{
-    local(*test) = @_;
-    local($c);
-
-    return 1 if (!defined $test{'category'});
-    local($ok) = 0;
-    foreach $c (split(',', $test{'category'})) {
-	$c =~ s/\s+//;
-	if ($c =~ /^!/) {
-	    $c = $';
-	    return 0 if (defined $categories{$c});
-	} else {
-	    $ok = 1 if (defined $categories{$c});
-	}
-    }
-    return $ok;
-}
-
-sub
-scrub_dir
-{
-    local($dir) = @_;
-    local(@todo) = ();
-    local($file);
-
-    if (!opendir(DIR, $dir)) {
-	print STDERR "$prog: couldn't open directory $dir - $!\n";
-	return undef;
-    }
-    while (defined ($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);
-    return compare_output($name, $what, $expect, $expect_pat, $got);
-}
-
-sub
-compare_output
-{
-    local($name, $what, $expect, $expect_pat, $got) = @_;
-    local($why) = '';
-
-    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, $exp_len, $got_len);
-    local($ce, $cg);
-
-    $exp_len = length($exp);
-    $got_len = length($got);
-    if ($exp_len != $got_len) {
-	if ($exp_len < $got_len) {
-	    if (substr($got, 0, $exp_len) eq $exp) {
-		return "got too much output";
-	    }
-	} elsif (substr($exp, 0, $got_len) eq $got) {
-	    return "got too little output";
-	}
-    }
-    for ($i = 0; $i < $exp_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 (wanted '"
-	. &format_char($ce) . "', got '"
-	. &format_char($cg) . "'";
-}
-
-sub
-format_char
-{
-    local($ch, $s);
-
-    $ch = ord($_[0]);
-    if ($ch == 10) {
-	return '\n';
-    } elsif ($ch == 13) {
-	return '\r';
-    } elsif ($ch == 8) {
-	return '\b';
-    } elsif ($ch == 9) {
-	return '\t';
-    } elsif ($ch > 127) {
-	$ch -= 127;
-	$s = "M-";
-    } else {
-	$s = '';
-    }
-    if ($ch < 32) {
-	$s .= '^';
-	$ch += ord('@');
-    } elsif ($ch == 127) {
-	return $s . "^?";
-    }
-    return $s . sprintf("%c", $ch);
-}
-
-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);
-    local(%cnt, $sfield);
-
-    %test = ();
-    %cnt = ();
-    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);
-	$sfield = $field;
-	$flags = $test_fields{$field};
-	if (!defined $flags) {
-	    print STDERR "$prog:$file:$.: unrecognized field \"$field\"\n";
-	    return undef;
-	}
-	if ($flags =~ /s/) {
-	    local($cnt) = $cnt{$field}++;
-	    $test{$field} = $cnt{$field};
-	    $cnt = 0 if $cnt eq '';
-	    $sfield .= ":$cnt";
-	} elsif (defined $test{$field}) {
-	    print STDERR "$prog:$file:$.: multiple \"$field\" fields\n";
-	    return undef;
-	}
-	$do_chop = $flags !~ /m/;
-	$need_redo = 0;
-	if ($val eq '' || $val eq '!' || $flags =~ /p/) {
-	    if ($flags =~ /[Mm]/) {
-		if ($flags =~ /p/) {
-		    if ($val =~ /^!/) {
-			$do_chop = 1;
-			$val = $';
-		    } else {
-			$do_chop = 0;
-		    }
-		    if ($val eq '') {
-			print STDERR
-		"$prog:$file:$.: no parameters given for field \"$field\"\n";
-			return undef;
-		    }
-		} else {
-		    if ($val eq '!') {
-			$do_chop = 1;
-		    }
-		    $val = '';
-		}
-		while (<$in>) {
-		    last if !/^\t/;
-		    $val .= $';
-		}
-		chop $val if $do_chop;
-		$do_chop = 1;
-		$need_redo = 1;
-		#
-		# Syntax check on fields that can several instances
-		# (can give useful line numbers this way)
-		#
-		if ($field eq 'file-setup') {
-		    local($type, $perm, $rest, $c, $len, $name);
-		    #
-		    # format is: type perm "name"
-		    #
-		    if ($val !~ /^[ \t]*(\S+)[ \t]+(\S+)[ \t]+([^ \t].*)/) {
-			print STDERR
-		    "$prog:$file:$.: bad parameter line for file-setup field\n";
-			return undef;
-		    }
-		    ($type, $perm, $rest) = ($1, $2, $3);
-		    if ($type !~ /^(file|dir|symlink)$/) {
-			print STDERR
-		    "$prog:$file:$.: bad file type for file-setup: $type\n";
-			return undef;
-		    }
-		    if ($perm !~ /^\d+$/) {
-			print STDERR
-		    "$prog:$file:$.: bad permissions for file-setup: $type\n";
-			return undef;
-		    }
-		    $c = substr($rest, 0, 1);
-		    if (($len = index($rest, $c, 1) - 1) <= 0) {
-			print STDERR
-    "$prog:$file:$.: missing end quote for file name in file-setup: $rest\n";
-			return undef;
-		    }
-		    $name = substr($rest, 1, $len);
-		    if ($name =~ /^\// || $name =~ /(^|\/)\.\.(\/|$)/) {
-			# Note: this is not a security thing - just a sanity
-			# check - a test can still use symlinks to get at files
-			# outside the test directory.
-			print STDERR
-"$prog:$file:$.: file name in file-setup is absolute or contains ..: $name\n";
-			return undef;
-		    }
-		}
-		if ($field eq 'file-result') {
-		    local($type, $perm, $uid, $gid, $matchType,
-		    	  $rest, $c, $len, $name);
-		    #
-		    # format is: type perm uid gid matchType "name"
-		    #
-		    if ($val !~ /^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S.*)/) {
-			print STDERR
-		    "$prog:$file:$.: bad parameter line for file-result field\n";
-			return undef;
-		    }
-		    ($type, $perm, $uid, $gid, $matchType, $rest)
-			= ($1, $2, $3, $4, $5, $6);
-		    if ($type !~ /^(file|dir|symlink)$/) {
-			print STDERR
-		    "$prog:$file:$.: bad file type for file-result: $type\n";
-			return undef;
-		    }
-		    if ($perm !~ /^\d+$/ && $perm ne '*') {
-			print STDERR
-		    "$prog:$file:$.: bad permissions for file-result: $perm\n";
-			return undef;
-		    }
-		    if ($uid !~ /^\d+$/ && $uid ne '*') {
-			print STDERR
-		    "$prog:$file:$.: bad user-id for file-result: $uid\n";
-			return undef;
-		    }
-		    if ($gid !~ /^\d+$/ && $gid ne '*') {
-			print STDERR
-		    "$prog:$file:$.: bad group-id for file-result: $gid\n";
-			return undef;
-		    }
-		    if ($matchType !~ /^(exact|pattern)$/) {
-			print STDERR
-		"$prog:$file:$.: bad match type for file-result: $matchType\n";
-			return undef;
-		    }
-		    $c = substr($rest, 0, 1);
-		    if (($len = index($rest, $c, 1) - 1) <= 0) {
-			print STDERR
-    "$prog:$file:$.: missing end quote for file name in file-result: $rest\n";
-			return undef;
-		    }
-		    $name = substr($rest, 1, $len);
-		    if ($name =~ /^\// || $name =~ /(^|\/)\.\.(\/|$)/) {
-			# Note: this is not a security thing - just a sanity
-			# check - a test can still use symlinks to get at files
-			# outside the test directory.
-			print STDERR
-"$prog:$file:$.: file name in file-result is absolute or contains ..: $name\n";
-			return undef;
-		    }
-		}
-	    } elsif ($val eq '') {
-		print STDERR
-		    "$prog:$file:$.: no value given for field \"$field\"\n";
-		return undef;
-	    }
-	}
-	$val .= "\n" if !$do_chop;
-	$test{$sfield} = $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
-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");
-	&never_called_funcs();
-	&catch_sigalrm();
-	$old_env{'foo'} = 'bar';
-	$internal_test_fields{'foo'} = 'bar';
-}
-
-sub
-check_file_result
-{
-    local(*test) = @_;
-
-    return '' if (!defined $test{'file-result'});
-
-    local($why) = '';
-    local($i);
-    local($type, $perm, $uid, $gid, $rest, $c, $len, $name);
-    local(@stbuf);
-
-    for ($i = 0; $i < $test{'file-result'}; $i++) {
-	$val = $test{"file-result:$i"};
-	#
-	# format is: type perm "name"
-	#
-	($type, $perm, $uid, $gid, $matchType, $rest) =
-	    split(' ', $val, 6);
-	$c = substr($rest, 0, 1);
-	$len = index($rest, $c, 1) - 1;
-	$name = substr($rest, 1, $len);
-	$rest = substr($rest, 2 + $len);
-	$perm = oct($perm) if $perm =~ /^\d+$/;
-
-	@stbuf = lstat($name);
-	if (!@stbuf) {
-	    $why .= "\texpected $type \"$name\" not created\n";
-	    next;
-	}
-	if ($perm ne '*' && ($stbuf[2] & 07777) != $perm) {
-	    $why .= "\t$type \"$name\" has unexpected permissions\n";
-	    $why .= sprintf("\t\texpected 0%o, found 0%o\n",
-		    $perm, $stbuf[2] & 07777);
-	}
-	if ($uid ne '*' && $stbuf[4] != $uid) {
-	    $why .= "\t$type \"$name\" has unexpected user-id\n";
-	    $why .= sprintf("\t\texpected %d, found %d\n",
-		    $uid, $stbuf[4]);
-	}
-	if ($gid ne '*' && $stbuf[5] != $gid) {
-	    $why .= "\t$type \"$name\" has unexpected group-id\n";
-	    $why .= sprintf("\t\texpected %d, found %d\n",
-		    $gid, $stbuf[5]);
-	}
-
-	if ($type eq 'file') {
-	    if (-l _ || ! -f _) {
-		$why .= "\t$type \"$name\" is not a regular file\n";
-	    } else {
-		local $tmp = &check_output($test{'long-name'}, $name,
-			    "$type contents in \"$name\"",
-			    $matchType eq 'exact' ? $rest : undef
-			    $matchType eq 'pattern' ? $rest : undef);
-		return undef if (!defined $tmp);
-		$why .= $tmp;
-	    }
-	} elsif ($type eq 'dir') {
-	    if ($rest !~ /^\s*$/) {
-		print STDERR "$prog:$test{':long-name'}: file-result test for directory $name should not have content specified\n";
-		return undef;
-	    }
-	    if (-l _ || ! -d _) {
-		$why .= "\t$type \"$name\" is not a directory\n";
-	    }
-	} elsif ($type eq 'symlink') {
-	    if (!-l _) {
-		$why .= "\t$type \"$name\" is not a symlink\n";
-	    } else {
-		local $content = readlink($name);
-		if (!defined $content) {
-		    print STDERR "$prog:$test{':long-name'}: file-result test for $type $name failed - could not readlink - $!\n";
-		    return undef;
-		}
-		local $tmp = &compare_output($test{'long-name'},
-			    "$type contents in \"$name\"",
-			    $matchType eq 'exact' ? $rest : undef
-			    $matchType eq 'pattern' ? $rest : undef);
-		return undef if (!defined $tmp);
-		$why .= $tmp;
-	    }
-	}
-    }
-
-    return $why;
-}
-
-sub HELP_MESSAGE
-{
-    print STDERR $Usage;
-    exit 0;
-}
--- bin/ksh/tests/cdhist.t
+++ /dev/null
@@ -1,162 +0,0 @@
-name: cd-history
-description:
-	Test someone's CD history package (uses arrays)
-# Fails on OS/2, since directory names are prepended with drive letter.
-category: !os:os2
-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
----
--- bin/ksh/tests/alias.t
+++ /dev/null
@@ -1,112 +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
----
-
-name: alias-8
-description:
-	Check that newlines in an alias don't cause the command to be lost.
-stdin:
-	alias foo='
-	
-	
-	echo hi
-	
-	
-	
-	echo there
-	
-	
-	'
-	foo
-expected-stdout:
-	hi
-	there
----
-
--- bin/ksh/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
----
-
--- bin/ksh/tests/regress.t
+++ /dev/null
@@ -1,1093 +0,0 @@
-#	$OpenBSD: regress.t,v 1.12 2003/11/08 19:17:27 jmc Exp $
-
-#
-# 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 existent 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
-	    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 at 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 at 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 ($?)"
-		}
-		echo=echo; [ -x /bin/echo ] && echo=/bin/echo
-		exec $echo subtest-1 hi
-	EOF
-	echo subtest-1 foo/*
-	TMPDIR=$PWD/foo $0 <<- 'EOF'
-		echo=echo; [ -x /bin/echo ] && echo=/bin/echo
-		sed 's/^/X /' << E_O_F; exec $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
----
-
-name: regression-50
-description:
-	Check that aliases do not use continuation prompt after trailing
-	semi-colon.
-file-setup: file 644 "env"
-	PS1=Y
-	PS2=X
-env-setup: !ENV=./env!
-arguments: !-i!
-stdin:
-	alias foo='echo hi ; '
-	foo
-	foo echo there
-expected-stdout: 
-	hi
-	hi
-	there
-expected-stderr: !
-	YYYY
----
-
-name: regression-51
-description:
-	Check that set allows both +o and -o options on same command line.
-stdin:
-	set a b c
-	set -o noglob +o allexport
-	echo A: $*, *
-expected-stdout: 
-	A: a b c, *
----
-
-name: regression-52
-description:
-	Check that globing works in pipelined commands
-file-setup: file 644 "env"
-	PS1=P
-file-setup: file 644 "abc"
-	stuff
-env-setup: !ENV=./env!
-arguments: !-i!
-stdin:
-	sed 's/^/X /' < ab*
-	echo mark 1
-	sed 's/^/X /' < ab* | sed 's/^/Y /'
-	echo mark 2
-expected-stdout: 
-	X stuff
-	mark 1
-	Y X stuff
-	mark 2
-expected-stderr: !
-	PPPPP
----
-
-name: regression-53
-description:
-	Check that getopts works in functions
-stdin:
-	#!/bin/ksh
-	
-	bfunc() {
-	    echo bfunc: enter "(args: $*; OPTIND=$OPTIND)"
-	    while getopts B oc; do
-		case $oc in
-		  (B)
-		    echo bfunc: B option
-		    ;;
-		  (*)
-		    echo bfunc: odd option "($oc)"
-		    ;;
-		esac
-	    done
-	    echo bfunc: leave
-	}
-	
-	function kfunc {
-	    echo kfunc: enter "(args: $*; OPTIND=$OPTIND)"
-	    while getopts K oc; do
-		case $oc in
-		  (K)
-		    echo kfunc: K option
-		    ;;
-		  (*)
-		    echo bfunc: odd option "($oc)"
-		    ;;
-		esac
-	    done
-	    echo kfunc: leave
-	}
-	
-	set -- -f -b -k -l
-	echo "line 1: OPTIND=$OPTIND"
-	getopts kbfl optc
-	echo "line 2: ret=$?, optc=$optc, OPTIND=$OPTIND"
-	bfunc -BBB blah
-	echo "line 3: OPTIND=$OPTIND"
-	getopts kbfl optc
-	echo "line 4: ret=$?, optc=$optc, OPTIND=$OPTIND"
-	kfunc -KKK blah
-	echo "line 5: OPTIND=$OPTIND"
-	getopts kbfl optc
-	echo "line 6: ret=$?, optc=$optc, OPTIND=$OPTIND"
-	echo
-	
-	OPTIND=1
-	set -- -fbkl
-	echo "line 10: OPTIND=$OPTIND"
-	getopts kbfl optc
-	echo "line 20: ret=$?, optc=$optc, OPTIND=$OPTIND"
-	bfunc -BBB blah
-	echo "line 30: OPTIND=$OPTIND"
-	getopts kbfl optc
-	echo "line 40: ret=$?, optc=$optc, OPTIND=$OPTIND"
-	kfunc -KKK blah
-	echo "line 50: OPTIND=$OPTIND"
-	getopts kbfl optc
-	echo "line 60: ret=$?, optc=$optc, OPTIND=$OPTIND"
-expected-stdout: 
-	line 1: OPTIND=1
-	line 2: ret=0, optc=f, OPTIND=2
-	bfunc: enter (args: -BBB blah; OPTIND=2)
-	bfunc: B option
-	bfunc: B option
-	bfunc: leave
-	line 3: OPTIND=2
-	line 4: ret=0, optc=b, OPTIND=3
-	kfunc: enter (args: -KKK blah; OPTIND=1)
-	kfunc: K option
-	kfunc: K option
-	kfunc: K option
-	kfunc: leave
-	line 5: OPTIND=3
-	line 6: ret=0, optc=k, OPTIND=4
-	
-	line 10: OPTIND=1
-	line 20: ret=0, optc=f, OPTIND=2
-	bfunc: enter (args: -BBB blah; OPTIND=2)
-	bfunc: B option
-	bfunc: B option
-	bfunc: leave
-	line 30: OPTIND=2
-	line 40: ret=1, optc=?, OPTIND=2
-	kfunc: enter (args: -KKK blah; OPTIND=1)
-	kfunc: K option
-	kfunc: K option
-	kfunc: K option
-	kfunc: leave
-	line 50: OPTIND=2
-	line 60: ret=1, optc=?, OPTIND=2
----
-
-
-name: regression-54
-description:
-	Check that ; is not required before the then in if (( ... )) then ...
-stdin:
-	if (( 1 )) then
-	    echo ok dparen
-	fi
-	if [[ -n 1 ]] then
-	    echo ok dbrackets
-	fi
-expected-stdout: 
-	ok dparen
-	ok dbrackets
----
-
-
-name: regression-55
-description:
-	Check ${foo:%bar} is allowed (ksh88 allows it...)
-stdin:
-	x=fooXbarXblah
-	echo 1 ${x%X*}
-	echo 2 ${x:%X*}
-	echo 3 ${x%%X*}
-	echo 4 ${x:%%X*}
-	echo 5 ${x#*X}
-	echo 6 ${x:#*X}
-	echo 7 ${x##*X}
-	echo 8 ${x:##*X}
-expected-stdout: 
-	1 fooXbar
-	2 fooXbar
-	3 foo
-	4 foo
-	5 barXblah
-	6 barXblah
-	7 blah
-	8 blah
----
-
-
-name: regression-56
-description:
-	Check eval vs substitution exit codes
-	(this is what ksh88 does)
-stdin:
-	eval $(false)
-	echo A $?
-	eval ' $(false)'
-	echo B $?
-	eval " $(false)"
-	echo C $?
-	eval "eval $(false)"
-	echo D $?
-	eval 'eval '"$(false)"
-	echo E $?
-	IFS="$IFS:"
-	eval $(echo :; false)
-	echo F $?
-expected-stdout: 
-	A 1
-	B 1
-	C 1
-	D 0
-	E 0
-	F 1
----
-
-name: regression-57
-description:
-	Check if typeset output is correct for
-	uninitialized array elements.
-stdin:
-	typeset -i xxx[4]
-	echo A
-	typeset -i | grep xxx | sed 's/^/    /'
-	echo B
-	typeset | grep xxx | sed 's/^/    /'
-	
-	xxx[1]=2+5
-	echo M
-	typeset -i | grep xxx | sed 's/^/    /'
-	echo N
-	typeset | grep xxx | sed 's/^/    /'
-expected-stdout: 
-	A
-	    xxx
-	B
-	    typeset -i xxx
-	M
-	    xxx[1]=7
-	N
-	    typeset -i xxx
----
-
-name: regression-58
-description:
-	Check if trap exit is ok (exit not mistaken for signal name)
-stdin:
-	trap 'echo hi' exit
-	trap exit 1
-expected-stdout: 
-	hi
----
-
-name: regression-59
-description:
-	Check if ${#array[*]} is calculated correctly.
-stdin:
-	a[12]=hi
-	a[8]=there
-	echo ${#a[*]}
-expected-stdout: 
-	2
----
-
-name: regression-60
-description:
-	Check if default exit status is previous command
-stdin:
-	(true; exit)
-	echo A $?
-	(false; exit)
-	echo B $?
-	( (exit 103) ; exit)
-	echo C $?
-expected-stdout: 
-	A 0
-	B 1
-	C 103
----
-
-name: regression-61
-description:
-	Check if EXIT trap is executed for sub shells.
-stdin:
-	trap 'echo parent exit' EXIT
-	echo start
-	(echo A; echo A last)
-	echo B
-	(echo C; trap 'echo sub exit' EXIT; echo C last)
-	echo parent last
-expected-stdout: 
-	start
-	A
-	A last
-	B
-	C
-	C last
-	sub exit
-	parent last
-	parent exit
----
-
-name: regression-62
-description:
-	Check if test -nt/-ot succeeds if second(first) file is missing.
-stdin:
-	touch a
-	test a -nt b && echo nt OK || echo nt BAD
-	test b -ot a && echo ot OK || echo ot BAD
-expected-stdout: 
-	nt OK
-	ot OK
----
-
--- bin/ksh/tests/unclass2.t
+++ /dev/null
@@ -1,163 +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 -vsA foo -- A 1 3 2
-	echo ${foo[*]}
-expected-stderr:
-	echo ${foo[*]}
-expected-stdout:
-	1 2 3 A
----
-
-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!
-file-setup: file 644 "foo"
-	XXX=_
-	PS1=X
-	false && echo hmmm
-arguments: !-i!
-stdin:
-	echo hi${XXX}there
-expected-stdout:
-	hi_there
-expected-stderr: !
-	XX
----
-
--- bin/ksh/tests/unclass1.t
+++ /dev/null
@@ -1,99 +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
-# Under os/2, _emx_sig environment variable changes.
-category: !os:os2
-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
----
--- bin/ksh/tests/glob.t
+++ /dev/null
@@ -1,99 +0,0 @@
-name: glob-bad-1
-description:
-	Check that globbing isn't done when glob has syntax error
-file-setup: dir 755 "[x"
-file-setup: file 644 "[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
-category: !os:os2
-file-setup: dir 755 "dir"
-file-setup: symlink 644 "dir/abc"
-	non-existent-file
-stdin:
-	echo d*/*
-	echo d*/abc
-expected-stdout:
-	dir/abc
-	dir/abc
----
-
-name: glob-range-1
-description:
-	Test range matching
-file-setup: file 644 ".bc"
-file-setup: file 644 "abc"
-file-setup: file 644 "bbc"
-file-setup: file 644 "cbc"
-file-setup: file 644 "-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)
-file-setup: file 644 "abc"
-stdin:
-	echo [a--]*
-expected-stdout:
-	[a--]*
----
-
-name: glob-range-3
-description:
-	Check that globbing matches the right things...
-file-setup: file 644 "aÂc"
-stdin:
-	echo a[Á-Ú]*
-expected-stdout:
-	aÂc
----
-
-name: glob-range-4
-description:
-	Results unspecified according to POSIX
-file-setup: file 644 ".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]*)
-file-setup: file 644 "abc"
-file-setup: file 644 "bbc"
-file-setup: file 644 "cbc"
-file-setup: file 644 "dbc"
-file-setup: file 644 "ebc"
-file-setup: file 644 "-bc"
-stdin:
-	echo [a-c-e]*
-expected-stdout:
-	-bc abc bbc cbc ebc
----
-
--- bin/ksh/tests/eglob.t
+++ /dev/null
@@ -1,145 +0,0 @@
-name: eglob-bad-1
-description:
-	Check that globbing isn't done when glob has syntax error
-file-setup: file 644 "abcx"
-file-setup: file 644 "abcz"
-file-setup: file 644 "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)
-file-setup: file 644 "abcx"
-file-setup: file 644 "abcz"
-file-setup: file 644 "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.
-file-setup: file 644 "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
-file-setup: file 644 "abc"
-stdin:
-	x='@(*)'
-	echo $x
-expected-stdout:
-	@(*)
----
-
-name: eglob-nomatch-1
-description:
-	Check that the pattern doesn't match
-stdin:
-	echo 1: no-file+(a|b)stuff
-	echo 2: no-file+(a*(c)|b)stuff
-	echo 3: no-file+((((c)))|b)stuff
-expected-stdout:
-	1: no-file+(a|b)stuff
-	2: no-file+(a*(c)|b)stuff
-	3: no-file+((((c)))|b)stuff
----
-
-name: eglob-match-1
-description:
-	Check that the pattern matches correctly
-file-setup: file 644 "abd"
-file-setup: file 644 "acd"
-file-setup: file 644 "abac"
-stdin:
-	echo 1: a+(b|c)d
-	echo 2: a!(@(b|B))d
-	echo 3: *(a(b|c))		# (...|...) can be used within X(..)
-	echo 4: a[b*(foo|bar)]d		# patterns not special inside [...]
-expected-stdout:
-	1: abd acd
-	2: acd
-	3: abac
-	4: 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 1: ${x#*(a|b)cd}
-	echo 2: "${x#*(a|b)cd}"
-	echo 3: ${x#"*(a|b)cd"}
-	echo 4: ${x#a(b|c)}
-expected-stdout:
-	1: ef
-	2: ef
-	3: abcdef
-	4: cdef
----
-
--- bin/ksh/tests/history.t
+++ /dev/null
@@ -1,559 +0,0 @@
-#	$OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
-
-# 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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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!
-file-setup: file 644 "Env"
-	PS1=X
-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).
-# No ed on os/2 (yet?).
-category: !os:os2
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-file-setup: file 644 "Env"
-	PS1=X
-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
-category: !os:os2
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-file-setup: file 644 "Env"
-	PS1=X
-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)
-category: !os:os2
-arguments: !-i!
-env-setup: !ENV=./Env!HISTFILE=hist.file!
-file-setup: file 644 "Env"
-	PS1=X
-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*$/
----
--- bin/ksh/tests/heredoc.t
+++ /dev/null
@@ -1,331 +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
----
-
-name: heredoc-tmpfile-1
-description:
-	Check that heredoc temp files aren't removed too soon or too late.
-	Heredoc in simple command.
-stdin:
-	TMPDIR=$PWD
-	eval '
-		cat <<- EOF
-		hi
-		EOF
-		for i in a b ; do
-			cat <<- EOF
-			more
-			EOF
-		done
-	    ' &
-	sleep 1
-	echo Left overs: *
-expected-stdout:
-	hi
-	more
-	more
-	Left overs: *
----
-
-name: heredoc-tmpfile-2
-description:
-	Check that heredoc temp files aren't removed too soon or too late.
-	Heredoc in function, multiple calls to function.
-stdin:
-	TMPDIR=$PWD
-	eval '
-		foo() {
-			cat <<- EOF
-			hi
-			EOF
-		}
-		foo
-		foo
-	    ' &
-	sleep 1
-	echo Left overs: *
-expected-stdout:
-	hi
-	hi
-	Left overs: *
----
-
-name: heredoc-tmpfile-3
-description:
-	Check that heredoc temp files aren't removed too soon or too late.
-	Heredoc in function in loop, multiple calls to function.
-stdin:
-	TMPDIR=$PWD
-	eval '
-		foo() {
-			cat <<- EOF
-			hi
-			EOF
-		}
-		for i in a b; do
-			foo
-			foo() {
-				cat <<- EOF
-				folks $i
-				EOF
-			}
-		done
-		foo
-	    ' &
-	sleep 1
-	echo Left overs: *
-expected-stdout:
-	hi
-	folks b
-	folks b
-	Left overs: *
----
-
-name: heredoc-tmpfile-4
-description:
-	Check that heredoc temp files aren't removed too soon or too late.
-	Backgrounded simple command with here doc
-stdin:
-	TMPDIR=$PWD
-	eval '
-		cat <<- EOF &
-		hi
-		EOF
-	    ' &
-	sleep 1
-	echo Left overs: *
-expected-stdout:
-	hi
-	Left overs: *
----
-
-name: heredoc-tmpfile-5
-description:
-	Check that heredoc temp files aren't removed too soon or too late.
-	Backgrounded subshell command with here doc
-stdin:
-	TMPDIR=$PWD
-	eval '
-	      (
-		sleep 1	# so parent exits
-		echo A
-		cat <<- EOF
-		hi
-		EOF
-		echo B
-	      ) &
-	    ' &
-	sleep 2
-	echo Left overs: *
-expected-stdout:
-	A
-	hi
-	B
-	Left overs: *
----
-
-name: heredoc-tmpfile-6
-description:
-	Check that heredoc temp files aren't removed too soon or too late.
-	Heredoc in pipeline.
-stdin:
-	TMPDIR=$PWD
-	eval '
-		cat <<- EOF | sed "s/hi/HI/"
-		hi
-		EOF
-	    ' &
-	sleep 1
-	echo Left overs: *
-expected-stdout:
-	HI
-	Left overs: *
----
-
-name: heredoc-tmpfile-7
-description:
-	Check that heredoc temp files aren't removed too soon or too late.
-	Heredoc in backgrounded pipeline.
-stdin:
-	TMPDIR=$PWD
-	eval '
-		cat <<- EOF | sed 's/hi/HI/' &
-		hi
-		EOF
-	    ' &
-	sleep 1
-	echo Left overs: *
-expected-stdout:
-	HI
-	Left overs: *
----
-
-name: heredoc-tmpfile-8
-description:
-	Check that heredoc temp files aren't removed too soon or too late.
-	Heredoc in function, backgrounded call to function.
-stdin:
-	TMPDIR=$PWD
-	# Background eval so main shell doesn't do parsing
-	eval '
-		foo() {
-			cat <<- EOF
-			hi
-			EOF
-		}
-		foo
-		# sleep so eval can die
-		(sleep 1; foo) &
-		(sleep 1; foo) &
-		foo
-	    ' &
-	sleep 2
-	echo Left overs: *
-expected-stdout:
-	hi
-	hi
-	hi
-	hi
-	Left overs: *
----
-
--- bin/ksh/tests/syntax.t
+++ /dev/null
@@ -1,10 +0,0 @@
-name: syntax-1
-description:
-	Check that lone ampersand is a syntax error
-stdin:
-	 &
-expected-exit: e != 0
-expected-stderr-pattern:
-	/syntax error/
----
-
--- bin/ksh/tests/README
+++ /dev/null
@@ -1,22 +0,0 @@
-Tests can be assigned categories to restrict what program they
-are applied to (eg, pdksh, ksh88, etc.).  The following are
-a list of names to be used for various shells (to keep things
-consistent):
-
-    sh		generic		any v7 bourne shell like thing
-    sh-v	generic		any system V bourne shell like thing
-    ksh		generic		any ksh
-    posix	generic		basic posix shell
-    posix-upu	generic		`user portability utility' options
-    sh-v7	specific	the real v7 bourne shell
-    sh-sysv	specific	the real sysv bourne shell
-    pdksh	specific	public domain ksh
-    ksh88	specific	at&t ksh88
-    ksh93	specific	at&t ksh93
-    bash	specific	GNU bourne-again shell
-
-The idea is to categorize all the tests according to the `best match'
-(most generic thing).  All generics that apply should be specified.
-Generally, at most one specific shell will be given.
-
-At the moment, most (all) tests have not been categorized (any volunteers?).
--- bin/ksh/tests/read.t
+++ /dev/null
@@ -1,58 +0,0 @@
-#	$OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
-
-#
-# 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 separators 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]
----
-


More information about the Midnightbsd-cvs mailing list