oksh-noxz

[fork] Portable OpenBSD ksh, based on the Public Domain Korn Shell (pdksh).
git clone https://noxz.tech/git/oksh-noxz.git
oksh-noxz

commit: e3fc9d2684c8a8133f5017720fa2da7631677b76
parent: abe2dfdf4c2874f27993e7dedbf236868e6afe79
author: Brian Callahan <dodonpachi-github@mailinator.com>
date:   Sun, 17 Sep 2017 17:13:35 -0400
Update to latest OpenBSD ksh code. Add Cygwin support.
DBUG-REPORTS1398--------
MCVS/Entries101+-
MCVS/Entries.Log1+
MCVS/Root2+-
DChangeLog1600---------
DChangeLog.03589--------------------
MGNUmakefile29+-
DIAFA-PACKAGE18-
DINSTALL151-
MMakefile7+-
DNEWS662----
MNOTES253+-
MPROJECTS5+-
MREADME.md4+-
MREADME.pdksh185+-
Malloc.c71+-
Mc_ksh.c133+-
Mc_sh.c158+-
Mc_test.c18+-
Mc_ulimit.c11+-
Mconfig.h18+-
Medit.c156+-
Medit.h34+-
Memacs.c237+-
Meval.c95+-
Mexec.c159+-
Mexpand.h19+-
Mexpr.c22+-
Mhistory.c667++--
Mio.c28+-
Mjobs.c179+-
Dksh_limval.h13-
Mlex.c133+-
Mlex.h42+-
Mmail.c22+-
Mmain.c190+-
Mmisc.c91+-
Dmknod.c91-
Moksh.1685++--
Mpath.c49+-
Mportable/linux/linux.h36+-
Aportable/linux/unvis.c285++
Aportable/linux/vis.c242++
Aportable/linux/vis.h93+
Mportable/netbsd/netbsd.h4+-
Dproto.h267--
Msh.165+-
Msh.h368+-
Mshf.c233+-
Mshf.h5+-
Msyn.c132+-
Mtable.c32+-
Mtable.h55+-
Mtrap.c21+-
Mtree.c56+-
Mtree.h14+-
Mtty.c44+-
Mtty.h24+-
Mvar.c128+-
Mvi.c552+--
Avis.c243++
61 files changed, 3478 insertions(+), 10747 deletions(-)
diff --git a/BUG-REPORTS b/BUG-REPORTS
@@ -1,1398 +0,0 @@
-$OpenBSD: BUG-REPORTS,v 1.19 2013/11/28 10:33:37 sobrado 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@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@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@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 function is autoloaded,
-  ksh complains the definition file didn't define the function, even if it did.
-  [see Mail.6:52]
-  [fixed in 5.2.0 - exec.c(comexec): when checking if defined, use cp,
-
-x pdksh 5.1.3, ICS unix 3.2 (reported by Robert Clark): auto configuration
-  test for memmove doesn't work
-  [see Mail.6:65]
-  [fixed in 5.2.0 - special cases added for memmove, bcopy, memset]
-
-x pdksh 5.1.3, Unixware (Intel-SVR4.2) (reported by Thanh Ma): auto
-  configuration test for memset doesn't work; same for rlimit type.
-  [see Mail.6:67]
-  [fixed in 5.2.0 - special cases added for memmove, bcopy, memset; rlim_t
-   configuration stuff re-arranged]
-
-x pdksh 5.1.3, - (reported by Mike Jetzer + fix): . in vi doesn't work
-  after history motion or after one command is completed and another is being
-  edited.
-  [see Mail.6:85]
-  [fixed in 5.2.0 - fix up classify table, special case for empty initial
-   insert]
-
-x pdksh 5.1.3, - Janjaap van Velthooven: ^v (version) missing in vi mode.
-  [see Mail.6:98]
-  [fixed in 5.2.0 - added]
-
-x pdksh 5.1.3, - : y% on or before right bracket/paren/brace doesn't yank the
-  brackets - just what is in the brackets...
-  [fixed in 5.2.0 - changes to vi.c(domove,vi_cmd)]
-
-x pdksh 5.1.3, - (reported by Rob Mayoff): [[ ]] command doesn't do lazy
-  evaluation.
-  [see Mail.7:2]
-  [fixed in 5.2.1 - test routines re-arranged to deal with this]
-
-x pdksh 5.1.3, - (reported by Will Renkel): "r | more" doesn't work (nothing
-  is sent to more).
-  [see Mail.7:13]
-  [fixed in 5.2.0 - history commands now done in c_fc, not pushed onto input
-   stack]
-
-x pdksh 5.1.3, - (reported by Rod Byrne, John Rochester): if a program leaves
-  the non-blocking (O_NONBLOCK) flag set after it exists, the shell
-  exits (multiple eofs).
-  [see Mail.7:15,16,51]
-  [fixed in 5.2.0: O_NONBLOCK is reset if read fails with EAGAIN,EWOULDBLOCK]
-
-x pdksh 5.1.3, - (reported by Dale DePriest + fix): emacs: can't delete chars
-  from pattern in incremental search mode.
-  [see Mail.7:17]
-  [fixed in 5.2.0 - handle it]
-
-x pdksh 5.1.3, Linux 1.2.2 (reported by Fritz Heinrichmeyer + fix): siglist.sh
-  doesn't work due to bug in bash 1.4.3 (trap is called incorrectly in
-  subshell causing temp file to be removed prematurely).
-  [see Mail.7:21]
-  [fixed in 5.2.0 - clear all traps in subshell so file isn't removed]
-
-x pdksh 5.1.3, - (reported by Dale DePriest + fix): emacs: can't prefix
-  commands with more than single digit; many commands don't use nnumber
-  prefix.
-  [see Mail.7:26,40]
-  [fixed in 5.2.0 - x_set_arg reads sequence of numbers, other commands
-  changed to use x_arg]
-
-x pdksh 5.1.3, - (reported by Dale DePriest): fc command line parsing
-  (and its interaction with history alias) doesn't act like at&t ksh:
-  history -40 gives bad option 4 error.
-  [see Mail.7:41,49]
-  [fixed in 5.2.1 - kludge parsing of -40 (numbers are option letters)]
-
-x pdksh 5.1.3, - (reported by Dale DePriest): if PS1 contains paramaters that
-  get expanded, and if those parameters contain any ! characters, the !'s get
-  changed to history numbers.
-  [see Mail.7:44]
-  [fixed in 5.2.0 - substitution done after ! and !! substitution]
-
-x pdksh 5.1.3, - (reported by Steve Wallis): set -a (set -o allexport) has
-  no effect.
-  [see Mail.7:47]
-  [fixed in 5.2.0 - changes to c_read, c_getopts, and comexec]
-
-x pdksh 5.1.3, - (reported by Alexander S. Jones): (sleep 10000&) waits for
-  the sleep to complete.
-  [see Mail.7:54]
-  [fixed in 5.2.0 - execute() case TASYNC clears EXEC flag in call to execute]
-
-x pdksh 5.1.3, - (reported by Will Renkel): positional parameters can't be
-  accessed within temporary variable assignments (eg, "FOO=$1 blah" doesn't
-  set FOO to $1.
-  [see Mail.7:57]
-  [fixed in 5.2.0 - var.c(newblock) - copy argc/argv from previous environment]
-
-x pdksh 5.1.3, SCO unix ? (reported by Sean Hogan): job control stuff doesn't
-  work as sco doesn't do job control operations on /dev/tty.
-  [see Mail.7:30,43,69,70,74]
-  [fixed in 5.2.0 - don't try opening /dev/tty if on SCO]
-
-x pdksh 5.1.3, - (reported with fix by Mike Jetzer): vi globing tacks
-  * at the end of files even if there are globing chars in last component
-  of filename (at&t ksh does not).
-  [see Mail.7:71]
-  [fixed in 5.2.0 - don't append * if there are unescaped globing chars]
-
-x pdksh 5.1.3, - (reported with fix by Gabor Zahemszky): typoes in acconfig.h,
-  sh.h uses SVR3_PGRP insteda of SYSV_PGRP.
-  [see Mail.7:87]
-  [fixed in 5.2.0]
-
-x pdksh 5.1.3, - (reported by Gabor Zahemszky): emacs doesn't have ^[^].
-  [see Mail.7:87]
-  [fixed in 5.2.0 - added search-char-backward]
-
-x pdksh 5.2.0, - (reported by David Tamkin): pwd -P doesn't strip .. and .
-  properly.
-  [see Mail.7:98]
-  [fixed in 5.2.0 - include ksh_stat.h in c_ksh.c]
-
-x pdksh 5.2.0, - (reported by Dale DePriest): unistd.h config test
-  doesn't include sys/types before dirent.h.
-  [see Mail.8:2]
-  [fixed in 5.2.0]
-
-x pdksh 5.2.0, - (reported by Robert Gallant): emacs file/command completion
-  code can clobber memory.
-  [see Mail.8:11]
-  [fixed in 5.2.1 - wrong variable being checked in buffer growing in
-   emacs.c(compl_file,compl_command)]
-
-x pdksh 5.2.0, - (reported by David Tamkin): when CDPATH set and cd'ing to a
-  directory that doesn't exist, the error message contains the last element
-  of the CDPATH.
-  [see Mail.8:8]
-  [fixed in 5.2.0 - fixed error message]
-
-x pdksh 5.2.0, - (reported by David Tamkin): if PS1 has an error in it
-  (eg, parameter expansion error), the shell loops forever printing
-  the error.
-  [see Mail.8:32]
-  [fixed in 5.2.3 - create error handling environment while expanding PS1]
-
-x pdksh 5.2.0, Coherent machines (reported by Gabor Zahemszky): insert after
-  movement in emacs mode replaces all chars with first char on line.
-  System's bcopy doesn't handle overlapping src/dst.
-  [see Mail.8:38,43]
-  [fixed in 5.2.1 - check for broken memmove/bcopy in aclocal.m4]
-
-x pdksh 5.2.0, - (reported by Gabor Zahemszky): ^[= in vi prints empty
-  strings for directory matches if markdirs is set.
-  [see Mail.8:48]
-  [fixed in 5.2.1 - skip trailing /'s before looking for last /]
-
-x pdksh 5.2.0, - (reported by Gabor Zahemszky): <ESC>^H bound to del-back-char
-  not del-back-word
-  [see Mail.8:50-52]
-  [fixed in 5.2.1 - fixed x_emacs_keys]
-
-x pdksh 5.2.1, - (reported by David Tamkin): compile fails due to lack
-  of c_test.h
-  [see Mail.8:58]
-  [fixed in 5.2.2 - fixed put c_test.h in distribution]
-
-x pdksh 5.2.2, - (reported by Simon J. Gerraty): hist_source not being
-  initialized in complex history.
-  [see Mail.8:64]
-  [fixed in 5.2.3 - set it in second hist_init()]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): set -A does not reset
-  the array contents.
-  [see Mail.8:65]
-  [fixed in 5.2.3 - changed var.c(unset) to unset whole array if appropriate]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): getopts stops after an error;
-  at&t ksh carries on with next option.
-  [see Mail.8:65]
-  [fixed in 5.2.3 - remove GI_DONE flag from ksh_getopt()]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): getopts prints shell name
-  twice in error messages.
-  [see Mail.8:65]
-  [fixed in 5.2.3 - added GI_NONAME flag]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): pdksh's test doesn't know about
-  /dev/fd/n.
-  [see Mail.8:65]
-  [fixed in 5.2.3 - added test_stat() and test_eaccess()]
-
-x pdksh 5.2.2, - (reported by Thomas Gellekum): config test for memmove/bcopy
-  missing semi-colon
-  [see Mail.8:67]
-  [fixed in 5.2.3]
-
-x pdksh 5.2.2, - (reported by Donald Craig): fc string doesn't find string
-  if it is the most recent command.
-  [see Mail.8:76]
-  [fixed in 5.2.3 - fixed off by one error in history.c(hist_get)]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): pdksh doesn't do the
-  "You have running jobs" when user attempts to log out.
-  [see Mail.8:74]
-  [fixed in 5.2.3 - added set -o nohup option with supporting code]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): configure test for
-  broken memmove/bcopy doesn't work.
-  [see Mail.8:93]
-  [fixed in 5.2.3 - fixed test to copy overlapping buffers]
-
-x pdksh 5.1.3, - (reported by <wendt@sv5.mch.sni.de>): doesn't compile on
-  solaris 5.x with COMPLEX_HISTORY defined.
-  [see Mail.8:98]
-  [fixed in 5.2.3 - undef COMPLEX_HISTORY if flock not available]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): tilde expansion not preformed
-  in word part of ${foo[-+=?} substitution.
-  [see Mail.9:7]
-  [fixed in 5.2.3 - allow ~foo to end in a close brace]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): "fc 30" edits from 30 to
-  most recent history (should be just 30).
-  [see Mail.9:7]
-  [fixed in 5.2.3 - if !-l and no last given, use first]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): [many problems with man page]
-  [see Mail.9:12]
-  [fixed in 5.2.3 - fixed problems]
-
-x pdksh 5.2.2, - (reported by Gabor Zahemszky): #else followed by non-comment
-  in sigact.c.
-  [see Mail.9:13]
-  [fixed in 5.2.3 - turn it into a comment]
-
-x pdksh 5.2.2, - (reported with fix by Gabor Zahemszky): two argument form of
-  cd doesn't work.
-  [see Mail.9:14]
-  [fixed in 5.2.3 - in c_cd(), use current_wd not path]
-
-x pdksh 5.2.2, - (reported with fix by Gabor Zahemszky): command -V doesn't
-  report reserved words.
-  [see Mail.9:30]
-  [fixed in 5.2.3 - in c_whence(), look for reserved words if vflag set]
-
-x pdksh 5.2.3, - (reported by Dale DePriest): at&t's tbl wants space
-  between font specification and end of table descrption (ie, fB . not
-  fB.).
-  [see Mail.9:41]
-  [fixed in 5.2.4 - put spaces in]
-
-x pdksh 5.2.3, - (reported by David Tamkin & Claus L{gel Rasmussen): PS1
-  isn't imported from environment anymore.
-  [see Mail.9:43,76]
-  [fixed in 5.2.4 - main: don't set PS1 if it is already set]
-
-x pdksh 5.2.3, - (reported by Gary Rafe): If PS1 contains newlines, vi
-  editing mode dones't redraw lines properly.
-  [see Mail.9:63]
-  [fixed in 5.2.4 - added prompt_skip stuff to vi/emacs]
-
-x pdksh 5.2.3, - (reported & fixed by Mike Jetzer): cd: error message if
-  directory didn't exist was wrong.
-  [see Mail.9:66]
-  [fixed in 5.2.4 - print correct string in error message]
-
-x pdksh 5.2.3, - (reported & fixed by Mike Jetzer): vi: <ESC>* shouldn't append
-  a * if word contains a $.
-  [see Mail.9:66]
-  [fixed in 5.2.4 - vi.c(glob_word): check for $ in word, check for null
-   expansion]
-
-x pdksh 5.2.3, - (reported & fixed by Mike Jetzer): vi: <ESC>= doesn't
-  list expansions in column form.
-  [see Mail.9:66]
-  [fixed in 5.2.4 - use pr_menu to print things nicely]
-
-x pdksh 5.2.3, - (reported Larry Bouzane): should be a way of installing
-  binary/man page as pdksh instead of ksh.
-  [see Mail.9:100]
-  [fixed in 5.2.4 - use the --enable-shell=pdksh option to configure]
-
-x pdksh 5.2.3, - (reported by Gabor Zahemszky): [many problems with man
-  page]
-  [see Mail.10:20]
-  [fixed in 5.2.4 - fixed problems]
-
-x pdksh 5.2.3, - (reported by Gabor Zahemszky): exec 1<&9 reports
-  error with ">&9" in it.
-  [see Mail.10:20]
-  [fixed in 5.2.4 - changed iosetup()]
-
-x pdksh 5.2.3, - (reported by Gabor Zahemszky): man page doesn't document
-  /dev/fd/N
-  [see Mail.10:20]
-  [fixed in 5.2.4 - updated manual]
-
-x pdksh 5.2.3, - (reported by Ted Coady): [[ foo/bar = foo* ]]
-  fails; should succeed.
-  [see Mail.10:32]
-  [fixed in 5.2.4 - fixed problem in exec.c(dbteste_getopnd)]
-
-x pdksh 5.2.3, - (reported by Ruei-wun Tu): make on NeXT/NeXTSTEP 3.3
-  doesn't understand .PRECIOUS target and so does nothing.
-  [see Mail.10:43]
-  [fixed in 5.2.4 - moved .PRECIOUS after all in Makefile.in]
-
-x pdksh 5.2.3, - (reported & fixed by Paul Borman): shell doesn't kill
-  foreground process when SIGHUP received; Also, CONT sent before HUP.
-  [see Mail.10:44]
-  [fixed in 5.2.4 - j_exit now sends HUP to foreground process]
-
-x pdksh 5.2.3, AIX 3.2.5 (reported by Ian Portsmouth): C compiler compains
-  about sigtraps[] being re-declared in trap.c.
-  [see Mail.10:73]
-  [fixed in 5.2.4 - use cpp define to avoid bogus re-declaration error]
-
-x pdksh 5.2.3, - (reported by Michael Haardt): ENV should not be
-  included if shell is compiled as sh and posix option not set.
-  [see Mail.10:83]
-  [fixed in 5.2.4 - only include ENV if POSIX, if compiled as sh]
-
-x pdksh 5.2.3, - (reported & fixed by DaviD W. Sanderson): case statements
-  don't allow {/} in place of IN/ESAC.
-  [see Mail.10:77,78]
-  [fixed in 5.2.4 - allow {/} in case statements]
-
-x pdksh 5.2.3, - (reported by Larry Daffner): $? is incorrectly zero'd
-  at start of traps.
-  [see Mail.11:9]
-  [fixed in 5.2.4 - don't clear exstat in main.c(shell)]
-
-x pdksh 5.2.3, - (reported by Frank "Crash" Edwards): configure on linux XXX
-  doesn't detect the presence of lstat().
-  [see Mail.11:36]
-  [fixed in 5.2.4 - change configure to include <sys/stat.h> in lstat() test]
-
-x pdksh 5.2.3, - (reported by Gabor Zahemszky): typeset -f dumps core
-  in the after using autoload functions.
-  [see Mail.11:74?]
-  [fixed in 5.2.4 - c_typeset no longer traverses the array link for functions]
-
-x pdksh 5.2.3, - (reported by Gabor Zahemszky): typeset -f does not report
-  undefined autoload functions
-  [see Mail.11:74?]
-  [fixed in 5.2.4 - c_typeset: don't ignore unset functions]
-
-x pdksh 5.2.3, - (reported by Dale DePriest): alias -t -r does not
-  reset aliases.
-  [see Mail.11:99]
-  [fixed in 5.2.4 - c_alias: call ksh_getopt_reset() before calling c_unalias]
-
-x pdksh 5.2.3, - (reported & fixed by Jason Tyler): 'echo abc^Jfc -e - a=b e'
-  echos b, not bbc.
-  [see Mail.11:100?]
-  [fixed in 5.2.4 - hist_replace: use s, not last]
-
-x pdksh 5.2.3, - (reported by Jason Tyler): 'fc -e -' when there is
-  no history causes infinite loop.
-  [see Mail.11:100?]
-  [fixed in 5.2.4 - histbackup: allow histptr to go below history]
-
-x pdksh 5.2.4, - (reported by David Tamkin): jmp_buf is used instead of
-  sigjmp_buf.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.5 - added ksh_jmp_buf and defined appropriately]
-
-x pdksh 5.2.4, - (reported by Stephen Coffin): /<RETURN> in vi mode does not
-  repeat last search.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.5 - vi.c(vi_hook) - make it repeat last search]
-
-x pdksh 5.2.4, - (reported by Gabor Zahemszky): functions containing select
-  commands aren't printed correctly by typeset.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.5 - tree.c(ptree) - add case for TSELECT]
-
-x pdksh 5.2.4, - (reported & fixed by Stefan Dalibor): COLUMNS isn't set on
-  shell start up (and window size is ignored) 'cause tty_fd isn't valid when
-  x_init() is called.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.5 - call x_init() after j_init() is called]
-
-x pdksh 5.2.4, - (reported by Will Renkel): "echo -" just prints a blank
-  line - should print the minus.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.5 - c_ksh.c(c_print): don't do argument parsing on lone -]
-
-x pdksh 5.1.3, - (reported by Gabor Zahemszky): emacs doesn't have ^[*.
-  [see Mail.7:87]
-  [fixed in 5.2.5]
-
-x pdksh 5.2.3, - (reported by Mike Jetzer): in vi, <ESC>= doesn't append
-  a / after directories.
-  [see Mail.9:66]
-  [fixed in 5.2.5]
-
-x pdksh 5.2.0, - (reported by Gabor Zahemszky): can set readonly variables
-  via command assignments (eg, "readonly x=y; x=z /bin/echo hi" should
-  fail and doesn't).
-  [see Mail.8:50,65]
-  [fixed in 5.2.5 - LOCAL_COPY flag passed from comexec() down to local()]
-
-x pdksh 5.2.4, - (reported by Tom Karches): history: "r old=new", with
-  no commands prefix given, prints "fc: too mnay arguments" - it should
-  do the subst on the previous command.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.5]
-
-x pdksh 5.2.3, - (reported by Vigen Pogosyan): assignments in $(( ... ))
-  remember the base that was assigned in pdksh - does not in at&t ksh.
-  [see Mail.10:54]
-  [fixed in 5.2.5: uset setint() in expr.c(evalexpr)]
-
-x pdksh 5.2.4, - (reported by Gabor Zahemszky): emacs: ^O steps down
-  two lines (should be 1).
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.5: convert history line to command number, then convert back]
-
-x pdksh 5.2.3, - (reported by David Gast(? gast@twinsun.com)): fc -ln -1 -1
-  reports the current command, not the previous command.
-  [see Mail.10:49]
-  [fixed in 5.2.5]
-
-x pdksh 5.2.3, - (reported by Matthew Green): foo=`^Jecho bar` doesn't
-  set foo to bar (foo is empty).
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.5: syn.c: set multiline.on when source is SSTRING]
-
-x pdksh 5.2.5, - (reported by Gabor Zahemszky): continue/break: if n
-  is too big, shell prints internal error message.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.6: fix c_brkcont to use last loop if n is too big]
-
-x pdksh 5.2.5, - (reported by Gabor Zahemszky): set: +o in ksh93
-  prints command that sets various options.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.6: changed misc.c(printoptions)]
-
-x pdksh 5.2.5, - (reported by Gabor Zahemszky): COLUMNS/LINES variables
-  are not exported.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.6: use typeset() in edit.c(x_init) to export COLUMNS/LINES]
-
-x pdksh 5.2.5, - (reported by Gabor Zahemszky): emacs: <ESC><ESC> puts
-  space after completed directories.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.6: check for single/non-directory match in emacs.c(do_complete)]
-
-x pdksh 5.2.5, - (reported by Gabor Zahemszky): vi: # removes comment
-  and executes if command already commented.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.6: added vi.c(do_comment)]
-
-x pdksh 5.2.7, - (reported by Adrian Marsh): test doesn't have == operator.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: added == to c_test.c operator table]
-
-x pdksh 5.2.7, - (reported by Mike Jetzer): pdksh sets/exports COLUMNS/LINES
-  which causes applications not to respond to window size changes.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: COLUMNS/LINES no longer exported automatically]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): getopts sets OPTIND differently
-  that at&t ksh when a bad option is given.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: OPTIND not set if option was bad - fragile fix - may go away]
-
-x pdksh 5.2.7, - (reported with fix by Marc Olzheim): sh version shouldn't
-  have mail check stuff, macro expansion in PS[0-9].
-  [fixed in 5.2.8: added lots of ifdefs]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): sub commands in PS1 cause
-  a warning message to be printed.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: lex.c(set_prompt) - don't print the warning message]
-
-x pdksh 5.2.7, - (reported by Tom Watson): some environment variables
-  (eg, PATH) are converted to uppercase on 16-bit int machine.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: struct tbl.flag (32 bit thing) was being treated as an
-   int in some places]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): unset always returns 0 - should
-  return 1 if variable/function is not set.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: fixed c_sh.c(c_unset)]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): select should only print the
-  menu the first time, if REPLAY is empty, or if a blank line is entered.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: fixed up exec.c(execute,do_selectargs)]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): shell reports "cannot execute"
-  error if file exists, even if . not in path.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: fixed up exec.c(comexec)]
-
-x pdksh 5.1.3, - (reported with partial fix by ra@rhi.hi.is): shell doesn't
-  listen to sigwinch.
-  [see Mail.7:7 and related]
-  [fixed in 5.2.8: changed edit.c(x_init) to catch sigwinch]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): typeset doesn't report
-  variables that have attributes (like export) but no values.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: fixed up c_ksh.c(c_typeset)]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): error message printed as
-  a result of "set -o nounset" is different from at7t ksh.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: fixed error messges in eval.c]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): vi/emacs: when listing
-  command/file completions, should go back at most one space.  Also, should
-  allow completions on zero length names.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: fixed edit.c(x_locate_word); now allows zero-length
-   file completions (but not command)]
-
-* pdksh 5.2.7, - (reported by Gabor Zahemszky): emacs: <esc># doesn't do
-  the comment thing.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: added emacs.c(x_comment) et al.]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): arithmatic expressions
-  containing variables not expanded as in at&t ksh. eg, "x=1+2, let y=x"
-  fails.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: added evaling/INEXPREVAL/ET_RECURSIVE code to expr.c]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): unsetting the 0th element
-  of an array kills the whole array.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: var.c(unset) - allow ARRAY to be preserved]
-
-x pdksh 5.2.7, - (reported by Gabor Zahemszky): unsetting a function while
-  it is being executed can result in core dump.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: table.c(texpand) - dont free if FINUSE is set]
-
-* pdksh 5.2.7, - (reported by Gabor Zahemszky): exec 3<&p doesn't close
-  shells copy of the coprocess file desc.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.8: coprocess stuff made to act like ksh93 co-processes]
-
-x pdksh 5.2.8, - (reported with fix by Lars Hecking): doesn't compile as
-  sh - c_ksh.c and jobs.c boom out.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.9: added ifdef KSH to appropriate places]
-
-x pdksh 5.2.8, - (reported by Paolo Zeppegno): assignments containing brackets
-  are treated as commands.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.9: fixed bug in vars.c(skip_wdvarname).]
-
-x pdksh 5.2.5, - (reported by Adrian Marsh): configuration on Linux FT fails.
-  Caused by configure script using -g flag - gcc passes -lg to ld, ld fails
-  to find -lg (autoconf or Linux FT bug).
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.9: changed autoconf's -g test to do linking as well.]
-
-x pdksh 5.2.8, Solaris 2.5.1 (reported by Stefan Dalibor): 2 tests
-  (xxx-exec-environment-1 and 2) fail because printenv isn't found.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.9: changed test to use env instead]
-
-x pdksh 5.2.8, - (reported by Stefan Dalibor): shell assumes 80 columns when
-  it starts up if COLUMNS is set correctly in the environ.
-  [see Mail.XXX:XXX]
-  [fixed in 5.2.9: fixed so window size is checked at startup]
-
-x pdksh 5.2.8, NeXT machines (reported by Kai Wong): clock_t, which lives
-  in sys/time.h, isn't found by configure (causes warning messages).
-  [fixed in 5.2.9: configure now checks in sys/time.h]
-
-x pdksh 5.2.3, - (reported by Mike Jetzer): in vi, <ESC>= on word with ~
-  but no /, beeps (or prints final path component?).
-  [see Mail.9:66]
-  [fixed in 5.2.9: fixed edit.c(add_glob) so no * is appended to ~username]
-
-x pdksh 5.1.3, NeXT machines (reported by Jason Baugher): job control doesn't
-  work on NeXT machines (both m68k and x86 based) in rlogin sessions.
-  (caused by open("/dev/tty") failing - rlogin on NeXT doesn't set up
-  controlling tty properly).
-  [see Mail.7:29]
-  [fixed in 5.2.9: added hack to main to get a controlling tty]
-
-x pdksh 5.2.8, NeXT 3.2 (reported by Andrew S Townley): the output of the
-  siglist.sh script fills the disk.  Also, the signal list generated (by the
-  fixed script) is mostly empty.
-  [see Mail.XXX]
-  [fixed in 5.2.9: fixed siglist.sh script to avoid infinite loops.  Added
-   comment to README warning of problem with NeXT's native cc -E]
-
-x pdksh 5.2.9, - (reported by Loris Talpo): long prompts are messed up in
-  vi mode.
-  [see Mail.XXX]
-  [fixed in 5.2.9: lex.c(pprompt) was broken]
-
-x pdksh 5.2.9, - (reported by Will Renkel): a double backslash followed
-  by a newline in an unquoted here document results in one of the backslashes
-  and the newline being stripped.
-  [see Mail.XXX]
-  [fixed in 5.2.10: fixed backslash-newline processing in lex.c]
-
-x pdksh 5.2.9, - (reported by Han Holl): read x?prompt doesn't work
-  on non-interactive shells when the input is from a tty.
-  [see Mail.XXX]
-  [fixed in 5.2.10: changed test in c_read() from FTALKING to isatty]
-
-x pdksh 5.2.10, - (reported by Dale DePriest): expanding aliases causes
-  extra input.
-  [see Mail.XXX]
-  [fixed in 5.2.11: fixed syn.c(c_list).]
-
-x pdksh 5.2.10, - (reported by John Rochester): window size changes don't
-  happen on Dec unix (osf) because TIOCGWINSZ is defined in <sys/ioctl.h>
-  not in <termios.h>.
-  [see Mail.XXX]
-  [fixed in 5.2.12: sys/ioctl.h included with termios.h/termio.h if possible]
-
-x pdksh 5.2.11, - (reported by Randy Bouzane): aliases in command substitutions
-  result in code dumps.
-  [see Mail.XXX]
-  [fixed in 5.2.12: lex.c(getsc__): break if eof is read]
-
-x pdksh 5.2.11, - (reported by Will Renkel): aliases containing ;<newline>
-  or <newline><newline> aren't fully read/executed.
-  [see Mail.XXX]
-  [fixed in 5.2.12: syn.c(get_command): call inalias()]
-
-x pdksh 5.2.11, SGI/IRIX 5.2 (reported by bert@xpilot.com): pipelines
-  containing built in commands hang forever.
-  [see Mail.XXX]
-  [fixed in 5.2.12: fixed pgrp sync code in jobs.c]
-
-x pdksh 5.2.11, - (reported by Herbert Thielen via Larry Daffner): shell leaves
-  temp files around when executing shell scripts that have functions with
-  here documents which end in an exec.
-  [see Mail.XXX]
-  [fixed in 5.2.12: call main.c(cleanup_proc_env()) from exec.c(execute()).]
-
-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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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]
-
diff --git a/CVS/Entries b/CVS/Entries
@@ -1,55 +1,46 @@
-/BUG-REPORTS/1.19/Thu Nov 28 10:33:37 2013//
-/CONTRIBUTORS/1.10/Mon Feb  6 16:47:07 2006//
-/ChangeLog/1.16/Thu Nov 28 10:33:37 2013//
-/ChangeLog.0/1.5/Thu Nov 28 10:33:37 2013//
-/IAFA-PACKAGE/1.7/Wed Jul 14 13:37:23 1999//
-/INSTALL/1.1.1.1/Wed Aug 14 06:19:10 1996//
-/LEGAL/1.2/Thu Jul 17 20:59:43 2003//
-/Makefile/1.29/Mon Dec  2 20:41:01 2013//
-/NEWS/1.15/Thu Aug  2 11:05:54 2007//
-/NOTES/1.12/Thu Nov 28 10:33:37 2013//
-/PROJECTS/1.7/Thu Nov 28 10:33:37 2013//
-/README/1.10/Mon Mar 10 03:48:16 2003//
-/alloc.c/1.8/Mon Jul 21 17:30:08 2008//
-/c_ksh.c/1.34/Tue Dec 17 16:37:05 2013//
-/c_sh.c/1.45/Wed Aug 27 08:26:04 2014//
-/c_test.c/1.18/Sun Mar  1 20:11:06 2009//
-/c_test.h/1.4/Mon Dec 20 11:34:26 2004//
-/c_ulimit.c/1.19/Thu Nov 28 10:33:37 2013//
-/config.h/1.14/Mon Mar 14 21:20:00 2011//
-/edit.c/1.40/Thu Mar 12 10:20:30 2015//
-/edit.h/1.9/Mon May 30 17:14:35 2011//
-/emacs.c/1.50/Wed Mar 25 12:10:52 2015//
-/eval.c/1.40/Sat Sep 14 20:09:30 2013//
-/exec.c/1.51/Sat Apr 18 18:28:36 2015//
-/expand.h/1.6/Wed Mar 30 17:16:37 2005//
-/expr.c/1.24/Mon Dec  8 14:26:31 2014//
-/history.c/1.40/Thu Nov 20 15:22:39 2014//
-/io.c/1.25/Mon Aug 11 20:28:47 2014//
-/jobs.c/1.41/Sat Apr 18 18:28:36 2015//
-/ksh.1/1.159/Wed Mar 25 12:10:52 2015//
-/ksh_limval.h/1.2/Sat Dec 18 20:55:52 2004//
-/lex.c/1.49/Tue Dec 17 16:37:06 2013//
-/lex.h/1.13/Sun Mar  3 19:11:34 2013//
-/mail.c/1.17/Thu Nov 28 10:33:37 2013//
-/main.c/1.55/Mon Feb  9 09:09:30 2015//
-/misc.c/1.40/Wed Mar 18 15:12:36 2015//
-/mknod.c/1.2/Tue Oct 27 23:59:21 2009//
-/path.c/1.12/Wed Mar 30 17:16:37 2005//
-/proto.h/1.35/Wed Sep  4 15:49:19 2013//
-/sh.1/1.128/Mon May  4 19:34:13 2015//
-/sh.h/1.33/Wed Dec 18 13:53:12 2013//
-/shf.c/1.16/Fri Apr 19 17:36:09 2013//
-/shf.h/1.6/Sun Dec 11 18:53:51 2005//
-/syn.c/1.29/Mon Jun  3 18:40:05 2013//
-/table.c/1.15/Sun Feb 19 07:52:30 2012//
-/table.h/1.8/Sun Feb 19 07:52:30 2012//
-/trap.c/1.23/Wed May 19 17:36:08 2010//
-/tree.c/1.20/Wed Jun 27 07:17:19 2012//
-/tree.h/1.10/Mon Mar 28 21:28:22 2005//
-/tty.c/1.10/Sun Aug 10 02:44:26 2014//
-/tty.h/1.5/Mon Dec 20 11:34:26 2004//
-/var.c/1.41/Fri Apr 17 17:20:41 2015//
-/version.c/1.12/Wed Jul 14 13:37:24 1999//
-/vi.c/1.28/Wed Dec 18 16:45:46 2013//
-D/tests////
+/CONTRIBUTORS/1.10/Sun Sep 17 20:11:12 2017//
+/LEGAL/1.2/Sun Sep 17 20:11:12 2017//
+/Makefile/1.34/Sun Sep 17 20:11:49 2017//
+/NOTES/1.14/Sun Sep 17 20:11:49 2017//
+/PROJECTS/1.8/Sun Sep 17 20:11:49 2017//
+/README/1.16/Sun Sep 17 20:11:49 2017//
+/ksh.1/1.195/Sun Sep 17 20:11:49 2017//
+/sh.1/1.143/Sun Sep 17 20:11:49 2017//
+/alloc.c/1.17/Sun Sep 17 20:17:53 2017//
+/c_ksh.c/1.51/Sun Sep 17 20:17:53 2017//
+/c_sh.c/1.60/Sun Sep 17 20:17:53 2017//
+/c_test.c/1.23/Sun Sep 17 20:17:53 2017//
+/c_test.h/1.4/Sun Sep 17 20:17:53 2017//
+/c_ulimit.c/1.24/Sun Sep 17 20:17:53 2017//
+/config.h/1.16/Sun Sep 17 20:17:53 2017//
+/edit.c/1.57/Sun Sep 17 20:17:53 2017//
+/edit.h/1.11/Sun Sep 17 20:17:53 2017//
+/emacs.c/1.73/Sun Sep 17 20:17:53 2017//
+/eval.c/1.54/Sun Sep 17 20:17:53 2017//
+/exec.c/1.68/Sun Sep 17 20:17:53 2017//
+/expand.h/1.12/Sun Sep 17 20:17:53 2017//
+/expr.c/1.32/Sun Sep 17 20:17:53 2017//
+/history.c/1.71/Sun Sep 17 20:17:53 2017//
+/io.c/1.35/Sun Sep 17 20:17:53 2017//
+/jobs.c/1.55/Sun Sep 17 20:17:53 2017//
+/lex.c/1.71/Sun Sep 17 20:17:53 2017//
+/lex.h/1.16/Sun Sep 17 20:17:53 2017//
+/mail.c/1.22/Sun Sep 17 20:17:53 2017//
+/main.c/1.83/Sun Sep 17 20:17:53 2017//
+/misc.c/1.59/Sun Sep 17 20:17:53 2017//
+/path.c/1.19/Sun Sep 17 20:17:53 2017//
+/sh.h/1.64/Sun Sep 17 20:17:53 2017//
+/shf.c/1.31/Sun Sep 17 20:17:53 2017//
+/shf.h/1.8/Sun Sep 17 20:17:53 2017//
+/syn.c/1.38/Sun Sep 17 20:17:53 2017//
+/table.c/1.23/Sun Sep 17 20:17:53 2017//
+/table.h/1.12/Sun Sep 17 20:17:53 2017//
+/trap.c/1.30/Sun Sep 17 20:17:53 2017//
+/tree.c/1.27/Sun Sep 17 20:17:53 2017//
+/tree.h/1.12/Sun Sep 17 20:17:53 2017//
+/tty.c/1.16/Sun Sep 17 20:17:53 2017//
+/tty.h/1.6/Sun Sep 17 20:17:53 2017//
+/var.c/1.59/Sun Sep 17 20:17:53 2017//
+/version.c/1.12/Sun Sep 17 20:17:53 2017//
+/vi.c/1.49/Sun Sep 17 20:17:53 2017//
+D
diff --git a/CVS/Entries.Log b/CVS/Entries.Log
@@ -1 +1,2 @@
+A D/tests////
 R D/tests////
diff --git a/CVS/Root b/CVS/Root
@@ -1 +1 @@
-anoncvs@anoncvs.comstyle.com:/cvs
+anoncvs@ftp4.usa.openbsd.org:/cvs
diff --git a/ChangeLog b/ChangeLog
@@ -1,1600 +0,0 @@
-Tue Jul 13 14:32:57 NDT 1999 Michael Rendell (michael@lyman.cs.mun.ca)
-
-	* made pdksh-5.2.14 distribution
-
-Wed Jun 30 17:42:54 NDT 1999 Michael Rendell (michael@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@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@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@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@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@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@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@deimos.cs.mun.ca)
-
-	* emacs.c(x_bound,bind_if_not_bound): new variable/function.
-	* 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@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@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@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@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@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@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@deimos.cs.mun.ca)
-
-	* exec.c(herein): restore source to osource after yylex().
-
-Mon May 10 12:14:40 NDT 1999 Michael Rendell (michael@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@panda.cs.mun.ca)
-
-	* main.c(initcom[]): PPID no longer read only.
-
-Mon Dec 14 17:09:52 NST 1998 Michael Rendell (michael@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@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@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@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@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@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@panda.cs.mun.ca)
-
-	* trap.c(inittrap): Don't assume sys_siglist[] has NSIG non-null
-	  entries (fix from clifford@clifford.at).
-
-Thu Aug  6 14:46:45 NDT 1998 Michael Rendell (michael@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@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@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@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@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@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@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@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@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@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@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@panda.cs.mun.ca)
-
-	* made pdksh-5.2.13 distribution
-
-Mon Oct 27 12:21:51 NST 1997 Michael Rendell (michael@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@panda.cs.mun.ca)
-
-	* exec.c(comexec): case CFUNC: set $0 to kshname if non-function
-	  function.
-
-$OpenBSD: ChangeLog,v 1.16 2013/11/28 10:33:37 sobrado Exp $
-
-Tue Oct 29 11:34:58 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.2.12 distribution
-
-Fri Oct 25 11:59:48 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(vi_cmd): case Cntl('i'): dont fall through, call complete_word().
-
-Tue Oct 22 17:38:21 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* table.h(USERATTRIB): new define.
-	* c_ksh.c(c_typeset): report unset params only if it has some
-	  interesting attributes.
-
-Tue Oct 22 15:54:39 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* jobs.c(exchild): changed NEED_PGRP_SYNC code so j_sync_pipe[1] isn't
-	  left open in 2nd+ children.
-
-Tue Oct 22 12:59:49 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* main.c(main): memset() env to 0.
-
-Mon Oct 21 12:53:44 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* main.c(cleanup_proc_env): new function.
-	* exec.c(execute): call cleanup_proc_env() before calling ksh_execve().
-
-Fri Oct 11 22:53:57 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(display): use ch not e->buf[cur] when printing character.
-
-Fri Oct 11 13:26:11 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* aclocal.m4(KSH_TIMES_CHECK,KSH_DUP2_CLEXEC_CHECK,KSH_OPENDIR_CHECK):
-	  changed sense of test so "yes" result is printed if you have a good
-	  system.
-	* aclocal.m4(KSH_C_FUNC_ATTR): changed return type of test_cnst to int.
-
-Fri Oct 11 13:05:40 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* syn.c(get_command): added inalias() call when setting cf = CONTIN.
-
-Thu Oct 10 16:22:03 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.c(getsc__): case SALIAS: if we read eof, break, don't continue.
-
-Tue Oct  8 13:14:00 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* aclocal.m4(KSH_TERM): added SYS_IOCTL_WITH_TERMIOS,
-	  SYS_IOCTL_WITH_TERMIO tests.
-	* tty.h: include <sys/ioctl.h> with <termios.h>/<termio.h>
-	  if possible.
-
-Tue Oct  8 11:42:36 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.2.11 distribution
-
-Tue Oct  8 11:02:54 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* syn.c(inalias): new function.
-	* syn.c(c_list): call inalias() instead of testing source->type.
-
-Mon Oct  7 17:00:40 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.2.10 distribution
-
-Mon Oct  7 16:23:53 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_sh.c(c_read): when printing prompt, use isatty, not FTALKING.
-
-Wed Oct  2 12:00:51 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.c(yylex): redirection stuff: save result of getsc() == '-'
-	  and use it for ungetsc().
-
-	* lex.h(struct source): moved ugbuf out of union so it can be used
-	  with alias stuff.
-	* lex.c(getsc__) case SALIAS: instead of appending a space, get the
-	  next character and stuff it in ugbuf.
-
-	* lex.c(getsc_,getsc__): getsc_() renamed to getsc__().
-	* lex.c(getsc_,getsc): getsc() macro renamed to getsc_().
-	* lex.c(backslash_skip,ignore_backslash_newline): new variables.
-	* lex.c(getsc): new macro that checks backslash_skip.
-	* lex.c(getsc_bn_,getsc_bn): getsc_bn() macro deleted (all calls
-	  replaced with getsc()); getsc_bn_ renamed to getsc_bn.
-	* lex.c(ungetsc_,ungetsc): ungetsc() macro deleted; renamed ungetsc_()
-	  to ungetsc().
-	* lex.c(yylex,ungetsc,getsc_bn): set and use backslash_skip,
-	  ignore_backslash_newline.
-	* lex.c(yylex): removed special cases for backslash-newline sequence,
-	  explicitly ignore backslash followed by eof.
-
-Mon Sep 30 17:14:41 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.2.9 distribution
-
-Mon Sep 30 12:52:21 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.c(pprompt): fixed usage of ntruncate.
-
-Thu Sep 19 17:43:33 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(KSH_SYSTEM_PROFILE): new define.
-	* main.c(main): use KSH_SYSTEM_PROFILE.
-
-	* aclocal.m4(KSH_OS_TYPE): added case for NEXT.
-
-Thu Sep 19 15:39:54 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* tty.c(tty_init): added hack for NeXT's rlogin's missing controlling
-	  tty.
-
-Mon Sep 16 11:18:10 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* edit.c(add_glob): don't append a * to a ~username.
-
-	* edit.c(x_init): set got_sigwinch before calling check_sigwinch().
-
-Wed Sep 11 14:38:38 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ksh.c(c_let): ifdef'd KSH.
-	* lex.h(SDPAREN),lex.c: ifdef'd KSH all uses of SDPAREN.
-	* lex.h(MDPAREN),syn.c: ifdef'd KSH all uses of MDPAREN.
-
-Mon Sep  9 16:18:03 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* aclocal.m4(AC_PROG_CC): replaced autoconf's version with
-	  modified version.
-
-	* configure.in(clock_t): check in sys/time.h as well.
-	* ksh_times.h: include ksh_time.h.
-	* ksh_time.h,ksh_times.h: added ifndef KSH_TIME_H/KSH_TIMES_H.
-
-Fri Sep  6 13:20:24 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* edit.c(promptlen): X\r hack for delimiting hidden characters
-	  in prompt.
-	  (Based on fix from Bill Kish)
-
-Tue Sep  3 11:03:26 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* Makefile.in: removed options.h from HDRS (also removed file).
-
-Thu Aug 29 10:04:01 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* aclocal.m4(KSH_MEMMOVE): added return 0 to end of main().
-
-Fri Aug 23 14:23:50 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* aclocal.m4,ksh_stat.h: changed S_IFFIFO to S_IFIFO.
-
-Fri Aug 23 09:58:09 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* var.c(skip_wdvarname): don't check for array if first char
-	  isn't [.
-
-Thu Aug 22 12:51:25 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* jobs.c: added ifdef KSH around Coproc_id/j->coproc_id usagae.
-	* c_ksh.c(c_read): added ifdef KSH around opipe.
-
-Tue Aug 20 09:41:32 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* configure.in: fixed quoting of sed LDSTATIC expression.
-
-Mon Aug 19 14:26:08 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.2.8 distribution
-
-Mon Aug 19 11:38:16 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* table.c(texpand): don't free entry if FINUSE is set.
-
-	* var.c(unset): preserve ARRAY and DEFINED if unsetting foo[0].
-
-Thu Aug 15 15:08:52 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* jobs.c(sm_sigchld,sm_default): moved to sh.h.
-	* sh.h(Coproc_id, struct coproc): new typedef; added njobs and
-	  id fields to struct coproc.
-	* exec.c(execute): case TCOPROC: re-did coprocess stuff to use
-	  njobs/coprocess id.
-	* jobs.c(struct Job): added coproc_id field.
-	* jobs.c(exchild): initialize coproc_id to 0; set job coproc_id
-	  and increment coproc.njobs in parent.
-	* jobs.c(checkjob): check coproc_id and close co-process input/output
-	  if needed.
-
-	* exec.c(iosetup): only play with coprocess fds if this is an
-	  empty exec.
-	* c_sh.c(c_read): commented out coproc_readw_close() call and eof call.
-	* c_ksh.c(c_print): commented out closing coprocess fd on EPIPE.
-
-	* jobs.c(exchild): in parent, last part of job: use orig_flags (not
-	  flags) when checking XCOPROC.
-
-Thu Aug 15 15:00:42 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* io.c(get_coproc_fd,cleanup_coproc): renamed to coproc_getfd() and
-	  coproc_cleanup(), respecitively; changed all calls.
-
-Tue Aug 13 16:56:59 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* expr.c(O_COMMA,P_COMMA): new enums.
-	* expr.c(evalexpr): added case for O_COMMA.
-
-Tue Aug 13 15:18:28 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* expr.c(do_ppmm): new function to handle ++/--.
-	* expr.c(evalexpr): call do_ppmm() in P_PRIMARY code.
-	* expr.c(LAST_BINOP): deleted.
-	* expr.c(IS_BINOP): new define.
-	* expr.c(evalexpr): use IS_BINOP.
-	* expr.c(O_PLUSPLUS,O_MINUSMUNS,opinfo[]): new enums; updated opinfo
-	* expr.c(ET_LVALUE,ET_RDONLY): new enums.
-
-	* expr.c(token): var code: don't increment cp in iter part of for loop,
-	  do it in body; don't correct for off by 1 in array or !noasign code.
-	* table.h(EXPRLVALUE): new define.
-	* expr.c(token): var code: set EXPRLVALUE flag if noassign.
-	* expr.c(intvar): copy temp var if EXPRLVALUE set.
-	* expr.c(assign_check): new function.
-	* expr.c(evalexpr): if assign-op, call assign_check().
-
-Tue Aug 13 11:02:32 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(do_comment),edit.c(x_do_comment): made do_comment generic,
-	  renamed and moved to edit.c; changed all calls.
-	* emacs.c(x_ftab[]): added x_comment.
-	* emacs.c(x_defbindings[]): added XFUNC_comment as <esc>#.
-	* emacs.c(x_comment): new function.
-
-Mon Aug 12 16:13:36 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* expr.c(ET_BADVAR): deleted.
-	* expr.c(ET_RECURSIVE, struct expr.evaling),table.h(EXPRNEVAL): added.
-	* expr.c(v_evaluate): if curstate.evaling set, clear EXPRINEVAL.
-	* expr.c(evalerr): added ET_RECURSIVE case, removed ET_BADVAR case.
-	* expr.c(intvar): do recursion check, call v_evaluate() on value.
-
-Mon Aug 12 14:25:23 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* io.c(coproc_read_close): call coproc_readw_close() instead of
-	  duplicating code.
-
-Mon Aug 12 11:21:39 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* edit.c(x_locate_word): changed to allow at most 1 leading blank
-	  before the word.
-	* edit.c(x_file_glob,x_command_glob,add_glob): allow zero length word.
-	* edit.c(x_cf_glob): allow zero length globs on when doing file
-	  completion.
-
-	* edit.c(x_complete_word): #if 0 - it isn't used...
-	* edit.c(x_file_glob,x_command_glob,x_locate_word): made static.
-
-	* eval.c(varsub): changed FNOUNSET error from "unset variable"
-	  to "parameter no set", ala at&t ksh.
-
-	* c_ksh.c(c_typeset): print variables that aren't set (just
-	  leave out the =...).
-
-Mon Aug 12 11:03:22 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(findfunc): removed redundant DEFINED check after tsearch().
-
-Fri Aug  9 22:16:21 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* jobs.c(j_change): when turning off FMONITOR and not FTALKING,
-	  changed SS_RESTORE_CURR to SS_RESTORE_ORIG.
-
-	* edit.c(x_sigwinch): new function.
-	* edit.c(x_init): set up signal handler for SIGWINCH; moved
-	  code to get window size into x_sigwinch(); call x_sigwinch().
-	* emacs.c(xx_cols): new variable.
-	* emacs.c(x_init): set xx_cols_to x_cols; change all uses of x_cols
-	  to xx_cols.
-	* vi.c(display): when displaying morec, changed x_cols-2 to
-	  pwidth+winwidth+1.
-
-Fri Aug  9 12:49:00 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* table.h(FKSH): new define.
-	* tree.h(struct op): put evalflags into new union u, added ksh_func
-	  to union; changed all uses of evalflags.
-	* syn.c(function_body): set u.ksh_func.
-	* exec.c(execute): changed define() arg to t (was t->left).
-	* exec.c(define): copy t->left (was t); set FKSH in flag if is
-	  a ksh function.
-	* exec.c(comexec): don't keep assignments for x() style functions.
-	* exec.c(comexec: case CFUNC: set kshname ($0) for ksh style functions
-	  only (was FPOSIX).
-
-	* exec.c(execute): case TAND/TOR: pass XERROK on when executing right
-	  hand side.
-
-	* jobs.c(exchild): deleted redundant code to set j->flags
-	  (near new_job() call).
-
-	* sh.h(ksh_tmout),main.c(alarm_init),trap.c(alarm_init,alarm_catcher):
-	  ifdef'd KSH.
-
-	* sh.h(SS_SHTRAP,Trap.shtrap): added.
-	* trap.c(trapsig): if shtrap is non-zero, call it.
-	* trap.c(setsig): set shtrap if SS_SHTRAP set.
-	* jobs.c(j_init),trap.c(alarm_init): pass SS_SHTRAP.
-	* jobs.c(j_sigchld),trap.c(alarm_catcher): don't call trapsig().
-	* trap.c(Sigact_alarm): removed.
-
-Thu Aug  8 15:57:14 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(comexec): case CEXEC: print cannot execute error only
-	  if / in pathname; also, set exit code to 126.
-
-	* exec.c(do_selectargs): added print_menu arg; only print
-	  menu if this is set, or if REPLY is null; removed "while isspace"
-	  loop.
-	* exec.c(execute): case TSELECT: call do_selectargs with print_menu
-	  of TRUE on first call only.
-
-	* exec.c(define): added was_set variable and logic.
-	* c_sh.c(c_unset): return 1 if variable/function to be unset wasn't
-	  set to begin with.
-
-Wed Jul 31 10:33:00 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(Tflag): new type.
-	* sh.h(builtin_flag): changed type to Tflag.
-	* table.h(struct tbl): changed type of flag field to Tflag.
-	* c_ksh.c(typeset): changed type of flag, fset, fclr to Tflag.
-	* c_ksh.c(c_alias): changed type of xflag to Tflag.
-	* exec.c(comexec): changed type of old_inuse to Tflag.
-	* exec.c(builtin): changed type of flag to Tflag.
-	* var.c(typeset): changed set, clr args to Tflag; convert second
-	  arg of call to local() to boolean.
-
-Wed Jul 31 10:26:25 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(C_QUOTE): new define.
-	* sh.h(ctypes[]),misc.c(ctypes[]): changed from char to short.
-	* misc.c(initctypes): set C_QUOTE bits in ctypes[].
-	* misc.c(print_value_quoted): use C_QUOTE.
-
-Mon Jul 29 11:38:36 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.c(set_prompt): don't print warning message if setjmp returns
-	  non-zero.
-
-Fri Jul 26 10:16:27 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.c(set_prompt): don't do ! and parameter expansion if !KSH.
-
-	* table.h(V_MAIL,V_MAILPATH,V_MAILCHECK): ifdef KSH.
-	* var.c(initvar,setspec,unsetspec): ifdef KSH use of MAIL stuff.
-	* mail.c: ifdef KSH whole file.
-	* main.c(shell): ifdef KSH call to mcheck().
-	* main.c(initcoms[]): ifdef KSH the MAILCHECK=600.
-	  (based on patches from Marc Olzheim).
-
-	* exec.c(PS4_SUBSTITUTE): new macro.
-	* exec.c(execute, comexec, iosetup): use PS4_SUBSTITUTE.
-
-Thu Jul 25 17:19:17 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(F_VIESCCOMPLETE): new define.
-	* misc.c(options[]): added vi-esccomplete.
-	* vi.c(classify[]): make ^[ a repeatable command.
-	* vi.c(vi_cmd): check F_VIESCCOMPLETE for ^[.
-
-Mon Jul 22 16:54:38 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ksh.c(c_getopts): return if variable is readonly; don't change
-	  OPTIND if option is bad (fragile).
-	* c_sh.c(c_brkcont): use ksh_getopt(); changed error message if
-	  n <= 0.
-	* c_sh.c(c_dot,c_eval,c_exitreturn): use ksh_getopt().
-	* misc.c(ksh_getopt): print `unknown option' instead of `bad option'.
-
-Mon Jul 22 16:08:40 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* edit.c(x_init): do NOT export COLUMNS/LINES - causes more problems
-	  than it fixes.
-
-Mon Jul 22 15:49:35 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* syn.c(get_command): fixed test for '< foo (command)' so it
-	  works.
-
-Fri Jun 21 09:57:47 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* aclocal.m4(KSH_OPENDIR_CHECK): include dirent.h if HAVE_DIRENT_H
-	  defined (was DIRENT || _POSIX_VERSION).
-	* aclocal.m4(KSH_UNISTD_H): don't test HAVE_DIRENT_H when including
-	  dirent.h.
-
-Wed Jun 12 11:02:32 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_test.c(b_ops[]): added "==" entry (ksh93ism).
-
-Mon Jun 10 14:00:21  1996 Michael Rendell (michael@lyman.cs.mun.ca)
-
-	* ksh_stat.h: undef S_ISSOCK if STAT_MACROS_BROKEN defined.
-	* aclocal.m4(AC_HEADER_STAT): redefine autoconf's version to handle
-	  FreeBSD's S_ISSOCK.
-
-Tue Jun  4 08:41:19 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.2.7 distribution
-
-	* vi.c(CMDLEN): changed from 16 back to 1024.
-
-Sun Jun  2 11:54:46 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.2.6 distribution
-
-Sun Jun  2 11:46:56 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(search_access): changed ordering of xsuffixes[], rsuffixes[];
-	  removed code that used xsuffixes[] when suffix is present.
-	* lex.c(getsc_line): set O_TEXT/O_BINARY if os/2.
-	* main.c(remove_temps): added os2 ifdefs.
-	  [Changes from Dale DePriest.]
-
-Tue May 21 14:18:22 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(vi_cmd): case '#': call do_comment() to do work.
-	* vi.c(do_comment): new function.
-	* vi.c(putbuf,grabhist,grabsearch): fixed pesimestic off-by-1 error
-	  (cbufsize - 1 -> cbufsize).
-	* vi.c(vi_hook): case VCMD: case -1: added refresh(0).
-	* vi.c(vi_cmd): case 'P': don't move cursor back if nothing added.
-
-Tue May 21 12:03:34 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* emacs.c(do_complete): don't add space if single match and
-	  it doesn't end with a /.
-
-Tue May 21 11:51:36 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* edit.c(x_init): use typeset to set EXPORT attribute for
-	  COLUMNS/LINES.
-
-Tue May 21 11:40:12 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* misc.c(parseargs): option setting: ignore context if option
-	  isn't being changed.
-	* misc.c(printoptions): for non-verbose mode: print a set command
-	  (eg, set -o vi -o ...) instead of just the option names.
-
-Tue May 21 11:14:27 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_sh.c(c_brkcont): if n is too big, use last enclosing loop.
-
-Fri May 10 09:27:47 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(Getopt): changed field p from int to unsigned.
-
-Tue May  7 12:10:47 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.2.5 distribution
-
-Tue May  7 11:45:37 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* syn.c(compile): set multiline if source is SSTRING.
-	* syn.c(yyparse): don't peek before calling c_list() - build
-	  TEOF if c_list() fails and c is 0.
-	* syn.c(c_list): remove SSTRING test.
-	* syn.c(get_command): if EOF is reached, free iops,args,vars.
-	* syn.c(syntaxerr): set multiline.on to false when it is used;
-	  don't use multiline.on if start token is 0.
-
-Tue May  7 10:11:41 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* history.c(c_fc,hist_execute): moved calls to histbackup() from
-	  c_fc() to hist_execute().
-	* history.c(hist_get): number: took out +1 correction as histbackup
-	  hasn't been done yet; string: added -1 correction to ensure
-	  current fc command isn't searched.
-	* history.c(hist_get_newest,hist_get_oldest): don't find the
-	  current (fc) command; removed print_err argument (was always
-	  true).
-	* history.c(hist_get,hist_get_newest): added allow_cur argument;
-	  changed all calls.
-
-Mon May  6 09:55:29 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* emacs.c(x_nextcmdp): renamed to x_nextcmd, changed from
-	  char ** to int.
-	* emacs.c(x_nl_next_com): save absolute command number, not
-	  relative position in history array (which changes).
-	* emacs.c(x_emacs): convert x_nextcmd back to relative position.
-	* emacs.c(x_init_emacs): initialize x_nextcmd to -1.
-
-Sun May  5 13:10:48 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* expr.c(evalexpr): when assigning a non-integer, call setint()
-	 (not setstr(..., strval(...))).
-
-Sun May  5 12:16:11 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* mail.c(maddmsg): changed name to mprintit(); now prints message
-	  directly instead of saving in a linked list; changed all calls.
-	* mail.c(mprint): deleted; deleted all calls.
-	* mail.c(mmsgs,struct mailmsg): deleted.
-
-Sun May  5 11:52:05 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.h(SF_TTY): new flag.
-	* lex.h(STTY): deleted.
-	* main.c(main): if tty, use SSTDIN, set SF_TTY.
-	* main.c(shell): check SF_TTY instead of STTY.
-	* lex.c(getsc_): call getsc_line for SSTDIN/SFILE.
-	* lex.c(getsc_line): new function (merged old STTY/SSTDIN/SFILE code).
-
-Fri May  3 11:24:17 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* main.c(shell): changed exit_atend to toplevel.  Changed interactive
-	  to be falking&toplevel (was talking&s->type==STTY).
-
-Fri May  3 10:59:22 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* var.c(getint): only allow one base (ie, disallow 2#4#5).
-
-Thu May  2 21:31:23 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* var.c(array_index_calc): new function
-	* var.c(global): call array_index_calc(); moved $2 code into
-	  if (!letter(c))...
-	* var.c(local): call array_index_calc(); added copy argument & code;
-	  changed all calls.
-	* table.h(LOCAL_COPY): new define.
-	* exec.c(comexec): maybe pass LOCAL_COPY to typeset().
-
-Thu May  2 16:34:29 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* emacs.c: command completion changes.
-	* emacs.c(Comp_type,CT_LIST,CT_COMPLETE,CT_COMPLIST): new type.
-	* emacs.c(x_ins): return type changed to int; return -1 if
-	  string can't be inserted.
-	* emacs.c(x_do_ins): new function.
-	* emacs.c(add_stash,list_stash,compl_dec,compl_file,compl_command,
-	  str_match): deleted; changed callers to use do_complete().
-	* emacs.c(do_complete,x_expand): new functions.
-	* emacs.c(x_ftab[],x_defbindings[]): added entry for file-expand;
-	  bound to <ESC>*.
-
-Thu May  2 15:31:32 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.c(set_prompt): pass strlen() + 1 to shf_sopen.
-	  (fix from Arnon Kanfi).
-
-Wed Apr 24 11:50:52 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* history.c(c_fc): -e -: don't increment wp past null; allow
-	  pat=replace arg with "-1" type argument.
-	  (based on fix from Jason Tyler).
-
-Mon Apr 15 11:58:34 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* table.c(tenter),alloc.c(alloc): changed use of offsetof() so field
-	  parameter is a constant expression.
-	* sh.h: took out undef of offsetof on CRAYs.
-
-Fri Apr 12 16:01:40 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* jobs.c(JF_USETTYMODE): renamed JR_ORIGFG to JF_USETTYMODE.
-	* jobs.c(j_waitj): clear JF_USETTYMODE if fg job is stopped.
-
-Sun Apr  7 12:35:30 NDT 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ksh(c_print): echo: don't treat a lone minus as an option.
-
-Sat Apr  6 00:09:37 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ulimit.c(c_ulimit.c): always pass 2 args to ulimit().
-	* ksh_sigsetjmp(): changed all uses to be simple expressions - seems
-	  to be required by the cray C compiler.
-	* sh.h(offsetof): undef if on a cray.
-	  (based on fixes from Dave Kinchlea)
-
-Sat Mar 23 13:58:12 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* siglist.in: added WAITING,LWP,FREEZE,THAW,CANCEL
-
-Thu Mar  7 23:26:37 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* edit.c(x_init): set LINES if possible.
-
-Thu Mar  7 23:01:55 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* main.c(main): call x_init() after j_init()
-	  (based on fix from Stefan Dalibor).
-
-Thu Mar  7 16:13:10 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* aclocal.m4(KSH_OS_TYPE): check for TitanOS (use cc -43).
-	* aclocal.m4(KSH_SIGNAL_TYPE): for bsd41 signals, check if signal
-	  interrupt read().
-
-Thu Mar  7 13:59:29 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(strstr),missing.c(strstr): changed args to const.
-
-Wed Mar  6 17:21:36 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* io.c(errorf,bi_errorf): changed null pointer string check to
-	  empty string; changed all calls (due to new error gcc warnings).
-
-Wed Mar  6 17:15:58 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(search_access): files aren't executable if they don't
-	  have any execute bits.
-	* ksh_stat.h: added S_IXUSR,S_IXGRP,S_IXOTH.
-	* exec.c(search_access,search_access1): OS2: changed the meaning
-	  of these two functions (search_access1 now called from search_access).
-
-Wed Mar  6 16:23:23 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* tree.c(ptree): add case for TSELECT.
-
-Wed Mar  6 12:40:34 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(Z_,is_zeroarg): new defines.
-	* vi.c(classify): use Z_ for G, g, _, |, v, ^I, ^F.
-	* vi.c(vi_cmd): use is_zerocount().
-	* vi.c(complete_word): if command prefixed by a count, complete
-	  to count'th expansion (as reported by print_expansions()).
-
-Tue Mar  5 14:43:48 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* eval.c(GF_NONE,GF_EXCHECK,GF_GLOBBED,GF_MARKDIR): new defines.
-	* eval.c(glob_str): added markdirs argument; changed all calls;
-	  made function non-static.
-	* eval.c(glob): added markdirs argument; changed all calls.
-	* tree.h(DOMARKDIRS): new define.
-	* eval.c(expand): set DOMARKDIRS if FMARKDIRS.
-	* edit.c(x_complete_word,x_print_expansions,x_file_glob,x_command_glob,
-	  x_locate_word,x_cf_glob,x_add_glob,x_longest_prefix,x_free_words):
-	  new functions.
-	* proto,edit.h: moved functions defined in edit.c to edit.h.
-	* vi.c(struct edstate): moved to top of file.
-	* vi.c(print_expansions): added struct edstate argument; changed all
-	  calls.
-	* vi.c(struct glob,Glob,globstr,glob_word,): deleted
-	* vi.c(vi_pprompt): new function; changed all calls of pprompt() in
-	  vi.c to use vi_pprompt().
-	* vi.c(x_vi): moved to top of file.
-	* vi.c(expand_word,complete_word): free buf if it is not null.
-	* vi.c(expand_word,complete_word,print_expansions): changed
-	  to use new edit.c functions.
-
-Tue Feb 20 11:02:05 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* table.c(twalk,tnext,struct tstate),table.h(struct tstate): moved
-	  struct tstate from table.c to table.h; changed twalk,tnext to take
-	  struct tstate* argument; changed all calls; deleted static tstate
-	  variable.
-
-Sat Feb 17 12:28:11 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(vi_hook): case VSEARCH: if new pattern is empty, repeat last
-	  search.
-
-Sat Feb 10 15:59:28 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* table.h(struct arg_info): new struct.
-	* table.h(struct block): changed argv, argc fields to argi.
-
-Sat Feb 10 15:12:47 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	ANSI C name space requirements:
-
-	* vi.c(isbad,iscmd,islong,ismove,issrch,isundoable,iswordch): changed
-	  to is_bad,is_cmd,is_long,is_move,is_srch,is_undoable,is_wordch.
-	* emacs.c(iscfs,ismfs): changed to is_cfs, is_mfs.
-	* emacs.c(strmatch): changed to str_match.
-	* sh.h(strchr_dirsep,strrchr_dirsep): changed to ksh_strchr_dirsep,
-	  ksh_strtchr_dirsep; changed all calls.
-	* missing.c(strichars[]): changed to ichars[].
-	* var.c(strint,strval): changed to setint_v, str_val.
-	* missing.c(strsave,strnsave): changed to str_save,str_nsave.
-
-Fri Feb  9 11:30:15 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* main.c(main): remove envp parameter; declare and use environ.
-
-	* c_ksh.c(c_print): octal digit escape sequences must start with \0.
-
-Sat Feb  3 15:35:41 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(vi_cmd,classify[]): made ^I a command.
-
-Fri Feb  2 10:40:32 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.h(struct source): added u.freeme field.
-	* lex.c(getsc_): case SREREAD: free u.freeme iff start isn't u.ugbuf.
-
-Thu Feb  1 15:27:06 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_test.h(Test_env): added end union.
-	* c_test.c(c_test): keep track of end 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@panda.cs.mun.ca)
-
-	* edit.h, sh.h, tty.h: changed _I_ to I__.
-	* edit.h, edit.c: changed _D_ to D__.
-
-	* jobs.c,shf.c,tty.c: include ksh_stat.h (POSIX: needed for open).
-
-	* sigact.c: use ARGS instead of __P; comment out __P defines.
-
-	* shf.c: include math.h if FP.
-	* shf.c(my_ceil): remove modf() declaration.
-	* shf.c(shf_fvprintf): comment out frexp() declaration; changed
-	  exp to expo.
-
-	* jobs.c(struct job, j_utime, j_stime): changed utime/stime to
-	  usrtime/systime; change j_utime/j_stime to j_usrtime/j_systime.
-
-Wed Jan 31 16:13:44 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* edit.c(x_getc): cast return value to int to avoid warnings on
-	  strange compilers.
-	* exec.c(funcfunc): changed second arg to unsigned int (was int).
-	* syn.c(elsepart): move return NULL to end of function (avoids
-	  warning from some compilers).
-	* vi.c(classify[]): changed type to unsigned char.
-	* shf.c(shf_smprintf): delete unused variable n.
-	* aclocal.m4(KSH_TIMES_CHECK): define INT32 in test code.
-	* aclocal.m4(KSH_SIGNAL_CHECK): typeo: had bsd42 instead of bsd41.
-	* sh.h(MAGIC): changed to 7 to increase portability.
-	* jobs.c(tcsetpgrp,tcgetpgrp): define if TTY_PGRP (was TIOCSPGRP).
-
-Tue Jan 23 11:40:25 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(ksh_jmp_buf): new define.
-
-Thu Jan 18 15:03:19 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* history.c(hist_replace): fixed substitution code (again).
-
-Wed Jan 17 20:10:02 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.2.4 distribution
-
-	* main.c(initcoms): changed hash alias to "hash=alias -t".
-
-	* exec.c(do_selectargs): deleted c_read() declaration.
-
-	* c_ksh(c_alias): call ksh_getopt_reset() before calling c_unalias().
-
-Wed Jan 17 19:47:55 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* history.c(histbackup): changed "histptr > history"
-	  to "histptr >= history".
-
-	* history.c(hist_replace): removed un-needed "last" - use "s" instead.
-	  (based on fix from Jason Tyler).
-
-Thu Jan 11 15:59:46 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ksh.c(c_whence,c_command),main.c(initcoms[]): removed ifdef KSH
-	  (type is a builtin in sys-5 sh).
-
-Wed Jan 10 11:49:59 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* Makefile.in: added NEWS.os2 to OS2FILES.
-
-	* version.c: include "sh.h" (needed for const define).
-
-	* exec.c(pr_menu): made non-static.
-	* vi.c(print_expansions): gather expansions into an arrat
-	  and use pr_menu().
-	  (fixes from Mike Jetzer).
-
-	* vi.c(redraw_line): added newline option; changed all calls.
-
-Wed Jan 10 10:21:06 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(classify): made 'U' a C_.
-	* vi.c(ohnum): new variable.
-	* vi.c(vi_reset): set ohnum to hlast.
-	* vi.c(grabhist): set ohnum.
-	* vi.c(vi_cmd): case n,N,/,? set ohnum; added case 'U'.
-	* vi.c(edit_reset): clear holdlen.
-	  (based on fix from Dale DePriest).
-
-Tue Jan  9 11:23:36 NST 1996 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* emacs.c(iscfs): make ', " 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@panda.cs.mun.ca)
-
-	* sh.h(struct temp): added shf field.
-	* io.c(maketemp): changed to use O_EXCL; keep trying if open
-	  fails (due to O_EXCL); fill in shf field; changed all calls.
-
-	* main.c(include): added intr_ok flag; changed all calls.
-
-	* main.c(main): if compiled as sh and posix option not set, do not
-	  include $ENV.
-
-	* trap.c: define FROM_TRAP_C before including sh.h.
-	* sh.h: don't declare sigtraps if FROM_TRAP_C declared.
-
-	* c_ksh.c(c_cd): fixed error message.
-	* vi.c(glob_word): don't add * if word contains a $.
-	  (Based on fixes from Mike Jetzer).
-
-	* eval.c(tilde): if HOME,PWD,OLDPWD aren't set, don't expand
-	  ~,~+/~-.
-
-Fri Jan  5 12:15:58 NST 1996 Michael Rendell (michael@garfield.cs.mun.ca)
-
-	* c_ksh.c(c_typeset): 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@panda.cs.mun.ca)
-
-	* vi.c(globstr): deleted ifdef'd out code.
-
-Sun Dec 10 11:07:52 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.c(yylex): added case for STBRACE; wrap word part of
-	  trim substitution in @(..).
-	* eval.c(trimsub): deleted code to wrap pattern in @(..); changed
-	  '%' code to use strnsave().
-
-Fri Dec  8 22:55:56 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* eval.c(trimsub): if trim pattern contains a |, wrap pattern
-	  in @(...).
-	* lex.c(yylex): make | special when incounted in a ${...}
-	  substitution.
-
-Fri Dec  8 11:52:38 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* var.c: ifdef'd HISTFILE, HISTSIZE stuff with HISTORY (was KSH).
-
-	* *.c,*.h: ifdef'd coprocess stuff with KSH.
-
-Thu Dec  7 14:41:06 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
-	* options.h(BRACEEXPAND): changed to BRACE_EXPAND; changed all
-	  references.
-
-Thu Dec  7 13:54:20 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
-	* exec.c(do_selectargs): don't print newline on eof.
-
-Thu Dec  7 10:23:30 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
-	* c_ksh.c(c_print): added -f for OS2.
-	* tree.h(DODIRSWP),eval.c: deleted define and all uses of it.
-	* exec.c(scriptexec): ...
-	* io.c(check_fd): set O_TEXT/O_BINARY flag for OS2.
-	* main.c(main): set O_BINARY/O_TEXT, search path for arg.
-	* emacs.c(compl_file): call opendir with buf, not dirnam.
-	  (based on changes from Dale DePriest).
-
-Wed Nov 29 15:50:36 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
-	* eval.c(expand,debunk): handle extended pattern matching stuff.
-	* eval.c(debunk): now has two arguments, changed all calls.
-	* eval.c(globit): changed to use has_globbing.
-	* eval.c(copy_non_glob): deleted.
-
-	* misc.c(has_globbing): new function.
-	* misc.c(cclass): changed argument to unsigned char *; handle
-	  extended pattern matching.
-	* misc.c(do_gmatch): new function (taken from gmatch()).
-	* misc.c(gmatch): changed to call do_gmatch.
-	* misc.c(do_gmatch): added cases for extended pattern matching
-	  (*(foo|bar), etc.).
-	* misc.c(pat_scan): new function.
-
-	* lex.c(yylex): added SPATTERN case.
-
-	* lex.c(arraysub): changed to assume just past the leading [
-	  (was assuming about to read [); changed all calls; changed
-	  to use getsc_bn().
-
-	* lex.c(ungetsc): added argument; changed all calls; can now unget
-	  arbitrary number of characters.
-	* lex.c(ungetsc_): new function.
-
-	* lex.h(struct source): added start field, removed u.start field,
-	  changed all uses.
-	* lex.c(getsc_): case STTY: skip blank line only if this is first line
-	  of a command (eg, not part of here documennt, etc.).
-
-	* lex.c(yylex): case SHEREDELIM,SHEREDQUOTE: ignore \newline.
-	* lex.c(readhere,get_brace_var): ignore \newline.
-	* lex.c(getsc_bn,getsc_bn_): new define/function.
-
-	* exec.c(iosetup): don't enforce noclobber for non-regular files.
-
-	* tree.h(OPAT,SPAT,CPAT): new defines.
-	* tree.c(tputS,wdscan): added cases for OPAT,SPAT,CPAT.
-
-	* lex.c(yylex): moved case '[' from Subst: switch to case SBASE:.
-
-Tue Nov 14 11:00:48 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
-	* syn.c(get_command,caselist): moved parsing of IN/ESAC into
-	  caselist; allow {/} instead of IN/ESAC;
-	* syn.c(casepart): new parameter: endtok.
-	* lex.c(yylex): allow } as well as ESAC when ESACONLY set.
-	  (changes based on fix from DaviD W. Sanderson).
-
-Tue Nov 14 10:22:17 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
-	* main.c(shell): do not zero exstat at start of routine.
-
-	* exec.c(execute): removed redundant "exstat = rv" before
-	  unwind(LERROR).
-
-Thu Nov  9 15:01:54 NST 1995 Michael Rendell (michael@angel.cs.mun.ca)
-
-	* var.c(arrayname): made argument const.
-	* var.c(typeset): made var argument const.
-	* var.c(export): made val argument const.
-	* tree.c(wdscan): changed return type to non-const (added casts).
-
-Thu Nov  9 14:39:49 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ksh.c(c_alias),c_sh.c(c_set): made args[] array const.
-	* c_ulimt.c(c_ulimit): made limits[] array const.
-	* edit.c(x_mode): x_cur_mode no longer explicitly initialized to 0.
-	* emacs.c(x_tab,x_atab): no longer explicitly initialized to 0.
-	* exec.c(comexec): made texec non-static, non-initialized.
-	* history.c(hist_finish): once no longer explicitly initialized to 0.
-	* io.c(maketemp): io no longer explicitly initialized to 0.
-	* jobs.c(job_list,last_job,async_job,free_jobs,free_procs): no longer
-	  explicitly initialized to 0.
-	* jobs.c(lookup_msgs[],tt_sigs[]): made array const.
-	* mail.c(mplist,mbox,mlastchkd,mmsgs): no longer explicitly
-	  initialized to 0.
-	* vi.c(expand_word,complete_word): buf no longer explicitly
-	  initialized to 0.
-	* vi.c(classify[]): made array const.
-
-Tue Nov  7 11:08:01 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* mkman: new script
-	* Makefile.in: use mkman to generate ksh.1
-	* ksh.Man,ksh.1: renamed ksh.1 to ksh.Man
-	* ksh.Man: changed way sh/ksh option handled.
-	  (changes based on fix from Michael Haardt).
-
-Tue Sep 19 09:53:53 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* jobs.c(j_stopped): deleted function.
-	* jobs.c(j_exit): send SIGCONT, then SIGHUP; send SIGHUP if
-	  job is in foreground.
-	  (based on fix from Paul Borman)
-
-	* Makefile.in: move .PRECIOUS to after all.
-
-Wed Sep 13 15:00:22 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(dbteste_getopnd): changed tests from TO_STLT/TO_STGT
-	  to TO_STEQL/TO_STNEQ.
-
-Thu Aug 31 11:54:02 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* jobs.c(exchild): if fork fails, allow user to ^C out of loop.
-
-Tue Aug 29 09:40:37 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(iosetup): don't do globing if not interactive (POSIX).
-
-	* exec.c(iosetup): print <& or >& as appropriate in error message.
-
-	* tree.h(IONAMEXP): new define.
-	* tree.c(pioact): handle IONAMEXP.
-	* exec.c(iosetup): set IONAMEXP.
-
-	* io.c(savefd): added noclose parameter; changed all calls.
-	* exec.c(iosetup): move call to savefd() to after the open();
-	  re-arranged the dup'ing (failed dups reported).
-
-	* main.c(shell): call quitenv() before internal_error().
-
-Sun Aug 13 21:38:44 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(ksh_sigsetjmp,ksh_siglongjmp): new defines; changed
-	  all uses of setjmp/longjmp to these.
-	* configure.in: added checks for sigsetjmp() and _setjmp().
-
-Wed Jul 26 10:08:23 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ulimit.c(c_ulimit): added -p ("maxproc", RLIMIT_NPROC)
-	  (fix from Simon J. Gerraty).
-
-Thu Jun 29 10:22:51 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* edit.c(promptlen): added spp parameter; changed all calls.
-	* vi.c(prompt_skip): new variable.
-	* vi.c(edit_reset): set prompt_skip; use prompt_skip in all calls
-	  to pprompt().
-
-Sat Jun 24 15:55:03 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* IAFA-PACKAGE: new file.
-	* Makefile.in: added IAFA-PACKAGE to DISTFILES.
-
-Mon Jun 19 10:04:52 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* main.c(initcoms[]): added EXTRA_INITCOMS.
-
-Fri Jun 16 12:33:10 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(search_access1): use FILECMP() instead of strcmp().
-
-	* sh.h(FIELCHCONV): OS2 version: added isascii().
-	* misc.c(gmatch); took unsigned out again for sc and pc.
-
-	* main.c(main): don't set PS1 if it's already set; set it if
-	  we are root and prompt doesn't contain a #.
-
diff --git a/ChangeLog.0 b/ChangeLog.0
@@ -1,3589 +0,0 @@
-$OpenBSD: ChangeLog.0,v 1.5 2013/11/28 10:33:37 sobrado Exp $
-
-Thu Jun 15 11:02:06 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.2.3 distribution
-
-	* c_ksh.c(c_whence): search keyword table if vflag set.
-
-	* tree.h(DOVACHECK): new define.
-	* eval.c(expand): check DOVACHECK flag.
-	* exec.c(execute): when calling eval(), or in t->evalflags.
-	* syn.c(get_command): set evalflags to DOVACHECK instead of DOASNTILDE.
-
-Wed Jun 14 09:27:19 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ksh.c(c_cd): two argument format: use current_wd, not path
-	  when appending elen bytes.
-	  (fix from Gabor Zahemszky).
-
-Tue Jun 13 15:54:11 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* history.c(c_fc): if last not specified and !-l, use first as last.
-
-	* eval.c(maybe_expand_tilde): allow CSUBST to end tilde word.
-
-	* misc.c(gmatch): made sc and pc unsigned.
-
-Fri Jun  2 11:55:40 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* configure.in: added flock to AC_CHECK_FUNCS call.
-	* conf-end.h: undef COMPLEX_HISTORY if !HAVE_FLOCK.
-
-Tue May 30 20:38:47 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(SEEK_SET,SEEK_CUR,SEEK_END): define if not defined.
-	* history.c: change L_XTND to SEEK_END.
-
-Tue May 30 17:01:34 NDT 1995 John Rochester (jr@panda.cs.mun.ca)
-
-	* shf.c(shf_seek): new function.
-	* shf.h(shf_seek): new prototype.
-
-Tue May 30 16:42:41 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* aclocal.m4(KSH_DEV_FD): new test.
-	* acconfig.h(HAVE_DEV_FD): new define.
-	* configure.in: call KSH_DEV_FD.
-
-	* c_test.h(TO_FILAXST): new enum.
-	* c_test.c(test_stat,test_eaccess): new functions for /dev/fd/n
-	  handling.
-	* c_test.c(test_evalop): call test_stat() and test_eaccess()
-	  instead of stat() and eaccess() in most places; added case
-	  for TO_FILAXST.
-
-Tue May 30 16:06:21 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* aclocal.m4(KSH_MEMMOVE): fixed test so copies overlap.
-
-Sun May 28 11:11:03 NDT 1995 John Rochester (jr@panda.cs.mun.ca)
-
-	* sh.h(safe_prompt): new variable.
-	* main.c(initsubs): removed PS1.
-	* main.c(main): initialize safe_prompt; initialize PS1 from
-	  safe_prompt.
-	* lex.c(set_prompt): create new env while expanding PS1 - if expansion
-	  fails, use safe_prompt.
-
-Sat May 27 20:59:02 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c: put comments around token after #endif.
-
-Thu May 25 10:10:45 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_test.c(test_eval): case TO_OPTION: negate test if option starts
-	  with a !, always fail if option doesn't exist.
-
-	* sh.h(FNOHUP): new define.
-	* misc.c(options[]): "nohup" new option.
-	* jobs.c(j_stopped,j_stopped_running): name of j_stopped changed
-	  to j_stopped_running; changed all calls; check for/warn about
-	  running jobs if appropriate.
-	* jobs.c(j_exit): check for/kill running jobs if appropriate.
-	* main.c(shell),c_sh.c(c_exit): un-ifdef JOBS the j_stopped_running()
-	  call and really_exit initialization/clearing.
-
-Wed May 24 10:06:14 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* options.h(DEFAULT_ENV): new define.
-	* main.c(main): if ENV isn't set and DEFAULT_ENV is defined, include
-	  the later.
-	  (based on patches from Dave Kinchlea).
-
-	* sh.h(LAEXPR): new define.
-	* expr.c(evaluate): changed return type to error indicator; added
-	  rval and error_ok arguments; changed all calls (c_sh.c(c_shift),
-	  c_ulimit.c(c_ulimit),eval.c(expand),var.c(global,local)).
-	* expr.c(v_evaluate): added error_ok argument; changed return value
-	  to error indicator; call unwind() if !error_ok.
-	* expr.c(evalerr): changed errorf() to warningf(); call unwind(LAEXPR).
-	* c_test.c(test_eval): merged code for integer operations to have
-	  two calls to evaluate().
-
-	* io.c(warningf): print trailing newline; changed all calls.
-
-	* history.c(hist_get): string search: use histptr, not histptr - 1.
-
-Tue May 23 11:07:50 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(GI_NONAME): new define.
-	* misc.c(ksh_getopts): honour GI_NONAME flag.
-	* c_ksh.c(getopts_reset): set GI_NONAME flag.
-
-	* exec.c(comexec): don't change $0 if FPOSIX flag set.
-
-	* misc.c(ksh_getopt): don't use GI_DONE to allow parsing past
-	  bad options.
-	* sh.h(GI_DONE): deleted define.
-
-	* var.c(unset): added array_ref parameter; unset/free whole array
-	  if not an array_reference; changed all calls.
-	* c_sh.c(c_unset): set array_ref parameter if there is a [ in the name.
-
-Mon May 22 10:33:14 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* history.c(hist_init): complex version: initialize hist_source
-	  (fix from Simon J. Gerraty).
-
-Sat May 20 11:06:15 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.2.2 distribution
-
-	* Makefile.in: added c_test.h to HDRS.
-
-Fri May 19 12:35:18 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.2.1 distribution
-
-	* emacs.c(v_version): ignore typed character if it is a space.
-	* emacs.c(x_emacs_keys): bind <ESC>erase-char to delete-back-word
-	  (was delete-back-char).
-	* emacs.c(x_defkeybindings[]): bound list-file to ^X^Y and
-	  newline-and-next to ^O, as per man page.
-
-	* c_ksh.c(c_whence): changed "is a keyword" to "is a reserved word".
-
-	* sh.h: changed SVSV_PGRP to SYSV_PGRP.
-
-	* vi.c(vi_cmd): uncommented case for ^[ to make it easy to enable
-	  completion.
-
-Mon May 15 15:25:22 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* history.c(c_fc): accept -40 as -- -40.
-	* main.c(initcoms[]): take -- out of history alias.
-
-	* vi.c(print_expansions): handle trailing slash correctly (don't
-	  print empty strings).
-
-	* c_ksh.c(c_cd): put back ksh_get_wd() call for os/2.
-
-	* misc.c(ksh_get_wd): changed buf to b in call to getcwd().
-
-Tue May  9 13:57:31 NDT 1995 Michael Rendell (michael@dragon.cs.mun.ca)
-
-	* c_test.h: new file.
-	* c_test.c: major code restructuring: common parsing/evaluation
-	  routines call/called-by three sets of routines: one for
-	  normal test (and [..]), one for parsing [[ .. ]] one for
-	  evaluating [[ .. ]].
-	* c_test.c(oexpr,aexpr,nexpr,primary,is_op): renamed to test_oexpr,
-	  test_aexpr, test_nexpr, test_primary, test_isop.
-	* c_test.c(eval_unop,eval_binop): combined into new test_eval function.
-	* c_test.c(syntax): renamed to ptest_error,
-	* c_test.c(ptest_isa,ptest_getopnd,ptest_eval): new functions.
-	* syn.c(syntaxerr): added extra arg; changed all calls.
-	* syn.c(db_parse,db_oaexpr,db_nexpr,db_primary): deleted.
-	* syn.c(dbtestp_isa,dbtestp_getopnd,dbtestp_eval,dbtestp_error): added.
-	* syn.c(get_command): case DBRACKET: changed to call new routines.
-	* tree.c(ptree): case DBRACKET: changed.
-	* exec.c(execute): case DBRACKET: changed.
-	* exec.c(dbteste_isa,dbteste_getopnd,dbteste_eval,dbteste_error): added.
-
-Fri May  5 17:10:23 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* emacs.c(compl_file,compl_command): fixed buffer growing code.
-
-Thu May  4 22:44:01 NDT 1995 Michael Rendell (michael@garfield.cs.mun.ca)
-
-	* aclocal.m4(KSH_UNISTD_H): include <sys/types.h> and only include
-	  <dirent.h> if HAVE_DIRENT_H is defined.
-
-Thu May  4 21:19:15 NDT 1995 Michael Rendell (michael@garfield.cs.mun.ca)
-
-	* c_ksh.c: include "ksh_stat.h".
-	* c_ksh.c(c_cd): don't do physical chdir if S_ISLNK not defined.
-
-Wed May  3 10:08:32 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.2.0 distribution
-
-	* misc.c: include <ctype.h>.
-	* misc.c(gmatch): added isfile argument; changed all calls.
-	* sh.h(FILECHCONV): (os2 version) - use isupper.
-	* emacs.c(strmatch): don't increment in FILECHCONV.
-
-	* aclocal.m4(KSH_HEADER_SYS_WAIT): new macro.
-	* configure.in: use KSH_HEADER_SYS_WAIT instead of AC_HEADER_SYS_WAIT.
-	* ksh_wait.h: if POSIX_SYS_WAIT not defined, undef W* macros.
-
-Tue May  2 12:10:39 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* emacs.c,emacs-gen.sh,emacs-c.in,emacs.out,Makefile.in: changed emacs
-	  source munging to create emacs.out which is included by emacs.c
-	  rather then munging emacs.c itself.
-
-	* lex.c(pprompt): flush shl_out.
-
-	* vi.c(glob_word): if path has *?[, don't add * (was if last component).
-
-	* emacs.c(x_search_char): renamed to x_search_char_forw.
-	* emacs.c(x_search_char_back): new function; bound to ^[^].
-
-	* sh.h: changed SVR3_PGRP to SYSV_PGRP.
-	(fixes from Gabor Zahemszky).
-
-Tue May  2 10:09:57 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ksh.c(c_cd): deleted OS2 ifdefs.
-	* path.c(make_path): use ISRELPATH instead of ISABSPATH
-	* path.c(simplify_path): use ISROOTEDPATH instead of ISABSPATH.
-	* sh.h(ISABSPATH,ISROOTEDPATH,ISRELPATH): changed/new defines.
-
-	* aclocal.m4(AC_LANG_C,AC_LANG_CPLUSPLUS,AC_TRY_RUN): copied
-	  from autoconf's acgeneral.m4, changed to handle .exe suffix.
-	* aclocal.m4(KSH_OS_TYPE): os2 case: set $ac_exe_suffix.
-	* configure.in: substitute ac_exe_suffix.
-	* Makefile.in: changed references to E to exe_suffix, set to
-	  ac_exe_suffix
-
-	* c_ksh.c(c_cd): ifdef S_ISLNK second use of get_phys_path().
-	* edit.c(x_mode): removed ifndef OS2.
-	  (fixes from Dale DePriest)
-	* exec.c(search_access1): add .sh to suffix lists.
-	* vi.c(vi_insert,vi_hook): OS2: changes to allow arrow keys work
-	  in insert mode.
-
-Mon May  1 16:28:44 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* path.c(ksh_get_wd): getcwd() case, return alloc'd buffer, not
-	  a malloc'd one.
-
-Mon May  1 09:41:56 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* aclocal.m4: changed HAVE_SYS_RESOURCES_H to HAVE_SYS_RESOURCE_H.
-
-	* aclocal.m4(KSH_OS_TYPE): new macro.
-	* aclocal.m4(KSH_OS2_EMX): deleted.
-	* configure.in: deleted calls to AC_AIX,AC_MINIX,AC_ISC_POSIX,
-	  KSH_OS2_EMX; replaced with KSH_OS_TYPE.
-	* acconfig.h(OS_ISC,OS_SCO): new undefs.
-	* sh.h: changed use of isc386 to OS_ISC
-	* edit.c: changed use of M_UNIX to OS_SCO.
-
-Sat Apr 29 21:10:54 NDT 1995 Michael Rendell (michael@garfield.cs.mun.ca)
-
-	* vi.c(glob_word): don't append * if there are unescaped globing
-	  characters in the last component of the filename; some redundant
-	  code eliminated.
-	  (based on fix from Michael Jetzer).
-
-Fri Apr 28 16:10:22 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* eval.c(globit): save/restore actual DIRSEP char - don't use DIRSEP.
-
-	* c_ulimit.c: removed ARGS from declaration of ulimit to avoid
-	  portability problems (osf/1 has ulimit(int,...), os2 has
-	  ulimit(int,long)).
-
-	* tty.c(tty_init): added __SCO__ defines to avoid opening /dev/tty.
-
-	* configure.in,aclocal.m4,acconfig.h: added KSH_OS2_EMX test.
-	* os2/config.h, os2/configure.cmd, os2/make.sed: updated for new
-	  autoconf.
-
-Tue Apr 25 12:20:45 NDT 1995 Michael Rendell (michael@dragon.cs.mun.ca)
-
-	* configure.in: added sys/param.h test; changed getcwd test to getwd.
-	* c_ksh.c(c_pwd): new function.
-	* sh.h(current_wd, current_wd_size): new variables.
-	* c_ksh.c(c_cd): changed to handle -L, -P.
-	* main.c(main): use set_current_wd when setting $PWD;
-	  instead of changing to / when can't get pwd, print warning;
-	  deleted pwd alias; don't make PWD and OLDPWD reaedonly.
-	* path.c(simplify_path): changed to handle relative paths.
-	* path.c(make_path): added phys_path argument to support cd -P.
-	* path.c(set_current_wd,get_phys_path,do_phys_path): new functions.
-	* misc.c(ksh_get_wd): new function.
-	* missing.c(getcwd): deleted.
-	* misc.c(options[]),sh.h: added "physical", FPHYSICAL.
-
-Mon Apr 24 14:33:03 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* shf.c(shf_smprintf): new function.
-
-	* expand.h(Xsize): new define.
-
-Fri Apr 21 21:22:44 NDT 1995 Michael Rendell (michael@garfield.cs.mun.ca)
-
-	* sh.h: changed SIZEOF_long to SIZEOF_LONG.
-	* exec.c(scriptexec): if OS2 ifdefed code, changed ISDIRSEP to
-	  explicit /.
-
-Thu Apr 20 21:18:12 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* history.c(hist_get) if n < 0, use n + 1 to account for histbackup().
-
-	* lex.c(set_prompt): added source argument; changed all calls;
-	  changed to do ! and !! substitutions when setting PS1.
-	* lex.c(pprompt): ifdef'd out code to deal with ! and !!.
-
-	* shf.c(shf_puts): new routine.
-	* exec.c(herein), lex.c(getsc_): changed to use shf_puts.
-
-Thu Apr 20 15:50:35 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* siglist.sh: clear traps in subshell to cover for bug in bash 1.4.3
-	  (based on fix from Fritz Heinrichmeyer).
-
-Wed Apr 19 12:04:59 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(classify): cleaned up table; filled in U_ flag for commands
-	  that don't modify things.
-	* vi.c(first_insert, saved_inslen): new variables.
-	* vi.c(vi_reset): don't reset yanklen, inslen, lastcmd, lastac;
-	  set first_insert, saved_inslen.
-	* vi.c(vi_insert): added code to handle first insertion to allow
-	  redoing commands from last edit.
-	  (based on fixes from Michael Jetzer).
-
-	* vi.c(VVERSION): new state.
-	* vi.c(classify): cleared C_ flag for 032 (^Z); set it for ^V.
-	* vi.c(nextstate): added VVERSION.
-	* vi.c(vi_hook): cases for VVERSION.
-	* sh.h(ksh_version): new declaration; removed declaration from
-	  all other files.
-
-	* Makefile.in: removed rcs-ci, rcs-diff targets; put RCSFILES
-	  into DISTFILES and removed former.
-
-	* var.c(newblock): copy argc/argv from previous env if it exists.
-
-Tue Apr 18 23:10:32 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* jobs.c(exchild): report internal error if execute() returns in child.
-	* exec.c(execute): case TASYNC: clear exec flag in call to execute().
-
-Tue Apr 18 12:05:23 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* emacs.c(x_bind): added list argument.
-	* c_ksh.c(c_bind): added -l (list) option.
-
-	* emacs.c,emacs-c.in: moved emacs.c to emacs-c.in.
-	* Makefile: add rule to create emacs.c from emacs-c.in.
-	* emacs-gen.sh: new file.
-	* emacs.c(struct x_defbindings, x_defbindings[]): new struct/array.
-	* emacs.c(struct x_ftab, x_ftab[]): removed x_db_tab, x_db_char;
-	  initialize x_ftab[] via script.
-	* emacs.c(x_init_emacs): changed to load key bindings from
-	  x_defbindings.
-	* emacs.c(Findex): added typedef.
-	* emacs.c(x_tab[]): changed to index into x_ftab; changed all refernces.
-	* emacs.c(xft_*): changed to XFUNC_*.
-	* emacs.c(XF_PREFIX): new flag, used for x_meta1, 2, 3.
-	* emacs.c(KPREF,KNULL): deleted (no functional use), changed
-	  references to KSTD.
-	* emacs.c(x_last_command): changed type to Findex.
-	* emacs.c(x_emacs): set x_last_command to 0 at start; removed
-	  same from case KEOL.
-
-	* emacs.c(XF_ARG): new flag for struct ftab.
-	* emacs.c(x_ftab[]): filled in XF_ARG for appropriate commands.
-	* emacs.c(x_arg_defaulted): new variable.
-	* emacs.c(x_emacs,x_set_arg): set x_arg_defaulted.
-	* emacs.c(x_bword, x_fword,x_fold_case): removed use of x_last_command.
-	* emacs.c(x_fold_upper,x_fold_lower,x_fold_capitailze): trivial
-	  functions that call x_fold_case; changed x_ftab[] to use these
-	  instead of x_fold_case so arbitrary keys can be bound to them.
-	* emacs.c(x_fold_case): changed to assume argument is 'L', 'U', or 'C'.
-	* emacs.c(x_del_back,x_del_char,x_prev_histword,x_prev_com,x_next_com,
-	  x_kill,x_insert): use x_arg and x_arg_defaulted.
-	* emacs.c(x_delete): don't change mark point (xmp) if <= cp; added
-	  force_push argument; changed all calls.
-
-Mon Apr 17 10:30:12 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* emacs.c(x_e_getc): changed to handle macroptr, ungetting characters.
-	* emacs.c(x_e_ungetc): new function.
-	* emacs.c(x_emacs): let x_e_getc() take care of macroptr.
-	* emacs.c(x_version,x_search_hist): use x_e_ungetc() instead of
-	  macroptr.
-	* emacs.c(x_set_arg): handle string of digits.
-
-	* emacs.c(x_search_hist): handle deleting chars from search string.
-	  (fix from Dale DePriest)
-	* emacs.c(x_search): added sameline paramater.
-	* emacs.c(x_search_list): changes x_zots() to x_e_puts(); make
-	  deleting in empty pattern break out of search.
-
-	* vi.c(domove): case '%': adjust ncursor forward only if matching
-	  opening bracket (so when cursor is on the B in "(fooBar)", c%
-	  changes the openbracket as well.
-	* vi.c(vi_cmd): case y/d/c: special case to move end point ahead
-	  if move cmd is % and match was to the left of the cursor.
-
-Thu Apr 13 10:34:26 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(complete_word): no bell on ambiguous matches (user can
-	  tell its ambiguous 'cause there is not space or slash appended)
-
-	* configure.in,aclocal.m4: added KSH_MEMMOVE, KSH_MEMSET tests
-	  to fix problems with compiler builtins.
-
-	* misc.c(blocking_read, reset_nonblock) new routines.
-	* sh.h: deleted O_NONBLOCK ifdefs/defines.
-	* main.c(main),lex.c(getsc_),edit.c(x_getc),shf.c(shf_fillbuf):
-	  use reset_nonblock().
-	  (fix based on code from John Rochester)
-
-Tue Apr 11 14:36:22 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* history.c(c_fc): mostly POSIXized.
-	* history.c(hist_execute,hist_get_newest,hist_get_oldest): new routines.
-	* history.c(hist_get,histget): changed histget to hist_get.
-	* history.c(hist_replace,histrpl): changed histrpl to hist_replace.
-	* lex.h(SHIST,histpush): deleted; deleted all references.
-	* history.c(histget): add approx check for history that hasn't
-	  happened yet.
-
-	* misc.c(getn): allow leading plus (eg, +3).
-
-	* main.c(initcoms[]): defined history as "fc -l --".
-
-	* conf-end.h(JOBS): don't define if no posix or bsd process groups
-	  (was if SIGCONT not defined).
-
-Mon Apr 10 14:51:54 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(comexec),c_ksh.c(c_getopts),c_sh.c(c_read): use FEXPORT flag.
-
-	* ksh_wait.h: changed to work with autoconf 2.x AC_HEADER_SYS_WAIT -
-	  if sys/wait.h uses union wait, don't include it.
-
-Thu Apr  6 12:19:58 NDT 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* tty.c(tty_init): print warning if open of /dev/tty fails.
-
-Sat Mar  4 01:20:03 NST 1995 Michael Rendell (michael@garfield.cs.mun.ca)
-
-	* io.c(maketemp): create valid dos filenames.
-
-Mon Feb 27 11:04:32 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* Changed from autoconf 1.x to autoconf 2.x.
-	* acconfig.h: included old config.h.top and config.h.bot.
-	* config.h.top, config.h.bot: deleted; deleted all references.
-	* install.sh: changed to install-sh; changed all references.
-	* Makefile.in: use @CPPFLAGS@, @CFLAGS@, @LDFLAGS@;
-	  use @configure_input@; remove config.log and config.cache in
-	  distclean; use @prefix@ and @exec_prefix@.
-	* ksh_dir.h: changed to use new autoconf defines; changed NLENGTH()
-	  to NAMLEN(); changed all references.
-
-Mon Feb 27  9:31:02 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(ISABSPATH): new macro.
-	* var.c(setspec): use ISABSPATH() when setting tmpdir.
-
-	* emacs.c(compl_file): added OS2 ifdefs.
-	* exec.c(scriptexec): OS2: ignore path specified in #! scripts.
-	* sh.h(ksh_dupbase): OS2: now same as unix.
-	* trap.c(sigtraps[],inittraps): remove OS2 defines.
-	* trap.c(alarm_catcher): V7_SIGNALS: use sig, not i.
-	  (Fixes from Dale DePriest)
-
-Mon Feb 27 10:06:00 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* configure.in: test for resource.h.
-	* c_ulimit.c: include ksh_time.h instead of sys/time.h; use
-	  HAVE_SYS_RESOURCE_H when including sys/resource.h
-	  (was HAVE_SETRLIMIT).
-	* aclocal.m4(KSH_RLIM_T): check sys/resources.h for rlim_t.
-
-Fri Feb 24 17:30:16 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(struct macro_state, macro): new structure/variable.
-	* vi.c(vi_hook, vi_cmd): use macro state info to allow nested macros,
-	  detect recursive macros.
-
-Wed Feb 22 21:20:43 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ksh.c(c_whence): "an export" instead of "a export".
-	* vi.c(classify[]): added @<char>.
-	* vi.c(vi_hook,vi_cmd): added support for @<char> (macros).
-	  (fixes from Frank Edwards).
-
-Sun Feb 19 11:57:20 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(comexec): case CFUNC: use cp (not tp->name) when checking if
-	  an autoloaded function was defined; save/restore kshname before/after
-	  function call.
-	* var.c(popblock): don't set kshname to e->loc->argv[0] - it isn't
-	  always right.
-
-Fri Feb 10 12:36:16 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* misc.c(parse_args): check OF_SET when building set_opts (was
-	  checking OF_CMDLINE).
-
-	* conf-end.h(JOBS): don't define if SIGCONT not defined.
-
-	* sh.h(FLOGIN) new enum.
-	* misc.c(options[],parse_args): added login option; set FLOGIN if
-	  name in argv[0] starts with -.
-	* main.c(main): use FLOGIN flag; changed the way OS2 code looks
-	  for profile.
-
-Wed Feb  1 09:55:40 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* expr.c(varsub): in FUNSET test, don't always fail # and %
-	  substitutions (test for unset variable).
-
-Wed Jan 25 09:22:15 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(MIN_COLS): new define.
-	* sh.h(MIN_EDIT_SPACE): new define.
-	* vi.c(prompt_trunc): new variable.
-	* vi.c(edit_resize): calculate how much of prompt to truncate.
-	* lex.c(pprompt): added new argument; changed all calls.
-	* lex.c(yylex),emacs.c(x_emacs),vi.c(x_vi): move pprompt() inside
-	  x_emacs(), x_vi() or just before read in yylex().
-
-Tue Jan 24 12:35:18 NST 1995 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* misc.c(parse_args): changed arrayname variable to array.
-	* var.c(basename): changed name of function to arrayname();
-	  changed all references (Based on fix from Dan Quinlan).
-
-Fri Dec 30 10:34:50 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* ksh.1: modifications to generate two man pages: sh and ksh
-	  (Fixes from Michael Harrdt).
-
-Wed Dec 28 16:55:13 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(complete_word): don't check for globing characters.
-
-Wed Dec 28 10:32:18 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(search_access1): don't use ret variable; move "." to end
-	  of xsuffixes/rsuffixes.
-	* os2.c(_execve): OS2: fixed typo.
-	* sh.h(FILENCMP): changed stricmp to strnicmp.
-	* os2/config.h: added define for rlim_t.
-	* os2/make.sed: changed > null to > nul.
-	* Makefile.in(dist): generate os2/makefile after running Dist-fixup.
-	  (Fixes from Dale DePriest)
-
-Thu Dec 22 15:06:06 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.1.3 distribution
-
-	* *.c: removed RCSids.
-
-Wed Dec 21 11:55:01 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* table.h(struct tbl): changed array field to union of array/fname;
-	  changed all references.
-	* c_ksh.c(c_whence): print undefined function path.
-	* exec.c(comexec): do autoloading of undefined functions; print
-	  error if function can't be found.
-	* exec.c(findcom): fill in tp->u.fname for undefined functions;
-	  search FPATH if search of PATH fails.
-	* table.h(FC_NOAUTOLOAD): deleted define; removed all references.
-
-Tue Dec 20 14:16:16 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(herein): check if name is null.
-	* lex.h(HEREDELIM,SHEREDELIM,SHEREDQUOTE): new defines.
-	* lex.c(yylex): added code for HEREDELIM.
-	* syn.c(synio): use HEREDELIM.
-	* lex.c(readhere): changed to allow \n in here-delimiter.
-
-	* tree.c(tputS): quote ", ` and $ inside "-quotes.
-	* tree.c(ptree,pioact): made static.
-	* tree.c(ptree,fptreef,vfptreef): added indent argument; changed to
-	  use indent argument; changed all calls.
-	* tree.h(struct ioword): added delim field.
-	* tree.c(iocopy),syn.c(synio,syntaxerr): deal with delim field.
-	* tree.c(pioact): print contents of here documents.
-
-	* c_ksh.c(c_typeset): typeset -f foo: set exit code to 1 if function
-	  not found.
-
-Mon Dec 19 15:14:02 NST 1994 Michael Rendell (michael@garfield.cs.mun.ca)
-
-	* history.c(histinit): increment line number for each history line.
-
-	* exec.c(iosetup): OS2: if open /dev/null fails, try nul instead.
-	* Makefile.in(debugtools,install,uninstall): make check-pgrp last;
-	  use $E.
-	* eval.c(eval,expand): OS2: added DODIRSWP code.
-	* main.c(main): OS2: only include $HOME/kshrc.ksh if interactive.
-	* sh.h(FILENCMP,FILECMP,FILECHCONV): new defines.
-	* misc.c(gmatch),vi.c(grabsearch,complete_word),emacs.c(compl_file):
-	  OS2: case insensitive compares.
-	  (fixes from Dale DePriest).
-
-Mon Dec 19 09:54:42 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(vi_cmd): make ~ honour argcnt (fix from Troy Bollinger).
-
-	* vi.c(complete_word): don't add trailing / if there is already one.
-	* vi.c(glob_word): return rval, not 0.
-
-Thu Dec 15 11:06:01 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(vi_cmd): call complete_word() with argument of 1 not 0.
-
-Tue Dec 13 12:07:50 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* history.c(histget): made static; added approx argument; changed
-	  all calls.
-
-Tue Dec 13 10:58:14 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* Makefile.in(mandir): use $(manext), not 1 (fix from Mike Long).
-
-Mon Dec 12 20:55:53 NST 1994 John Rochester (jr@panda.cs.mun.ca)
-
-	* tree.c(ptree): print TELIF part of if statements
-
-Fri Dec  9 15:21:36 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* trap.c(inittraps): OS2: don't trap SIGTERM (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@panda.cs.mun.ca)
-
-	* expr.c(evalexpr): changed div-by-zero test to only derefernce vr
-	  if operation is a divide.
-
-Mon Dec  5 14:42:52 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(search): OS2: typo - changed namlen to namelen.
-	* exec.c(search_access): OS2: check execute bit explicitly.
-	* main.c(main): OS2: don't include ./profile.ksh.
-	* options.h(DEFAULT_PATH): OS2: added /os2 to path.
-	* sh.h(ksh_getdup): OS2: define to getdup(); prototype for getdup().
-	* Makefile.in(dist): create os2 Makefile based on distribution
-	  Makefile.in.
-
-Mon Dec  5 12:17:14 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.1.2 distribution
-
-	* eval.c(globit): when searching directory, re-calculate end of
-	  string based on prefix length.
-
-Fri Dec  2 11:07:48 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* syn.c(wordlist): if token isn't 'in', don't reject ;.
-
-	* eval.c(expand): leading non-white-space IFS chars no cause initial
-	  empty field.
-
-Thu Dec  1 12:04:00 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.1.1 distribution
-
-Thu Dec  1 10:50:38 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(TF_FATAL,fatal_trap): new define,variable.
-	* trap.c(inittraps,trapsig,fatal_trap_check,trap_pending,runtrap,
-	  settrap): use TF_FATAL, fatal_trap.
-	* trap.c(runtraps): changed argument from bool to TF_* flag; changed
-	  all calls.
-	* jobs.c(j_waitj): check fatal_trap flag.
-
-Wed Nov 30 11:20:03 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* conf-end.h: new file.
-	* config.h.bot: moved guts to conf-end.h.
-
-	* emacs.c(struct x_ftab): changed type of xf_db_char from char to int.
-	* emacs.c(x_emacs): changed type of c from char to int.
-	* emacs.c(X_NTAB): new define.
-	* emacs.c(x_bind,x_init_eamcs): new X_NTAB, X_TABSZ.
-	* emacs.c(x_prefix3, x_meta3): ifdef OS2.
-	* emacs.c(x_bind): ifdef OS2; mask *a1 with CHARMASK.
-
-	* exec.c(search_access): new function.
-	* exec.c(search): use search_access() instead of duplicating test.
-	* exec.c(search,search_access1): ifdef OS2.
-
-	* Makefile.in(OS2FILES): new macro.
-	* Makefile.in(dist): add OS2FILES to distribution.
-
-	* options.h(DEFAULT_PATH): ifdef OS2.
-	* edit.c(x_getc,x_mode): ifdef OS2.
-	* path.c(make_path): ifdef OS2.
-
-Tue Nov 29 16:51:35 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(EXECSHELL,EXECSHELL_STR): ifdef OS2.
-	* exec.c(scriptexec): use EXECSHELL_STR (was "EXECSHELL").
-
-	* trap.c(sigtraps[]): ifdef OS2.
-	* lex.c(yylex): ifdef OS2.
-	* misc.c(change_flag): ifdef OS2.
-	* history.c(HISTFILE): ifdef OS2.
-	* eval.c(homedir): ifdef OS2.
-	* c_sh.c(shbuiltins[]): ifdef OS2.
-
-	* sh.h(ksh_execve,ksh_dupbase): new defines.
-
-	* jobs.c(exchild): ifdef use of nice.
-
-Tue Nov 29 12:32:26 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* eval.c(globit,copy_non_glob): changed to pass/use &xp it can change
-	  (memory can be re-allocated).
-
-	* ksh_dir.h(NLENGTH): new macro.
-	* eval.c(globit): use NLENGTH macro.
-
-	* alloc.c(aresize): removed redundant np and optr variables.
-
-Mon Nov 28 14:55:49 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* config.h.bot(HISTORY): new define.
-	* lex.c(getsc_): ifdef HISTORY.
-	* history.c: ifdef HISTORY (dummy histsave, init_histvec and
-	  hist_finish routines).
-	* c_ksh.c(kshbuiltins): c_fc: ifdef KSH
-	* lex.h(HISTORY): changed to HISTORYSIZE; changed all references.
-
-	* options.h(KSH): new define.
-	* config.h.bot: changed to deal with KSH define.
-	* exec.c(do_select,pr_menu): ifdef KSH.
-	* exec.c(execute): case TSELECT: ifdef KSH.
-	* c_ksh.c(c_whence,c_command,kshbuiltins[]): ifdef KSH.
-	* main.c(initcoms[],main): ifdef some aliases, SECONDS/RANDOM/TMOUT.
-	* syn.c(get_command): case TDBRACKET: ifdef KSH.
-	* syn.c(db_parse,db_aoexpr,db_nexpr,dp_primary): ifdef KSH.
-	* syn.c(tokentab[]): "select", "[[" ifdef KSH.
-	* var.c(special,getspec,setspec,unsetspec): ifdef KSH.
-	* ksh.1: ifdef KSH; misc fixups.
-	  (changes mostly from Michael Haardt).
-
-Mon Nov 28 14:27:34 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* var.c(skip_varname,special,global,local), table.c(hash,tsearch,
-	  tenter): made argument and return value const.
-
-	* main.c(version_param[]): new variable.
-	* main.c(initcoms[],main): use version_param instead of "KSH_VERSION".
-
-	* history.c(histsave): EASY_HISTORY: changed to take same arguments
-	  as COMPLEX_HISTORY histsave(); changed all calls, removing
-	  unneeded ifdefs.
-
-	* vi.c(x_vi), emacs.c(x_emacs): changed unwind() call from LINTR
-	  to LSHELL so newline isn't printed twice - also lets runtrap()
-	  set the exit code.
-
-	* vi.c(vi_cmd): increment source line if saving to history.
-
-Fri Nov 25 14:43:57 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* syn.c(get_command): don't generate a syntax error if EOF is read.
-
-	* configure.in: add LDSTATIC to LDFALGS if the former is set.
-
-	* history.c(hist_skip_back): start at the end of the buffer, not
-	  one past the end (fix from Simon J. Gerraty).
-
-Thu Nov 24 09:53:49 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* syn.c(get_command,dogroup): allow { ...;} to be used instead
-	  of do ...;done in for/select loops.
-
-Wed Nov 23 09:09:43 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.1.0 distribution
-
-	* var.c(setspec): set seconds to current time - assigned value,
-	  not just current time.
-
-	* emacs.c(x_copy_arg): deleted ifdef'd out code (x_prev_histword()
-	  does what it was supposed to do).
-
-	* emacs.c(compl_command): don't call list_stash() twice (happened
-	  if type == 2 and multi set).
-
-Tue Nov 22 10:26:13 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_test.c(eval_unop): don't assume S_ISBLK, S_ISCHR, S_ISUID,
-	  S_ISGID are defined.
-
-	* path.c(make_path): avoid addeding extra /'s in paths; avoid
-	  infinate loop if result buffer not big enough.
-
-	* main.c(main): setting PWD: avoid calling setstr() with the
-	  current value of PWD.
-
-	* var.c(typeset): set free_me to 0 if t is integer.
-
-	* emacs.c(x_search_hist): added overflow checking to fixed sized
-	  buffers.
-	* emacs.c(compl_file,compl_command): removed fixed sized buffers.
-
-	* vi.c(x_vi), emacs.c(x_emacs): on interrupt, unwind instead of
-	  calling runtraps().
-
-	* vi.c(vi_cmd): added 'g' command to goto the most recent command.
-
-	* c_sh.c(c_read), c_ksh.c(c_print): always increment source->line when
-	  saving history.
-
-Mon Nov 21 10:45:34 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(do_selectargs): removed use of pmenu variable (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@panda.cs.mun.ca)
-
-	* vi.c(FSHOW8): inverted meaning: now if set, do the M- stuff
-	  (done so 8 bit char sets work by default).
-
-	* main.c(main): set exstat to 127 if command file can't be opened.
-
-	* main.c(main): use argv[0] instead of kshname when deciding
-	  whether to include profiles.
-
-Fri Nov 18 14:25:11 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.0.10.1 distribution
-
-	* tty.h: deleted KSH_VDISABLE; moved _POSIX_VDISABLE stuff to edit.c.
-	* edit.c(x_init): calculate value for vdisable_c.
-	* edit.c(x_mode): use vdisable_c instead of KSH_VDISABLE.
-
-Thu Nov 17 12:09:13 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.0.10 distribution
-
-	* lex.c(getsc_),edit.c(x_getc): call runtraps(FALSE) if read is
-	  interrupted.
-	* vi.c(x_vi),emacs.c(x_emacs): call runtraps(FALSE) (was TRUE).
-
-Wed Nov 16 09:48:54 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(execute,scriptexec): call __setostype(0)/(1) before/after
-	  execve() on ISC machines.
-
-	* trap.c(trap_pending): new fuction.
-	* jobs.c(j_waitj): use trap_pending(); return -<signal-number> if
-	  interrupted.
-	* jobs.c(waitfor): added sigp argument; changed all calls.
-	* c_sh.c(c_wait): use signal number set by waitfor() to set exit status.
-
-	* shf.c(SHF_INTERRUPT): no longer calls intrcheck() - now sets
-	  error flag and returns EOF.
-	* c_sh.c(c_read): re-arranged to have single shf_getc() call; if read
-	  interrupted and signal is fatal (fatal_trap_check()), make read
-	  return with appropriate exit code.
-	* trap.c(fatal_trap_check()): new function.
-	* trap.c(inittraps()): catch and cleanup on SIGHUP; don't force the
-	  setting of SIGINT,SIGQUIT,SIGTERM,SIGHUP.
-
-	* table.c(tenter): changed to use strlen()/memcpy() instead of loops.
-
-	* var.c(initvar): new function.
-	* main.c(main): call initvar().
-	* var.c(special): changed to use hash table for lookup.
-
-	* main.c(main),syn.c(initkeywords): moved table initialization
-	  from main() to initkeywords().
-
-Tue Nov 15 10:01:20 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* eval.c(copy_non_glob): new routine.
-	* eval.c(globit): changed to use copy_non_glob() instead of strchr().
-
-	* misc.c(cclass): if [..] pattern has no closing ], do literal
-	  compare of character with [ (used to always fail).
-
-	* eval.c(globit): handle symbolic links in the check code.
-
-	* configure.in: added check for lstat().
-	* ksh_stat.h: defined lstat to be stat if lstat is not available.
-
-	* exec.c(search): return Xclose() instead of Xstring().
-
-Mon Nov 14 16:28:41 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* ksh_times.h: changed BROKEN_TIMES to TIMES_BROKEN.
-
-	* c_test.c(syntax): removed \n from error messages.
-
-	* eval.c(glob,globit): changed to use dynamicly allocated string
-	  instead of a fixed sized buffer.
-
-Thu Nov 10 10:47:55 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* history.c(sethistsize): don't set size if new size is < 0; fixed
-	  offset calculation so histptr is not way beyond the end of array;
-	  if history is shrinking, save newest history back.
-
-	* vi.c(vi_hook): case VSEARCH: call restore_cbuf() after \n or \r.
-
-	* main.c(quitenv): call restfd() even if fd < 0 to re-close fd.
-
-	* exec.c(execute): commented out code that set savefd[0/1] to -1
-	  if input/output was a pipeline.
-
-	* missing.c(dup2_fixup): deleted function.
-	* sh.h(dup2->dup2_fixup): deleted define.
-	* io.c(ksh_dup2): new function; changed all dup2() calls to ksh_dup2().
-
-Wed Nov  9 11:11:31 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* edit.h(struct edchars): added eof field.
-	* edit.c(x_init): initialize eof fields.
-	* vi.c(x_vi): changed ^D to edchars.eof.
-	* vi.c(vi_cmd): make I/cc/S skip blanks.
-
-	* history.c(histsave): EASY_HISTORY: use memmove() to copy pointers
-	  back one.
-
-	* vi.c(vi_cmd): make G act the same as at&t ksh.
-	* vi.c(ismeta,O_): deleted macros; removed all references to O_.
-	* vi.c(classify[]): add ^X and ^F to command mode.
-
-Tue Nov  8 11:15:01 NST 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* main.c(initsubs[]): don't set SHELL.
-
-	* vi.c(vi_cmd): added v command (start up vi).
-	* vi.c(vi_hook): added case for vi_cmd() returning 2.
-	* vi.c(grabsearch): set anchored flag if pattern starts with ^.
-	  (based on fixes from Michael Jetzer).
-
-	* history.c(findhist): added anchored argument; changed all calls.
-	* history.c(histget): start searching from histptr-1; changed to
-	  call findhist() to do searching.
-	* history.c(c_fc): changed to print multiline commands correctly.
-	  (based on fixes from Michael Jetzer).
-
-Fri Nov  4 10:30:14 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.c(yylex): when pushing alias sources, allocate from existing
-	  source's area.
-
-	* lex.c(struct source): added areap field.
-	* lex.c(pushs): added area argument; changed all calls.
-	* history.c(histrpl): changed constant sized hline[] to expandable
-	  string; removed hline/hsize parameters; changed all calls; put
-	  newline at end of string.
-	* history.c(c_fc): changed to use dynamically sized buffer when reading
-	  commands; strip nulls after read.
-	* history.c(histbackup): made static.
-
-	* trap.c(block_pipe): if handler is SIG_DFL, change it to SIG_IGN.
-
-	* lex.c(readhere): changed to allow eof after end-of-file marker
-	  (bug report from Andrew Moore).
-
-Thu Nov  3 09:09:39 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* io.c(coproc_read_close,coproc_write_close): new functions.
-	* c_sh.c(c_read): call coproc_read_close() when eof is read.
-	* c_ksh.c(c_print): set PO_COPROC if fd is coproc.write; call
-	  coproc_write_close() if write fails due to EPIPE.
-	* exec.c(iosetup): call coproc_write_close() after #>&p.
-	* sh.h(EF_COPROC_DUPED): deleted.
-	* sh.h(struct coproc): deleted isopen field.
-	* io.c(cleanup_coproc): do not use isopen field.
-	* c_sh.c(c_exec): deleted EF_COPROC_DUPED code.
-	* exec.c(TCOPROC): don't set isopen; don't start new coprocess if
-	  old job exists and write pipe hasn't been closed.
-
-	* misc.c(str_zcpy): new function.
-	* lex.c(getsc_): made line[] buffer local/static; use str_zcpy()
-	  to fill line[].
-	* history.c(c_fc): use local hline buffer instead of global line[];
-	  use str_zcpy() to fill hline[];
-	* history.c(histrpl): added hline and hsize parameters; changed all
-	  calls.
-	* history.c(hist_init): EASY_HISTORY: use local hilne buffer instead
-	  of global line[].
-	* lex.h(line[]): deleted.
-	* syn.c(compile): do not set s->str to null for STTY and SHIST.
-
-Wed Nov  2 11:48:36 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.c(getsc_): case SDDPAREN: set csstate before going to
-	  SPAREN state.
-
-	* Makefile.in(RCSFILES): removed POSIX from list (now covered in
-	  man page).
-
-Tue Nov  1 09:27:46 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* eval.c(comsub): save/restore source before/after compile().
-
-	* c_ulimit.c(c_ulimit): allow value to be arithmetic expression
-	  (as per Korn book).
-
-	* c_sh.c(c_read): call set_prompt() before printing prompt.
-
-	* expr.c(v_evaluate): treat an empty expression as 0.
-
-Mon Oct 31 09:23:57 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(grabhist,grabsearch): check that history line doesn't overflow
-	  edit buffer.
-
-	* history.c(hist_finish): (EASY_HISTORY) changed for-loop condition to
-	  prevent passing the end of history.
-
-	* eval.c(expand): when stuffing MAGIC, cast c to char.
-
-	* misc.c(strip_nuls): new function.
-	* lex.c(getsc_): case STTY/SFILE/SSTDIN: call strip_nuls() after
-	  reading commands.
-
-	* edit.c(set_editmode): reversed strstr() arguments - check for
-	  vi/emacs in $EDITOR/$VISUAL string.
-
-	* syn.c(yyparse): allow EOF as well as newline after a command.
-	* lex.c(getsc_): case SSTRING: don't fake newline
-
-Sun Oct 30 10:55:20 NST 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ksh.c(c_print): echo: check for -n, -e and -E options.
-
-	* exec.c(comexec): don't allow command -p if restricted.
-
-Fri Oct 28 10:24:48 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* var.c(typeset): in fake_assign code, was freeing t->val.s + t->type
-	  instead of t->val.s - now uses free_me variable instead of aflag.
-
-	* Makefile.in(depend): change blank lines in depend output to sh.h
-	  so dumb make(1)s won't die.
-
-	* mail.c: changed checking to use atime/mtime instead of size; changed
-	  struct mbox mb_size field to mb_mtime, changed all references.
-
-	* main.c(shell): do not execute (or set the exit status for) a null
-	  command.
-	* lex.c(readhere): read the newline after the eof marker.
-
-Wed Oct 26 09:11:08 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* eval.c(globit): added FMARKDIRS support.
-
-	* emacs.c(x_ftab[]): added entries for ansi arrow key bindings.
-
-	* exec.c(execute,iosetup): move tracing of redirections from
-	  execute() to iosetup() so expanded name can be printed.
-
-	* exec.c(execute): case TDBRACKET: read was being called instead of
-	  test.
-
-	* ksh_stat.h(S_ISCDF): new define.
-	* c_test.c: added -H for context dependent files (HP bizarreness).
-
-	* main.c(initcoms[]): added alias local=typeset.
-
-	* Makefile.in(stamp-h,config.status): added double quotes CONFIG_FILES
-	  and LDSTATIC assignments for dmake.
-	* aclocal.m4(KSH_SYS_SIGLIST): do something with sys_siglist so it
-	  isn't optimized away.
-	* aclocal.m4(KSH_CLOCK_T): do extra check for clock_t in sys/times.h.
-	* acconfig.h(CLOCK_T_IN_SYS_TIMES_H): new define.
-	* sh.h(SIGNALS): use _SIGMAX if NSIG, _MINIX not defined.
-	  (fixes from Brian Campbell <brianc@qnx.com>)
-
-	* emacs.c(x_transpose): changed behavior if FGMACS flag set
-	  (fix from <guy@netapp.com>).
-
-Tue Oct 25 17:11:58 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* tty.c(KSH_VDISABLE): new define.
-	* edit.c(x_init): use KSH_VDISABLE.
-
-Tue Oct 25 09:55:09 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.0.9 distribution
-
-	* c_ulimit.c(c_ulimit): changed SOFT, HARD from enum to defines
-	  to avoid problems with ancient compilers.
-
-	* vi.c(CHAR_LEN,char_len): changed macro to function; added FVISHOW8
-	  support.
-	* misc.c(options[]), sh.h(FVISHOW8): added FVISHOW8 option.
-
-Sun Oct 23 11:02:26 NDT 1994 Michael Rendell (michael@maple.cs.mun.ca)
-
-	* main.c(shell): keep unwinding if LINTR and not interactive.
-
-	* lex.c(yylex): do redumentery quote parsing for $(..).
-
-Thu Oct 20 11:02:27 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(execute): case TSELECT: set rv to 1 if eof is read.
-	* exec.c(execute): case TFOR/TSELECT/TWHILE/TUNTIL: set rv to 0 before
-	  entering loop, but after setjmp incase of a continue; rv to 0
-	  after a break.
-	* exec.c(execute): case TFOR/TSELECT: do readonly check before
-	  assigning value.
-	* c_ksh.c(c_getopts): do readonly check before assigning value.
-
-	* misc.c(print_columns),c_ksh.c(kill_fmt_entry),
-	  misc.c(options_fmt_entry),exec.c(select_fmt_entry): new functions.
-	* c_ksh.c(c_kill),misc.c(printoptions),exec.c(pr_menu): use
-	  print_columns() call a call-back routine to format information
-	  in columns.
-
-Wed Oct 19 10:26:25 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* misc.c(cclass): require MAGIC before - and ].
-	* eval.c(expand): prefix - and ] with MAGIC if appropriate.
-
-	* var.c(typeset): don't allow export flag of readonly variables
-	  to be cleared.
-
-	* eval.c(globit): added call to intrcheck().
-
-Mon Oct 17 11:48:05 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* lex.c(readhere): check for and report write errors.
-
-Sun Oct 16 16:10:59 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* c_ksh.c(c_cd): don't allow cd if restricted.
-	* exec.c(comexec): if restricted and command contains /, print error.
-	* exec.c(ioestup): if restricted, don't allow file creations.
-	* main.c(is_restricted): new function.
-	* main.c(main): save and reset FRESTRICTED during .profile/ENV reading;
-	  set FRESTRICTED if argv[0] or SHELL refers to restricted shell;
-	  make PATH, ENV, SHELL readonly if restricted.
-	* var.c(typeset): check for restricted shell and PATH/ENV/SHELL.
-
-Thu Oct 13 21:01:14 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* main.c(shell): only call j_notify() for interactive shells.
-
-	* c_sh.c(c_read): check if variable is readonly before assigning
-	  value.
-
-Wed Oct 12 14:08:46 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.h(COPROC),tree.h(TCOPROC,XCOPROC): added defines.
-	* lex.c(yylex): return COPROC for |& token.
-	* syn.c(tokentab): added COPROC.
-	* syn.c(c_list): accept COPROC, create TCOPROC node.
-	* tree.c(ptree): added case for TCOPROC.
-	* exec.c(execute): added case for TCOPROC.
-	* io.c(check_fd,get_coproc_fd): new functions.
-	* c_sh.c(c_read),c_ksh.c(c_print): changed to use check_fd();
-	  added -p option; for c_print() ensure SIGPIPE doesn't kill shell.
-	* exec.c(iosetup): changed to use check_fd() for IODUP; when
-	  checking fore close, require exactly the string '-', not any
-	  string starting with '-'; added strerror() to error message.
-	* jobs.c(exchild): don't open /dev/null if XCOPROC; close
-	  coproc.read/write/childread in child if XCOPROC; don't pass
-	  XCOPROC flag on to execute(); set coproc.job to job in parent
-	  if XCOPROC.
-	* jobs.c(check_job): clear coproc.job if said job dies.
-	* trap.c(block_pipe,restore_pipe): new functions.
-	* sh.h(struct coproc, EF_COPROC_DUPED): new structure and define.
-	* c_sh.c(c_exec): if EF_COPROC_DUPED set, clean up co-process stuff.
-
-	* main.c(cleanup_parents_env): new function.
-	* jobs.c(exchild): call cleanup_parents_env() after fork().
-
-	* tree.h(IORDUP): new define.
-	* lex.c(yylex): changed redirection parsing to not accept & only after
-	  a single < or >; set IORDUP flag for x<&y; fixed <</<>/>> check to
-	  not allow >< (again).
-	* tree.c(pioact): use IORDUP flag to print <& or >&.
-
-	* jobs.c(exchild): set JF_ORIGFG flag if job started in foreground.
-	* jobs.c(j_waitj): don't get default tty settings if JF_ORIGFG not
-	  set.
-
-	* misc.c(parse_args): treat -A as a flag that is handled later
-	  (used to require argument); do array setting after argument
-	  sorting.
-	* var.c(set_array): changed second argument from 0/1 flag to
-	  -1/1 flag; changed all calls.
-
-Thu Oct  6 11:55:27 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* table.c(tinit): added initial table size argument; call texpand
-	  if size isn't 0; changed all calls.
-	* main.c(main): try to make sure table size is big enough for
-	  builtins and keywords (cut down on amount of re-hashing).
-
-	* eval.c(expand): added next and prev fields to struct SubType;
-	  removed fixed length subtype array, changed code to allocate
-	  SubTypes as needed.
-
-Wed Oct  5 09:25:06 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* main.c(main): moved initio() above inittraps() as later can print
-	  stuff.
-
-	* table.h(IMPORT): new flag.
-	* var.c(typeset): if IMPORT flag set, don't allow array references,
-	  insist on assignment.
-	* var.c(import): deleted function.
-	* main.c(main): use typeset() instead of import().
-
-	* sh.h: include expand.h.
-	* expand.h(Xnleft): new define.
-	* expand.h(struct XString, Xinit): added areap field; added area
-	  argument to Xinit; changed all calls.
-	* lex.h(struct source): added xs field.
-	* shf.c(shf_gets,shf_getse): changed name fromshf_gets to shf_getse;
-	  return pointer to null byte instead of start of buffer.
-	* lex.c(pushs): if type is SFILE or SSTDIN, initialize s->xs.
-	* lex.c(getsc_): case SFILE/SSTDIN: use s->xs instead of fixed
-	  size line buffer.
-
-	* syn.c(compile): don't change s->str if SFILE.
-	* main.c(main): call pushs() explicitly for each of SSTRING,
-	  SFILE, SSTDIN, STTY.
-
-	* aclocal.m4(KSH_GCC_FUNC_ATTR): changed GCC_FUNC_ATTR to
-	  HAVE_GCC_FUNC_ATTR.
-	* config.h.bot: changed use of GCC_FUNC_ATTR; deleted
-	  GCC_FA_NORETURN, GCC_FA_CONST, GCC_FA_FORMAT defines, created
-	  generic GCC_FUNC_ATTR define; changed all uses of GCC_FA_*.
-
-	* main.c(main): set s->file for SSTDIN input.
-
-	* main.c(shell): pass LERROR on if not interactive.
-
-	* expand.h(Xcheck,XcheckN): added XcheckN define, changed Xcheck
-	  to use XcheckN; made XcheckN call Xcheck_grow_() do do any real work
-	  (to cut down on code size).
-	* misc.c(Xcheck_grow_): new function.
-	* exec.c(search),c_sh.c(c_read): changed to use Xstring() routines
-	  (used to use the fixed size buffer line[]).
-	* exec.c(findcom): avoid re-saving search() result in ATEMP.
-
-Tue Oct  4 15:32:37 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* jobs.c(j_jobs): return int value indicating error/ok; changed
-	  all calls.
-
-	* misc.c(getn): added int * argument to hold result; changed
-	  return value to indicate success/failure; changed all calls.
-	* misc.c(bi_getn): new function.
-	* misc.c(getn_): deleted function.
-
-	* io.c(internal_error,error_prefix,warningf): new functions.
-	* *.c: changed errorf() calls reporting internal errors to
-	  use internal_error() function; changed many shellf()s to
-	  warningf().
-	* io.c(errorf),lex.c(yyerror): changed to use error_prefix().
-
-	* alloc.c(aprint): ifdef'd out.
-	* tree.c(phash): deleted function.
-
-Mon Oct  3 15:08:24 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* sh.h(kshname): new variable
-	* main.c(main): changed name to kshname, deleted local variable.
-	* exec.c(comsub): update kshname.
-	* var.c(popblock): restore kshname.
-	* io.c(errorf,bi_errorf): print shell name before error message.
-
-	* c_ksh.c(c_cd): print new directory on stdout, not stderr.
-
-	* sh.h(GI_MINUS): new define.
-	* misc.c(ksh_getopts): changed so once - or + introduces option,
-	  all options must start with same character.
-
-	* sh.h(builtin_argv0): new variable.
-	* exec.c(call_builtin): set/clear builtin_argv0, builtin_flag; changed
-	  argument to a struct tbl *; changed all calls.
-	* io.c(bi_errorf): new function.
-	* c_ksh.c,c_sh.c,c_ulimit.c,emacs.c,history.c,jobs.c: changed all uses
-	  of errorf() to bi_errorf().
-	* emacs.c(x_bind): changed return value to int; changed all calls.
-	* history.c(histrpl): return 0 if there is an error; changed all calls.
-	* misc.c(parse_args): use bi_errorf(); return -1 for error; changed all
-	  calls.
-	* misc.c(ksh_getopts): call bi_errorf instead of errorf which means
-	  ksh_getopts() may return after an error, so changed all calls to
-	  check for '?' return.
-
-	* exec.c(iosetup): use shellf() to report errors and return value
-	  indicating success or failure.
-	* exec.c(execute): if iosetup fails, cause fatal error for special
-	  builtins, return otherwise; print PS4 and redirections.
-
-Fri Sep 30 15:17:37 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* c_ulimit.c(c_ulimit): accept unlimited as a valid value.
-
-	* c_test.c(c_test): changed posix special case code to use
-	  while loop.
-
-	* c_ksh.c(c_whence): for whence -p, don't look for built-ins or
-	  fuctions.
-
-Thu Sep 29 10:34:59 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* c_ksh.c(c_alias): added -r option so the sysv-bounre shell
-	  hash -r will work.
-
-	* eval.c(debunk): use strchr() to find first MAGIC, if any.
-
-Wed Sep 28 15:34:32 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* sh.h(O_NONBLOCK): define to O_NDELAY or FNDELAY if not defined.
-	* main.c(main): if stdin is O_NONBLOCK'd, clear O_NONBLOCK.
-
-	* misc.c(options[], parse_args): make -c a normal flag, not an option
-	  with an argument (POSIX); deleted cargp argument to parse_args().
-	* main.c(main): print error if -c and no arguments left.
-
-	* lex.h(SSTDIN): new define.
-	* lex.c(yylex): added case for SSTDIN.
-	* main.c(main): if -s flag used, set source type to SSTDIN.
-
-Tue Sep 27 08:52:11 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* lex.c(get_brace_var): new function.
-	* lex.c(yylex): removed most ${..} parsing - leave it to expand();
-	  use get_brace_var() to read the variable part of a ${..} expression.
-	* tree.c(tputs,wdscan): case OSUBST: delete code that understood
-	  partially compiled ${..}.
-	* sh.h(C_SUBOP,C_SUBOP1,C_SUBOP2): changed C_SUBOP to C_SUBOP1,
-	  added C_SUBOP2.
-	* misc.c(initctypes): removed # and % from C_SUBOP; changed C_SUBOP to
-	  C_SUBOP1; added C_SUBOP2.
-	* eval.c(varsub): look at word part of substitution to figure out
-	  type of substitution; check for bad substitutions; check for unset
-	  variables for #/% substitutions.
-	* eval.c(struct SubType): changed type field to stype; changed quote
-	  field to short; added f field.
-	* tree.h(DOTEMP_): new define.
-	* eval.c(expand): case CSUBST: case '=': deleted bad substitution
-	  error (now handled in varsub); case OSUBST: removed special handling
-	  of trimming - varsub() does it now; when pushing/poping state (st),
-	  save/restore value of f; set f to DOPAT when trimming; case CSUBST:
-	  case '=': restore original position in string, substitute the value
-	  of the variable (as opposed to the value that was assigned to the
-	  variable); case OSUBST: if '?' qualifier, turn off DOBLANK when
-	  expandined word part; define DOTEMP_ when expanding word part
-	  of ${..[#%=?]..}; deleted first_eq and tstart - replaced with
-	  tilde_ok and saw_eq.
-
-	* eval.c(expand): tilde expansion: use tstart variable instead of cp;
-	  changed '?' error message to be like at&t ksh; don't test if strval()
-	  returns NULL - it doesn't.
-
-	* var.c(strval): if !ISSET, instead of returning null, set s to null.
-
-	* exec.c(comexec): case TDBRACKET: don't pass DOASNTILDE to evalstr().
-
-	* exec.c(scriptexec): changed line[] to buf[] so it doesn't get
-	  confused with global the line[].
-
-	* main.c(initsubs): initialize PS4.
-	* edit.c(x_getc): cast char to unsigned before returning.
-
-Mon Sep 26 11:06:55 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* eval.c(globit): call strnsave instead of strsave; if file has
-	  trailing /, use stat() to check that it is a directory.
-
-	* eval.c(expand): case CSUBST: case #/%: deleted duplicate *dp = 0;
-	  case CSUBST: case =: copy string and call debunk() to oust MAGICs.
-
-	* misc.c(print_value_quoted): deleted bogus shf_shlout argument to
-	  shprintf(); deleted unneeded test (p != s).
-
-	* main.c(main): turn on FBRACEEXPAND.
-	* misc.c(change_flag): turn FBRACEEXPAND off if turning FPOSIX on.
-
-	* vi.c(x_vi): use x_vi_zotc() to print ^D.
-	* vi.c(CHAR_LEN): new define.
-	* vi.c(vi_hook): use CHAR_LEN() instead of inline tests for
-	  c < ' ' || c== 0x7f; search editing: display M- if necessary.
-	* vi.c(display): changed to deal tiwh meta-characters.
-
-	* vi.c(x_vi_zotc): print M- for meta chars.
-	* emacs.c(x_e_getc): new function; changed all x_getc() calls to
-	  x_e_getc() calls.
-	* edit.c(x_getc): don't and out upper bit.
-
-	* sh.h(OPAREN,CPAREN,OBRACK,CBRACK,OBRACE,CBRACE): new defines
-	* expr.c(OPAREN,CPAREN): re-named to OPEN_PAREN, CLOSE_PAREN.
-
-	* eval.c(debunk): changed to convert MAGIC MAGIC -> MAGIC.
-	* eval.c(expand): removed ismagic_bracket stuff - not needed.
-	* eval.c(expand): always restore value of quote when CSUBST
-	  reached; don't set DOGLOB in fdo if trimming.
-
-Sat Sep 24 11:46:03 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* tree.h(DOBRACE_): new define.
-	* eval.c(expand): changed check for leading ! in [..] to be more
-	  robust (old test could have looked before start of string).
-	* eval.c(expand,maybe_expand_tilde): case ~: moved code into a function
-	  (maybe_expand_tilde).
-	* eval.c(expand): expand alternations after macros, before globing
-	  (was before macros).
-	* eval.c(alt_expand): changed to be called after macro expansion.
-	* eval.c(alt_scan,alt_count): deleted (no longer needed).
-
-	* misc.c(cclass): return NULL (no match) if first char in a range
-	  is greater than the second.
-	* eval.c(expand): when building strings, stuff literal MAGIC chars.
-
-Thu Sep 22 15:05:48 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(comexec): re-arranged handling of builtin and exec;
-	  handle command (and command -p, etc.); deleted comexec_flags
-	  variable; made function static again; removed fcflags argument.
-	* table.h(FC_NOBLOCK): deleted define.
-	* c_sh.c(c_exec): changed empty function to deal with preserving I/O
-	  redirects (code taken from comexec()).
-	* c_ksh.c(c_command): new function - calls c_whence.
-	* c_ksh.c(c_whence): removed code to deal with command -p.
-
-	* Makefile.in: changed [ to test.
-	* shf.h: changed errno structure member to errno_; changed all uses
-	  (fixes for QNX from Brian Campbell).
-
-	* c_test.c(enum Op): deleted trailing comma (some compilers complain).
-	* proto.h: added volatile to tp arg of comexec() prototype.
-
-Thu Sep 22 11:08:31 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.0.8 distribution
-
-	* Makefile.in(install): added missing dollar (fix from Thomas Gellekum).
-
-	* emacs.c: changed CMASK to CHARMASK to avoid conflicts with some
-	  system headers (eg, HP-UX 9.01 <sys/param.h>).  Reported by Sean
-	  Hogan.
-
-	* history.c(c_fc): wp not being incremented; -e strcmp() test reversed
-	  (reported by Sean Hogan).
-
-Thu Sep 21 21:12:03 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.0.7 distribution
-
-Tue Sep 20 09:56:54 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* history.c(c_fc): use ksh_getopt() to parse arguments.
-	* c_ksh.c(c_bind): use ksh_getopt() to parse arguments.
-
-	* main.c(initcoms[]): changed hash alias from alias -t - to alias -t --.
-
-	* misc.c(print_value_quoted): don't use quotes if no special
-	  characters.
-
-	* c_ksh.c(c_whence): added POSIX command command.
-
-	* c_sh.c(c_label): removed check for null wp.
-
-	* exec.c(comexec): added new flags argument (FC_*);
-	  don't call newblock() if FC_NOBLOCK set; pass flags on to
-	  findcom(); changed all calls; made comexc() a non-static
-	  function.
-
-	* table.h:(FC_SPECBI,FC_FUNC,FC_REGBI,FC_UNREGBI,FC_PATH,FC_DEFPATH,
-	  FC_NOAUTOLOAD,FC_NOBLOCK): new defines.
-	* exec.c(findcom): merged insert/justsearch/autoload arguments
-	  into one flags argument; changed code to check various flags;
-	  changed all calls.
-
-Sat Sep 17 20:17:59 NDT 1994 Michael Rendell (michael@garfield.cs.mun.ca)
-
-	* exec.c(comexec): print error if builtin has no command.
-
-	* exec.c(execute): before doing redirections, check for TCOM and
-	  evaluate arguments and determine if it is a special builtin;
-	  print arguments (using PS4) if FXTRACE set; case TCOM: simply call
-	  comexec().
-	* exec.c(comexec): deleted vp argument; only call newblock() if
-	  needed (ie, !special, !empty); evaluate assignments and put
-	  in environment one at a time; print environment (using PS4) if
-	  FXTRACE set; removed code to turn empty command into :;
-	  removed environment setting code in switch statement.
-	* exec.c(echo): deleted function.
-
-	* lex.c(yylex): only honour CMDWORD if FPOSIX set.
-
-	* c_sh.c(shbuiltins): removed = attribute from false/true commands.
-
-	* sh.h(E_TCOM): delete define - not used.
-
-	* sh.h(null),var.c: use EXTERN for initialization of null.
-	* sh.h(space,newline,slash): new variables (" ", "\n", "/")
-	  use these everwhere instead of "", " ", "\n", "/".
-	* path.c: include sh.h.
-
-	* exec.c(execute): combined TFOR/TSELECT cases.
-
-Fri Sep 16 11:32:01 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.h(CMDWORD): new define to prevent continued alias expansion in
-	  non-command contexts.
-	* lex.c(yylex): only set ALIAS if SF_ALIAS and CMDWORD are set.
-	* syn.c(get_command): case LWORD/REDIR: pass CMDWORD if argc is 0.
-
-	* exec.c(comexec): if there is no command, do assignments and set
-	  the return value to subst_exstat (used to fake a : command).
-
-	* sh.h(subst_exstat): new variable.
-	* exec.c(execute): case TCOM: clear subst_exstat before doing eval()s.
-	* eval.c(expand): set subst_exstat to return value of waitlast().
-	* c_sh.c(c_set): if !FPOSIX, return subst_exstat instead of 0.
-
-	* exec.c(execute): removed 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@POOL.Informatik.RWTH-Aachen.DE>).
-	* jobs.c(j_notify,j_waitj): put ifdef JOBS around use of FMONITOR.
-	* main.c(shell): removed ifdef JOBS from declaration of interactive.
-
-	* ksh_limval.h,sh.h: moved include of <limits.h> from ksh_limval.h
-	  to sh.h since some machines define CLK_TCK there.
-
-Thu Sep 15 09:58:14 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* vi.c(vi_cmd): took out ESC as file completion char in command mode
-	  (too annoying).
-
-	* jobs.c(exchild): if starting a job in the background and FBGNICE
-	  is set, call nice().
-
-	* Makefile.in: changed maxext to manext (fix from Thomas Gellekum
-	  <thomas@ghpc8.ihf.rwth-aachen.de>); in the install target, check
-	  if the path of the installed shell is in /etc/shells and
-	  complain if it isn't; added depend target, removed old $(OBJS)
-	  and trap.o dependencies.
-
-Wed Sep 14 09:39:55 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* misc.c(options[]): changed position of vi-tabcomplete option.
-
-	* lex.c(yylex): ifdef use of FVI/FEMACS/FGMACES with VI/EMACS
-	  (fix from Gordan Larson <hoh@approve.se>).
-
-	* ksh.1(DESCRIPTION): added missing P in \fP
-	  (fix from Gordan Larson <hoh@approve.se>).
-
-Tue Sep 13 11:01:47 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.0.6 distribution
-
-Mon Sep 12 11:39:07 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(scriptexec): changed so it will compile if SHARPBANG is
-	  defined; fixed error message; shell argument is everything up to
-	  a newline; don't listen to #! line unless it ends in a newline.
-
-	* syn.c(get_command): case FOR: changed VARASN to ARRAYVAR.
-
-	* jobs.c(waitfor): restore signal mask before returning if named job
-	  isn't own own; when waiting for unspecified jobs, only consider
-	  running jobs; don't pass JW_STOPPEDWAIT flag to j_wait.
-
-	* table.h(V_TMPDIR,tmpdir): new define/variable.
-	* var.c(setspec, unsetspec): added case for V_TMPDIR.
-	* io.c(maketemp): use tmpdir variable if it is set, else use /tmp.
-
-	* var.c(popblock): if poping a variable that wasn't set in the old
-	  environment, call unsetspec().
-
-Fri Sep  9 10:37:18 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(PATHMAX): increased value from 256 to 1024.
-
-	* main.c(main): moved initialization of name to start of main;
-	  if getcwd() fails, use name in error message and call shf_flush().
-
-	* io.c(maketemp): check/use TMPDIR variable instead of /tmp; allocate
-	  temp structure and path in one chunk.
-
-	* c_ksh.c(c_cd): when checking for no home directory, compare
-	  against null, not (char *) 0.
-
-Thu Sep  8 10:52:59 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.c(yylex): case SHIST: flush shl_out after printing command.
-
-	* jobs.c(check_job): when notifing, do not remove job if it is stopped.
-
-Wed Sep  7 10:55:35 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.0.5 distribution
-
-	* main.c(shell): commented out shf_flush(shl_out) - shouldn't be
-	  needed since -v flushes itself.
-
-Tue Sep  6 09:30:57 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* sh.h(LSHELL,really_exit): new define/variable.
-	* c_sh.c(c_exitreturn): if how is LEXIT, check if there are stopped
-	  jobs and, if so, unwind with LSHELL (also check/set really_exit).
-	* main.c(shell): added case for LSHELL - stop unwinding if shell
-	  is interactive; changed local reallyquit to global really_exit.
-	* main.c(include),exec.c(comexec): added case for LSHELL.
-
-	* c_sh.c(c_exitreturn): quitenv() for LRETURN as well as LEXIT.
-
-	* sh.h(TF_CHANGED): new define.
-	* trap.c(runtrap): default EXIT/ERR trap during execution and restore
-	  original if TF_CHANGED not set.
-	* trap.c(settrap): set TF_CHANGED when setting trap.
-
-	* jobs.c(j_stopped): check that job created by current process; print
-	  "You have stopped jobs" message.
-	* main.c(shell): don't print you have stopped jobs message.
-
-	* main.c(initcoms): removed echo alias.
-	* c_ksh.c(kshbuiltins): added echo as a builtin.
-	* c_ksh.c(c_print): if wp[0] is echo, act like strict sysv echo;
-	  added \a (BEL) escape sequence.
-
-	* syn.c(function_body): new function; calls get_command() to get
-	  the body of a function (old code did nested { } block which
-	  caused problems with how redirections after the block were
-	  handled).
-	* syn.c(get_command): call function body to deal with foo() and
-	  function foo.
-
-	* jobs.c(restore_ttypgrp): new variable.
-	* jobs.c(j_change): set restore_ttypgrp if process group is set.
-	* jobs.c(j_exit): if necessary, restore tty process group for main
-	  shell.
-
-Fri Sep  2 21:32:03 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* main.c(main): set FPRIVILEGED if uid (gid) doesn't match euid (egid);
-	  don't include $HOME/.profile if FPRIVILEGED; include
-	  /etc/suid_profile instead of $ENV if FPRIVILEGED.
-	* misc.c(change_flag): if clearing FPRIVILEGED flag, set euid (egid)
-	  to uid (gid).
-
-Fri Sep  2 21:10:23 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* main.c(main): don't include $ENV if uid (gid) doesn't match
-	  euid (egid) (from J.T.Conklin).
-
-Fri Sep  2 12:07:14 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* syn.c(get_command): removed MPAREN case, taken care of in '(' case,
-	  as per POSIX.2 which says () is two operators, not one.
-	* lex.c(yylex): don't check for/return MPAREN.
-	* lex.h(MPAREN): deleted define.
-
-	* configure.in: add test for library routine confstr(); add
-	  header test for paths.h.
-	* sh.h: include paths.h if available; define DEFAULT__PATH.
-	* table.h(def_path): new variable.
-	* options.h(DEFAULT_PATH): new define.
-	* main.c(main): initialize value of def_path; set path to def_path;
-	  remove PATH initalization from initsubs; do not set value of HOME
-	  variable (POSIX); allow SHELL, PS1, PS2, PS3 to have empty values
-	  (at&t ksh).
-	* var.c(unsetspec): when unsetting PATH, set path to def_path.
-
-	* jobs.c(j_waitj): restore proc mask before calling error if
-	  1st tcsetpgrp() fails.
-
-Thu Sep  1 10:28:03 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* Makefile.in: added check-sig.c, check-fd.c and check-pgrp.c
-	  to RCSFILES; added rules for compiling the above; added debugtools
-	  target to compile them all.
-
-	* c_test.c(arg0,t_error,T_ERR_EXIT): new variables/defines.
-	* c_test.c(c_test): set arg0 to wp[0], t_error to 0; after
-	  calling eval_binop() or oexpr() check t_error and if set,
-	  return T_ERR_EXIT.
-	* c_test.c(syntax): set t_error exit; use shellf() instead of
-	  errorf(); use arg0 instead of "test"; delete GCC_FA_NORETURN
-	  attribute; changed all calls to return after calling.
-	* c_test.c(oexpr,aexpr,primary): check terror after calling
-	  oexpr(), aexpr(), nexpr().
-
-	* c_test.c(primary): if unary operator is -t and there is no
-	  argument, don't increment t_wp; if missing closing parenthesis,
-	  show next operand (if any) in error message.
-	* c_test.c(eval_unop): default case, print t_wp[-2] (was -1).
-	* c_test.c(c_test): set t_wp before calling eval_binop() incase
-	  there is an erorr.
-	* c_test.c(syntax): print first message even if op is an empty string.
-
-Wed Aug 31 11:48:51 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* expr.c(O_LT, O_GT): reverse order of enums to match opinfo table.
-
-	* c_test.c(nexpr): always call !nexpr() (never !primary()).
-	* c_test.c(c_test): switch on argc-1 to make code match POSIX
-	  description; make 4 arg case fall into 3 arg case, and 3 arg case
-	  fall into 2 arg case.
-	* c_test.c(is_not,is_and,is_or): new defines.
-	* c_test.c(c_test,oexpr,aexpr,nexpr): use is_not,is_and and is_or.
-	* c_test.c(primary): don't decrement t_wp in final string case.
-
-	* c_test.c(eval_unop): change S_ISIFO to S_ISFIFO and S_ISFITO
-	  to S_ISFIFO.
-
-	* misc.c(parse_args): use OF_SET when initializing set_opts.
-
-Wed Aug 31 09:32:39 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* made pdksh-5.0.4 distribution
-
-	* jobs.c(j_change): do not restore tty process group when turning
-	  off job control; no need to save original tty process group;
-	  deleted orig_ttypgrp variable. (fixes bug in which turning off
-	  job control causes an interactive shell to exit)
-
-Tue Aug 30 14:43:48 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* aclocal.m4(KSH_OPENDIR_CHECK): always include sys/types.h;
-	  set return value according to what failed.
-
-Tue Aug 30 11:17:09 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* missing.c(strerror): for systems without sys_errlist[], report
-	  error number if unknown.
-
-	* Makefile.in: added BUG-REPORTS to DISTFILES.
-
-	* jobs.c(exchild): do tcsetpgrp() in both parent and child after
-	  the first process is created (may need to change to every child).
-
-	* aclocal.m4(KSH_PGRP_SYNC): new test - defines NEED_PGRP_SYNC.
-	* acconfig.h: added define for NEED_PGRP_SYNC.
-	* configure.in: use KSH_PGRP_SYNC test.
-	* jobs.c(exchild,j_startjob,j_sync_open,j_sync_pipe): if NEED_PGRP_SYNC
-	  is defined, use a pipe to block the first process in a pipeline
-	  until the whole pipeline is set up.
-
-Mon Aug 29 09:15:00 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* jobs.c(exchild): for background, unmonitored jobs, don't open
-	  /dev/null if input is a pipe.
-
-	* jobs.c(exchild): for background, unmonitored jobs, use setsig()
-	  instead of setexecsig() to set up SIGQUIT and SIGINT; changed
-	  restoration of SIGTSTP,SIGTTIN,SIGTTOU - set them to DFL if
-	  monitoring and not a `..` command, otherwise leave them alone.
-	* jobs.c(j_init): only use SIGTSTP,SIGTTIN,SIGTTOU if talking
-	  or monitoring - if just talking leave signals ignored.
-	* jobs.c(j_change): if going into job control, set TF_SHELL_USES
-	  flag for sigtraps[SIGTSTP,SIGTTIN,SIGTTOU]; if leaving job control
-	  ignore signals if interactive, else restore original signals.
-
-	* table.h(SPEC_BI, REG_BI): new defines.
-	* exec.c(builtin): check for * or + in front of builtin names and set
-	  SPEC_BI or REG_BI if found.
-	* exec.c(findcom): search for special builtins first, then functions,
-	  then regular builtins, then PATH search.
-	* c_sh.c(shbuiltins[]),c_ksh(kshbuiltins[]): add */+ in front of POSIX
-	  special/regular builtins; add = infront of unset;
-	  remove = from alias.
-	* c_sh.c(c_label): set exit value according to name (for true/false).
-	* c_sh.c(shbuiltins[]): add entries for true and false.
-	* main.c(initcoms[]): deleted true/false aliases.
-
-	* aclocal.m4(KSH_OPENDIR_CHECK): new test - see if opendir() will
-	  open non-directories.
-	* configure.in,acconfig.h: added KSH_OPENDIR_CHECK.
-	* missing.c,ksh_dir.h(ksh_opendir): new define/function.
-	* eval.c(globit),emacs.c(compl_file): use ksh_opendir() instead of
-	  opendir().
-
-	* main.c(include): save source filename since search() uses line[]
-	  for the filename and shell() trashes line[].
-
-	* table.h(FINUSE,FDELETE) new defines.
-	* exec.c(execute): case CFUNC: re-arranged code so normal return goes
-	  through setjmp() switch; use FDELETE/FINUSE flags to avoid problems
-	  with a function being undefined or redefined during its execution.
-	* exec.c(define): if FINUSE is set, set FDELETED and find a new table
-	  entry.
-
-Fri Aug 26 21:58:25 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.c(getsc_): flush output after write when echoing.
-
-	* Makefile.in(dist): after creating distrubution, use pathchk -p
-	  to check file names.
-
-Fri Aug 26 10:28:20 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* made pdksh-5.0.3 distribution
-
-	* expr.c(IS_ASSIGNOP): new define.
-	* expr.c(evalexpr): use IS_ASSIGNOP (bug fix).
-
-	* exec.c(execute): case TFOR,TSELECT: change e->type just
-	  before setjmp() to avoid problems with bad jmpbufs.
-
-	* jobs.c(startlast): new function.
-	* jobs.c(waitlast): print error if job not started.
-	* eval.c(comsub): call startlast() after execute().
-	* jobs.c(exchild,j_startjob,j_sync_pipe): when starting a pipeline
-	  use a pipe to ensure the first process doesn't die before
-	  the last process is started.
-
-	* exec.c(execute): case TFUNC: set/clear FXTRACE according to
-	  tp->flag & TRACE, and restore old value when function completes.
-
-	* c_test.c,exec.c,io.c,mail.c,vi.c: changed all uses of
-	  (x&S_IFMT) == S_IF* to the equivilent S_IS* (for ISC unix).
-	* c_test.c(eval_unop): if system doesn't have symlinks or sockets
-	  (S_ISLNK,S_ISSOCK), return 0 (used to cause internal error).
-	* ksh_stat.h(S_ISVTX): define if sys/stat.h doesn't.
-
-	* sigaction.c(Signal,signal): ifdef'd Signal() and signal() out as
-	  they cause header file conflicts on some systems (eg, signal()
-	  in ISC unix); also ifdef'd out other routines not used by ksh
-	  (ie, sigdelset, sigfillset, sigismember, sigpending).
-
-Thu Aug 25 11:50:03 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* c_test.c(primary): always check that *t_wp isn't 0 before using it.
-
-	* eval.c(homedir): cache home directory values.
-
-	* exec.c(findcom): search builtins before tracked aliases.
-
-	* table.h(commands,taliases): changed name of commands to taliases.
-
-	* c_ksh.c(c_unalias): changed to use ksh_getopt(); added -t and -a
-	  options; exit with non-zero value if non-alias name unaliased
-	  (POSIX).
-
-	* main.c(initcoms[]): alias hash to 'alias -t -'; added autoload alias
-	  as well; set selected comands to be tracked aliases (eg, grep,
-	  ls, who, vi, emacs, etc.).
-
-	* c_ksh.c(c_alias): when printing aliases, check ISSET, not DEFINED
-	  flag (so unset tracked aliases won't cause problems); changed
-	  to use ksh_getopt(); added -t flag; added -x flag (does nothing).
-	* c_ksh.c(c_hash): deleted function; removed all references.
-
-	* table.h(CTALIAS): new define.
-	* exec.c(findcom): added search argument for whence -p; fixed
-	  introduced bug preventing tracking of commands when insert set;
-	  changed all calls; when creating tracked aliases, set type to CTALIAS
-	  (was CEXEC).
-	* exec.c(findcom,flushcom): when freeing old tracked aliases, use
-	  APERM, not commands.areap.
-	* c_ksh.c(c_whence): changed to use ksh_getopt(); assume findcom()
-	  never returns 0 and never returns tp->type == CNONE; made output
-	  closer to at&t ksh output; combined vflag/!vflag switch statements;
-	  added case for CTALIAS.
-	* exec.c(findcom): set tracked alias type to CTALIAS.
-
-	* c_ksh.c(c_print): added -s option; changed to use Xstring() routines
-	  and write() instead of shf routines; returns non-zero if there
-	  was a write error.
-
-	* jobs.c(struct job): changed pid_t lpid field to Proc *last_proc;
-	  changed all uses.
-	* jobs.c(check_job): use j->last_proc instead of lp.
-	* jobs.c(j_waitj): when checking for fake ^C, test j->last_proc
-	  status to see if it was signaled and use WTERMSIG to get signal.
-
-	* main.c: initialize integer TMOUT parameter to 0; call alarm_init()
-	  if FTALKING.
-	* trap.c(alarm_init,alarm_catcher): new functions.
-	* trap.c(runtraps): if ksh_tmout_leave is set, exit.
-	* sh.h(TMOUT_EXECUTING,TMOUT_READING,TMOUT_LEAVING,ksh_tmout,
-	  ksh_tmout_state): new enum values/variables.
-	* table.h(V_TMOUT): new define.
-	* var.c(special,setspec,unsetspec): added V_TMOUT entry.
-	* edit.c(x_getc): call intrcheck() if read interrupted.
-
-Thu Aug 25 09:36:54 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* c_test.c(c_test): for argc cases 4 and 5, return the complement
-	  of the expressioin result; for [[ .. ]] expressions, don't parse
-	  based on argc; deleted struct t_op.op_flags field and related
-	  defines UNOP,BINOP,ACCEPT_BE,ISTEST,ISDBRACKET,ISBOTH - changed all
-	  uses to test the value of isdbracket.
-	* c_test.c(filstat): moved body of filstat() into eval_unop(), deleted
-	  filstat().
-
-	* c_test.c: incorperated changes from J.T. Conlin (jtc@cygnus.com)
-	  for POSIXization of test builtin.
-
-Wed Aug 24 12:16:25 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* new-version.sh: new file - updates date in version.c
-	* Makefile.in: added new-version.sh to RCSFILES; call new-version.sh
-	  in dist: target.
-
-Tue Aug 23 09:28:10 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* made pdksh-5.0.2 distribution
-
-	* jobs.c(exchild): don't call restoresigs().
-	* exec.c(execute): do call restoresigs() (just before execve()).
-
-	* c_sh.c(c_trap): ifdef'd out code to print default traps.  Too ugly
-	  and it isn't clear POSIX needs it.
-
-	* c_ksh.c(c_print): put -e option back in for echo emulation (-R).
-
-	* c_sh.c(c_shift): generate error if n < 0.
-
-	* c_sh.c(c_trap): use shellf instead of errorf to report errors
-	  (so we can return a value instead of unwinding - POSIX).
-
-	* exec.c(execute): if command fails and !FERREXIT, call
-	  trapsig(SIGERR_).
-
-	* c_sh.c(c_exit,c_return,c_exitreturn): combined c_exit and c_return
-	  functions.
-
-Mon Aug 22 09:39:54 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* eval.c(expand): case XARG: set word to IFS_WORD to force null
-	  words to be created.
-
-	* lex.c(yylex): added indquotes flag and code for `...` parsing
-	  (to deal with "`...`" the way sh/at&t-ksh does).
-
-	* trap.c(runtrap): don't reset ERR trap.
-
-	* sh.h: combnied SS_USER/SS_FORCE flags with RESTORE_CURR et. al.
-	  flags; changed RESTORE_* to SS_RESTORE_*.
-	* trap.c(setsig): combined restore, force and user flags; changed
-	  all calls.
-	* trap.c(setexecsig): use SS_RESTORE_* values as argument.
-
-	* table.h: changed LCASE to LCASEV (and UCASE_AL to UCASEV_AL) to
-	  avoid problems with ioctl/tty LCASE define.
-
-	* sh.h(struct env): deleted interactive field.
-	* main.c(shell),exec.c(iopsetup): deleted e->interactive assignment.
-
-	* sh.h: made e a struct env * (was struct env); changed all references.
-	* main.c(newenv): copy loc, flags and interactive fields explicitly.
-
-	* var.c(newblock): allocate block structure, don't assume already
-	  exists.
-	* var.c(popblock): free old block structure.
-	* main.c(main): set e->loc to 0 before calling newblock().
-	* exec.c(comexec): let newblock() allocate new structure; deleted
-	  l variable (changed references to e->loc).
-	* table.h: deleted globals variable.
-
-	* c_ksh.c(c_print): treat a lone - like --.
-
-	* main.c(main),trap.c(inittraps): move SIGINT,SIGQUIT,SIGTERM signal
-	  initialization to inittraps() and do it regardless of FTALKING.
-
-	* trap.c(settrap): deleted force trap since probably will never
-	  add -f flag to trap.
-
-	* main.c(unwind): if we are dieing of SIGINT or SIGTERM, kill
-	  ourselves with a signal.
-
-	* vi.c(x_vi),emacs(x_emacs): if ^C read, call trapsig()/runtraps();
-	  don't return -2.
-	* edit.c(x_read): don't check for -2 return value.
-	* vi.c(x_vi): check for quit char (^\) and fake SIGQUIT.
-
-	* exec.c(comexec): made flags argument volatile.
-
-	* misc.c(getn_): new function.
-	* c_sh.c(c_exit,c_return): call quitenv() before unwind()ing;
-	  moved c_exit() next to c_return(); use getn_() instead of getn().
-
-	* main.c(shell): added exit_atend argument to deal with POSIX trap exit
-	  semantics; changed all calls.
-	* sh.h: added STOP_RETURN macro.
-	* c_sh.c(c_return): determine if we are returning or exiting before
-	  unwind()ing so POSIX trap exit semantics are honored.
-
-	* jobs.c(j_sigchld): call trapsig() instead of messing with sigtraps[].
-	* trap.c(trapsig): don't restore signal handler if it wasn't set to
-	  trapsig.
-
-	* sh.h: added TF_TTY_INTR flag.
-	* trap.c(inittrap): set TF_TTY_INTR for SIGINT.
-	* jobs.c(j_waitj): if
-
-	* jobs.c,sh.h: deleted SA_RESTART ifdefs; moved SIGCLD->SIGCHLD ifdefs
-	  from jobs.c to sh.h.
-
-Sat Aug 20 15:26:24 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* sh.h: added KSH_SA_FLAGS define.
-	* trap.c(inittrap,setsig): set sa_flags field to KSH_SA_FLAGS.
-	* sigact.c(sigaction): if using BSD42_SIGNALS, set the SV_INTERRUPT
-	  flag.
-	* configure.in: deleted AC_RESTARTABLE_SYSCALLS.
-	* config.h.bot: add error message to prevent compilation if using
-	  BSD41 signals.
-
-	* shf.h: added SHF_INTERRUPT flag.
-	* shf.c(shf_fillbuf,shf_putchar,shf_write,shf_emptybuf): call
-	  intrcheck() if read()/write() interrupted and SHF_INTERRUPT set.
-	* c_sh.c(c_read): use SHF_INTERRUPT flag.
-	* lex.c(getsc_): call intrcheck() if read() interrupted.
-
-	* main.c(main),trap.c(inittrap): moved Sigact* initialization
-	  from main() to inittrap(); made Sigact_trap/Sigact_ign static;
-	  deleted Sigact and Sigact_dfl.
-	* sh.h: deleted declarations of Sigact*.
-
-	* main.c(shell): deleted sigaction call - no longer needed.
-
-	* sh.h: added RESTORE_CURR, RESTORE_ORIG, RESTORE_DFL and RESTORE_IGN
-	  defines.
-
-	* trap.c(intrcheck): new function.
-	* trap.c(runtraps): added intr argument; clear trap/intrsig
-	  before running traps; changed all calls.
-	* trap.c(runtrap): save/restore exstat when running trap.
-	* jobs.c(j_waitj): changed interrupt test to check intrsig
-	  and return -1.
-	* jobs.c(waitfor): if j_waitj() returns -1, call intrcheck().
-	* jobs.c(j_change): use setsig() instead of sigaction() to
-	  set up SIGTTIN,SIGTTOU,SIGTSTP.
-
-	* trap.c(inittraps): initialize flags for INT/QUIT/TERM.
-	* sh.h(intrsig): new variable.
-	* trap.c(trapsig): set intrsig if signal has TF_DFL_INTR flag set;
-	  deleted longjmp().
-	* trap.c(runtraps): clear intrsig.
-	* trap.c(runtrap): if signal is defaulted and TF_DFL_INTR is
-	  set, set exstat and call unwind(); return if signal ignored;
-	  reset an ERR trap before executing it.
-	* trap.c(cleartraps): deleted special case for EXIT; reset
-	  command traps using settrap(); clear intrsig.
-	* trap.c(restoresigs): only deal with traps that have the TF_EXEC_IGN
-	  flag set (others take care of themselves).
-
-	* trap.c(sigtraps[]): added ERR trap.
-	* trap.c(gettrap): deleted #if 0'd ERR/EXIT check.
-	* trap.c(gettrap,runtrap,cleartraps,restoresigs): use SIGNAL+1 to
-	  go through trap table.
-	* sh.h(SIGEXIT_,SIGERR_): new defines.
-	* c_kill.c(c_kill): test for signals > 128 (was >= 128)
-	* c_sh.c(c_trap): when printing traps, use SIGNALS+1.
-
-	* sh.h(struct trap): replaced ourtrap and sig_dfl fields with
-	  flags field; defined TF_SHELL_USES, etc. for flags field; added
-	  cursig field.
-	* sh.h(struct env): replaced func_parse field with
-	  flags field; defined EF_FUNC_PARSE, EF_BRKCONT_PASS for flags
-	  field; defined STOP_BRKCONT(); changed uses of func_parse
-	  (get_command()/readhere()).
-	* c_sh.c(c_brkcont): use STOP_BRKCONT(), EF_BRKCONT_PASS; call
-	  unwind() to do the work.
-
-Fri Aug 19 09:59:43 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* trap.c(settrap): new function - does most of what c_trap did.
-	* c_sh.c(c_trap): changed to use settrap(); print out default
-	  actions as well as caught/ignored actions.
-	* trap.c,c_sh.c(setsig): moved setsig from c_sh.c to trap.c and
-	  made it static; added force and user arguments; don't do anything
-	  for EXIT and ERR.
-	* main.c(main): use sigtrap() instead of ignoresig().
-	* trap.c(ignoresig): deleted function.
-
-	* exec.c(execute): case TSELECT: don't change SIGINT signal handler.
-
-	* proto.h: use GCC_FA_NORETURN on aerror().
-	* syn.c(yyparse): made function static and void.
-
-	* exec.c(herein): changed error() calls to errorf()s; use error()
-	  in error handler; call shf_close() instead of shf_fdclose().
-
-	* tree.h,sh.h: moved LBREAK/LCONTIN from tree.h to sh.h;
-	  added LEXIT, LRETURN, LERROR, and LINTR defines; changed values
-	  of LBREAK/LCONTIN; changed all calls to longjmp() and setjmp().
-	* exec.c(execute): put Break: label after main switch, changed
-	  goto Break[0-9] to Break; deleted Break[0-9] labels.
-	* exec.c(execute): changed FOR, SELECT, WHILE, DO loop setjmps
-	  to explicitly check for LBREAK/LCONTIN, otherwise call unwind().
-	* exec.c(execute): case TFUNC: added setjmp switch statement to take
-	  care of various L* values.
-	* main.c(include,shell): added setjmp switch statement to take care of
-	  various L* values.
-	* main.c(unwind): added L* parameter to pass on to longjmp();
-	  changed all calls.
-	* c_sh.c(c_return): just call unwind(LRETURN);
-	* main.c(unwind): put code from leave() in E_NONE case.
-	* main.c(error,leave): deleted functions; replace all calls with
-	  unwind(LLEAVE or LERROR).
-	* *.c(longjmp): replaced all calls with unwind(L..) (except the
-	  call in unwind()).
-
-	* shf.h: add areap field to struct shf.
-	* shf.c(shf_fdopen,shf_sopen): initialize areap
-	* shf.c(shf_emptybuf,shf_close,shf_sclose,shf_finish): use areap
-	  instead of ATEMP.
-
-	* shf.c(shf_sopen): if buf is 0 and writing and DYNMAIC, allocate
-	  a buffer; if writing, save room for a trailing null.
-	* shf.c(shf_sclose): new function.
-	* shf.c(shf_snprintf),tree.c(snptreef): use shf_sclose().
-	* tree.c(snptreef): changed return type to char *; if buffer
-	  is null, pass SHF_DYNAMIC to shf_sopen(); return (possibly
-	  allocated) string.
-	* syn.c(syntaxerr): use snptreef() instead of ident.
-
-	* tree.h: new define TDBRACKET; new defines DB_NORM,DB_OR,DB_AND,
-	  DB_BE,DB_PAT.
-	* tree.c(ptree): added case for TDBRACKET.
-	* syn.c(get_command): case DBRACKET: make TDBRACKET command;
-	  at end of function, null terminate args/vars if TDBRACKET.
-	* c_test.c(is_db_patop): new function.
-	* syn.c(db_primary): set type of arg to DB_PAT if is_db_patop()
-	  returns true.
-	* exec.c(execute): added case for TDBRACKET.
-
-	* syn.c(get_command): case MDPAREN: make arg[0] an allocated stuffed
-	  string (was a literal string).
-
-Thu Aug 18 11:06:49 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* c_test.c(is_op,is_binop,is_unop): new functions to test for
-	  unary/binary operators.
-	* c_test.c(oexpr,aexpr,nexpr,primary): no longer take argument -
-	  call is_unop/is_binop directly.
-	* c_test.c(ISDBRACKET,ISTEST,ISBOTH,ACCEPT_BE): new defines.
-	* c_test.c(struct t_op): changed op_type field to op_flags.
-	* c_test.c(ops[]): broke into two arrays: u_ops and b_ops;
-	  set flag field to ISDBRACKET/ISTEST/ISBOTH as appropriate.
-	* c_test.c(t_lex): deleted function.
-	* c_test.c(primary): before checking for unary operator, check
-	  for -BE (binary expression next) if appropriate.
-
-	* c_test.c: made operator type an enum to make it easier to add
-	  operators; changed oexpr/aexpr/nexpr/primary/filstat/t_lex
-	  operand/return types.
-	* c_test.c(struct t_op): changed op_text from char * to char [4].
-	* c_test.c(primary): case FILTT: using digit(**t_wp) causes core dump
-	  when there is no arg - just test if *t_wp is 0; move test into
-	  filstat().
-	* c_test.c(primary): use *opnd1 != 0 instead of strlen(opnd1) (3
-	  instances).
-
-	* tree.c(wdscan,wdcopy): changed string argument to const; changed
-	  return type of wdscan to const.
-
-	* eval.c(expand): case CSUBST: case '?': use st->var->anme instead
-	  of cp to allow proper nesting.
-	* eval.c(expand): case OSUBST: don't change cp - declare local
-	  variable.
-	* eval.c(expand): case COMSUB: deleted Xsavepos() call; XCOM: deleted
-	  Xrestpos() call.
-	* eval.c(expand): save the position of the first unquoted = for tilde
-	  expansion.
-	* eval.c(expand): case '~': use sp == (cp+2) instead of dp == Xstring
-	  so we aren't fooled by ''~ or ${foo}~; sp[-1]/sp[-2] and firsteq
-	  for the DOASNTILDE after first = or unquoted : test.
-
-	* tree.h(struct op): changed noexpand field to evalflags; changed
-	  all uses.
-	* exec.c(execute): if t->evalflags is non-zero, pass them to eval().
-
-	* lex.h: added DBRACKET define for [[ keyword.
-	* syn.c(get_command): added case for DBRACKET.
-	* syn.c(db_parse,db_oaexpr,db_nexpr,db_primary): new functions
-	  to parse [[ .. ]] expressions.
-	* syn.c(tokentab[]): added [[/DBRACKET keyword.
-	* c_test.c(is_db_unop,is_db_binop): new functions to test if arg
-	  is [[ .. ]] unary/binary operator.
-
-	* syn.c(syntaxerr): call REJECT; before token; removed REJECT
-	  before all calls to syntaxerr().
-	* syn.c(get_command): removed syntax error kludge.
-
-Wed Aug 17 11:07:40 NDT 1994 Michael Rendell (michael@arlene.cs.mun.ca)
-
-	* c_test.c(struct ops): changed -U to -O.
-
-	* tree.h: added new defined DOASNTILDE.
-	* eval.c(expand): case '~': changed !(f&DOBLANK) to f&DOASNTILDE.
-	* exec.c(execute): case TCOM: pass DOASNTILDE when evaluating vars
-	  and when expanding args when t->noexpand is set.
-
-	* exec.c(execute): case TCASE: pass DOTILDE to both evalstr() calls
-	  (POSIX).
-
-	* syn.c(get_command): don't check for redirections before determining
-	  command type; handle REDIR where LWORD are handled; default case
-	  always returns; pass ARRAYVAR flag to tpeek() if t->noexpand;
-	  don't allow redirections before "x()" function; don't allow
-	  redirection before keywords; allow a '(' in the case LWORD/REDIR:
-	  if no variables or arguments (POSIX doesn't allow this, but
-	  at&t ksh/bourne sh do).
-	* lex.h(ARRAYVAR): new define.
-	* lex.c(yylex): parse x[1 & 2] as one word if VARASN|ARRAYVAR.
-
-	* var.c(is_wdvarname): added aok argument; changed all calls.
-	* syn.c(get_command): case FOR/SELECT: check identifier is valid.
-
-	* c_sh.c(c_trap): use print_value_quoted() to print traps;
-	  use ksh_getopt() to skip possible --.
-	* trap.c(gettrap): allow digits only if signal numbers match
-	  POSIX values (ie, HUP=1,INT=2,QUIT=3,ABRT=6,KILL=9,ALRM=14,TERM=15).
-
-	* misc.c(print_value_quoted): new function to print strings with
-	  appropriate quoting.
-	* c_ksh.c(c_typeset,c_alias): use print_value_quoted() when printing
-	  values.
-
-	* lex.h: added new ESACONLY flag - only accept ESAC keyword.
-	* lex.c(yylex): check for ESACONLY flag when doing keyword search.
-	* syn.c(caselist): pass ESACONLY flag to tpeek().
-
-Tue Aug 16 10:17:47 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.h(struct source); changed echo field to generic flags field;
-	  defined SF_ECHO and SF_ALIASEND.
-	* lex.c(_getsc): case SALIAS: use isspace() to check for trailing
-	  space in alias; if alias does not end in a space, return a fake
-	  space to keep the current alias in the source list - this allows
-	  recursive alias detection; set SF_ALIAS in next source if alias
-	  does end if space.
-	* lex.c(yylex): deleted expanding_alias, rec_alias_cnt and
-	  rec_alias_table variables; check for recursive aliases by checking
-	  the source list; don't use EXPALIAS flag; if SF_ALIAS is set in
-	  current source, set ALIAS flag and clear SF_ALAIS; deleted global
-	  alias variable.
-	* table.h: deleted EXPALIAS define.
-	* main.c(shell): changed s->echo to set/clr of SF_ECHO in s->flags.
-
-	* table.h: added aliases and keywords tables; deleted lexicals table
-	  (POSIX says they are 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@panda.cs.mun.ca)
-
-	* c_ksh.c(c_print): added at&t ksh -R flag; deleted -e flag;
-	  changed to use ksh_getopt().
-	* main.c(initcoms[]): changed echo alias from 'print -' to 'print -R'.
-
-	* sh.h: new variable procpid; added pid field to struct temp.
-	* jobs.c: changed references to my_pid to procpid; deleted my_pid
-	  variable.
-	* io.c(maketemp): initialize pid field from procpid.
-	* main.c(remove_temps): only remove temporary files created by
-	  the current process.
-
-Sun Aug 14 11:47:05 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* var.c: added var field to struct Expand and struct SubType; deleted
-	  struct SubType.name field.
-	* var.c(expand): case OSUBST: use x.var/st->var field to save result
-	  of global() for use in case CSUBST - this avoids problems with
-	  x[i+=1] being evaluated twice; check to see if value is being
-	  assigned to non-variable (eg, ${*:=aja}) or read-only variable.
-	* var.c(varsub): set value of xp->var; possibly generate error if
-	  FNOUNSET set when expanding ${#*}, ${#var}, or ${#array[*]}.
-
-	* table.h: added struct tbl.areap field to get rid of lastarea
-	  problems; deleted lastarea variable; changted all refernces
-	  to lastarea to var->areap.
-	* table.c(tenter): initialize areap field.
-	* var.c(arraysearch): deleted area parameter; initialize areap field.
-	* var.c(global,local,intval,setint): initialize areap field of vtemp.
-
-Fri Aug 12 10:54:51 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* expr.c: re-wrote e*() functions using single function and table;
-	  token() now does table lookup; added full C expressions (sans
-	  pre/post increment, sizeof).
-
-	* table.h(INT_U,INT_L): new flags.
-	* var.c(strval): handle INT_U.
-	* c_ksh.c(c_typeset): add exclusions for INT_U/INT_L;
-	  add -U option for unsigned (non-at&t ksh).
-
-	* var.c(set_array): use global() instead of local();
-
-	* var.c(global): when parsing $123, don't limit number to 1000.
-
-	* expr.c(v_evaluate): like old evaluate, but assigns result to
-	  specified variable.
-	* expr.c(evaluate): changed to use v_evaluate().
-	* expr.c(e0): when parsing literals, use strint() instead of setstr().
-
-	* var.c(setstr): when assigning to integers, use v_evaluate() instead
-	  of strint().
-
-Thu Aug 11 11:33:17 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* var.c(strint): don't change anything until number completely
-	  parsed; don't clear ISSET flag if parsing fails; fail parse
-	  if non-integer/non-letter found; default base if copying from
-	  integer variable; set ISSET if parsing succeeds.
-
-	* expr.c(tempvar): set vp->val.i to 0.
-	* expr.c(token): when skipping a literal number, don't allow _;
-	  use isspace() to skip.
-	* expr.c(asn): use strint()/setstr() instead of setint().
-	* expr.c(e0): added unary ~ and + (posix).
-
-	* var.c(global,local): always call substitute on contents of [..];
-	  free sub when finished eval.
-
-	* ksh_limval.h: new file.
-	* shf.c: use ksh_limval.h.
-	* Makefile.in: added ksh_limval.h to HDRS.
-
-Wed Aug 10 10:57:01 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ksh.c(c_whence): case CFUNC: print exported/traced/undefined,
-	  do not print function definition.
-	* exec.c(findcom): new argument indicated if functions to be
-	  autoloaded; changed all calls.
-
-	* misc.c(ksh_getopt): added # option modifier for typeset.
-	* c_ksh.c(c_typeset): changed to use ksh_getopt(); added
-	  -L, -R, -Z, -l, -u flags; quote variable values when printing;
-	  generally re-arranged function.
-	* table.h: added LJUST,RJUST,ZEROFIL,LCASE,RCASE; deleted FUNCT.
-	* exec.c(findfunc): new function.
-	* exec.c(define,findcom): use findfunc(); skeleton autoload code.
-	* var.c(typeset): added two arguments for initial field width and
-	  base; changed all calls; deal with LJUST,.. flags; re-arrange to
-	  have one loop iterating over array; do readonly check before
-	  changing attributes.
-	* var.c(strval): deal with LJUST,.. flags when getting integers.
-	* var.c(setstr): deal with LJUST,.. flags when setting strings.
-	* var.c(setstr): deal with LJUST,.. flags when setting strings.
-	* var.c(arraysearch,tenter): initialize {new,p}->field to 0.
-	* table.h: added struct tbl.field.
-
-	* siglist.in: changed signal messages to be more or less the
-	  same as sys_siglist[]; moved SIGUNUSED before SIGBUS.
-	* jobs.c(j_print): assume sigtrap[].mess always valid; use
-	  sigtrap[].mess directly for stopped processes.
-
-	* aclocal.m4(KSH_SYS_SIGLIST): new macro like KSH_SYS_ERRLIST.
-	* configure.in: use KSH_SYS_SIGLIST instead of AC_SYS_SIGLIST_DECLARED.
-
-Tue Aug  9 10:28:45 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* version.c: removed RCS logs since version numbers don't match
-	  release numbers.
-
-	* configure.in: added AC_PROG_CPP
-	* Makefile.in: added rules for generating siglist.out
-	* siglist.in,siglist.sh: new files.
-	* trap.c(inittraps,deftraps[]): deleted deftraps[]; initialize
-	  sigtraps[] directly by including siglist.out.
-
-	* tree.h: added EXPRSUB for $((..)), re-numbered defines.
-	* tree.c(tputS,wdscan): added case for EXPRSUB.
-	* eval.c(expand,alt_count,alt_scan): added case for EXPRSUB.
-	* lex.h: added SDDPAREN for $((..)).
-	* lex.c(yylex): added case for SDDPAREN.
-
-	* lex.c(yylex): case SPAREN: match parenthesis using counter instead
-	  of pushing/poping states.
-
-	* lex.h: re-numbered S* defines to be sequential; added SREREAD.
-	* lex.c(yyerror): pop SREREADs.
-	* lex.c(getsc_): added case for SREREAD.
-	* lex.c(arraysub): changed to save whatever is read and return a value
-	  indicating if brackets matched; changed all calls.
-	* lex.c(yylex): if brackets in array reference are not balanced,
-	  or if array reference not followed by an =, re-read the input.
-
-Mon Aug  8 21:20:08 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h: fix lseek prototype (from sjg@zen.void.oz.au)
-
-	* configure.in,jobs.c: added HAVE_SYSCONF; don't use sysconf() unless
-	  HAVE_SYSCONF defined (for NetBSD-Feb12 from sjg@zen.void.oz.au).
-
-	* jobs.c(put_job): removed PJ_ON_END case and define (not used).
-
-Wed Jul 27 10:19:42 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-5.0.1 distribution
-
-	* exec.c(comexec): when doing exec has no command, fall through
-	  and do variable assignments.
-
-	* c_ksh.c(c_let): complain if there are no arguments.
-
-	* exec.c(comexec): if XEXEC is set, exit after executing
-	  (builtin/function) command; deleted FERREXIT code; don't set
-	  exstat.
-	* exec.c(execute): handle FERREXIT; set exstat to rv for all
-	  cases.
-
-	* lex.c,syn.c: changed calls to errorf to yyerror (except the
-	  on in yyerror()).
-	* lex.h(struct source): added errline field.
-	* lex.c(yyerror): now a varargs function; if source->errline field is
-	  non-zero, print it instead of source->line.
-	* syn.c(syntaxerr): set source->errline if read EOF in a multiline
-	  command.
-
-Tue Jul 26 11:22:06 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* lex.h(SYNTAXERR,INP): deleted macros.
-	* lex.h(HISTORY): upped to 128 as per POSIX.
-	* lex.h,syn.c(multiline): moved from lex.h to syn.c.
-	* tree.c(vfptreef): added %R to format I/O redirections.
-	* tree.c(pioact): don't output unit more than once; print unit
-	  only if it isn't the default for the action; print only
-	  one opening quote for quoted here documents; print <> for
-	  read-write (was ><).
-	* syn.c(zzerr, syntaxerr): replaced zzerr function with new syntaxerr
-	  function; changed uses of SYNTAXERR to syntaxerr() calls; print
-	  out the last unused token; if in a multiline command when EOF
-	  encountered, print token that was unmatched.
-
-	* tree.h(TBANG),lex.h(BANG): for POSIX ! keyword
-	* tree.c(ptree),exec.c(execute): added case for TBANG.
-	* syn.c(restab[]): added ! keyword.
-	* syn.c(get_command): added case for BANG (!).
-
-	* tree.h(XERROK): new define to allow non-zero exits to be
-	  ignored in certian circumstances (set -e).
-	* exec.c(execute): pass XERROK to recursive execute() calls; set
-	  XERROK when evaluating conditional part of if/while/until/&&/||.
-	* exec.c(comexec): pass XERROK on to functions; don't exit if
-	  XERROK is set.
-
-	* jobs.c(async_pid): new variable needed since async_job may go
-	  away, but $! should still be expanded.
-	* jobs.c(j_async): return async_pid.
-	* jobs.c(j_set_async): set async_pid.
-
-Mon Jul 25 14:15:25 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* misc.c(parse_args): changed to use ksh_getopt().
-
-	* c_sh(c_set): deleted call to resetopts() - neither POSIX nor
-	  at&t ksh touch OPTIND when positional parameters are changed.
-	* exec.c(comexec): changed resetopts() call to getopts_reset(1) - this
-	  is not a proper fix - should declare a local optind.
-
-	* misc.c(builtin_getopt,ksh_getopt): renamed builtin_getopt to
-	  ksh_getopt (shorter); changed to use state structure instead
-	  of static variables; changed all calls; optionally allow + to
-	  introduce an option; don't skip lone - (or +) in arguments - set
-	  optind to point to it.
-	* misc.c(ksh_getopt_reset): changed to use state structure instead
-	  of static variables.
-	* sh.h(Getopt): new structure for ksh_getopt() state.
-	* exec.c(call_builtin): call ksh_getopt_reset().
-	* c_ksh.c(c_getopts,getopts_reset): new getopts implementation that is
-	  POSIX complient and uses ksh_getopt() routine.
-	* var.c(setspec): call getopts_reset() when OPTIND set.
-	* getopts.c: deleted file.
-	* Makefile.in: deleted getopts.c and getopts.o.
-	* options.h(FASCIST): deleted option.
-
-Thu Jul 21 09:52:03 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-4.9+mun.5 distribution
-
-	* syn.c(get_command),shf.c(shf_fdopen,shf_sopen,shf_emptybuf):
-	  added cast to alloc()/aresize() calls.
-	* sh.h: changed enum flags_enum to enum flags.
-	* misc.c(change_flag): changed type of first argument to enum flag.
-	* edit.c(set_editmode): change type of static array to enum flag.
-
-	* edit.c(x_init): initialize tty chars to -1, except for werase,
-	  which is set to ^W.
-	* edit(x_mode): split oldedchars structure declaration and
-	  initalization (some old compilers don't like them combined).
-
-	* c_test.c: made -h work like -L.
-
-Wed Jul 20 11:12:52 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* config.h.top: moved compile options into options.h; include
-	  options.h.
-	* options.h: new file.
-
-	* c_ksh.c(c_fgbg): if !FPOSIX, set return job exit status.
-
-	* jobs.c(j_jobs,j_notify): use JF_REMOVE to flag jobs to delete
-	  after all notification done (to prevent multiple + or - jobs).
-
-	* jobs.c(put_job): new funtion, takes argument to specify where
-	  to put job; changed all calls to put_job_on_front and
-	  put_job_on_end to use this; put background processes just
-	  after stopped jobs (instead of at end) (POSIX).
-	* jobs.c(put_job_on_front,put_job_on_end): deleted.
-
-Tue Jul 19 10:33:55 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* aclocal.m4(AC_MMAP): copied from autoconf's acspecific.m4 and
-	  modified to use the MAP_FILE flag if available.
-
-	* misc.c(change_flag): ifdef use of FVI/FEMACS/FGMACS.
-
-Mon Jul 18 13:19:29 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(async): deleted.
-	* var.c(global): call j_async() instead of using async global.
-	* jobs.c(j_async,j_set_async()): new functions.
-	* jobs.c(j_startjob): new function.
-	* jobs.c(exchild,j_waitlast): call j_startjob() to start job.
-	* jobs.c(j_sigchld): if any jobs aren't started, note signal
-	  occured and return without calling wait.
-	* jobs.c(j_resume): allow un-reported dead jobs to be fg'd/bg'd;
-	  if backgrounding, set async job.
-	* jobs.c(j_jobs,j_notify,j_waitj,check_job,remove_job): re-wrote to
-	  deal with posix `known processes'.
-	* jobs.c(j_lookup()): if number specified, see if it is a lpid first,
-	  then check for pgrp.
-	* jobs.c(new_job): added functionality of j_newjob().
-	* jobs.c(j_newjob): deleted function and all calls.
-
-	* tty.c(tty_init,tty_close): new functions which initialize
-	  tty_fd, tty_state and tty_devtty.
-	* jobs.c(j_init,j_change): use tty_init()/tty_close(); changed
-	  references of ttyfd to tty_fd; moved tty_fd, tty_state and
-	  tty_devtty to tty.h; call tty_init() if !FMONITOR; save/restore
-	  tty modes on foreground job completion if FTALKING (was FMONITOR).
-	* edit.h(X_chars): new structure for tty driver characters (replaces
-	  ed_erase, ed_kill, ed_werase, ed_intr, ed_quit); moved prototypes
-	  for emacs.c and vi.c from proto.h to edit.h; changed all references
-	  to ed_* to edchars.*.
-	* edit.c(x_mode): use tty_state instead of cborig; re-initialize
-	  tty state from tty_state whenever entering xmode; save tty characters
-	  in edchars structure.
-	* edit.c(x_init): now called from main(); initializes edchars, x_cols,
-	  and calls x_init_emacs.
-	* emacs.c(x_init_emacs): changed erase,kill,werase,intr,quit arguments
-	  to X_chars argument.
-
-Fri Jul 15 10:35:13 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* io.c(restfd): only flush if fd is 2; use dup2() instead of
-	  fcntl(F_DUPFD) (2 system calls instead of 3).
-
-	* ksh_wait.h(WEXITSTATUS): changed mask from 0x7f to 0xff.
-
-	* tty.h: added TTY_state structure.
-	* tty.c: new file - contains get_tty() and set_tty().
-	* edit.c(x_init,x_mode): use get_tty() and set_tty().
-	* jobs.c(j_waitj,j_resume): save/restore tty modes of stopped
-	  jobs, as per POSIX.1, B.2, job control; for foreground jobs,
-	  save tty state after successful completion, restore tty state
-	  after non-successful completion (signaled, non-0 exit, stopped).
-
-	* misc.c(options): changed "alternations" to "braceexpand" (this
-	  is what bash uses - no need to invent new option names); changed
-	  ALTERNATIONS define to BRACEEXPAND, same for FALTERNATIONS to
-	  FBRACEEXPAND.
-
-	* jobs.c(check_job): if process died of SIGINT or SIGPIPE, leave
-	  job state as PEXITED (not PSIGNALLED).
-	* jobs.c(j_print): if printing short notice, ignore SIGPIPE the
-	  way SIGINT is ignored.
-
-	* exec.c(comexec): flush shl_out after 'not found' message.
-
-	* c_ksh(c_kill): re-wrote function (again) to handle posix
-	  options (-s, --, etc.) and posix -l output.
-
-	* configure.in: added strcasecmp function check.
-	* missing.c(strcasecmp): define strcasecmp function if not available.
-	* trap.c(gettrap): use strcasecmp when comparing signal names.
-
-	* var.c(global): expand $! to nothing if there haven't been any
-	  asynchronous processes started yet.
-
-	* misc.c(options): added posix option (set automatically if
-	  POSIXLY_CORRECT env variable is set or if POSIXLY_CORRECT config
-	  define is defined)
-	* var.c(special,setspec): added POSIXLY_CORRECT.
-	* config.h.top: added POSIXLY_CORRECT define.
-	* main.c(main): set FPOSIX if POSIXLY_CORRECT is defined.
-	* POSIX: new file describing what the posix flag controls.
-
-Thu Jul 14 10:53:15 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* jobs.c,sh.h(killpg): moved killpg define to sh.h.
-
-	* jobs.c(exchild): set async variable when starting background
-	  processes.
-	* jobs.c(j_resume): print [job-num] before command when backgrounding;
-	  print to stdout instead of stderr.
-	* c_ksh.c(c_fgbg): call builtin_getopt to skip possible --, complain
-	  about unknown options.
-
-	* jobs.c(held_sigchld): new global variable.
-	* jobs.c(j_sigchld): if any jobs aren't started, set held_sigchld and
-	  return.
-	* jobs.c(exchild,waitlast): after setting JF_START, if held_sigchld
-	  set, call j_sigchld().
-
-	* jobs.c(exchild): added/initialized ppid field to struct job; deleted
-	  global is_child.
-	* jobs.c(waitfor): don't wait for a process that isn't a child of
-	  the current process.
-	* jobs.c(j_exit): kill stopped jobs owned by current process only.
-
-	* jobs.c(check_job): don't do monitor stuff for XXCOM jobs, but do
-	  set up notification.
-	* jobs.c(j_waitj): added JW_NOTIFY flag to print job notification
-	  messages.
-
-	* jobs.c(exchild): remove !XPIPEI condition - we now close pipe so
-	  pipeline doesn't have to call waitlast().
-	* exec.c(execute): case TPIPE: no need to restore 0 or call waitlast()
-	  since exchild() handles everything.
-
-	* jobs.c(remove_job): set last_job to 0 if we are removing it.
-	* jobs.c(waitlast): check if last_job is 0.
-
-	* jobs.c(struct job): combined started, waiting, interactive
-	  field into flags field; added JF_* flags; changed JW_NONOTIFY
-	  to JW_NOTIFY and changed all calls to j_waitj() to reverse
-	  this flag.
-
-	* jobs.c(exchild): ignore SIGTSTP, TTIN, TTOU for `command` jobs.
-
-Wed Jul 13 09:28:34 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* main.c(main): when checking if FMONITOR set on command line,
-	  use 127 instead of -1 (signed vs unsigned char problem).
-
-	* tree.h: renumbered, XEXEC, XFORK, ... and DOBLANK, DOGLOB, ...
-	  to use bits in order (instead of 0 5 2 4...).
-	* jobs.c(j_init): don't set sigtrap[SIGCHLD].sig_dfl = 1 as a
-	  forked child may be a shell that needs to trap SIGCHLD.
-
-	* tree.h(XPCLOSE,XCCLOSE): flags for close in parent, close in child.
-	* jobs.c(exchild): added third argument - a file descriptor - if
-	  flags has XPCLOSE, close fd in parent, if flags has XCCLOSE, close
-	  in child.
-	* exec.c(execute): pass input side of pipe to exchild() so it can
-	  be closed in the child.
-
-Tue Jul 12 10:21:57 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* main.c(main): let ignoresig() handle SIGTERM.
-	* jobs.c(exchild): let restoresigs handle SIGTERM.
-
-	* lex.c(yylex): don't parse array references inside double quotes
-	  (partial fix).
-
-	* emacs.c(x_print): use shprintf instead of shellf so the output
-	  of bind can be redirected.
-
-	* trap.c(deftraps): added SIGINFO (from jconklin@netcom.com).
-
-Fri Jul  8 09:37:51 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-4.9+mun.4 distribution
-
-	* Makefine.in: added $(LDSTATIC) to LDFALGS to make static
-	  linking easier (suggested by sjg); use cp -p when creating
-	  distributions to preserve file dates.
-	* configure.in: set LDSTATIC in Makefile if present in environ
-	  when configure is run.
-
-	* sigact.c(sigsuspend): when calling 4.2bsd sigpause, pass *mask,
-	  not mask.
-
-	* main.c(main): fixed up initialization of PWD (free memory, print
-	  more informative message).
-
-	* misc.c(getcwd): range check backwards.
-
-	* c_sh.c(setsig): set sa_flags/sa_mask.
-
-	* edit.c(init_editmode),main.c,proto.h: deleted function - not needed
-	  since VISUAL/EDITOR are special.
-
-	* lex.c(set_prompt),table.h: take out PS3.
-
-	* c_sh.c(c_umask): handle multiple actions in symbolic mode clauses
-	  (eg, u+r-w); handle X (eg, o+X); ignore s (eg, u+s).
-
-	* shf.c(shf_fillbuf): continue reading if we get an EINTR.
-	* shf.c(shf_emptybuf,shf_write,shf_putchar): continue writing if we
-	  get an EINTR.
-
-Thu Jul  7 10:19:24 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sigaction,sigprocmask: changed NULL third argument to
-	  (struct sigaction *) 0.
-	* sh.h(kshpid): changed type from int to pid_t.
-	* proto.h(do_ulimit): removed do_ulimit() declaration.
-	* vi.c(complete_word): removed unused variable pos.
-	* syn.c(pipeline,elsepart): removed unused variable c.
-	* jobs.c(exchild): deleted variable s (assigned but not used).
-	* history(hist_init),shf.c(shf_gets): changed variable e to end
-	  because there is a global e.
-	* exec.c(do_selectargs): removed secondarg argument; changed return
-	  (char *) 1 to (char *) 0; changed all calls.
-
-	* io.c(canseek): use fd argument instead of 0.
-
-	* lex.c(readhere): don't use fixed sized buffer (line).
-
-	* expand.h: changed multi-statement macros to use do {..} while (0);
-	  changed temporary variable vp to vp__ to avoid lint complaints.
-
-	* aclocal.m4(KSH_DUP2_CHECK): define F_GETFD/F_SETFD if not
-	  already defined.
-
-	* etc/profile, etc/ksh.kshrc: replaced with new versions from
-	  Simon J. Gerraty (sjg@zen.void.oz.au).
-
-Wed Jul  6 10:09:55 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* jobs.c(killpg),configure.in: restored use of killpg() - some
-	  systems don't understand kill(-pgrp, signal) (ultrix 2.2);
-	  added test for killpg() in configure.in.
-
-	* trap.c(inittraps): changed initialization of sigtraps - was
-	  using -1 in deftraps[] as end of table marker but some systems
-	  (eg, ultrix 2.2) define signals with -1 values (SIGPWR).
-
-	* Makefile.in(mandir,install): fixed mandir value; added /
-	  in man installation; prefixed ksh.1 with $(srcdir).
-
-	* jobs.c(j_init): Ignore failure of TIOCSETD.
-
-	* misc.c(options[]): changed "vicomplete" to "vitabcomplete".
-
-	* emacs.c(x_e_putc,x_e_puts,x_debug_info): x_e_putc()/x_e_puts() are
-	  the x_putc()/x_puts() functions from ksh4.9 edit.c (they got lost
-	  in the merge); same for x_debug_info(); changed x_e_putc/x_e_puts
-	  to call x_putc/x_puts.
-
-Mon Jul  4 09:29:05 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-4.9+mun.3 distribution
-
-	* main.c(remove_temps): use unlink() instead of remove(); delete
-	  remove() define.
-
-	* sh.h(func_heredocs, struct env): added func_heredocs for here
-	  documents in functions; added func_parse field to struct env
-	  - set when a function is being parsed.
-	* lex.c(readhere): if e.func_parse, save temp file in func_heredocs.
-	* syn.c(get_command): increment/decrement func_parse when parsing
-	  functions.
-	* main.c(remove_temps,reclaim,leave): added remove_temps(); make
-	  reclaim() call remove_temps(); make leave() clean up function
-	  here documents.
-
-	* aclocal.m4(KSH_TIMES_CHECK): new test - define TIMES_BROKEN
-	  if times() doesn't exist or if it always returns 0.
-	* acconfig.h(TIMES_BROKEN): new define.
-	* missing.c(ksh_times): new function.
-	* ksh_times.h: new file.
-	* c_sh.c,jobs.c: changed <sys/times.h> to "ksh_times.h"
-	* c_sh.c,ksh_time.h(CLK_TCK): moved CLK_TCK define from c_sh.c
-	  to ksh_time.h (needed in missing.c).
-
-	* syn.c(get_command): case TIME: don't call pipeline() with CONTIN
-	  flag.
-
-	* c_sh.c(c_times): combined some printfs().
-
-	* jobs.c(j_jobs,j_kill,j_resume,waitfor): block SIGCHLD before
-	  calling j_lookup() or looking at jobs list - avoids potential
-	  problems with remove_job() being called in signal handler.
-
-Sun Jul  3 11:09:01 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* exec.c(do_selectargs, selread, pr_menu): re-wrote do_selectargs to
-	  let c_read() to most of the work; deleted selread; make pr_menu
-	  calculate width/ncolumns each call so select can be used recursively.
-
-	* configure.in, aclocal.m4(KSH_TERMIOS_H, KSH_TERM_CHECK): replaced
-	  KSH_TERMIOS_H with KSH_TERM_CHECK; removed calls to
-	  tcgetpgrp/tcsetpgrp - there is a 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@zen.void.oz.au)
-
-	* var.c (setstr): don't set ALLOC flag if vp.s is NULL.
-
-Thu Jun 30 10:16:44 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_sh.c(c_read): ignore null characters; use builtin_getopt()
-	  instead of explicit parsing; removed -e option (neither at&t ksh
-	  nor POSIX have this); added -s option (put line in history, at&t ksh);
-	  if no variable specified, use REPLY (at&t ksh).
-
-	* exec.c(do_selectargs): use Xstring macros to deal with saving
-	  input (was static, growing, buffers); flush shl_out after
-	  shellf().
-
-	* vi.c(expand_word,complete_word): deleted call to free_edstate
-	  since already done by restore_edstate().
-	* var.c(global): in 'if !letter(c)' block, deleted !c from
-	  'if (!c || !n[1])' - don't know why it was added since it makes
-	  no difference to what is returned.
-
-	* syn.c(dogroup): removed onlydone argument since it is only
-	  used in the while/until statements, where "while command; done"
-	  is not allowed anyway; Changed all calls.
-
-	* misc.c(options[]): allow -i to be specified on the command
-	  line.
-
-	* exec.c(iosetup): if stderr (fd 2) is being re-directed,
-	  re-open shl_out to clear any errors.
-	* main.c(quitenv): if restoring fd 2, clear any write errors
-	* io.c(initio): initialize shl_out, shl_spare for writing
-	  (was SHF_GETFL).
-
-	* main.c(main): ignore SIGQUIT if talking.
-
-Wed Jun 29 11:11:34 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_sh.c(c_exit): removed jobs/really quit stuff - exit should
-	  always exit.
-	* main.c(shell): made reallyquit a local variable.
-	* sh.h(reallyquit): deleted reallyquit
-
-	* exec.c(comexec), main.c(main), misc.c(change_flag), jobs.c:
-	  ifdef'd use of FMONITOR.
-	* sh.h, misc.c: define FMONITOR option only if JOBS defined.
-
-	* c_sh.c(c_wait): POSIXized: option parsing (of no options);
-	  return 0 if not given any arguments; deal with multiple arguments.
-	* jobs.c(j_lookup): changed second argument to return an integer
-	  error code, added defines for error codes, added error message
-	  array; changed all calls to use new conventions.
-	* jobs.c(waitfor): returns -1 if job not found; added argument
-	  to specify if notification messages should be suppressed.
-	* jobs.c(j_waitj): added flags argument instead of intr argument;
-	  added JW_STOPPEDWAIT flag to wait for stopped jobs to complete;
-	  added JW_NONOTIFY flag to suppress notification of normal
-	  job termination.
-
-Tue Jun 28 16:13:10 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ksh.c(c_jobs): added -n and -p options, allow job ids to be
-	  specified for -l option.
-	* jobs.c(j_jobs): added new arguments to deal with -n and -p options.
-
-	* shf.h(SHF_BSIZE): reduced size to 512 to reduce memory requirements
-	  (I/O is used mostly for one line messages).
-
-	* config.h.bot: removed necessity for tty process groups to define
-	  JOBS, added necessity of signal blocking/pausing.
-
-Mon Jun 27 21:49:52 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* jobs.c(exchild,j_print,j_waitj,j_jobs,check_job): exchild() - removed
-	  commented out shf_flush() calls; j_print() - print a space between
-	  status reports when lflag < 0, changed flag argument to use
-	  long/medium/short defines; Changed Job.notify field to use
-	  long/medium/short defines; j_waitj() - instead of calling j_print(),
-	  set j->notify to print the job; j_jobs() - clear j->notify so user
-	  won't be notified twice if a job finishes before a jobs command;
-	  check_job() - put job on front of list only if it is stopped.
-
-	* main.c(main): pass flag to j_init() indicating if -m flag set/cleared
-	  on command line; don't initialize ttyfd.
-	* sh.h: delete ttyfd.
-	* jobs.c(j_init,ttyfd,check_job): made ttyfd static; re-worked j_init()
-	  to initialize ttyfd, initialize FMONITOR if not set by command line,
-	  initialize shl_j for asynchronous job notification;
-	  check_job() - use shl_j, look through saved fds to find real
-	  standard-error.
-
-	* jobs.c(TTY_PGRP, ttypgrps_ok): modified conditions so job control
-	  is useful without tty process groups; added ttypgrps_ok flag that
-	  indicates if tty process groups should be set up; modifications so
-	  job control useful if ttypgrps_ok not set.
-
-	* main.c(main): set FTALKING if 0 and 2 are tty as specified in POSIX
-	  (was 0 and 1).
-
-	* misc.c(parse_args): do POSIX option processing for -A, -c and -o
-	  (allow -onoglob, -ctrue).
-	* main.c(main): don't set up shl_stdout before/after parse_args() since
-	  lone -o on command line no longer accepted; remove code to allow
-	  -c with no options to read from stdin (at&t khs does this but POSIX
-	  requires an option to -c).
-
-Thu Jun 23 17:46:54 NDT 1994 John Rochester (jr@panda.cs.mun.ca)
-
-	* trap.c(cleartraps): added special case for clearing trap 0 from
-	  ksh-4.9 sources.
-
-Thu Jun 23 10:17:03 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* misc.c(builtin_getopt): print error messages for unknown option,
-	  missing option; reset state if argv is 0.
-	* c_ulimit.c(c_ulimit): let builtin_getopt() print error messages.
-	* exec.c(call_builtin): call builtin_getopt() with 0 argv.
-
-	* c_sh.c(c_unset): added -v option (POSIX); use builtin_getopt() to
-	  parse arguments; removed bogus comment about global() and special
-	  variables; don't allow read-only variables to be unset (POSIX).
-
-	* var.c(unset, unsetspec): when unsetting a special variable, call
-	  unsetspec(); unsetspec() new function.
-	* mail.c(mbset, mcheck): check that path is not 0 before calling stat
-	  (so mbset() can be called with 0 when MAIL is unset); deleted #if 0'd
-	  declarations of munset, mballoc and maddmsg.
-
-	* misc.c(parse_args): pass argv+i+1 to set_array (not argv+i); when
-	  skipping arguments, leave i just before the NULL.
-
-	* exec.c(echo): flush shl_out when done.
-
-	* shf.c(shf_close): always used to return EOF.
-
-	* trap.c(trapsig): skip error handlers when checking for PARSE or LOOP.
-
-Wed Jun 22 10:24:09 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* sh.h(C_IFSWS), misc.c(initctypes): added and initialized C_IFSWS
-	  (IFS white space).
-	* c_sh.c(c_read): print continuation prompt if line ends in backslash;
-	  multiple non-white-space IFS chars delimit fields; strip trailing
-	  IFS-white-space from last variable; watch out for backslash followed
-	  by EOF.
-	* eval.c(expand): only do field splitting on the results of
-	  parameter/command substition (POSIX, !v7-sh);  multiple
-	  non-white-space IFS chars delimit fields.
-
-	* eval.c(expand,alt_expand): removed NOALT tests since it could
-	  never be set; added return after call to alt_expand() in expand().
-
-Mon Jun  6 10:12:41 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* misc.c(setctypes, initctypes): setctypes - don't allow leading null
-	  in IFS (IFS="" could cause problems, 0 is already added);
-	  initctypes - don't use a leading null.
-
-	* sh.h, eval.c: move definition of ifs0 from eval.c to sh.h; handle
-	  null ifs0.
-	* var.c(setspec): set ifs0 to first character of IFS.
-
-	* lex.c(yylex): when parsing ${..}, array references were not being
-	  null terminated.
-
-Fri Jun  3 12:28:06 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* var.c(export): changed to use memcpy() instead of loops.
-
-	* eval.c(varsub, expand): check for #foo[@] in addition to #foo[*];
-	  handle ${foo[*]} and ${foo[@]} - added free_me field to struct Expand
-	  so pointer vector can get freed.
-
-	* c_sh.c(c_dot), main.c(include): set up positional parameters if
-	  any are specified; Added argc,argv args to include(); changed all
-	  calls to include(); change include() to return 0 or 1 - caller
-	  can check exstat if desired; c_dot() should return 1 if can't open
-	  file (was -1).
-
-	* c_sh.c(c_brkcont): warning message could call getn() with NULL - save
-	  original number and print it.
-
-	* main.c(main): set $0 to first argument when -c used, ie,
-	  "sh -c cmd-string this-is-$0 argumernts..."
-
-	* exec.c(iosetup): print "cannot open" if IOHERE fails.
-
-	* io.c(errorf): set exstat to 1.
-
-	* exec.c(search): assume mode is R_OK or X_OK (not 0/1 - 0 is F_OK, we
-	  want R_OK); changed all calls to pass R_OK/X_OK.
-	  sh.h: define R_OK,W_OK,X_OK,F_OK if not defined.
-	  eaccess(): changed all calls to use [RWXF]_OK.
-
-	* sh.h(flag[], shell_flags[], Flag()): Renamed flag[] array to
-	  shell_flags[] to avoid conflicts with other uses of flag; Changed
-	  all references to flag[] to Flag(); defined Flag() to cast its arg
-	  to an int (for old pcc based C compilers).
-
-	* vi.c(iswordch): use letnum() instead of isalnum || _.
-
-	* misc.c(parse_args): call set_array() to deal with -A flag.
-	* var.c(set_array): new function.
-
-
-Fri Jun  3 10:22:26 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* eval.c(substitute): afree(s).
-
-	* var.c(global,local), sh.h: ARRAYMAX: new define - max index of an
-	  array; changed 511 constants to this; changed global() and local()
-	  to use array_ref_len() instead of arraysub().
-
-	* expr.c(token): deleted unneeded arraysub() decl.
-
-	* lex.c(arraysub), proto.h: made static, removed unused arguments,
-	  changed callers; removed prototype from proto.h.
-
-	* ChangeLog: changed descriptions from func(file) to file(func).
-
-Wed Jun  1 09:17:50 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* made pdksh-4.9+mun.2 distribution
-
-	* Makefile.in: added RCSFILES macro and rcs-ci target.
-
-	* configure.in: add termio.h to the AC_HAVE_HEADERS() call.
-
-	* sh.h, main.c, edit.c, misc.c: use EXTERN for aperm, x_cols,
-	  builtin_optind and builtin_optarg in sh.h, delete definitions
-	  in main.c, edit.c and misc.c.
-
-	* io.c(maketemp): changed sizeof(PATH) to sizeof(path).
-
-	* aclocal.m4(KSH_VOID,KSH_DUP2_CHECK): test that a void * variable
-	  can be used (Ultrix 2.2 compiler doesn't do this); added ifdef
-	  HAVE_FCNTL_H to dup2 test.
-
-	* aclocal.m4, configure.in, sh.h, tree.c, io.c, shf.c: added
-	  new config test KSH_PROTOTYPES to check for function prototypes
-	  (MIPS RICS/os 5.0 C compiler isn't STDC and it can't mix <stddef.h>
-	  with <varargs.h>).  Removed stdarg.h test (now 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@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@panda.cs.mun.ca)
-
-	* made pdksh-4.9+mun.1 distribution
-
-	* finished autoconf'ing source code.
-
-Fri May 20 16:47:06 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* c_ulimit.c(c_ulimit) (was do_ulimit.c(do_ulimit)): major rework;
-	  deal with combinations of getrusage and ulimit, use options at&t
-	  ksh uses (-SHa..).
-	* misc.c(builtin_getopt): yet another getopt routine for builtin
-	  commands
-	* misc.c(parse_args), c_sh.c(c_set), main.c(main): custom option
-	  parsing routine for command line/set options.  Lots of changes
-	  to main() to incorporate this (easier to follow).
-	* c_test.c(c_test): added -e (file exists) test.
-
-Fri May 5 12:16:46 NDT 1994 Michael Rendell (michael@panda.cs.mun.ca)
-
-	* numerous changes from old Notes.4-9 file:
-	  - c_ksh.c:
-	      - calls to errorf identify what function the error is in
-		(eg, errorf("print: bad -u option");)
-	  - added array stuff (lots of places)
-	      - table.c
-	      - lex.c
-	      - var.c: +arraysearch(), +basename()
-	  - c_sh.c(c_exit), main.c(shell), sh.h:
-	      - added reallyquit flag to deal with stopped jobs at exit time;
-		only two exit commands (or eofs) in a row will work.  in
-		shell(), set exstat from execute value.
-	  - c_ksh.c(c_print):
-	      - handle \\ at end of string better (don't skip the null)
-	  - c_ksh.c(c_whence):
-	      - stop looking as soon as we get a failure
-	      - pass flag[FTRACKALL] to findcom() instead of 0
-	  - c_ksh.c(c_alias):
-	      - print '%s alias not found' if not found
-	  - c_ksh.c(c_jobs):
-	      - handle -l option (list pid)
-	  - c_ksh.c(c_kill):
-	      - two column -l output to try to keep it on one screen
-	  - c_sh.c(c_read):
-	      - skip IFS at start of line "echo ' a b' |(read a b; echo $a)"
-		should print a, not nothing.
-	      - changed EOF check to set all vars to null (same way \n is
-		handled)
-	  - eval.c(comsub):
-	      - after compile(), return if t is NULL
-	      - use setfileno() instead of fileno(x) = .. (see sh.h changes);
-	  - exec.c(iosetup):
-	      - set exstat if redirect fails
-	  - exec.c(fd_clexec):
-	      - check that fd >= 0
-	  - exec.c:
-	      - change SHARPBANG ifdef code - everyone uses scriptexec().
-		ifdef is put around open/read/parse code in scriptexec().
-		[code cleanup]
-	  - exec.c(search):
-	      - eaccess test out side of loop: must be regular file to exec it
-		(like test in loop)
-	  - eval.c(expand):
-	      - added while getc() == 0 in XCOM
-		[a null in the output of a file would be treated as eof and
-		 waitlast would not be called]
-	  - eval.c(trimsub):
-	      - '%' subst: use ATEMP, not APERM
-	  - eval.c(tilde): use Xinit et. al., instead of fixed length buffer
-	  - getopts.c(getopt): rename getopt() to ksh_getopt() to avoid
-	    problems with prototypes in system #include files.
-	  - io.c(fopenshf):
-	      - call clearerr(fd) if already open
-	      - use F_GETFL to determine appropriate mode for fdopen() call
-		instead of opening everything for read/write
-	      - use ifdef _FSTDIO instead of ifdef _BSDI (_FSTDIO is used in
-		4.4bsd, NetBSD, FreeBSD and other non BSDI environs)
-	  - lex.c(ungetsc): don't decrement if str == null, remove nullstr hack
-	  - lex.c(yylex):
-	      - \ at eol: call Xfree before goto Again
-	      - use memset() to clear ident, instead of while loop
-	  - syn.c(get_command): renamed from command() to get_command() to
-	    avoid conflicts with command(main.c).
-	  - sym.c(get_command):
-	      - allow A=B <alias-name> to work (alias was not being expanded)
-	      - allow `if .. if .. fi fi' to work (no ; after group terminator
-		(fi , esac, done, ), })
-	      - allow `alias FI=fi ; if .. if .. fi FI' to work (alias
-		expansion after group terminator)
-	      - do not assume resize returns same pointer
-	  - tree.c(pioact):
-	      - handle IORDWR case
-	      - added leading quote for file in IOHERE case
-	  - var.c(special):
-	      - add MAILCHECK check
-	  - var.c(setspec):
-	      - add MAILCHECK case (doesn't do anything yet)
-	  - var.c(strint):
-	      - handle null vp->val.s
-	  - eval.c(sh.h, expand), misc.c(options[]):
-	      - enable alternations only if alternations flag set
-		(set -o alternations).  This is so (att ksh) scripts that don't
-		expect alternations won't break.
-	      - added notify option (asynchronous job completion notification)
-	      - added vicomplete to enable tab char as file name completion
-		char in vi (this is likely to go away - exits for historical
-		reasons)
-	  - jobs.c, main.c, sh.c, trap.c:
-	      - define/use SIG_HDLR instead of void
-	  - eval.c(expand): alt_expand() does not return a value so don't test
-	    it, just return.  Also changed decl of alt_expand() to reflect
-	    reality.
-	  - emacs.c(x_emacs): first return returns random value (i); change to
-	    return 0.  Also changed the way interrupts are returned to called
-	    (return -2 means interrupt).
-	  - c_sh.c(c_brkcont): at&t ksh allows breaks/continues outside of
-	    loops, 4.9 prints an error and breaks out of all env's (if, case,
-	    etc.). Fixed to act like at&t (ie, allow bogus continues), except
-	    a warning message is printed.  (Some HP-UX shell scripts actually
-	    have continues outside of loops...)
-	  - main.c(shell): parameter s should be volatile as it is used after a
-	    setjmp.
-	  - edit.c(promptlen): handle tabs, backspaces...
-	  - cleaner fix to the ^C/source->line problem: in pprompt(lex.c),
-	    convert ! to source->line+1 (same in promptlen(edit.c)), increment
-	    source->line after a (non-empty, non-eof) line has been read
-	    (before call to histsave()).  To be pedantic, also adjust
-	    position of source->line++ in SHIST in case PS9 is ever used.
-	    Remove code in shell(main.c) that does the source->line--,
-	    remove the source->line-- for eof and empty line in from
-	    getsc_(lex.c).
-	  - trap.c(sigtrap[]): do not depend on signal number matching position
-	    in initialization array.  Use second table in which order does not
-	    matter to initialize sigtrap[] array.  Easier to read/port, and
-	    generally less fragile.  requires call to inittraps() in main.c.
-	  - trap.c(cleartraps): need to clear Sigact flags/mask after use
-	    (actually, declare a local struct sigact and use that instead of
-	    Sigact)
-	  - exec.c(execute): case TSELECT: no USE_SIGACT code for call to
-	    signal(); case TPIPE: don't call waitlast() if XXCOM since
-	    waitlast() will be called in expand(); 4.9 code that set and
-	    then cleared the XEXEC flag in the TPIPE case not added since
-	    it was ifdef'd out, also the code to not exit if XPIPEI flag
-	    set was not added; 4.9 XXWHL flag not added (don't flush stdin
-	    if in a while loop) since this problem fixed (I hope) by shf stuff.
-	  - ttyfd{sh.h/lex.c}: use EXTERN/_I_ to initialize ttyfd. Remove from
-	    lex.c
-	  - interrupted reads: instead of testing sigchld_caught after reads
-	    fail, continue them if errno == EINTR.
-	      - edit.c(x_getc): check for EINTR, and continue reading if so.
-	      - lex.c(getsc_): check for EINTR, and continue reading if so.
-		(don't check return of x_read() - check has already been done)
-	      - exec.c(selread): check for EINTR, and continue reading if so.
-	  - history changes:
-	      - history.c:
-		  - histrpl(): bounds check doesn't take global flag into
-		    account - move check into loop and past loop.
-		  - c_fc(): if pattern is the empty string, histrpl()
-		    goes into infinate loop.  Start searching for = after first
-		    char (this is what at&t ksh seems to do).
-		  - c_fc(): `fc -l first' should list at most 16
-		    commands according to at&t manual.
-		  - findhist(): re-wrote: shorter, easier to follow.  Now
-		    returns an int.  (used only by vi code)
-		  - use COMPLEX_HISTORY's allocated history array in
-		    EASY_HISTORY: common init_histvec(), sethistfile() and
-		    sethistsize() functions.
-		    In the process, hist_open() went away.  Use histsize
-		    instead of HISTORY in hist_init() and hist_finish()
-		    #ifdefs in lex.h, table.h,
-		    var.c disappear, history variable definitions in lex.c
-		    disappear.
-		  - hist_init(COMPLEX_HISTORY): move hstarted = 1 to after the
-		    FTALKING test.
-		  - hist_finish(): don't open hname if its null
-		  - histrpl(): made static, use ARGS in decl
-		  - made current and curpos static
-		  - changes to allow embedded newlines in commands:
-		      - histsave(): trash only trailing newline
-		      - hist_init(): read in null terminated lines instead of
-			newline terminated
-		      - hist_finish(): write null terminated lines
-		  - make multiple line command appear in single history line
-		    (EASY_HISTORY only):
-		      - added histappend() to append new command to last
-			command
-		      - added call to histappend() in getsc_(lex.c) (also: only
-			adjust source->line if not multiline).
-	      - lex.h:
-		  - remove second decl of history if !EASY_HISTORY
-	  - tree.c(ptree): case TCOM: check if t->vars or t->args is 0
-	  - vi.c(x_vi): ^D anywhere in command line is eof ($ foobar^D exits).
-	    at&t ksh ignores ^D in middle of line
-	  - edit.c:
-	      - don't need to include string.h - included in stdh.h
-	      - init_editmode(): in at&t ksh, VISUAL takes precenence over
-		EDITOR, so put it first.  Also, at&t ksh doesn't use FCEDIT so
-		trash it.
-	      - moved initialization of ed_* from x_read() to x_init() since
-		thats where they are set from tty structs.
-	      - x_init(): set ed_intrc, ed_quitc for _BSD & _POSIX_TERM ifdefs
-	      - send output to shlout (instead of stdout - at&t ksh writes to
-		stderr)
-	      - made x_do_init static.
-	  - exit.c(x_getc), lex.c(yylex): restart interrupted reads in
-	    x_getc(), changed read-restart in yylex() to only effect call
-	    to read().
-	  - syn.c(thenpart): then THEN is not optional - generate a syntax
-	    error if no THEN. (ie, `if true ; fi' is not legal).
-	  - syn.c(get_command): don't accept keywords after re-directory (eg,
-	    `> /dev/null if true ; then echo hi ; fi' is not legal).
-	  - vi.c: handle \ and ^[ in command mode ala at&t ksh (filename
-	    completion)
-	  - syn.c(thenpart), syn.c(elsepart): calling token(0) when they want a
-	    keyword (always worked 'cause tpeek() is always called before, with
-	    the keyword flag).  Fix: call token(KEYWORD|ALIAS) (at&t ksh does
-	    alias expansion here). Question: pass CONTIN as well?
-	  - syn.c(get_command): LWORD/MPAREN case: do alias expansion when
-	    getting open brace ({).  CASE case: ditto for `in' and `esac'.
-	    IF case: ditto for `fi'.  FUNCTION case: dito for open brace ({).
-	  - syn.c(dogroup): alias expansion when getting `do' and `done'.
-	  - syn.c(wordlist): alias expansion when getting `in'.
-	  - syn.c(nested): alias expansion when getting `)', `}'
-	  - syn.c(casepart): alias expansion when getting `esac' or `;;'.
-	    Also removed use of cf variable - it does nothing.
-	  - eval.c(expand): case CSUBST: '#'/'%' - increment st so nested
-	    substitutions work.
-	  - var.c(typeset): INTEGER && no assignment: memory was being freed
-	     and then used (there was even a comment saying it was being
-	     done...)
-	  - lex.c, lex.h, exec.c, main.c:
-	      added shf_{open,fdopen,close,gets}() routines so stdio wasn't
-	      used.  When reading a command file under osf/1, stdio would
-	      mess up the read pointer when a child exited: the exit flushed
-	      all open files and flushing a file open for reading changes the
-	      current read position (does a seek to where the next char would
-	      be read).  This position is then used by the parent process,
-	      who thinks the read position is still at the end of the buffer
-	      it read.
-	  - c_sh.c:
-	      use shf_*() routines avoids two bugs in read:
-		  - on sunos 4.1.3, a read would gobble up a stdio buffer and
-		    never put it back (ie, lseek backwards).  Neither a
-		    fflush() nor a fseek(x, 0L, 1) fixed the problem.
-		    (see Bug 26)
-		  - on linux, stdio knows its current offset and seeks there
-		    before reading a buffer.  This causes grief when the shell
-		    replaces file descriptors behind stdio's back (ie, all the
-		    time).
-		      $ read x << EOF
-		      hi
-		      EOF
-		      $ cat > /dev/tty << EOF
-		      1:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
-		      2:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
-		      3:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
-		      EOF
-		      $
-		    the cat picks up reading at the offset where the read
-		    command left off (ie, at bcdefg... - the 1:a are skipped).
-	  - exec.c(comexec): built-in c_exec && no args: close the saved fd's
-	    (were thrown away).  Also, set close-on-exec flag for fd's > 2,
-	    as per at&t manual.
-	  - lex.c(yylex): only accept 1 digit before a redirection (eg, 1> is
-	    ok, 1abc> is not)
-	  - exec.c(iosetup): only accept 1 digit after a dup-redirection
-	    (eg, >&1 is ok, >&1abc is not)
-	  - exec.c(iosetup): use O_APPEND flag for >> redirections; use O_CREAT
-	    flag for <> redirections.  (re-organized to accumulate open() flags
-	    and do one open() call); changed error message to know about dup
-	    failing.
-	  - c_sh.c(c_umask): umask should have leading 0 - doesn't when umask
-	    has 3 digits (eg, `umask 222; umask' prints 222 instead of 0222)
-	  - c_sh.c(setsig): declare local struct sigaction and use it so
-	    sa_flags doesn't have to be cleared (also to try to keep away from
-	    global vars).
-	  - main.c(main):
-	      - don't go set TALKING if name starts with -.
-	      - read $HOME/.profile (not .profile)
-	  - main.c(main): re-wrote option parsing code
-	  - edit.c(init_editmode): don't check FCEDIT
-	  - if set -o vi/emacs/gmacs on command line, don't set edit mode from
-	    FCEDIT/EDITOR/etc.
-	  - var.c(setspec): FCEDIT should not magicly change edit mode; VISUAL
-	    and EDITOR should (EDITOR only if VISUAL is not set)
-	  - changed noclobber char from ! to | (this is what at&t ksh uses)
-	  - exec.c(iosetup): use O_EXCL flag if FNOCLOBBER set and >| not used
-	  - c_sh.c(c_set): don't clear FERREXIT if FTALKING is set; although
-	    some ksh manuals say -e is ignored for interactive shells, they
-	    all seem to honour the -e flag for interactive shells.
-	  - vi.c: reset history position to the end after a line is modified
-	  - `(( 1 + 2 ))' no longer prints `+: bad expression'!
-	  - lex.c(yylex): added parenthesis counting so `(( ((1+2)) ))' no
-	    longer generates a syntax error
-	  - expr.c(intvar): if strint() fails, give bad number error
-	    (`let 1+foo' should fail)
-	  - `echo hi 1abc123> /dev/tty' no longer interpreted as
-	    `echo hi 1> /dev/tty' (is `echo hi 1abc123 > /dev/tty')
-	  - `echo hi 1<> /tmp/does-not-exist' now works (used to say cannot
-	    open)
-	  - c_sh.c(c_umask): umask now takes symbolic arguments (g-r, +w, etc.)
-	  - c_ksh.c(c_whence): pass flag[FTRACKALL] to findcom() instead of 1.
-	  - `echo hi >< bar' now produces an error
-	  - jobs.c(j_lookup): now checks for ambiguous job specifications;
-	    callers now get an error message.
-	  - c_ksh.c(c_fgbg): multiple jobs can be specified
-	  - emacs.c(x_transpose): move past transposed chars like (gnu) emacs
-	    does
-	  - main.c(main): don't copy initcoms (messes up memory allocated for
-	    shf_iob[] in initio(), should not be necessary)
-	  - main.c(main), var.c(import), var.c(typeset), c_ksh.c(c_alias),
-	    expr.c(token), misc.c(strnsave): added strnsave() function; use it
-	    instead of writing nulls in the middle of strings; main() no longer
-	    copies startup commands before executing them.
-	  - vi.c: wbuf[] no longer a fixed size (was hard coded to 80 chars).
-	  - alloc.c(aresize): if passed a null pointer, don't free it
-	  - expand.h: restored usage description and NOTE from previous version
-	  - alloc.c, table.h, table.c:
-	      - changed struct fields named `free' to nfree (struct table) and
-		freelist (struct Block) to allow memory debugging
-		(involves #defining free)
-	  - main.c(main): smart initialization of PWD (ensures it is always
-	    valid).
-	  - lex.h, table.h, tree.h: removed 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()
diff --git a/GNUmakefile b/GNUmakefile
@@ -10,12 +10,11 @@ DOCDIR ?= ${PREFIX}/share/doc/oksh
 INSTALL = /usr/bin/install
 
 CFLAGS ?= -O2 -pipe
-CFLAGS += -Wall
+CFLAGS += -Wall -DEMACS -DVI
 
 OBJS =	alloc.o c_ksh.o c_sh.o c_test.o c_ulimit.o edit.o emacs.o eval.o \
-	exec.o expr.o history.o io.o jobs.o lex.o mail.o main.o mknod.o \
-	misc.o path.o shf.o syn.o table.o trap.o tree.o tty.o var.o \
-	version.o vi.o
+	exec.o expr.o history.o io.o jobs.o lex.o mail.o main.o misc.o \
+	path.o shf.o syn.o table.o trap.o tree.o tty.o var.o version.o vi.o
 
 #
 # Portability stuff.
@@ -25,7 +24,8 @@ ifeq ($(UNAME_S),Linux)
 GROUP =	root
 OBJS +=	portable/common/reallocarray.o portable/linux/setmode.o \
 	portable/linux/signame.o portable/linux/strlcat.o \
-	portable/linux/strlcpy.o portable/common/strtonum.o
+	portable/linux/strlcpy.o portable/common/strtonum.o \
+	portable/linux/unvis.o portable/linux/vis.o
 else ifeq ($(UNAME_S),FreeBSD)
 GROUP =	bin
 OBJS +=	portable/common/reallocarray.o
@@ -38,6 +38,11 @@ OBJS += portable/common/reallocarray.o
 else ifeq ($(UNAME_S),Darwin)
 GROUP =	bin
 OBJS += portable/common/reallocarray.o portable/common/strtonum.o
+else ifeq ($(findstring CYGWIN,$(UNAME_S)),CYGWIN)
+OBJS +=	portable/common/reallocarray.o portable/linux/setmode.o \
+	portable/linux/signame.o portable/linux/strlcat.o \
+	portable/linux/strlcpy.o portable/common/strtonum.o \
+	portable/linux/unvis.o portable/linux/vis.o
 endif
 
 #
@@ -59,14 +64,18 @@ oksh: ${OBJS}
 endif
 
 install: all
-ifneq ($(UNAME_S),Darwin)
-	${INSTALL} -c -s -o root -g ${GROUP} -m 555 ${PROG} ${PREFIX}/bin
-	${INSTALL} -c -s -o root -g ${GROUP} -m 444 oksh.1 ${MANDIR}/man1/${PROG}.1
-	echo ${UPDATE}
-else
+ifeq ($(UNAME_S),Darwin)
 	@mkdir -p ${PREFIX}/bin ${MANDIR}/man1
 	${INSTALL} -m 755 ${PROG} ${PREFIX}/bin
 	${INSTALL} -m 644 ${PROG}.1 ${MANDIR}/man1
+else ifeq ($(findstring CYGWIN,$(UNAME_S)),CYGWIN)
+	@mkdir -p ${PREFIX}/bin ${MANDIR}/man1
+	${INSTALL} -c -s -m 555 ${PROG} ${PREFIX}/bin
+	${INSTALL} -c -m 444 oksh.1 ${MANDIR}/man1/${PROG}.1
+else
+	${INSTALL} -c -s -o root -g ${GROUP} -m 555 ${PROG} ${PREFIX}/bin
+	${INSTALL} -c -o root -g ${GROUP} -m 444 oksh.1 ${MANDIR}/man1/${PROG}.1
+	echo ${UPDATE}
 endif
 
 clean:
diff --git a/IAFA-PACKAGE b/IAFA-PACKAGE
@@ -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@zen.void.oz.au (Simon J. Gerraty),
-		michael@cs.mun.ca (Michael Rendell), (plus many others)
-Maintained-by:	michael@cs.mun.ca (Michael Rendell)
-Maintained-at:	ftp://ftp.cs.mun.ca:/pub/pdksh/
-Platforms:	Written in C, runs on most UNIX boxes (uses GNU autoconf;
-		works best in a POSIX or BSD environment).  Also runs on OS/2
-		and (using cygwin32 package) on win95/NT
-Copying-Policy:	Freely Redistributable (mostly public domain, some copyrighted)
-Keywords:	pdksh, ksh, Korn, shell, command line interpreter
diff --git a/INSTALL b/INSTALL
@@ -1,151 +0,0 @@
-$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'.
diff --git a/Makefile b/Makefile
@@ -1,17 +1,16 @@
-#	$OpenBSD: Makefile,v 1.29 2013/12/02 20:41:01 millert Exp $
+#	$OpenBSD: Makefile,v 1.34 2017/08/01 14:30:05 deraadt Exp $
 
 PROG=	ksh
 SRCS=	alloc.c c_ksh.c c_sh.c c_test.c c_ulimit.c edit.c emacs.c eval.c \
-	exec.c expr.c history.c io.c jobs.c lex.c mail.c main.c mknod.c \
+	exec.c expr.c history.c io.c jobs.c lex.c mail.c main.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
+DEFS=	-Wall -DEMACS -DVI
 CFLAGS+=${DEFS} -I. -I${.CURDIR} -I${.CURDIR}/../../lib/libc/gen
 MAN=	ksh.1 sh.1
 
 LINKS=	${BINDIR}/ksh ${BINDIR}/rksh
 LINKS+=	${BINDIR}/ksh ${BINDIR}/sh
-MLINKS=	ksh.1 rksh.1
 
 .include <bsd.prog.mk>
diff --git a/NEWS b/NEWS
@@ -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.15 2007/08/02 11:05:54 fgsch 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)
diff --git a/NOTES b/NOTES
@@ -1,4 +1,4 @@
-$OpenBSD: NOTES,v 1.12 2013/11/28 10:33:37 sobrado Exp $
+$OpenBSD: NOTES,v 1.14 2016/01/29 11:50:40 tb Exp $
 
 General features of at&t ksh88 that are not (yet) in pdksh:
     - exported aliases and functions (not in ksh93).
@@ -180,7 +180,7 @@ Known differences between pdksh & at&t ksh (that are not likely to change)
       (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
+      it is done after substitution (and therefore 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
@@ -244,255 +244,6 @@ Oddities in ksh (pd & at&t):
     - 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.
diff --git a/PROJECTS b/PROJECTS
@@ -1,4 +1,4 @@
-$OpenBSD: PROJECTS,v 1.7 2013/11/28 10:33:37 sobrado Exp $
+$OpenBSD: PROJECTS,v 1.8 2015/09/14 09:42:33 nicm Exp $
 
 Things to be done in pdksh (see also the NOTES file):
 
@@ -109,6 +109,3 @@ Things to be done in pdksh (see also the NOTES file):
 
 	* 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).
diff --git a/README.md b/README.md
@@ -8,7 +8,7 @@ Because other operating systems deserve a good shell to use.
 Originally a port of ksh to FreeBSD. The default FreeBSD shell is tcsh.
 No one likes tcsh. DragonFly BSD should also just work.
 Later NetBSD support was added. NetBSD also has a ksh variant so it might be less useful there.
-Linux support, tested on Slackware and Ubuntu, exists.
+Linux support, tested on Slackware and Ubuntu, exists. This includes Cygwin.
 Darwin (Mac OS X) supported as well.
 Other operating system support welcome and appreciated.
 
@@ -19,4 +19,4 @@ The rest are BSD or ISC licensed.
 
 Get a tarball
 -------------
-http://devio.us/~bcallah/oksh/oksh-6.tar.gz
+http://devio.us/~bcallah/oksh/oksh-20170917.tar.gz
diff --git a/README.pdksh b/README.pdksh
@@ -1,197 +1,22 @@
-$OpenBSD: README,v 1.10 2003/03/10 03:48:16 david Exp $
+$OpenBSD: README,v 1.16 2017/05/11 20:17:17 jmc 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
+PDksh 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@cs.mun.ca),
-who took over from Simon J. Gerraty (sjg@zen.void.oz.au) at the later's
-suggestion.  A short list of things that have been added since the last
-public pdksh release (4.9) are auto-configuration, arrays, $(( .. )),
-[[ .. ]], variable attributes, co-processes, extended file globbing,
-many POSIXisms and many bug fixes.  See the NEWS and ChangeLog files for
-other features added and bugs fixed.
-
-Note that pdksh is provided AS IS, with NO WARRANTY, either expressed or
-implied.  Also note that although the bulk of the code in pdksh is in the
-public domain, some files are copyrighten (but freely distributable) and
-subject to certain conditions (eg, don't remove copyright, document any
-changes, etc.).  See the LEGAL file for details.
-
-If you would like to be notified via email of new releases as they become
-available, send mail to pdksh-request@cs.mun.ca with subject
-"send release notifications" (or "don't send release notifications" to stop
-them).
-
+PDksh was being maintained by Michael Rendell (michael@cs.mun.ca),
+who took over from Simon J. Gerraty (sjg@zen.void.oz.au) at the latter's
+suggestion.
 
 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@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@cs.mun.ca
diff --git a/alloc.c b/alloc.c
@@ -1,33 +1,14 @@
-/*	$OpenBSD: alloc.c,v 1.8 2008/07/21 17:30:08 millert 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.
- */
+/*	$OpenBSD: alloc.c,v 1.17 2017/08/15 17:57:57 jca Exp $	*/
+
+/* Public domain, like most of the rest of ksh */
 
 /*
  * area-based allocation built on malloc/free
  */
 
+#include <stdint.h>
+#include <stdlib.h>
+
 #include "sh.h"
 
 struct link {
@@ -62,7 +43,11 @@ alloc(size_t size, Area *ap)
 {
 	struct link *l;
 
-	l = malloc(sizeof(struct link) + size);
+	/* ensure that we don't overflow by allocating space for link */
+	if (size > SIZE_MAX - sizeof(struct link))
+		internal_errorf(1, "unable to allocate memory");
+
+	l = calloc(1, sizeof(struct link) + size);
 	if (l == NULL)
 		internal_errorf(1, "unable to allocate memory");
 	l->next = ap->freelist;
@@ -74,6 +59,26 @@ alloc(size_t size, Area *ap)
 	return L2P(l);
 }
 
+/*
+ * Copied from calloc().
+ *
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW	(1UL << (sizeof(size_t) * 4))
+
+void *
+areallocarray(void *ptr, size_t nmemb, size_t size, Area *ap)
+{
+	/* condition logic cloned from calloc() */
+	if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+	    nmemb > 0 && SIZE_MAX / nmemb < size) {
+		internal_errorf(1, "unable to allocate memory");
+	}
+
+	return aresize(ptr, nmemb * size, ap);
+}
+
 void *
 aresize(void *ptr, size_t size, Area *ap)
 {
@@ -82,6 +87,10 @@ aresize(void *ptr, size_t size, Area *ap)
 	if (ptr == NULL)
 		return alloc(size, ap);
 
+	/* ensure that we don't overflow by allocating space for link */
+	if (size > SIZE_MAX - sizeof(struct link))
+		internal_errorf(1, "unable to allocate memory");
+
 	l = P2L(ptr);
 	lprev = l->prev;
 	lnext = l->next;
@@ -102,20 +111,12 @@ aresize(void *ptr, size_t size, Area *ap)
 void
 afree(void *ptr, Area *ap)
 {
-	struct link *l, *l2;
+	struct link *l;
 
 	if (!ptr)
 		return;
 
 	l = P2L(ptr);
-
-	for (l2 = ap->freelist; l2 != NULL; l2 = l2->next) {
-		if (l == l2)
-			break;
-	}
-	if (l2 == NULL)
-		internal_errorf(1, "afree: %p not present in area %p", ptr, ap);
-
 	if (l->prev)
 		l->prev->next = l->next;
 	else
diff --git a/c_ksh.c b/c_ksh.c
@@ -1,13 +1,17 @@
-/*	$OpenBSD: c_ksh.c,v 1.34 2013/12/17 16:37:05 deraadt Exp $	*/
+/*	$OpenBSD: c_ksh.c,v 1.51 2017/09/03 11:52:01 jca Exp $	*/
 
 /*
  * built-in Korn commands: c_*
  */
 
-#include "sh.h"
 #include <sys/stat.h>
+
 #include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
 
+#include "sh.h"
 
 int
 c_cd(char **wp)
@@ -77,7 +81,7 @@ c_cd(char **wp)
 		 * we could try to find another substitution. For now
 		 * we don't
 		 */
-		if ((cp = strstr(current_wd, wp[0])) == (char *) 0) {
+		if ((cp = strstr(current_wd, wp[0])) == NULL) {
 			bi_errorf("bad substitution");
 			return 1;
 		}
@@ -95,11 +99,11 @@ c_cd(char **wp)
 		return 1;
 	}
 
-	Xinit(xs, xp, PATH, ATEMP);
+	Xinit(xs, xp, PATH_MAX, 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;
+	xp = NULL;
 
 	cdpath = str_val(global("CDPATH"));
 	do {
@@ -110,15 +114,14 @@ c_cd(char **wp)
 			simplify_path(Xstring(xs, xp));
 			rval = chdir(try = Xstring(xs, xp));
 		}
-	} while (rval < 0 && cdpath != (char *) 0);
+	} while (rval < 0 && cdpath != NULL);
 
 	if (rval < 0) {
 		if (cdnode)
 			bi_errorf("%s: bad directory", dir);
 		else
 			bi_errorf("%s - %s", try, strerror(errno));
-		if (fdir)
-			afree(fdir, ATEMP);
+		afree(fdir, ATEMP);
 		return 1;
 	}
 
@@ -133,7 +136,7 @@ c_cd(char **wp)
 		setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR);
 
 	if (Xstring(xs, xp)[0] != '/') {
-		pwd = (char *) 0;
+		pwd = NULL;
 	} else
 	if (!physical || !(pwd = get_phys_path(Xstring(xs, xp))))
 		pwd = Xstring(xs, xp);
@@ -152,8 +155,7 @@ c_cd(char **wp)
 	if (printpath || cdnode)
 		shprintf("%s\n", pwd);
 
-	if (fdir)
-		afree(fdir, ATEMP);
+	afree(fdir, ATEMP);
 
 	return 0;
 }
@@ -183,11 +185,11 @@ c_pwd(char **wp)
 		return 1;
 	}
 	p = current_wd[0] ? (physical ? get_phys_path(current_wd) : current_wd) :
-	    (char *) 0;
+	    NULL;
 	if (p && access(p, R_OK) < 0)
-		p = (char *) 0;
+		p = NULL;
 	if (!p) {
-		freep = p = ksh_get_wd((char *) 0, 0);
+		freep = p = ksh_get_wd(NULL, 0);
 		if (!p) {
 			bi_errorf("can't get current directory - %s",
 			    strerror(errno));
@@ -195,8 +197,7 @@ c_pwd(char **wp)
 		}
 	}
 	shprintf("%s\n", p);
-	if (freep)
-		afree(freep, ATEMP);
+	afree(freep, ATEMP);
 	return 0;
 }
 
@@ -432,23 +433,23 @@ c_whence(char **wp)
 
 	fcflags = FC_BI | FC_PATH | FC_FUNC;
 	if (!iam_whence) {
-		/* Note that -p on its own is deal with in comexec() */
+		/* Note that -p on its own is dealt 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.
+		/* Convert command options to whence options.  Note that
+		 * command -pV and command -pv use a different path search
+		 * than whence -v or whence -pv.  This should be considered
+		 * a feature.
 		 */
 		vflag = Vflag;
-	}
-	if (pflag)
+	} else if (pflag)
 		fcflags &= ~(FC_BI | FC_FUNC);
 
 	while ((vflag || ret == 0) && (id = *wp++) != NULL) {
 		tp = NULL;
-		if ((iam_whence || vflag) && !pflag)
+		if (!iam_whence || !pflag)
 			tp = ktsearch(&keywords, id, hash(id));
-		if (!tp && !pflag) {
+		if (!tp && (!iam_whence || !pflag)) {
 			tp = ktsearch(&aliases, id, hash(id));
 			if (tp && !(tp->flag & ISSET))
 				tp = NULL;
@@ -466,8 +467,7 @@ c_whence(char **wp)
 		case CALIAS:
 			if (vflag)
 				shprintf(" is an %salias for ",
-				    (tp->flag & EXPORT) ? "exported " :
-				    null);
+				    (tp->flag & EXPORT) ? "exported " : "");
 			if (!iam_whence && !vflag)
 				shprintf("alias %s=", id);
 			print_value_quoted(tp->val.s);
@@ -491,7 +491,7 @@ c_whence(char **wp)
 		case CSHELL:
 			if (vflag)
 				shprintf(" is a%s shell builtin",
-				    (tp->flag & SPEC_BI) ? " special" : null);
+				    (tp->flag & SPEC_BI) ? " special" : "");
 			break;
 		case CTALIAS:
 		case CEXEC:
@@ -501,7 +501,7 @@ c_whence(char **wp)
 					if (tp->type == CTALIAS)
 						shprintf("a tracked %salias for ",
 						    (tp->flag & EXPORT) ?
-						    "exported " : null);
+						    "exported " : "");
 				}
 				shprintf("%s", tp->val.s);
 			} else {
@@ -515,7 +515,7 @@ c_whence(char **wp)
 			break;
 		}
 		if (vflag || !ret)
-			shprintf("%s", newline);
+			shprintf("\n");
 	}
 	return ret;
 }
@@ -534,16 +534,12 @@ c_command(char **wp)
 int
 c_typeset(char **wp)
 {
-	struct block *l = e->loc;
+	struct block *l;
 	struct tbl *vp, **p;
-	Tflag fset = 0, fclr = 0;
-	int thing = 0, func = 0, local = 0;
+	int fset = 0, fclr = 0, thing = 0, func = 0, local = 0, pflag = 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;
+	int field, base, optc, flag;
 
 	switch (**wp) {
 	case 'e':		/* export */
@@ -562,7 +558,7 @@ c_typeset(char **wp)
 		break;
 	}
 
-	fieldstr = basestr = (char *) 0;
+	fieldstr = basestr = NULL;
 	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
@@ -714,7 +710,7 @@ c_typeset(char **wp)
 	/* list variables and attributes */
 	flag = fset | fclr; /* no difference at this point.. */
 	if (func) {
-		for (l = e->loc; l; l = l->next) {
+		for (l = genv->loc; l; l = l->next) {
 			for (p = ktsort(&l->funs); (vp = *p++); ) {
 				if (flag && (vp->flag & flag) == 0)
 					continue;
@@ -727,7 +723,7 @@ c_typeset(char **wp)
 			}
 		}
 	} else {
-		for (l = e->loc; l; l = l->next) {
+		for (l = genv->loc; l; l = l->next) {
 			for (p = ktsort(&l->vars); (vp = *p++); ) {
 				struct tbl *tvp;
 				int any_set = 0;
@@ -816,7 +812,7 @@ c_typeset(char **wp)
 							else
 								print_value_quoted(s);
 						}
-						shprintf("%s", newline);
+						shprintf("\n");
 					}
 					/* Only report first `element' of an array with
 					* no set elements.
@@ -834,9 +830,8 @@ 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 rv = 0, rflag = 0, tflag, Uflag = 0, pflag = 0, prefix = 0;
+	int xflag = 0;
 	int optc;
 
 	builtin_opt.flags |= GF_PLUSOPT;
@@ -882,7 +877,7 @@ c_alias(char **wp)
 	/* "hash -r" means reset all the tracked aliases.. */
 	if (rflag) {
 		static const char *const args[] = {
-			"unalias", "-ta", (const char *) 0
+			"unalias", "-ta", NULL
 		};
 
 		if (!tflag || *wp) {
@@ -906,7 +901,7 @@ c_alias(char **wp)
 					shf_putc('=', shl_stdout);
 					print_value_quoted(ap->val.s);
 				}
-				shprintf("%s", newline);
+				shprintf("\n");
 			}
 	}
 
@@ -930,7 +925,7 @@ c_alias(char **wp)
 					shf_putc('=', shl_stdout);
 					print_value_quoted(ap->val.s);
 				}
-				shprintf("%s", newline);
+				shprintf("\n");
 			} else {
 				shprintf("%s alias not found\n", alias);
 				rv = 1;
@@ -943,10 +938,10 @@ c_alias(char **wp)
 		if ((val && !tflag) || (!val && tflag && !Uflag)) {
 			if (ap->flag&ALLOC) {
 				ap->flag &= ~(ALLOC|ISSET);
-				afree((void*)ap->val.s, APERM);
+				afree(ap->val.s, APERM);
 			}
 			/* ignore values for -t (at&t ksh does this) */
-			newval = tflag ? search(alias, path, X_OK, (int *) 0) :
+			newval = tflag ? search(alias, path, X_OK, NULL) :
 			    val;
 			if (newval) {
 				ap->val.s = str_save(newval, APERM);
@@ -998,7 +993,7 @@ c_unalias(char **wp)
 		}
 		if (ap->flag&ALLOC) {
 			ap->flag &= ~(ALLOC|ISSET);
-			afree((void*)ap->val.s, APERM);
+			afree(ap->val.s, APERM);
 		}
 		ap->flag &= ~(DEFINED|ISSET|EXPORT);
 	}
@@ -1009,7 +1004,7 @@ c_unalias(char **wp)
 		for (ktwalk(&ts, t); (ap = ktnext(&ts)); ) {
 			if (ap->flag&ALLOC) {
 				ap->flag &= ~(ALLOC|ISSET);
-				afree((void*)ap->val.s, APERM);
+				afree(ap->val.s, APERM);
 			}
 			ap->flag &= ~(DEFINED|ISSET|EXPORT);
 		}
@@ -1024,7 +1019,7 @@ c_let(char **wp)
 	int rv = 1;
 	long val;
 
-	if (wp[1] == (char *) 0) /* at&t ksh does this */
+	if (wp[1] == NULL) /* at&t ksh does this */
 		bi_errorf("no arguments");
 	else
 		for (wp++; *wp; wp++)
@@ -1063,7 +1058,7 @@ c_jobs(char **wp)
 		}
 	wp += builtin_opt.optind;
 	if (!*wp) {
-		if (j_jobs((char *) 0, flag, nflag))
+		if (j_jobs(NULL, flag, nflag))
 			rv = 1;
 	} else {
 		for (; *wp; wp++)
@@ -1129,7 +1124,7 @@ kill_fmt_entry(void *arg, int i, char *buf, int buflen)
 int
 c_kill(char **wp)
 {
-	Trap *t = (Trap *) 0;
+	Trap *t = NULL;
 	char *p;
 	int lflag = 0;
 	int i, n, rv, sig;
@@ -1166,7 +1161,7 @@ c_kill(char **wp)
 		shf_fprintf(shl_out,
 		    "usage: kill [-s signame | -signum | -signame] { job | pid | pgrp } ...\n"
 		    "       kill -l [exit_status ...]\n");
-		bi_errorf("%s", null);
+		bi_errorf(NULL);
 		return 1;
 	}
 
@@ -1184,18 +1179,20 @@ c_kill(char **wp)
 			}
 		} else if (Flag(FPOSIX)) {
 			p = null;
-			for (i = 1; i < NSIG; i++, p = space)
+			for (i = 1; i < NSIG; i++, p = " ")
 				if (sigtraps[i].name)
 					shprintf("%s%s", p, sigtraps[i].name);
-			shprintf("%s", newline);
+			shprintf("\n");
 		} else {
-			int w, i;
-			int mess_width;
-			struct kill_info ki;
+			int mess_width = 0, w, i;
+			struct kill_info ki = {
+				.num_width = 1,
+				.name_width = 0,
+			};
 
-			for (i = NSIG, ki.num_width = 1; i >= 10; i /= 10)
+			for (i = NSIG; 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;
@@ -1276,15 +1273,15 @@ c_getopts(char **wp)
 		return 1;
 	}
 
-	if (e->loc->next == (struct block *) 0) {
+	if (genv->loc->next == NULL) {
 		internal_errorf(0, "c_getopts: no argv");
 		return 1;
 	}
 	/* Which arguments are we parsing... */
-	if (*wp == (char *) 0)
-		wp = e->loc->next->argv;
+	if (*wp == NULL)
+		wp = genv->loc->next->argv;
 	else
-		*--wp = e->loc->next->argv[0];
+		*--wp = genv->loc->next->argv[0];
 
 	/* Check that our saved state won't cause a core dump... */
 	for (argc = 0; wp[argc]; argc++)
@@ -1296,7 +1293,7 @@ c_getopts(char **wp)
 		return 1;
 	}
 
-	user_opt.optarg = (char *) 0;
+	user_opt.optarg = NULL;
 	optc = ksh_getopt(wp, &user_opt, options);
 
 	if (optc >= 0 && optc != '?' && (user_opt.info & GI_PLUS)) {
@@ -1324,7 +1321,7 @@ c_getopts(char **wp)
 	/* Paranoia: ensure no bizarre results. */
 	if (voptarg->flag & INTEGER)
 	    typeset("OPTARG", 0, INTEGER, 0, 0);
-	if (user_opt.optarg == (char *) 0)
+	if (user_opt.optarg == NULL)
 		unset(voptarg, 0);
 	else
 		/* This can't fail (have cleared readonly/integer) */
@@ -1363,7 +1360,7 @@ c_bind(char **wp)
 	wp += builtin_opt.optind;
 
 	if (*wp == NULL)	/* list all */
-		rv = x_bind((char*)NULL, (char*)NULL, 0, list);
+		rv = x_bind(NULL, NULL, 0, list);
 
 	for (; *wp != NULL; wp++) {
 		cp = strchr(*wp, '=');
diff --git a/c_sh.c b/c_sh.c
@@ -1,15 +1,25 @@
-/*	$OpenBSD: c_sh.c,v 1.45 2014/08/27 08:26:04 jmc Exp $	*/
+/*	$OpenBSD: c_sh.c,v 1.60 2017/07/22 09:37:21 anton Exp $	*/
 
 /*
  * built-in Bourne commands
  */
 
-#include "sh.h"
+#include <sys/resource.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 *);
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sh.h"
+
+static void p_tv(struct shf *, int, struct timeval *, int, char *, char *);
+static void p_ts(struct shf *, int, struct timespec *, int, char *, char *);
 
 /* :, false and true */
 int
@@ -21,7 +31,7 @@ c_label(char **wp)
 int
 c_shift(char **wp)
 {
-	struct block *l = e->loc;
+	struct block *l = genv->loc;
 	int n;
 	long val;
 	char *arg;
@@ -199,12 +209,12 @@ c_dot(char **wp)
 	/* Set positional parameters? */
 	if (wp[builtin_opt.optind + 1]) {
 		argv = wp + builtin_opt.optind;
-		argv[0] = e->loc->argv[0]; /* preserve $0 */
+		argv[0] = genv->loc->argv[0]; /* preserve $0 */
 		for (argc = 0; argv[argc + 1]; argc++)
 			;
 	} else {
 		argc = 0;
-		argv = (char **) 0;
+		argv = NULL;
 	}
 	i = include(file, argc, argv, 0);
 	if (i < 0) { /* should not happen */
@@ -223,8 +233,8 @@ c_wait(char **wp)
 	if (ksh_getopt(wp, &builtin_opt, null) == '?')
 		return 1;
 	wp += builtin_opt.optind;
-	if (*wp == (char *) 0) {
-		while (waitfor((char *) 0, &sig) >= 0)
+	if (*wp == NULL) {
+		while (waitfor(NULL, &sig) >= 0)
 			;
 		rv = sig;
 	} else {
@@ -323,7 +333,7 @@ c_read(char **wp)
 				if (c == '\0')
 					continue;
 				if (c == EOF && shf_error(shf) &&
-				    shf_errno(shf) == EINTR) {
+				    shf->errno_ == EINTR) {
 					/* Was the offending signal one that
 					 * would normally kill a process?
 					 * If so, pretend the read was killed.
@@ -351,7 +361,7 @@ c_read(char **wp)
 						/* set prompt in case this is
 						 * called from .profile or $ENV
 						 */
-						set_prompt(PS2, (Source *) 0);
+						set_prompt(PS2, NULL);
 						pprompt(prompt, 0);
 					}
 				} else if (c != EOF)
@@ -520,7 +530,7 @@ c_exitreturn(char **wp)
 		/* need to tell if this is exit or return so trap exit will
 		 * work right (POSIX)
 		 */
-		for (ep = e; ep; ep = ep->oenv)
+		for (ep = genv; ep; ep = ep->oenv)
 			if (STOP_RETURN(ep->type)) {
 				how = LRETURN;
 				break;
@@ -542,7 +552,7 @@ int
 c_brkcont(char **wp)
 {
 	int n, quit;
-	struct env *ep, *last_ep = (struct env *) 0;
+	struct env *ep, *last_ep = NULL;
 	char *arg;
 
 	if (ksh_getopt(wp, &builtin_opt, null) == '?')
@@ -561,7 +571,7 @@ c_brkcont(char **wp)
 	}
 
 	/* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */
-	for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv)
+	for (ep = genv; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv)
 		if (ep->type == E_LOOP) {
 			if (--quit == 0)
 				break;
@@ -596,7 +606,7 @@ int
 c_set(char **wp)
 {
 	int argi, setargs;
-	struct block *l = e->loc;
+	struct block *l = genv->loc;
 	char **owp = wp;
 
 	if (wp[1] == NULL) {
@@ -614,7 +624,7 @@ c_set(char **wp)
 		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);
+		l->argv = areallocarray(NULL, l->argc+2, sizeof(char *), &l->area);
 		for (wp = l->argv; (*wp++ = *owp++) != NULL; )
 			;
 	}
@@ -655,37 +665,53 @@ c_unset(char **wp)
 			}
 			unset(vp, strchr(id, '[') ? 1 : 0);
 		} else {		/* unset function */
-			define(id, (struct op *) NULL);
+			define(id, NULL);
 		}
 	return 0;
 }
 
 static void
-p_time(struct shf *shf, int posix, struct timeval *tv, int width, char *prefix,
+p_tv(struct shf *shf, int posix, struct timeval *tv, int width, char *prefix,
     char *suffix)
 {
 	if (posix)
 		shf_fprintf(shf, "%s%*lld.%02ld%s", prefix ? prefix : "",
 		    width, (long long)tv->tv_sec, tv->tv_usec / 10000, suffix);
 	else
-		shf_fprintf(shf, "%s%*lldm%lld.%02lds%s", prefix ? prefix : "",
+		shf_fprintf(shf, "%s%*lldm%02lld.%02lds%s", prefix ? prefix : "",
 		    width, (long long)tv->tv_sec / 60,
 		    (long long)tv->tv_sec % 60,
 		    tv->tv_usec / 10000, suffix);
 }
 
+static void
+p_ts(struct shf *shf, int posix, struct timespec *ts, int width, char *prefix,
+    char *suffix)
+{
+	if (posix)
+		shf_fprintf(shf, "%s%*lld.%02ld%s", prefix ? prefix : "",
+		    width, (long long)ts->tv_sec, ts->tv_nsec / 10000000,
+		    suffix);
+	else
+		shf_fprintf(shf, "%s%*lldm%02lld.%02lds%s", prefix ? prefix : "",
+		    width, (long long)ts->tv_sec / 60,
+		    (long long)ts->tv_sec % 60,
+		    ts->tv_nsec / 10000000, 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");
+	p_tv(shl_stdout, 0, &usage.ru_utime, 0, NULL, " ");
+	p_tv(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");
+	p_tv(shl_stdout, 0, &usage.ru_utime, 0, NULL, " ");
+	p_tv(shl_stdout, 0, &usage.ru_stime, 0, NULL, "\n");
 
 	return 0;
 }
@@ -701,11 +727,12 @@ timex(struct op *t, int f, volatile int *xerrok)
 #define TF_POSIX	BIT(2)		/* report in posix format */
 	int rv = 0;
 	struct rusage ru0, ru1, cru0, cru1;
-	struct timeval usrtime, systime, tv0, tv1;
+	struct timeval usrtime, systime;
+	struct timespec ts0, ts1, ts2;
 	int tf = 0;
 	extern struct timeval j_usrtime, j_systime; /* computed by j_wait */
 
-	gettimeofday(&tv0, NULL);
+	clock_gettime(CLOCK_MONOTONIC, &ts0);
 	getrusage(RUSAGE_SELF, &ru0);
 	getrusage(RUSAGE_CHILDREN, &cru0);
 	if (t->left) {
@@ -722,7 +749,7 @@ timex(struct op *t, int f, volatile int *xerrok)
 		rv = execute(t->left, f | XTIME, xerrok);
 		if (t->left->type == TCOM)
 			tf |= t->left->str[0];
-		gettimeofday(&tv1, NULL);
+		clock_gettime(CLOCK_MONOTONIC, &ts1);
 		getrusage(RUSAGE_SELF, &ru1);
 		getrusage(RUSAGE_CHILDREN, &cru1);
 	} else
@@ -740,20 +767,20 @@ timex(struct op *t, int f, volatile int *xerrok)
 	}
 
 	if (!(tf & TF_NOREAL)) {
-		timersub(&tv1, &tv0, &tv1);
+		timespecsub(&ts1, &ts0, &ts2);
 		if (tf & TF_POSIX)
-			p_time(shl_out, 1, &tv1, 5, "real ", "\n");
+			p_ts(shl_out, 1, &ts2, 5, "real ", "\n");
 		else
-			p_time(shl_out, 0, &tv1, 5, NULL, " real ");
+			p_ts(shl_out, 0, &ts2, 5, NULL, " real ");
 	}
 	if (tf & TF_POSIX)
-		p_time(shl_out, 1, &usrtime, 5, "user ", "\n");
+		p_tv(shl_out, 1, &usrtime, 5, "user ", "\n");
 	else
-		p_time(shl_out, 0, &usrtime, 5, NULL, " user ");
+		p_tv(shl_out, 0, &usrtime, 5, NULL, " user ");
 	if (tf & TF_POSIX)
-		p_time(shl_out, 1, &systime, 5, "sys  ", "\n");
+		p_tv(shl_out, 1, &systime, 5, "sys  ", "\n");
 	else
-		p_time(shl_out, 0, &systime, 5, NULL, " system\n");
+		p_tv(shl_out, 0, &systime, 5, NULL, " system\n");
 	shf_flush(shl_out);
 
 	return rv;
@@ -799,78 +826,24 @@ c_exec(char **wp)
 	int i;
 
 	/* make sure redirects stay in place */
-	if (e->savefd != NULL) {
+	if (genv->savefd != NULL) {
 		for (i = 0; i < NUFILE; i++) {
-			if (e->savefd[i] > 0)
-				close(e->savefd[i]);
+			if (genv->savefd[i] > 0)
+				close(genv->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])
+			if (!Flag(FSH) && i > 2 && genv->savefd[i])
 				fcntl(i, F_SETFD, FD_CLOEXEC);
 		}
-		e->savefd = NULL;
+		genv->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] == NULL)
-		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:
-	builtin_argv0 = NULL;
-	bi_errorf("usage: mknod [-m mode] name b|c major minor");
-	bi_errorf("usage: mknod [-m mode] name p");
-	return 1;
-}
-
 static int
 c_suspend(char **wp)
 {
@@ -929,7 +902,6 @@ const struct builtin shbuiltins [] = {
 	{"ulimit", c_ulimit},
 	{"+umask", c_umask},
 	{"*=unset", c_unset},
-	{"mknod", c_mknod},
 	{"suspend", c_suspend},
 	{NULL, NULL}
 };
diff --git a/c_test.c b/c_test.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $	*/
+/*	$OpenBSD: c_test.c,v 1.23 2015/12/14 13:59:42 tb Exp $	*/
 
 /*
  * test(1); version 7-like  --  author Erik Baalbergen
@@ -9,8 +9,12 @@
  * modified by J.T. Conklin to add POSIX compatibility.
  */
 
-#include "sh.h"
 #include <sys/stat.h>
+
+#include <string.h>
+#include <unistd.h>
+
+#include "sh.h"
 #include "c_test.h"
 
 /* test(1) accepts the following grammar:
@@ -161,7 +165,7 @@ c_test(char **wp)
 				if (!Flag(FPOSIX) && strcmp(opnd1, "-t") == 0)
 				    break;
 				res = (*te.eval)(&te, TO_STNZE, opnd1,
-				    (char *) 0, 1);
+				    NULL, 1);
 				if (invert & 1)
 					res = !res;
 				return !res;
@@ -471,7 +475,7 @@ test_primary(Test_env *te, int do_eval)
 				return 0;
 			}
 
-			return (*te->eval)(te, op, opnd1, (const char *) 0,
+			return (*te->eval)(te, op, opnd1, NULL,
 			    do_eval);
 		}
 	}
@@ -494,7 +498,7 @@ test_primary(Test_env *te, int do_eval)
 		(*te->error)(te, -1, "missing expression operator");
 		return 0;
 	}
-	return (*te->eval)(te, TO_STNZE, opnd1, (const char *) 0, do_eval);
+	return (*te->eval)(te, TO_STNZE, opnd1, NULL, do_eval);
 }
 
 /*
@@ -535,7 +539,7 @@ 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 op == TO_FILTT ? "1" : NULL;
 	return *te->pos.wp++;
 }
 
@@ -550,7 +554,7 @@ 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];
+	    NULL : te->pos.wp[offset];
 
 	te->flags |= TEF_ERROR;
 	if (op)
diff --git a/c_ulimit.c b/c_ulimit.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: c_ulimit.c,v 1.19 2013/11/28 10:33:37 sobrado Exp $	*/
+/*	$OpenBSD: c_ulimit.c,v 1.24 2015/12/14 13:59:42 tb Exp $	*/
 
 /*
 	ulimit -- handle "ulimit" builtin
@@ -18,9 +18,14 @@
 	that was originally under case SYSULIMIT in source file "xec.c".
 */
 
-#include "sh.h"
 #include <sys/resource.h>
 
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+
+#include "sh.h"
+
 #define SOFT	0x1
 #define HARD	0x2
 
@@ -51,7 +56,7 @@ c_ulimit(char **wp)
 #ifdef RLIMIT_VMEM
 		{ "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
 #endif /* RLIMIT_VMEM */
-		{ (char *) 0 }
+		{ NULL }
 	};
 	static char	options[4 + NELEM(limits) * 2];
 	int		how = SOFT | HARD;
diff --git a/config.h b/config.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: config.h,v 1.14 2011/03/14 21:20:00 okan Exp $	*/
+/*	$OpenBSD: config.h,v 1.16 2017/08/01 14:30:05 deraadt Exp $	*/
 
 /* config.h.  NOT generated automatically. */
 
@@ -11,12 +11,6 @@
 #ifndef CONFIG_H
 #define CONFIG_H
 
-/* Include emacs editing? */
-#define EMACS 1
-
-/* Include vi editing? */
-#define VI 1
-
 /* Include job control? */
 #define JOBS 1
 
@@ -32,9 +26,6 @@
 /* Specify default $ENV? */
 /* #undef DEFAULT_ENV */
 
-/* The number of bytes in a int.  */
-#define SIZEOF_INT 4
-
 /*
  * End of configuration stuff for PD ksh.
  */
@@ -45,13 +36,6 @@
 # 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
diff --git a/edit.c b/edit.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: edit.c,v 1.40 2015/03/12 10:20:30 sthen Exp $	*/
+/*	$OpenBSD: edit.c,v 1.57 2016/09/08 12:12:40 nicm Exp $	*/
 
 /*
  * Command line editing - common code
@@ -8,16 +8,22 @@
 #include "config.h"
 #ifdef EDIT
 
-#include "sh.h"
-#include "tty.h"
-#define EXTERN
-#include "edit.h"
-#undef EXTERN
 #include <sys/ioctl.h>
+#include <sys/stat.h>
+
 #include <ctype.h>
+#include <errno.h>
 #include <libgen.h>
-#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
 
+#include "sh.h"
+#include "edit.h"
+#include "tty.h"
+
+X_chars edchars;
 
 static void x_sigwinch(int);
 volatile sig_atomic_t got_sigwinch;
@@ -48,7 +54,6 @@ x_init(void)
 #endif /* EMACS */
 }
 
-/* ARGSUSED */
 static void
 x_sigwinch(int sig)
 {
@@ -294,9 +299,7 @@ static void	glob_path(int flags, const char *pat, XPtrV *wp,
 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)
@@ -307,33 +310,37 @@ x_print_expansions(int nwords, char *const *words, int is_command)
 
 		/* Special case for 1 match (prefix is whole word) */
 		if (nwords == 1)
-			prefix_len = x_basename(words[0], (char *) 0);
+			prefix_len = x_basename(words[0], NULL);
 		/* Any (non-trailing) slashes in non-common word suffixes? */
 		for (i = 0; i < nwords; i++)
-			if (x_basename(words[i] + prefix_len, (char *) 0) >
+			if (x_basename(words[i] + prefix_len, NULL) >
 			    prefix_len)
 				break;
 		/* All in same directory? */
 		if (i == nwords) {
+			XPtrV l;
+
 			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);
+			XPput(l, NULL);
+
+			/* Enumerate expansions */
+			x_putc('\r');
+			x_putc('\n');
+			pr_list((char **) XPptrv(l));
+
+			XPfree(l); /* not x_free_words() */
+			return;
 		}
 	}
 
-	/*
-	 * Enumerate expansions
-	 */
+	/* 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() */
+	pr_list(words);
 }
 
 /*
@@ -449,7 +456,7 @@ x_command_glob(int flags, const char *str, int slen, char ***wordsp)
 	glob_table(pat, &w, &keywords);
 	glob_table(pat, &w, &aliases);
 	glob_table(pat, &w, &builtins);
-	for (l = e->loc; l; l = l->next)
+	for (l = genv->loc; l; l = l->next)
 		glob_table(pat, &w, &l->funs);
 
 	glob_path(flags, pat, &w, path);
@@ -459,7 +466,7 @@ x_command_glob(int flags, const char *str, int slen, char ***wordsp)
 	nwords = XPsize(w);
 
 	if (!nwords) {
-		*wordsp = (char **) 0;
+		*wordsp = NULL;
 		XPfree(w);
 		return 0;
 	}
@@ -468,16 +475,17 @@ x_command_glob(int flags, const char *str, int slen, char ***wordsp)
 	if (flags & XCF_FULLPATH) {
 		/* Sort by basename, then path order */
 		struct path_order_info *info;
-		struct path_order_info *last_info = 0;
+		struct path_order_info *last_info = NULL;
 		char **words = (char **) XPptrv(w);
 		int path_order = 0;
 		int i;
 
-		info = (struct path_order_info *)
-			alloc(sizeof(struct path_order_info) * nwords, ATEMP);
+		info = areallocarray(NULL, nwords,
+		    sizeof(struct path_order_info), ATEMP);
+
 		for (i = 0; i < nwords; i++) {
 			info[i].word = words[i];
-			info[i].base = x_basename(words[i], (char *) 0);
+			info[i].base = x_basename(words[i], NULL);
 			if (!last_info || info[i].base != last_info->base ||
 			    strncmp(words[i], last_info->word, info[i].base) != 0) {
 				last_info = &info[i];
@@ -489,7 +497,7 @@ x_command_glob(int flags, const char *str, int slen, char ***wordsp)
 			path_order_cmp);
 		for (i = 0; i < nwords; i++)
 			words[i] = info[i].word;
-		afree((void *) info, ATEMP);
+		afree(info, ATEMP);
 	} else {
 		/* Sort and remove duplicate entries */
 		char **words = (char **) XPptrv(w);
@@ -571,13 +579,88 @@ x_locate_word(const char *buf, int buflen, int pos, int *startp,
 	return end - start;
 }
 
+static int
+x_try_array(const char *buf, int buflen, const char *want, int wantlen,
+    int *nwords, char ***words)
+{
+	const char *cmd, *cp;
+	int cmdlen, n, i, slen;
+	char *name, *s;
+	struct tbl *v, *vp;
+
+	*nwords = 0;
+	*words = NULL;
+
+	/* Walk back to find start of command. */
+	if (want == buf)
+		return 0;
+	for (cmd = want; cmd > buf; cmd--) {
+		if (strchr(";|&()`", cmd[-1]) != NULL)
+			break;
+	}
+	while (cmd < want && isspace((u_char)*cmd))
+		cmd++;
+	cmdlen = 0;
+	while (cmd + cmdlen < want && !isspace((u_char)cmd[cmdlen]))
+		cmdlen++;
+	for (i = 0; i < cmdlen; i++) {
+		if (!isalnum((u_char)cmd[i]) && cmd[i] != '_')
+			return 0;
+	}
+
+	/* Take a stab at argument count from here. */
+	n = 1;
+	for (cp = cmd + cmdlen + 1; cp < want; cp++) {
+		if (!isspace((u_char)cp[-1]) && isspace((u_char)*cp))
+			n++;
+	}
+
+	/* Try to find the array. */
+	if (asprintf(&name, "complete_%.*s_%d", cmdlen, cmd, n) < 0)
+		internal_errorf(1, "unable to allocate memory");
+	v = global(name);
+	free(name);
+	if (~v->flag & (ISSET|ARRAY)) {
+		if (asprintf(&name, "complete_%.*s", cmdlen, cmd) < 0)
+			internal_errorf(1, "unable to allocate memory");
+		v = global(name);
+		free(name);
+		if (~v->flag & (ISSET|ARRAY))
+			return 0;
+	}
+
+	/* Walk the array and build words list. */
+	for (vp = v; vp; vp = vp->u.array) {
+		if (~vp->flag & ISSET)
+			continue;
+
+		s = str_val(vp);
+		slen = strlen(s);
+
+		if (slen < wantlen)
+			continue;
+		if (slen > wantlen)
+			slen = wantlen;
+		if (slen != 0 && strncmp(s, want, slen) != 0)
+			continue;
+
+		*words = areallocarray(*words, (*nwords) + 2, sizeof **words,
+		    ATEMP);
+		(*words)[(*nwords)++] = str_save(s, ATEMP);
+	}
+	if (*nwords != 0)
+		(*words)[*nwords] = NULL;
+
+	return *nwords != 0;
+}
+
 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;
+	char **words = NULL;
 	int is_command;
 
 	len = x_locate_word(buf, buflen, pos, startp, &is_command);
@@ -590,10 +673,12 @@ x_cf_glob(int flags, const char *buf, int buflen, int pos, int *startp,
 	if (len == 0 && is_command)
 		return 0;
 
-	nwords = (is_command ? x_command_glob : x_file_glob)(flags,
-	    buf + *startp, len, &words);
+	if (is_command)
+		nwords = x_command_glob(flags, buf + *startp, len, &words);
+	else if (!x_try_array(buf, buflen, buf + *startp, len, &nwords, &words))
+		nwords = x_file_glob(flags, buf + *startp, len, &words);
 	if (nwords == 0) {
-		*wordsp = (char **) 0;
+		*wordsp = NULL;
 		return 0;
 	}
 
@@ -616,7 +701,7 @@ add_glob(const char *str, int slen)
 	bool saw_slash = false;
 
 	if (slen < 0)
-		return (char *) 0;
+		return NULL;
 
 	toglob = str_nsave(str, slen + 1, ATEMP); /* + 1 for "*" */
 	toglob[slen] = '\0';
@@ -673,8 +758,7 @@ x_free_words(int nwords, char **words)
 	int i;
 
 	for (i = 0; i < nwords; i++)
-		if (words[i])
-			afree(words[i], ATEMP);
+		afree(words[i], ATEMP);
 	afree(words, ATEMP);
 }
 
@@ -695,7 +779,7 @@ x_basename(const char *s, const char *se)
 {
 	const char *p;
 
-	if (se == (char *) 0)
+	if (se == NULL)
 		se = s + strlen(s);
 	if (s == se)
 		return 0;
diff --git a/edit.h b/edit.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: edit.h,v 1.9 2011/05/30 17:14:35 martynas Exp $	*/
+/*	$OpenBSD: edit.h,v 1.11 2016/01/26 17:39:31 mmcc Exp $	*/
 
 /* NAME:
  *      edit.h - globals for edit modes
@@ -14,15 +14,6 @@
  *
  */
 
-/* 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 */
@@ -35,7 +26,7 @@ typedef struct {
 	int eof;
 } X_chars;
 
-EXTERN X_chars edchars;
+extern X_chars edchars;
 
 /* x_cf_glob() flags */
 #define XCF_COMMAND	BIT(0)	/* Do command completion */
@@ -63,24 +54,3 @@ 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:
- */
diff --git a/emacs.c b/emacs.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: emacs.c,v 1.50 2015/03/25 12:10:52 jca Exp $	*/
+/*	$OpenBSD: emacs.c,v 1.73 2017/08/30 17:02:53 jca Exp $	*/
 
 /*
  *  Emacs-like command line editing and history
@@ -14,15 +14,15 @@
 #include "config.h"
 #ifdef EMACS
 
-#include "sh.h"
-#include <sys/stat.h>
-#ifdef __linux__
-#include "portable/linux/queue.h"
-#else
 #include <sys/queue.h>
-#endif
+#include <sys/stat.h>
+
 #include <ctype.h>
-#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sh.h"
 #include "edit.h"
 
 static	Area	aedit;
@@ -30,9 +30,6 @@ static	Area	aedit;
 
 #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
@@ -53,7 +50,8 @@ struct	x_ftab {
 #define	is_cfs(c)	(c == ' ' || c == '\t' || c == '"' || c == '\'')
 
 /* Separator for motion */
-#define	is_mfs(c)	(!(isalnum((unsigned char)c) || c == '_' || c == '$'))
+#define	is_mfs(c)	(!(isalnum((unsigned char)c) || \
+			c == '_' || c == '$' || c & 0x80))
 
 /* Arguments for do_complete()
  * 0 = enumerate  M-= complete as much as possible and then list
@@ -86,7 +84,7 @@ 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 char    *xlp;		/* last byte visible on screen */
 static int	x_adj_ok;
 /*
  * we use x_adj_done so that functions can tell
@@ -136,13 +134,14 @@ static void	x_push(int);
 static void	x_adjust(void);
 static void	x_e_ungetc(int);
 static int	x_e_getc(void);
+static int	x_e_getu8(char *, int);
 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);
+static int	isu8cont(unsigned char);
 
 /* proto's for keybindings */
 static int	x_abort(int);
@@ -186,8 +185,6 @@ static int	x_search_char_forw(int);
 static int	x_search_char_back(int);
 static int	x_search_hist(int);
 static int	x_set_mark(int);
-static int	x_stuff(int);
-static int	x_stuffreset(int);
 static int	x_transpose(int);
 static int	x_version(int);
 static int	x_xchg_point_mark(int);
@@ -245,8 +242,6 @@ static const struct x_ftab x_ftab[] = {
 	{ 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 },
@@ -267,12 +262,18 @@ static const struct x_ftab x_ftab[] = {
 	{ 0, 0, 0 },
 };
 
+int
+isu8cont(unsigned char c)
+{
+	return (c & (0x80 | 0x40)) == 0x80;
+}
+
 int
 x_emacs(char *buf, size_t len)
 {
 	struct kb_entry		*k, *kmatch = NULL;
 	char			line[LINE + 1];
-	int			at = 0, submatch, ret, c;
+	int			at = 0, ntries = 0, submatch, ret;
 	const char		*p;
 
 	xbp = xbuf = buf; xend = buf + len;
@@ -307,17 +308,14 @@ x_emacs(char *buf, size_t len)
 		x_nextcmd = -1;
 	}
 
-	line[0] = '\0';
 	x_literal_set = 0;
 	x_arg = -1;
 	x_last_command = NULL;
 	while (1) {
 		x_flush();
-		if ((c = x_e_getc()) < 0)
+		if ((at = x_e_getu8(line, at)) < 0)
 			return 0;
-
-		line[at++] = c;
-		line[at] = '\0';
+		ntries++;
 
 		if (x_arg == -1) {
 			x_arg = 1;
@@ -355,14 +353,18 @@ x_emacs(char *buf, size_t len)
 				macro_args = kmatch->args;
 				ret = KSTD;
 			} else
-				ret = kmatch->ftab->xf_func(c);
+				ret = kmatch->ftab->xf_func(line[at - 1]);
 		} else {
 			if (submatch)
 				continue;
-			if (at == 1)
-				ret = x_insert(c);
-			else
-				ret = x_error(c); /* not matched meta sequence */
+			if (ntries > 1) {
+				ret = x_error(0); /* unmatched meta sequence */
+			} else if (at > 1) {
+				x_ins(line);
+				ret = KSTD;
+			} else {
+				ret = x_insert(line[0]);
+			}
 		}
 
 		switch (ret) {
@@ -387,8 +389,7 @@ x_emacs(char *buf, size_t len)
 		}
 
 		/* reset meta sequence */
-		at = 0;
-		line[0] = '\0';
+		at = ntries = 0;
 		if (x_arg_set)
 			x_arg_set = 0; /* reset args next time around */
 		else
@@ -421,10 +422,8 @@ x_ins_string(int c)
 	return x_insert(c);
 }
 
-static int x_do_ins(const char *cp, int len);
-
 static int
-x_do_ins(const char *cp, int len)
+x_do_ins(const char *cp, size_t len)
 {
 	if (xep+len >= xend) {
 		x_e_putc(BEL);
@@ -464,19 +463,6 @@ x_ins(char *s)
 	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)
 {
@@ -488,6 +474,8 @@ x_del_back(int c)
 	}
 	if (x_arg > col)
 		x_arg = col;
+	while (x_arg < col && isu8cont(xcp[-x_arg]))
+		x_arg++;
 	x_goto(xcp - x_arg);
 	x_delete(x_arg, false);
 	return KSTD;
@@ -504,11 +492,13 @@ x_del_char(int c)
 	}
 	if (x_arg > nleft)
 		x_arg = nleft;
+	while (x_arg < nleft && isu8cont(xcp[x_arg]))
+		x_arg++;
 	x_delete(x_arg, false);
 	return KSTD;
 }
 
-/* Delete nc chars to the right of the cursor (including cursor position) */
+/* Delete nc bytes to the right of the cursor (including cursor position) */
 static void
 x_delete(int nc, int push)
 {
@@ -539,6 +529,7 @@ x_delete(int nc, int push)
 	}
 	memmove(xcp, xcp+nc, xep - xcp + 1);	/* Copies the null */
 	x_adj_ok = 0;			/* don't redraw */
+	xlp_valid = false;
 	x_zots(xcp);
 	/*
 	 * if we are already filling the line,
@@ -680,6 +671,8 @@ x_size(int c)
 		return 4;	/* Kludge, tabs are always four spaces. */
 	if (iscntrl(c))		/* control char */
 		return 2;
+	if (isu8cont(c))
+		return 0;
 	return 1;
 }
 
@@ -688,6 +681,11 @@ x_zots(char *str)
 {
 	int	adj = x_adj_done;
 
+	if (str > xbuf && isu8cont(*str)) {
+		while (str > xbuf && isu8cont(*str))
+			str--;
+		x_e_putc('\b');
+	}
 	x_lastcp();
 	while (*str && str < xlp && adj == x_adj_done)
 		x_zotc(*str++);
@@ -717,6 +715,8 @@ x_mv_back(int c)
 	}
 	if (x_arg > col)
 		x_arg = col;
+	while (x_arg < col && isu8cont(xcp[-x_arg]))
+		x_arg++;
 	x_goto(xcp - x_arg);
 	return KSTD;
 }
@@ -732,6 +732,8 @@ x_mv_forw(int c)
 	}
 	if (x_arg > nleft)
 		x_arg = nleft;
+	while (x_arg < nleft && isu8cont(xcp[x_arg]))
+		x_arg++;
 	x_goto(xcp + x_arg);
 	return KSTD;
 }
@@ -863,7 +865,7 @@ kb_find_hist_func(char c)
 	line[0] = c;
 	line[1] = '\0';
 	TAILQ_FOREACH(k, &kblist, entry)
-		if (!strcmp((const char *)k->seq, line))
+		if (!strcmp(k->seq, line))
 			return (k->ftab->xf_func);
 
 	return (x_insert);
@@ -888,9 +890,10 @@ x_search_hist(int c)
 		if ((c = x_e_getc()) < 0)
 			return KSTD;
 		f = kb_find_hist_func(c);
-		if (c == CTRL('['))
+		if (c == CTRL('[')) {
+			x_e_ungetc(c);
 			break;
-		else if (f == x_search_hist)
+		} else if (f == x_search_hist)
 			offset = x_search(pat, 0, offset);
 		else if (f == x_del_back) {
 			if (p == pat) {
@@ -1023,7 +1026,7 @@ x_redraw(int limit)
 		x_e_putc('\r');
 	x_flush();
 	if (xbp == xbuf) {
-		x_col = promptlen(prompt, (const char **) 0);
+		x_col = promptlen(prompt, NULL);
 		if (x_col > xx_cols)
 			truncate = (x_col / xx_cols) * xx_cols;
 		if (prompt_redraw)
@@ -1065,7 +1068,9 @@ x_redraw(int limit)
 	for (cp = xlp; cp > xcp; )
 		x_bs(*--cp);
 	x_adj_ok = 1;
-	D__(x_flush();)
+#ifdef DEBUG
+	x_flush();
+#endif
 	return;
 }
 
@@ -1139,6 +1144,8 @@ x_kill(int c)
 		x_arg = lastcol;
 	else if (x_arg > lastcol)
 		x_arg = lastcol;
+	while (x_arg < lastcol && isu8cont(xbuf[x_arg]))
+		x_arg++;
 	ndel = x_arg - col;
 	if (ndel < 0) {
 		x_goto(xbuf + x_arg);
@@ -1152,8 +1159,7 @@ static void
 x_push(int nchars)
 {
 	char	*cp = str_nsave(xcp, nchars, AEDIT);
-	if (killstack[killsp])
-		afree((void *)killstack[killsp], AEDIT);
+	afree(killstack[killsp], AEDIT);
 	killstack[killsp] = cp;
 	killsp = (killsp + 1) % KILLSIZE;
 }
@@ -1217,36 +1223,6 @@ x_error(int c)
 	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 *
 kb_encode(const char *s)
 {
@@ -1279,7 +1255,7 @@ kb_decode(const char *s)
 
 	l[0] = '\0';
 	for (i = 0; i < strlen(s); i++) {
-		if (iscntrl(s[i])) {
+		if (iscntrl((unsigned char)s[i])) {
 			l[at++] = '^';
 			l[at++] = UNCTRL(s[i]);
 		} else
@@ -1311,8 +1287,7 @@ static void
 kb_del(struct kb_entry *k)
 {
 	TAILQ_REMOVE(&kblist, k, entry);
-	if (k->args)
-		free(k->args);
+	free(k->args);
 	afree(k, AEDIT);
 }
 
@@ -1344,7 +1319,7 @@ kb_add_string(void *func, void *args, char *str)
 	k->ftab = xf;
 	k->args = args ? strdup(args) : NULL;
 
-	strlcpy((char *)k->seq, str, count + 1);
+	strlcpy(k->seq, str, count + 1);
 
 	TAILQ_INSERT_TAIL(&kblist, k, entry);
 
@@ -1377,9 +1352,9 @@ kb_print(struct kb_entry *k)
 {
 	if (!(k->ftab->xf_flags & XF_NOBIND))
 		shprintf("%s = %s\n",
-		  kb_decode((const char *)k->seq), k->ftab->xf_name);
+		    kb_decode(k->seq), k->ftab->xf_name);
 	else if (k->args) {
-	     shprintf("%s = ", kb_decode((const char *)k->seq));
+		shprintf("%s = ", kb_decode(k->seq));
 		shprintf("'%s'\n", kb_decode(k->args));
 	}
 }
@@ -1421,7 +1396,7 @@ x_bind(const char *a1, const char *a2,
 	if (a2 == NULL) {
 		/* print binding */
 		TAILQ_FOREACH(k, &kblist, entry)
-			if (!strcmp((const char *)k->seq, in)) {
+			if (!strcmp(k->seq, in)) {
 				kb_print(k);
 				return (0);
 			}
@@ -1432,7 +1407,7 @@ x_bind(const char *a1, const char *a2,
 	if (strlen(a2) == 0) {
 		/* clear binding */
 		TAILQ_FOREACH_SAFE(k, &kblist, entry, kb)
-			if (!strcmp((const char *)k->seq, in)) {
+			if (!strcmp(k->seq, in)) {
 				kb_del(k);
 				break;
 			}
@@ -1443,7 +1418,7 @@ x_bind(const char *a1, const char *a2,
 	if (macro) {
 		/* delete old mapping */
 		TAILQ_FOREACH_SAFE(k, &kblist, entry, kb)
-			if (!strcmp((const char *)k->seq, in)) {
+			if (!strcmp(k->seq, in)) {
 				kb_del(k);
 				break;
 			}
@@ -1458,7 +1433,7 @@ x_bind(const char *a1, const char *a2,
 		if (!strcmp(x_ftab[i].xf_name, a2)) {
 			/* delete old mapping */
 			TAILQ_FOREACH_SAFE(k, &kblist, entry, kb)
-				if (!strcmp((const char *)k->seq, in)) {
+				if (!strcmp(k->seq, in)) {
 					kb_del(k);
 					break;
 				}
@@ -1473,21 +1448,10 @@ x_bind(const char *a1, const char *a2,
 void
 x_init_emacs(void)
 {
-	char *locale;
-
 	x_tty = 1;
 	ainit(AEDIT);
 	x_nextcmd = -1;
 
-	/* 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;
-
-	/* new keybinding stuff */
 	TAILQ_INIT(&kblist);
 
 	/* man page order */
@@ -1546,12 +1510,7 @@ x_init_emacs(void)
 	kb_add(x_search_char_forw,	NULL, CTRL(']'), 0);
 	kb_add(x_search_hist,		NULL, CTRL('R'), 0);
 	kb_add(x_set_mark,		NULL, CTRL('['), ' ', 0);
-#if defined(TIOCSTI)
-	kb_add(x_stuff,			NULL, CTRL('T'), 0);
-	/* stuff-reset */
-#else
 	kb_add(x_transpose,		NULL, CTRL('T'), 0);
-#endif
 	kb_add(x_prev_com,		NULL, CTRL('P'), 0);
 	kb_add(x_prev_com,		NULL, CTRL('X'), 'A', 0);
 	kb_add(x_fold_upper,		NULL, CTRL('['), 'U', 0);
@@ -1577,6 +1536,8 @@ x_init_emacs(void)
 	kb_add(x_mv_end,		NULL, CTRL('['), '[', 'F', 0); /* end */
 	kb_add(x_mv_begin,		NULL, CTRL('['), 'O', 'H', 0); /* home */
 	kb_add(x_mv_end,		NULL, CTRL('['), 'O', 'F', 0); /* end */
+	kb_add(x_mv_begin,		NULL, CTRL('['), '[', '1', '~', 0); /* home */
+	kb_add(x_mv_end,		NULL, CTRL('['), '[', '4', '~', 0); /* end */
 
 	/* can't be bound */
 	kb_add(x_set_arg,		NULL, CTRL('['), '0', 0);
@@ -1762,8 +1723,8 @@ x_expand(int c)
 	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)) {
+		if (x_escape(words[i], strlen(words[i]), x_do_ins) < 0 ||
+		    (++i < nwords && x_ins(" ") < 0)) {
 			x_e_putc(BEL);
 			return KSTD;
 		}
@@ -1805,13 +1766,13 @@ do_complete(int flags,	/* XCF_{COMMAND,FILE,COMMAND_FILE} */
 	if (nwords == 1 || nlen > olen) {
 		x_goto(xbuf + start);
 		x_delete(olen, false);
-		x_escape(words[0], nlen, x_emacs_putbuf);
+		x_escape(words[0], nlen, x_do_ins);
 		x_adjust();
 		completed = 1;
 	}
 	/* add space if single non-dir match */
 	if (nwords == 1 && words[0][nlen - 1] != '/') {
-		x_ins(space);
+		x_ins(" ");
 		completed = 1;
 	}
 
@@ -1882,6 +1843,43 @@ x_e_getc(void)
 	return c;
 }
 
+static int
+x_e_getu8(char *buf, int off)
+{
+	int	c, cc, len;
+
+	c = x_e_getc();
+	if (c == -1)
+		return -1;
+	buf[off++] = c;
+
+	if (c == 0xf4)
+		len = 4;
+	else if ((c & 0xf0) == 0xe0)
+		len = 3;
+	else if ((c & 0xe0) == 0xc0 && c > 0xc1)
+		len = 2;
+	else
+		len = 1;
+
+	for (; len > 1; len--) {
+		cc = x_e_getc();
+		if (cc == -1)
+			break;
+		if (isu8cont(cc) == 0 ||
+		    (c == 0xe0 && len == 3 && cc < 0xa0) ||
+		    (c == 0xed && len == 3 && cc & 0x20) ||
+		    (c == 0xf4 && len == 4 && cc & 0x30)) {
+			x_e_ungetc(cc);
+			break;
+		}
+		buf[off++] = cc;
+	}
+	buf[off] = '\0';
+
+	return off;
+}
+
 static void
 x_e_putc(int c)
 {
@@ -1899,7 +1897,8 @@ x_e_putc(int c)
 			x_col--;
 			break;
 		default:
-			x_col++;
+			if (!isu8cont(c))
+				x_col++;
 			break;
 		}
 	}
@@ -1919,7 +1918,7 @@ x_debug_info(int c)
 	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);
+	shellf("\n");
 	x_redraw(-1);
 	return 0;
 }
@@ -2130,13 +2129,13 @@ x_fold_case(int c)
 }
 
 /* NAME:
- *      x_lastcp - last visible char
+ *      x_lastcp - last visible byte
  *
  * SYNOPSIS:
  *      x_lastcp()
  *
  * DESCRIPTION:
- *      This function returns a pointer to that  char in the
+ *      This function returns a pointer to that byte in the
  *      edit buffer that will be the last displayed on the
  *      screen.  The sequence:
  *
diff --git a/eval.c b/eval.c
@@ -1,14 +1,21 @@
-/*	$OpenBSD: eval.c,v 1.40 2013/09/14 20:09:30 millert Exp $	*/
+/*	$OpenBSD: eval.c,v 1.54 2017/08/27 00:29:04 nayden Exp $	*/
 
 /*
  * Expansion - quoting, separation, substitution, globbing
  */
 
-#include "sh.h"
-#include <pwd.h>
-#include <dirent.h>
 #include <sys/stat.h>
 
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sh.h"
+
 /*
  * string expansion
  *
@@ -187,7 +194,7 @@ expand(char *cp,	/* input word */
 	doblank = 0;
 	make_magic = 0;
 	word = (f&DOBLANK) ? IFS_WS : IFS_WORD;
-	st_head.next = (SubType *) 0;
+	st_head.next = NULL;
 	st = &st_head;
 
 	while (1) {
@@ -292,9 +299,9 @@ expand(char *cp,	/* input word */
 					if (!st->next) {
 						SubType *newst;
 
-						newst = (SubType *) alloc(
+						newst = alloc(
 						    sizeof(SubType), ATEMP);
-						newst->next = (SubType *) 0;
+						newst->next = NULL;
 						newst->prev = st;
 						st->next = newst;
 					}
@@ -319,7 +326,7 @@ expand(char *cp,	/* input word */
 						 * expected)
 						 */
 						*dp++ = MAGIC;
-						*dp++ = '@' + 0x80;
+						*dp++ = '@' + 0x80U;
 						break;
 					case '=':
 						/* Enabling tilde expansion
@@ -406,7 +413,7 @@ expand(char *cp,	/* input word */
 					 */
 					len = strlen(dp) + 1;
 					setstr(st->var,
-					    debunk((char *) alloc(len, ATEMP),
+					    debunk(alloc(len, ATEMP),
 					    dp, len), KSH_UNWIND_ERROR);
 					x.str = str_val(st->var);
 					type = XSUB;
@@ -600,7 +607,7 @@ expand(char *cp,	/* input word */
 			if (!quote)
 				switch (c) {
 				case '[':
-				case NOT:
+				case '!':
 				case '-':
 				case ']':
 					/* For character classes - doesn't hurt
@@ -700,16 +707,15 @@ varsub(Expand *xp, char *sp, char *word,
 	int slen;
 	char *p;
 	struct tbl *vp;
+	int zero_ok = 0;
 
 	if (sp[0] == '\0')	/* Bad variable name */
 		return -1;
 
-	xp->var = (struct tbl *) 0;
+	xp->var = NULL;
 
 	/* ${#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;
@@ -726,7 +732,7 @@ varsub(Expand *xp, char *sp, char *word,
 					n++;
 			c = n; /* ksh88/ksh93 go for number, not max index */
 		} else if (c == '*' || c == '@')
-			c = e->loc->argc;
+			c = genv->loc->argc;
 		else {
 			p = str_val(global(sp));
 			zero_ok = p != null;
@@ -772,16 +778,17 @@ varsub(Expand *xp, char *sp, char *word,
 		case '#':
 			return -1;
 		}
-		if (e->loc->argc == 0) {
+		if (genv->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->u.strv = (const char **) genv->loc->argv + 1;
 			xp->str = *xp->u.strv++;
 			xp->split = c == '@'; /* $@ */
 			state = XARG;
 		}
+		zero_ok = 1;	/* exempt "$@" and "$*" from 'set -u' */
 	} else {
 		if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') {
 			XPtrV wv;
@@ -828,7 +835,7 @@ varsub(Expand *xp, char *sp, char *word,
 	    (((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 &&
+	if (Flag(FNOUNSET) && xp->str == null && !zero_ok &&
 	    (ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
 		errorf("%s: parameter not set", sp);
 	return state;
@@ -861,7 +868,7 @@ comsub(Expand *xp, char *cp)
 
 		if ((io->flag&IOTYPE) != IOREAD)
 			errorf("funny $() command: %s",
-			    snptreef((char *) 0, 32, "%R", io));
+			    snptreef(NULL, 32, "%R", io));
 		shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0,
 			SHF_MAPHI|SHF_CLEXEC);
 		if (shf == NULL)
@@ -871,7 +878,7 @@ comsub(Expand *xp, char *cp)
 	} else {
 		int ofd1, pv[2];
 		openpipe(pv);
-		shf = shf_fdopen(pv[0], SHF_RD, (struct shf *) 0);
+		shf = shf_fdopen(pv[0], SHF_RD, NULL);
 		ofd1 = savefd(1);
 		if (pv[1] != 1) {
 			ksh_dup2(pv[1], 1, false);
@@ -1069,7 +1076,6 @@ globit(XString *xs,	/* dest string */
 		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) : ".");
@@ -1101,47 +1107,6 @@ globit(XString *xs,	/* dest string */
 		*--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)
@@ -1190,7 +1155,7 @@ maybe_expand_tilde(char *p, XString *dsp, char **dpp, int isassign)
 	}
 	*tp = '\0';
 	r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ?
-	    tilde(Xstring(ts, tp)) : (char *) 0;
+	    tilde(Xstring(ts, tp)) : NULL;
 	Xfree(ts, tp);
 	if (r) {
 		while (*r) {
@@ -1226,7 +1191,7 @@ tilde(char *cp)
 		dp = homedir(cp);
 	/* If HOME, PWD or OLDPWD are not set, don't expand ~ */
 	if (dp == null)
-		dp = (char *) 0;
+		dp = NULL;
 	return dp;
 }
 
@@ -1271,7 +1236,7 @@ alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
 
 	/* find matching close brace, if any */
 	if (p) {
-		comma = (char *) 0;
+		comma = NULL;
 		count = 1;
 		for (p += 2; *p && count; p++) {
 			if (ISMAGIC(*p)) {
@@ -1317,7 +1282,7 @@ alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
 				l1 = brace_start - start;
 				l2 = (p - 1) - field_start;
 				l3 = end - brace_end;
-				new = (char *) alloc(l1 + l2 + l3 + 1, ATEMP);
+				new = alloc(l1 + l2 + l3 + 1, ATEMP);
 				memcpy(new, start, l1);
 				memcpy(new + l1, field_start, l2);
 				memcpy(new + l1 + l2, brace_end, l3);
diff --git a/exec.c b/exec.c
@@ -1,13 +1,22 @@
-/*	$OpenBSD: exec.c,v 1.51 2015/04/18 18:28:36 deraadt Exp $	*/
+/*	$OpenBSD: exec.c,v 1.68 2016/12/11 17:49:19 millert Exp $	*/
 
 /*
  * execute command tree
  */
 
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
 #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)
@@ -31,9 +40,12 @@ static void	dbteste_error(Test_env *, int, const char *);
  */
 int
 execute(struct op *volatile t,
-    volatile int flags, volatile int *xerrok)		/* if XEXEC don't fork */
+    volatile int flags,		/* if XEXEC don't fork */
+    volatile int *xerrok)	/* inform recursive callers in -e mode that
+				 * short-circuit && or || shouldn't be treated
+				 * as an error */
 {
-	int i, dummy = 0;
+	int i, dummy = 0, save_xerrok = 0;
 	volatile int rv = 0;
 	int pv[2];
 	char ** volatile ap;
@@ -83,7 +95,7 @@ execute(struct op *volatile t,
 				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);
+				    ap[i + 1] ? " " : "\n");
 			shf_flush(shl_out);
 		}
 		if (ap[0])
@@ -92,9 +104,9 @@ execute(struct op *volatile t,
 	flags &= ~XTIME;
 
 	if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {
-		e->savefd = (short *) alloc(sizeofN(short, NUFILE), ATEMP);
+		genv->savefd = areallocarray(NULL, NUFILE, sizeof(short), ATEMP);
 		/* initialize to not redirected */
-		memset(e->savefd, 0, sizeofN(short, NUFILE));
+		memset(genv->savefd, 0, NUFILE * sizeof(short));
 	}
 
 	/* do redirection, to be restored in quitenv() */
@@ -107,7 +119,7 @@ execute(struct op *volatile t,
 				 */
 				if (tp && tp->type == CSHELL &&
 				    (tp->flag & SPEC_BI))
-					errorf("%s", null);
+					errorf(NULL);
 				/* Deal with FERREXIT, quitenv(), etc. */
 				goto Break;
 			}
@@ -125,8 +137,8 @@ execute(struct op *volatile t,
 	case TPIPE:
 		flags |= XFORK;
 		flags &= ~XEXEC;
-		e->savefd[0] = savefd(0);
-		e->savefd[1] = savefd(1);
+		genv->savefd[0] = savefd(0);
+		genv->savefd[1] = savefd(1);
 		while (t->type == TPIPE) {
 			openpipe(pv);
 			(void) ksh_dup2(pv[1], 1, false); /* stdout of curr */
@@ -141,8 +153,8 @@ execute(struct op *volatile t,
 			flags |= XPIPEI;
 			t = t->right;
 		}
-		restfd(1, e->savefd[1]); /* stdout of last */
-		e->savefd[1] = 0; /* no need to re-restore this */
+		restfd(1, genv->savefd[1]); /* stdout of last */
+		genv->savefd[1] = 0; /* no need to re-restore this */
 		/* Let exchild() close 0 in parent, after fork, before wait */
 		i = exchild(t, flags|XPCLOSE, xerrok, 0);
 		if (!(flags&XBGND) && !(flags&XXCOM))
@@ -165,10 +177,10 @@ execute(struct op *volatile t,
 		 * signal handler
 		 */
 		sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
-		e->type = E_ERRH;
-		i = sigsetjmp(e->jbuf, 0);
+		genv->type = E_ERRH;
+		i = sigsetjmp(genv->jbuf, 0);
 		if (i) {
-			sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+			sigprocmask(SIG_SETMASK, &omask, NULL);
 			quitenv(NULL);
 			unwind(i);
 			/* NOTREACHED */
@@ -181,8 +193,8 @@ execute(struct op *volatile t,
 		coproc_cleanup(true);
 
 		/* do this before opening pipes, in case these fail */
-		e->savefd[0] = savefd(0);
-		e->savefd[1] = savefd(1);
+		genv->savefd[0] = savefd(0);
+		genv->savefd[1] = savefd(1);
 
 		openpipe(pv);
 		if (pv[0] != 0) {
@@ -190,7 +202,7 @@ execute(struct op *volatile t,
 			close(pv[0]);
 		}
 		coproc.write = pv[1];
-		coproc.job = (void *) 0;
+		coproc.job = NULL;
 
 		if (coproc.readw >= 0)
 			ksh_dup2(coproc.readw, 1, false);
@@ -203,8 +215,8 @@ execute(struct op *volatile t,
 			/* create new coprocess id */
 			++coproc.id;
 		}
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
-		e->type = E_EXEC; /* no more need for error handler */
+		sigprocmask(SIG_SETMASK, &omask, NULL);
+		genv->type = E_EXEC; /* no more need for error handler */
 
 		/* exchild() closes coproc.* in child after fork,
 		 * will also increment coproc.njobs when the
@@ -231,16 +243,14 @@ execute(struct op *volatile t,
 			rv = execute(t->right, flags & XERROK, xerrok);
 		else {
 			flags |= XERROK;
-			if (xerrok)
-				*xerrok = 1;
+			*xerrok = 1;
 		}
 		break;
 
 	case TBANG:
 		rv = !execute(t->right, XERROK, xerrok);
 		flags |= XERROK;
-		if (xerrok)
-			*xerrok = 1;
+		*xerrok = 1;
 		break;
 
 	case TDBRACKET:
@@ -263,13 +273,13 @@ execute(struct op *volatile t,
 	    {
 		volatile bool is_first = true;
 		ap = (t->vars != NULL) ? eval(t->vars, DOBLANK|DOGLOB|DOTILDE) :
-		    e->loc->argv + 1;
-		e->type = E_LOOP;
+		    genv->loc->argv + 1;
+		genv->type = E_LOOP;
 		while (1) {
-			i = sigsetjmp(e->jbuf, 0);
+			i = sigsetjmp(genv->jbuf, 0);
 			if (!i)
 				break;
-			if ((e->flags&EF_BRKCONT_PASS) ||
+			if ((genv->flags&EF_BRKCONT_PASS) ||
 			    (i != LBREAK && i != LCONTIN)) {
 				quitenv(NULL);
 				unwind(i);
@@ -280,10 +290,15 @@ execute(struct op *volatile t,
 		}
 		rv = 0; /* in case of a continue */
 		if (t->type == TFOR) {
+			save_xerrok = *xerrok;
 			while (*ap != NULL) {
 				setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
+				/* undo xerrok in all iterations except the
+				 * last */
+				*xerrok = save_xerrok;
 				rv = execute(t->left, flags & XERROK, xerrok);
 			}
+			/* ripple xerrok set at final iteration */
 		} else { /* TSELECT */
 			for (;;) {
 				if (!(cp = do_selectargs(ap, is_first))) {
@@ -300,12 +315,12 @@ execute(struct op *volatile t,
 
 	case TWHILE:
 	case TUNTIL:
-		e->type = E_LOOP;
+		genv->type = E_LOOP;
 		while (1) {
-			i = sigsetjmp(e->jbuf, 0);
+			i = sigsetjmp(genv->jbuf, 0);
 			if (!i)
 				break;
-			if ((e->flags&EF_BRKCONT_PASS) ||
+			if ((genv->flags&EF_BRKCONT_PASS) ||
 			    (i != LBREAK && i != LCONTIN)) {
 				quitenv(NULL);
 				unwind(i);
@@ -330,11 +345,13 @@ execute(struct op *volatile t,
 
 	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;
+		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, xerrok);
@@ -372,8 +389,7 @@ execute(struct op *volatile t,
 	quitenv(NULL);		/* restores IO */
 	if ((flags&XEXEC))
 		unwind(LEXIT);	/* exit child */
-	if (rv != 0 && !(flags & XERROK) &&
-	    (xerrok == NULL || !*xerrok)) {
+	if (rv != 0 && !(flags & XERROK) && !*xerrok) {
 		trapsig(SIGERR_);
 		if (Flag(FERREXIT))
 			unwind(LERROR);
@@ -499,7 +515,7 @@ comexec(struct op *t, struct tbl *volatile tp, char **ap, volatile int flags,
 				shf_fprintf(shl_out, "%s",
 				    PS4_SUBSTITUTE(str_val(global("PS4"))));
 			shf_fprintf(shl_out, "%s%s", cp,
-			    t->vars[i + 1] ? space : newline);
+			    t->vars[i + 1] ? " " : "\n");
 			if (!t->vars[i + 1])
 				shf_flush(shl_out);
 		}
@@ -527,8 +543,7 @@ comexec(struct op *t, struct tbl *volatile tp, char **ap, volatile int flags,
 
 	case CFUNC:			/* function call */
 	    {
-		volatile int old_xflag;
-		volatile Tflag old_inuse;
+		volatile int old_xflag, old_inuse;
 		const char *volatile old_kshname;
 
 		if (!(tp->flag & ISSET)) {
@@ -549,7 +564,7 @@ comexec(struct op *t, struct tbl *volatile tp, char **ap, volatile int flags,
 				}
 				break;
 			}
-			if (include(tp->u.fpath, 0, (char **) 0, 0) < 0) {
+			if (include(tp->u.fpath, 0, NULL, 0) < 0) {
 				warningf(true,
 				    "%s: can't open function definition file %s - %s",
 				    cp, tp->u.fpath, strerror(errno));
@@ -575,16 +590,16 @@ comexec(struct op *t, struct tbl *volatile tp, char **ap, volatile int flags,
 			kshname = ap[0];
 		else
 			ap[0] = (char *) kshname;
-		e->loc->argv = ap;
+		genv->loc->argv = ap;
 		for (i = 0; *ap++ != NULL; i++)
 			;
-		e->loc->argc = i - 1;
+		genv->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;
+			genv->loc->flags |= BF_DOGETOPTS;
+			genv->loc->getopts_state = user_opt;
 			getopts_reset(1);
 		}
 
@@ -594,8 +609,8 @@ comexec(struct op *t, struct tbl *volatile tp, char **ap, volatile int flags,
 		old_inuse = tp->flag & FINUSE;
 		tp->flag |= FINUSE;
 
-		e->type = E_FUNC;
-		i = sigsetjmp(e->jbuf, 0);
+		genv->type = E_FUNC;
+		i = sigsetjmp(genv->jbuf, 0);
 		if (i == 0) {
 			/* seems odd to pass XERROK here, but at&t ksh does */
 			exstat = execute(tp->val.t, flags & XERROK, xerrok);
@@ -689,11 +704,11 @@ scriptexec(struct op *tp, char **ap)
 {
 	char *shell;
 
-	shell = str_val(global(EXECSHELL_STR));
+	shell = str_val(global("EXECSHELL"));
 	if (shell && *shell)
-		shell = search(shell, path, X_OK, (int *) 0);
+		shell = search(shell, path, X_OK, NULL);
 	if (!shell || !*shell)
-		shell = EXECSHELL;
+		shell = _PATH_BSHELL;
 
 	*tp->args-- = tp->str;
 	*tp->args = shell;
@@ -723,9 +738,9 @@ struct tbl *
 findfunc(const char *name, unsigned int h, int create)
 {
 	struct block *l;
-	struct tbl *tp = (struct tbl *) 0;
+	struct tbl *tp = NULL;
 
-	for (l = e->loc; l; l = l->next) {
+	for (l = genv->loc; l; l = l->next) {
 		tp = ktsearch(&l->funs, name, h);
 		if (tp)
 			break;
@@ -733,7 +748,7 @@ findfunc(const char *name, unsigned int h, int create)
 			tp = ktenter(&l->funs, name, h);
 			tp->flag = DEFINED;
 			tp->type = CFUNC;
-			tp->val.t = (struct op *) 0;
+			tp->val.t = NULL;
 			break;
 		}
 	}
@@ -791,7 +806,7 @@ void
 builtin(const char *name, int (*func) (char **))
 {
 	struct tbl *tp;
-	Tflag flag;
+	int flag;
 
 	/* see if any flags should be set for this builtin */
 	for (flag = 0; ; name++) {
@@ -841,7 +856,7 @@ findcom(const char *name, int flags)
 		tp = findfunc(name, h, false);
 		if (tp && !(tp->flag & ISSET)) {
 			if ((fpath = str_val(global("FPATH"))) == null) {
-				tp->u.fpath = (char *) 0;
+				tp->u.fpath = NULL;
 				tp->u2.errno_ = 0;
 			} else
 				tp->u.fpath = search(name, fpath, R_OK,
@@ -898,7 +913,7 @@ findcom(const char *name, int flags)
 		} else if ((flags & FC_FUNC) &&
 		    (fpath = str_val(global("FPATH"))) != null &&
 		    (npath = search(name, fpath, R_OK,
-		    &tp->u2.errno_)) != (char *) 0) {
+		    &tp->u2.errno_)) != NULL) {
 			/* 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
@@ -1017,7 +1032,7 @@ call_builtin(struct tbl *tp, char **wp)
 	shf_flush(shl_stdout);
 	shl_stdout_ok = 0;
 	builtin_flag = 0;
-	builtin_argv0 = (char *) 0;
+	builtin_argv0 = NULL;
 	return rv;
 }
 
@@ -1039,13 +1054,13 @@ iosetup(struct ioword *iop, struct tbl *tp)
 
 	/* Used for tracing and error messages to print expanded cp */
 	iotmp = *iop;
-	iotmp.name = (iotype == IOHERE) ? (char *) 0 : cp;
+	iotmp.name = (iotype == IOHERE) ? NULL : cp;
 	iotmp.flag |= IONAMEXP;
 
 	if (Flag(FXTRACE))
 		shellf("%s%s\n",
 		    PS4_SUBSTITUTE(str_val(global("PS4"))),
-		    snptreef((char *) 0, 32, "%R", &iotmp));
+		    snptreef(NULL, 32, "%R", &iotmp));
 
 	switch (iotype) {
 	case IOREAD:
@@ -1089,7 +1104,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
 		    X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
 		    &emsg)) < 0) {
 			warningf(true, "%s: %s",
-			    snptreef((char *) 0, 32, "%R", &iotmp), emsg);
+			    snptreef(NULL, 32, "%R", &iotmp), emsg);
 			return -1;
 		}
 		if (u == iop->unit)
@@ -1115,10 +1130,10 @@ iosetup(struct ioword *iop, struct tbl *tp)
 		return -1;
 	}
 	/* Do not save if it has already been redirected (i.e. "cat >x >y"). */
-	if (e->savefd[iop->unit] == 0) {
+	if (genv->savefd[iop->unit] == 0) {
 		/* If these are the same, it means unit was previously closed */
 		if (u == iop->unit)
-			e->savefd[iop->unit] = -1;
+			genv->savefd[iop->unit] = -1;
 		else
 			/* c_exec() assumes e->savefd[fd] set for any
 			 * redirections.  Ask savefd() not to close iop->unit;
@@ -1126,7 +1141,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
 			 * 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);
+			genv->savefd[iop->unit] = savefd(iop->unit);
 	}
 
 	if (do_close)
@@ -1135,7 +1150,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
 		if (ksh_dup2(u, iop->unit, true) < 0) {
 			warningf(true,
 			    "could not finish (dup) redirection %s: %s",
-			    snptreef((char *) 0, 32, "%R", &iotmp),
+			    snptreef(NULL, 32, "%R", &iotmp),
 			    strerror(errno));
 			if (iotype != IODUP)
 				close(u);
@@ -1172,7 +1187,7 @@ herein(const char *content, int sub)
 	int i;
 
 	/* ksh -c 'cat << EOF' can cause this... */
-	if (content == (char *) 0) {
+	if (content == NULL) {
 		warningf(true, "here document missing");
 		return -2; /* special to iosetup(): don't print error */
 	}
@@ -1180,7 +1195,7 @@ herein(const char *content, int sub)
 	/* 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);
+	h = maketemp(ATEMP, TT_HEREDOC_EXP, &genv->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",
@@ -1192,7 +1207,7 @@ herein(const char *content, int sub)
 
 	osource = source;
 	newenv(E_ERRH);
-	i = sigsetjmp(e->jbuf, 0);
+	i = sigsetjmp(genv->jbuf, 0);
 	if (i) {
 		source = osource;
 		quitenv(shf);
@@ -1232,7 +1247,7 @@ static char *
 do_selectargs(char **ap, bool print_menu)
 {
 	static const char *const read_args[] = {
-		"read", "-r", "REPLY", (char *) 0
+		"read", "-r", "REPLY", NULL
 	};
 	const char *errstr;
 	char *s;
@@ -1250,7 +1265,7 @@ do_selectargs(char **ap, bool print_menu)
 			pr_menu(ap);
 		shellf("%s", str_val(global("PS3")));
 		if (call_builtin(findcom("read", FC_BI), (char **) read_args))
-			return (char *) 0;
+			return NULL;
 		s = str_val(global("REPLY"));
 		if (*s) {
 			i = strtonum(s, 1, argct, &errstr);
@@ -1406,7 +1421,7 @@ dbteste_getopnd(Test_env *te, Test_op op, int do_eval)
 	char *s = *te->pos.wp;
 
 	if (!s)
-		return (char *) 0;
+		return NULL;
 
 	te->pos.wp++;
 
diff --git a/expand.h b/expand.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: expand.h,v 1.6 2005/03/30 17:16:37 deraadt Exp $	*/
+/*	$OpenBSD: expand.h,v 1.12 2015/11/08 17:52:43 mmcc Exp $	*/
 
 /*
  * Expanding strings
@@ -55,11 +55,10 @@ typedef char * XStringP;
 #define Xcheck(xs, xp)	XcheckN(xs, xp, 1)
 
 /* free string */
-#define	Xfree(xs, xp)	afree((void*) (xs).beg, (xs).areap)
+#define	Xfree(xs, xp)	afree((xs).beg, (xs).areap)
 
 /* close, return string */
-#define	Xclose(xs, xp)	(char*) aresize((void*)(xs).beg, \
-					(size_t)((xp) - (xs).beg), (xs).areap)
+#define	Xclose(xs, xp)	aresize((xs).beg, ((xp) - (xs).beg), (xs).areap)
 /* begin of string */
 #define	Xstring(xs, xp)	((xs).beg)
 
@@ -82,7 +81,7 @@ typedef struct XPtrV {
 
 #define	XPinit(x, n) do { \
 			void **vp__; \
-			vp__ = (void**) alloc(sizeofN(void*, n), ATEMP); \
+			vp__ = areallocarray(NULL, n, sizeof(void *), ATEMP); \
 			(x).cur = (x).beg = vp__; \
 			(x).end = vp__ + n; \
 		} while (0)
@@ -90,8 +89,8 @@ typedef struct XPtrV {
 #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).beg = areallocarray((x).beg, n, \
+						   2 * sizeof(void *), ATEMP); \
 				(x).cur = (x).beg + n; \
 				(x).end = (x).cur + n; \
 			} \
@@ -101,7 +100,7 @@ typedef struct XPtrV {
 #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	XPclose(x)	areallocarray((x).beg, XPsize(x), \
+					 sizeof(void *), ATEMP)
 
-#define	XPfree(x)	afree((void*) (x).beg, ATEMP)
+#define	XPfree(x)	afree((x).beg, ATEMP)
diff --git a/expr.c b/expr.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: expr.c,v 1.24 2014/12/08 14:26:31 otto Exp $	*/
+/*	$OpenBSD: expr.c,v 1.32 2015/12/30 09:07:00 tedu Exp $	*/
 
 /*
  * Korn expression evaluation
@@ -7,9 +7,11 @@
  * todo: better error handling: if in builtin, should be builtin error, etc.
  */
 
-#include "sh.h"
 #include <ctype.h>
+#include <limits.h>
+#include <string.h>
 
+#include "sh.h"
 
 /* The order of these enums is constrained by the order of opinfo[] */
 enum token {
@@ -174,11 +176,11 @@ v_evaluate(struct tbl *vp, const char *expr, volatile int error_ok,
 	curstate.expression = curstate.tokp = expr;
 	curstate.noassign = 0;
 	curstate.arith = arith;
-	curstate.evaling = (struct tbl *) 0;
-	curstate.val = (struct tbl *) 0;
+	curstate.evaling = NULL;
+	curstate.val = NULL;
 
 	newenv(E_ERRH);
-	i = sigsetjmp(e->jbuf, 0);
+	i = sigsetjmp(genv->jbuf, 0);
 	if (i) {
 		/* Clear EXPRINEVAL in of any variables we were playing with */
 		if (curstate.evaling)
@@ -187,7 +189,7 @@ v_evaluate(struct tbl *vp, const char *expr, volatile int error_ok,
 		if (i == LAEXPR) {
 			if (error_ok == KSH_RETURN_ERROR)
 				return 0;
-			errorf("%s", null);
+			errorf(NULL);
 		}
 		unwind(i);
 		/* NOTREACHED */
@@ -203,7 +205,7 @@ v_evaluate(struct tbl *vp, const char *expr, volatile int error_ok,
 	v = intvar(es, evalexpr(es, MAX_PREC));
 
 	if (es->tok != END)
-		evalerr(es, ET_UNEXPECTED, (char *) 0);
+		evalerr(es, ET_UNEXPECTED, NULL);
 
 	if (vp->flag & INTEGER)
 		setint_v(vp, v, es->arith);
@@ -307,7 +309,7 @@ evalexpr(Expr_state *es, enum prec prec)
 			vl = es->val;
 			token(es);
 		} else {
-			evalerr(es, ET_UNEXPECTED, (char *) 0);
+			evalerr(es, ET_UNEXPECTED, NULL);
 			/* NOTREACHED */
 		}
 		if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) {
@@ -560,7 +562,7 @@ tempvar(void)
 {
 	struct tbl *vp;
 
-	vp = (struct tbl*) alloc(sizeof(struct tbl), ATEMP);
+	vp = alloc(sizeof(struct tbl), ATEMP);
 	vp->flag = ISSET|INTEGER;
 	vp->type = 0;
 	vp->areap = ATEMP;
@@ -588,7 +590,7 @@ intvar(Expr_state *es, struct tbl *vp)
 		vp->flag |= EXPRINEVAL;
 		v_evaluate(vq, str_val(vp), KSH_UNWIND_ERROR, es->arith);
 		vp->flag &= ~EXPRINEVAL;
-		es->evaling = (struct tbl *) 0;
+		es->evaling = NULL;
 	}
 	return vq;
 }
diff --git a/history.c b/history.c
@@ -1,9 +1,7 @@
-/*	$OpenBSD: history.c,v 1.40 2014/11/20 15:22:39 tedu Exp $	*/
+/*	$OpenBSD: history.c,v 1.71 2017/09/07 19:08:32 jca Exp $	*/
 
 /*
  * command history
- *
- * only implements in-memory history.
  */
 
 /*
@@ -11,29 +9,32 @@
  *	a)	the original in-memory history  mechanism
  *	b)	a more complicated mechanism done by  pc@hillside.co.uk
  *		that more closely follows the real ksh way of doing
- *		things. You need to have the mmap system call for this
- *		to work on your system
+ *		things.
  */
 
-#include "sh.h"
 #include <sys/stat.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#if defined(__linux__) || defined(__CYGWIN__)
+#include "portable/linux/vis.h"
+#else
+#include <vis.h>
+#endif
 
-#ifdef HISTORY
-# include <sys/mman.h>
+#include "sh.h"
 
-/*
- *	variables for handling the data file
- */
-static int	histfd;
-static int	hsize;
+#ifdef HISTORY
 
-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 void	history_write(void);
+static FILE	*history_open(void);
+static int	history_load(Source *);
+static void	history_close(void);
 
 static int	hist_execute(char *);
 static int	hist_replace(char **, const char *, const char *, int);
@@ -41,22 +42,34 @@ static char   **hist_get(const char *, int, int);
 static char   **hist_get_oldest(void);
 static void	histbackup(void);
 
+static FILE	*histfh;
+static char   **histbase;	/* actual start of the history[] allocation */
 static char   **current;	/* current position in history[] */
 static char    *hname;		/* current name of history file */
 static int	hstarted;	/* set after hist_init() called */
+static int	ignoredups;	/* ditch duplicated history lines? */
+static int	ignorespace;	/* ditch lines starting with a space? */
 static Source	*hist_source;
+static uint32_t	line_co;
 
+static struct stat last_sb;
 
 int
 c_fc(char **wp)
 {
 	struct shf *shf;
 	struct temp *tf = NULL;
-	char *p, *editor = (char *) 0;
+	char *p, *editor = NULL;
 	int gflag = 0, lflag = 0, nflag = 0, sflag = 0, rflag = 0;
-	int optc;
-	char *first = (char *) 0, *last = (char *) 0;
+	int optc, ret;
+	char *first = NULL, *last = NULL;
 	char **hfirst, **hlast, **hp;
+	static int depth;
+
+	if (depth != 0) {
+		bi_errorf("history function called recursively");
+		return 1;
+	}
 
 	if (!Flag(FTALKING_I)) {
 		bi_errorf("history functions not available");
@@ -112,7 +125,7 @@ c_fc(char **wp)
 
 	/* Substitute and execute command */
 	if (sflag) {
-		char *pat = (char *) 0, *rep = (char *) 0;
+		char *pat = NULL, *rep = NULL;
 
 		if (editor || lflag || nflag || rflag) {
 			bi_errorf("can't use -e, -l, -n, -r with -s (-e -)");
@@ -139,7 +152,10 @@ c_fc(char **wp)
 		    hist_get_newest(false);
 		if (!hp)
 			return 1;
-		return hist_replace(hp, pat, rep, gflag);
+		depth++;
+		ret = hist_replace(hp, pat, rep, gflag);
+		depth--;
+		return ret;
 	}
 
 	if (editor && (lflag || nflag)) {
@@ -203,7 +219,7 @@ c_fc(char **wp)
 
 	/* Run editor on selected lines, then run resulting commands */
 
-	tf = maketemp(ATEMP, TT_HIST_EDIT, &e->temps);
+	tf = maketemp(ATEMP, TT_HIST_EDIT, &genv->temps);
 	if (!(shf = tf->shf)) {
 		bi_errorf("cannot create temp file %s - %s",
 		    tf->name, strerror(errno));
@@ -223,7 +239,6 @@ c_fc(char **wp)
 	/* XXX: source should not get trashed by this.. */
 	{
 		Source *sold = source;
-		int ret;
 
 		ret = command(editor ? editor : "${FCEDIT:-/bin/ed} $_", 0);
 		source = sold;
@@ -242,7 +257,7 @@ c_fc(char **wp)
 			return 1;
 		}
 
-		n = fstat(shf_fileno(shf), &statb) < 0 ? 128 :
+		n = fstat(shf->fd, &statb) < 0 ? 128 :
 		    statb.st_size + 1;
 		Xinit(xs, xp, n, hist_source->areap);
 		while ((n = shf_read(xp, Xnleft(xs, xp), shf)) > 0) {
@@ -252,14 +267,17 @@ c_fc(char **wp)
 		}
 		if (n < 0) {
 			bi_errorf("error reading temp file %s - %s",
-			    tf->name, strerror(shf_errno(shf)));
+			    tf->name, strerror(shf->errno_));
 			shf_close(shf);
 			return 1;
 		}
 		shf_close(shf);
 		*xp = '\0';
 		strip_nuls(Xstring(xs, xp), Xlength(xs, xp));
-		return hist_execute(Xstring(xs, xp));
+		depth++;
+		ret = hist_execute(Xstring(xs, xp));
+		depth--;
+		return ret;
 	}
 }
 
@@ -277,7 +295,7 @@ hist_execute(char *cmd)
 		if ((q = strchr(p, '\n'))) {
 			*q++ = '\0'; /* kill the newline */
 			if (!*q) /* ignore trailing newline */
-				q = (char *) 0;
+				q = NULL;
 		}
 		histsave(++(hist_source->line), p, 1);
 
@@ -346,7 +364,7 @@ hist_replace(char **hp, const char *pat, const char *rep, int global)
 static char **
 hist_get(const char *str, int approx, int allow_cur)
 {
-	char **hp = (char **) 0;
+	char **hp = NULL;
 	int n;
 
 	if (getn(str, &n)) {
@@ -356,18 +374,18 @@ hist_get(const char *str, int approx, int allow_cur)
 				hp = hist_get_oldest();
 			else {
 				bi_errorf("%s: not in history", str);
-				hp = (char **) 0;
+				hp = NULL;
 			}
 		} else if (hp > histptr) {
 			if (approx)
 				hp = hist_get_newest(allow_cur);
 			else {
 				bi_errorf("%s: not in history", str);
-				hp = (char **) 0;
+				hp = NULL;
 			}
 		} else if (!allow_cur && hp == histptr) {
 			bi_errorf("%s: invalid range", str);
-			hp = (char **) 0;
+			hp = NULL;
 		}
 	} else {
 		int anchored = *str == '?' ? (++str, 0) : 1;
@@ -376,7 +394,7 @@ hist_get(const char *str, int approx, int allow_cur)
 		n = findhist(histptr - history - 1, 0, str, anchored);
 		if (n < 0) {
 			bi_errorf("%s: not in history", str);
-			hp = (char **) 0;
+			hp = NULL;
 		} else
 			hp = &history[n];
 	}
@@ -389,7 +407,7 @@ hist_get_newest(int allow_cur)
 {
 	if (histptr < history || (!allow_cur && histptr == history)) {
 		bi_errorf("no history (yet)");
-		return (char **) 0;
+		return NULL;
 	}
 	if (allow_cur)
 		return histptr;
@@ -402,7 +420,7 @@ hist_get_oldest(void)
 {
 	if (histptr <= history) {
 		bi_errorf("no history (yet)");
-		return (char **) 0;
+		return NULL;
 	}
 	return history;
 }
@@ -417,12 +435,24 @@ histbackup(void)
 
 	if (histptr >= history && last_line != hist_source->line) {
 		hist_source->line--;
-		afree((void*)*histptr, APERM);
+		afree(*histptr, APERM);
 		histptr--;
 		last_line = hist_source->line;
 	}
 }
 
+static void
+histreset(void)
+{
+	char **hp;
+
+	for (hp = history; hp <= histptr; hp++)
+		afree(*hp, APERM);
+
+	histptr = history - 1;
+	hist_source->line = 0;
+}
+
 /*
  * Return the current position.
  */
@@ -490,6 +520,28 @@ findhistrel(const char *str)
 	return start + rec + 1;
 }
 
+void
+sethistcontrol(const char *str)
+{
+	char *spec, *tok, *state;
+
+	ignorespace = 0;
+	ignoredups = 0;
+
+	if (str == NULL)
+		return;
+
+	spec = str_save(str, ATEMP);
+	for (tok = strtok_r(spec, ":", &state); tok != NULL;
+	     tok = strtok_r(NULL, ":", &state)) {
+		if (strcmp(tok, "ignoredups") == 0)
+			ignoredups = 1;
+		else if (strcmp(tok, "ignorespace") == 0)
+			ignorespace = 1;
+	}
+	afree(spec, ATEMP);
+}
+
 /*
  *	set history
  *	this means reallocating the dataspace
@@ -498,18 +550,22 @@ void
 sethistsize(int n)
 {
 	if (n > 0 && n != histsize) {
-		int cursize = histptr - history;
+		int offset = histptr - history;
 
 		/* save most recent history */
-		if (n < cursize) {
-			memmove(history, histptr - n, n * sizeof(char *));
-			cursize = n;
-		}
+		if (offset > n - 1) {
+			char **hp;
 
-		history = (char **)aresize(history, n*sizeof(char *), APERM);
+			offset = n - 1;
+			for (hp = history; hp < histptr - offset; hp++)
+				afree(*hp, APERM);
+			memmove(history, histptr - offset, n * sizeof(char *));
+		}
 
 		histsize = n;
-		histptr = history + cursize;
+		histbase = areallocarray(histbase, n + 1, sizeof(char *), APERM);
+		history = histbase + 1;
+		histptr = history + offset;
 	}
 }
 
@@ -528,22 +584,16 @@ sethistfile(const char *name)
 	/* 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;
+	if (hname) {
 		afree(hname, APERM);
 		hname = NULL;
-		/* let's reset the history */
-		histptr = history - 1;
-		hist_source->line = 0;
+		histreset();
 	}
 
+	history_close();
 	hist_init(hist_source);
 }
 
@@ -553,13 +603,29 @@ sethistfile(const char *name)
 void
 init_histvec(void)
 {
-	if (history == (char **)NULL) {
+	if (histbase == NULL) {
 		histsize = HISTORYSIZE;
-		history = (char **)alloc(histsize*sizeof (char *), APERM);
+		/*
+		 * allocate one extra element so that histptr always
+		 * lies within array bounds
+		 */
+		histbase = areallocarray(NULL, histsize + 1, sizeof(char *),
+		    APERM);
+		history = histbase + 1;
 		histptr = history - 1;
 	}
 }
 
+static void
+history_lock(int operation)
+{
+	while (flock(fileno(histfh), operation) != 0) {
+		if (errno == EINTR || errno == EAGAIN)
+			continue;
+		else
+			break;
+	}
+}
 
 /*
  *	Routines added by Peter Collinson BSDI(Europe)/Hillside Systems to
@@ -576,57 +642,139 @@ init_histvec(void)
 void
 histsave(int lno, const char *cmd, int dowrite)
 {
-	char **hp;
-	char *c, *cp;
+	char		*c, *cp;
+
+	if (ignorespace && cmd[0] == ' ')
+		return;
 
 	c = str_save(cmd, APERM);
-	if ((cp = strchr(c, '\n')) != NULL)
+	if ((cp = strrchr(c, '\n')) != NULL)
 		*cp = '\0';
 
-	if (histfd && dowrite)
-		writehistfile(lno, c);
+	/*
+	 * XXX to properly check for duplicated lines we should first reload
+	 * the histfile if needed
+	 */
+	if (ignoredups && histptr >= history && strcmp(*histptr, c) == 0) {
+		afree(c, APERM);
+		return;
+	}
 
-	hp = histptr;
+	if (dowrite && histfh) {
+#ifndef SMALL
+		struct stat	sb;
 
-	if (++hp >= history + histsize) { /* remove oldest command */
-		afree((void*)*history, APERM);
-		for (hp = history; hp < history + histsize - 1; hp++)
-			hp[0] = hp[1];
+		history_lock(LOCK_EX);
+		if (fstat(fileno(histfh), &sb) != -1) {
+			if (timespeccmp(&sb.st_mtim, &last_sb.st_mtim, ==))
+				; /* file is unchanged */
+			else {
+				histreset();
+				history_load(hist_source);
+			}
+		}
+#endif
+	}
+
+	if (histptr < history + histsize - 1)
+		histptr++;
+	else { /* remove oldest command */
+		afree(*history, APERM);
+		memmove(history, history + 1,
+		    (histsize - 1) * sizeof(*history));
+	}
+	*histptr = c;
+
+	if (dowrite && histfh) {
+#ifndef SMALL
+		char *encoded;
+
+		/* append to file */
+		if (fseeko(histfh, 0, SEEK_END) == 0 &&
+		    stravis(&encoded, c, VIS_SAFE | VIS_NL) != -1) {
+			fprintf(histfh, "%s\n", encoded);
+			fflush(histfh);
+			fstat(fileno(histfh), &last_sb);
+			line_co++;
+			history_write();
+			free(encoded);
+		}
+		history_lock(LOCK_UN);
+#endif
 	}
-	*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
- */
+static FILE *
+history_open(void)
+{
+	FILE		*f = NULL;
+#ifndef SMALL
+	struct stat	sb;
+	int		fd, fddup;
+
+	if ((fd = open(hname, O_RDWR | O_CREAT | O_EXLOCK, 0600)) == -1)
+		return NULL;
+	if (fstat(fd, &sb) == -1 || sb.st_uid != getuid()) {
+		close(fd);
+		return NULL;
+	}
+	fddup = savefd(fd);
+	if (fddup != fd)
+		close(fd);
 
-/*
- *	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
+	if ((f = fdopen(fddup, "r+")) == NULL)
+		close(fddup);
+	else
+		last_sb = sb;
+#endif
+	return f;
+}
+
+static void
+history_close(void)
+{
+	if (histfh) {
+		fflush(histfh);
+		fclose(histfh);
+		histfh = NULL;
+	}
+}
+
+static int
+history_load(Source *s)
+{
+	char		*p, encoded[LINE + 1], line[LINE + 1];
+
+	rewind(histfh);
+
+	/* just read it all; will auto resize history upon next command */
+	for (line_co = 1; ; line_co++) {
+		p = fgets(encoded, sizeof(encoded), histfh);
+		if (p == NULL || feof(histfh) || ferror(histfh))
+			break;
+		if ((p = strchr(encoded, '\n')) == NULL) {
+			bi_errorf("history file is corrupt");
+			return 1;
+		}
+		*p = '\0';
+		s->line = line_co;
+		s->cmd_offset = line_co;
+		strunvis(line, encoded);
+		histsave(line_co, line, 0);
+	}
+
+	history_write();
+
+	return 0;
+}
+
+#define HMAGIC1 0xab
+#define HMAGIC2 0xcd
 
 void
 hist_init(Source *s)
 {
-	unsigned char	*base;
-	int	lines;
-	int	fd;
+	int oldmagic1, oldmagic2;
 
 	if (Flag(FTALKING) == 0)
 		return;
@@ -639,325 +787,66 @@ hist_init(Source *s)
 	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)
+	histfh = history_open();
+	if (histfh == NULL)
 		return;
 
-	histfd = savefd(fd);
-	if (histfd != fd)
-		close(fd);
-
-	(void) flock(histfd, LOCK_EX);
+	oldmagic1 = fgetc(histfh);
+	oldmagic2 = fgetc(histfh);
 
-	hsize = lseek(histfd, 0L, SEEK_END);
-
-	if (hsize == 0) {
-		/* add magic */
-		if (sprinkle(histfd)) {
-			hist_finish();
+	if (oldmagic1 == EOF || oldmagic2 == EOF) {
+		if (!feof(histfh) && ferror(histfh)) {
+			history_close();
 			return;
 		}
+	} else if (oldmagic1 == HMAGIC1 && oldmagic2 == HMAGIC2) {
+		bi_errorf("ignoring old style history file");
+		history_close();
+		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();
-			if (unlink(hname) != 0)
-				return;
-			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))
-					if (unlink(hname) != 0)
-						return;
-				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;
-}
+	rewind(histfh);
 
-/*
- *	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;
+	history_load(s);
 
-	/*
-	 *	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;
+	history_lock(LOCK_UN);
 }
 
-
-/*
- *	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)
+history_write(void)
 {
-	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;
-			}
-		}
-	}
-}
+	char		**hp, *encoded;
 
-/*
- *	Insert a line into the history at a specified number
- */
-static void
-histinsert(Source *s, int lno, unsigned char *line)
-{
-	char **hp;
+	/* see if file has grown over 25% */
+	if (line_co < histsize + (histsize / 4))
+		return;
 
-	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);
+	/* rewrite the whole caboodle */
+	rewind(histfh);
+	if (ftruncate(fileno(histfh), 0) == -1) {
+		bi_errorf("failed to rewrite history file - %s",
+		    strerror(errno));
 	}
-}
-
-/*
- *	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;
+	for (hp = history; hp <= histptr; hp++) {
+		if (stravis(&encoded, *hp, VIS_SAFE | VIS_NL) != -1) {
+			if (fprintf(histfh, "%s\n", encoded) == -1) {
+				free(encoded);
+				return;
 			}
-			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;
+			free(encoded);
 		}
 	}
-	/*
-	 *	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();
+
+	line_co = histsize;
+
+	fflush(histfh);
+	fstat(fileno(histfh), &last_sb);
 }
 
 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);
+	history_close();
 }
 
 #else /* HISTORY */
diff --git a/io.c b/io.c
@@ -1,12 +1,18 @@
-/*	$OpenBSD: io.c,v 1.25 2014/08/11 20:28:47 guenther Exp $	*/
+/*	$OpenBSD: io.c,v 1.35 2016/03/20 00:01:21 krw Exp $	*/
 
 /*
  * shell buffered IO and formatted output
  */
 
+#include <sys/stat.h>
+
 #include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
 #include "sh.h"
-#include <sys/stat.h>
 
 static int initio_done;
 
@@ -23,7 +29,7 @@ errorf(const char *fmt, ...)
 
 	shl_stdout_ok = 0;	/* debugging: note that stdout not valid */
 	exstat = 1;
-	if (*fmt) {
+	if (fmt != NULL && *fmt != '\0') {
 		error_prefix(true);
 		va_start(va, fmt);
 		shf_vfprintf(shl_out, fmt, va);
@@ -36,11 +42,11 @@ errorf(const char *fmt, ...)
 
 /* like errorf(), but no unwind is done */
 void
-warningf(int fileline, const char *fmt, ...)
+warningf(bool show_lineno, const char *fmt, ...)
 {
 	va_list va;
 
-	error_prefix(fileline);
+	error_prefix(show_lineno);
 	va_start(va, fmt);
 	shf_vfprintf(shl_out, fmt, va);
 	va_end(va);
@@ -58,7 +64,7 @@ bi_errorf(const char *fmt, ...)
 
 	shl_stdout_ok = 0;	/* debugging: note that stdout not valid */
 	exstat = 1;
-	if (*fmt) {
+	if (fmt != NULL && *fmt != '\0') {
 		error_prefix(true);
 		/* not set when main() calls parse_args() */
 		if (builtin_argv0)
@@ -75,7 +81,7 @@ bi_errorf(const char *fmt, ...)
 	 */
 	if ((builtin_flag & SPEC_BI) ||
 	    (Flag(FPOSIX) && (builtin_flag & KEEPASN))) {
-		builtin_argv0 = (char *) 0;
+		builtin_argv0 = NULL;
 		unwind(LERROR);
 	}
 }
@@ -296,7 +302,7 @@ check_fd(char *name, int mode, const char **emsgp)
 
 	if (isdigit((unsigned char)name[0]) && !name[1]) {
 		fd = name[0] - '0';
-		if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) {
+		if ((fl = fcntl(fd, F_GETFL)) < 0) {
 			if (emsgp)
 				*emsgp = "bad file descriptor";
 			return -1;
@@ -422,14 +428,14 @@ maketemp(Area *ap, Temp_type type, struct temp **tlist)
 	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 = alloc(sizeof(struct temp) + len, ap);
 	tp->name = path = (char *) &tp[1];
-	tp->shf = (struct shf *) 0;
+	tp->shf = NULL;
 	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->shf = shf_fdopen(fd, SHF_WR, NULL);
 	tp->pid = procpid;
 
 	tp->next = *tlist;
diff --git a/jobs.c b/jobs.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: jobs.c,v 1.41 2015/04/18 18:28:36 deraadt Exp $	*/
+/*	$OpenBSD: jobs.c,v 1.55 2016/03/17 23:33:23 mmcc Exp $	*/
 
 /*
  * Process and job control
@@ -15,11 +15,20 @@
  *
  */
 
-#include "sh.h"
+#include <sys/resource.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
 #include <sys/time.h>
-#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sh.h"
 #include "tty.h"
 
 /* Order important! */
@@ -71,7 +80,7 @@ struct job {
 	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 */
+	int	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 */
@@ -100,7 +109,7 @@ static const char	*const lookup_msgs[] = {
 	"no such job",
 	"ambiguous",
 	"argument must be %job or process id",
-	(char *) 0
+	NULL
 };
 
 struct timeval	j_systime, j_usrtime;	/* user and system time of last j_waitjed job */
@@ -111,7 +120,7 @@ static Job		*async_job;
 static pid_t		async_pid;
 
 static int		nzombie;	/* # of zombies owned by this process */
-INT32			njobs;		/* # of jobs started */
+int			njobs;		/* # of jobs started */
 static int		child_max;	/* CHILD_MAX */
 
 
@@ -146,7 +155,7 @@ 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);
+	sigprocmask(SIG_SETMASK, &sm_default, NULL);
 
 	sigemptyset(&sm_sigchld);
 	sigaddset(&sm_sigchld, SIGCHLD);
@@ -161,7 +170,7 @@ j_init(int mflagset)
 	/* 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);
+	shl_j = shf_fdopen(2, SHF_WR, NULL);
 
 	if (Flag(FMONITOR) || Flag(FTALKING)) {
 		int i;
@@ -247,7 +256,7 @@ j_exit(void)
 	Job	*j;
 	int	killed = 0;
 
-	for (j = job_list; j != (Job *) 0; j = j->next) {
+	for (j = job_list; j != NULL; j = j->next) {
 		if (j->ppid == procpid &&
 		    (j->state == PSTOPPED ||
 		    (j->state == PRUNNING &&
@@ -407,7 +416,7 @@ exchild(struct op *t, int flags, volatile int *xerrok,
 	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
 
 	p = new_proc();
-	p->next = (Proc *) 0;
+	p->next = NULL;
 	p->state = PRUNNING;
 	p->status = 0;
 	p->pid = 0;
@@ -454,7 +463,7 @@ exchild(struct op *t, int flags, volatile int *xerrok,
 	if (i < 0) {
 		kill_job(j, SIGKILL);
 		remove_job(j, "fork failed");
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+		sigprocmask(SIG_SETMASK, &omask, NULL);
 		errorf("cannot fork - try again");
 	}
 	ischild = i == 0;
@@ -494,7 +503,7 @@ exchild(struct op *t, int flags, volatile int *xerrok,
 		/* Do this before restoring signal */
 		if (flags & XCOPROC)
 			coproc_cleanup(false);
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+		sigprocmask(SIG_SETMASK, &omask, NULL);
 		cleanup_parents_env();
 #ifdef JOBS
 		/* If FMONITOR or FTALKING is set, these signals are ignored,
@@ -515,7 +524,7 @@ exchild(struct op *t, int flags, volatile int *xerrok,
 			setsig(&sigtraps[SIGQUIT], SIG_IGN,
 			    SS_RESTORE_IGN|SS_FORCE);
 			if (!(flags & (XPIPEI | XCOPROC))) {
-				int fd = open("/dev/null", 0);
+				int fd = open("/dev/null", O_RDONLY);
 				if (fd != 0) {
 					(void) ksh_dup2(fd, 0, true);
 					close(fd);
@@ -566,7 +575,7 @@ exchild(struct op *t, int flags, volatile int *xerrok,
 			rv = j_waitj(j, JW_NONE, "jw:last proc");
 	}
 
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+	sigprocmask(SIG_SETMASK, &omask, NULL);
 
 	return rv;
 }
@@ -584,7 +593,7 @@ startlast(void)
 		last_job->flags |= JF_WAITING;
 		j_startjob(last_job);
 	}
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+	sigprocmask(SIG_SETMASK, &omask, NULL);
 }
 
 /* wait for last job: only used for `command` jobs */
@@ -603,13 +612,13 @@ waitlast(void)
 			warningf(true, "waitlast: no last job");
 		else
 			internal_errorf(0, "waitlast: not started");
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+		sigprocmask(SIG_SETMASK, &omask, NULL);
 		return 125; /* not so arbitrary, non-zero value */
 	}
 
 	rv = j_waitj(j, JW_NONE, "jw:waitlast");
 
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+	sigprocmask(SIG_SETMASK, &omask, NULL);
 
 	return rv;
 }
@@ -628,7 +637,7 @@ waitfor(const char *cp, int *sigp)
 
 	*sigp = 0;
 
-	if (cp == (char *) 0) {
+	if (cp == NULL) {
 		/* wait for an unspecified job - always returns 0, so
 		 * don't have to worry about exited/signaled jobs
 		 */
@@ -637,18 +646,18 @@ waitfor(const char *cp, int *sigp)
 			if (j->ppid == procpid && j->state == PRUNNING)
 				break;
 		if (!j) {
-			sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+			sigprocmask(SIG_SETMASK, &omask, NULL);
 			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);
+			sigprocmask(SIG_SETMASK, &omask, NULL);
 			return -1;
 		}
 	} else {
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+		sigprocmask(SIG_SETMASK, &omask, NULL);
 		if (ecode != JL_NOSUCH)
 			bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
 		return -1;
@@ -657,7 +666,7 @@ waitfor(const char *cp, int *sigp)
 	/* 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);
+	sigprocmask(SIG_SETMASK, &omask, NULL);
 
 	if (rv < 0) /* we were interrupted */
 		*sigp = 128 + -rv;
@@ -676,8 +685,8 @@ j_kill(const char *cp, int sig)
 
 	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
 
-	if ((j = j_lookup(cp, &ecode)) == (Job *) 0) {
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+	if ((j = j_lookup(cp, &ecode)) == NULL) {
+		sigprocmask(SIG_SETMASK, &omask, NULL);
 		bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
 		return 1;
 	}
@@ -698,7 +707,7 @@ j_kill(const char *cp, int sig)
 		}
 	}
 
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+	sigprocmask(SIG_SETMASK, &omask, NULL);
 
 	return rv;
 }
@@ -717,14 +726,14 @@ j_resume(const char *cp, int bg)
 
 	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
 
-	if ((j = j_lookup(cp, &ecode)) == (Job *) 0) {
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+	if ((j = j_lookup(cp, &ecode)) == NULL) {
+		sigprocmask(SIG_SETMASK, &omask, NULL);
 		bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
 		return 1;
 	}
 
 	if (j->pgrp == 0) {
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+		sigprocmask(SIG_SETMASK, &omask, NULL);
 		bi_errorf("job not job-controlled");
 		return 1;
 	}
@@ -733,15 +742,15 @@ j_resume(const char *cp, int bg)
 		shprintf("[%d] ", j->job);
 
 	running = 0;
-	for (p = j->proc_list; p != (Proc *) 0; p = p->next) {
+	for (p = j->proc_list; p != NULL; p = p->next) {
 		if (p->state == PSTOPPED) {
 			p->state = PRUNNING;
 			p->status = 0;
 			running = 1;
 		}
-		shprintf("%s%s", p->command, p->next ? "| " : null);
+		shprintf("%s%s", p->command, p->next ? "| " : "");
 	}
-	shprintf("%s", newline);
+	shprintf("\n");
 	shf_flush(shl_stdout);
 	if (running)
 		j->state = PRUNNING;
@@ -761,8 +770,7 @@ j_resume(const char *cp, int bg)
 			    j->saved_ttypgrp : j->pgrp) < 0) {
 				if (j->flags & JF_SAVEDTTY)
 					tcsetattr(tty_fd, TCSADRAIN, &tty_state);
-				sigprocmask(SIG_SETMASK, &omask,
-				    (sigset_t *) 0);
+				sigprocmask(SIG_SETMASK, &omask, NULL);
 				bi_errorf("1st tcsetpgrp(%d, %d) failed: %s",
 				    tty_fd,
 				    (int) ((j->flags & JF_SAVEDTTYPGRP) ?
@@ -775,7 +783,7 @@ j_resume(const char *cp, int bg)
 		j->flags |= JF_FG;
 		j->flags &= ~JF_KNOWN;
 		if (j == async_job)
-			async_job = (Job *) 0;
+			async_job = NULL;
 	}
 
 	if (j->state == PRUNNING && killpg(j->pgrp, SIGCONT) < 0) {
@@ -794,7 +802,7 @@ j_resume(const char *cp, int bg)
 			}
 # endif /* JOBS */
 		}
-		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+		sigprocmask(SIG_SETMASK, &omask, NULL);
 		bi_errorf("cannot continue job %s: %s",
 		    cp, strerror(err));
 		return 1;
@@ -807,7 +815,7 @@ j_resume(const char *cp, int bg)
 # endif /* JOBS */
 		rv = j_waitj(j, JW_NONE, "jw:resume");
 	}
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+	sigprocmask(SIG_SETMASK, &omask, NULL);
 	return rv;
 }
 #endif /* JOBS */
@@ -819,7 +827,7 @@ j_stopped_running(void)
 	Job	*j;
 	int	which = 0;
 
-	for (j = job_list; j != (Job *) 0; j = j->next) {
+	for (j = job_list; j != NULL; j = j->next) {
 #ifdef JOBS
 		if (j->ppid == procpid && j->state == PSTOPPED)
 			which |= 1;
@@ -850,7 +858,7 @@ j_njobs(void)
 	for (j = job_list; j; j = j->next)
 		nj++;
 
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+	sigprocmask(SIG_SETMASK, &omask, NULL);
 	return nj;
 }
 
@@ -874,8 +882,8 @@ j_jobs(const char *cp, int slp,
 	if (cp) {
 		int	ecode;
 
-		if ((j = j_lookup(cp, &ecode)) == (Job *) 0) {
-			sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+		if ((j = j_lookup(cp, &ecode)) == NULL) {
+			sigprocmask(SIG_SETMASK, &omask, NULL);
 			bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
 			return 1;
 		}
@@ -898,7 +906,7 @@ j_jobs(const char *cp, int slp,
 		if (j->flags & JF_REMOVE)
 			remove_job(j, "jobs");
 	}
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+	sigprocmask(SIG_SETMASK, &omask, NULL);
 	return 0;
 }
 
@@ -927,7 +935,7 @@ j_notify(void)
 			remove_job(j, "notify");
 	}
 	shf_flush(shl_out);
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+	sigprocmask(SIG_SETMASK, &omask, NULL);
 }
 
 /* Return pid of last process in last asynchronous job */
@@ -941,7 +949,7 @@ j_async(void)
 	if (async_job)
 		async_job->flags |= JF_KNOWN;
 
-	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+	sigprocmask(SIG_SETMASK, &omask, NULL);
 
 	return async_pid;
 }
@@ -964,7 +972,7 @@ j_set_async(Job *j)
 	async_job = j;
 	async_pid = j->last_proc->pid;
 	while (nzombie > child_max) {
-		oldest = (Job *) 0;
+		oldest = NULL;
 		for (jl = job_list; jl; jl = jl->next)
 			if (jl != async_job && (jl->flags & JF_ZOMBIE) &&
 			    (!oldest || jl->age < oldest->age))
@@ -1136,7 +1144,6 @@ j_waitj(Job *j,
  *
  * If jobs are compiled in then this routine expects sigchld to be blocked.
  */
-/* ARGSUSED */
 static void
 j_sigchld(int sig)
 {
@@ -1168,12 +1175,12 @@ j_sigchld(int sig)
 		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)
+		for (j = job_list; j != NULL; j = j->next)
+			for (p = j->proc_list; p != NULL; p = p->next)
 				if (p->pid == pid)
 					goto found;
 found:
-		if (j == (Job *) 0) {
+		if (j == NULL) {
 			/* Can occur if process has kids, then execs shell
 			warningf(true, "bad process waited for (pid = %d)",
 				pid);
@@ -1227,7 +1234,7 @@ check_job(Job *j)
 	}
 
 	jstate = PRUNNING;
-	for (p=j->proc_list; p != (Proc *) 0; p = p->next) {
+	for (p=j->proc_list; p != NULL; p = p->next) {
 		if (p->state == PRUNNING)
 			return;	/* some processes still running */
 		if (p->state > jstate)
@@ -1256,7 +1263,7 @@ check_job(Job *j)
 		 * (at least, this is what ksh93d thinks)
 		 */
 		if (coproc.job == j) {
-			coproc.job = (void *) 0;
+			coproc.job = NULL;
 			/* 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
@@ -1285,7 +1292,7 @@ check_job(Job *j)
 				struct env *ep;
 				int fd = 2;
 
-				for (ep = e; ep; ep = ep->oenv)
+				for (ep = genv; ep; ep = ep->oenv)
 					if (ep->savefd && ep->savefd[2])
 						fd = ep->savefd[2];
 				shf_reopen(fd, SHF_WR, shl_j);
@@ -1345,7 +1352,7 @@ j_print(Job *j, int how, struct shf *shf)
 	else if (j == job_list->next)
 		jobchar = '-';
 
-	for (p = j->proc_list; p != (Proc *) 0;) {
+	for (p = j->proc_list; p != NULL;) {
 		coredumped = 0;
 		switch (p->state) {
 		case PRUNNING:
@@ -1394,13 +1401,13 @@ j_print(Job *j, int how, struct shf *shf)
 			if (buf[0]) {
 				output = 1;
 				shf_fprintf(shf, "%s%s ",
-				    buf, coredumped ? " (core dumped)" : null);
+				    buf, coredumped ? " (core dumped)" : "");
 			}
 		} else {
 			output = 1;
 			shf_fprintf(shf, "%-20s %s%s%s", buf, p->command,
-			    p->next ? "|" : null,
-			    coredumped ? " (core dumped)" : null);
+			    p->next ? "|" : "",
+			    coredumped ? " (core dumped)" : "");
 		}
 
 		state = p->state;
@@ -1409,15 +1416,15 @@ j_print(Job *j, int how, struct shf *shf)
 		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);
+				    " ", p->command, p->next ? "|" : "");
 			else if (how == JP_MEDIUM)
 				shf_fprintf(shf, " %s%s", p->command,
-				    p->next ? "|" : null);
+				    p->next ? "|" : "");
 			p = p->next;
 		}
 	}
 	if (output)
-		shf_fprintf(shf, newline);
+		shf_fprintf(shf, "\n");
 }
 
 /* Convert % sequence to job
@@ -1437,37 +1444,37 @@ j_lookup(const char *cp, int *ecodep)
 		if (errstr) {
 			if (ecodep)
 				*ecodep = JL_NOSUCH;
-			return (Job *) 0;
+			return NULL;
 		}
 		/* Look for last_proc->pid (what $! returns) first... */
-		for (j = job_list; j != (Job *) 0; j = j->next)
+		for (j = job_list; j != NULL; 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)
+		for (j = job_list; j != NULL; j = j->next)
 			if (j->pgrp && j->pgrp == job)
 				return j;
 		if (ecodep)
 			*ecodep = JL_NOSUCH;
-		return (Job *) 0;
+		return NULL;
 	}
 	if (*cp != '%') {
 		if (ecodep)
 			*ecodep = JL_INVALID;
-		return (Job *) 0;
+		return NULL;
 	}
 	switch (*++cp) {
 	case '\0': /* non-standard */
 	case '+':
 	case '%':
-		if (job_list != (Job *) 0)
+		if (job_list != NULL)
 			return job_list;
 		break;
 
 	case '-':
-		if (job_list != (Job *) 0 && job_list->next)
+		if (job_list != NULL && job_list->next)
 			return job_list->next;
 		break;
 
@@ -1476,20 +1483,20 @@ j_lookup(const char *cp, int *ecodep)
 		job = strtonum(cp, 1, INT_MAX, &errstr);
 		if (errstr)
 			break;
-		for (j = job_list; j != (Job *) 0; j = j->next)
+		for (j = job_list; j != NULL; 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) {
+		last_match = NULL;
+		for (j = job_list; j != NULL; j = j->next)
+			for (p = j->proc_list; p != NULL; p = p->next)
+				if (strstr(p->command, cp+1) != NULL) {
 					if (last_match) {
 						if (ecodep)
 							*ecodep = JL_AMBIG;
-						return (Job *) 0;
+						return NULL;
 					}
 					last_match = j;
 				}
@@ -1499,13 +1506,13 @@ j_lookup(const char *cp, int *ecodep)
 
 	default:		/* %string */
 		len = strlen(cp);
-		last_match = (Job *) 0;
-		for (j = job_list; j != (Job *) 0; j = j->next)
+		last_match = NULL;
+		for (j = job_list; j != NULL; j = j->next)
 			if (strncmp(cp, j->proc_list->command, len) == 0) {
 				if (last_match) {
 					if (ecodep)
 						*ecodep = JL_AMBIG;
-					return (Job *) 0;
+					return NULL;
 				}
 				last_match = j;
 			}
@@ -1515,7 +1522,7 @@ j_lookup(const char *cp, int *ecodep)
 	}
 	if (ecodep)
 		*ecodep = JL_NOSUCH;
-	return (Job *) 0;
+	return NULL;
 }
 
 static Job	*free_jobs;
@@ -1531,17 +1538,17 @@ new_job(void)
 	int	i;
 	Job	*newj, *j;
 
-	if (free_jobs != (Job *) 0) {
+	if (free_jobs != NULL) {
 		newj = free_jobs;
 		free_jobs = free_jobs->next;
 	} else
-		newj = (Job *) alloc(sizeof(Job), APERM);
+		newj = 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)
+		if (j == NULL)
 			break;
 	}
 	newj->job = i;
@@ -1558,11 +1565,11 @@ new_proc(void)
 {
 	Proc	*p;
 
-	if (free_procs != (Proc *) 0) {
+	if (free_procs != NULL) {
 		p = free_procs;
 		free_procs = free_procs->next;
 	} else
-		p = (Proc *) alloc(sizeof(Proc), APERM);
+		p = alloc(sizeof(Proc), APERM);
 
 	return p;
 }
@@ -1580,7 +1587,7 @@ remove_job(Job *j, const char *where)
 
 	prev = &job_list;
 	curr = *prev;
-	for (; curr != (Job *) 0 && curr != j; prev = &curr->next, curr = *prev)
+	for (; curr != NULL && curr != j; prev = &curr->next, curr = *prev)
 		;
 	if (curr != j) {
 		internal_errorf(0, "remove_job: job not found (%s)", where);
@@ -1589,7 +1596,7 @@ remove_job(Job *j, const char *where)
 	*prev = curr->next;
 
 	/* free up proc structures */
-	for (p = j->proc_list; p != (Proc *) 0; ) {
+	for (p = j->proc_list; p != NULL; ) {
 		tmp = p;
 		p = p->next;
 		tmp->next = free_procs;
@@ -1602,9 +1609,9 @@ remove_job(Job *j, const char *where)
 	free_jobs = j;
 
 	if (j == last_job)
-		last_job = (Job *) 0;
+		last_job = NULL;
 	if (j == async_job)
-		async_job = (Job *) 0;
+		async_job = NULL;
 }
 
 /* put j in a particular location (taking it out job_list if it is there
@@ -1653,7 +1660,7 @@ kill_job(Job *j, int sig)
 	Proc	*p;
 	int	rval = 0;
 
-	for (p = j->proc_list; p != (Proc *) 0; p = p->next)
+	for (p = j->proc_list; p != NULL; p = p->next)
 		if (p->pid != 0)
 			if (kill(p->pid, sig) < 0)
 				rval = -1;
diff --git a/ksh_limval.h b/ksh_limval.h
@@ -1,13 +0,0 @@
-/*	$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
diff --git a/lex.c b/lex.c
@@ -1,13 +1,37 @@
-/*	$OpenBSD: lex.c,v 1.49 2013/12/17 16:37:06 deraadt Exp $	*/
+/*	$OpenBSD: lex.c,v 1.71 2017/07/04 11:46:15 anton Exp $	*/
 
 /*
  * lexical analysis and source input
  */
+
 #include <ctype.h>
+#include <errno.h>
 #include <libgen.h>
-#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
 #include "sh.h"
 
+/*
+ * states while lexing word
+ */
+#define	SINVALID	-1	/* invalid state */
+#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 ${..[#%]..} */
+#define	SBRACEQ	13		/* inside "${}" */
+
 /* Structure to keep track of the lexing state and the various pieces of info
  * needed for each particular state.
  */
@@ -69,6 +93,15 @@ int		promptlen(const char *cp, const char **spp);
 static int backslash_skip;
 static int ignore_backslash_newline;
 
+Source *source;		/* yyparse/yylex source */
+YYSTYPE	yylval;		/* result from yylex */
+struct ioword *heres[HERES], **herep;
+char	ident[IDENT+1];
+
+char  **history;	/* saved commands */
+char  **histptr;	/* last history item */
+int	histsize;	/* history size */
+
 /* optimized getsc_bn() */
 #define getsc()		(*source->str != '\0' && *source->str != '\\' \
 			 && !backslash_skip ? *source->str++ : getsc_bn())
@@ -112,7 +145,7 @@ yylex(int cf)
 
 
   Again:
-	states[0].ls_state = -1;
+	states[0].ls_state = SINVALID;
 	states[0].ls_info.base = NULL;
 	statep = &states[1];
 	state_info.base = states;
@@ -162,6 +195,9 @@ yylex(int cf)
 			if (Flag(FCSHHISTORY) && (source->flags & SF_TTY) &&
 			    c == '!') {
 				char **replace = NULL;
+				int get, i;
+				char match[200] = { 0 }, *str = match;
+				size_t mlen;
 
 				c2 = getsc();
 				if (c2 == '\0' || c2 == ' ' || c2 == '\t')
@@ -170,8 +206,7 @@ yylex(int cf)
 					replace = hist_get_newest(0);
 				else if (isdigit(c2) || c2 == '-' ||
 				    isalpha(c2)) {
-					int get = !isalpha(c2);
-					char match[200], *str = match;
+					get = !isalpha(c2);
 
 					*str++ = c2;
 					do {
@@ -215,6 +250,11 @@ yylex(int cf)
 					s->u.freeme = NULL;
 					source = s;
 					continue;
+				} else if (*match != '\0') {
+					/* restore what followed the '!' */
+					mlen = strlen(match);
+					for (i = mlen-1; i >= 0; i--)
+						ungetsc(match[i]);
 				} else
 					ungetsc(c2);
 			}
@@ -363,12 +403,12 @@ yylex(int cf)
 						Xcheck(ws, wp);
 						*wp++ = c;
 						c = getsc();
-					} while (ctype(c, C_ALPHA|C_DIGIT));
+					} while (ctype(c, C_ALPHA) || digit(c));
 					*wp++ = '\0';
 					*wp++ = CSUBST;
 					*wp++ = 'X';
 					ungetsc(c);
-				} else if (ctype(c, C_DIGIT|C_VAR1)) {
+				} else if (ctype(c, C_VAR1) || digit(c)) {
 					Xcheck(ws, wp);
 					*wp++ = OSUBST;
 					*wp++ = 'X';
@@ -387,40 +427,22 @@ yylex(int cf)
 				/* 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)
+				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 = s->ls_info.base))
-							break;
-						base = s-- - STATE_BSIZE;
+						}
 					}
+					if (s != base)
+						break;
+					if (!(s = s->ls_info.base))
+						break;
+					base = s-- - STATE_BSIZE;
 				}
 				break;
 			default:
@@ -542,6 +564,15 @@ yylex(int cf)
 			break;
 
 		case SBRACEQ:
+			/*{*/
+			if (c == '}') {
+				POP_STATE();
+				*wp++ = CSUBST;
+				*wp++ = /*{*/ '}';
+			} else
+				goto Sbase2;
+			break;
+
 		case SBRACE:
 			/*{*/
 			if (c == '}') {
@@ -699,7 +730,7 @@ Done:
 	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);
+		struct ioword *iop = alloc(sizeof(*iop), ATEMP);
 
 		if (c2 == 2)
 			iop->unit = dp[1] - '0';
@@ -727,9 +758,9 @@ Done:
 				ungetsc(c2);
 		}
 
-		iop->name = (char *) 0;
-		iop->delim = (char *) 0;
-		iop->heredoc = (char *) 0;
+		iop->name = NULL;
+		iop->delim = NULL;
+		iop->heredoc = NULL;
 		Xfree(ws, wp);	/* free word */
 		yylval.iop = iop;
 		return REDIR;
@@ -908,7 +939,7 @@ yyerror(const char *fmt, ...)
 	va_start(va, fmt);
 	shf_vfprintf(shl_out, fmt, va);
 	va_end(va);
-	errorf("%s", null);
+	errorf(NULL);
 }
 
 /*
@@ -920,7 +951,7 @@ pushs(int type, Area *areap)
 {
 	Source *s;
 
-	s = (Source *) alloc(sizeof(Source), areap);
+	s = alloc(sizeof(Source), areap);
 	s->type = type;
 	s->str = null;
 	s->start = NULL;
@@ -970,10 +1001,10 @@ getsc__(void)
 
 		case SWORDSEP:
 			if (*s->u.strv == NULL) {
-				s->start = s->str = newline;
+				s->start = s->str = "\n";
 				s->type = SEOF;
 			} else {
-				s->start = s->str = space;
+				s->start = s->str = " ";
 				s->type = SWORDS;
 			}
 			break;
@@ -1084,7 +1115,7 @@ getsc_line(Source *s)
 			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) {
+			    s->u.shf->errno_ == EINTR) {
 				shf_clearerr(s->u.shf);
 				if (trap)
 					runtraps(0);
@@ -1134,7 +1165,7 @@ getsc_line(Source *s)
 #endif /* HISTORY */
 	}
 	if (interactive)
-		set_prompt(PS2, (Source *) 0);
+		set_prompt(PS2, NULL);
 }
 
 static char *
@@ -1161,7 +1192,7 @@ set_prompt(int to, Source *s)
 		ps1 = str_save(str_val(global("PS1")), ATEMP);
 		saved_atemp = ATEMP;	/* ps1 is freed by substitute() */
 		newenv(E_ERRH);
-		if (sigsetjmp(e->jbuf, 0)) {
+		if (sigsetjmp(genv->jbuf, 0)) {
 			prompt = safe_prompt;
 			/* Don't print an error - assume it has already
 			 * been printed.  Reason is we may have forked
@@ -1369,7 +1400,8 @@ dopprompt(const char *sp, int ntruncate, const char **spp, int doprint)
 					    "\\%c", *cp);
 					break;
 				}
-				n = cp[0] * 8 * 8 + cp[1] * 8 + cp[2];
+				n = (cp[0] - '0') * 8 * 8 + (cp[1] - '0') * 8 +
+				    (cp[2] - '0');
 				snprintf(strbuf, sizeof strbuf, "%c", n);
 				cp += 2;
 				break;
@@ -1620,7 +1652,8 @@ getsc_bn(void)
 static Lex_state *
 push_state_(State_info *si, Lex_state *old_end)
 {
-	Lex_state	*new = alloc(sizeof(Lex_state) * STATE_BSIZE, ATEMP);
+	Lex_state *new = areallocarray(NULL, STATE_BSIZE,
+	    sizeof(Lex_state), ATEMP);
 
 	new[0].ls_info.base = old_end;
 	si->base = &new[0];
diff --git a/lex.h b/lex.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: lex.h,v 1.13 2013/03/03 19:11:34 guenther Exp $	*/
+/*	$OpenBSD: lex.h,v 1.16 2015/10/10 07:35:16 nicm Exp $	*/
 
 /*
  * Source input, lexer and parser
@@ -48,24 +48,6 @@ struct source {
 #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 ${..[#%]..} */
-#define	SBRACEQ	13		/* inside "${}" */
-
 typedef union {
 	int	i;
 	char   *cp;
@@ -118,15 +100,23 @@ typedef union {
 
 #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];
+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 */
+extern char   **history;	/* saved commands */
+extern char   **histptr;	/* last history item */
+extern int	histsize;	/* history size */
+
 #endif /* HISTORY */
+
+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);
diff --git a/mail.c b/mail.c
@@ -1,16 +1,18 @@
-/*	$OpenBSD: mail.c,v 1.17 2013/11/28 10:33:37 sobrado Exp $	*/
+/*	$OpenBSD: mail.c,v 1.22 2015/10/19 14:42:16 mmcc 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 <string.h>
 #include <time.h>
 
+#include "config.h"
+#include "sh.h"
+
 #define MBMESSAGE	"you have mail in $_"
 
 typedef struct mbox {
@@ -89,10 +91,8 @@ 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);
+	afree(mbox.mb_msg, APERM);
+	afree(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;
@@ -151,8 +151,8 @@ munset(mbox_t *mlist)
 		mbp = mlist;
 		mlist = mbp->mb_next;
 		if (!mlist)
-			afree((void *)mbp->mb_path, APERM);
-		afree((void *)mbp, APERM);
+			afree(mbp->mb_path, APERM);
+		afree(mbp, APERM);
 	}
 }
 
@@ -162,7 +162,7 @@ mballoc(char *p, char *m)
 	struct stat	stbuf;
 	mbox_t	*mbp;
 
-	mbp = (mbox_t *)alloc(sizeof(mbox_t), APERM);
+	mbp = alloc(sizeof(mbox_t), APERM);
 	mbp->mb_next = NULL;
 	mbp->mb_path = p;
 	mbp->mb_msg = m;
diff --git a/main.c b/main.c
@@ -1,14 +1,21 @@
-/*	$OpenBSD: main.c,v 1.55 2015/02/09 09:09:30 jsg Exp $	*/
+/*	$OpenBSD: main.c,v 1.83 2017/08/11 23:10:55 guenther Exp $	*/
 
 /*
  * startup, main loop, environments and error handling
  */
 
-#define	EXTERN				/* define EXTERNs in sh.h */
-
-#include "sh.h"
 #include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
 #include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sh.h"
 
 extern char **environ;
 
@@ -21,6 +28,51 @@ static void	remove_temps(struct temp *tp);
 static int	is_restricted(char *name);
 static void	init_username(void);
 
+const char *kshname;
+pid_t	kshpid;
+pid_t	procpid;
+uid_t	ksheuid;
+int	exstat;
+int	subst_exstat;
+const char *safe_prompt;
+
+Area	aperm;
+
+struct env	*genv;
+
+char	shell_flags[FNFLAGS];
+
+char	null[] = "";
+
+int shl_stdout_ok;
+
+unsigned int	ksh_tmout;
+enum tmout_enum	ksh_tmout_state = TMOUT_EXECUTING;
+
+int	really_exit;
+
+int ifs0 = ' ';
+
+volatile sig_atomic_t	trap;
+volatile sig_atomic_t	intrsig;
+volatile sig_atomic_t	fatal_trap;
+
+Getopt	builtin_opt;
+Getopt	user_opt;
+
+struct coproc	coproc;
+sigset_t	sm_default, sm_sigchld;
+
+char	*builtin_argv0;
+int	 builtin_flag;
+
+char	*current_wd;
+int	 current_wd_size;
+
+#ifdef EDIT
+int	x_cols = 80;
+#endif /* EDIT */
+
 /*
  * shell initialization
  */
@@ -32,7 +84,7 @@ 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", "-ir", "PPID", NULL,
 	"typeset", "-i", "OPTIND=1", NULL,
 	"eval", "typeset -i RANDOM MAILCHECK=\"${MAILCHECK-600}\" SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"", NULL,
 	"alias",
@@ -50,7 +102,7 @@ static const char *initcoms [] = {
 	  "integer=typeset -i",
 	  "nohup=nohup ",
 	  "local=typeset",
-	  "r=fc -e -",
+	  "r=fc -s",
 	 /* Aliases that are builtin commands in at&t */
 	  "login=exec login",
 	  NULL,
@@ -68,22 +120,20 @@ char username[_PW_NAME_LEN + 1];
 
 /* The shell uses its own variation on argv, to build variables like
  * $0 and $@.
- * If we need to alter argv, allocate a new array first since
- * modifying the original argv will modify ps output.
+ * Allocate a new array since modifying the original argv will modify
+ * ps output.
  */
 static char **
 make_argv(int argc, char *argv[])
 {
 	int i;
-	char **nargv = argv;
-
-	if (strcmp(argv[0], kshname) != 0) {
-		nargv = alloc(sizeof(char *) * (argc + 1), &aperm);
-		nargv[0] = (char *) kshname;
-		for (i = 1; i < argc; i++)
-			nargv[i] = argv[i];
-		nargv[i] = NULL;
-	}
+	char **nargv;
+
+	nargv = areallocarray(NULL, argc + 1, sizeof(char *), &aperm);
+	nargv[0] = (char *) kshname;
+	for (i = 1; i < argc; i++)
+		nargv[i] = argv[i];
+	nargv[i] = NULL;
 
 	return nargv;
 }
@@ -100,16 +150,15 @@ main(int argc, char *argv[])
 	struct env env;
 	pid_t ppid;
 
-	/* make sure argv[] is sane */
-	if (!*argv) {
-		static const char *empty_argv[] = {
-			"ksh", (char *) 0
-		};
+	kshname = argv[0];
 
-		argv = (char **) empty_argv;
-		argc = 1;
+#ifdef __OpenBSD__
+	if (pledge("stdio rpath wpath cpath fattr flock getpw proc exec tty",
+	    NULL) == -1) {
+		perror("pledge");
+		exit(1);
 	}
-	kshname = *argv;
+#endif
 
 	ainit(&aperm);		/* initialize permanent Area */
 
@@ -117,7 +166,7 @@ main(int argc, char *argv[])
 	memset(&env, 0, sizeof(env));
 	env.type = E_NONE;
 	ainit(&env.area);
-	e = &env;
+	genv = &env;
 	newblock();		/* set up global l->vars and l->funs */
 
 	/* Do this first so output routines (eg, errorf, shellf) can work */
@@ -150,7 +199,7 @@ main(int argc, char *argv[])
 
 	def_path = _PATH_DEFPATH;
 	{
-		size_t len = confstr(_CS_PATH, (char *) 0, 0);
+		size_t len = confstr(_CS_PATH, NULL, 0);
 		char *new;
 
 		if (len > 0) {
@@ -236,7 +285,7 @@ main(int argc, char *argv[])
 		    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;
+			pwdx = NULL;
 		set_current_wd(pwdx);
 		if (current_wd[0])
 			simplify_path(current_wd);
@@ -266,14 +315,11 @@ main(int argc, char *argv[])
 	{
 		struct tbl *vp = global("PS1");
 
-		/* Set PS1 if it isn't set, or we are root and prompt doesn't
-		 * contain a # or \$ (only in ksh mode).
-		 */
-		if (!(vp->flag & ISSET) ||
-		    (!ksheuid && !strchr(str_val(vp), '#') &&
-		    (Flag(FSH) || !strstr(str_val(vp), "\\$"))))
+		/* Set PS1 if it isn't set */
+		if (!(vp->flag & ISSET)) {
 			/* setstr can't fail here */
 			setstr(vp, safe_prompt, KSH_RETURN_ERROR);
+		}
 	}
 
 	/* Set this before parsing arguments */
@@ -281,7 +327,7 @@ main(int argc, char *argv[])
 
 	/* this to note if monitor is set on command line (see below) */
 	Flag(FMONITOR) = 127;
-	argi = parse_args(argv, OF_CMDLINE, (int *) 0);
+	argi = parse_args(argv, OF_CMDLINE, NULL);
 	if (argi < 0)
 		exit(1);
 
@@ -304,14 +350,13 @@ main(int argc, char *argv[])
 		Flag(FSTDIN) = 1;
 		s = pushs(SSTDIN, ATEMP);
 		s->file = "<stdin>";
-		s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0),
-		    (struct shf *) 0);
+		s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0), NULL);
 		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;
+			s->file = NULL;
 		}
 	}
 
@@ -334,7 +379,7 @@ main(int argc, char *argv[])
 		x_init();
 #endif
 
-	l = e->loc;
+	l = genv->loc;
 	l->argv = make_argv(argc - (argi - 1), &argv[argi - 1]);
 	l->argc = argc - argi;
 	getopts_reset(1);
@@ -352,14 +397,13 @@ main(int argc, char *argv[])
 		warningf(false, "Cannot determine current working directory");
 
 	if (Flag(FLOGIN)) {
-		include(KSH_SYSTEM_PROFILE, 0, (char **) 0, 1);
+		include(KSH_SYSTEM_PROFILE, 0, NULL, 1);
 		if (!Flag(FPRIVILEGED))
-			include(substitute("$HOME/.profile", 0), 0,
-			    (char **) 0, 1);
+			include(substitute("$HOME/.profile", 0), 0, NULL, 1);
 	}
 
 	if (Flag(FPRIVILEGED))
-		include("/etc/suid_profile", 0, (char **) 0, 1);
+		include("/etc/suid_profile", 0, NULL, 1);
 	else if (Flag(FTALKING)) {
 		char *env_file;
 
@@ -373,7 +417,7 @@ main(int argc, char *argv[])
 #endif /* DEFAULT_ENV */
 		env_file = substitute(env_file, DOTILDE);
 		if (*env_file != '\0')
-			include(env_file, 0, (char **) 0, 1);
+			include(env_file, 0, NULL, 1);
 	}
 
 	if (is_restricted(argv[0]) || is_restricted(str_val(global("SHELL"))))
@@ -382,7 +426,7 @@ main(int argc, char *argv[])
 		static const char *const restr_com[] = {
 			"typeset", "-r", "PATH",
 			"ENV", "SHELL",
-			(char *) 0
+			NULL
 		};
 		shcomexec((char **) restr_com);
 		/* After typeset command... */
@@ -429,19 +473,19 @@ include(const char *name, int argc, char **argv, int intr_ok)
 		return -1;
 
 	if (argv) {
-		old_argv = e->loc->argv;
-		old_argc = e->loc->argc;
+		old_argv = genv->loc->argv;
+		old_argc = genv->loc->argc;
 	} else {
-		old_argv = (char **) 0;
+		old_argv = NULL;
 		old_argc = 0;
 	}
 	newenv(E_INCL);
-	i = sigsetjmp(e->jbuf, 0);
+	i = sigsetjmp(genv->jbuf, 0);
 	if (i) {
 		quitenv(s ? s->u.shf : NULL);
 		if (old_argv) {
-			e->loc->argv = old_argv;
-			e->loc->argc = old_argc;
+			genv->loc->argv = old_argv;
+			genv->loc->argc = old_argc;
 		}
 		switch (i) {
 		case LRETURN:
@@ -465,8 +509,8 @@ include(const char *name, int argc, char **argv, int intr_ok)
 		}
 	}
 	if (argv) {
-		e->loc->argv = argv;
-		e->loc->argc = argc;
+		genv->loc->argv = argv;
+		genv->loc->argc = argc;
 	}
 	s = pushs(SFILE, ATEMP);
 	s->u.shf = shf;
@@ -474,8 +518,8 @@ include(const char *name, int argc, char **argv, int intr_ok)
 	i = shell(s, false);
 	quitenv(s->u.shf);
 	if (old_argv) {
-		e->loc->argv = old_argv;
-		e->loc->argc = old_argc;
+		genv->loc->argv = old_argv;
+		genv->loc->argc = old_argc;
 	}
 	return i & 0xff;	/* & 0xff to ensure value not -1 */
 }
@@ -511,7 +555,7 @@ shell(Source *volatile s, volatile int toplevel)
 	newenv(E_PARSE);
 	if (interactive)
 		really_exit = 0;
-	i = sigsetjmp(e->jbuf, 0);
+	i = sigsetjmp(genv->jbuf, 0);
 	if (i) {
 		switch (i) {
 		case LINTR: /* we get here if SIGINT not caught or ignored */
@@ -519,7 +563,7 @@ shell(Source *volatile s, volatile int toplevel)
 		case LSHELL:
 			if (interactive) {
 				if (i == LINTR)
-					shellf("%s", newline);
+					shellf("\n");
 				/* Reset any eof that was read as part of a
 				 * multiline command.
 				 */
@@ -622,18 +666,18 @@ unwind(int i)
 		i = LLEAVE;
 	}
 	while (1) {
-		switch (e->type) {
+		switch (genv->type) {
 		case E_PARSE:
 		case E_FUNC:
 		case E_INCL:
 		case E_LOOP:
 		case E_ERRH:
-			siglongjmp(e->jbuf, i);
+			siglongjmp(genv->jbuf, i);
 			/* NOTREACHED */
 
 		case E_NONE:
 			if (i == LINTR)
-				e->flags |= EF_FAKE_SIGDIE;
+				genv->flags |= EF_FAKE_SIGDIE;
 			/* FALLTHROUGH */
 
 		default:
@@ -654,21 +698,21 @@ newenv(int type)
 {
 	struct env *ep;
 
-	ep = (struct env *) alloc(sizeof(*ep), ATEMP);
+	ep = alloc(sizeof(*ep), ATEMP);
 	ep->type = type;
 	ep->flags = 0;
 	ainit(&ep->area);
-	ep->loc = e->loc;
+	ep->loc = genv->loc;
 	ep->savefd = NULL;
-	ep->oenv = e;
+	ep->oenv = genv;
 	ep->temps = NULL;
-	e = ep;
+	genv = ep;
 }
 
 void
 quitenv(struct shf *shf)
 {
-	struct env *ep = e;
+	struct env *ep = genv;
 	int fd;
 
 	if (ep->oenv && ep->oenv->loc != ep->loc)
@@ -715,7 +759,7 @@ quitenv(struct shf *shf)
 		shf_close(shf);
 	reclaim();
 
-	e = e->oenv;
+	genv = genv->oenv;
 	afree(ep, ATEMP);
 }
 
@@ -732,16 +776,16 @@ cleanup_parents_env(void)
 	 */
 
 	/* close all file descriptors hiding in savefd */
-	for (ep = e; ep; ep = ep->oenv) {
+	for (ep = genv; 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;
+			ep->savefd = NULL;
 		}
 	}
-	e->oenv = (struct env *) 0;
+	genv->oenv = NULL;
 }
 
 /* Called just before an execve cleanup stuff temporary files */
@@ -750,7 +794,7 @@ cleanup_proc_env(void)
 {
 	struct env *ep;
 
-	for (ep = e; ep; ep = ep->oenv)
+	for (ep = genv; ep; ep = ep->oenv)
 		remove_temps(ep->temps);
 }
 
@@ -758,9 +802,9 @@ cleanup_proc_env(void)
 static void
 reclaim(void)
 {
-	remove_temps(e->temps);
-	e->temps = NULL;
-	afreeall(&e->area);
+	remove_temps(genv->temps);
+	genv->temps = NULL;
+	afreeall(&genv->area);
 }
 
 static void
diff --git a/misc.c b/misc.c
@@ -1,11 +1,18 @@
-/*	$OpenBSD: misc.c,v 1.40 2015/03/18 15:12:36 tedu Exp $	*/
+/*	$OpenBSD: misc.c,v 1.59 2017/08/30 17:15:36 jca Exp $	*/
 
 /*
  * Miscellaneous functions
  */
 
-#include "sh.h"
 #include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sh.h"
 #ifdef __OpenBSD__
 #include "charclass.h"
 #else
@@ -45,7 +52,6 @@ initctypes(void)
 	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);
@@ -123,11 +129,11 @@ const struct option options[] = {
 	{ "braceexpand",  0,		OF_ANY }, /* non-standard */
 #endif
 	{ "bgnice",	  0,		OF_ANY },
-	{ (char *) 0,	'c',	    OF_CMDLINE },
+	{ NULL,	'c',	    OF_CMDLINE },
 	{ "csh-history",  0,		OF_ANY }, /* non-standard */
 #ifdef EMACS
 	{ "emacs",	  0,		OF_ANY },
-	{ "emacs-usemeta",  0,		OF_ANY }, /* non-standard */
+	{ "emacs-usemeta",  0,		OF_ANY }, /* XXX delete after 6.2 */
 #endif
 	{ "errexit",	'e',		OF_ANY },
 #ifdef EMACS
@@ -141,7 +147,7 @@ const struct option options[] = {
 #ifdef JOBS
 	{ "monitor",	'm',		OF_ANY },
 #else /* JOBS */
-	{ (char *) 0,	'm',		     0 }, /* so FMONITOR not ifdef'd */
+	{ NULL,	'm',		     0 }, /* so FMONITOR not ifdef'd */
 #endif /* JOBS */
 	{ "noclobber",	'C',		OF_ANY },
 	{ "noexec",	'n',		OF_ANY },
@@ -171,7 +177,7 @@ const struct option options[] = {
 	/* Anonymous flags: used internally by shell only
 	 * (not visible to user)
 	 */
-	{ (char *) 0,	0,		OF_INTERNAL }, /* FTALKING_I */
+	{ NULL,	0,		OF_INTERNAL }, /* FTALKING_I */
 };
 
 /*
@@ -183,8 +189,13 @@ option(const char *n)
 	int i;
 
 	for (i = 0; i < NELEM(options); i++)
-		if (options[i].name && strcmp(options[i].name, n) == 0)
+		if (options[i].name && strcmp(options[i].name, n) == 0) {
+#ifdef EMACS
+			if (i == FEMACSUSEMETA)
+				warningf(true, "%s: deprecated option", n);
+#endif
 			return i;
+		}
 
 	return -1;
 }
@@ -224,7 +235,11 @@ printoptions(int verbose)
 		/* verbose version */
 		shprintf("Current option settings\n");
 
-		for (i = n = oi.opt_width = 0; i < NELEM(options); i++)
+		for (i = n = oi.opt_width = 0; i < NELEM(options); i++) {
+#ifdef EMACS
+			if (i == FEMACSUSEMETA)
+				continue;
+#endif
 			if (options[i].name) {
 				len = strlen(options[i].name);
 				oi.opts[n].name = options[i].name;
@@ -232,15 +247,23 @@ printoptions(int verbose)
 				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("%s", newline);
+		for (i = 0; i < NELEM(options); i++) {
+#ifdef EMACS
+			if (i == FEMACSUSEMETA)
+				continue;
+#endif
+			if (options[i].name)
+				shprintf(" %co %s",
+					 Flag(i) ? '-' : '+',
+					 options[i].name);
+		}
+		shprintf("\n");
 	}
 }
 
@@ -326,7 +349,7 @@ parse_args(char **argv,
 	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;
+	char *array = NULL;
 	Getopt go;
 	int i, optc, set, sortargs = 0, arrayset = 0;
 
@@ -372,7 +395,7 @@ parse_args(char **argv,
 			break;
 
 		case 'o':
-			if (go.optarg == (char *) 0) {
+			if (go.optarg == NULL) {
 				/* lone -o: print options
 				 *
 				 * Note that on the command line, -o requires
@@ -506,7 +529,7 @@ gmatch(const char *s, const char *p, int isfile)
 		int len = pe - p + 1;
 		char tbuf[64];
 		char *t = len <= sizeof(tbuf) ? tbuf :
-		    (char *) alloc(len, ATEMP);
+		    alloc(len, ATEMP);
 		debunk(t, p, len);
 		return !strcmp(t, s);
 	}
@@ -549,7 +572,7 @@ has_globbing(const char *xp, const char *xpe)
 			if (!in_bracket) {
 				saw_glob = 1;
 				in_bracket = 1;
-				if (ISMAGIC(p[1]) && p[2] == NOT)
+				if (ISMAGIC(p[1]) && p[2] == '!')
 					p += 2;
 				if (ISMAGIC(p[1]) && p[2] == ']')
 					p += 2;
@@ -715,7 +738,7 @@ posix_cclass(const unsigned char *pattern, int test, const unsigned char **ep)
 	size_t len;
 	int rval = 0;
 
-	if ((colon = ((const unsigned char *)strchr((const char *)pattern, ':'))) == NULL || colon[1] != MAGIC) {
+	if ((colon = strchr(pattern, ':')) == NULL || colon[1] != MAGIC) {
 		*ep = pattern - 2;
 		return -1;
 	}
@@ -723,7 +746,7 @@ posix_cclass(const unsigned char *pattern, int test, const unsigned char **ep)
 	len = (size_t)(colon - pattern);
 
 	for (cc = cclasses; cc->name != NULL; cc++) {
-		if (!strncmp((const char *)pattern, cc->name, len) && cc->name[len] == '\0') {
+		if (!strncmp(pattern, cc->name, len) && cc->name[len] == '\0') {
 			if (cc->isctype(test))
 				rval = 1;
 			break;
@@ -741,15 +764,15 @@ cclass(const unsigned char *p, int sub)
 	int c, d, rv, not, found = 0;
 	const unsigned char *orig_p = p;
 
-	if ((not = (ISMAGIC(*p) && *++p == NOT)))
+	if ((not = (ISMAGIC(*p) && *++p == '!')))
 		p++;
 	do {
 		/* check for POSIX character class (e.g. [[:alpha:]]) */
 		if ((p[0] == MAGIC && p[1] == '[' && p[2] == ':') ||
 		    (p[0] == '[' && p[1] == ':')) {
 			do {
-				const char *pp = (const char *)p + (*p == MAGIC) + 2;
-				rv = posix_cclass((const unsigned char *)pp, sub, &p);
+				const char *pp = p + (*p == MAGIC) + 2;
+				rv = posix_cclass(pp, sub, &p);
 				switch (rv) {
 				case 1:
 					found = 1;
@@ -811,7 +834,7 @@ pat_scan(const unsigned char *p, const unsigned char *pe, int match_sep)
 		if ((*p & 0x80) && strchr("*+?@! ", *p & 0x7f))
 			nest++;
 	}
-	return (const unsigned char *) 0;
+	return NULL;
 }
 
 /*
@@ -836,7 +859,7 @@ void
 ksh_getopt_reset(Getopt *go, int flags)
 {
 	go->optind = 1;
-	go->optarg = (char *) 0;
+	go->optarg = NULL;
 	go->p = 0;
 	go->flags = flags;
 	go->info = 0;
@@ -884,7 +907,7 @@ ksh_getopt(char **argv, Getopt *go, const char *options)
 			go->info |= GI_MINUSMINUS;
 			return -1;
 		}
-		if (arg == (char *) 0 ||
+		if (arg == NULL ||
 		    ((flag != '-' ) && /* neither a - nor a + (if + allowed) */
 		    (!(go->flags & GF_PLUSOPT) || flag != '+')) ||
 		    (c = arg[1]) == '\0') {
@@ -906,7 +929,7 @@ ksh_getopt(char **argv, Getopt *go, const char *options)
 			    (go->flags & GF_NONAME) ? "" : argv[0],
 			    (go->flags & GF_NONAME) ? "" : ": ", c);
 			if (go->flags & GF_ERROR)
-				bi_errorf("%s", null);
+				bi_errorf(NULL);
 		}
 		return '?';
 	}
@@ -921,7 +944,7 @@ ksh_getopt(char **argv, Getopt *go, const char *options)
 		else if (argv[go->optind])
 			go->optarg = argv[go->optind++];
 		else if (*o == ';')
-			go->optarg = (char *) 0;
+			go->optarg = NULL;
 		else {
 			if (options[0] == ':') {
 				go->buf[0] = c;
@@ -932,7 +955,7 @@ ksh_getopt(char **argv, Getopt *go, const char *options)
 			    (go->flags & GF_NONAME) ? "" : argv[0],
 			    (go->flags & GF_NONAME) ? "" : ": ", c);
 			if (go->flags & GF_ERROR)
-				bi_errorf("%s", null);
+				bi_errorf(NULL);
 			return '?';
 		}
 		go->p = 0;
@@ -951,14 +974,14 @@ ksh_getopt(char **argv, Getopt *go, const char *options)
 				go->optarg = argv[go->optind - 1] + go->p;
 				go->p = 0;
 			} else
-				go->optarg = (char *) 0;
+				go->optarg = NULL;
 		} else {
 			if (argv[go->optind] && (digit(argv[go->optind][0]) ||
 			    !strcmp(argv[go->optind], "unlimited"))) {
 				go->optarg = argv[go->optind++];
 				go->p = 0;
 			} else
-				go->optarg = (char *) 0;
+				go->optarg = NULL;
 		}
 	}
 	return c;
@@ -984,7 +1007,7 @@ print_value_quoted(const char *s)
 	}
 	for (p = s; *p; p++) {
 		if (*p == '\'') {
-			shprintf("%s", "'\\'" + 1 - inquote);
+			shprintf(inquote ? "'\\'" : "\\'");
 			inquote = 0;
 		} else {
 			if (!inquote) {
@@ -1005,7 +1028,7 @@ 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);
+	char *str = alloc(max_width + 1, ATEMP);
 	int i;
 	int r, c;
 	int rows, cols;
@@ -1043,7 +1066,7 @@ print_columns(struct shf *shf, int n, char *(*func) (void *, int, char *, int),
 				    col_width,
 				    (*func)(arg, i, str, max_width + 1));
 				if (c + 1 < cols)
-					shf_fprintf(shf, "%*s", nspace, null);
+					shf_fprintf(shf, "%*s", nspace, "");
 			}
 		}
 		shf_putchar('\n', shf);
@@ -1109,7 +1132,7 @@ reset_nonblock(int fd)
 {
 	int flags;
 
-	if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
+	if ((flags = fcntl(fd, F_GETFL)) < 0)
 		return -1;
 	if (!(flags & O_NONBLOCK))
 		return 0;
diff --git a/mknod.c b/mknod.c
@@ -1,91 +0,0 @@
-/*	$OpenBSD: mknod.c,v 1.2 2009/10/27 23:59:21 deraadt 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.
- */
-
-#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);
-}
-
diff --git a/oksh.1 b/oksh.1
@@ -1,19 +1,20 @@
-.\"	$OpenBSD: ksh.1,v 1.159 2015/03/25 12:10:52 jca Exp $
+.\"	$OpenBSD: ksh.1,v 1.195 2017/08/30 17:08:45 jca Exp $
 .\"
 .\"	Public Domain
 .\"
-.Dd $Mdocdate: March 25 2015 $
+.Dd $Mdocdate: August 30 2017 $
 .Dt OKSH 1
 .Os
 .Sh NAME
-.Nm oksh
+.Nm oksh ,
+.Nm rksh
 .Nd public domain Korn shell
 .Sh SYNOPSIS
 .Nm oksh
 .Bk -words
 .Op Fl +abCefhiklmnpruvXx
 .Op Fl +o Ar option
-.Op Fl c Ar string \*(Ba Fl s \*(Ba Ar file Op Ar argument ...
+.Op Fl c Ar string | Fl s | Ar file Op Ar argument ...
 .Ek
 .Sh DESCRIPTION
 .Nm
@@ -123,10 +124,10 @@ option of the built-in 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 ) .
+.Sq Cm > ,
+.Sq Cm >| ,
+.Sq Cm >> ,
+.Sq Cm <> ) .
 .El
 .It Fl s
 The shell reads commands from standard input; all non-option arguments
@@ -205,9 +206,9 @@ The shell begins parsing its input by breaking it into
 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 | ,
 .Ql \&; ,
 .Ql \&( ,
 .Ql \&) ,
@@ -218,18 +219,18 @@ 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 ,
+.Sq Cm < ,
+.Sq Cm <& ,
+.Sq Cm << ,
+.Sq Cm > ,
+.Sq Cm >& ,
+.Sq Cm >> ,
 etc. are used to specify redirections (see
 .Sx Input/output redirection
 below);
-.Ql \*(Ba
+.Ql |
 is used to create pipelines;
-.Ql \*(Ba&
+.Ql |&
 is used to create co-processes (see
 .Sx Co-processes
 below);
@@ -258,7 +259,7 @@ or in groups using double
 or single
 .Pq Sq '
 quotes.
-Note that the following characters are also treated specially by the
+The following characters are also treated specially by the
 shell and must be quoted if they are to represent themselves:
 .Ql \e ,
 .Ql \&" ,
@@ -298,7 +299,7 @@ and
 .Ql }
 delimit
 .Xr csh 1 Ns -style
-alterations (see
+alternations (see
 .Sx Brace expansion
 below);
 and finally,
@@ -339,11 +340,14 @@ or an external command
 parameter; see
 .Sx Command execution
 below).
-Note that all command constructs have an exit status: for external commands,
+.Pp
+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
+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.
@@ -395,7 +399,7 @@ have equal precedence which is higher than that of
 and
 .Ql \&; ,
 which also have equal precedence.
-Note that the
+The
 .Ql &&
 and
 .Ql ||
@@ -429,7 +433,7 @@ 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
+A command must follow the
 .Ql &&
 and
 .Ql ||
@@ -470,7 +474,7 @@ 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<newline> }
 $ { { echo foo; echo bar; } }
 .Ed
 .Pp
@@ -493,12 +497,12 @@ Note that
 and
 .Ql }
 are reserved words, not meta-characters.
-.It Xo case Ar word No in
+.It Xo Ic case Ar word Cm in
 .Oo Op \&(
 .Ar pattern
 .Op | Ar pattern
 .No ... )
-.Ar list No ;;\ \& Oc ... esac
+.Ar list No ;;\ \& Oc ... Cm esac
 .Xc
 The
 .Ic case
@@ -523,9 +527,9 @@ 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
+.Cm in
 and
-.Ic esac
+.Cm esac
 e.g.\&
 .Ic case $foo { *) echo bar; } .
 The exit status of a
@@ -535,9 +539,9 @@ statement is that of the executed
 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
+.It Xo Ic for Ar name
+.Oo Cm in Ar word No ... Oc ;
+.Cm do Ar list ; Cm done
 .Xc
 For each
 .Ar word
@@ -547,14 +551,14 @@ is set to the word and
 .Ar list
 is executed.
 If
-.Ic in
+.Cm 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
+.Cm do
 and
-.Ic done
+.Cm done
 e.g.\&
 .Ic for i; { echo $i; } .
 The exit status of a
@@ -564,13 +568,12 @@ statement is the last exit status of
 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
+.It Xo Ic if Ar list ;
+.Cm then Ar list ;
+.Oo Cm elif Ar list ;
+.Cm then Ar list ; Oc ...
+.Oo Cm else Ar list ; Oc
+.Cm fi
 .Xc
 If the exit status of the first
 .Ar list
@@ -579,16 +582,16 @@ is zero, the second
 is executed; otherwise, the
 .Ar list
 following the
-.Ic elif ,
+.Cm elif ,
 if any, is executed with similar consequences.
 If all the lists following the
 .Ic if
 and
-.Ic elif Ns s
+.Cm elif Ns s
 fail (i.e. exit with non-zero status), the
 .Ar list
 following the
-.Ic else
+.Cm else
 is executed.
 The exit status of an
 .Ic if
@@ -597,9 +600,9 @@ statement is that of non-conditional
 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
+.It Xo Ic select Ar name
+.Oo Cm in Ar word No ... Oc ;
+.Cm do Ar list ; Cm done
 .Xc
 The
 .Ic select
@@ -609,7 +612,8 @@ An enumerated list of the specified
 .Ar word Ns (s)
 is printed on standard error, followed by a prompt
 .Po
-.Ev PS3: normally
+.Ev PS3 :
+normally
 .Sq #?\ \&
 .Pc .
 A number corresponding to one of the enumerated words is then read from
@@ -641,9 +645,9 @@ If
 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
+.Cm do
 and
-.Ic done
+.Cm done
 e.g.\&
 .Ic select i; { echo $i; } .
 The exit status of a
@@ -651,18 +655,18 @@ The exit status of a
 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
+.It Xo Ic until Ar list ;
+.Cm do Ar list ;
+.Cm 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
+.It Xo Ic while Ar list ;
+.Cm do Ar list ;
+.Cm done
 .Xc
 A
 .Ic while
@@ -675,7 +679,7 @@ The exit status of a
 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
+.It Xo Ic function Ar name
 .No { Ar list ; No }
 .Xc
 Defines the function
@@ -700,21 +704,21 @@ The
 reserved word is described in the
 .Sx Command execution
 section.
-.It (( Ar expression No ))
+.It Ic (( Ar expression Cm ))
 The arithmetic expression
 .Ar expression
 is evaluated; equivalent to
-.Dq let expression
+.Ic let Ar expression
 (see
 .Sx Arithmetic expressions
 and the
 .Ic let
 command, below).
-.It Bq Bq Ar \ \&expression\ \&
+.It Ic [[ Ar expression Cm ]]
 Similar to the
 .Ic test
 and
-.Ic \&[ ... \&]
+.Ic \&[ No ... Cm \&]
 commands (described later), with the following exceptions:
 .Bl -bullet -offset indent
 .It
@@ -747,9 +751,9 @@ expressions are patterns (e.g. the comparison
 succeeds).
 .It
 There are two additional binary operators,
-.Ql \*(Lt
+.Ql <
 and
-.Ql \*(Gt ,
+.Ql > ,
 which return true if their first string operand is less than, or greater than,
 their second string operand, respectively.
 .It
@@ -768,12 +772,12 @@ and
 .Ql ||
 operators.
 This means that in the following statement,
-.Ic $(\*(Lt foo)
+.Ic $(< 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 ]]
+$ [[ -r foo && $(< foo) = b*r ]]
 .Ed
 .El
 .El
@@ -818,12 +822,6 @@ the
 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
@@ -838,19 +836,31 @@ 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'
-type='whence -v'
-.Ed
+.Pp
+.Bl -item -compact -offset indent
+.It
+.Ic autoload Ns ='typeset -fu'
+.It
+.Ic functions Ns ='typeset -f'
+.It
+.Ic hash Ns ='alias -t'
+.It
+.Ic history Ns ='fc -l'
+.It
+.Ic integer Ns ='typeset -i'
+.It
+.Ic local Ns ='typeset'
+.It
+.Ic login Ns ='exec login'
+.It
+.Ic nohup Ns ='nohup '
+.It
+.Ic r Ns ='fc -s'
+.It
+.Ic stop Ns ='kill -STOP'
+.It
+.Ic type Ns ='whence -v'
+.El
 .Pp
 Tracked aliases allow the shell to remember where it found a particular
 command.
@@ -880,7 +890,7 @@ automatically tracked:
 .Xr cp 1 ,
 .Xr date 1 ,
 .Xr ed 1 ,
-.Xr emacs 1 ,
+.Sy emacs ,
 .Xr grep 1 ,
 .Xr ls 1 ,
 .Xr mail 1 ,
@@ -900,15 +910,15 @@ 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
+.Pf $ Ar name
 or
-.Pf ${ Ns Ar ... Ns } ;
+.Pf ${ Ar ... Ns } ;
 command substitutions take the form
-.Pf $( Ns Ar command Ns \&)
+.Pf $( Ar command )
 or
-.Pf ` Ns Ar command Ns ` ;
+.Pf ` Ar command Ns ` ;
 and arithmetic substitutions take the form
-.Pf $(( Ns Ar expression Ns )) .
+.Pf $(( Ar expression ) ) .
 .Pp
 If a substitution appears outside of double quotes, the results of the
 substitution are generally subject to word or field splitting according to
@@ -939,9 +949,9 @@ whitespace does create an empty field.
 Example: If
 .Ev IFS
 is set to
-.Dq \*(Ltspace\*(Gt: ,
+.Dq <space>: ,
 and VAR is set to
-.Dq \*(Ltspace\*(GtA\*(Ltspace\*(Gt:\*(Ltspace\*(Gt\*(Ltspace\*(GtB::D ,
+.Dq <space>A<space>:<space><space>B::D ,
 the substitution for $VAR results in four fields:
 .Sq A ,
 .Sq B ,
@@ -984,11 +994,11 @@ brace expansion and file name expansion (see the relevant sections below).
 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 \&)
+.Pf $( Ar command )
 substitutions, normal quoting rules are used when
 .Ar command
 is parsed; however, for the
-.Pf ` Ns Ar command Ns `
+.Pf ` Ar command Ns `
 form, a
 .Ql \e
 followed by any of
@@ -1000,21 +1010,15 @@ 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
+.Pf < Ar file
 is interpreted to mean substitute the contents of
 .Ar file .
 Note that
-.Ic $(\*(Lt foo)
+.Ic $(< 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))
@@ -1039,11 +1043,11 @@ where
 .Ar expr
 is an arithmetic expression.
 Parameter substitutions take the form
-.Pf $ Ns Ar name ,
-.Pf ${ Ns Ar name Ns } ,
+.Pf $ Ar name ,
+.Pf ${ Ar name Ns } ,
 or
 .Sm off
-.Pf ${ Ar name Oo Ar expr Oc }
+.Pf ${ Ar name Bo Ar expr Bc }
 .Sm on
 where
 .Ar name
@@ -1115,9 +1119,7 @@ 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
+.Pf ${ Ar name Ns = Ns Ar value Ns }
 form of the parameter substitution (see below).
 .Pp
 Parameters with the export attribute (set using the
@@ -1137,7 +1139,7 @@ from its environment and automatically sets the export attribute for those
 parameters.
 .Pp
 Modifiers can be applied to the
-.Pf ${ Ns Ar name Ns }
+.Pf ${ Ar name Ns }
 form of parameter substitution:
 .Bl -tag -width Ds
 .Sm off
@@ -1209,7 +1211,7 @@ is not needed, it is not evaluated.
 The following forms of parameter substitution can also be used:
 .Pp
 .Bl -tag -width Ds -compact
-.It Pf ${# Ns Ar name Ns \&}
+.It Pf ${# Ar name Ns }
 The number of positional parameters if
 .Ar name
 is
@@ -1218,21 +1220,13 @@ is
 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 [@]}
+.It Pf ${# Ar name Ns [*]}
+.It Pf ${# 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
+.It Pf ${ Ar name Ns # Ns Ar pattern Ns }
+.It Pf ${ Ar name Ns ## Ns Ar pattern Ns }
 If
 .Ar pattern
 matches the beginning of the value of parameter
@@ -1243,16 +1237,8 @@ A single
 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
+.It Pf ${ Ar name Ns % Ns Ar pattern Ns }
+.It Pf ${ Ar name Ns %% Ns Ar pattern Ns }
 Like ${..#..} substitution, but it deletes from the end of the value.
 .El
 .Pp
@@ -1400,12 +1386,6 @@ is set, it overrides
 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
@@ -1427,6 +1407,15 @@ It is also searched when a command can't be found using
 See
 .Sx Functions
 below for more information.
+.It Ev HISTCONTROL
+A colon separated list of history settings.
+If
+.Li ignoredups
+is present, lines identical to the previous history line will not be saved.
+If
+.Li ignorespace
+is present, lines starting with a space will not be saved.
+Unknown settings are ignored.
 .It Ev HISTFILE
 The name of the file used to store command history.
 When assigned to, history is loaded from the specified file.
@@ -1440,10 +1429,7 @@ 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.
+.Pa $HOME/.sh_history .
 .It Ev HISTSIZE
 The number of commands normally stored for history.
 The default is 500.
@@ -1558,15 +1544,6 @@ The default prompt is
 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:
@@ -1579,7 +1556,7 @@ The current date, in the format
 .Dq Day Month Date
 for example
 .Dq Wed Nov 03 .
-.It Li \eD{ Ns Ar format Ns Li }
+.It Li \eD Ns Brq Ar format
 The current date, with
 .Ar format
 converted by
@@ -1651,11 +1628,11 @@ if
 .Ev HISTFILE
 contains a history list from a previous session.
 .It Li \e$
-The default prompt i.e.\&
-.Sq # \&
+The default prompt character i.e.\&
+.Sq #
 if the effective UID is 0,
 otherwise
-.Sq $ \& .
+.Sq $ .
 Since the shell interprets
 .Sq $
 as a special character within double quotes,
@@ -1690,11 +1667,11 @@ 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 "
+PS1="$x$(print \e\er)$x$(tput so)$x\e$PWD$x$(tput se)$x> "
 .Ed
 .It Ev PS2
 Secondary prompt string, by default
-.Sq \*(Gt\ \& ,
+.Sq >\ \& ,
 used when more input is needed to complete a command.
 .It Ev PS3
 Prompt used by the
@@ -1727,12 +1704,10 @@ 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
+.Xr srand_deterministic 3
 and subsequent references of
 .Ev RANDOM
-will use
-.Xr rand 3
-to produce values, resulting in a predictable sequence.
+produce a predictable sequence.
 .It Ev REPLY
 Default parameter for the
 .Ic read
@@ -1815,7 +1790,7 @@ 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)
+.Ss Brace expansion (alternation)
 Brace expressions take the following form:
 .Bd -unfilled -offset indent
 .Sm off
@@ -1917,7 +1892,7 @@ A character class may not be used as an endpoint of a range.
 Like [..],
 except it matches any character not inside the brackets.
 .Sm off
-.It *( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
+.It *( Ar pattern Ns | No ...| Ar pattern )
 .Sm on
 Matches any string of characters that matches zero or more occurrences of the
 specified patterns.
@@ -1930,7 +1905,7 @@ matches the strings
 .Dq foobarfoo ,
 etc.
 .Sm off
-.It +( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
+.It +( Ar pattern Ns | No ...| Ar pattern )
 .Sm on
 Matches any string of characters that matches one or more occurrences of the
 specified patterns.
@@ -1942,7 +1917,7 @@ matches the strings
 .Dq foobar ,
 etc.
 .Sm off
-.It ?( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
+.It ?( Ar pattern Ns | No ...| Ar pattern )
 .Sm on
 Matches the empty string or a string that matches one of the specified
 patterns.
@@ -1954,7 +1929,7 @@ only matches the strings
 and
 .Dq bar .
 .Sm off
-.It @( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
+.It @( Ar pattern Ns | No ...| Ar pattern )
 .Sm on
 Matches a string that matches one of the specified patterns.
 Example: The pattern
@@ -1964,7 +1939,7 @@ only matches the strings
 and
 .Dq bar .
 .Sm off
-.It !( Ar pattern\*(Ba No ...\*(Ba Ar pattern )
+.It !( Ar pattern Ns | No ...| Ar pattern )
 .Sm on
 Matches any string that does not match one of the specified patterns.
 Examples: The pattern
@@ -1980,17 +1955,12 @@ matches no strings; the pattern
 matches all strings (think about it).
 .El
 .Pp
-Note that
-.Nm pdksh
-currently never matches
+Unlike most shells,
+.Nm ksh
+never matches
 .Sq \&.
 and
-.Sq .. ,
-but the original
-.Nm ksh ,
-Bourne
-.Nm sh ,
-and bash do, so this may have to change (too bad).
+.Sq .. .
 .Pp
 Note that none of the above pattern elements match either a period
 .Pq Sq \&.
@@ -2019,7 +1989,7 @@ 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
+.It Cm > Ar file
 Standard output is redirected to
 .Ar file .
 If
@@ -2028,37 +1998,37 @@ 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
+.Ic cmd < foo > 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
+.It Cm >| Ar file
 Same as
-.Ic \*(Gt ,
+.Cm > ,
 except the file is truncated, even if the
 .Ic noclobber
 option is set.
-.It \*(Gt\*(Gt Ar file
+.It Cm >> Ar file
 Same as
-.Ic \*(Gt ,
+.Cm > ,
 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
+.It Cm < Ar file
 Standard input is redirected from
 .Ar file ,
 which is opened for reading.
-.It \*(Lt\*(Gt Ar file
+.It Cm <> Ar file
 Same as
-.Ic \*(Lt ,
+.Cm < ,
 except the file is opened for reading and writing.
-.It \*(Lt\*(Lt Ar marker
+.It Cm << 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
@@ -2082,11 +2052,11 @@ and
 .Ql \enewline .
 If multiple here documents are used on the same command line, they are saved in
 order.
-.It \*(Lt\*(Lt- Ar marker
+.It Cm <<- Ar marker
 Same as
-.Ic \*(Lt\*(Lt ,
+.Cm << ,
 except leading tabs are stripped from lines in the here document.
-.It \*(Lt& Ar fd
+.It Cm <& Ar fd
 Standard input is duplicated from file descriptor
 .Ar fd .
 .Ar fd
@@ -2097,9 +2067,9 @@ 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
+.It Cm >& Ar fd
 Same as
-.Ic \*(Lt& ,
+.Cm <& ,
 except the operation is done on standard output.
 .El
 .Pp
@@ -2132,7 +2102,7 @@ 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
+.D1 $ cat /foo/bar 2>&1 > /dev/null | cat -n
 .Ss Arithmetic expressions
 Integer arithmetic expressions can be used with the
 .Ic let
@@ -2154,15 +2124,15 @@ Unary operators:
 Binary operators:
 .Bd -literal -offset indent
 ,
-= *= /= %= += -= \*(Lt\*(Lt= \*(Gt\*(Gt= &= ^= \*(Ba=
-\*(Ba\*(Ba
+= *= /= %= += -= <<= >>= &= ^= |=
+||
 &&
-\*(Ba
+|
 ^
 &
 == !=
-\*(Lt \*(Lt= \*(Gt= \*(Gt
-\*(Lt\*(Lt \*(Gt\*(Gt
+< <= >= >
+<< >>
 + -
 * / %
 .Ed
@@ -2227,8 +2197,8 @@ 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=
+.No *= /= += -= <<=
+.No >>= &= ^= |=
 .Xc
 Assignment operators.
 .Sm off
@@ -2252,7 +2222,7 @@ For example,
 .Dq var1 *= 5 + 3
 is the same as specifying
 .Dq var1 = var1 * (5 + 3) .
-.It \*(Ba\*(Ba
+.It ||
 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.
@@ -2260,7 +2230,7 @@ The right argument is evaluated only if the left argument is zero.
 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
+.It |
 Arithmetic (bit-wise) OR.
 .It ^
 Arithmetic (bit-wise) XOR
@@ -2271,14 +2241,14 @@ Arithmetic (bit-wise) AND.
 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
+.It <
 Less than; the result is 1 if the left argument is less than the right, 0 if
 not.
-.It \*(Lt= \*(Gt= \*(Gt
+.It <= >= >
 Less than or equal, greater than or equal, greater than.
 See
-.Ic \*(Lt .
-.It \*(Lt\*(Lt \*(Gt\*(Gt
+.Ic < .
+.It << >>
 Shift left (right); the result is the left argument with its bits shifted left
 (right) by the amount given in the right argument.
 .It + - * /
@@ -2303,25 +2273,25 @@ otherwise the result is
 .El
 .Ss Co-processes
 A co-process, which is a pipeline created with the
-.Sq \*(Ba&
+.Sq |&
 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
+.Cm >&p
 and
-.Ic \*(Lt&p
+.Cm <&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
+.Ic exec Ar n Ns Cm >&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
+.Ic exec Ar n Ns Cm <&p
 redirection.
 .Pp
 Some notes concerning co-processes:
@@ -2330,7 +2300,7 @@ Some notes concerning co-processes:
 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&- .
+.Ic exec 3>&p; exec 3>&- .
 .It
 In order for co-processes to share a common output, the shell must keep the
 write portion of the output pipe open.
@@ -2462,19 +2432,6 @@ 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
@@ -2498,35 +2455,11 @@ The following is a list of things that are affected by the state of the
 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 echo
 options.
@@ -2742,15 +2675,10 @@ Additional
 .Nm
 regular commands
 .Pp
-.Ic \&[ , echo , let , mknod ,
+.Ic \&[ , echo , let ,
 .Ic print , suspend , test ,
 .Ic 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
@@ -2775,7 +2703,7 @@ The null command.
 Exit status is set to zero.
 .Pp
 .It Xo Ic alias
-.Oo Fl d \*(Ba t Oo Fl r Oc \*(Ba
+.Oo Fl d | t Oo Fl r Oc |
 .Cm +-x Oc
 .Op Fl p
 .Op Cm +
@@ -2861,9 +2789,7 @@ for more information.
 .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.
+.Ar string .
 Future input of the
 .Ar string
 will cause the editing command to be immediately invoked.
@@ -2874,10 +2800,23 @@ flag is given, the specified input
 will afterwards be immediately replaced by the given
 .Ar substitute
 string, which may contain editing commands.
+Control characters may be written using caret notation.
+For example, ^X represents Control-X.
 .Pp
-Control characters may be written using caret notation
-i.e. ^X represents Control-X.
-Multi-character sequences are supported.
+If a certain character occurs as the first character of any bound
+multi-character
+.Ar string
+sequence, that character becomes a command prefix character.
+Any character sequence that starts with a command prefix character
+but that is not bound to a command or substitute
+is implicitly considered as bound to the
+.Sq error
+command.
+By default, two command prefix characters exist:
+Escape
+.Pq ^[
+and Control-X
+.Pq ^X .
 .Pp
 The following default bindings show how the arrow keys
 on an ANSI terminal or xterm are bound
@@ -2994,7 +2933,7 @@ is executed exactly as if
 had not been specified, with two exceptions:
 firstly,
 .Ar cmd
-cannot be a shell function;
+cannot be an alias or 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).
@@ -3005,7 +2944,9 @@ 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 ) .
+.Ic getconf PATH ) .
+Nevertheless, reserved words, aliases, shell functions, and
+builtin commands are still found before external commands.
 .Pp
 If the
 .Fl v
@@ -3121,12 +3062,13 @@ A command that exits with a non-zero status.
 .It Xo
 .Ic fc
 .Oo
-.Fl e Ar editor \*(Ba
+.Fl e Ar editor |
 .Fl l Op Fl n
 .Oc
 .Op Fl r
 .Op Ar first Op Ar last
 .Xc
+Fix command.
 .Ar first
 and
 .Ar last
@@ -3154,13 +3096,16 @@ parameter (if this parameter is not set,
 is used), and then executed by the shell.
 .Pp
 .It Xo
-.Ic fc
-.Cm -e - \*(Ba Fl s
+.Ic fc 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
+Re-execute the most recent command beginning with
+.Ar prefix ,
+or the previous command if no
+.Ar prefix
+is specified,
 performing the optional substitution of
 .Ar old
 with
@@ -3171,13 +3116,14 @@ is specified, all occurrences of
 .Ar old
 are replaced with
 .Ar new .
-The meaning of
-.Cm -e -
-and
+The editor is not invoked when the
 .Fl s
-is identical: re-execute the selected command without invoking an editor.
+flag is used.
+The obsolescent equivalent
+.Dq Fl e No -
+is also accepted.
 This command is usually accessed with the predefined
-.Ic alias r='fc -e -' .
+.Ic alias r='fc -s' .
 .Pp
 .It Ic fg Op Ar job ...
 Resume the specified job(s) in the foreground.
@@ -3300,10 +3246,10 @@ and the displayed job.
 .Pp
 .It Xo
 .Ic kill
-.Oo Fl s Ar signame \*(Ba
-.No - Ns Ar signum \*(Ba
+.Oo Fl s Ar signame |
+.No - Ns Ar signum |
 .No - Ns Ar signame Oc
-.No { Ar job \*(Ba pid \*(Ba pgrp No }
+.No { Ar job | pid | pgrp No }
 .Ar ...
 .Xc
 Send the specified signal to the specified jobs, process IDs, or process
@@ -3341,46 +3287,9 @@ is syntactic sugar for
 .No let \&" Ns Ar expr Ns \&" .
 .Pp
 .It Xo
-.Ic mknod
-.Op Fl m Ar mode
-.Ar name
-.Cm b\*(Bac
-.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 nprsu Ns Oo Ar n Oc |
 .Fl R Op Fl en
 .Oc
 .Op Ar argument ...
@@ -3544,7 +3453,7 @@ If used outside of a function or
 script, it has the same effect as
 .Ic exit .
 Note that
-.Nm pdksh
+.Nm ksh
 treats both profile and
 .Ev ENV
 files as
@@ -3590,17 +3499,21 @@ 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
+.It Fl a | Ic allexport
 All new parameters are created with the export attribute.
-.It Fl b \*(Ba Ic notify
+.It Fl b | 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
+.It Fl C | Ic noclobber
+Prevent
+.Cm >
+redirection from overwriting existing files.
+Instead,
+.Cm >|
+must be used to force an overwrite.
+.It Fl e | Ic errexit
 Exit (after executing the
 .Dv ERR
 trap) as soon as an error occurs or a command fails (i.e. exits with a
@@ -3618,28 +3531,28 @@ For
 or
 .Ic || ,
 only the status of the last command is tested.
-.It Fl f \*(Ba Ic noglob
+.It Fl f | Ic noglob
 Do not expand file name patterns.
-.It Fl h \*(Ba Ic trackall
+.It Fl h | 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
+.It Fl k | Ic keyword
 Parameter assignments are recognized anywhere in a command.
-.It Fl m \*(Ba Ic monitor
+.It Fl m | Ic monitor
 Enable job control (default for interactive shells).
-.It Fl n \*(Ba Ic noexec
+.It Fl n | Ic noexec
 Do not execute any commands.
 Useful for checking the syntax of scripts
 (ignored if interactive).
-.It Fl p \*(Ba Ic privileged
+.It Fl p | 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
+.It Fl s | 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
@@ -3653,20 +3566,20 @@ the positional parameters (or to array
 if
 .Fl A
 is used).
-.It Fl u \*(Ba Ic nounset
+.It Fl u | 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
+.It Fl v | Ic verbose
 Write shell input to standard error as it is read.
-.It Fl X \*(Ba Ic markdirs
+.It Fl X | Ic markdirs
 Mark directories with a trailing
 .Ql /
 during file name generation.
-.It Fl x \*(Ba Ic xtrace
+.It Fl x | Ic xtrace
 Print commands and parameter assignments when they are executed, preceded by
 the value of
 .Ev PS4 .
@@ -3683,9 +3596,6 @@ 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
@@ -3709,8 +3619,8 @@ See above for a description of what this means.
 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
+Currently set by default;
+this is different from the original Korn shell (which
 doesn't have this option, but does send the
 .Dv SIGHUP
 signal).
@@ -3780,7 +3690,7 @@ In the original Korn shell, unless
 was set, the vi command-line mode would let the
 .Xr tty 4
 driver do the work until ESC (^[) was entered.
-.Nm pdksh
+.Nm ksh
 is always in viraw mode.
 .El
 .Pp
@@ -3791,7 +3701,8 @@ options (with single letter names) can be found in the parameter
 .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.
+will print the current shell options in a form that
+can be reinput to the shell to achieve the same option settings.
 .Pp
 Remaining arguments, if any, are positional parameters and are assigned, in
 order, to the positional parameters (i.e. $1, $2, etc.).
@@ -4079,8 +3990,8 @@ 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
+.Dl $ time sleep 1 2> afile
+.Dl $ { time sleep 1; } 2> afile
 .Pp
 Times for the first command do not go to
 .Dq afile ,
@@ -4359,6 +4270,7 @@ kilobytes on the amount of locked (wired) physical memory.
 Impose a limit of
 .Ar n
 kilobytes on the amount of physical memory used.
+This limit is not enforced.
 .It Fl n Ar n
 Impose a limit of
 .Ar n
@@ -4493,7 +4405,7 @@ is similar to
 .Ic command Fl v
 except that
 .Ic whence
-will find reserved words and won't print aliases as alias commands.
+won't print aliases as alias commands.
 With the
 .Fl v
 option,
@@ -4558,7 +4470,7 @@ sign
 .Pq Sq % .
 Other percent sequences can also be used to refer to jobs:
 .Bl -tag -width "%+ | %% | %XX"
-.It %+ \*(Ba %% \*(Ba %
+.It %+ | %% | %
 The most recently stopped job or, if there are no stopped jobs, the oldest
 running job.
 .It %-
@@ -4681,10 +4593,10 @@ In these editing modes, if a line is longer than the screen width (see the
 .Ev COLUMNS
 parameter),
 a
-.Ql \*(Gt ,
+.Ql > ,
 .Ql + ,
 or
-.Ql \*(Lt
+.Ql <
 character is displayed in the last column indicating that there are more
 characters after, before and after, or before the current position,
 respectively.
@@ -4714,7 +4626,7 @@ 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 ,
+.Pf ^[ Ar n ,
 where
 .Ar n
 is a sequence of 1 or more digits.
@@ -4759,7 +4671,7 @@ alphanumerics, underscore
 and dollar sign
 .Pq Sq $
 characters.
-.It beginning-of-history: ^[\*(Lt
+.It beginning-of-history: ^[<
 Moves to the beginning of the history.
 .It beginning-of-line: ^A
 Moves the cursor to the beginning of the edited input line.
@@ -4786,6 +4698,24 @@ 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).
+.Pp
+Custom completions may be configured by creating an array named
+.Ql complete_command ,
+optionally suffixed with an argument number to complete only for a single
+argument.
+So defining an array named
+.Ql complete_kill
+provides possible completions for any argument to the
+.Xr kill 1
+command, but
+.Ql complete_kill_1
+only completes the first argument.
+For example, the following command makes
+.Nm
+offer a selection of signal names for the first argument to
+.Xr kill 1 :
+.Pp
+.Dl set -A complete_kill_1 -- -9 -HUP -INFO -KILL -TERM
 .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
@@ -4853,7 +4783,7 @@ has been performed.
 Lowercases the next
 .Ar n
 words.
-.It end-of-history: ^[\*(Gt
+.It end-of-history: ^[>
 Moves to the end of the history.
 .It end-of-line: ^E
 Moves the cursor to the end of the input line.
@@ -4979,14 +4909,6 @@ 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
@@ -5092,7 +5014,7 @@ list of possible completions is displayed; if used a third time, the completion
 is undone.
 .It ^H
 Erases previous character.
-.It ^J \*(Ba ^M
+.It ^J | ^M
 End of line.
 The current line is read, parsed, and executed by the shell.
 .It ^V
@@ -5233,7 +5155,7 @@ 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 .
+.No _ Ns Ar c .
 .El
 .Pp
 Intra-line movement commands:
@@ -5257,7 +5179,7 @@ Move to column 0.
 .It ^
 Move to the first non-whitespace character.
 .It Xo
-.Oo Ar n Oc Ns \*(Ba
+.Oo Ar n Oc Ns |
 .Xc
 Move to column
 .Ar n .
@@ -5642,35 +5564,14 @@ 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@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.
+.Sh BUGS
+.Pf $( Ar command )
+expressions are currently parsed by finding the closest matching (unquoted)
+parenthesis.
+Thus constructs inside
+.Pf $( Ar command )
+may produce an error.
+For example, the parenthesis in
+.Ql x);;
+is interpreted as the closing parenthesis in
+.Ql $(case x in x);; *);; esac) .
diff --git a/path.c b/path.c
@@ -1,8 +1,13 @@
-/*	$OpenBSD: path.c,v 1.12 2005/03/30 17:16:37 deraadt Exp $	*/
+/*	$OpenBSD: path.c,v 1.19 2017/09/03 11:52:01 jca Exp $	*/
 
-#include "sh.h"
 #include <sys/stat.h>
 
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sh.h"
+
 /*
  *	Contains a routine to search a : separated list of
  *	paths (a la CDPATH) and make appropriate file names.
@@ -67,7 +72,7 @@ make_path(const char *cwd, const char *file,
 			for (pend = plist; *pend && *pend != ':'; pend++)
 				;
 			plen = pend - plist;
-			*cdpathp = *pend ? ++pend : (char *) 0;
+			*cdpathp = *pend ? ++pend : NULL;
 		}
 
 		if ((use_cdpath == 0 || !plen || plist[0] != '/') &&
@@ -95,7 +100,7 @@ make_path(const char *cwd, const char *file,
 	memcpy(xp, file, len);
 
 	if (!use_cdpath)
-		*cdpathp = (char *) 0;
+		*cdpathp = NULL;
 
 	return rval;
 }
@@ -116,7 +121,7 @@ simplify_path(char *path)
 	if (!*path)
 		return;
 
-	if ((isrooted = path[0] == '/'))
+	if ((isrooted = (path[0] == '/')))
 		very_start++;
 
 	/* Before			After
@@ -177,7 +182,7 @@ set_current_wd(char *path)
 	int len;
 	char *p = path;
 
-	if (!p && !(p = ksh_get_wd((char *) 0, 0)))
+	if (!p && !(p = ksh_get_wd(NULL, 0)))
 		p = null;
 
 	len = strlen(p) + 1;
@@ -200,7 +205,7 @@ get_phys_path(const char *path)
 	xp = do_phys_path(&xs, xp, path);
 
 	if (!xp)
-		return (char *) 0;
+		return NULL;
 
 	if (Xlength(xs, xp) == 0)
 		Xput(xs, xp, '/');
@@ -215,7 +220,7 @@ do_phys_path(XString *xsp, char *xp, const char *path)
 	const char *p, *q;
 	int len, llen;
 	int savepos;
-	char lbuf[PATH];
+	char lbuf[PATH_MAX];
 
 	Xcheck(*xsp, xp);
 	for (p = path; p; p = q) {
@@ -246,7 +251,7 @@ do_phys_path(XString *xsp, char *xp, const char *path)
 		if (llen < 0) {
 			/* EINVAL means it wasn't a symlink... */
 			if (errno != EINVAL)
-				return (char *) 0;
+				return NULL;
 			continue;
 		}
 		lbuf[llen] = '\0';
@@ -255,31 +260,7 @@ do_phys_path(XString *xsp, char *xp, const char *path)
 		xp = lbuf[0] == '/' ? Xstring(*xsp, xp) :
 		    Xrestpos(*xsp, xp, savepos);
 		if (!(xp = do_phys_path(xsp, xp, lbuf)))
-			return (char *) 0;
+			return NULL;
 	}
 	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 */
diff --git a/portable/linux/linux.h b/portable/linux/linux.h
@@ -5,16 +5,50 @@
 /* Includes */
 #include <sys/file.h>
 #include <sys/param.h>
+#include <stdlib.h>
 #include <time.h>
 
 /* Defines */
 #define _PW_NAME_LEN	LOGIN_NAME_MAX
-#define CHILD_MAX	80
+#define O_EXLOCK	0
 #define srand_deterministic(x)	srand(x)
 
+#ifndef __CYGWIN__
+#define CHILD_MAX	80
+#endif
+
+#ifdef __CYGWIN__
+#define setresgid(x, y, z)	setgid(x); setegid(x)
+#define setresuid(x, y, z)	setuid(x); seteuid(x)
+#endif
+
+/* From OpenBSD sys/time.h */
+#define	timespeccmp(tsp, usp, cmp)					\
+	(((tsp)->tv_sec == (usp)->tv_sec) ?				\
+	    ((tsp)->tv_nsec cmp (usp)->tv_nsec) :			\
+	    ((tsp)->tv_sec cmp (usp)->tv_sec))
+
+#define	timespecsub(tsp, usp, vsp)					\
+	do {								\
+		(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec;		\
+		(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec;	\
+		if ((vsp)->tv_nsec < 0) {				\
+			(vsp)->tv_sec--;				\
+			(vsp)->tv_nsec += 1000000000L;			\
+		}							\
+	} while (0)
+
+/* Resource limits for Cygwin, from OpenBSD sys/resource.h */
+#ifdef __CYGWIN__
+#define	RLIMIT_RSS	5		/* resident set size */
+#define	RLIMIT_MEMLOCK	6		/* locked-in-memory address space */
+#define	RLIMIT_NPROC	7		/* number of processes */
+#endif
+
 /* Functions */
 const char *const sys_signame;
 mode_t	getmode(const void *, mode_t);
+void   *reallocarray(void *, size_t, size_t);
 void   *setmode(const char *);
 size_t	strlcat(char *, const char *, size_t);
 size_t	strlcpy(char *, const char *, size_t);
diff --git a/portable/linux/unvis.c b/portable/linux/unvis.c
@@ -0,0 +1,285 @@
+/*	$OpenBSD: unvis.c,v 1.17 2015/09/13 11:32:51 guenther Exp $ */
+/*-
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include "vis.h"
+
+/*
+ * decode driven by state machine
+ */
+#define	S_GROUND	0	/* haven't seen escape char */
+#define	S_START		1	/* start decoding special sequence */
+#define	S_META		2	/* metachar started (M) */
+#define	S_META1		3	/* metachar more, regular char (-) */
+#define	S_CTRL		4	/* control char started (^) */
+#define	S_OCTAL2	5	/* octal digit 2 */
+#define	S_OCTAL3	6	/* octal digit 3 */
+
+#define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+
+/*
+ * unvis - decode characters previously encoded by vis
+ */
+int
+unvis(char *cp, char c, int *astate, int flag)
+{
+
+	if (flag & UNVIS_END) {
+		if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
+			*astate = S_GROUND;
+			return (UNVIS_VALID);
+		} 
+		return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
+	}
+
+	switch (*astate) {
+
+	case S_GROUND:
+		*cp = 0;
+		if (c == '\\') {
+			*astate = S_START;
+			return (0);
+		} 
+		*cp = c;
+		return (UNVIS_VALID);
+
+	case S_START:
+		switch(c) {
+		case '-':
+			*cp = 0;
+			*astate = S_GROUND;
+			return (0);
+		case '\\':
+		case '"':
+			*cp = c;
+			*astate = S_GROUND;
+			return (UNVIS_VALID);
+		case '0': case '1': case '2': case '3':
+		case '4': case '5': case '6': case '7':
+			*cp = (c - '0');
+			*astate = S_OCTAL2;
+			return (0);
+		case 'M':
+			*cp = (char) 0200;
+			*astate = S_META;
+			return (0);
+		case '^':
+			*astate = S_CTRL;
+			return (0);
+		case 'n':
+			*cp = '\n';
+			*astate = S_GROUND;
+			return (UNVIS_VALID);
+		case 'r':
+			*cp = '\r';
+			*astate = S_GROUND;
+			return (UNVIS_VALID);
+		case 'b':
+			*cp = '\b';
+			*astate = S_GROUND;
+			return (UNVIS_VALID);
+		case 'a':
+			*cp = '\007';
+			*astate = S_GROUND;
+			return (UNVIS_VALID);
+		case 'v':
+			*cp = '\v';
+			*astate = S_GROUND;
+			return (UNVIS_VALID);
+		case 't':
+			*cp = '\t';
+			*astate = S_GROUND;
+			return (UNVIS_VALID);
+		case 'f':
+			*cp = '\f';
+			*astate = S_GROUND;
+			return (UNVIS_VALID);
+		case 's':
+			*cp = ' ';
+			*astate = S_GROUND;
+			return (UNVIS_VALID);
+		case 'E':
+			*cp = '\033';
+			*astate = S_GROUND;
+			return (UNVIS_VALID);
+		case '\n':
+			/*
+			 * hidden newline
+			 */
+			*astate = S_GROUND;
+			return (UNVIS_NOCHAR);
+		case '$':
+			/*
+			 * hidden marker
+			 */
+			*astate = S_GROUND;
+			return (UNVIS_NOCHAR);
+		}
+		*astate = S_GROUND;
+		return (UNVIS_SYNBAD);
+		 
+	case S_META:
+		if (c == '-')
+			*astate = S_META1;
+		else if (c == '^')
+			*astate = S_CTRL;
+		else {
+			*astate = S_GROUND;
+			return (UNVIS_SYNBAD);
+		}
+		return (0);
+		 
+	case S_META1:
+		*astate = S_GROUND;
+		*cp |= c;
+		return (UNVIS_VALID);
+		 
+	case S_CTRL:
+		if (c == '?')
+			*cp |= 0177;
+		else
+			*cp |= c & 037;
+		*astate = S_GROUND;
+		return (UNVIS_VALID);
+
+	case S_OCTAL2:	/* second possible octal digit */
+		if (isoctal(c)) {
+			/* 
+			 * yes - and maybe a third 
+			 */
+			*cp = (*cp << 3) + (c - '0');
+			*astate = S_OCTAL3;	
+			return (0);
+		} 
+		/* 
+		 * no - done with current sequence, push back passed char 
+		 */
+		*astate = S_GROUND;
+		return (UNVIS_VALIDPUSH);
+
+	case S_OCTAL3:	/* third possible octal digit */
+		*astate = S_GROUND;
+		if (isoctal(c)) {
+			*cp = (*cp << 3) + (c - '0');
+			return (UNVIS_VALID);
+		}
+		/*
+		 * we were done, push back passed char
+		 */
+		return (UNVIS_VALIDPUSH);
+
+	default:	
+		/* 
+		 * decoder in unknown state - (probably uninitialized) 
+		 */
+		*astate = S_GROUND;
+		return (UNVIS_SYNBAD);
+	}
+}
+
+/*
+ * strunvis - decode src into dst 
+ *
+ *	Number of chars decoded into dst is returned, -1 on error.
+ *	Dst is null terminated.
+ */
+
+int
+strunvis(char *dst, const char *src)
+{
+	char c;
+	char *start = dst;
+	int state = 0;
+
+	while ((c = *src++)) {
+	again:
+		switch (unvis(dst, c, &state, 0)) {
+		case UNVIS_VALID:
+			dst++;
+			break;
+		case UNVIS_VALIDPUSH:
+			dst++;
+			goto again;
+		case 0:
+		case UNVIS_NOCHAR:
+			break;
+		default:
+			*dst = '\0';
+			return (-1);
+		}
+	}
+	if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
+		dst++;
+	*dst = '\0';
+	return (dst - start);
+}
+
+ssize_t
+strnunvis(char *dst, const char *src, size_t sz)
+{
+	char c, p;
+	char *start = dst, *end = dst + sz - 1;
+	int state = 0;
+
+	if (sz > 0)
+		*end = '\0';
+	while ((c = *src++)) {
+	again:
+		switch (unvis(&p, c, &state, 0)) {
+		case UNVIS_VALID:
+			if (dst < end)
+				*dst = p;
+			dst++;
+			break;
+		case UNVIS_VALIDPUSH:
+			if (dst < end)
+				*dst = p;
+			dst++;
+			goto again;
+		case 0:
+		case UNVIS_NOCHAR:
+			break;
+		default:
+			if (dst <= end)
+				*dst = '\0';
+			return (-1);
+		}
+	}
+	if (unvis(&p, c, &state, UNVIS_END) == UNVIS_VALID) {
+		if (dst < end)
+			*dst = p;
+		dst++;
+	}
+	if (dst <= end)
+		*dst = '\0';
+	return (dst - start);
+}
+
diff --git a/portable/linux/vis.c b/portable/linux/vis.c
@@ -0,0 +1,242 @@
+/*	$OpenBSD: vis.c,v 1.25 2015/09/13 11:32:51 guenther Exp $ */
+/*-
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "linux.h"
+#include "vis.h"
+
+#define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+#define	isvisible(c,flag)						\
+	(((c) == '\\' || (flag & VIS_ALL) == 0) &&			\
+	(((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) &&		\
+	(((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') ||	\
+		(flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) ||	\
+	((flag & VIS_SP) == 0 && (c) == ' ') ||				\
+	((flag & VIS_TAB) == 0 && (c) == '\t') ||			\
+	((flag & VIS_NL) == 0 && (c) == '\n') ||			\
+	((flag & VIS_SAFE) && ((c) == '\b' ||				\
+		(c) == '\007' || (c) == '\r' ||				\
+		isgraph((u_char)(c))))))
+
+/*
+ * vis - visually encode characters
+ */
+char *
+vis(char *dst, int c, int flag, int nextc)
+{
+	if (isvisible(c, flag)) {
+		if ((c == '"' && (flag & VIS_DQ) != 0) ||
+		    (c == '\\' && (flag & VIS_NOSLASH) == 0))
+			*dst++ = '\\';
+		*dst++ = c;
+		*dst = '\0';
+		return (dst);
+	}
+
+	if (flag & VIS_CSTYLE) {
+		switch(c) {
+		case '\n':
+			*dst++ = '\\';
+			*dst++ = 'n';
+			goto done;
+		case '\r':
+			*dst++ = '\\';
+			*dst++ = 'r';
+			goto done;
+		case '\b':
+			*dst++ = '\\';
+			*dst++ = 'b';
+			goto done;
+		case '\a':
+			*dst++ = '\\';
+			*dst++ = 'a';
+			goto done;
+		case '\v':
+			*dst++ = '\\';
+			*dst++ = 'v';
+			goto done;
+		case '\t':
+			*dst++ = '\\';
+			*dst++ = 't';
+			goto done;
+		case '\f':
+			*dst++ = '\\';
+			*dst++ = 'f';
+			goto done;
+		case ' ':
+			*dst++ = '\\';
+			*dst++ = 's';
+			goto done;
+		case '\0':
+			*dst++ = '\\';
+			*dst++ = '0';
+			if (isoctal(nextc)) {
+				*dst++ = '0';
+				*dst++ = '0';
+			}
+			goto done;
+		}
+	}
+	if (((c & 0177) == ' ') || (flag & VIS_OCTAL) ||
+	    ((flag & VIS_GLOB) && (c == '*' || c == '?' || c == '[' || c == '#'))) {
+		*dst++ = '\\';
+		*dst++ = ((u_char)c >> 6 & 07) + '0';
+		*dst++ = ((u_char)c >> 3 & 07) + '0';
+		*dst++ = ((u_char)c & 07) + '0';
+		goto done;
+	}
+	if ((flag & VIS_NOSLASH) == 0)
+		*dst++ = '\\';
+	if (c & 0200) {
+		c &= 0177;
+		*dst++ = 'M';
+	}
+	if (iscntrl((u_char)c)) {
+		*dst++ = '^';
+		if (c == 0177)
+			*dst++ = '?';
+		else
+			*dst++ = c + '@';
+	} else {
+		*dst++ = '-';
+		*dst++ = c;
+	}
+done:
+	*dst = '\0';
+	return (dst);
+}
+
+/*
+ * strvis, strnvis, strvisx - visually encode characters from src into dst
+ *	
+ *	Dst must be 4 times the size of src to account for possible
+ *	expansion.  The length of dst, not including the trailing NULL,
+ *	is returned. 
+ *
+ *	Strnvis will write no more than siz-1 bytes (and will NULL terminate).
+ *	The number of bytes needed to fully encode the string is returned.
+ *
+ *	Strvisx encodes exactly len bytes from src into dst.
+ *	This is useful for encoding a block of data.
+ */
+int
+strvis(char *dst, const char *src, int flag)
+{
+	char c;
+	char *start;
+
+	for (start = dst; (c = *src);)
+		dst = vis(dst, c, flag, *++src);
+	*dst = '\0';
+	return (dst - start);
+}
+
+int
+strnvis(char *dst, const char *src, size_t siz, int flag)
+{
+	char *start, *end;
+	char tbuf[5];
+	int c, i;
+
+	i = 0;
+	for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) {
+		if (isvisible(c, flag)) {
+			if ((c == '"' && (flag & VIS_DQ) != 0) ||
+			    (c == '\\' && (flag & VIS_NOSLASH) == 0)) {
+				/* need space for the extra '\\' */
+				if (dst + 1 >= end) {
+					i = 2;
+					break;
+				}
+				*dst++ = '\\';
+			}
+			i = 1;
+			*dst++ = c;
+			src++;
+		} else {
+			i = vis(tbuf, c, flag, *++src) - tbuf;
+			if (dst + i <= end) {
+				memcpy(dst, tbuf, i);
+				dst += i;
+			} else {
+				src--;
+				break;
+			}
+		}
+	}
+	if (siz > 0)
+		*dst = '\0';
+	if (dst + i > end) {
+		/* adjust return value for truncation */
+		while ((c = *src))
+			dst += vis(tbuf, c, flag, *++src) - tbuf;
+	}
+	return (dst - start);
+}
+
+int
+stravis(char **outp, const char *src, int flag)
+{
+	char *buf;
+	int len, serrno;
+
+	buf = reallocarray(NULL, 4, strlen(src) + 1);
+	if (buf == NULL)
+		return -1;
+	len = strvis(buf, src, flag);
+	serrno = errno;
+	*outp = realloc(buf, len + 1);
+	if (*outp == NULL) {
+		*outp = buf;
+		errno = serrno;
+	}
+	return (len);
+}
+
+int
+strvisx(char *dst, const char *src, size_t len, int flag)
+{
+	char c;
+	char *start;
+
+	for (start = dst; len > 1; len--) {
+		c = *src;
+		dst = vis(dst, c, flag, *++src);
+	}
+	if (len)
+		dst = vis(dst, *src, flag, '\0');
+	*dst = '\0';
+	return (dst - start);
+}
diff --git a/portable/linux/vis.h b/portable/linux/vis.h
@@ -0,0 +1,93 @@
+/*	$OpenBSD: vis.h,v 1.15 2015/07/20 01:52:27 millert Exp $	*/
+/*	$NetBSD: vis.h,v 1.4 1994/10/26 00:56:41 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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.
+ *
+ *	@(#)vis.h	5.9 (Berkeley) 4/3/91
+ */
+
+#ifndef _VIS_H_
+#define	_VIS_H_
+
+/*
+ * to select alternate encoding format
+ */
+#define	VIS_OCTAL	0x01	/* use octal \ddd format */
+#define	VIS_CSTYLE	0x02	/* use \[nrft0..] where appropriate */
+
+/*
+ * to alter set of characters encoded (default is to encode all
+ * non-graphic except space, tab, and newline).
+ */
+#define	VIS_SP		0x04	/* also encode space */
+#define	VIS_TAB		0x08	/* also encode tab */
+#define	VIS_NL		0x10	/* also encode newline */
+#define	VIS_WHITE	(VIS_SP | VIS_TAB | VIS_NL)
+#define	VIS_SAFE	0x20	/* only encode "unsafe" characters */
+#define	VIS_DQ		0x200	/* backslash-escape double quotes */
+#define	VIS_ALL		0x400	/* encode all characters */
+
+/*
+ * other
+ */
+#define	VIS_NOSLASH	0x40	/* inhibit printing '\' */
+#define	VIS_GLOB	0x100	/* encode glob(3) magics and '#' */
+
+/*
+ * unvis return codes
+ */
+#define	UNVIS_VALID	 1	/* character valid */
+#define	UNVIS_VALIDPUSH	 2	/* character valid, push back passed char */
+#define	UNVIS_NOCHAR	 3	/* valid sequence, no character produced */
+#define	UNVIS_SYNBAD	-1	/* unrecognized escape sequence */
+#define	UNVIS_ERROR	-2	/* decoder in unknown state (unrecoverable) */
+
+/*
+ * unvis flags
+ */
+#define	UNVIS_END	1	/* no more characters */
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+char	*vis(char *, int, int, int);
+int	strvis(char *, const char *, int);
+int	stravis(char **, const char *, int);
+int	strnvis(char *, const char *, size_t, int)
+		__attribute__ ((__bounded__(__string__,1,3)));
+int	strvisx(char *, const char *, size_t, int)
+		__attribute__ ((__bounded__(__string__,1,3)));
+int	strunvis(char *, const char *);
+int	unvis(char *, char, int *, int);
+ssize_t strnunvis(char *, const char *, size_t)
+		__attribute__ ((__bounded__(__string__,1,3)));
+
+__END_DECLS
+
+#endif /* !_VIS_H_ */
diff --git a/portable/netbsd/netbsd.h b/portable/netbsd/netbsd.h
@@ -3,6 +3,6 @@
  */
 
 /* Defines */
-#define setresgid(x, x, x)	setgid(x); setegid(x)
-#define setresuid(x, x, x)	setuid(x); seteuid(x)
+#define setresgid(x, y, z)	setgid(x); setegid(x)
+#define setresuid(x, y, z)	setuid(x); seteuid(x)
 #define srand_deterministic(x)	srand(x)
diff --git a/proto.h b/proto.h
@@ -1,267 +0,0 @@
-/*	$OpenBSD: proto.h,v 1.35 2013/09/04 15:49:19 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, volatile 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, 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_suspend(void);
-void	j_exit(void);
-void	j_change(void);
-int	exchild(struct op *, int, volatile 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);
-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 (*)(const void *, const void *));
-int	xstrcmp(const void *, const 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 */
-void	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 */
diff --git a/sh.1 b/sh.1
@@ -1,4 +1,4 @@
-.\"	$OpenBSD: sh.1,v 1.128 2015/05/04 19:34:13 jmc Exp $
+.\"	$OpenBSD: sh.1,v 1.143 2017/06/01 20:37:38 tb Exp $
 .\"
 .\" Copyright (c) 2015 Jason McIntyre <jmc@openbsd.org>
 .\"
@@ -14,7 +14,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: May 4 2015 $
+.Dd $Mdocdate: June 1 2017 $
 .Dt SH 1
 .Os
 .Sh NAME
@@ -30,22 +30,21 @@ The
 .Nm
 utility is a
 .Em command language interpreter :
-it reads its input,
-breaks it down into parts,
-and then executes those parts.
-Its chief uses are in interfacing between the user and the operating system,
-reading commands on the command line,
-and in chaining together groups of commands in a very flexible manner,
-through a shell script.
+it reads one or more commands,
+either from the command line or from a file
+(a shell script),
+and then sets about executing those commands.
+Thus it is the
+main interface between the user and the operating system.
 .Pp
 This version of
 .Nm
 is actually
 .Nm ksh
 in disguise.
-As such, it will also accept options documented in
+As such, it also supports the features described in
 .Xr ksh 1 .
-This manual page describes only features
+This manual page describes only the parts
 relevant to a POSIX compliant
 .Nm .
 If portability is a concern,
@@ -122,8 +121,6 @@ Do not expand file name patterns.
 When a utility is first executed,
 hash (record) its location
 so that future invocations do not need to search for it.
-Builtins are not hashed, regardless of whether this option is set or not.
-This option is set by default for non-interactive shells.
 .It Fl i
 Enable behaviour convenient for an interactive shell.
 This option is set by default
@@ -214,7 +211,7 @@ are listed below.
 Unless otherwise indicated,
 they exit 0 on success,
 and >0 if an error occurs.
-.Bl -ohang
+.Bl -tag -width 2n
 .It Ic .\& Ar file
 Execute the commands in
 .Ar file ,
@@ -329,6 +326,9 @@ but identify how the shell will interpret it
 Do not invoke
 .Ar command ,
 but identify the pathname the shell will use to run it.
+For aliases, a command to define that alias is printed.
+For shell reserved words, shell functions, and built-in utilities,
+just the name is printed.
 .El
 .Pp
 The exit status is that of
@@ -508,6 +508,14 @@ is a colon,
 .Ev OPTARG
 is set to the unsupported option,
 otherwise an error message is displayed.
+.It Ic hash Op Fl r | Ar utility
+Add
+.Ar utility
+to the hash list
+or remove
+.Pq Fl r
+all utilities from the hash list.
+Without arguments, show the utilities currently hashed.
 .It Ic jobs Oo Fl l | p Oc Op Ar id ...
 Display the status of all jobs in the current shell environment,
 or those selected by
@@ -737,8 +745,6 @@ no change occurs.
 .It Ic times
 Display accumulated process times for the shell (user and system)
 and all child processes (user and system).
-.It Ic true
-Return a true (zero) value.
 .It Ic trap Op Ar action signal ...
 Perform
 .Ar action
@@ -774,6 +780,18 @@ otherwise
 should be a signal name
 (without the SIG prefix)
 or number.
+.It Ic true
+Return a true (zero) value.
+.It Ic type Ar command ...
+For each
+.Ar command ,
+show how the shell would interpret it.
+.It Ic ulimit Op Fl f Ar n
+Limit the maximum size of a file that can be created to
+.Ar n
+blocks.
+Without arguments,
+display the current file size limit.
 .It Ic umask Oo Fl S Oc Op Ar mask
 Set the file mode creation mask to
 .Ar mask .
@@ -939,7 +957,7 @@ at the end of a bigword.
 Move to the start of the current word,
 or the start of the next word if the cursor is currently
 at the start of a word.
-.It Oo Ar count Oc Ns Ic b
+.It Oo Ar count Oc Ns Ic B
 Move to the start of the current bigword,
 or the start of the next bigword if the cursor is currently
 at the start of a bigword.
@@ -1339,7 +1357,7 @@ In that case the shell attempts arithmetic expansion first,
 then attempts command substitution if that fails.
 Or a non-ambiguous version can be used:
 .Pp
-.D1 $( Pf ( Ar command Ns Pf ) \ \&)
+.D1 "$( (" Ns Ar command Ns ") )"
 .Pp
 Arithmetic expansion works similarly,
 with an arithmetic expression being evaluated and substituted.
@@ -1377,7 +1395,7 @@ greater than, and greater than or equal to, respectively.
 The result is 1 if true, or 0 otherwise.
 .It == !=
 Equal (the result is 1 if both arguments are equal, and 0 otherwise)
-and not equal (the result is 1 if both arguments are non-zero, and 0 otherwise),
+and not equal (the result is 0 if both arguments are equal, and 1 otherwise),
 respectively.
 .It &
 Bitwise AND.
@@ -1644,7 +1662,7 @@ where commands are executed in the order given.
 The exit status of a sequential list is that of the last command executed.
 The format for a sequential list is:
 .Pp
-.D1 Ar command\ \& ; Op Ar command ...
+.D1 Ar command No \&; Op Ar command ...
 .Pp
 A series of one or more commands separated by
 .Sq &
@@ -1979,6 +1997,8 @@ The following environment variables affect the execution of
 Colon separated list of directories used by the
 .Ic cd
 command.
+If unset or empty,
+the current working directory is used.
 .It Ev ENV
 Pathname to a file containing commands to be executed
 when an interactive shell is started.
@@ -2073,7 +2093,7 @@ Enable POSIX mode
 The shell's parent process ID.
 Subshells have the same
 .Ev PPID
-as the parent of the current shell.
+as the current shell.
 .It Ev PS1
 User prompt displayed every time an interactive shell
 is ready to read a command.
@@ -2195,9 +2215,6 @@ This implementation of
 .Nm
 does not provide notification when these files are created.
 .It
-Command substitution occurring within double quotes
-is subject to pathname expansion but should not be.
-.It
 The built-in
 .Ic newgrp
 is unsupported.
diff --git a/sh.h b/sh.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: sh.h,v 1.33 2013/12/18 13:53:12 millert Exp $	*/
+/*	$OpenBSD: sh.h,v 1.64 2017/09/03 11:52:01 jca Exp $	*/
 
 /*
  * Public Domain Bourne/Korn shell
@@ -10,26 +10,16 @@
 
 /* Start of common headers */
 
-#include <stdio.h>
-#include <sys/types.h>
+#include <limits.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 <stdbool.h>
 
-#include <paths.h>
+/* end of common headers */
 
 /* oksh portable: system-specific headers */
-#ifdef __linux__
+#if defined(__linux__) || defined(__CYGWIN__)
 #include "portable/linux/linux.h"
 #endif
 #if defined(__FreeBSD__) || defined(__DragonFly__)
@@ -42,55 +32,31 @@
 #include "portable/darwin/darwin.h"
 #endif
 
-/* 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 */
 
+#define BITS(t)	(CHAR_BIT * sizeof(t))
+
 /* 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	LINE	4096		/* input line size */
 
-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 */
+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
@@ -99,9 +65,9 @@ typedef struct Area {
 	struct link *freelist;	/* free list */
 } Area;
 
-EXTERN	Area	aperm;		/* permanent object space */
+extern	Area	aperm;		/* permanent object space */
 #define	APERM	&aperm
-#define	ATEMP	&e->area
+#define	ATEMP	&genv->area
 
 #ifdef KSH_DEBUG
 # define kshdebug_init()	kshdebug_init_()
@@ -116,7 +82,7 @@ EXTERN	Area	aperm;		/* permanent object space */
 /*
  * parsing & execution environment
  */
-EXTERN	struct env {
+struct env {
 	short	type;			/* environment type - see below */
 	short	flags;			/* EF_* */
 	Area	area;			/* temporary allocation area */
@@ -125,7 +91,8 @@ EXTERN	struct env {
 	struct	env *oenv;		/* link to previous environment */
 	sigjmp_buf jbuf;		/* long jump back to env creator */
 	struct temp *temps;		/* temp files */
-} *e;
+};
+extern	struct env	*genv;
 
 /* struct env.type values */
 #define	E_NONE	0		/* dummy environment */
@@ -186,7 +153,7 @@ enum sh_flag {
 	FCSHHISTORY,	/* csh-style history enabled */
 #ifdef EMACS
 	FEMACS,		/* emacs command editing */
-	FEMACSUSEMETA,	/* use 8th bit as meta */
+	FEMACSUSEMETA,	/* XXX delete after 6.2 */
 #endif
 	FERREXIT,	/* -e: quit on error */
 #ifdef EMACS
@@ -229,11 +196,9 @@ enum sh_flag {
 
 #define Flag(f)	(shell_flags[(int) (f)])
 
-EXTERN	char shell_flags [FNFLAGS];
+extern	char shell_flags[FNFLAGS];
 
-EXTERN	char	null [] I__("");	/* null value for variable */
-EXTERN	char	space [] I__(" ");
-EXTERN	char	newline [] I__("\n");
+extern	char	null[];	/* null value for variable */
 
 enum temp_type {
 	TT_HEREDOC_EXP,	/* expanded heredoc */
@@ -256,7 +221,7 @@ struct temp {
 #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;
+extern int shl_stdout_ok;
 
 /*
  * trap handlers
@@ -297,9 +262,9 @@ typedef struct trap {
 #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	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	volatile sig_atomic_t got_sigwinch;
 extern	Trap	sigtraps[NSIG+1];
 
@@ -312,17 +277,17 @@ enum tmout_enum {
 	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);
+extern unsigned int ksh_tmout;
+extern enum tmout_enum ksh_tmout_state;
 
 /* For "You have stopped jobs" message */
-EXTERN int really_exit;
+extern int really_exit;
 
 /*
  * fast character classes
  */
 #define	C_ALPHA	 BIT(0)		/* a-z_A-Z */
-#define	C_DIGIT	 BIT(1)		/* 0-9 */
+/* was	C_DIGIT */
 #define	C_LEX1	 BIT(2)		/* \0 \t\n|&;<>() */
 #define	C_VAR1	 BIT(3)		/* *@#!$-? */
 #define	C_IFSWS	 BIT(4)		/* \t \n (IFS white space) */
@@ -335,10 +300,10 @@ 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)
+#define	digit(c)	isdigit((unsigned char)(c))
+#define	letnum(c)	(ctype(c, C_ALPHA) || isdigit((unsigned char)(c)))
 
-EXTERN int ifs0 I__(' ');	/* for "$*" */
+extern int ifs0;	/* for "$*" */
 
 /* Argument parsing for built-in commands and getopts command */
 
@@ -362,12 +327,12 @@ typedef struct {
 	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 */
+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 */
+typedef int Coproc_id; /* something that won't (realistically) wrap */
 struct coproc {
 	int	read;		/* pipe from co-process's stdout */
 	int	readw;		/* other side of read (saved temporarily) */
@@ -376,20 +341,20 @@ struct coproc {
 	int	njobs;		/* number of live jobs using output pipe */
 	void	*job;		/* 0 or job of co-process using input pipe */
 };
-EXTERN struct coproc coproc;
+extern struct coproc coproc;
 
 /* Used in jobs.c and by coprocess stuff in exec.c */
-EXTERN sigset_t		sm_default, sm_sigchld;
+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.) */
+extern char	*builtin_argv0;
+extern int	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;
+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
@@ -399,7 +364,7 @@ EXTERN int	current_wd_size;
 /* 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 */
+extern	int	x_cols;	/* tty columns */
 #else
 # define x_cols 80		/* for pr_menu(exec.c) */
 #endif
@@ -416,19 +381,244 @@ EXTERN	int	x_cols I__(80);	/* tty columns */
 #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 */
+#define KSH_UNWIND_ERROR	0x0	/* unwind the stack (longjmp) */
+#define KSH_RETURN_ERROR	0x1	/* return 1/0 for success/failure */
+#define KSH_IGNORE_RDONLY	0x4	/* ignore the read-only flag */
 
 #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__
+/* alloc.c */
+Area *	ainit(Area *);
+void	afreeall(Area *);
+void *	alloc(size_t, Area *);
+void *	areallocarray(void *, size_t, size_t, Area *);
+void *	aresize(void *, size_t, Area *);
+void	afree(void *, Area *);
+/* c_ksh.c */
+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, volatile 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, 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	sethistcontrol(const 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(bool, 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_suspend(void);
+void	j_exit(void);
+void	j_change(void);
+int	exchild(struct op *, int, volatile 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);
+/* 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);
+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 (*)(const void *, const void *));
+int	xstrcmp(const void *, const 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);
+/* 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 *);
+/* 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);
+/* 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 *, int, int, 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 **);
+/* vi.c: see edit.h */
diff --git a/shf.c b/shf.c
@@ -1,13 +1,20 @@
-/*	$OpenBSD: shf.c,v 1.16 2013/04/19 17:36:09 millert Exp $	*/
+/*	$OpenBSD: shf.c,v 1.31 2016/03/20 00:01:21 krw Exp $	*/
 
 /*
  *  Shell file I/O routines
  */
 
-#include "sh.h"
 #include <sys/stat.h>
-#include "ksh_limval.h"
 
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sh.h"
 
 /* flags to shf_emptybuf() */
 #define EB_READSW	0x01	/* about to switch to reading */
@@ -34,7 +41,7 @@ shf_open(const char *name, int oflags, int mode, int sflags)
 	int fd;
 
 	/* Done before open so if alloca fails, fd won't be lost. */
-	shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP);
+	shf = alloc(sizeof(struct shf) + bsize, ATEMP);
 	shf->areap = ATEMP;
 	shf->buf = (unsigned char *) &shf[1];
 	shf->bsize = bsize;
@@ -72,7 +79,7 @@ shf_fdopen(int fd, int sflags, struct shf *shf)
 
 	/* use fcntl() to figure out correct read/write flags */
 	if (sflags & SHF_GETFL) {
-		int flags = fcntl(fd, F_GETFL, 0);
+		int flags = fcntl(fd, F_GETFL);
 
 		if (flags < 0)
 			/* will get an error on first read/write */
@@ -97,12 +104,12 @@ shf_fdopen(int fd, int sflags, struct shf *shf)
 
 	if (shf) {
 		if (bsize) {
-			shf->buf = (unsigned char *) alloc(bsize, ATEMP);
+			shf->buf = alloc(bsize, ATEMP);
 			sflags |= SHF_ALLOCB;
 		} else
-			shf->buf = (unsigned char *) 0;
+			shf->buf = NULL;
 	} else {
-		shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP);
+		shf = alloc(sizeof(struct shf) + bsize, ATEMP);
 		shf->buf = (unsigned char *) &shf[1];
 		sflags |= SHF_ALLOCS;
 	}
@@ -129,7 +136,7 @@ shf_reopen(int fd, int sflags, struct shf *shf)
 
 	/* use fcntl() to figure out correct read/write flags */
 	if (sflags & SHF_GETFL) {
-		int flags = fcntl(fd, F_GETFL, 0);
+		int flags = fcntl(fd, F_GETFL);
 
 		if (flags < 0)
 			/* will get an error on first read/write */
@@ -185,7 +192,7 @@ shf_sopen(char *buf, int bsize, int sflags, struct shf *shf)
 		internal_errorf(1, "shf_sopen: flags 0x%x", sflags);
 
 	if (!shf) {
-		shf = (struct shf *) alloc(sizeof(struct shf), ATEMP);
+		shf = alloc(sizeof(struct shf), ATEMP);
 		sflags |= SHF_ALLOCS;
 	}
 	shf->areap = ATEMP;
@@ -328,8 +335,7 @@ shf_emptybuf(struct shf *shf, int flags)
 		    !(shf->flags & SHF_ALLOCB))
 			return EOF;
 		/* allocate more space for buffer */
-		nbuf = (unsigned char *) aresize(shf->buf, shf->wbsize * 2,
-		    shf->areap);
+		nbuf = areallocarray(shf->buf, 2, shf->wbsize, shf->areap);
 		shf->rp = nbuf + (shf->rp - shf->buf);
 		shf->wp = nbuf + (shf->wp - shf->buf);
 		shf->rbsize += shf->wbsize;
@@ -470,7 +476,7 @@ shf_getse(char *buf, int bsize, struct shf *shf)
 		internal_errorf(1, "shf_getse: flags %x", shf->flags);
 
 	if (bsize <= 0)
-		return (char *) 0;
+		return NULL;
 
 	--bsize;	/* save room for null */
 	do {
@@ -698,41 +704,13 @@ shf_smprintf(const char *fmt, ...)
 	struct shf shf;
 	va_list args;
 
-	shf_sopen((char *) 0, 0, SHF_WR|SHF_DYNAMIC, &shf);
+	shf_sopen(NULL, 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_LLONG) ? va_arg((a), unsigned long long) :		\
-	    ((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 */
@@ -745,19 +723,6 @@ shf_smprintf(const char *fmt, ...)
 #define FL_UPPER	0x200	/* format character was uppercase */
 #define FL_NUMBER	0x400	/* 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)
 {
@@ -771,17 +736,6 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
 	char		numbuf[(BITS(long 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;
@@ -879,9 +833,8 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
 
 		switch (c) {
 		case 'p': /* pointer */
-			flags &= ~(FL_LLONG | FL_LONG | FL_SHORT);
-			if (sizeof(char *) > sizeof(int))
-				flags |= FL_LONG; /* hope it fits.. */
+			flags &= ~(FL_LLONG | FL_SHORT);
+			flags |= FL_LONG;
 			/* aaahhh... */
 		case 'd':
 		case 'i':
@@ -890,7 +843,19 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
 		case 'x':
 			flags |= FL_NUMBER;
 			s = &numbuf[sizeof(numbuf)];
-			llnum = POP_INT(flags, c == 'd', args);
+			if (flags & FL_LLONG)
+				llnum = va_arg(args, unsigned long long);
+			else if (flags & FL_LONG) {
+				if (c == 'd' || c == 'i')
+					llnum = va_arg(args, long);
+				else
+					llnum = va_arg(args, unsigned long);
+			} else {
+				if (c == 'd' || c == 'i')
+					llnum = va_arg(args, int);
+				else
+					llnum = va_arg(args, unsigned int);
+			}
 			switch (c) {
 			case 'd':
 			case 'i':
@@ -953,134 +918,6 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
 			}
 			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_LLONG/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)";
diff --git a/shf.h b/shf.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: shf.h,v 1.6 2005/12/11 18:53:51 deraadt Exp $	*/
+/*	$OpenBSD: shf.h,v 1.8 2015/12/14 06:09:43 mmcc Exp $	*/
 
 #ifndef SHF_H
 # define SHF_H
@@ -9,15 +9,12 @@
 
 #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() */
diff --git a/syn.c b/syn.c
@@ -1,9 +1,11 @@
-/*	$OpenBSD: syn.c,v 1.29 2013/06/03 18:40:05 jca Exp $	*/
+/*	$OpenBSD: syn.c,v 1.38 2015/12/30 09:07:00 tedu Exp $	*/
 
 /*
  * shell parser (C version)
  */
 
+#include <string.h>
+
 #include "sh.h"
 #include "c_test.h"
 
@@ -47,26 +49,24 @@ 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)))
+	((reject) ? (reject = false, symbol) : (symbol = yylex(cf)))
 #define	tpeek(cf) \
-	((reject) ? (symbol) : (REJECT, symbol = yylex(cf)))
+	((reject) ? (symbol) : (reject = true, symbol = yylex(cf)))
 
 static void
 yyparse(void)
 {
 	int c;
 
-	ACCEPT;
+	reject = false;
 
 	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);
+		syntaxerr(NULL);
 }
 
 static struct op *
@@ -78,13 +78,13 @@ pipeline(int cf)
 	if (t != NULL) {
 		while (token(0) == '|') {
 			if ((p = get_command(CONTIN)) == NULL)
-				syntaxerr((char *) 0);
+				syntaxerr(NULL);
 			if (tl == NULL)
-				t = tl = block(TPIPE, t, p, NOWORDS);
+				t = tl = block(TPIPE, t, p, NULL);
 			else
-				tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);
+				tl = tl->right = block(TPIPE, tl->right, p, NULL);
 		}
-		REJECT;
+		reject = true;
 	}
 	return (t);
 }
@@ -99,10 +99,10 @@ andor(void)
 	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);
+				syntaxerr(NULL);
+			t = block(c == LOGAND? TAND: TOR, t, p, NULL);
 		}
-		REJECT;
+		reject = true;
 	}
 	return (t);
 }
@@ -128,19 +128,19 @@ c_list(int multi)
 			break;
 		else if (c == '&' || c == COPROC)
 			p = block(c == '&' ? TASYNC : TCOPROC,
-				  p, NOBLOCK, NOWORDS);
+				  p, NULL, NULL);
 		else if (c != ';')
 			have_sep = 0;
 		if (!t)
 			t = p;
 		else if (!tl)
-			t = tl = block(TLIST, t, p, NOWORDS);
+			t = tl = block(TLIST, t, p, NULL);
 		else
-			tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
+			tl = tl->right = block(TLIST, tl->right, p, NULL);
 		if (!have_sep)
 			break;
 	}
-	REJECT;
+	reject = true;
 	return t;
 }
 
@@ -152,7 +152,7 @@ synio(int cf)
 
 	if (tpeek(cf) != REDIR)
 		return NULL;
-	ACCEPT;
+	reject = false;
 	iop = yylval.iop;
 	ishere = (iop->flag&IOTYPE) == IOHERE;
 	musthave(LWORD, ishere ? HEREDELIM : 0);
@@ -172,7 +172,7 @@ static void
 musthave(int c, int cf)
 {
 	if ((token(cf)) != c)
-		syntaxerr((char *) 0);
+		syntaxerr(NULL);
 }
 
 static struct op *
@@ -185,7 +185,7 @@ nested(int type, int smark, int emark)
 	t = c_list(true);
 	musthave(emark, KEYWORD|ALIAS);
 	nesting_pop(&old_nesting);
-	return (block(type, t, NOBLOCK, NOWORDS));
+	return (block(type, t, NULL, NULL));
 }
 
 static struct op *
@@ -197,23 +197,23 @@ get_command(int cf)
 	XPtrV args, vars;
 	struct nesting_state old_nesting;
 
-	iops = (struct ioword **) alloc(sizeofN(struct ioword *, NUFILE+1),
-	    ATEMP);
+	iops = areallocarray(NULL, NUFILE + 1,
+	    sizeof(struct ioword *), ATEMP);
 	XPinit(args, 16);
 	XPinit(vars, 16);
 
 	syniocf = KEYWORD|ALIAS;
 	switch (c = token(cf|KEYWORD|ALIAS|VARASN)) {
 	default:
-		REJECT;
-		afree((void*) iops, ATEMP);
+		reject = true;
+		afree(iops, ATEMP);
 		XPfree(args);
 		XPfree(vars);
 		return NULL; /* empty line */
 
 	case LWORD:
 	case REDIR:
-		REJECT;
+		reject = true;
 		syniocf &= ~(KEYWORD|ALIAS);
 		t = newtp(TCOM);
 		t->lineno = source->line;
@@ -228,7 +228,7 @@ get_command(int cf)
 				break;
 
 			case LWORD:
-				ACCEPT;
+				reject = false;
 				/* the iopn == 0 and XPsize(vars) == 0 are
 				 * dubious but at&t ksh acts this way
 				 */
@@ -249,14 +249,14 @@ get_command(int cf)
 				 */
 				afree(t, ATEMP);
 				if (XPsize(args) == 0 && XPsize(vars) == 0) {
-					ACCEPT;
+					reject = false;
 					goto Subshell;
 				}
 				/* Must be a function */
 				if (iopn != 0 || XPsize(args) != 1 ||
 				    XPsize(vars) != 0)
-					syntaxerr((char *) 0);
-				ACCEPT;
+					syntaxerr(NULL);
+				reject = false;
 				/*(*/
 				musthave(')', 0);
 				t = function_body(XPptrv(args)[0], false);
@@ -287,7 +287,7 @@ get_command(int cf)
 		/* Leave KEYWORD in syniocf (allow if (( 1 )) then ...) */
 		t = newtp(TCOM);
 		t->lineno = source->line;
-		ACCEPT;
+		reject = false;
 		XPput(args, wdcopy(let_cmd, ATEMP));
 		musthave(LWORD,LETEXPR);
 		XPput(args, yylval.cp);
@@ -297,7 +297,7 @@ get_command(int cf)
 	case DBRACKET: /* [[ .. ]] */
 		/* Leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */
 		t = newtp(TDBRACKET);
-		ACCEPT;
+		reject = false;
 		{
 			Test_env te;
 
@@ -356,9 +356,9 @@ get_command(int cf)
 	case BANG:
 		syniocf &= ~(KEYWORD|ALIAS);
 		t = pipeline(0);
-		if (t == (struct op *) 0)
-			syntaxerr((char *) 0);
-		t = block(TBANG, NOBLOCK, t, NOWORDS);
+		if (t == NULL)
+			syntaxerr(NULL);
+		t = block(TBANG, NULL, t, NULL);
 		break;
 
 	case TIME:
@@ -369,7 +369,7 @@ get_command(int cf)
 			t->str[0] = '\0'; /* TF_* flags */
 			t->str[1] = '\0';
 		}
-		t = block(TTIME, t, NOBLOCK, NOWORDS);
+		t = block(TTIME, t, NULL, NULL);
 		break;
 
 	case FUNCTION:
@@ -385,12 +385,12 @@ get_command(int cf)
 	}
 
 	if (iopn == 0) {
-		afree((void*) iops, ATEMP);
+		afree(iops, ATEMP);
 		t->ioact = NULL;
 	} else {
 		iops[iopn++] = NULL;
-		iops = (struct ioword **) aresize((void*) iops,
-		    sizeofN(struct ioword *, iopn), ATEMP);
+		iops = areallocarray(iops, iopn,
+		    sizeof(struct ioword *), ATEMP);
 		t->ioact = iops;
 	}
 
@@ -424,7 +424,7 @@ dogroup(void)
 	else if (c == '{')
 		c = '}';
 	else
-		syntaxerr((char *) 0);
+		syntaxerr(NULL);
 	list = c_list(true);
 	musthave(c, KEYWORD|ALIAS);
 	return list;
@@ -439,7 +439,7 @@ thenpart(void)
 	t = newtp(0);
 	t->left = c_list(true);
 	if (t->left == NULL)
-		syntaxerr((char *) 0);
+		syntaxerr(NULL);
 	t->right = elsepart();
 	return (t);
 }
@@ -452,7 +452,7 @@ elsepart(void)
 	switch (token(KEYWORD|ALIAS|VARASN)) {
 	case ELSE:
 		if ((t = c_list(true)) == NULL)
-			syntaxerr((char *) 0);
+			syntaxerr(NULL);
 		return (t);
 
 	case ELIF:
@@ -462,7 +462,7 @@ elsepart(void)
 		return (t);
 
 	default:
-		REJECT;
+		reject = true;
 	}
 	return NULL;
 }
@@ -480,7 +480,7 @@ caselist(void)
 	else if (c == '{')
 		c = '}';
 	else
-		syntaxerr((char *) 0);
+		syntaxerr(NULL);
 	t = tl = NULL;
 	while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) { /* no ALIAS here */
 		struct op *tc = casepart(c);
@@ -504,12 +504,12 @@ casepart(int endtok)
 	t = newtp(TPAT);
 	c = token(CONTIN|KEYWORD); /* no ALIAS here */
 	if (c != '(')
-		REJECT;
+		reject = true;
 	do {
 		musthave(LWORD, 0);
 		XPput(ptns, yylval.cp);
 	} while ((c = token(0)) == '|');
-	REJECT;
+	reject = true;
 	XPput(ptns, NULL);
 	t->vars = (char **) XPclose(ptns);
 	musthave(')', 0);
@@ -552,12 +552,12 @@ function_body(char *name,
 	 */
 	if (ksh_func) {
 		musthave('{', CONTIN|KEYWORD|ALIAS); /* } */
-		REJECT;
+		reject = true;
 	}
 
-	old_func_parse = e->flags & EF_FUNC_PARSE;
-	e->flags |= EF_FUNC_PARSE;
-	if ((t->left = get_command(CONTIN)) == (struct op *) 0) {
+	old_func_parse = genv->flags & EF_FUNC_PARSE;
+	genv->flags |= EF_FUNC_PARSE;
+	if ((t->left = get_command(CONTIN)) == NULL) {
 		/*
 		 * Probably something like foo() followed by eof or ;.
 		 * This is accepted by sh and ksh88.
@@ -565,18 +565,18 @@ function_body(char *name,
 		 * 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 = areallocarray(NULL, 2, sizeof(char *), ATEMP);
+		t->left->args[0] = alloc(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->args[1] = NULL;
+		t->left->vars = alloc(sizeof(char *), ATEMP);
+		t->left->vars[0] = NULL;
 		t->left->lineno = 1;
 	}
 	if (!old_func_parse)
-		e->flags &= ~EF_FUNC_PARSE;
+		genv->flags &= ~EF_FUNC_PARSE;
 
 	return t;
 }
@@ -591,13 +591,13 @@ wordlist(void)
 	/* 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;
+			reject = true;
 		return NULL;
 	}
 	while ((c = token(0)) == LWORD)
 		XPput(args, yylval.cp);
 	if (c != '\n' && c != ';')
-		syntaxerr((char *) 0);
+		syntaxerr(NULL);
 	XPput(args, NULL);
 	return (char **) XPclose(args);
 }
@@ -682,7 +682,7 @@ syntaxerr(const char *what)
 
 	if (!what)
 		what = "unexpected";
-	REJECT;
+	reject = true;
 	c = token(0);
     Again:
 	switch (c) {
@@ -698,7 +698,7 @@ syntaxerr(const char *what)
 		/* NOTREACHED */
 
 	case LWORD:
-		s = snptreef((char *) 0, 32, "%S", yylval.cp);
+		s = snptreef(NULL, 32, "%S", yylval.cp);
 		break;
 
 	case REDIR:
@@ -743,7 +743,7 @@ newtp(int type)
 {
 	struct op *t;
 
-	t = (struct op *) alloc(sizeof(*t), ATEMP);
+	t = alloc(sizeof(*t), ATEMP);
 	t->type = type;
 	t->u.evalflags = 0;
 	t->args = t->vars = NULL;
@@ -823,7 +823,7 @@ dbtestp_isa(Test_env *te, Test_meta meta)
 {
 	int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN));
 	int uqword = 0;
-	char *save = (char *) 0;
+	char *save = NULL;
 	int ret = 0;
 
 	/* unquoted word? */
@@ -850,7 +850,7 @@ dbtestp_isa(Test_env *te, Test_meta meta)
 	} else /* meta == TM_END */
 		ret = uqword && strcmp(yylval.cp, db_close) == 0;
 	if (ret) {
-		ACCEPT;
+		reject = false;
 		if (meta != TM_END) {
 			if (!save)
 				save = wdcopy(dbtest_tokens[(int) meta], ATEMP);
@@ -866,9 +866,9 @@ dbtestp_getopnd(Test_env *te, Test_op op, int do_eval)
 	int c = tpeek(ARRAYVAR);
 
 	if (c != LWORD)
-		return (const char *) 0;
+		return NULL;
 
-	ACCEPT;
+	reject = false;
 	XPput(*te->pos.av, yylval.cp);
 
 	return null;
@@ -887,7 +887,7 @@ dbtestp_error(Test_env *te, int offset, const char *msg)
 	te->flags |= TEF_ERROR;
 
 	if (offset < 0) {
-		REJECT;
+		reject = true;
 		/* Kludgy to say the least... */
 		symbol = LWORD;
 		yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av) +
diff --git a/table.c b/table.c
@@ -1,13 +1,30 @@
-/*	$OpenBSD: table.c,v 1.15 2012/02/19 07:52:30 otto Exp $	*/
+/*	$OpenBSD: table.c,v 1.23 2015/11/01 15:38:53 mmcc Exp $	*/
 
 /*
  * dynamic hashed associative table for commands and variables
  */
 
+#include <limits.h>
+#include <stddef.h>
+#include <string.h>
+
 #include "sh.h"
 
 #define	INIT_TBLS	8	/* initial table size (power of 2) */
 
+struct table taliases;	/* tracked aliases */
+struct table builtins;	/* built-in commands */
+struct table aliases;	/* aliases */
+struct table keywords;	/* keywords */
+struct table homedirs;	/* homedir() cache */
+
+char *path;		/* copy of either PATH or def_path */
+const char *def_path;	/* path to use if PATH not set */
+char *tmpdir;		/* TMPDIR value */
+const char *prompt;
+int cur_prompt;		/* PS1 or PS2 */
+int current_lineno;	/* LINENO value */
+
 static void	texpand(struct table *, int);
 static int	tnamecmp(const void *, const void *);
 
@@ -40,7 +57,7 @@ texpand(struct table *tp, int nsize)
 	struct tbl **ntblp, **otblp = tp->tbls;
 	int osize = tp->size;
 
-	ntblp = (struct tbl**) alloc(sizeofN(struct tbl *, nsize), tp->areap);
+	ntblp = areallocarray(NULL, nsize, sizeof(struct tbl *), tp->areap);
 	for (i = 0; i < nsize; i++)
 		ntblp[i] = NULL;
 	tp->size = nsize;
@@ -58,10 +75,10 @@ texpand(struct table *tp, int nsize)
 				*p = tblp;
 				tp->nfree--;
 			} else if (!(tblp->flag & FINUSE)) {
-				afree((void*)tblp, tp->areap);
+				afree(tblp, tp->areap);
 			}
 		}
-	afree((void*)otblp, tp->areap);
+	afree(otblp, tp->areap);
 }
 
 /* table */
@@ -117,13 +134,13 @@ ktenter(struct table *tp, const char *n, unsigned int h)
 
 	/* create new tbl entry */
 	len = strlen(n) + 1;
-	p = (struct tbl *) alloc(offsetof(struct tbl, name[0]) + len,
+	p = 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;
+	p->u.array = NULL;
 	memcpy(p->name, n, len);
 
 	/* enter in tp->tbls */
@@ -170,7 +187,8 @@ ktsort(struct table *tp)
 	int i;
 	struct tbl **p, **sp, **dp;
 
-	p = (struct tbl **)alloc(sizeofN(struct tbl *, tp->size+1), ATEMP);
+	p = areallocarray(NULL, tp->size + 1,
+	    sizeof(struct tbl *), ATEMP);
 	sp = tp->tbls;		/* source */
 	dp = p;			/* dest */
 	for (i = 0; i < tp->size; i++)
diff --git a/table.h b/table.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: table.h,v 1.8 2012/02/19 07:52:30 otto Exp $	*/
+/*	$OpenBSD: table.h,v 1.12 2017/08/30 17:08:45 jca Exp $	*/
 
 /* $From: table.h,v 1.3 1994/05/31 13:34:34 michael Exp $ */
 
@@ -13,7 +13,7 @@ struct table {
 };
 
 struct tbl {			/* table item */
-	Tflag	flag;		/* flags */
+	int	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 */
@@ -136,12 +136,11 @@ struct tstate {
 	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 */
+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;
@@ -161,23 +160,33 @@ extern const struct builtin shbuiltins [], kshbuiltins [];
 #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
+#define	V_HISTCONTROL		9
+#define	V_HISTSIZE		10
+#define	V_HISTFILE		11
+#define	V_VISUAL		12
+#define	V_EDITOR		13
+#define	V_COLUMNS		14
+#define	V_POSIXLY_CORRECT	15
+#define	V_TMOUT			16
+#define	V_TMPDIR		17
+#define	V_LINENO		18
 
 /* 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 */
+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 */
+
+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 *);
diff --git a/trap.c b/trap.c
@@ -1,9 +1,14 @@
-/*	$OpenBSD: trap.c,v 1.23 2010/05/19 17:36:08 jasper Exp $	*/
+/*	$OpenBSD: trap.c,v 1.30 2016/03/17 23:33:23 mmcc Exp $	*/
 
 /*
  * signal handling
  */
 
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
 #include "sh.h"
 
 Trap sigtraps[NSIG + 1];
@@ -57,7 +62,6 @@ alarm_init(void)
 		SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
 }
 
-/* ARGSUSED */
 static void
 alarm_catcher(int sig)
 {
@@ -198,7 +202,7 @@ runtraps(int flag)
 		fatal_trap = 0;
 	for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
 		if (p->set && (!flag ||
-		    ((p->flags & flag) && p->trap == (char *) 0)))
+		    ((p->flags & flag) && p->trap == NULL)))
 			runtrap(p);
 }
 
@@ -211,7 +215,7 @@ runtrap(Trap *p)
 	int	old_changed = 0;
 
 	p->set = 0;
-	if (trapstr == (char *) 0) { /* SIG_DFL */
+	if (trapstr == NULL) { /* SIG_DFL */
 		if (p->flags & TF_FATAL) {
 			/* eg, SIGHUP */
 			exstat = 128 + i;
@@ -229,7 +233,7 @@ runtrap(Trap *p)
 	if (i == SIGEXIT_ || i == SIGERR_) {	/* avoid recursion on these */
 		old_changed = p->flags & TF_CHANGED;
 		p->flags &= ~TF_CHANGED;
-		p->trap = (char *) 0;
+		p->trap = NULL;
 	}
 	oexstat = exstat;
 	/* Note: trapstr is fully parsed before anything is executed, thus
@@ -260,7 +264,7 @@ cleartraps(void)
 	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);
+			settrap(p, NULL);
 	}
 }
 
@@ -282,8 +286,7 @@ settrap(Trap *p, char *s)
 {
 	sig_t f;
 
-	if (p->trap)
-		afree(p->trap, APERM);
+	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;
@@ -387,7 +390,7 @@ setsig(Trap *p, sig_t f, int flags)
 		sigemptyset(&sigact.sa_mask);
 		sigact.sa_flags = 0 /* interruptible */;
 		sigact.sa_handler = f;
-		sigaction(p->signal, &sigact, (struct sigaction *) 0);
+		sigaction(p->signal, &sigact, NULL);
 	}
 
 	return 1;
diff --git a/tree.c b/tree.c
@@ -1,9 +1,11 @@
-/*	$OpenBSD: tree.c,v 1.20 2012/06/27 07:17:19 otto Exp $	*/
+/*	$OpenBSD: tree.c,v 1.27 2015/11/01 15:38:53 mmcc Exp $	*/
 
 /*
  * command tree climbing
  */
 
+#include <string.h>
+
 #include "sh.h"
 
 #define INDENT	4
@@ -348,11 +350,6 @@ tputS(char *wp, struct shf *shf)
 		}
 }
 
-/*
- * this is the _only_ way to reliably handle
- * variable args with an ANSI compiler
- */
-/* VARARGS */
 void
 fptreef(struct shf *shf, int indent, const char *fmt, ...)
 {
@@ -363,7 +360,6 @@ fptreef(struct shf *shf, int indent, const char *fmt, ...)
   va_end(va);
 }
 
-/* VARARGS */
 char *
 snptreef(char *s, int n, const char *fmt, ...)
 {
@@ -457,7 +453,7 @@ tcopy(struct op *t, Area *ap)
 	if (t == NULL)
 		return NULL;
 
-	r = (struct op *) alloc(sizeof(struct op), ap);
+	r = alloc(sizeof(struct op), ap);
 
 	r->type = t->type;
 	r->u.evalflags = t->u.evalflags;
@@ -469,8 +465,8 @@ tcopy(struct op *t, Area *ap)
 	else {
 		for (tw = t->vars; *tw++ != NULL; )
 			;
-		rw = r->vars = (char **)
-			alloc((tw - t->vars + 1) * sizeof(*tw), ap);
+		rw = r->vars = areallocarray(NULL, tw - t->vars + 1,
+		    sizeof(*tw), ap);
 		for (tw = t->vars; *tw != NULL; )
 			*rw++ = wdcopy(*tw++, ap);
 		*rw = NULL;
@@ -481,8 +477,8 @@ tcopy(struct op *t, Area *ap)
 	else {
 		for (tw = t->args; *tw++ != NULL; )
 			;
-		rw = r->args = (char **)
-			alloc((tw - t->args + 1) * sizeof(*tw), ap);
+		rw = r->args = areallocarray(NULL, tw - t->args + 1,
+		    sizeof(*tw), ap);
 		for (tw = t->args; *tw != NULL; )
 			*rw++ = wdcopy(*tw++, ap);
 		*rw = NULL;
@@ -565,7 +561,7 @@ wdstrip(const char *wp)
 	struct shf shf;
 	int c;
 
-	shf_sopen((char *) 0, 32, SHF_WR | SHF_DYNAMIC, &shf);
+	shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf);
 
 	/* problems:
 	 *	`...` -> $(...)
@@ -632,20 +628,20 @@ iocopy(struct ioword **iow, Area *ap)
 
 	for (ior = iow; *ior++ != NULL; )
 		;
-	ior = (struct ioword **) alloc((ior - iow + 1) * sizeof(*ior), ap);
+	ior = areallocarray(NULL, 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);
+		q = alloc(sizeof(*p), ap);
 		ior[i] = q;
 		*q = *p;
-		if (p->name != (char *) 0)
+		if (p->name != NULL)
 			q->name = wdcopy(p->name, ap);
-		if (p->delim != (char *) 0)
+		if (p->delim != NULL)
 			q->delim = wdcopy(p->delim, ap);
-		if (p->heredoc != (char *) 0)
+		if (p->heredoc != NULL)
 			q->heredoc = str_save(p->heredoc, ap);
 	}
 	ior[i] = NULL;
@@ -665,19 +661,18 @@ tfree(struct op *t, Area *ap)
 	if (t == NULL)
 		return;
 
-	if (t->str != NULL)
-		afree((void*)t->str, ap);
+	afree(t->str, ap);
 
 	if (t->vars != NULL) {
 		for (w = t->vars; *w != NULL; w++)
-			afree((void*)*w, ap);
-		afree((void*)t->vars, ap);
+			afree(*w, ap);
+		afree(t->vars, ap);
 	}
 
 	if (t->args != NULL) {
 		for (w = t->args; *w != NULL; w++)
-			afree((void*)*w, ap);
-		afree((void*)t->args, ap);
+			afree(*w, ap);
+		afree(t->args, ap);
 	}
 
 	if (t->ioact != NULL)
@@ -686,7 +681,7 @@ tfree(struct op *t, Area *ap)
 	tfree(t->left, ap);
 	tfree(t->right, ap);
 
-	afree((void*)t, ap);
+	afree(t, ap);
 }
 
 static	void
@@ -696,13 +691,10 @@ iofree(struct ioword **iow, Area *ap)
 	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);
+		afree(p->name, ap);
+		afree(p->delim, ap);
+		afree(p->heredoc, ap);
+		afree(p, ap);
 	}
 	afree(iow, ap);
 }
diff --git a/tree.h b/tree.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: tree.h,v 1.10 2005/03/28 21:28:22 deraadt Exp $	*/
+/*	$OpenBSD: tree.h,v 1.12 2015/10/15 22:53:50 mmcc Exp $	*/
 
 /*
  * command trees for compile/execute
@@ -6,10 +6,6 @@
 
 /* $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.
  */
@@ -139,3 +135,11 @@ struct ioword {
 #define DB_AND	3		/* && -> -a conversion */
 #define DB_BE	4		/* an inserted -BE */
 #define DB_PAT	5		/* a pattern argument */
+
+void	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 *);
diff --git a/tty.c b/tty.c
@@ -1,12 +1,27 @@
-/*	$OpenBSD: tty.c,v 1.10 2014/08/10 02:44:26 guenther Exp $	*/
+/*	$OpenBSD: tty.c,v 1.16 2015/12/14 13:59:42 tb Exp $	*/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
 
 #include "sh.h"
-#include <sys/stat.h>
-#define EXTERN
 #include "tty.h"
-#undef EXTERN
 
-/* Initialize tty_fd.  Used for saving/reseting tty modes upon
+int		tty_fd = -1;	/* dup'd tty file descriptor */
+int		tty_devtty;	/* true if tty_fd is from /dev/tty */
+struct termios	tty_state;	/* saved tty state */
+
+void
+tty_close(void)
+{
+	if (tty_fd >= 0) {
+		close(tty_fd);
+		tty_fd = -1;
+	}
+}
+
+/* Initialize tty_fd.  Used for saving/resetting tty modes upon
  * foreground job completion and for setting up tty process group.
  */
 void
@@ -15,19 +30,15 @@ tty_init(int init_ttystate)
 	int	do_close = 1;
 	int	tfd;
 
-	if (tty_fd >= 0) {
-		close(tty_fd);
-		tty_fd = -1;
-	}
+	tty_close();
 	tty_devtty = 1;
 
-	if ((tfd = open("/dev/tty", O_RDWR, 0)) < 0) {
+	tfd = open("/dev/tty", O_RDWR, 0);
+	if (tfd < 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;
@@ -46,12 +57,3 @@ tty_init(int init_ttystate)
 	if (do_close)
 		close(tfd);
 }
-
-void
-tty_close(void)
-{
-	if (tty_fd >= 0) {
-		close(tty_fd);
-		tty_fd = -1;
-	}
-}
diff --git a/tty.h b/tty.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto Exp $	*/
+/*	$OpenBSD: tty.h,v 1.6 2015/09/25 11:58:14 nicm Exp $	*/
 
 /*
 	tty.h -- centralized definitions for a variety of terminal interfaces
@@ -11,27 +11,11 @@
 	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 int		tty_fd;		/* 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__
diff --git a/var.c b/var.c
@@ -1,12 +1,16 @@
-/*	$OpenBSD: var.c,v 1.41 2015/04/17 17:20:41 deraadt Exp $	*/
+/*	$OpenBSD: var.c,v 1.59 2017/08/30 17:08:45 jca Exp $	*/
 
-#include "sh.h"
-#include <time.h>
-#include "ksh_limval.h"
 #include <sys/stat.h>
+
 #include <ctype.h>
+#include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "sh.h"
 
 /*
  * Variables
@@ -30,7 +34,7 @@ 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
+ * assume caller has allocated and set up genv->loc
  */
 void
 newblock(void)
@@ -38,21 +42,21 @@ newblock(void)
 	struct block *l;
 	static char *const empty[] = {null};
 
-	l = (struct block *) alloc(sizeof(struct block), ATEMP);
+	l = alloc(sizeof(struct block), ATEMP);
 	l->flags = 0;
-	ainit(&l->area); /* todo: could use e->area (l->area => l->areap) */
-	if (!e->loc) {
+	ainit(&l->area); /* todo: could use genv->area (l->area => l->areap) */
+	if (!genv->loc) {
 		l->argc = 0;
 		l->argv = (char **) empty;
 	} else {
-		l->argc = e->loc->argc;
-		l->argv = e->loc->argv;
+		l->argc = genv->loc->argc;
+		l->argv = genv->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;
+	l->next = genv->loc;
+	genv->loc = l;
 }
 
 /*
@@ -61,11 +65,11 @@ newblock(void)
 void
 popblock(void)
 {
-	struct block *l = e->loc;
+	struct block *l = genv->loc;
 	struct tbl *vp, **vpp = l->vars.tbls, *vq;
 	int i;
 
-	e->loc = l->next;	/* pop block */
+	genv->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)
@@ -94,6 +98,7 @@ initvar(void)
 		{ "POSIXLY_CORRECT",	V_POSIXLY_CORRECT },
 		{ "TMPDIR",		V_TMPDIR },
 #ifdef HISTORY
+		{ "HISTCONTROL",	V_HISTCONTROL },
 		{ "HISTFILE",		V_HISTFILE },
 		{ "HISTSIZE",		V_HISTSIZE },
 #endif /* HISTORY */
@@ -108,7 +113,7 @@ initvar(void)
 		{ "SECONDS",		V_SECONDS },
 		{ "TMOUT",		V_TMOUT },
 		{ "LINENO",		V_LINENO },
-		{ (char *) 0,	0 }
+		{ NULL,	0 }
 	};
 	int i;
 	struct tbl *tp;
@@ -158,7 +163,7 @@ array_index_calc(const char *n, bool *arrayp, int *valp)
 struct tbl *
 global(const char *n)
 {
-	struct block *l = e->loc;
+	struct block *l = genv->loc;
 	struct tbl *vp;
 	long	 num;
 	int c;
@@ -215,7 +220,7 @@ global(const char *n)
 		}
 		return vp;
 	}
-	for (l = e->loc; ; l = l->next) {
+	for (l = genv->loc; ; l = l->next) {
 		vp = ktsearch(&l->vars, n, h);
 		if (vp != NULL) {
 			if (array)
@@ -241,7 +246,7 @@ global(const char *n)
 struct tbl *
 local(const char *n, bool copy)
 {
-	struct block *l = e->loc;
+	struct block *l = genv->loc;
 	struct tbl *vp;
 	unsigned int h;
 	bool	 array;
@@ -260,7 +265,7 @@ local(const char *n, bool copy)
 	vp = ktenter(&l->vars, n, h);
 	if (copy && !(vp->flag & DEFINED)) {
 		struct block *ll = l;
-		struct tbl *vq = (struct tbl *) 0;
+		struct tbl *vq = NULL;
 
 		while ((ll = ll->next) && !(vq = ktsearch(&ll->vars, n, h)))
 			;
@@ -352,12 +357,12 @@ int
 setstr(struct tbl *vq, const char *s, int error_ok)
 {
 	const char *fs = NULL;
-	int no_ro_check = error_ok & 0x4;
-	error_ok &= ~0x4;
+	int no_ro_check = error_ok & KSH_IGNORE_RDONLY;
+	error_ok &= ~KSH_IGNORE_RDONLY;
 	if ((vq->flag & RDONLY) && !no_ro_check) {
 		warningf(true, "%s: is read only", vq->name);
 		if (!error_ok)
-			errorf("%s", null);
+			errorf(NULL);
 		return 0;
 	}
 	if (!(vq->flag&INTEGER)) { /* string dest */
@@ -368,7 +373,7 @@ setstr(struct tbl *vq, const char *s, int error_ok)
 				internal_errorf(true,
 				    "setstr: %s=%s: assigning to self",
 				    vq->name, s);
-			afree((void*)vq->val.s, vq->areap);
+			afree(vq->val.s, vq->areap);
 		}
 		vq->flag &= ~(ISSET|ALLOC);
 		vq->type = 0;
@@ -387,8 +392,7 @@ setstr(struct tbl *vq, const char *s, int error_ok)
 	vq->flag |= ISSET;
 	if ((vq->flag&SPECIAL))
 		setspec(vq);
-	if (fs)
-		afree((char *)fs, ATEMP);
+	afree((void *)fs, ATEMP);
 	return 1;
 }
 
@@ -516,7 +520,7 @@ formatstr(struct tbl *vp, const char *s)
 	} else
 		nlen = olen;
 
-	p = (char *) alloc(nlen + 1, ATEMP);
+	p = alloc(nlen + 1, ATEMP);
 	if (vp->flag & (RJUST|LJUST)) {
 		int slen;
 
@@ -572,14 +576,13 @@ export(struct tbl *vp, const char *val)
 	int vallen = strlen(val) + 1;
 
 	vp->flag |= ALLOC;
-	xp = (char*)alloc(namelen + 1 + vallen, vp->areap);
+	xp = 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);
+	afree(op, vp->areap);
 }
 
 /*
@@ -588,7 +591,7 @@ export(struct tbl *vp, const char *val)
  * 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)
+typeset(const char *var, int set, int clr, int field, int base)
 {
 	struct tbl *vp;
 	struct tbl *vpbase, *t;
@@ -659,6 +662,7 @@ typeset(const char *var, Tflag set, Tflag clr, int field, int base)
 		 */
 		for (t = vpbase; t; t = t->u.array) {
 			int fake_assign;
+			int error_ok = KSH_RETURN_ERROR;
 			char *s = NULL;
 			char *free_me = NULL;
 
@@ -669,11 +673,11 @@ typeset(const char *var, Tflag set, Tflag clr, int field, int base)
 			if (fake_assign) {
 				if (t->flag & INTEGER) {
 					s = str_val(t);
-					free_me = (char *) 0;
+					free_me = NULL;
 				} else {
 					s = t->val.s + t->type;
 					free_me = (t->flag & ALLOC) ? t->val.s :
-					    (char *) 0;
+					    NULL;
 				}
 				t->flag &= ~ALLOC;
 			}
@@ -681,6 +685,10 @@ typeset(const char *var, Tflag set, Tflag clr, int field, int base)
 				t->type = 0;
 				t->flag &= ~ALLOC;
 			}
+			if (!(t->flag & RDONLY) && (set & RDONLY)) {
+				/* allow var to be initialized read-only */
+				error_ok |= KSH_IGNORE_RDONLY;
+			}
 			t->flag = (t->flag | set) & ~clr;
 			/* Don't change base if assignment is to be done,
 			 * in case assignment fails.
@@ -690,7 +698,7 @@ typeset(const char *var, Tflag set, Tflag clr, int field, int base)
 			if (set & (LJUST|RJUST|ZEROFIL))
 				t->u2.field = field;
 			if (fake_assign) {
-				if (!setstr(t, s, KSH_RETURN_ERROR)) {
+				if (!setstr(t, s, error_ok)) {
 					/* Somewhat arbitrary action here:
 					 * zap contents of variable, but keep
 					 * the flag settings.
@@ -700,30 +708,28 @@ typeset(const char *var, Tflag set, Tflag clr, int field, int base)
 						t->flag &= ~ISSET;
 					else {
 						if (t->flag & ALLOC)
-							afree((void*) t->val.s,
-							    t->areap);
+							afree(t->val.s, t->areap);
 						t->flag &= ~(ISSET|ALLOC);
 						t->type = 0;
 					}
 				}
-				if (free_me)
-					afree((void *) free_me, t->areap);
+				afree(free_me, t->areap);
 			}
 		}
 		if (!ok)
-		    errorf("%s", null);
+		    errorf(NULL);
 	}
 
 	if (val != NULL) {
 		if (vp->flag&INTEGER) {
 			/* do not zero base before assignment */
-			setstr(vp, val, KSH_UNWIND_ERROR | 0x4);
+			setstr(vp, val, KSH_UNWIND_ERROR | KSH_IGNORE_RDONLY);
 			/* 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);
+			setstr(vp, val, KSH_RETURN_ERROR | KSH_IGNORE_RDONLY);
 	}
 
 	/* only x[0] is ever exported, so use vpbase */
@@ -741,7 +747,7 @@ void
 unset(struct tbl *vp, int array_ref)
 {
 	if (vp->flag & ALLOC)
-		afree((void*)vp->val.s, vp->areap);
+		afree(vp->val.s, vp->areap);
 	if ((vp->flag & ARRAY) && !array_ref) {
 		struct tbl *a, *tmp;
 
@@ -750,10 +756,10 @@ unset(struct tbl *vp, int array_ref)
 			tmp = a;
 			a = a->u.array;
 			if (tmp->flag & ALLOC)
-				afree((void *) tmp->val.s, tmp->areap);
+				afree(tmp->val.s, tmp->areap);
 			afree(tmp, tmp->areap);
 		}
-		vp->u.array = (struct tbl *) 0;
+		vp->u.array = NULL;
 	}
 	/* If foo[0] is being unset, the remainder of the array is kept... */
 	vp->flag &= SPECIAL | (array_ref ? ARRAY|DEFINED : 0);
@@ -835,13 +841,13 @@ is_wdvarassign(const char *s)
 char **
 makenv(void)
 {
-	struct block *l = e->loc;
+	struct block *l;
 	XPtrV env;
 	struct tbl *vp, **vpp;
 	int i;
 
 	XPinit(env, 64);
-	for (l = e->loc; l != NULL; l = l->next)
+	for (l = genv->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)) {
@@ -954,8 +960,7 @@ setspec(struct tbl *vp)
 
 	switch (special(vp->name)) {
 	case V_PATH:
-		if (path)
-			afree(path, APERM);
+		afree(path, APERM);
 		path = str_save(str_val(vp), APERM);
 		flushcom(1);	/* clear tracked aliases */
 		break;
@@ -972,10 +977,8 @@ setspec(struct tbl *vp)
 		change_flag(FPOSIX, OF_SPECIAL, 1);
 		break;
 	case V_TMPDIR:
-		if (tmpdir) {
-			afree(tmpdir, APERM);
-			tmpdir = (char *) 0;
-		}
+		afree(tmpdir, APERM);
+		tmpdir = NULL;
 		/* Use tmpdir iff it is an absolute path, is writable and
 		 * searchable and is a directory...
 		 */
@@ -989,6 +992,9 @@ setspec(struct tbl *vp)
 		}
 		break;
 #ifdef HISTORY
+	case V_HISTCONTROL:
+		sethistcontrol(str_val(vp));
+		break;
 	case V_HISTSIZE:
 		vp->flag &= ~SPECIAL;
 		sethistsize((int) intval(vp));
@@ -1061,8 +1067,7 @@ unsetspec(struct tbl *vp)
 {
 	switch (special(vp->name)) {
 	case V_PATH:
-		if (path)
-			afree(path, APERM);
+		afree(path, APERM);
 		path = str_save(def_path, APERM);
 		flushcom(1);	/* clear tracked aliases */
 		break;
@@ -1072,17 +1077,20 @@ unsetspec(struct tbl *vp)
 		break;
 	case V_TMPDIR:
 		/* should not become unspecial */
-		if (tmpdir) {
-			afree(tmpdir, APERM);
-			tmpdir = (char *) 0;
-		}
+		afree(tmpdir, APERM);
+		tmpdir = NULL;
 		break;
 	case V_MAIL:
-		mbset((char *) 0);
+		mbset(NULL);
 		break;
 	case V_MAILPATH:
-		mpset((char *) 0);
+		mpset(NULL);
+		break;
+#ifdef HISTORY
+	case V_HISTCONTROL:
+		sethistcontrol(NULL);
 		break;
+#endif
 	case V_LINENO:
 	case V_MAILCHECK:	/* at&t ksh leaves previous value in place */
 	case V_RANDOM:
@@ -1132,7 +1140,7 @@ arraysearch(struct tbl *vp, int val)
 		else
 			new = curr;
 	} else
-		new = (struct tbl *)alloc(sizeof(struct tbl) + namelen,
+		new = alloc(sizeof(struct tbl) + namelen,
 		    vp->areap);
 	strlcpy(new->name, vp->name, namelen);
 	new->flag = vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL);
diff --git a/vi.c b/vi.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: vi.c,v 1.28 2013/12/18 16:45:46 deraadt Exp $	*/
+/*	$OpenBSD: vi.c,v 1.49 2017/09/02 18:53:53 deraadt Exp $	*/
 
 /*
  *	vi command editing
@@ -9,21 +9,23 @@
 #include "config.h"
 #ifdef VI
 
-#include "sh.h"
-#include <ctype.h>
 #include <sys/stat.h>		/* completion */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sh.h"
 #include "edit.h"
 
-#define CMDLEN		2048
-#define Ctrl(c)		(c&0x1f)
-#define	is_wordch(c)	(letnum(c))
+#define CTRL(c)		(c & 0x1f)
 
 struct edstate {
-	int	winleft;
-	char	*cbuf;
-	int	cbufsize;
-	int	linelen;
-	int	cursor;
+	char	*cbuf;		/* main buffer to build the command line */
+	int	cbufsize;	/* number of bytes allocated for cbuf */
+	int	linelen;	/* current number of bytes in cbuf */
+	int	winleft;	/* first byte# in cbuf to be displayed */
+	int	cursor;		/* byte# in cbuf having the cursor */
 };
 
 
@@ -66,6 +68,7 @@ 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);
+static int	isu8cont(unsigned char);
 
 #define C_	0x1		/* a valid command that isn't a M_, E_, U_ */
 #define M_	0x2		/* movement command (h, l, etc.) */
@@ -139,24 +142,24 @@ const unsigned char	classify[128] = {
 #define VSEARCH		9		/* /, ? */
 #define VVERSION	10		/* <ESC> ^V */
 
-static char		undocbuf[CMDLEN];
+static char		undocbuf[LINE];
 
 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	undobuf = { undocbuf, LINE, 0, 0, 0 };
 
 static struct edstate	*es;			/* current editor state */
 static struct edstate	*undo;
 
-static char	ibuf[CMDLEN];		/* input buffer */
+static char	ibuf[LINE];		/* 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	srchlen;		/* number of bytes in search pattern */
+static char	ybuf[LINE];		/* yank buffer */
 static int	yanklen;		/* length of yank buffer */
 static int	fsavecmd = ' ';		/* last find command */
 static int	fsavech;		/* character to find */
@@ -164,7 +167,7 @@ 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	insert;			/* mode: INSERT, REPLACE, or 0 */
 static int	hnum;			/* position in history */
 static int	ohnum;			/* history line copied (after mod) */
 static int	hlast;			/* 1 past last position in history */
@@ -192,7 +195,7 @@ x_vi(char *buf, size_t len)
 {
 	int	c;
 
-	vi_reset(buf, len > CMDLEN ? CMDLEN : len);
+	vi_reset(buf, len > LINE ? LINE : len);
 	vi_pprompt(1);
 	x_flush();
 	while (1) {
@@ -257,7 +260,7 @@ vi_hook(int ch)
 
 	case VNORMAL:
 		if (insert != 0) {
-			if (ch == Ctrl('v')) {
+			if (ch == CTRL('v')) {
 				state = VLIT;
 				ch = '^';
 			}
@@ -371,7 +374,7 @@ vi_hook(int ch)
 		break;
 
 	case VXCH:
-		if (ch == Ctrl('['))
+		if (ch == CTRL('['))
 			state = VNORMAL;
 		else {
 			curcmd[cmdlen++] = ch;
@@ -380,7 +383,7 @@ vi_hook(int ch)
 		break;
 
 	case VSEARCH:
-		if (ch == '\r' || ch == '\n' /*|| ch == Ctrl('[')*/ ) {
+		if (ch == '\r' || ch == '\n' /*|| ch == CTRL('[')*/ ) {
 			restore_cbuf();
 			/* Repeat last search? */
 			if (srchlen == 0) {
@@ -395,10 +398,14 @@ vi_hook(int ch)
 				(void) strlcpy(srchpat, locpat, sizeof srchpat);
 			}
 			state = VCMD;
-		} else if (ch == edchars.erase || ch == Ctrl('h')) {
+		} else if (ch == edchars.erase || ch == CTRL('h')) {
 			if (srchlen != 0) {
-				srchlen--;
-				es->linelen -= char_len((unsigned char)locpat[srchlen]);
+				do {
+					srchlen--;
+					es->linelen -= char_len(
+					    (unsigned char)locpat[srchlen]);
+				} while (srchlen > 0 &&
+				    isu8cont(locpat[srchlen]));
 				es->cursor = es->linelen;
 				refresh(0);
 				return 0;
@@ -547,7 +554,7 @@ nextstate(int ch)
 		return VXCH;
 	else if (ch == '.')
 		return VREDO;
-	else if (ch == Ctrl('v'))
+	else if (ch == CTRL('v'))
 		return VVERSION;
 	else if (is_cmd(ch))
 		return VCMD;
@@ -560,31 +567,34 @@ vi_insert(int ch)
 {
 	int	tcursor;
 
-	if (ch == edchars.erase || ch == Ctrl('h')) {
+	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);
 		}
+		tcursor = es->cursor - 1;
+		while(tcursor > 0 && isu8cont(es->cbuf[tcursor]))
+			tcursor--;
+		if (insert == INSERT)
+			memmove(es->cbuf + tcursor, es->cbuf + es->cursor,
+			    es->linelen - es->cursor);
+		if (insert == REPLACE && es->cursor < undo->linelen)
+			memcpy(es->cbuf + tcursor, undo->cbuf + tcursor,
+			    es->cursor - tcursor);
+		else
+			es->linelen -= es->cursor - tcursor;
+		if (inslen < es->cursor - tcursor)
+			inslen = 0;
+		else
+			inslen -= es->cursor - tcursor;
+		es->cursor = tcursor;
 		expanded = NONE;
 		return 0;
 	}
@@ -618,7 +628,7 @@ vi_insert(int ch)
 	 * buffer (if user inserts & deletes char, ibuf gets trashed and
 	 * we don't want to use it)
 	 */
-	if (first_insert && ch != Ctrl('['))
+	if (first_insert && ch != CTRL('['))
 		saved_inslen = 0;
 	switch (ch) {
 	case '\0':
@@ -628,7 +638,7 @@ vi_insert(int ch)
 	case '\n':
 		return 1;
 
-	case Ctrl('['):
+	case CTRL('['):
 		expanded = NONE;
 		if (first_insert) {
 			first_insert = 0;
@@ -646,19 +656,19 @@ vi_insert(int ch)
 			return redo_insert(lastac - 1);
 
 	/* { Begin nonstandard vi commands */
-	case Ctrl('x'):
+	case CTRL('x'):
 		expand_word(0);
 		break;
 
-	case Ctrl('f'):
+	case CTRL('f'):
 		complete_word(0, 0);
 		break;
 
-	case Ctrl('e'):
+	case CTRL('e'):
 		print_expansions(es, 0);
 		break;
 
-	case Ctrl('i'):
+	case CTRL('i'):
 		if (Flag(FVITABCOMPLETE)) {
 			complete_word(0, 0);
 			break;
@@ -697,7 +707,8 @@ vi_cmd(int argcnt, const char *cmd)
 	if (is_move(*cmd)) {
 		if ((cur = domove(argcnt, cmd, 0)) >= 0) {
 			if (cur == es->linelen && cur != 0)
-				cur--;
+				while (isu8cont(es->cbuf[--cur]))
+					continue;
 			es->cursor = cur;
 		} else
 			return -1;
@@ -713,8 +724,8 @@ vi_cmd(int argcnt, const char *cmd)
 		}
 		switch (*cmd) {
 
-		case Ctrl('l'):
-		case Ctrl('r'):
+		case CTRL('l'):
+		case CTRL('r'):
 			redraw_line(1);
 			break;
 
@@ -758,7 +769,8 @@ vi_cmd(int argcnt, const char *cmd)
 		case 'a':
 			modified = 1; hnum = hlast;
 			if (es->linelen != 0)
-				es->cursor++;
+				while (isu8cont(es->cbuf[++es->cursor]))
+					continue;
 			insert = INSERT;
 			break;
 
@@ -886,7 +898,7 @@ vi_cmd(int argcnt, const char *cmd)
 
 		case 'j':
 		case '+':
-		case Ctrl('n'):
+		case CTRL('n'):
 			if (grabhist(modified, hnum + argcnt) < 0)
 				return -1;
 			else {
@@ -897,7 +909,7 @@ vi_cmd(int argcnt, const char *cmd)
 
 		case 'k':
 		case '-':
-		case Ctrl('p'):
+		case CTRL('p'):
 			if (grabhist(modified, hnum - argcnt) < 0)
 				return -1;
 			else {
@@ -913,13 +925,24 @@ vi_cmd(int argcnt, const char *cmd)
 			if (cmd[1] == 0)
 				vi_error();
 			else {
-				int	n;
-
-				if (es->cursor + argcnt > es->linelen)
+				c1 = 0;
+				for (cur = es->cursor;
+				    cur < es->linelen; cur++) {
+					if (!isu8cont(es->cbuf[cur]))
+						c1++;
+					if (c1 > argcnt)
+						break;
+				}
+				if (argcnt > c1)
 					return -1;
-				for (n = 0; n < argcnt; ++n)
-					es->cbuf[es->cursor + n] = cmd[1];
-				es->cursor += n - 1;
+
+				del_range(es->cursor, cur);
+				while (argcnt-- > 0)
+					putbuf(&cmd[1], 1, 0);
+				while (es->cursor > 0)
+					if (!isu8cont(es->cbuf[--es->cursor]))
+						break;
+				es->cbuf[es->linelen] = '\0';
 			}
 			break;
 
@@ -932,9 +955,11 @@ vi_cmd(int argcnt, const char *cmd)
 			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);
+			for (cur = es->cursor; cur < es->linelen; cur++)
+				if (!isu8cont(es->cbuf[cur]))
+					if (argcnt-- == 0)
+						break;
+			del_range(es->cursor, cur);
 			insert = INSERT;
 			break;
 
@@ -961,22 +986,25 @@ vi_cmd(int argcnt, const char *cmd)
 			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);
+			for (cur = es->cursor; cur < es->linelen; cur++)
+				if (!isu8cont(es->cbuf[cur]))
+					if (argcnt-- == 0)
+						break;
+			yank_range(es->cursor, cur);
+			del_range(es->cursor, cur);
 			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
+			if (es->cursor == 0)
 				return -1;
+			modified = 1; hnum = hlast;
+			for (cur = es->cursor; cur > 0; cur--)
+				if (!isu8cont(es->cbuf[cur]))
+					if (argcnt-- == 0)
+						break;
+			yank_range(cur, es->cursor);
+			del_range(cur, es->cursor);
+			es->cursor = cur;
 			break;
 
 		case 'u':
@@ -1067,7 +1095,7 @@ vi_cmd(int argcnt, const char *cmd)
 				argcnt++;
 				p++;
 			}
-			if (putbuf(space, 1, 0) != 0)
+			if (putbuf(" ", 1, 0) != 0)
 				argcnt = -1;
 			else if (putbuf(sp, argcnt, 0) != 0)
 				argcnt = -1;
@@ -1082,18 +1110,20 @@ vi_cmd(int argcnt, const char *cmd)
 
 		case '~': {
 			char	*p;
+			unsigned char c;
 			int	i;
 
 			if (es->linelen == 0)
 				return -1;
 			for (i = 0; i < argcnt; i++) {
 				p = &es->cbuf[es->cursor];
-				if (islower((unsigned char)*p)) {
+				c = (unsigned char)*p;
+				if (islower(c)) {
 					modified = 1; hnum = hlast;
-					*p = toupper(*p);
-				} else if (isupper((unsigned char)*p)) {
+					*p = toupper(c);
+				} else if (isupper(c)) {
 					modified = 1; hnum = hlast;
-					*p = tolower(*p);
+					*p = tolower(c);
 				}
 				if (es->cursor < es->linelen - 1)
 					es->cursor++;
@@ -1111,33 +1141,35 @@ vi_cmd(int argcnt, const char *cmd)
 		    }
 
 		case '=':			/* at&t ksh */
-		case Ctrl('e'):			/* Nonstandard vi/ksh */
+		case CTRL('e'):			/* Nonstandard vi/ksh */
 			print_expansions(es, 1);
 			break;
 
 
-		case Ctrl('i'):			/* Nonstandard vi/ksh */
+		case CTRL('i'):			/* Nonstandard vi/ksh */
 			if (!Flag(FVITABCOMPLETE))
 				return -1;
 			complete_word(1, argcnt);
 			break;
 
-		case Ctrl('['):			/* some annoying at&t ksh's */
+		case CTRL('['):			/* some annoying at&t ksh's */
 			if (!Flag(FVIESCCOMPLETE))
 				return -1;
 		case '\\':			/* at&t ksh */
-		case Ctrl('f'):			/* Nonstandard vi/ksh */
+		case CTRL('f'):			/* Nonstandard vi/ksh */
 			complete_word(1, argcnt);
 			break;
 
 
 		case '*':			/* at&t ksh */
-		case Ctrl('x'):			/* Nonstandard vi/ksh */
+		case CTRL('x'):			/* Nonstandard vi/ksh */
 			expand_word(1);
 			break;
 		}
-		if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen)
-			es->cursor--;
+		if (insert == 0 && es->cursor >= es->linelen)
+			while (es->cursor > 0)
+				if (!isu8cont(es->cbuf[--es->cursor]))
+					break;
 	}
 	return 0;
 }
@@ -1151,31 +1183,20 @@ domove(int argcnt, const char *cmd, int sub)
 	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);
+		ncursor = (*cmd == 'b' ? backword : 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++;
+		ncursor = (*cmd == 'e' ? endword : Endword)(argcnt);
+		if (!sub)
+			while (isu8cont((unsigned char)es->cbuf[--ncursor]))
+				continue;
 		break;
 
 	case 'f':
@@ -1201,35 +1222,30 @@ domove(int argcnt, const char *cmd, int sub)
 		break;
 
 	case 'h':
-	case Ctrl('h'):
+	case CTRL('h'):
 		if (!sub && es->cursor == 0)
 			return -1;
-		ncursor = es->cursor - argcnt;
-		if (ncursor < 0)
-			ncursor = 0;
+		for (ncursor = es->cursor; ncursor > 0; ncursor--)
+			if (!isu8cont(es->cbuf[ncursor]))
+				if (argcnt-- == 0)
+					break;
 		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;
-		}
+		for (ncursor = es->cursor; ncursor < es->linelen; ncursor++)
+			if (!isu8cont(es->cbuf[ncursor]))
+				if (argcnt-- == 0)
+					break;
 		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);
+		ncursor = (*cmd == 'w' ? forwword : Forwword)(argcnt);
 		break;
 
 	case '0':
@@ -1249,13 +1265,12 @@ domove(int argcnt, const char *cmd, int sub)
 			ncursor = es->linelen;
 		if (ncursor)
 			ncursor--;
+		while (isu8cont(es->cbuf[ncursor]))
+			ncursor--;
 		break;
 
 	case '$':
-		if (es->linelen != 0)
-			ncursor = es->linelen;
-		else
-			ncursor = 0;
+		ncursor = es->linelen;
 		break;
 
 	case '%':
@@ -1297,7 +1312,8 @@ redo_insert(int count)
 		if (putbuf(ibuf, inslen, insert==REPLACE) != 0)
 			return -1;
 	if (es->cursor > 0)
-		es->cursor--;
+		while (isu8cont(es->cbuf[--es->cursor]))
+			continue;
 	insert = 0;
 	return 0;
 }
@@ -1342,17 +1358,16 @@ bracktype(int ch)
  *	Non user interface editor routines below here
  */
 
-static int	cur_col;		/* current column on line */
-static int	pwidth;			/* width of prompt */
+static int	cur_col;		/* current display column */
+static int	pwidth;			/* display columns needed for 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	winwidth;		/* available column positions */
+static char	*wbuf[2];		/* current & previous window buffer */
 static int	wbuf_len;		/* length of window buffers (x_cols-3)*/
-static int	win;			/* window buffer in use */
+static int	win;			/* number of 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 char	holdbuf[LINE];		/* place to hold last edit buffer */
 static int	holdlen;		/* length of holdbuf */
 
 static void
@@ -1377,7 +1392,7 @@ save_edstate(struct edstate *old)
 {
 	struct edstate *new;
 
-	new = (struct edstate *)alloc(sizeof(struct edstate), APERM);
+	new = alloc(sizeof(struct edstate), APERM);
 	new->cbuf = alloc(old->cbufsize, APERM);
 	memcpy(new->cbuf, old->cbuf, old->linelen);
 	new->cbufsize = old->cbufsize;
@@ -1401,7 +1416,7 @@ static void
 free_edstate(struct edstate *old)
 {
 	afree(old->cbuf, APERM);
-	afree((char *)old, APERM);
+	afree(old, APERM);
 }
 
 
@@ -1439,7 +1454,6 @@ edit_reset(char *buf, size_t len)
 	winwidth = x_cols - pwidth - 3;
 	win = 0;
 	morec = ' ';
-	lastref = 1;
 	holdlen = 0;
 }
 
@@ -1510,80 +1524,100 @@ findch(int ch, int cnt, int forw, int incl)
 	return ncursor;
 }
 
+/* Move right one character, and then to the beginning of the next word. */
 static int
 forwword(int argcnt)
 {
-	int	ncursor;
+	int ncursor, skip_space, want_letnum;
+	unsigned char uc;
 
 	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((unsigned char)es->cbuf[ncursor]))
-			while (!is_wordch(es->cbuf[ncursor]) &&
-			    !isspace((unsigned char)es->cbuf[ncursor]) &&
-			    ncursor < es->linelen)
-				ncursor++;
-		while (isspace((unsigned char)es->cbuf[ncursor]) &&
-		    ncursor < es->linelen)
-			ncursor++;
+		skip_space = 0;
+		want_letnum = -1;
+		ncursor--;
+		while (++ncursor < es->linelen) {
+			uc = es->cbuf[ncursor];
+			if (isspace(uc)) {
+				skip_space = 1;
+				continue;
+			} else if (skip_space)
+				break;
+			if (uc & 0x80)
+				continue;
+			if (want_letnum == -1)
+				want_letnum = letnum(uc);
+			else if (want_letnum != letnum(uc))
+				break;
+		}
 	}
 	return ncursor;
 }
 
+/* Move left one character, and then to the beginning of the word. */
 static int
 backword(int argcnt)
 {
-	int	ncursor;
+	int ncursor, skip_space, want_letnum;
+	unsigned char uc;
 
 	ncursor = es->cursor;
 	while (ncursor > 0 && argcnt--) {
-		while (--ncursor > 0 && isspace((unsigned char)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((unsigned char)es->cbuf[ncursor]))
-					;
-			ncursor++;
+		skip_space = 1;
+		want_letnum = -1;
+		while (ncursor-- > 0) {
+			uc = es->cbuf[ncursor];
+			if (isspace(uc)) {
+				if (skip_space)
+					continue;
+				else
+					break;
+			}
+			skip_space = 0;
+			if (uc & 0x80)
+				continue;
+			if (want_letnum == -1)
+				want_letnum = letnum(uc);
+			else if (want_letnum != letnum(uc))
+				break;
 		}
+		ncursor++;
 	}
 	return ncursor;
 }
 
+/* Move right one character, and then to the byte after the word. */
 static int
 endword(int argcnt)
 {
-	int	ncursor;
+	int ncursor, skip_space, want_letnum;
+	unsigned char uc;
 
 	ncursor = es->cursor;
 	while (ncursor < es->linelen && argcnt--) {
-		while (++ncursor < es->linelen - 1 &&
-		    isspace((unsigned char)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((unsigned char)es->cbuf[ncursor]))
-					;
-			ncursor--;
+		skip_space = 1;
+		want_letnum = -1;
+		while (++ncursor < es->linelen) {
+			uc = es->cbuf[ncursor];
+			if (isspace(uc)) {
+				if (skip_space)
+					continue;
+				else
+					break;
+			}
+			skip_space = 0;
+			if (uc & 0x80)
+				continue;
+			if (want_letnum == -1)
+				want_letnum = letnum(uc);
+			else if (want_letnum != letnum(uc))
+				break;
 		}
 	}
 	return ncursor;
 }
 
+/* Move right one character, and then to the beginning of the next big word. */
 static int
 Forwword(int argcnt)
 {
@@ -1601,6 +1635,7 @@ Forwword(int argcnt)
 	return ncursor;
 }
 
+/* Move left one character, and then to the beginning of the big word. */
 static int
 Backword(int argcnt)
 {
@@ -1619,22 +1654,20 @@ Backword(int argcnt)
 	return ncursor;
 }
 
+/* Move right one character, and then to the byte after the big word. */
 static int
 Endword(int argcnt)
 {
 	int	ncursor;
 
 	ncursor = es->cursor;
-	while (ncursor < es->linelen - 1 && argcnt--) {
-		while (++ncursor < es->linelen - 1 &&
+	while (ncursor < es->linelen && argcnt--) {
+		while (++ncursor < es->linelen &&
 		    isspace((unsigned char)es->cbuf[ncursor]))
 			;
-		if (ncursor < es->linelen - 1) {
-			while (++ncursor < es->linelen &&
-			    !isspace((unsigned char)es->cbuf[ncursor]))
-				;
-			ncursor--;
-		}
+		while (ncursor < es->linelen &&
+		    !isspace((unsigned char)es->cbuf[ncursor]))
+			ncursor++;
 	}
 	return ncursor;
 }
@@ -1716,10 +1749,6 @@ redraw_line(int newline)
 static void
 refresh(int leftside)
 {
-	if (leftside < 0)
-		leftside = lastref;
-	else
-		lastref = leftside;
 	if (outofwin())
 		rewindow();
 	display(wbuf[1 - win], wbuf[win], leftside);
@@ -1766,24 +1795,38 @@ rewindow(void)
 	es->winleft = holdcur1;
 }
 
+/* Printing the byte ch at display column col moves to which column? */
 static int
 newcol(int ch, int col)
 {
 	if (ch == '\t')
 		return (col | 7) + 1;
+	if (isu8cont(ch))
+		return col;
 	return col + char_len(ch);
 }
 
+/* Display wb1 assuming that wb2 is currently displayed. */
 static void
 display(char *wb1, char *wb2, int leftside)
 {
+	char	*twb1;	/* pointer into the buffer to display */
+	char	*twb2;	/* pointer into the previous display buffer */
+	static int lastb = -1; /* last byte# written from wb1, if UTF-8 */
+	int	 cur;	/* byte# in the main command line buffer */
+	int	 col;	/* display column loop variable */
+	int	 ncol;	/* display column of the cursor */
+	int	 cnt;	/* remaining display columns to fill */
+	int	 moreright;
+	char	 mc;	/* new "more character" at the right of window */
 	unsigned char ch;
-	char	*twb1, *twb2, mc;
-	int	cur, col, cnt;
-	int	ncol = 0;
-	int	moreright;
 
-	col = 0;
+	/*
+	 * Fill the current display buffer with data from cbuf.
+	 * In this first loop, col does not include the prompt.
+	 */
+
+	ncol = col = 0;
 	cur = es->winleft;
 	moreright = 0;
 	twb1 = wb1;
@@ -1812,7 +1855,8 @@ display(char *wb1, char *wb2, int leftside)
 					}
 				} else {
 					*twb1++ = ch;
-					col++;
+					if (!isu8cont(ch))
+						col++;
 				}
 			}
 		}
@@ -1822,6 +1866,9 @@ display(char *wb1, char *wb2, int leftside)
 	}
 	if (cur == es->cursor)
 		ncol = col + pwidth;
+
+	/* Pad the current display buffer to the right margin. */
+
 	if (col < winwidth) {
 		while (col < winwidth) {
 			*twb1++ = ' ';
@@ -1831,21 +1878,62 @@ display(char *wb1, char *wb2, int leftside)
 		moreright++;
 	*twb1 = ' ';
 
+	/*
+	 * Update the terminal display with data from wb1.
+	 * In this final loop, col includes the prompt.
+	 */
+
 	col = pwidth;
 	cnt = winwidth;
-	twb1 = wb1;
-	twb2 = wb2;
-	while (cnt--) {
+	for (twb1 = wb1, twb2 = wb2; cnt; twb1++, twb2++) {
 		if (*twb1 != *twb2) {
+
+			/*
+			 * When a byte changes in the middle of a UTF-8
+			 * character, back up to the start byte, unless
+			 * the previous byte was the last one written.
+			 */
+
+			if (col > 0 && isu8cont(*twb1)) {
+				col--;
+				if (lastb >= 0 && twb1 == wb1 + lastb + 1)
+					cur_col = col;
+				else while (twb1 > wb1 && isu8cont(*twb1)) {
+					twb1--;
+					twb2--;
+				}
+			}
+
 			if (cur_col != col)
 				ed_mov_opt(col, wb1);
+
+			/*
+			 * Always write complete characters, and
+			 * advance all pointers accordingly.
+			 */
+
 			x_putc(*twb1);
+			while (isu8cont(twb1[1])) {
+				x_putc(*++twb1);
+				twb2++;
+			}
+			lastb = *twb1 & 0x80 ? twb1 - wb1 : -1;
 			cur_col++;
-		}
-		twb1++;
-		twb2++;
+		} else if (isu8cont(*twb1))
+			continue;
+
+		/*
+		 * For changed continuation bytes, we backed up.
+		 * For unchanged ones, we jumped to the next byte.
+		 * So, getting here, we had a real column.
+		 */
+
 		col++;
+		cnt--;
 	}
+
+	/* Update the "more character". */
+
 	if (es->winleft > 0 && moreright)
 		/* POSIX says to use * for this but that is a globbing
 		 * character and may confuse people; + is more innocuous
@@ -1862,31 +1950,52 @@ display(char *wb1, char *wb2, int leftside)
 		x_putc(mc);
 		cur_col++;
 		morec = mc;
+		lastb = -1;
 	}
-	if (cur_col != ncol)
+
+	/* Move the cursor to its new position. */
+
+	if (cur_col != ncol) {
 		ed_mov_opt(ncol, wb1);
+		lastb = -1;
+	}
 }
 
+/* Move the display cursor to display column number col. */
 static void
 ed_mov_opt(int col, char *wb)
 {
-	if (col < cur_col) {
-		if (col + 1 < cur_col - col) {
+	int ci;
+
+	/* The cursor is already at the right place. */
+
+	if (cur_col == col)
+		return;
+
+	/* The cursor is too far right. */
+
+	if (cur_col > col) {
+		if (cur_col > 2 * col + 1) {
+			/* Much too far right, redraw from scratch. */
 			x_putc('\r');
 			vi_pprompt(0);
 			cur_col = pwidth;
-			while (cur_col++ < col)
-				x_putc(*wb++);
 		} else {
-			while (cur_col-- > col)
+			/* Slightly too far right, back up. */
+			do {
 				x_putc('\b');
+			} while (--cur_col > col);
+			return;
 		}
-	} else {
-		wb = &wb[cur_col - pwidth];
-		while (cur_col++ < col)
-			x_putc(*wb++);
 	}
-	cur_col = col;
+
+	/* Advance the cursor. */
+
+	for (ci = pwidth; ci < col || isu8cont(*wb);
+	     ci = newcol((unsigned char)*wb++, ci))
+		if (ci > cur_col || (ci == cur_col && !isu8cont(*wb)))
+			x_putc(*wb);
+	cur_col = ci;
 }
 
 
@@ -1904,18 +2013,18 @@ expand_word(int command)
 	/* Undo previous expansion */
 	if (command == 0 && expanded == EXPAND && buf) {
 		restore_edstate(es, buf);
-		buf = 0;
+		buf = NULL;
 		expanded = NONE;
 		return 0;
 	}
 	if (buf) {
 		free_edstate(buf);
-		buf = 0;
+		buf = NULL;
 	}
 
 	nwords = x_cf_glob(XCF_COMMAND_FILE|XCF_FULLPATH,
 	    es->cbuf, es->linelen, es->cursor,
-	    &start, &end, &words, (int *) 0);
+	    &start, &end, &words, NULL);
 	if (nwords == 0) {
 		vi_error();
 		return -1;
@@ -1930,7 +2039,7 @@ expand_word(int command)
 			rval = -1;
 			break;
 		}
-		if (++i < nwords && putbuf(space, 1, 0) != 0) {
+		if (++i < nwords && putbuf(" ", 1, 0) != 0) {
 			rval = -1;
 			break;
 		}
@@ -1966,13 +2075,13 @@ complete_word(int command, int count)
 	}
 	if (command == 0 && expanded == PRINT && buf) {
 		restore_edstate(es, buf);
-		buf = 0;
+		buf = NULL;
 		expanded = NONE;
 		return 0;
 	}
 	if (buf) {
 		free_edstate(buf);
-		buf = 0;
+		buf = NULL;
 	}
 
 	/* XCF_FULLPATH for count 'cause the menu printed by print_expansions()
@@ -2001,12 +2110,12 @@ complete_word(int command, int count)
 		 */
 		if (is_command) {
 			match = words[count] +
-			    x_basename(words[count], (char *) 0);
+			    x_basename(words[count], NULL);
 			/* 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) {
+				    NULL), match) == 0) {
 					match = words[count];
 					break;
 				}
@@ -2038,7 +2147,7 @@ complete_word(int command, int count)
 
 		/* If not a directory, add a space to the end... */
 		if (match_len > 0 && match[match_len - 1] != '/')
-			rval = putbuf(space, 1, 0);
+			rval = putbuf(" ", 1, 0);
 	}
 	x_free_words(nwords, words);
 
@@ -2071,7 +2180,11 @@ print_expansions(struct edstate *e, int command)
 	return 0;
 }
 
-/* How long is char when displayed (not counting tabs) */
+/*
+ * The number of bytes needed to encode byte c.
+ * Control bytes get "M-" or "^" prepended.
+ * This function does not handle tabs.
+ */
 static int
 char_len(int c)
 {
@@ -2125,4 +2238,9 @@ vi_macro_reset(void)
 	}
 }
 
+static int
+isu8cont(unsigned char c)
+{
+	return !Flag(FVISHOW8) && (c & (0x80 | 0x40)) == 0x80;
+}
 #endif	/* VI */
diff --git a/vis.c b/vis.c
@@ -0,0 +1,243 @@
+/*	$OpenBSD: vis.c,v 1.25 2015/09/13 11:32:51 guenther Exp $ */
+/*-
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "portable/linux/vis.h"
+
+#define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+#define	isvisible(c,flag)						\
+	(((c) == '\\' || (flag & VIS_ALL) == 0) &&			\
+	(((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) &&		\
+	(((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') ||	\
+		(flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) ||	\
+	((flag & VIS_SP) == 0 && (c) == ' ') ||				\
+	((flag & VIS_TAB) == 0 && (c) == '\t') ||			\
+	((flag & VIS_NL) == 0 && (c) == '\n') ||			\
+	((flag & VIS_SAFE) && ((c) == '\b' ||				\
+		(c) == '\007' || (c) == '\r' ||				\
+		isgraph((u_char)(c))))))
+
+/*
+ * vis - visually encode characters
+ */
+char *
+vis(char *dst, int c, int flag, int nextc)
+{
+	if (isvisible(c, flag)) {
+		if ((c == '"' && (flag & VIS_DQ) != 0) ||
+		    (c == '\\' && (flag & VIS_NOSLASH) == 0))
+			*dst++ = '\\';
+		*dst++ = c;
+		*dst = '\0';
+		return (dst);
+	}
+
+	if (flag & VIS_CSTYLE) {
+		switch(c) {
+		case '\n':
+			*dst++ = '\\';
+			*dst++ = 'n';
+			goto done;
+		case '\r':
+			*dst++ = '\\';
+			*dst++ = 'r';
+			goto done;
+		case '\b':
+			*dst++ = '\\';
+			*dst++ = 'b';
+			goto done;
+		case '\a':
+			*dst++ = '\\';
+			*dst++ = 'a';
+			goto done;
+		case '\v':
+			*dst++ = '\\';
+			*dst++ = 'v';
+			goto done;
+		case '\t':
+			*dst++ = '\\';
+			*dst++ = 't';
+			goto done;
+		case '\f':
+			*dst++ = '\\';
+			*dst++ = 'f';
+			goto done;
+		case ' ':
+			*dst++ = '\\';
+			*dst++ = 's';
+			goto done;
+		case '\0':
+			*dst++ = '\\';
+			*dst++ = '0';
+			if (isoctal(nextc)) {
+				*dst++ = '0';
+				*dst++ = '0';
+			}
+			goto done;
+		}
+	}
+	if (((c & 0177) == ' ') || (flag & VIS_OCTAL) ||
+	    ((flag & VIS_GLOB) && (c == '*' || c == '?' || c == '[' || c == '#'))) {
+		*dst++ = '\\';
+		*dst++ = ((u_char)c >> 6 & 07) + '0';
+		*dst++ = ((u_char)c >> 3 & 07) + '0';
+		*dst++ = ((u_char)c & 07) + '0';
+		goto done;
+	}
+	if ((flag & VIS_NOSLASH) == 0)
+		*dst++ = '\\';
+	if (c & 0200) {
+		c &= 0177;
+		*dst++ = 'M';
+	}
+	if (iscntrl((u_char)c)) {
+		*dst++ = '^';
+		if (c == 0177)
+			*dst++ = '?';
+		else
+			*dst++ = c + '@';
+	} else {
+		*dst++ = '-';
+		*dst++ = c;
+	}
+done:
+	*dst = '\0';
+	return (dst);
+}
+DEF_WEAK(vis);
+
+/*
+ * strvis, strnvis, strvisx - visually encode characters from src into dst
+ *	
+ *	Dst must be 4 times the size of src to account for possible
+ *	expansion.  The length of dst, not including the trailing NULL,
+ *	is returned. 
+ *
+ *	Strnvis will write no more than siz-1 bytes (and will NULL terminate).
+ *	The number of bytes needed to fully encode the string is returned.
+ *
+ *	Strvisx encodes exactly len bytes from src into dst.
+ *	This is useful for encoding a block of data.
+ */
+int
+strvis(char *dst, const char *src, int flag)
+{
+	char c;
+	char *start;
+
+	for (start = dst; (c = *src);)
+		dst = vis(dst, c, flag, *++src);
+	*dst = '\0';
+	return (dst - start);
+}
+DEF_WEAK(strvis);
+
+int
+strnvis(char *dst, const char *src, size_t siz, int flag)
+{
+	char *start, *end;
+	char tbuf[5];
+	int c, i;
+
+	i = 0;
+	for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) {
+		if (isvisible(c, flag)) {
+			if ((c == '"' && (flag & VIS_DQ) != 0) ||
+			    (c == '\\' && (flag & VIS_NOSLASH) == 0)) {
+				/* need space for the extra '\\' */
+				if (dst + 1 >= end) {
+					i = 2;
+					break;
+				}
+				*dst++ = '\\';
+			}
+			i = 1;
+			*dst++ = c;
+			src++;
+		} else {
+			i = vis(tbuf, c, flag, *++src) - tbuf;
+			if (dst + i <= end) {
+				memcpy(dst, tbuf, i);
+				dst += i;
+			} else {
+				src--;
+				break;
+			}
+		}
+	}
+	if (siz > 0)
+		*dst = '\0';
+	if (dst + i > end) {
+		/* adjust return value for truncation */
+		while ((c = *src))
+			dst += vis(tbuf, c, flag, *++src) - tbuf;
+	}
+	return (dst - start);
+}
+
+int
+stravis(char **outp, const char *src, int flag)
+{
+	char *buf;
+	int len, serrno;
+
+	buf = reallocarray(NULL, 4, strlen(src) + 1);
+	if (buf == NULL)
+		return -1;
+	len = strvis(buf, src, flag);
+	serrno = errno;
+	*outp = realloc(buf, len + 1);
+	if (*outp == NULL) {
+		*outp = buf;
+		errno = serrno;
+	}
+	return (len);
+}
+
+int
+strvisx(char *dst, const char *src, size_t len, int flag)
+{
+	char c;
+	char *start;
+
+	for (start = dst; len > 1; len--) {
+		c = *src;
+		dst = vis(dst, c, flag, *++src);
+	}
+	if (len)
+		dst = vis(dst, *src, flag, '\0');
+	*dst = '\0';
+	return (dst - start);
+}